channel.cc revision e46c8d387587ba148e229a7bb18f1cc0708a2a87
1470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com/*
22919e95c2a59a087ba8297c2f551c3ebc3754c9ehenrika@webrtc.org *  Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
3470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com *
4470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com *  Use of this source code is governed by a BSD-style license
5470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com *  that can be found in the LICENSE file in the root of the source
6470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com *  tree. An additional intellectual property rights grant can be found
7470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com *  in the file PATENTS.  All contributing project authors may
8470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com *  be found in the AUTHORS file in the root of the source tree.
9470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com */
10470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
116388c3e2fdfc91b3648fb7d408a14ddb25e41cd1turaj@webrtc.org#include "webrtc/voice_engine/channel.h"
126388c3e2fdfc91b3648fb7d408a14ddb25e41cd1turaj@webrtc.org
136388c3e2fdfc91b3648fb7d408a14ddb25e41cd1turaj@webrtc.org#include "webrtc/modules/audio_device/include/audio_device.h"
146388c3e2fdfc91b3648fb7d408a14ddb25e41cd1turaj@webrtc.org#include "webrtc/modules/audio_processing/include/audio_processing.h"
156388c3e2fdfc91b3648fb7d408a14ddb25e41cd1turaj@webrtc.org#include "webrtc/modules/utility/interface/audio_frame_operations.h"
166388c3e2fdfc91b3648fb7d408a14ddb25e41cd1turaj@webrtc.org#include "webrtc/modules/utility/interface/process_thread.h"
176388c3e2fdfc91b3648fb7d408a14ddb25e41cd1turaj@webrtc.org#include "webrtc/modules/utility/interface/rtp_dump.h"
186388c3e2fdfc91b3648fb7d408a14ddb25e41cd1turaj@webrtc.org#include "webrtc/system_wrappers/interface/critical_section_wrapper.h"
196388c3e2fdfc91b3648fb7d408a14ddb25e41cd1turaj@webrtc.org#include "webrtc/system_wrappers/interface/logging.h"
206388c3e2fdfc91b3648fb7d408a14ddb25e41cd1turaj@webrtc.org#include "webrtc/system_wrappers/interface/trace.h"
216388c3e2fdfc91b3648fb7d408a14ddb25e41cd1turaj@webrtc.org#include "webrtc/voice_engine/include/voe_base.h"
226388c3e2fdfc91b3648fb7d408a14ddb25e41cd1turaj@webrtc.org#include "webrtc/voice_engine/include/voe_external_media.h"
236388c3e2fdfc91b3648fb7d408a14ddb25e41cd1turaj@webrtc.org#include "webrtc/voice_engine/include/voe_rtp_rtcp.h"
246388c3e2fdfc91b3648fb7d408a14ddb25e41cd1turaj@webrtc.org#include "webrtc/voice_engine/output_mixer.h"
256388c3e2fdfc91b3648fb7d408a14ddb25e41cd1turaj@webrtc.org#include "webrtc/voice_engine/statistics.h"
266388c3e2fdfc91b3648fb7d408a14ddb25e41cd1turaj@webrtc.org#include "webrtc/voice_engine/transmit_mixer.h"
276388c3e2fdfc91b3648fb7d408a14ddb25e41cd1turaj@webrtc.org#include "webrtc/voice_engine/utility.h"
28470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
29470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com#if defined(_WIN32)
30470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com#include <Qos.h>
31470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com#endif
32470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
3350419b07772de974964072478886c4c35ab9c8ccandrew@webrtc.orgnamespace webrtc {
3450419b07772de974964072478886c4c35ab9c8ccandrew@webrtc.orgnamespace voe {
35470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
366141e13873d0fdea626de08dfec2efa2c9171c76pbos@webrtc.orgint32_t
37470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.comChannel::SendData(FrameType frameType,
386141e13873d0fdea626de08dfec2efa2c9171c76pbos@webrtc.org                  uint8_t   payloadType,
396141e13873d0fdea626de08dfec2efa2c9171c76pbos@webrtc.org                  uint32_t  timeStamp,
406141e13873d0fdea626de08dfec2efa2c9171c76pbos@webrtc.org                  const uint8_t*  payloadData,
416141e13873d0fdea626de08dfec2efa2c9171c76pbos@webrtc.org                  uint16_t  payloadSize,
42470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                  const RTPFragmentationHeader* fragmentation)
43470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com{
44470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
45470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                 "Channel::SendData(frameType=%u, payloadType=%u, timeStamp=%u,"
46470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                 " payloadSize=%u, fragmentation=0x%x)",
47470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                 frameType, payloadType, timeStamp, payloadSize, fragmentation);
48470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
49470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    if (_includeAudioLevelIndication)
50470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
51755b04a06ec4ae91ae7fb601c641e683f4e9e87dandrew@webrtc.org        assert(_rtpAudioProc.get() != NULL);
52470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        // Store current audio level in the RTP/RTCP module.
53470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        // The level will be used in combination with voice-activity state
54470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        // (frameType) to add an RTP header extension
552853dde5201d9ddc284ce5efb9688f6340487acepwestin@webrtc.org        _rtpRtcpModule->SetAudioLevel(_rtpAudioProc->level_estimator()->RMS());
56470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
57470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
58470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    // Push data from ACM to RTP/RTCP-module to deliver audio frame for
59470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    // packetization.
60470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    // This call will trigger Transport::SendPacket() from the RTP/RTCP module.
612853dde5201d9ddc284ce5efb9688f6340487acepwestin@webrtc.org    if (_rtpRtcpModule->SendOutgoingData((FrameType&)frameType,
62470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                                        payloadType,
63470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                                        timeStamp,
64ddfdfed3b55de3da5fda9a55d34e46d6e422baafstefan@webrtc.org                                        // Leaving the time when this frame was
65ddfdfed3b55de3da5fda9a55d34e46d6e422baafstefan@webrtc.org                                        // received from the capture device as
66ddfdfed3b55de3da5fda9a55d34e46d6e422baafstefan@webrtc.org                                        // undefined for voice for now.
67ddfdfed3b55de3da5fda9a55d34e46d6e422baafstefan@webrtc.org                                        -1,
68470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                                        payloadData,
69470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                                        payloadSize,
70470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                                        fragmentation) == -1)
71470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
72470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        _engineStatisticsPtr->SetLastError(
73470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            VE_RTP_RTCP_MODULE_ERROR, kTraceWarning,
74470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            "Channel::SendData() failed to send data to RTP/RTCP module");
75470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        return -1;
76470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
77470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
78470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    _lastLocalTimeStamp = timeStamp;
79470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    _lastPayloadType = payloadType;
80470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
81470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    return 0;
82470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com}
83470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
846141e13873d0fdea626de08dfec2efa2c9171c76pbos@webrtc.orgint32_t
856141e13873d0fdea626de08dfec2efa2c9171c76pbos@webrtc.orgChannel::InFrameType(int16_t frameType)
86470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com{
87470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
88470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                 "Channel::InFrameType(frameType=%d)", frameType);
89470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
909a065d1eae9ed296e1e2eaaad73d7ca1223bfe79mflodman@webrtc.org    CriticalSectionScoped cs(&_callbackCritSect);
91470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    // 1 indicates speech
92470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    _sendFrameType = (frameType == 1) ? 1 : 0;
93470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    return 0;
94470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com}
95470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
966141e13873d0fdea626de08dfec2efa2c9171c76pbos@webrtc.orgint32_t
979213521ea98b0977c7cdabd2853060835af226f3pbos@webrtc.orgChannel::OnRxVadDetected(int vadDecision)
98470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com{
99470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
100470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                 "Channel::OnRxVadDetected(vadDecision=%d)", vadDecision);
101470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
1029a065d1eae9ed296e1e2eaaad73d7ca1223bfe79mflodman@webrtc.org    CriticalSectionScoped cs(&_callbackCritSect);
103470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    if (_rxVadObserverPtr)
104470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
105470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        _rxVadObserverPtr->OnRxVad(_channelId, vadDecision);
106470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
107470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
108470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    return 0;
109470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com}
110470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
111470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.comint
112470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.comChannel::SendPacket(int channel, const void *data, int len)
113470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com{
114470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    channel = VoEChannelId(channel);
115470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    assert(channel == _channelId);
116470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
117470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
118470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                 "Channel::SendPacket(channel=%d, len=%d)", channel, len);
119470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
120470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    if (_transportPtr == NULL)
121470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
122470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        WEBRTC_TRACE(kTraceError, kTraceVoice, VoEId(_instanceId,_channelId),
123470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                     "Channel::SendPacket() failed to send RTP packet due to"
124470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                     " invalid transport object");
125470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        return -1;
126470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
127470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
128470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    // Insert extra RTP packet using if user has called the InsertExtraRTPPacket
129470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    // API
130470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    if (_insertExtraRTPPacket)
131470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
1326141e13873d0fdea626de08dfec2efa2c9171c76pbos@webrtc.org        uint8_t* rtpHdr = (uint8_t*)data;
1336141e13873d0fdea626de08dfec2efa2c9171c76pbos@webrtc.org        uint8_t M_PT(0);
134470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        if (_extraMarkerBit)
135470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        {
136470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            M_PT = 0x80;            // set the M-bit
137470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        }
138470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        M_PT += _extraPayloadType;  // set the payload type
139470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        *(++rtpHdr) = M_PT;     // modify the M|PT-byte within the RTP header
140470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        _insertExtraRTPPacket = false;  // insert one packet only
141470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
142470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
1436141e13873d0fdea626de08dfec2efa2c9171c76pbos@webrtc.org    uint8_t* bufferToSendPtr = (uint8_t*)data;
1446141e13873d0fdea626de08dfec2efa2c9171c76pbos@webrtc.org    int32_t bufferLength = len;
145470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
146470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    // Dump the RTP packet to a file (if RTP dump is enabled).
1476141e13873d0fdea626de08dfec2efa2c9171c76pbos@webrtc.org    if (_rtpDumpOut.DumpPacket((const uint8_t*)data, len) == -1)
148470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
149470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        WEBRTC_TRACE(kTraceWarning, kTraceVoice,
150470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                     VoEId(_instanceId,_channelId),
151470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                     "Channel::SendPacket() RTP dump to output file failed");
152470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
153470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
154470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    // SRTP or External encryption
155470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    if (_encrypting)
156470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
1579a065d1eae9ed296e1e2eaaad73d7ca1223bfe79mflodman@webrtc.org        CriticalSectionScoped cs(&_callbackCritSect);
158470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
159470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        if (_encryptionPtr)
160470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        {
161470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            if (!_encryptionRTPBufferPtr)
162470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            {
163470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                // Allocate memory for encryption buffer one time only
164470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                _encryptionRTPBufferPtr =
1656141e13873d0fdea626de08dfec2efa2c9171c76pbos@webrtc.org                    new uint8_t[kVoiceEngineMaxIpPacketSizeBytes];
166512535097e543333584f268eb62fe81c9ac76cc6xians@webrtc.org                memset(_encryptionRTPBufferPtr, 0,
167512535097e543333584f268eb62fe81c9ac76cc6xians@webrtc.org                       kVoiceEngineMaxIpPacketSizeBytes);
168470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            }
169470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
170470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            // Perform encryption (SRTP or external)
1716141e13873d0fdea626de08dfec2efa2c9171c76pbos@webrtc.org            int32_t encryptedBufferLength = 0;
172470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            _encryptionPtr->encrypt(_channelId,
173470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                                    bufferToSendPtr,
174470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                                    _encryptionRTPBufferPtr,
175470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                                    bufferLength,
176470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                                    (int*)&encryptedBufferLength);
177470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            if (encryptedBufferLength <= 0)
178470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            {
179470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                _engineStatisticsPtr->SetLastError(
180470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                    VE_ENCRYPTION_FAILED,
181470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                    kTraceError, "Channel::SendPacket() encryption failed");
182470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                return -1;
183470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            }
184470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
185470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            // Replace default data buffer with encrypted buffer
186470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            bufferToSendPtr = _encryptionRTPBufferPtr;
187470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            bufferLength = encryptedBufferLength;
188470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        }
189470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
190470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
191470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    // Packet transmission using WebRtc socket transport
192470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    if (!_externalTransport)
193470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
194470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        int n = _transportPtr->SendPacket(channel, bufferToSendPtr,
195470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                                          bufferLength);
196470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        if (n < 0)
197470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        {
198470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            WEBRTC_TRACE(kTraceError, kTraceVoice,
199470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                         VoEId(_instanceId,_channelId),
200470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                         "Channel::SendPacket() RTP transmission using WebRtc"
201470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                         " sockets failed");
202470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            return -1;
203470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        }
204470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        return n;
205470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
206470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
207470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    // Packet transmission using external transport transport
208470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
2099a065d1eae9ed296e1e2eaaad73d7ca1223bfe79mflodman@webrtc.org        CriticalSectionScoped cs(&_callbackCritSect);
210470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
211470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        int n = _transportPtr->SendPacket(channel,
212470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                                          bufferToSendPtr,
213470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                                          bufferLength);
214470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        if (n < 0)
215470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        {
216470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            WEBRTC_TRACE(kTraceError, kTraceVoice,
217470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                         VoEId(_instanceId,_channelId),
218470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                         "Channel::SendPacket() RTP transmission using external"
219470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                         " transport failed");
220470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            return -1;
221470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        }
222470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        return n;
223470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
224470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com}
225470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
226470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.comint
227470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.comChannel::SendRTCPPacket(int channel, const void *data, int len)
228470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com{
229470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    channel = VoEChannelId(channel);
230470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    assert(channel == _channelId);
231470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
232470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
233470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                 "Channel::SendRTCPPacket(channel=%d, len=%d)", channel, len);
234470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
235470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
2369a065d1eae9ed296e1e2eaaad73d7ca1223bfe79mflodman@webrtc.org        CriticalSectionScoped cs(&_callbackCritSect);
23783661f534e56dfaf3542963b54b1e208f223a377xians@webrtc.org        if (_transportPtr == NULL)
23883661f534e56dfaf3542963b54b1e208f223a377xians@webrtc.org        {
23983661f534e56dfaf3542963b54b1e208f223a377xians@webrtc.org            WEBRTC_TRACE(kTraceError, kTraceVoice,
24083661f534e56dfaf3542963b54b1e208f223a377xians@webrtc.org                         VoEId(_instanceId,_channelId),
24183661f534e56dfaf3542963b54b1e208f223a377xians@webrtc.org                         "Channel::SendRTCPPacket() failed to send RTCP packet"
24283661f534e56dfaf3542963b54b1e208f223a377xians@webrtc.org                         " due to invalid transport object");
24383661f534e56dfaf3542963b54b1e208f223a377xians@webrtc.org            return -1;
24483661f534e56dfaf3542963b54b1e208f223a377xians@webrtc.org        }
245470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
246470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
2476141e13873d0fdea626de08dfec2efa2c9171c76pbos@webrtc.org    uint8_t* bufferToSendPtr = (uint8_t*)data;
2486141e13873d0fdea626de08dfec2efa2c9171c76pbos@webrtc.org    int32_t bufferLength = len;
249470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
250470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    // Dump the RTCP packet to a file (if RTP dump is enabled).
2516141e13873d0fdea626de08dfec2efa2c9171c76pbos@webrtc.org    if (_rtpDumpOut.DumpPacket((const uint8_t*)data, len) == -1)
252470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
253470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        WEBRTC_TRACE(kTraceWarning, kTraceVoice,
254470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                     VoEId(_instanceId,_channelId),
255470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                     "Channel::SendPacket() RTCP dump to output file failed");
256470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
257470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
258470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    // SRTP or External encryption
259470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    if (_encrypting)
260470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
2619a065d1eae9ed296e1e2eaaad73d7ca1223bfe79mflodman@webrtc.org        CriticalSectionScoped cs(&_callbackCritSect);
262470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
263470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        if (_encryptionPtr)
264470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        {
265470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            if (!_encryptionRTCPBufferPtr)
266470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            {
267470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                // Allocate memory for encryption buffer one time only
268470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                _encryptionRTCPBufferPtr =
2696141e13873d0fdea626de08dfec2efa2c9171c76pbos@webrtc.org                    new uint8_t[kVoiceEngineMaxIpPacketSizeBytes];
270470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            }
271470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
272470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            // Perform encryption (SRTP or external).
2736141e13873d0fdea626de08dfec2efa2c9171c76pbos@webrtc.org            int32_t encryptedBufferLength = 0;
274470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            _encryptionPtr->encrypt_rtcp(_channelId,
275470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                                         bufferToSendPtr,
276470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                                         _encryptionRTCPBufferPtr,
277470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                                         bufferLength,
278470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                                         (int*)&encryptedBufferLength);
279470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            if (encryptedBufferLength <= 0)
280470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            {
281470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                _engineStatisticsPtr->SetLastError(
282470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                    VE_ENCRYPTION_FAILED, kTraceError,
283470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                    "Channel::SendRTCPPacket() encryption failed");
284470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                return -1;
285470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            }
286470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
287470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            // Replace default data buffer with encrypted buffer
288470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            bufferToSendPtr = _encryptionRTCPBufferPtr;
289470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            bufferLength = encryptedBufferLength;
290470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        }
291470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
292470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
293470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    // Packet transmission using WebRtc socket transport
294470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    if (!_externalTransport)
295470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
296470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        int n = _transportPtr->SendRTCPPacket(channel,
297470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                                              bufferToSendPtr,
298470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                                              bufferLength);
299470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        if (n < 0)
300470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        {
301470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            WEBRTC_TRACE(kTraceInfo, kTraceVoice,
302470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                         VoEId(_instanceId,_channelId),
303470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                         "Channel::SendRTCPPacket() transmission using WebRtc"
304470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                         " sockets failed");
305470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            return -1;
306470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        }
307470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        return n;
308470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
309470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
310470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    // Packet transmission using external transport transport
311470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
3129a065d1eae9ed296e1e2eaaad73d7ca1223bfe79mflodman@webrtc.org        CriticalSectionScoped cs(&_callbackCritSect);
313de727ab260115d1813b0a039fc74fca488d0c31dhenrike@webrtc.org        if (_transportPtr == NULL)
314de727ab260115d1813b0a039fc74fca488d0c31dhenrike@webrtc.org        {
315de727ab260115d1813b0a039fc74fca488d0c31dhenrike@webrtc.org            return -1;
316de727ab260115d1813b0a039fc74fca488d0c31dhenrike@webrtc.org        }
317470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        int n = _transportPtr->SendRTCPPacket(channel,
318470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                                              bufferToSendPtr,
319470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                                              bufferLength);
320470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        if (n < 0)
321470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        {
322470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            WEBRTC_TRACE(kTraceInfo, kTraceVoice,
323470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                         VoEId(_instanceId,_channelId),
324470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                         "Channel::SendRTCPPacket() transmission using external"
325470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                         " transport failed");
326470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            return -1;
327470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        }
328470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        return n;
329470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
330470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
331470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    return len;
332470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com}
333470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
334470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.comvoid
3359213521ea98b0977c7cdabd2853060835af226f3pbos@webrtc.orgChannel::OnPlayTelephoneEvent(int32_t id,
3369213521ea98b0977c7cdabd2853060835af226f3pbos@webrtc.org                              uint8_t event,
3379213521ea98b0977c7cdabd2853060835af226f3pbos@webrtc.org                              uint16_t lengthMs,
3389213521ea98b0977c7cdabd2853060835af226f3pbos@webrtc.org                              uint8_t volume)
339470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com{
340470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
341470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                 "Channel::OnPlayTelephoneEvent(id=%d, event=%u, lengthMs=%u,"
342fcd12b3b7d7e92d6f8cdfdf8277808ae52a07c36wu@webrtc.org                 " volume=%u)", id, event, lengthMs, volume);
343470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
344470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    if (!_playOutbandDtmfEvent || (event > 15))
345470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
346470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        // Ignore callback since feedback is disabled or event is not a
347470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        // Dtmf tone event.
348470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        return;
349470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
350470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
351470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    assert(_outputMixerPtr != NULL);
352470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
353470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    // Start playing out the Dtmf tone (if playout is enabled).
354470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    // Reduce length of tone with 80ms to the reduce risk of echo.
355470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    _outputMixerPtr->PlayDtmfTone(event, lengthMs - 80, volume);
356470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com}
357470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
358470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.comvoid
3599213521ea98b0977c7cdabd2853060835af226f3pbos@webrtc.orgChannel::OnIncomingSSRCChanged(int32_t id,
3609213521ea98b0977c7cdabd2853060835af226f3pbos@webrtc.org                               uint32_t SSRC)
361470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com{
362470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
363470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                 "Channel::OnIncomingSSRCChanged(id=%d, SSRC=%d)",
364470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                 id, SSRC);
365470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
3666141e13873d0fdea626de08dfec2efa2c9171c76pbos@webrtc.org    int32_t channel = VoEChannelId(id);
367470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    assert(channel == _channelId);
368470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
369470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    // Reset RTP-module counters since a new incoming RTP stream is detected
3702853dde5201d9ddc284ce5efb9688f6340487acepwestin@webrtc.org    _rtpRtcpModule->ResetReceiveDataCountersRTP();
3712853dde5201d9ddc284ce5efb9688f6340487acepwestin@webrtc.org    _rtpRtcpModule->ResetStatisticsRTP();
372470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
373470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    if (_rtpObserver)
374470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
3759a065d1eae9ed296e1e2eaaad73d7ca1223bfe79mflodman@webrtc.org        CriticalSectionScoped cs(&_callbackCritSect);
376470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
377470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        if (_rtpObserverPtr)
378470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        {
379470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            // Send new SSRC to registered observer using callback
380470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            _rtpObserverPtr->OnIncomingSSRCChanged(channel, SSRC);
381470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        }
382470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
383470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com}
384470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
3859213521ea98b0977c7cdabd2853060835af226f3pbos@webrtc.orgvoid Channel::OnIncomingCSRCChanged(int32_t id,
3869213521ea98b0977c7cdabd2853060835af226f3pbos@webrtc.org                                    uint32_t CSRC,
3879213521ea98b0977c7cdabd2853060835af226f3pbos@webrtc.org                                    bool added)
388470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com{
389470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
390470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                 "Channel::OnIncomingCSRCChanged(id=%d, CSRC=%d, added=%d)",
391470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                 id, CSRC, added);
392470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
3936141e13873d0fdea626de08dfec2efa2c9171c76pbos@webrtc.org    int32_t channel = VoEChannelId(id);
394470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    assert(channel == _channelId);
395470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
396470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    if (_rtpObserver)
397470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
3989a065d1eae9ed296e1e2eaaad73d7ca1223bfe79mflodman@webrtc.org        CriticalSectionScoped cs(&_callbackCritSect);
399470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
400470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        if (_rtpObserverPtr)
401470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        {
402470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            _rtpObserverPtr->OnIncomingCSRCChanged(channel, CSRC, added);
403470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        }
404470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
405470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com}
406470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
407470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.comvoid
4089213521ea98b0977c7cdabd2853060835af226f3pbos@webrtc.orgChannel::OnApplicationDataReceived(int32_t id,
4099213521ea98b0977c7cdabd2853060835af226f3pbos@webrtc.org                                   uint8_t subType,
4109213521ea98b0977c7cdabd2853060835af226f3pbos@webrtc.org                                   uint32_t name,
4119213521ea98b0977c7cdabd2853060835af226f3pbos@webrtc.org                                   uint16_t length,
4126141e13873d0fdea626de08dfec2efa2c9171c76pbos@webrtc.org                                   const uint8_t* data)
413470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com{
414470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
415470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                 "Channel::OnApplicationDataReceived(id=%d, subType=%u,"
416470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                 " name=%u, length=%u)",
417470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                 id, subType, name, length);
418470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
4196141e13873d0fdea626de08dfec2efa2c9171c76pbos@webrtc.org    int32_t channel = VoEChannelId(id);
420470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    assert(channel == _channelId);
421470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
422470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    if (_rtcpObserver)
423470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
4249a065d1eae9ed296e1e2eaaad73d7ca1223bfe79mflodman@webrtc.org        CriticalSectionScoped cs(&_callbackCritSect);
425470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
426470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        if (_rtcpObserverPtr)
427470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        {
428470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            _rtcpObserverPtr->OnApplicationDataReceived(channel,
429470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                                                        subType,
430470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                                                        name,
431470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                                                        data,
432470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                                                        length);
433470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        }
434470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
435470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com}
436470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
4376141e13873d0fdea626de08dfec2efa2c9171c76pbos@webrtc.orgint32_t
438470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.comChannel::OnInitializeDecoder(
4399213521ea98b0977c7cdabd2853060835af226f3pbos@webrtc.org    int32_t id,
4409213521ea98b0977c7cdabd2853060835af226f3pbos@webrtc.org    int8_t payloadType,
441813e4b0af06272dada388c2d8383b2e36a1da6a6leozwang@webrtc.org    const char payloadName[RTP_PAYLOAD_NAME_SIZE],
4429213521ea98b0977c7cdabd2853060835af226f3pbos@webrtc.org    int frequency,
4439213521ea98b0977c7cdabd2853060835af226f3pbos@webrtc.org    uint8_t channels,
4449213521ea98b0977c7cdabd2853060835af226f3pbos@webrtc.org    uint32_t rate)
445470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com{
446470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
447470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                 "Channel::OnInitializeDecoder(id=%d, payloadType=%d, "
448470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                 "payloadName=%s, frequency=%u, channels=%u, rate=%u)",
449470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                 id, payloadType, payloadName, frequency, channels, rate);
450470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
451ceb148ce593627ed0d30a1a8c01752bdebf9172dandrew@webrtc.org    assert(VoEChannelId(id) == _channelId);
452470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
453f75901fa4c5f9a1bcefc265b98a480c72119650chenrika@webrtc.org    CodecInst receiveCodec = {0};
454f75901fa4c5f9a1bcefc265b98a480c72119650chenrika@webrtc.org    CodecInst dummyCodec = {0};
455470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
456470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    receiveCodec.pltype = payloadType;
457470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    receiveCodec.plfreq = frequency;
458470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    receiveCodec.channels = channels;
459470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    receiveCodec.rate = rate;
460f75901fa4c5f9a1bcefc265b98a480c72119650chenrika@webrtc.org    strncpy(receiveCodec.plname, payloadName, RTP_PAYLOAD_NAME_SIZE - 1);
461ae1a58bba4f926d149a5f39243269c3f6625f494andrew@webrtc.org
4627a7a008031d43013b01176cfe40b0fd68c0d83b5tina.legrand@webrtc.org    _audioCodingModule.Codec(payloadName, &dummyCodec, frequency, channels);
463470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    receiveCodec.pacsize = dummyCodec.pacsize;
464470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
465470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    // Register the new codec to the ACM
466470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    if (_audioCodingModule.RegisterReceiveCodec(receiveCodec) == -1)
467470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
468470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        WEBRTC_TRACE(kTraceWarning, kTraceVoice,
469ceb148ce593627ed0d30a1a8c01752bdebf9172dandrew@webrtc.org                     VoEId(_instanceId, _channelId),
470470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                     "Channel::OnInitializeDecoder() invalid codec ("
471470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                     "pt=%d, name=%s) received - 1", payloadType, payloadName);
472470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        _engineStatisticsPtr->SetLastError(VE_AUDIO_CODING_MODULE_ERROR);
473470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        return -1;
474470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
475470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
476470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    return 0;
477470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com}
478470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
479470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.comvoid
4809213521ea98b0977c7cdabd2853060835af226f3pbos@webrtc.orgChannel::OnPacketTimeout(int32_t id)
481470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com{
482470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
483470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                 "Channel::OnPacketTimeout(id=%d)", id);
484470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
4859a065d1eae9ed296e1e2eaaad73d7ca1223bfe79mflodman@webrtc.org    CriticalSectionScoped cs(_callbackCritSectPtr);
486470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    if (_voiceEngineObserverPtr)
487470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
488470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        if (_receiving || _externalTransport)
489470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        {
4906141e13873d0fdea626de08dfec2efa2c9171c76pbos@webrtc.org            int32_t channel = VoEChannelId(id);
491470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            assert(channel == _channelId);
492470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            // Ensure that next OnReceivedPacket() callback will trigger
493470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            // a VE_PACKET_RECEIPT_RESTARTED callback.
494470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            _rtpPacketTimedOut = true;
495470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            // Deliver callback to the observer
496470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            WEBRTC_TRACE(kTraceInfo, kTraceVoice,
497470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                         VoEId(_instanceId,_channelId),
498470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                         "Channel::OnPacketTimeout() => "
499470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                         "CallbackOnError(VE_RECEIVE_PACKET_TIMEOUT)");
500470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            _voiceEngineObserverPtr->CallbackOnError(channel,
501470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                                                     VE_RECEIVE_PACKET_TIMEOUT);
502470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        }
503470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
504470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com}
505470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
506470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.comvoid
5079213521ea98b0977c7cdabd2853060835af226f3pbos@webrtc.orgChannel::OnReceivedPacket(int32_t id,
5089213521ea98b0977c7cdabd2853060835af226f3pbos@webrtc.org                          RtpRtcpPacketType packetType)
509470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com{
510470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
511470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                 "Channel::OnReceivedPacket(id=%d, packetType=%d)",
512470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                 id, packetType);
513470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
514ceb148ce593627ed0d30a1a8c01752bdebf9172dandrew@webrtc.org    assert(VoEChannelId(id) == _channelId);
515470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
516470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    // Notify only for the case when we have restarted an RTP session.
517470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    if (_rtpPacketTimedOut && (kPacketRtp == packetType))
518470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
5199a065d1eae9ed296e1e2eaaad73d7ca1223bfe79mflodman@webrtc.org        CriticalSectionScoped cs(_callbackCritSectPtr);
520470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        if (_voiceEngineObserverPtr)
521470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        {
5226141e13873d0fdea626de08dfec2efa2c9171c76pbos@webrtc.org            int32_t channel = VoEChannelId(id);
523470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            assert(channel == _channelId);
524470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            // Reset timeout mechanism
525470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            _rtpPacketTimedOut = false;
526470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            // Deliver callback to the observer
527470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            WEBRTC_TRACE(kTraceInfo, kTraceVoice,
528470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                         VoEId(_instanceId,_channelId),
529470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                         "Channel::OnPacketTimeout() =>"
530470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                         " CallbackOnError(VE_PACKET_RECEIPT_RESTARTED)");
531470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            _voiceEngineObserverPtr->CallbackOnError(
532470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                channel,
533470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                VE_PACKET_RECEIPT_RESTARTED);
534470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        }
535470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
536470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com}
537470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
538470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.comvoid
5399213521ea98b0977c7cdabd2853060835af226f3pbos@webrtc.orgChannel::OnPeriodicDeadOrAlive(int32_t id,
5409213521ea98b0977c7cdabd2853060835af226f3pbos@webrtc.org                               RTPAliveType alive)
541470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com{
542470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
543470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                 "Channel::OnPeriodicDeadOrAlive(id=%d, alive=%d)", id, alive);
544470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
54519da719a5febb4baa6e5dcdef8270792f9d31d6dhenrika@webrtc.org    {
54619da719a5febb4baa6e5dcdef8270792f9d31d6dhenrika@webrtc.org        CriticalSectionScoped cs(&_callbackCritSect);
54719da719a5febb4baa6e5dcdef8270792f9d31d6dhenrika@webrtc.org        if (!_connectionObserver)
54819da719a5febb4baa6e5dcdef8270792f9d31d6dhenrika@webrtc.org            return;
54919da719a5febb4baa6e5dcdef8270792f9d31d6dhenrika@webrtc.org    }
550470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
5516141e13873d0fdea626de08dfec2efa2c9171c76pbos@webrtc.org    int32_t channel = VoEChannelId(id);
552470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    assert(channel == _channelId);
553470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
554470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    // Use Alive as default to limit risk of false Dead detections
555470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    bool isAlive(true);
556470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
557470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    // Always mark the connection as Dead when the module reports kRtpDead
558470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    if (kRtpDead == alive)
559470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
560470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        isAlive = false;
561470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
562470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
563470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    // It is possible that the connection is alive even if no RTP packet has
564470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    // been received for a long time since the other side might use VAD/DTX
565470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    // and a low SID-packet update rate.
566470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    if ((kRtpNoRtp == alive) && _playing)
567470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
568470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        // Detect Alive for all NetEQ states except for the case when we are
569470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        // in PLC_CNG state.
570470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        // PLC_CNG <=> background noise only due to long expand or error.
571470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        // Note that, the case where the other side stops sending during CNG
572470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        // state will be detected as Alive. Dead is is not set until after
573470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        // missing RTCP packets for at least twelve seconds (handled
574470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        // internally by the RTP/RTCP module).
575470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        isAlive = (_outputSpeechType != AudioFrame::kPLCCNG);
576470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
577470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
578470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    UpdateDeadOrAliveCounters(isAlive);
579470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
580470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    // Send callback to the registered observer
581470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    if (_connectionObserver)
582470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
5839a065d1eae9ed296e1e2eaaad73d7ca1223bfe79mflodman@webrtc.org        CriticalSectionScoped cs(&_callbackCritSect);
584470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        if (_connectionObserverPtr)
585470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        {
586470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            _connectionObserverPtr->OnPeriodicDeadOrAlive(channel, isAlive);
587470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        }
588470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
589470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com}
590470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
5916141e13873d0fdea626de08dfec2efa2c9171c76pbos@webrtc.orgint32_t
5926141e13873d0fdea626de08dfec2efa2c9171c76pbos@webrtc.orgChannel::OnReceivedPayloadData(const uint8_t* payloadData,
5939213521ea98b0977c7cdabd2853060835af226f3pbos@webrtc.org                               uint16_t payloadSize,
594470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                               const WebRtcRTPHeader* rtpHeader)
595470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com{
596470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
597470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                 "Channel::OnReceivedPayloadData(payloadSize=%d,"
598470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                 " payloadType=%u, audioChannel=%u)",
599470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                 payloadSize,
600470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                 rtpHeader->header.payloadType,
601470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                 rtpHeader->type.Audio.channel);
602470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
6030870f02cdbcce7de8c6a4dceb6d1678c2c6c518froosa@google.com    _lastRemoteTimeStamp = rtpHeader->header.timestamp;
6040870f02cdbcce7de8c6a4dceb6d1678c2c6c518froosa@google.com
605470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    if (!_playing)
606470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
607470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        // Avoid inserting into NetEQ when we are not playing. Count the
608470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        // packet as discarded.
609470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        WEBRTC_TRACE(kTraceStream, kTraceVoice,
610470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                     VoEId(_instanceId, _channelId),
611470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                     "received packet is discarded since playing is not"
612470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                     " activated");
613470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        _numberOfDiscardedPackets++;
614470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        return 0;
615470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
616470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
617470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    // Push the incoming payload (parsed and ready for decoding) into the ACM
61816b6b90a82b796460bb20762761182c7d104cd2dtina.legrand@webrtc.org    if (_audioCodingModule.IncomingPacket(payloadData,
619470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                                          payloadSize,
620470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                                          *rtpHeader) != 0)
621470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
622470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        _engineStatisticsPtr->SetLastError(
623470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            VE_AUDIO_CODING_MODULE_ERROR, kTraceWarning,
624470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            "Channel::OnReceivedPayloadData() unable to push data to the ACM");
625470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        return -1;
626470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
627470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
628470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    // Update the packet delay
629470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    UpdatePacketDelay(rtpHeader->header.timestamp,
630470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                      rtpHeader->header.sequenceNumber);
631470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    return 0;
632470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com}
633470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
6349213521ea98b0977c7cdabd2853060835af226f3pbos@webrtc.orgint32_t Channel::GetAudioFrame(int32_t id, AudioFrame& audioFrame)
635470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com{
636470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
637470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                 "Channel::GetAudioFrame(id=%d)", id);
638470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
639470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    // Get 10ms raw PCM data from the ACM (mixer limits output frequency)
64063a509858d3988299726640c664b699d6229a1d4andrew@webrtc.org    if (_audioCodingModule.PlayoutData10Ms(audioFrame.sample_rate_hz_,
6417a7a008031d43013b01176cfe40b0fd68c0d83b5tina.legrand@webrtc.org                                           &audioFrame) == -1)
642470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
643470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        WEBRTC_TRACE(kTraceError, kTraceVoice,
644470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                     VoEId(_instanceId,_channelId),
645470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                     "Channel::GetAudioFrame() PlayoutData10Ms() failed!");
6467859e109855b9536593892734aa65af974e6baa4andrew@webrtc.org        // In all likelihood, the audio in this frame is garbage. We return an
6477859e109855b9536593892734aa65af974e6baa4andrew@webrtc.org        // error so that the audio mixer module doesn't add it to the mix. As
6487859e109855b9536593892734aa65af974e6baa4andrew@webrtc.org        // a result, it won't be played out and the actions skipped here are
6497859e109855b9536593892734aa65af974e6baa4andrew@webrtc.org        // irrelevant.
6507859e109855b9536593892734aa65af974e6baa4andrew@webrtc.org        return -1;
651470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
652470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
653470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    if (_RxVadDetection)
654470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
655470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        UpdateRxVadDetection(audioFrame);
656470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
657470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
658470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    // Convert module ID to internal VoE channel ID
65963a509858d3988299726640c664b699d6229a1d4andrew@webrtc.org    audioFrame.id_ = VoEChannelId(audioFrame.id_);
660470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    // Store speech type for dead-or-alive detection
66163a509858d3988299726640c664b699d6229a1d4andrew@webrtc.org    _outputSpeechType = audioFrame.speech_type_;
662470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
663470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    // Perform far-end AudioProcessing module processing on the received signal
664470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    if (_rxApmIsEnabled)
665470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
666470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        ApmProcessRx(audioFrame);
667470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
668470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
669470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    // Output volume scaling
670470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    if (_outputGain < 0.99f || _outputGain > 1.01f)
671470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
672470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        AudioFrameOperations::ScaleWithSat(_outputGain, audioFrame);
673470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
674470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
675470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    // Scale left and/or right channel(s) if stereo and master balance is
676470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    // active
677470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
678470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    if (_panLeft != 1.0f || _panRight != 1.0f)
679470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
68063a509858d3988299726640c664b699d6229a1d4andrew@webrtc.org        if (audioFrame.num_channels_ == 1)
681470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        {
682470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            // Emulate stereo mode since panning is active.
683470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            // The mono signal is copied to both left and right channels here.
6844ecea3e1057eebf846af9b93abf8faf8571bc576andrew@webrtc.org            AudioFrameOperations::MonoToStereo(&audioFrame);
685470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        }
686470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        // For true stereo mode (when we are receiving a stereo signal), no
687470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        // action is needed.
688470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
689470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        // Do the panning operation (the audio frame contains stereo at this
690470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        // stage)
691470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        AudioFrameOperations::Scale(_panLeft, _panRight, audioFrame);
692470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
693470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
694470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    // Mix decoded PCM output with file if file mixing is enabled
695470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    if (_outputFilePlaying)
696470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
69763a509858d3988299726640c664b699d6229a1d4andrew@webrtc.org        MixAudioWithFile(audioFrame, audioFrame.sample_rate_hz_);
698470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
699470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
700470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    // Place channel in on-hold state (~muted) if on-hold is activated
701470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    if (_outputIsOnHold)
702470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
703470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        AudioFrameOperations::Mute(audioFrame);
704470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
705470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
706470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    // External media
707470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    if (_outputExternalMedia)
708470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
7099a065d1eae9ed296e1e2eaaad73d7ca1223bfe79mflodman@webrtc.org        CriticalSectionScoped cs(&_callbackCritSect);
71063a509858d3988299726640c664b699d6229a1d4andrew@webrtc.org        const bool isStereo = (audioFrame.num_channels_ == 2);
711470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        if (_outputExternalMediaCallbackPtr)
712470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        {
713470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            _outputExternalMediaCallbackPtr->Process(
714470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                _channelId,
715470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                kPlaybackPerChannel,
7166141e13873d0fdea626de08dfec2efa2c9171c76pbos@webrtc.org                (int16_t*)audioFrame.data_,
71763a509858d3988299726640c664b699d6229a1d4andrew@webrtc.org                audioFrame.samples_per_channel_,
71863a509858d3988299726640c664b699d6229a1d4andrew@webrtc.org                audioFrame.sample_rate_hz_,
719470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                isStereo);
720470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        }
721470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
722470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
723470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    // Record playout if enabled
724470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
7259a065d1eae9ed296e1e2eaaad73d7ca1223bfe79mflodman@webrtc.org        CriticalSectionScoped cs(&_fileCritSect);
726470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
727470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        if (_outputFileRecording && _outputFileRecorderPtr)
728470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        {
7295398d9583b713f83db843a15f8bcc2ef8df23bccniklas.enbom@webrtc.org            _outputFileRecorderPtr->RecordAudioToFile(audioFrame);
730470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        }
731470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
732470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
733470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    // Measure audio level (0-9)
734470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    _outputAudioLevel.ComputeLevel(audioFrame);
735470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
736470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    return 0;
737470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com}
738470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
7396141e13873d0fdea626de08dfec2efa2c9171c76pbos@webrtc.orgint32_t
7409213521ea98b0977c7cdabd2853060835af226f3pbos@webrtc.orgChannel::NeededFrequency(int32_t id)
741470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com{
742470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
743470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                 "Channel::NeededFrequency(id=%d)", id);
744470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
745470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    int highestNeeded = 0;
746470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
747470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    // Determine highest needed receive frequency
7486141e13873d0fdea626de08dfec2efa2c9171c76pbos@webrtc.org    int32_t receiveFrequency = _audioCodingModule.ReceiveFrequency();
749470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
750470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    // Return the bigger of playout and receive frequency in the ACM.
751470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    if (_audioCodingModule.PlayoutFrequency() > receiveFrequency)
752470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
753470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        highestNeeded = _audioCodingModule.PlayoutFrequency();
754470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
755470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    else
756470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
757470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        highestNeeded = receiveFrequency;
758470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
759470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
760470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    // Special case, if we're playing a file on the playout side
761470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    // we take that frequency into consideration as well
762470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    // This is not needed on sending side, since the codec will
763470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    // limit the spectrum anyway.
764470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    if (_outputFilePlaying)
765470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
7669a065d1eae9ed296e1e2eaaad73d7ca1223bfe79mflodman@webrtc.org        CriticalSectionScoped cs(&_fileCritSect);
767470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        if (_outputFilePlayerPtr && _outputFilePlaying)
768470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        {
769470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            if(_outputFilePlayerPtr->Frequency()>highestNeeded)
770470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            {
771470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                highestNeeded=_outputFilePlayerPtr->Frequency();
772470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            }
773470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        }
774470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
775470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
776470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    return(highestNeeded);
777470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com}
778470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
7796141e13873d0fdea626de08dfec2efa2c9171c76pbos@webrtc.orgint32_t
780470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.comChannel::CreateChannel(Channel*& channel,
7819213521ea98b0977c7cdabd2853060835af226f3pbos@webrtc.org                       int32_t channelId,
7829213521ea98b0977c7cdabd2853060835af226f3pbos@webrtc.org                       uint32_t instanceId)
783470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com{
784470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    WEBRTC_TRACE(kTraceMemory, kTraceVoice, VoEId(instanceId,channelId),
785470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                 "Channel::CreateChannel(channelId=%d, instanceId=%d)",
786470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        channelId, instanceId);
787470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
788470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    channel = new Channel(channelId, instanceId);
789470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    if (channel == NULL)
790470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
791470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        WEBRTC_TRACE(kTraceMemory, kTraceVoice,
792470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                     VoEId(instanceId,channelId),
793470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                     "Channel::CreateChannel() unable to allocate memory for"
794470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                     " channel");
795470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        return -1;
796470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
797470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    return 0;
798470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com}
799470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
800470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.comvoid
8019213521ea98b0977c7cdabd2853060835af226f3pbos@webrtc.orgChannel::PlayNotification(int32_t id, uint32_t durationMs)
802470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com{
803470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
804470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                 "Channel::PlayNotification(id=%d, durationMs=%d)",
805470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                 id, durationMs);
806470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
807470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    // Not implement yet
808470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com}
809470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
810470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.comvoid
8119213521ea98b0977c7cdabd2853060835af226f3pbos@webrtc.orgChannel::RecordNotification(int32_t id, uint32_t durationMs)
812470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com{
813470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
814470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                 "Channel::RecordNotification(id=%d, durationMs=%d)",
815470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                 id, durationMs);
816470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
817470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    // Not implement yet
818470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com}
819470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
820470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.comvoid
8219213521ea98b0977c7cdabd2853060835af226f3pbos@webrtc.orgChannel::PlayFileEnded(int32_t id)
822470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com{
823470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
824470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                 "Channel::PlayFileEnded(id=%d)", id);
825470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
826470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    if (id == _inputFilePlayerId)
827470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
8289a065d1eae9ed296e1e2eaaad73d7ca1223bfe79mflodman@webrtc.org        CriticalSectionScoped cs(&_fileCritSect);
829470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
830470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        _inputFilePlaying = false;
831470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
832470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                     VoEId(_instanceId,_channelId),
833470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                     "Channel::PlayFileEnded() => input file player module is"
834470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                     " shutdown");
835470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
836470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    else if (id == _outputFilePlayerId)
837470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
8389a065d1eae9ed296e1e2eaaad73d7ca1223bfe79mflodman@webrtc.org        CriticalSectionScoped cs(&_fileCritSect);
839470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
840470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        _outputFilePlaying = false;
841470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
842470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                     VoEId(_instanceId,_channelId),
843470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                     "Channel::PlayFileEnded() => output file player module is"
844470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                     " shutdown");
845470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
846470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com}
847470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
848470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.comvoid
8499213521ea98b0977c7cdabd2853060835af226f3pbos@webrtc.orgChannel::RecordFileEnded(int32_t id)
850470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com{
851470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
852470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                 "Channel::RecordFileEnded(id=%d)", id);
853470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
854470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    assert(id == _outputFileRecorderId);
855470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
8569a065d1eae9ed296e1e2eaaad73d7ca1223bfe79mflodman@webrtc.org    CriticalSectionScoped cs(&_fileCritSect);
857470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
858470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    _outputFileRecording = false;
859470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
860470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                 VoEId(_instanceId,_channelId),
861470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                 "Channel::RecordFileEnded() => output file recorder module is"
862470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                 " shutdown");
863470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com}
864470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
8659213521ea98b0977c7cdabd2853060835af226f3pbos@webrtc.orgChannel::Channel(int32_t channelId,
8669213521ea98b0977c7cdabd2853060835af226f3pbos@webrtc.org                 uint32_t instanceId) :
867470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    _fileCritSect(*CriticalSectionWrapper::CreateCriticalSection()),
868470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    _callbackCritSect(*CriticalSectionWrapper::CreateCriticalSection()),
869470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    _instanceId(instanceId),
87022963abffe4179e75f18a2e7be1d1c58c9518089xians@google.com    _channelId(channelId),
871470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    _audioCodingModule(*AudioCodingModule::Create(
87222963abffe4179e75f18a2e7be1d1c58c9518089xians@google.com        VoEModuleId(instanceId, channelId))),
873470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    _rtpDumpIn(*RtpDump::CreateRtpDump()),
874470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    _rtpDumpOut(*RtpDump::CreateRtpDump()),
875470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    _outputAudioLevel(),
876470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    _externalTransport(false),
877470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    _inputFilePlayerPtr(NULL),
878470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    _outputFilePlayerPtr(NULL),
879470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    _outputFileRecorderPtr(NULL),
880470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    // Avoid conflict with other channels by adding 1024 - 1026,
881470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    // won't use as much as 1024 channels.
882470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    _inputFilePlayerId(VoEModuleId(instanceId, channelId) + 1024),
883470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    _outputFilePlayerId(VoEModuleId(instanceId, channelId) + 1025),
884470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    _outputFileRecorderId(VoEModuleId(instanceId, channelId) + 1026),
885470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    _inputFilePlaying(false),
886470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    _outputFilePlaying(false),
887470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    _outputFileRecording(false),
88822963abffe4179e75f18a2e7be1d1c58c9518089xians@google.com    _inbandDtmfQueue(VoEModuleId(instanceId, channelId)),
88922963abffe4179e75f18a2e7be1d1c58c9518089xians@google.com    _inbandDtmfGenerator(VoEModuleId(instanceId, channelId)),
890470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    _inputExternalMedia(false),
89122963abffe4179e75f18a2e7be1d1c58c9518089xians@google.com    _outputExternalMedia(false),
892470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    _inputExternalMediaCallbackPtr(NULL),
893470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    _outputExternalMediaCallbackPtr(NULL),
89422963abffe4179e75f18a2e7be1d1c58c9518089xians@google.com    _encryptionRTPBufferPtr(NULL),
89522963abffe4179e75f18a2e7be1d1c58c9518089xians@google.com    _decryptionRTPBufferPtr(NULL),
89622963abffe4179e75f18a2e7be1d1c58c9518089xians@google.com    _encryptionRTCPBufferPtr(NULL),
89722963abffe4179e75f18a2e7be1d1c58c9518089xians@google.com    _decryptionRTCPBufferPtr(NULL),
89822963abffe4179e75f18a2e7be1d1c58c9518089xians@google.com    _timeStamp(0), // This is just an offset, RTP module will add it's own random offset
89922963abffe4179e75f18a2e7be1d1c58c9518089xians@google.com    _sendTelephoneEventPayloadType(106),
9001de01354e68da71bc62c81af17afeac8ed374a18pwestin@webrtc.org    playout_timestamp_rtp_(0),
9011de01354e68da71bc62c81af17afeac8ed374a18pwestin@webrtc.org    playout_timestamp_rtcp_(0),
90222963abffe4179e75f18a2e7be1d1c58c9518089xians@google.com    _numberOfDiscardedPackets(0),
90322963abffe4179e75f18a2e7be1d1c58c9518089xians@google.com    _engineStatisticsPtr(NULL),
9042919e95c2a59a087ba8297c2f551c3ebc3754c9ehenrika@webrtc.org    _outputMixerPtr(NULL),
9052919e95c2a59a087ba8297c2f551c3ebc3754c9ehenrika@webrtc.org    _transmitMixerPtr(NULL),
90622963abffe4179e75f18a2e7be1d1c58c9518089xians@google.com    _moduleProcessThreadPtr(NULL),
90722963abffe4179e75f18a2e7be1d1c58c9518089xians@google.com    _audioDeviceModulePtr(NULL),
90822963abffe4179e75f18a2e7be1d1c58c9518089xians@google.com    _voiceEngineObserverPtr(NULL),
90922963abffe4179e75f18a2e7be1d1c58c9518089xians@google.com    _callbackCritSectPtr(NULL),
91022963abffe4179e75f18a2e7be1d1c58c9518089xians@google.com    _transportPtr(NULL),
91122963abffe4179e75f18a2e7be1d1c58c9518089xians@google.com    _encryptionPtr(NULL),
912755b04a06ec4ae91ae7fb601c641e683f4e9e87dandrew@webrtc.org    _rtpAudioProc(NULL),
91322963abffe4179e75f18a2e7be1d1c58c9518089xians@google.com    _rxAudioProcessingModulePtr(NULL),
91422963abffe4179e75f18a2e7be1d1c58c9518089xians@google.com    _rxVadObserverPtr(NULL),
91522963abffe4179e75f18a2e7be1d1c58c9518089xians@google.com    _oldVadDecision(-1),
91622963abffe4179e75f18a2e7be1d1c58c9518089xians@google.com    _sendFrameType(0),
917470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    _rtpObserverPtr(NULL),
918470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    _rtcpObserverPtr(NULL),
91922963abffe4179e75f18a2e7be1d1c58c9518089xians@google.com    _outputIsOnHold(false),
92022963abffe4179e75f18a2e7be1d1c58c9518089xians@google.com    _externalPlayout(false),
9211b60ceb499ee35460886f2bfaecee1f47319f925roosa@google.com    _externalMixing(false),
92222963abffe4179e75f18a2e7be1d1c58c9518089xians@google.com    _inputIsOnHold(false),
92322963abffe4179e75f18a2e7be1d1c58c9518089xians@google.com    _playing(false),
92422963abffe4179e75f18a2e7be1d1c58c9518089xians@google.com    _sending(false),
92522963abffe4179e75f18a2e7be1d1c58c9518089xians@google.com    _receiving(false),
92622963abffe4179e75f18a2e7be1d1c58c9518089xians@google.com    _mixFileWithMicrophone(false),
92722963abffe4179e75f18a2e7be1d1c58c9518089xians@google.com    _rtpObserver(false),
92822963abffe4179e75f18a2e7be1d1c58c9518089xians@google.com    _rtcpObserver(false),
929470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    _mute(false),
930470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    _panLeft(1.0f),
931470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    _panRight(1.0f),
932470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    _outputGain(1.0f),
93322963abffe4179e75f18a2e7be1d1c58c9518089xians@google.com    _encrypting(false),
93422963abffe4179e75f18a2e7be1d1c58c9518089xians@google.com    _decrypting(false),
935470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    _playOutbandDtmfEvent(false),
936470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    _playInbandDtmfEvent(false),
937470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    _extraPayloadType(0),
938470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    _insertExtraRTPPacket(false),
939470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    _extraMarkerBit(false),
940470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    _lastLocalTimeStamp(0),
9410870f02cdbcce7de8c6a4dceb6d1678c2c6c518froosa@google.com    _lastRemoteTimeStamp(0),
942470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    _lastPayloadType(0),
94322963abffe4179e75f18a2e7be1d1c58c9518089xians@google.com    _includeAudioLevelIndication(false),
944470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    _rtpPacketTimedOut(false),
945470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    _rtpPacketTimeOutIsEnabled(false),
946470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    _rtpTimeOutSeconds(0),
947470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    _connectionObserver(false),
948470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    _connectionObserverPtr(NULL),
949470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    _countAliveDetections(0),
950470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    _countDeadDetections(0),
951470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    _outputSpeechType(AudioFrame::kNormalSpeech),
9521de01354e68da71bc62c81af17afeac8ed374a18pwestin@webrtc.org    _average_jitter_buffer_delay_us(0),
953e46c8d387587ba148e229a7bb18f1cc0708a2a87turaj@webrtc.org    least_required_delay_ms_(0),
954470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    _previousTimestamp(0),
955470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    _recPacketDelayMs(20),
956470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    _RxVadDetection(false),
957470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    _rxApmIsEnabled(false),
958470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    _rxAgcIsEnabled(false),
95922963abffe4179e75f18a2e7be1d1c58c9518089xians@google.com    _rxNsIsEnabled(false)
960470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com{
961470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    WEBRTC_TRACE(kTraceMemory, kTraceVoice, VoEId(_instanceId,_channelId),
962470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                 "Channel::Channel() - ctor");
963470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    _inbandDtmfQueue.ResetDtmf();
964470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    _inbandDtmfGenerator.Init();
965470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    _outputAudioLevel.Clear();
966470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
9672853dde5201d9ddc284ce5efb9688f6340487acepwestin@webrtc.org    RtpRtcp::Configuration configuration;
9682853dde5201d9ddc284ce5efb9688f6340487acepwestin@webrtc.org    configuration.id = VoEModuleId(instanceId, channelId);
9692853dde5201d9ddc284ce5efb9688f6340487acepwestin@webrtc.org    configuration.audio = true;
9702853dde5201d9ddc284ce5efb9688f6340487acepwestin@webrtc.org    configuration.incoming_data = this;
9712853dde5201d9ddc284ce5efb9688f6340487acepwestin@webrtc.org    configuration.incoming_messages = this;
9722853dde5201d9ddc284ce5efb9688f6340487acepwestin@webrtc.org    configuration.outgoing_transport = this;
9732853dde5201d9ddc284ce5efb9688f6340487acepwestin@webrtc.org    configuration.rtcp_feedback = this;
9742853dde5201d9ddc284ce5efb9688f6340487acepwestin@webrtc.org    configuration.audio_messages = this;
9752853dde5201d9ddc284ce5efb9688f6340487acepwestin@webrtc.org
9762853dde5201d9ddc284ce5efb9688f6340487acepwestin@webrtc.org    _rtpRtcpModule.reset(RtpRtcp::CreateRtpRtcp(configuration));
9772853dde5201d9ddc284ce5efb9688f6340487acepwestin@webrtc.org
978470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    // Create far end AudioProcessing Module
979470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    _rxAudioProcessingModulePtr = AudioProcessing::Create(
980470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        VoEModuleId(instanceId, channelId));
981470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com}
982470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
983470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.comChannel::~Channel()
984470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com{
985470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    WEBRTC_TRACE(kTraceMemory, kTraceVoice, VoEId(_instanceId,_channelId),
986470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                 "Channel::~Channel() - dtor");
987470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
988470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    if (_outputExternalMedia)
989470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
990470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        DeRegisterExternalMediaProcessing(kPlaybackPerChannel);
991470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
992470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    if (_inputExternalMedia)
993470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
994470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        DeRegisterExternalMediaProcessing(kRecordingPerChannel);
995470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
996470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    StopSend();
997470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    StopPlayout();
998470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
999470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
10009a065d1eae9ed296e1e2eaaad73d7ca1223bfe79mflodman@webrtc.org        CriticalSectionScoped cs(&_fileCritSect);
1001470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        if (_inputFilePlayerPtr)
1002470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        {
1003470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            _inputFilePlayerPtr->RegisterModuleFileCallback(NULL);
1004470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            _inputFilePlayerPtr->StopPlayingFile();
1005470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            FilePlayer::DestroyFilePlayer(_inputFilePlayerPtr);
1006470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            _inputFilePlayerPtr = NULL;
1007470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        }
1008470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        if (_outputFilePlayerPtr)
1009470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        {
1010470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            _outputFilePlayerPtr->RegisterModuleFileCallback(NULL);
1011470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            _outputFilePlayerPtr->StopPlayingFile();
1012470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            FilePlayer::DestroyFilePlayer(_outputFilePlayerPtr);
1013470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            _outputFilePlayerPtr = NULL;
1014470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        }
1015470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        if (_outputFileRecorderPtr)
1016470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        {
1017470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            _outputFileRecorderPtr->RegisterModuleFileCallback(NULL);
1018470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            _outputFileRecorderPtr->StopRecording();
1019470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            FileRecorder::DestroyFileRecorder(_outputFileRecorderPtr);
1020470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            _outputFileRecorderPtr = NULL;
1021470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        }
1022470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
1023470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
1024470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    // The order to safely shutdown modules in a channel is:
1025470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    // 1. De-register callbacks in modules
1026470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    // 2. De-register modules in process thread
1027470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    // 3. Destroy modules
1028470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    if (_audioCodingModule.RegisterTransportCallback(NULL) == -1)
1029470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
1030470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        WEBRTC_TRACE(kTraceWarning, kTraceVoice,
1031470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                     VoEId(_instanceId,_channelId),
1032470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                     "~Channel() failed to de-register transport callback"
1033470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                     " (Audio coding module)");
1034470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
1035470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    if (_audioCodingModule.RegisterVADCallback(NULL) == -1)
1036470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
1037470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        WEBRTC_TRACE(kTraceWarning, kTraceVoice,
1038470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                     VoEId(_instanceId,_channelId),
1039470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                     "~Channel() failed to de-register VAD callback"
1040470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                     " (Audio coding module)");
1041470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
1042470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    // De-register modules in process thread
10432853dde5201d9ddc284ce5efb9688f6340487acepwestin@webrtc.org    if (_moduleProcessThreadPtr->DeRegisterModule(_rtpRtcpModule.get()) == -1)
1044470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
1045470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        WEBRTC_TRACE(kTraceInfo, kTraceVoice,
1046470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                     VoEId(_instanceId,_channelId),
1047470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                     "~Channel() failed to deregister RTP/RTCP module");
1048470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
1049470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
1050470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    // Destroy modules
1051470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    AudioCodingModule::Destroy(&_audioCodingModule);
1052470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    if (_rxAudioProcessingModulePtr != NULL)
1053470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
1054470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        AudioProcessing::Destroy(_rxAudioProcessingModulePtr); // far end APM
1055470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        _rxAudioProcessingModulePtr = NULL;
1056470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
1057470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
1058470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    // End of modules shutdown
1059470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
1060470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    // Delete other objects
1061470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    RtpDump::DestroyRtpDump(&_rtpDumpIn);
1062470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    RtpDump::DestroyRtpDump(&_rtpDumpOut);
1063470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    delete [] _encryptionRTPBufferPtr;
1064470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    delete [] _decryptionRTPBufferPtr;
1065470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    delete [] _encryptionRTCPBufferPtr;
1066470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    delete [] _decryptionRTCPBufferPtr;
1067470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    delete &_callbackCritSect;
1068470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    delete &_fileCritSect;
1069470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com}
1070470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
10716141e13873d0fdea626de08dfec2efa2c9171c76pbos@webrtc.orgint32_t
1072470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.comChannel::Init()
1073470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com{
1074470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1075470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                 "Channel::Init()");
1076470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
1077470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    // --- Initial sanity
1078470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
1079470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    if ((_engineStatisticsPtr == NULL) ||
1080470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        (_moduleProcessThreadPtr == NULL))
1081470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
1082470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        WEBRTC_TRACE(kTraceError, kTraceVoice,
1083470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                     VoEId(_instanceId,_channelId),
1084470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                     "Channel::Init() must call SetEngineInformation() first");
1085470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        return -1;
1086470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
1087470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
1088470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    // --- Add modules to process thread (for periodic schedulation)
1089470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
1090470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    const bool processThreadFail =
10912853dde5201d9ddc284ce5efb9688f6340487acepwestin@webrtc.org        ((_moduleProcessThreadPtr->RegisterModule(_rtpRtcpModule.get()) != 0) ||
1092470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        false);
1093470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    if (processThreadFail)
1094470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
1095470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        _engineStatisticsPtr->SetLastError(
1096470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            VE_CANNOT_INIT_CHANNEL, kTraceError,
1097470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            "Channel::Init() modules not registered");
1098470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        return -1;
1099470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
1100c450a1966965fbb3c16ec6d02c3d5cbec67df500pwestin@webrtc.org    // --- ACM initialization
1101470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
1102470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    if ((_audioCodingModule.InitializeReceiver() == -1) ||
1103470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com#ifdef WEBRTC_CODEC_AVT
1104470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        // out-of-band Dtmf tones are played out by default
1105470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        (_audioCodingModule.SetDtmfPlayoutStatus(true) == -1) ||
1106470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com#endif
1107470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        (_audioCodingModule.InitializeSender() == -1))
1108470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
1109470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        _engineStatisticsPtr->SetLastError(
1110470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
1111470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            "Channel::Init() unable to initialize the ACM - 1");
1112470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        return -1;
1113470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
1114470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
1115470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    // --- RTP/RTCP module initialization
1116470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
1117470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    // Ensure that RTCP is enabled by default for the created channel.
1118470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    // Note that, the module will keep generating RTCP until it is explicitly
1119470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    // disabled by the user.
1120470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    // After StopListen (when no sockets exists), RTCP packets will no longer
1121470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    // be transmitted since the Transport object will then be invalid.
1122470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
1123470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    const bool rtpRtcpFail =
1124b7edd065306329309dac6767fe4914c185f941f8turaj@webrtc.org        ((_rtpRtcpModule->SetTelephoneEventForwardToDecoder(true) == -1) ||
1125470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        // RTCP is enabled by default
11262853dde5201d9ddc284ce5efb9688f6340487acepwestin@webrtc.org        (_rtpRtcpModule->SetRTCPStatus(kRtcpCompound) == -1));
1127470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    if (rtpRtcpFail)
1128470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
1129470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        _engineStatisticsPtr->SetLastError(
1130470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            VE_RTP_RTCP_MODULE_ERROR, kTraceError,
1131470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            "Channel::Init() RTP/RTCP module not initialized");
1132470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        return -1;
1133470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
1134470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
1135470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com     // --- Register all permanent callbacks
1136470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    const bool fail =
1137470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        (_audioCodingModule.RegisterTransportCallback(this) == -1) ||
1138470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        (_audioCodingModule.RegisterVADCallback(this) == -1);
1139470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
1140470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    if (fail)
1141470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
1142470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        _engineStatisticsPtr->SetLastError(
1143470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            VE_CANNOT_INIT_CHANNEL, kTraceError,
1144470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            "Channel::Init() callbacks not registered");
1145470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        return -1;
1146470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
1147470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
1148470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    // --- Register all supported codecs to the receiving side of the
1149470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    // RTP/RTCP module
1150470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
1151470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    CodecInst codec;
11526141e13873d0fdea626de08dfec2efa2c9171c76pbos@webrtc.org    const uint8_t nSupportedCodecs = AudioCodingModule::NumberOfCodecs();
1153470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
1154470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    for (int idx = 0; idx < nSupportedCodecs; idx++)
1155470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
1156470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        // Open up the RTP/RTCP receiver for all supported codecs
11577a7a008031d43013b01176cfe40b0fd68c0d83b5tina.legrand@webrtc.org        if ((_audioCodingModule.Codec(idx, &codec) == -1) ||
11582853dde5201d9ddc284ce5efb9688f6340487acepwestin@webrtc.org            (_rtpRtcpModule->RegisterReceivePayload(codec) == -1))
1159470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        {
1160470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            WEBRTC_TRACE(kTraceWarning, kTraceVoice,
1161470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                         VoEId(_instanceId,_channelId),
1162470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                         "Channel::Init() unable to register %s (%d/%d/%d/%d) "
1163470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                         "to RTP/RTCP receiver",
1164470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                         codec.plname, codec.pltype, codec.plfreq,
1165470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                         codec.channels, codec.rate);
1166470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        }
1167470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        else
1168470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        {
1169470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            WEBRTC_TRACE(kTraceInfo, kTraceVoice,
1170470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                         VoEId(_instanceId,_channelId),
1171470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                         "Channel::Init() %s (%d/%d/%d/%d) has been added to "
1172470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                         "the RTP/RTCP receiver",
1173470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                         codec.plname, codec.pltype, codec.plfreq,
1174470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                         codec.channels, codec.rate);
1175470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        }
1176470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
1177470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        // Ensure that PCMU is used as default codec on the sending side
11784517585db5f2f2a14fdd56a96f4b44f745967c8ctina.legrand@webrtc.org        if (!STR_CASE_CMP(codec.plname, "PCMU") && (codec.channels == 1))
1179470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        {
1180470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            SetSendCodec(codec);
1181470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        }
1182470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
1183470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        // Register default PT for outband 'telephone-event'
1184470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        if (!STR_CASE_CMP(codec.plname, "telephone-event"))
1185470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        {
11862853dde5201d9ddc284ce5efb9688f6340487acepwestin@webrtc.org            if ((_rtpRtcpModule->RegisterSendPayload(codec) == -1) ||
1187470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                (_audioCodingModule.RegisterReceiveCodec(codec) == -1))
1188470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            {
1189470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                WEBRTC_TRACE(kTraceWarning, kTraceVoice,
1190470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                             VoEId(_instanceId,_channelId),
1191470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                             "Channel::Init() failed to register outband "
1192470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                             "'telephone-event' (%d/%d) correctly",
1193470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                             codec.pltype, codec.plfreq);
1194470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            }
1195470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        }
1196470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
1197470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        if (!STR_CASE_CMP(codec.plname, "CN"))
1198470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        {
1199470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            if ((_audioCodingModule.RegisterSendCodec(codec) == -1) ||
1200470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                (_audioCodingModule.RegisterReceiveCodec(codec) == -1) ||
12012853dde5201d9ddc284ce5efb9688f6340487acepwestin@webrtc.org                (_rtpRtcpModule->RegisterSendPayload(codec) == -1))
1202470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            {
1203470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                WEBRTC_TRACE(kTraceWarning, kTraceVoice,
1204470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                             VoEId(_instanceId,_channelId),
1205470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                             "Channel::Init() failed to register CN (%d/%d) "
1206470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                             "correctly - 1",
1207470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                             codec.pltype, codec.plfreq);
1208470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            }
1209470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        }
1210470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com#ifdef WEBRTC_CODEC_RED
1211470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        // Register RED to the receiving side of the ACM.
1212470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        // We will not receive an OnInitializeDecoder() callback for RED.
1213470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        if (!STR_CASE_CMP(codec.plname, "RED"))
1214470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        {
1215470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            if (_audioCodingModule.RegisterReceiveCodec(codec) == -1)
1216470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            {
1217470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                WEBRTC_TRACE(kTraceWarning, kTraceVoice,
1218470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                             VoEId(_instanceId,_channelId),
1219470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                             "Channel::Init() failed to register RED (%d/%d) "
1220470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                             "correctly",
1221470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                             codec.pltype, codec.plfreq);
1222470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            }
1223470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        }
1224470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com#endif
1225470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
1226684f0577fbe4ea393fef1dddf2ca7d02e3205b49pwestin@webrtc.org
1227470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    // Initialize the far end AP module
1228470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    // Using 8 kHz as initial Fs, the same as in transmission. Might be
1229470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    // changed at the first receiving audio.
1230470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    if (_rxAudioProcessingModulePtr == NULL)
1231470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
1232470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        _engineStatisticsPtr->SetLastError(
1233470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            VE_NO_MEMORY, kTraceCritical,
1234470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            "Channel::Init() failed to create the far-end AudioProcessing"
1235470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            " module");
1236470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        return -1;
1237470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
1238470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
1239470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    if (_rxAudioProcessingModulePtr->set_sample_rate_hz(8000))
1240470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
1241470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        _engineStatisticsPtr->SetLastError(
1242470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            VE_APM_ERROR, kTraceWarning,
1243470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            "Channel::Init() failed to set the sample rate to 8K for"
1244470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            " far-end AP module");
1245470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
1246470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
1247470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    if (_rxAudioProcessingModulePtr->set_num_channels(1, 1) != 0)
1248470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
1249470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        _engineStatisticsPtr->SetLastError(
1250470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            VE_SOUNDCARD_ERROR, kTraceWarning,
1251755b04a06ec4ae91ae7fb601c641e683f4e9e87dandrew@webrtc.org            "Init() failed to set channels for the primary audio stream");
1252470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
1253470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
1254470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    if (_rxAudioProcessingModulePtr->high_pass_filter()->Enable(
1255470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        WEBRTC_VOICE_ENGINE_RX_HP_DEFAULT_STATE) != 0)
1256470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
1257470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        _engineStatisticsPtr->SetLastError(
1258470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            VE_APM_ERROR, kTraceWarning,
1259470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            "Channel::Init() failed to set the high-pass filter for"
1260fcd12b3b7d7e92d6f8cdfdf8277808ae52a07c36wu@webrtc.org            " far-end AP module");
1261470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
1262470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
1263470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    if (_rxAudioProcessingModulePtr->noise_suppression()->set_level(
1264470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        (NoiseSuppression::Level)WEBRTC_VOICE_ENGINE_RX_NS_DEFAULT_MODE) != 0)
1265470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
1266470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        _engineStatisticsPtr->SetLastError(
1267470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            VE_APM_ERROR, kTraceWarning,
1268470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            "Init() failed to set noise reduction level for far-end"
1269fcd12b3b7d7e92d6f8cdfdf8277808ae52a07c36wu@webrtc.org            " AP module");
1270470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
1271470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    if (_rxAudioProcessingModulePtr->noise_suppression()->Enable(
1272470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        WEBRTC_VOICE_ENGINE_RX_NS_DEFAULT_STATE) != 0)
1273470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
1274470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        _engineStatisticsPtr->SetLastError(
1275470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            VE_APM_ERROR, kTraceWarning,
1276470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            "Init() failed to set noise reduction state for far-end"
1277fcd12b3b7d7e92d6f8cdfdf8277808ae52a07c36wu@webrtc.org            " AP module");
1278470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
1279470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
1280470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    if (_rxAudioProcessingModulePtr->gain_control()->set_mode(
1281470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        (GainControl::Mode)WEBRTC_VOICE_ENGINE_RX_AGC_DEFAULT_MODE) != 0)
1282470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
1283470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        _engineStatisticsPtr->SetLastError(
1284470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            VE_APM_ERROR, kTraceWarning,
1285470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            "Init() failed to set AGC mode for far-end AP module");
1286470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
1287470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    if (_rxAudioProcessingModulePtr->gain_control()->Enable(
1288470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        WEBRTC_VOICE_ENGINE_RX_AGC_DEFAULT_STATE) != 0)
1289470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
1290470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        _engineStatisticsPtr->SetLastError(
1291470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            VE_APM_ERROR, kTraceWarning,
1292470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            "Init() failed to set AGC state for far-end AP module");
1293470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
1294470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
1295470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    return 0;
1296470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com}
1297470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
12986141e13873d0fdea626de08dfec2efa2c9171c76pbos@webrtc.orgint32_t
1299470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.comChannel::SetEngineInformation(Statistics& engineStatistics,
1300470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                              OutputMixer& outputMixer,
1301470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                              voe::TransmitMixer& transmitMixer,
1302470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                              ProcessThread& moduleProcessThread,
1303470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                              AudioDeviceModule& audioDeviceModule,
1304470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                              VoiceEngineObserver* voiceEngineObserver,
1305470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                              CriticalSectionWrapper* callbackCritSect)
1306470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com{
1307470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1308470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                 "Channel::SetEngineInformation()");
1309470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    _engineStatisticsPtr = &engineStatistics;
1310470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    _outputMixerPtr = &outputMixer;
1311470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    _transmitMixerPtr = &transmitMixer,
1312470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    _moduleProcessThreadPtr = &moduleProcessThread;
1313470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    _audioDeviceModulePtr = &audioDeviceModule;
1314470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    _voiceEngineObserverPtr = voiceEngineObserver;
1315470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    _callbackCritSectPtr = callbackCritSect;
1316470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    return 0;
1317470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com}
1318470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
13196141e13873d0fdea626de08dfec2efa2c9171c76pbos@webrtc.orgint32_t
1320470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.comChannel::UpdateLocalTimeStamp()
1321470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com{
1322470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
132363a509858d3988299726640c664b699d6229a1d4andrew@webrtc.org    _timeStamp += _audioFrame.samples_per_channel_;
1324470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    return 0;
1325470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com}
1326470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
13276141e13873d0fdea626de08dfec2efa2c9171c76pbos@webrtc.orgint32_t
1328470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.comChannel::StartPlayout()
1329470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com{
1330470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1331470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                 "Channel::StartPlayout()");
1332470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    if (_playing)
1333470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
1334470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        return 0;
1335470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
13361b60ceb499ee35460886f2bfaecee1f47319f925roosa@google.com
13371b60ceb499ee35460886f2bfaecee1f47319f925roosa@google.com    if (!_externalMixing) {
13381b60ceb499ee35460886f2bfaecee1f47319f925roosa@google.com        // Add participant as candidates for mixing.
13391b60ceb499ee35460886f2bfaecee1f47319f925roosa@google.com        if (_outputMixerPtr->SetMixabilityStatus(*this, true) != 0)
13401b60ceb499ee35460886f2bfaecee1f47319f925roosa@google.com        {
13411b60ceb499ee35460886f2bfaecee1f47319f925roosa@google.com            _engineStatisticsPtr->SetLastError(
13421b60ceb499ee35460886f2bfaecee1f47319f925roosa@google.com                VE_AUDIO_CONF_MIX_MODULE_ERROR, kTraceError,
13431b60ceb499ee35460886f2bfaecee1f47319f925roosa@google.com                "StartPlayout() failed to add participant to mixer");
13441b60ceb499ee35460886f2bfaecee1f47319f925roosa@google.com            return -1;
13451b60ceb499ee35460886f2bfaecee1f47319f925roosa@google.com        }
1346470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
1347470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
1348470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    _playing = true;
1349ab12990b1b8c2410b34c055e73ed04e8a7ee1d85braveyao@webrtc.org
1350ab12990b1b8c2410b34c055e73ed04e8a7ee1d85braveyao@webrtc.org    if (RegisterFilePlayingToMixer() != 0)
1351ab12990b1b8c2410b34c055e73ed04e8a7ee1d85braveyao@webrtc.org        return -1;
1352ab12990b1b8c2410b34c055e73ed04e8a7ee1d85braveyao@webrtc.org
1353470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    return 0;
1354470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com}
1355470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
13566141e13873d0fdea626de08dfec2efa2c9171c76pbos@webrtc.orgint32_t
1357470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.comChannel::StopPlayout()
1358470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com{
1359470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1360470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                 "Channel::StopPlayout()");
1361470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    if (!_playing)
1362470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
1363470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        return 0;
1364470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
13651b60ceb499ee35460886f2bfaecee1f47319f925roosa@google.com
13661b60ceb499ee35460886f2bfaecee1f47319f925roosa@google.com    if (!_externalMixing) {
13671b60ceb499ee35460886f2bfaecee1f47319f925roosa@google.com        // Remove participant as candidates for mixing
13681b60ceb499ee35460886f2bfaecee1f47319f925roosa@google.com        if (_outputMixerPtr->SetMixabilityStatus(*this, false) != 0)
13691b60ceb499ee35460886f2bfaecee1f47319f925roosa@google.com        {
13701b60ceb499ee35460886f2bfaecee1f47319f925roosa@google.com            _engineStatisticsPtr->SetLastError(
13711b60ceb499ee35460886f2bfaecee1f47319f925roosa@google.com                VE_AUDIO_CONF_MIX_MODULE_ERROR, kTraceError,
13721b60ceb499ee35460886f2bfaecee1f47319f925roosa@google.com                "StopPlayout() failed to remove participant from mixer");
13731b60ceb499ee35460886f2bfaecee1f47319f925roosa@google.com            return -1;
13741b60ceb499ee35460886f2bfaecee1f47319f925roosa@google.com        }
1375470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
1376470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
1377470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    _playing = false;
1378470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    _outputAudioLevel.Clear();
1379470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
1380470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    return 0;
1381470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com}
1382470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
13836141e13873d0fdea626de08dfec2efa2c9171c76pbos@webrtc.orgint32_t
1384470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.comChannel::StartSend()
1385470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com{
1386470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1387470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                 "Channel::StartSend()");
1388470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
1389e07247af8d0888529e14156a9929cbd2376f8442xians@webrtc.org        // A lock is needed because |_sending| can be accessed or modified by
1390e07247af8d0888529e14156a9929cbd2376f8442xians@webrtc.org        // another thread at the same time.
13919a065d1eae9ed296e1e2eaaad73d7ca1223bfe79mflodman@webrtc.org        CriticalSectionScoped cs(&_callbackCritSect);
1392e07247af8d0888529e14156a9929cbd2376f8442xians@webrtc.org
1393e07247af8d0888529e14156a9929cbd2376f8442xians@webrtc.org        if (_sending)
1394e07247af8d0888529e14156a9929cbd2376f8442xians@webrtc.org        {
1395e07247af8d0888529e14156a9929cbd2376f8442xians@webrtc.org            return 0;
1396e07247af8d0888529e14156a9929cbd2376f8442xians@webrtc.org        }
1397e07247af8d0888529e14156a9929cbd2376f8442xians@webrtc.org        _sending = true;
1398470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
1399e07247af8d0888529e14156a9929cbd2376f8442xians@webrtc.org
14002853dde5201d9ddc284ce5efb9688f6340487acepwestin@webrtc.org    if (_rtpRtcpModule->SetSendingStatus(true) != 0)
1401470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
1402470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        _engineStatisticsPtr->SetLastError(
1403470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            VE_RTP_RTCP_MODULE_ERROR, kTraceError,
1404470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            "StartSend() RTP/RTCP failed to start sending");
14059a065d1eae9ed296e1e2eaaad73d7ca1223bfe79mflodman@webrtc.org        CriticalSectionScoped cs(&_callbackCritSect);
1406e07247af8d0888529e14156a9929cbd2376f8442xians@webrtc.org        _sending = false;
1407470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        return -1;
1408470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
1409e07247af8d0888529e14156a9929cbd2376f8442xians@webrtc.org
1410470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    return 0;
1411470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com}
1412470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
14136141e13873d0fdea626de08dfec2efa2c9171c76pbos@webrtc.orgint32_t
1414470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.comChannel::StopSend()
1415470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com{
1416470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1417470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                 "Channel::StopSend()");
1418470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
1419e07247af8d0888529e14156a9929cbd2376f8442xians@webrtc.org        // A lock is needed because |_sending| can be accessed or modified by
1420e07247af8d0888529e14156a9929cbd2376f8442xians@webrtc.org        // another thread at the same time.
14219a065d1eae9ed296e1e2eaaad73d7ca1223bfe79mflodman@webrtc.org        CriticalSectionScoped cs(&_callbackCritSect);
1422e07247af8d0888529e14156a9929cbd2376f8442xians@webrtc.org
1423e07247af8d0888529e14156a9929cbd2376f8442xians@webrtc.org        if (!_sending)
1424e07247af8d0888529e14156a9929cbd2376f8442xians@webrtc.org        {
1425e07247af8d0888529e14156a9929cbd2376f8442xians@webrtc.org            return 0;
1426e07247af8d0888529e14156a9929cbd2376f8442xians@webrtc.org        }
1427e07247af8d0888529e14156a9929cbd2376f8442xians@webrtc.org        _sending = false;
1428470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
1429e07247af8d0888529e14156a9929cbd2376f8442xians@webrtc.org
1430470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    // Reset sending SSRC and sequence number and triggers direct transmission
1431470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    // of RTCP BYE
14322853dde5201d9ddc284ce5efb9688f6340487acepwestin@webrtc.org    if (_rtpRtcpModule->SetSendingStatus(false) == -1 ||
14332853dde5201d9ddc284ce5efb9688f6340487acepwestin@webrtc.org        _rtpRtcpModule->ResetSendDataCountersRTP() == -1)
1434470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
1435470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        _engineStatisticsPtr->SetLastError(
1436470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            VE_RTP_RTCP_MODULE_ERROR, kTraceWarning,
1437470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            "StartSend() RTP/RTCP failed to stop sending");
1438470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
1439470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
1440470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    return 0;
1441470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com}
1442470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
14436141e13873d0fdea626de08dfec2efa2c9171c76pbos@webrtc.orgint32_t
1444470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.comChannel::StartReceiving()
1445470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com{
1446470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1447470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                 "Channel::StartReceiving()");
1448470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    if (_receiving)
1449470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
1450470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        return 0;
1451470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
1452470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    _receiving = true;
1453470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    _numberOfDiscardedPackets = 0;
1454470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    return 0;
1455470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com}
1456470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
14576141e13873d0fdea626de08dfec2efa2c9171c76pbos@webrtc.orgint32_t
1458470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.comChannel::StopReceiving()
1459470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com{
1460470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1461470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                 "Channel::StopReceiving()");
1462470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    if (!_receiving)
1463470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
1464470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        return 0;
1465470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
1466684f0577fbe4ea393fef1dddf2ca7d02e3205b49pwestin@webrtc.org
1467af71f0e5d98d894b22969d4714821b54218bc083henrika@webrtc.org    // Recover DTMF detection status.
14686141e13873d0fdea626de08dfec2efa2c9171c76pbos@webrtc.org    int32_t ret = _rtpRtcpModule->SetTelephoneEventForwardToDecoder(true);
1469af71f0e5d98d894b22969d4714821b54218bc083henrika@webrtc.org    if (ret != 0) {
1470af71f0e5d98d894b22969d4714821b54218bc083henrika@webrtc.org        _engineStatisticsPtr->SetLastError(
1471af71f0e5d98d894b22969d4714821b54218bc083henrika@webrtc.org            VE_INVALID_OPERATION, kTraceWarning,
1472af71f0e5d98d894b22969d4714821b54218bc083henrika@webrtc.org            "StopReceiving() failed to restore telephone-event status.");
1473af71f0e5d98d894b22969d4714821b54218bc083henrika@webrtc.org    }
1474470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    RegisterReceiveCodecsToRTPModule();
1475470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    _receiving = false;
1476470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    return 0;
1477470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com}
1478470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
14796141e13873d0fdea626de08dfec2efa2c9171c76pbos@webrtc.orgint32_t
1480470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.comChannel::SetNetEQPlayoutMode(NetEqModes mode)
1481470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com{
1482470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1483470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                 "Channel::SetNetEQPlayoutMode()");
1484470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    AudioPlayoutMode playoutMode(voice);
1485470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    switch (mode)
1486470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
1487470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        case kNetEqDefault:
1488470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            playoutMode = voice;
1489470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            break;
1490470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        case kNetEqStreaming:
1491470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            playoutMode = streaming;
1492470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            break;
1493470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        case kNetEqFax:
1494470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            playoutMode = fax;
1495470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            break;
1496b718619f0ab1ad984e334dd90f67e08bb6d80af3roosa@google.com        case kNetEqOff:
1497b718619f0ab1ad984e334dd90f67e08bb6d80af3roosa@google.com            playoutMode = off;
1498b718619f0ab1ad984e334dd90f67e08bb6d80af3roosa@google.com            break;
1499470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
1500470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    if (_audioCodingModule.SetPlayoutMode(playoutMode) != 0)
1501470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
1502470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        _engineStatisticsPtr->SetLastError(
1503470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
1504470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            "SetNetEQPlayoutMode() failed to set playout mode");
1505470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        return -1;
1506470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
1507470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    return 0;
1508470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com}
1509470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
15106141e13873d0fdea626de08dfec2efa2c9171c76pbos@webrtc.orgint32_t
1511470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.comChannel::GetNetEQPlayoutMode(NetEqModes& mode)
1512470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com{
1513470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    const AudioPlayoutMode playoutMode = _audioCodingModule.PlayoutMode();
1514470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    switch (playoutMode)
1515470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
1516470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        case voice:
1517470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            mode = kNetEqDefault;
1518470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            break;
1519470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        case streaming:
1520470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            mode = kNetEqStreaming;
1521470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            break;
1522470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        case fax:
1523470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            mode = kNetEqFax;
1524470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            break;
1525b718619f0ab1ad984e334dd90f67e08bb6d80af3roosa@google.com        case off:
1526b718619f0ab1ad984e334dd90f67e08bb6d80af3roosa@google.com            mode = kNetEqOff;
1527470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
1528470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
1529470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                 VoEId(_instanceId,_channelId),
1530470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                 "Channel::GetNetEQPlayoutMode() => mode=%u", mode);
1531470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    return 0;
1532470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com}
1533470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
15346141e13873d0fdea626de08dfec2efa2c9171c76pbos@webrtc.orgint32_t
1535470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.comChannel::SetOnHoldStatus(bool enable, OnHoldModes mode)
1536470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com{
1537470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1538470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                 "Channel::SetOnHoldStatus()");
1539470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    if (mode == kHoldSendAndPlay)
1540470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
1541470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        _outputIsOnHold = enable;
1542470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        _inputIsOnHold = enable;
1543470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
1544470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    else if (mode == kHoldPlayOnly)
1545470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
1546470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        _outputIsOnHold = enable;
1547470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
1548470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    if (mode == kHoldSendOnly)
1549470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
1550470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        _inputIsOnHold = enable;
1551470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
1552470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    return 0;
1553470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com}
1554470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
15556141e13873d0fdea626de08dfec2efa2c9171c76pbos@webrtc.orgint32_t
1556470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.comChannel::GetOnHoldStatus(bool& enabled, OnHoldModes& mode)
1557470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com{
1558470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1559470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                 "Channel::GetOnHoldStatus()");
1560470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    enabled = (_outputIsOnHold || _inputIsOnHold);
1561470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    if (_outputIsOnHold && _inputIsOnHold)
1562470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
1563470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        mode = kHoldSendAndPlay;
1564470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
1565470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    else if (_outputIsOnHold && !_inputIsOnHold)
1566470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
1567470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        mode = kHoldPlayOnly;
1568470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
1569470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    else if (!_outputIsOnHold && _inputIsOnHold)
1570470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
1571470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        mode = kHoldSendOnly;
1572470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
1573470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    WEBRTC_TRACE(kTraceStateInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1574470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                 "Channel::GetOnHoldStatus() => enabled=%d, mode=%d",
1575470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                 enabled, mode);
1576470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    return 0;
1577470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com}
1578470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
15796141e13873d0fdea626de08dfec2efa2c9171c76pbos@webrtc.orgint32_t
1580470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.comChannel::RegisterVoiceEngineObserver(VoiceEngineObserver& observer)
1581470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com{
1582470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1583470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                 "Channel::RegisterVoiceEngineObserver()");
15849a065d1eae9ed296e1e2eaaad73d7ca1223bfe79mflodman@webrtc.org    CriticalSectionScoped cs(&_callbackCritSect);
1585470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
1586470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    if (_voiceEngineObserverPtr)
1587470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
1588470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        _engineStatisticsPtr->SetLastError(
1589470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            VE_INVALID_OPERATION, kTraceError,
1590470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            "RegisterVoiceEngineObserver() observer already enabled");
1591470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        return -1;
1592470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
1593470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    _voiceEngineObserverPtr = &observer;
1594470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    return 0;
1595470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com}
1596470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
15976141e13873d0fdea626de08dfec2efa2c9171c76pbos@webrtc.orgint32_t
1598470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.comChannel::DeRegisterVoiceEngineObserver()
1599470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com{
1600470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1601470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                 "Channel::DeRegisterVoiceEngineObserver()");
16029a065d1eae9ed296e1e2eaaad73d7ca1223bfe79mflodman@webrtc.org    CriticalSectionScoped cs(&_callbackCritSect);
1603470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
1604470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    if (!_voiceEngineObserverPtr)
1605470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
1606470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        _engineStatisticsPtr->SetLastError(
1607470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            VE_INVALID_OPERATION, kTraceWarning,
1608470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            "DeRegisterVoiceEngineObserver() observer already disabled");
1609470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        return 0;
1610470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
1611470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    _voiceEngineObserverPtr = NULL;
1612470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    return 0;
1613470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com}
1614470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
16156141e13873d0fdea626de08dfec2efa2c9171c76pbos@webrtc.orgint32_t
1616470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.comChannel::GetSendCodec(CodecInst& codec)
1617470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com{
16187a7a008031d43013b01176cfe40b0fd68c0d83b5tina.legrand@webrtc.org    return (_audioCodingModule.SendCodec(&codec));
1619470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com}
1620470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
16216141e13873d0fdea626de08dfec2efa2c9171c76pbos@webrtc.orgint32_t
1622470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.comChannel::GetRecCodec(CodecInst& codec)
1623470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com{
16247a7a008031d43013b01176cfe40b0fd68c0d83b5tina.legrand@webrtc.org    return (_audioCodingModule.ReceiveCodec(&codec));
1625470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com}
1626470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
16276141e13873d0fdea626de08dfec2efa2c9171c76pbos@webrtc.orgint32_t
1628470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.comChannel::SetSendCodec(const CodecInst& codec)
1629470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com{
1630470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1631470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                 "Channel::SetSendCodec()");
1632470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
1633470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    if (_audioCodingModule.RegisterSendCodec(codec) != 0)
1634470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
1635470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        WEBRTC_TRACE(kTraceError, kTraceVoice, VoEId(_instanceId,_channelId),
1636470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                     "SetSendCodec() failed to register codec to ACM");
1637470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        return -1;
1638470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
1639470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
16402853dde5201d9ddc284ce5efb9688f6340487acepwestin@webrtc.org    if (_rtpRtcpModule->RegisterSendPayload(codec) != 0)
1641470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
16422853dde5201d9ddc284ce5efb9688f6340487acepwestin@webrtc.org        _rtpRtcpModule->DeRegisterSendPayload(codec.pltype);
16432853dde5201d9ddc284ce5efb9688f6340487acepwestin@webrtc.org        if (_rtpRtcpModule->RegisterSendPayload(codec) != 0)
1644470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        {
1645470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            WEBRTC_TRACE(
1646470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                    kTraceError, kTraceVoice, VoEId(_instanceId,_channelId),
1647470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                    "SetSendCodec() failed to register codec to"
1648470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                    " RTP/RTCP module");
1649470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            return -1;
1650470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        }
1651470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
1652470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
16532853dde5201d9ddc284ce5efb9688f6340487acepwestin@webrtc.org    if (_rtpRtcpModule->SetAudioPacketSize(codec.pacsize) != 0)
1654470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
1655470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        WEBRTC_TRACE(kTraceError, kTraceVoice, VoEId(_instanceId,_channelId),
1656470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                     "SetSendCodec() failed to set audio packet size");
1657470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        return -1;
1658470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
1659470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
1660470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    return 0;
1661470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com}
1662470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
16636141e13873d0fdea626de08dfec2efa2c9171c76pbos@webrtc.orgint32_t
1664470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.comChannel::SetVADStatus(bool enableVAD, ACMVADMode mode, bool disableDTX)
1665470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com{
1666470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1667470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                 "Channel::SetVADStatus(mode=%d)", mode);
1668470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    // To disable VAD, DTX must be disabled too
1669470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    disableDTX = ((enableVAD == false) ? true : disableDTX);
1670470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    if (_audioCodingModule.SetVAD(!disableDTX, enableVAD, mode) != 0)
1671470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
1672470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        _engineStatisticsPtr->SetLastError(
1673470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
1674470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            "SetVADStatus() failed to set VAD");
1675470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        return -1;
1676470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
1677470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    return 0;
1678470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com}
1679470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
16806141e13873d0fdea626de08dfec2efa2c9171c76pbos@webrtc.orgint32_t
1681470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.comChannel::GetVADStatus(bool& enabledVAD, ACMVADMode& mode, bool& disabledDTX)
1682470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com{
1683470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1684470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                 "Channel::GetVADStatus");
16857a7a008031d43013b01176cfe40b0fd68c0d83b5tina.legrand@webrtc.org    if (_audioCodingModule.VAD(&disabledDTX, &enabledVAD, &mode) != 0)
1686470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
1687470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        _engineStatisticsPtr->SetLastError(
1688470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
1689470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            "GetVADStatus() failed to get VAD status");
1690470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        return -1;
1691470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
1692470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    disabledDTX = !disabledDTX;
1693470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    return 0;
1694470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com}
1695470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
16966141e13873d0fdea626de08dfec2efa2c9171c76pbos@webrtc.orgint32_t
1697470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.comChannel::SetRecPayloadType(const CodecInst& codec)
1698470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com{
1699470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1700470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                 "Channel::SetRecPayloadType()");
1701470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
1702470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    if (_playing)
1703470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
1704470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        _engineStatisticsPtr->SetLastError(
1705470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            VE_ALREADY_PLAYING, kTraceError,
1706470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            "SetRecPayloadType() unable to set PT while playing");
1707470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        return -1;
1708470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
1709470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    if (_receiving)
1710470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
1711470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        _engineStatisticsPtr->SetLastError(
1712470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            VE_ALREADY_LISTENING, kTraceError,
1713470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            "SetRecPayloadType() unable to set PT while listening");
1714470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        return -1;
1715470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
1716470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
1717470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    if (codec.pltype == -1)
1718470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
1719470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        // De-register the selected codec (RTP/RTCP module and ACM)
1720470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
17216141e13873d0fdea626de08dfec2efa2c9171c76pbos@webrtc.org        int8_t pltype(-1);
1722470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        CodecInst rxCodec = codec;
1723470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
1724470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        // Get payload type for the given codec
17252853dde5201d9ddc284ce5efb9688f6340487acepwestin@webrtc.org        _rtpRtcpModule->ReceivePayloadType(rxCodec, &pltype);
1726470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        rxCodec.pltype = pltype;
1727470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
17282853dde5201d9ddc284ce5efb9688f6340487acepwestin@webrtc.org        if (_rtpRtcpModule->DeRegisterReceivePayload(pltype) != 0)
1729470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        {
1730470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            _engineStatisticsPtr->SetLastError(
1731470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                    VE_RTP_RTCP_MODULE_ERROR,
1732470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                    kTraceError,
1733470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                    "SetRecPayloadType() RTP/RTCP-module deregistration "
1734470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                    "failed");
1735470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            return -1;
1736470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        }
1737470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        if (_audioCodingModule.UnregisterReceiveCodec(rxCodec.pltype) != 0)
1738470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        {
1739470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            _engineStatisticsPtr->SetLastError(
1740470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
1741470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                "SetRecPayloadType() ACM deregistration failed - 1");
1742470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            return -1;
1743470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        }
1744470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        return 0;
1745470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
1746470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
17472853dde5201d9ddc284ce5efb9688f6340487acepwestin@webrtc.org    if (_rtpRtcpModule->RegisterReceivePayload(codec) != 0)
1748470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
1749470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        // First attempt to register failed => de-register and try again
17502853dde5201d9ddc284ce5efb9688f6340487acepwestin@webrtc.org        _rtpRtcpModule->DeRegisterReceivePayload(codec.pltype);
17512853dde5201d9ddc284ce5efb9688f6340487acepwestin@webrtc.org        if (_rtpRtcpModule->RegisterReceivePayload(codec) != 0)
1752470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        {
1753470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            _engineStatisticsPtr->SetLastError(
1754470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                VE_RTP_RTCP_MODULE_ERROR, kTraceError,
1755470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                "SetRecPayloadType() RTP/RTCP-module registration failed");
1756470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            return -1;
1757470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        }
1758470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
1759470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    if (_audioCodingModule.RegisterReceiveCodec(codec) != 0)
1760470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
1761470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        _audioCodingModule.UnregisterReceiveCodec(codec.pltype);
1762470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        if (_audioCodingModule.RegisterReceiveCodec(codec) != 0)
1763470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        {
1764470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            _engineStatisticsPtr->SetLastError(
1765470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
1766470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                "SetRecPayloadType() ACM registration failed - 1");
1767470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            return -1;
1768470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        }
1769470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
1770470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    return 0;
1771470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com}
1772470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
17736141e13873d0fdea626de08dfec2efa2c9171c76pbos@webrtc.orgint32_t
1774470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.comChannel::GetRecPayloadType(CodecInst& codec)
1775470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com{
1776470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1777470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                 "Channel::GetRecPayloadType()");
17786141e13873d0fdea626de08dfec2efa2c9171c76pbos@webrtc.org    int8_t payloadType(-1);
17792853dde5201d9ddc284ce5efb9688f6340487acepwestin@webrtc.org    if (_rtpRtcpModule->ReceivePayloadType(codec, &payloadType) != 0)
1780470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
1781470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        _engineStatisticsPtr->SetLastError(
178237198007eab6731fa0f77866155dd4f2b332a262henrika@webrtc.org            VE_RTP_RTCP_MODULE_ERROR, kTraceWarning,
1783470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            "GetRecPayloadType() failed to retrieve RX payload type");
1784470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        return -1;
1785470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
1786470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    codec.pltype = payloadType;
1787470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    WEBRTC_TRACE(kTraceStateInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1788470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                 "Channel::GetRecPayloadType() => pltype=%u", codec.pltype);
1789470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    return 0;
1790470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com}
1791470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
17926141e13873d0fdea626de08dfec2efa2c9171c76pbos@webrtc.orgint32_t
1793470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.comChannel::SetAMREncFormat(AmrMode mode)
1794470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com{
1795470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1796470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                 "Channel::SetAMREncFormat()");
1797470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
1798470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    // ACM doesn't support AMR
1799470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    return -1;
1800470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com}
1801470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
18026141e13873d0fdea626de08dfec2efa2c9171c76pbos@webrtc.orgint32_t
1803470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.comChannel::SetAMRDecFormat(AmrMode mode)
1804470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com{
1805470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1806470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                 "Channel::SetAMRDecFormat()");
1807470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
1808470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    // ACM doesn't support AMR
1809470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    return -1;
1810470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com}
1811470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
18126141e13873d0fdea626de08dfec2efa2c9171c76pbos@webrtc.orgint32_t
1813470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.comChannel::SetAMRWbEncFormat(AmrMode mode)
1814470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com{
1815470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1816470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                 "Channel::SetAMRWbEncFormat()");
1817470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
1818470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    // ACM doesn't support AMR
1819470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    return -1;
1820470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
1821470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com}
1822470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
18236141e13873d0fdea626de08dfec2efa2c9171c76pbos@webrtc.orgint32_t
1824470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.comChannel::SetAMRWbDecFormat(AmrMode mode)
1825470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com{
1826470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1827470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                 "Channel::SetAMRWbDecFormat()");
1828470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
1829470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    // ACM doesn't support AMR
1830470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    return -1;
1831470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com}
1832470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
18336141e13873d0fdea626de08dfec2efa2c9171c76pbos@webrtc.orgint32_t
1834470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.comChannel::SetSendCNPayloadType(int type, PayloadFrequencies frequency)
1835470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com{
1836470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1837470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                 "Channel::SetSendCNPayloadType()");
1838470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
1839470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    CodecInst codec;
18406141e13873d0fdea626de08dfec2efa2c9171c76pbos@webrtc.org    int32_t samplingFreqHz(-1);
18414517585db5f2f2a14fdd56a96f4b44f745967c8ctina.legrand@webrtc.org    const int kMono = 1;
1842470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    if (frequency == kFreq32000Hz)
1843470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        samplingFreqHz = 32000;
1844470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    else if (frequency == kFreq16000Hz)
1845470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        samplingFreqHz = 16000;
1846470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
18477a7a008031d43013b01176cfe40b0fd68c0d83b5tina.legrand@webrtc.org    if (_audioCodingModule.Codec("CN", &codec, samplingFreqHz, kMono) == -1)
1848470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
1849470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        _engineStatisticsPtr->SetLastError(
1850470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
1851470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            "SetSendCNPayloadType() failed to retrieve default CN codec "
1852470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            "settings");
1853470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        return -1;
1854470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
1855470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
1856470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    // Modify the payload type (must be set to dynamic range)
1857470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    codec.pltype = type;
1858470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
1859470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    if (_audioCodingModule.RegisterSendCodec(codec) != 0)
1860470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
1861470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        _engineStatisticsPtr->SetLastError(
1862470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
1863470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            "SetSendCNPayloadType() failed to register CN to ACM");
1864470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        return -1;
1865470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
1866470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
18672853dde5201d9ddc284ce5efb9688f6340487acepwestin@webrtc.org    if (_rtpRtcpModule->RegisterSendPayload(codec) != 0)
1868470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
18692853dde5201d9ddc284ce5efb9688f6340487acepwestin@webrtc.org        _rtpRtcpModule->DeRegisterSendPayload(codec.pltype);
18702853dde5201d9ddc284ce5efb9688f6340487acepwestin@webrtc.org        if (_rtpRtcpModule->RegisterSendPayload(codec) != 0)
1871470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        {
1872470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            _engineStatisticsPtr->SetLastError(
1873470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                VE_RTP_RTCP_MODULE_ERROR, kTraceError,
1874470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                "SetSendCNPayloadType() failed to register CN to RTP/RTCP "
1875470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                "module");
1876470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            return -1;
1877470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        }
1878470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
1879470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    return 0;
1880470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com}
1881470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
18826141e13873d0fdea626de08dfec2efa2c9171c76pbos@webrtc.orgint32_t
1883470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.comChannel::SetISACInitTargetRate(int rateBps, bool useFixedFrameSize)
1884470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com{
1885470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1886470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                 "Channel::SetISACInitTargetRate()");
1887470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
1888470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    CodecInst sendCodec;
18897a7a008031d43013b01176cfe40b0fd68c0d83b5tina.legrand@webrtc.org    if (_audioCodingModule.SendCodec(&sendCodec) == -1)
1890470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
1891470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        _engineStatisticsPtr->SetLastError(
1892470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            VE_CODEC_ERROR, kTraceError,
1893470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            "SetISACInitTargetRate() failed to retrieve send codec");
1894470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        return -1;
1895470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
1896470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    if (STR_CASE_CMP(sendCodec.plname, "ISAC") != 0)
1897470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
1898470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        // This API is only valid if iSAC is setup to run in channel-adaptive
1899470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        // mode.
1900470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        // We do not validate the adaptive mode here. It is done later in the
1901470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        // ConfigISACBandwidthEstimator() API.
1902470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        _engineStatisticsPtr->SetLastError(
1903470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            VE_CODEC_ERROR, kTraceError,
1904470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            "SetISACInitTargetRate() send codec is not iSAC");
1905470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        return -1;
1906470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
1907470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
19086141e13873d0fdea626de08dfec2efa2c9171c76pbos@webrtc.org    uint8_t initFrameSizeMsec(0);
1909470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    if (16000 == sendCodec.plfreq)
1910470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
1911470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        // Note that 0 is a valid and corresponds to "use default
1912470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        if ((rateBps != 0 &&
1913470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            rateBps < kVoiceEngineMinIsacInitTargetRateBpsWb) ||
1914470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            (rateBps > kVoiceEngineMaxIsacInitTargetRateBpsWb))
1915470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        {
1916470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com             _engineStatisticsPtr->SetLastError(
1917470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                VE_INVALID_ARGUMENT, kTraceError,
1918470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                "SetISACInitTargetRate() invalid target rate - 1");
1919470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            return -1;
1920470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        }
1921470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        // 30 or 60ms
19226141e13873d0fdea626de08dfec2efa2c9171c76pbos@webrtc.org        initFrameSizeMsec = (uint8_t)(sendCodec.pacsize / 16);
1923470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
1924470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    else if (32000 == sendCodec.plfreq)
1925470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
1926470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        if ((rateBps != 0 &&
1927470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            rateBps < kVoiceEngineMinIsacInitTargetRateBpsSwb) ||
1928470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            (rateBps > kVoiceEngineMaxIsacInitTargetRateBpsSwb))
1929470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        {
1930470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            _engineStatisticsPtr->SetLastError(
1931470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                VE_INVALID_ARGUMENT, kTraceError,
1932470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                "SetISACInitTargetRate() invalid target rate - 2");
1933470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            return -1;
1934470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        }
19356141e13873d0fdea626de08dfec2efa2c9171c76pbos@webrtc.org        initFrameSizeMsec = (uint8_t)(sendCodec.pacsize / 32); // 30ms
1936470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
1937470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
1938470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    if (_audioCodingModule.ConfigISACBandwidthEstimator(
1939470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        initFrameSizeMsec, rateBps, useFixedFrameSize) == -1)
1940470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
1941470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        _engineStatisticsPtr->SetLastError(
1942470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
1943470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            "SetISACInitTargetRate() iSAC BWE config failed");
1944470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        return -1;
1945470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
1946470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
1947470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    return 0;
1948470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com}
1949470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
19506141e13873d0fdea626de08dfec2efa2c9171c76pbos@webrtc.orgint32_t
1951470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.comChannel::SetISACMaxRate(int rateBps)
1952470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com{
1953470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1954470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                 "Channel::SetISACMaxRate()");
1955470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
1956470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    CodecInst sendCodec;
19577a7a008031d43013b01176cfe40b0fd68c0d83b5tina.legrand@webrtc.org    if (_audioCodingModule.SendCodec(&sendCodec) == -1)
1958470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
1959470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        _engineStatisticsPtr->SetLastError(
1960470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            VE_CODEC_ERROR, kTraceError,
1961470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            "SetISACMaxRate() failed to retrieve send codec");
1962470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        return -1;
1963470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
1964470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    if (STR_CASE_CMP(sendCodec.plname, "ISAC") != 0)
1965470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
1966470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        // This API is only valid if iSAC is selected as sending codec.
1967470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        _engineStatisticsPtr->SetLastError(
1968470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            VE_CODEC_ERROR, kTraceError,
1969470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            "SetISACMaxRate() send codec is not iSAC");
1970470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        return -1;
1971470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
1972470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    if (16000 == sendCodec.plfreq)
1973470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
1974470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        if ((rateBps < kVoiceEngineMinIsacMaxRateBpsWb) ||
1975470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            (rateBps > kVoiceEngineMaxIsacMaxRateBpsWb))
1976470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        {
1977470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            _engineStatisticsPtr->SetLastError(
1978470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                VE_INVALID_ARGUMENT, kTraceError,
1979470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                "SetISACMaxRate() invalid max rate - 1");
1980470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            return -1;
1981470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        }
1982470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
1983470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    else if (32000 == sendCodec.plfreq)
1984470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
1985470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        if ((rateBps < kVoiceEngineMinIsacMaxRateBpsSwb) ||
1986470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            (rateBps > kVoiceEngineMaxIsacMaxRateBpsSwb))
1987470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        {
1988470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            _engineStatisticsPtr->SetLastError(
1989470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                VE_INVALID_ARGUMENT, kTraceError,
1990470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                "SetISACMaxRate() invalid max rate - 2");
1991470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            return -1;
1992470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        }
1993470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
1994470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    if (_sending)
1995470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
1996470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        _engineStatisticsPtr->SetLastError(
1997470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            VE_SENDING, kTraceError,
1998470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            "SetISACMaxRate() unable to set max rate while sending");
1999470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        return -1;
2000470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
2001470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
2002470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    // Set the maximum instantaneous rate of iSAC (works for both adaptive
2003470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    // and non-adaptive mode)
2004470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    if (_audioCodingModule.SetISACMaxRate(rateBps) == -1)
2005470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
2006470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        _engineStatisticsPtr->SetLastError(
2007470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
2008470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            "SetISACMaxRate() failed to set max rate");
2009470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        return -1;
2010470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
2011470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
2012470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    return 0;
2013470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com}
2014470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
20156141e13873d0fdea626de08dfec2efa2c9171c76pbos@webrtc.orgint32_t
2016470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.comChannel::SetISACMaxPayloadSize(int sizeBytes)
2017470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com{
2018470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2019470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                 "Channel::SetISACMaxPayloadSize()");
2020470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    CodecInst sendCodec;
20217a7a008031d43013b01176cfe40b0fd68c0d83b5tina.legrand@webrtc.org    if (_audioCodingModule.SendCodec(&sendCodec) == -1)
2022470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
2023470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        _engineStatisticsPtr->SetLastError(
2024470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            VE_CODEC_ERROR, kTraceError,
2025470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            "SetISACMaxPayloadSize() failed to retrieve send codec");
2026470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        return -1;
2027470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
2028470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    if (STR_CASE_CMP(sendCodec.plname, "ISAC") != 0)
2029470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
2030470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        _engineStatisticsPtr->SetLastError(
2031470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            VE_CODEC_ERROR, kTraceError,
2032470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            "SetISACMaxPayloadSize() send codec is not iSAC");
2033470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        return -1;
2034470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
2035470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    if (16000 == sendCodec.plfreq)
2036470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
2037470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        if ((sizeBytes < kVoiceEngineMinIsacMaxPayloadSizeBytesWb) ||
2038470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            (sizeBytes > kVoiceEngineMaxIsacMaxPayloadSizeBytesWb))
2039470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        {
2040470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            _engineStatisticsPtr->SetLastError(
2041470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                VE_INVALID_ARGUMENT, kTraceError,
2042470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                "SetISACMaxPayloadSize() invalid max payload - 1");
2043470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            return -1;
2044470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        }
2045470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
2046470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    else if (32000 == sendCodec.plfreq)
2047470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
2048470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        if ((sizeBytes < kVoiceEngineMinIsacMaxPayloadSizeBytesSwb) ||
2049470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            (sizeBytes > kVoiceEngineMaxIsacMaxPayloadSizeBytesSwb))
2050470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        {
2051470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            _engineStatisticsPtr->SetLastError(
2052470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                VE_INVALID_ARGUMENT, kTraceError,
2053470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                "SetISACMaxPayloadSize() invalid max payload - 2");
2054470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            return -1;
2055470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        }
2056470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
2057470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    if (_sending)
2058470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
2059470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        _engineStatisticsPtr->SetLastError(
2060470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            VE_SENDING, kTraceError,
2061470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            "SetISACMaxPayloadSize() unable to set max rate while sending");
2062470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        return -1;
2063470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
2064470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
2065470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    if (_audioCodingModule.SetISACMaxPayloadSize(sizeBytes) == -1)
2066470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
2067470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        _engineStatisticsPtr->SetLastError(
2068470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
2069470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            "SetISACMaxPayloadSize() failed to set max payload size");
2070470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        return -1;
2071470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
2072470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    return 0;
2073470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com}
2074470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
20756141e13873d0fdea626de08dfec2efa2c9171c76pbos@webrtc.orgint32_t Channel::RegisterExternalTransport(Transport& transport)
2076470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com{
2077470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
2078470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com               "Channel::RegisterExternalTransport()");
2079470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
20809a065d1eae9ed296e1e2eaaad73d7ca1223bfe79mflodman@webrtc.org    CriticalSectionScoped cs(&_callbackCritSect);
2081470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
2082470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    if (_externalTransport)
2083470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
2084470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        _engineStatisticsPtr->SetLastError(VE_INVALID_OPERATION,
2085470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                                           kTraceError,
2086470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com              "RegisterExternalTransport() external transport already enabled");
2087470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com       return -1;
2088470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
2089470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    _externalTransport = true;
2090470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    _transportPtr = &transport;
2091470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    return 0;
2092470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com}
2093470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
20946141e13873d0fdea626de08dfec2efa2c9171c76pbos@webrtc.orgint32_t
2095470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.comChannel::DeRegisterExternalTransport()
2096470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com{
2097470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2098470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                 "Channel::DeRegisterExternalTransport()");
2099470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
21009a065d1eae9ed296e1e2eaaad73d7ca1223bfe79mflodman@webrtc.org    CriticalSectionScoped cs(&_callbackCritSect);
210183661f534e56dfaf3542963b54b1e208f223a377xians@webrtc.org
2102470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    if (!_transportPtr)
2103470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
2104470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        _engineStatisticsPtr->SetLastError(
2105470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            VE_INVALID_OPERATION, kTraceWarning,
2106470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            "DeRegisterExternalTransport() external transport already "
2107470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            "disabled");
2108470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        return 0;
2109470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
2110470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    _externalTransport = false;
2111470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    _transportPtr = NULL;
2112470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2113470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                 "DeRegisterExternalTransport() all transport is disabled");
2114684f0577fbe4ea393fef1dddf2ca7d02e3205b49pwestin@webrtc.org    return 0;
2115684f0577fbe4ea393fef1dddf2ca7d02e3205b49pwestin@webrtc.org}
2116684f0577fbe4ea393fef1dddf2ca7d02e3205b49pwestin@webrtc.org
21176141e13873d0fdea626de08dfec2efa2c9171c76pbos@webrtc.orgint32_t Channel::ReceivedRTPPacket(const int8_t* data, int32_t length) {
21180c45957e3a6963e1460c0b5b62a6adf43cf44314pwestin@webrtc.org  WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
21190c45957e3a6963e1460c0b5b62a6adf43cf44314pwestin@webrtc.org               "Channel::ReceivedRTPPacket()");
2120684f0577fbe4ea393fef1dddf2ca7d02e3205b49pwestin@webrtc.org
21210c45957e3a6963e1460c0b5b62a6adf43cf44314pwestin@webrtc.org  // Store playout timestamp for the received RTP packet
21221de01354e68da71bc62c81af17afeac8ed374a18pwestin@webrtc.org  UpdatePlayoutTimestamp(false);
2123684f0577fbe4ea393fef1dddf2ca7d02e3205b49pwestin@webrtc.org
21240c45957e3a6963e1460c0b5b62a6adf43cf44314pwestin@webrtc.org  // Dump the RTP packet to a file (if RTP dump is enabled).
21256141e13873d0fdea626de08dfec2efa2c9171c76pbos@webrtc.org  if (_rtpDumpIn.DumpPacket((const uint8_t*)data,
21266141e13873d0fdea626de08dfec2efa2c9171c76pbos@webrtc.org                            (uint16_t)length) == -1) {
21270c45957e3a6963e1460c0b5b62a6adf43cf44314pwestin@webrtc.org    WEBRTC_TRACE(kTraceWarning, kTraceVoice,
21280c45957e3a6963e1460c0b5b62a6adf43cf44314pwestin@webrtc.org                 VoEId(_instanceId,_channelId),
21290c45957e3a6963e1460c0b5b62a6adf43cf44314pwestin@webrtc.org                 "Channel::SendPacket() RTP dump to input file failed");
21300c45957e3a6963e1460c0b5b62a6adf43cf44314pwestin@webrtc.org  }
21310c45957e3a6963e1460c0b5b62a6adf43cf44314pwestin@webrtc.org
21320c45957e3a6963e1460c0b5b62a6adf43cf44314pwestin@webrtc.org  // Deliver RTP packet to RTP/RTCP module for parsing
21330c45957e3a6963e1460c0b5b62a6adf43cf44314pwestin@webrtc.org  // The packet will be pushed back to the channel thru the
21340c45957e3a6963e1460c0b5b62a6adf43cf44314pwestin@webrtc.org  // OnReceivedPayloadData callback so we don't push it to the ACM here
21356141e13873d0fdea626de08dfec2efa2c9171c76pbos@webrtc.org  if (_rtpRtcpModule->IncomingPacket((const uint8_t*)data,
21366141e13873d0fdea626de08dfec2efa2c9171c76pbos@webrtc.org                                     (uint16_t)length) == -1) {
21370c45957e3a6963e1460c0b5b62a6adf43cf44314pwestin@webrtc.org    _engineStatisticsPtr->SetLastError(
21380c45957e3a6963e1460c0b5b62a6adf43cf44314pwestin@webrtc.org        VE_SOCKET_TRANSPORT_MODULE_ERROR, kTraceWarning,
21390c45957e3a6963e1460c0b5b62a6adf43cf44314pwestin@webrtc.org        "Channel::IncomingRTPPacket() RTP packet is invalid");
21400c45957e3a6963e1460c0b5b62a6adf43cf44314pwestin@webrtc.org  }
21410c45957e3a6963e1460c0b5b62a6adf43cf44314pwestin@webrtc.org  return 0;
21420c45957e3a6963e1460c0b5b62a6adf43cf44314pwestin@webrtc.org}
21430c45957e3a6963e1460c0b5b62a6adf43cf44314pwestin@webrtc.org
21446141e13873d0fdea626de08dfec2efa2c9171c76pbos@webrtc.orgint32_t Channel::ReceivedRTCPPacket(const int8_t* data, int32_t length) {
21450c45957e3a6963e1460c0b5b62a6adf43cf44314pwestin@webrtc.org  WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
21460c45957e3a6963e1460c0b5b62a6adf43cf44314pwestin@webrtc.org               "Channel::ReceivedRTCPPacket()");
21470c45957e3a6963e1460c0b5b62a6adf43cf44314pwestin@webrtc.org  // Store playout timestamp for the received RTCP packet
21481de01354e68da71bc62c81af17afeac8ed374a18pwestin@webrtc.org  UpdatePlayoutTimestamp(true);
21490c45957e3a6963e1460c0b5b62a6adf43cf44314pwestin@webrtc.org
21500c45957e3a6963e1460c0b5b62a6adf43cf44314pwestin@webrtc.org  // Dump the RTCP packet to a file (if RTP dump is enabled).
21516141e13873d0fdea626de08dfec2efa2c9171c76pbos@webrtc.org  if (_rtpDumpIn.DumpPacket((const uint8_t*)data,
21526141e13873d0fdea626de08dfec2efa2c9171c76pbos@webrtc.org                            (uint16_t)length) == -1) {
21530c45957e3a6963e1460c0b5b62a6adf43cf44314pwestin@webrtc.org    WEBRTC_TRACE(kTraceWarning, kTraceVoice,
21540c45957e3a6963e1460c0b5b62a6adf43cf44314pwestin@webrtc.org                 VoEId(_instanceId,_channelId),
21550c45957e3a6963e1460c0b5b62a6adf43cf44314pwestin@webrtc.org                 "Channel::SendPacket() RTCP dump to input file failed");
21560c45957e3a6963e1460c0b5b62a6adf43cf44314pwestin@webrtc.org  }
2157684f0577fbe4ea393fef1dddf2ca7d02e3205b49pwestin@webrtc.org
21580c45957e3a6963e1460c0b5b62a6adf43cf44314pwestin@webrtc.org  // Deliver RTCP packet to RTP/RTCP module for parsing
21596141e13873d0fdea626de08dfec2efa2c9171c76pbos@webrtc.org  if (_rtpRtcpModule->IncomingPacket((const uint8_t*)data,
21606141e13873d0fdea626de08dfec2efa2c9171c76pbos@webrtc.org                                     (uint16_t)length) == -1) {
21610c45957e3a6963e1460c0b5b62a6adf43cf44314pwestin@webrtc.org    _engineStatisticsPtr->SetLastError(
21620c45957e3a6963e1460c0b5b62a6adf43cf44314pwestin@webrtc.org        VE_SOCKET_TRANSPORT_MODULE_ERROR, kTraceWarning,
21630c45957e3a6963e1460c0b5b62a6adf43cf44314pwestin@webrtc.org        "Channel::IncomingRTPPacket() RTCP packet is invalid");
21640c45957e3a6963e1460c0b5b62a6adf43cf44314pwestin@webrtc.org  }
21650c45957e3a6963e1460c0b5b62a6adf43cf44314pwestin@webrtc.org  return 0;
2166684f0577fbe4ea393fef1dddf2ca7d02e3205b49pwestin@webrtc.org}
2167684f0577fbe4ea393fef1dddf2ca7d02e3205b49pwestin@webrtc.org
21686141e13873d0fdea626de08dfec2efa2c9171c76pbos@webrtc.orgint32_t
2169470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.comChannel::SetPacketTimeoutNotification(bool enable, int timeoutSeconds)
2170470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com{
2171470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2172470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                 "Channel::SetPacketTimeoutNotification()");
2173470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    if (enable)
2174470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
21756141e13873d0fdea626de08dfec2efa2c9171c76pbos@webrtc.org        const uint32_t RTPtimeoutMS = 1000*timeoutSeconds;
21766141e13873d0fdea626de08dfec2efa2c9171c76pbos@webrtc.org        const uint32_t RTCPtimeoutMS = 0;
21772853dde5201d9ddc284ce5efb9688f6340487acepwestin@webrtc.org        _rtpRtcpModule->SetPacketTimeout(RTPtimeoutMS, RTCPtimeoutMS);
2178470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        _rtpPacketTimeOutIsEnabled = true;
2179470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        _rtpTimeOutSeconds = timeoutSeconds;
2180470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
2181470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    else
2182470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
21832853dde5201d9ddc284ce5efb9688f6340487acepwestin@webrtc.org        _rtpRtcpModule->SetPacketTimeout(0, 0);
2184470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        _rtpPacketTimeOutIsEnabled = false;
2185470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        _rtpTimeOutSeconds = 0;
2186470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
2187470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    return 0;
2188470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com}
2189470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
21906141e13873d0fdea626de08dfec2efa2c9171c76pbos@webrtc.orgint32_t
2191470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.comChannel::GetPacketTimeoutNotification(bool& enabled, int& timeoutSeconds)
2192470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com{
2193470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2194470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                 "Channel::GetPacketTimeoutNotification()");
2195470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    enabled = _rtpPacketTimeOutIsEnabled;
2196470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    if (enabled)
2197470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
2198470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        timeoutSeconds = _rtpTimeOutSeconds;
2199470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
2200470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    WEBRTC_TRACE(kTraceStateInfo, kTraceVoice, VoEId(_instanceId,-1),
2201470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                 "GetPacketTimeoutNotification() => enabled=%d,"
2202470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                 " timeoutSeconds=%d",
2203470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                 enabled, timeoutSeconds);
2204470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    return 0;
2205470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com}
2206470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
22076141e13873d0fdea626de08dfec2efa2c9171c76pbos@webrtc.orgint32_t
2208470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.comChannel::RegisterDeadOrAliveObserver(VoEConnectionObserver& observer)
2209470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com{
2210470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2211470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                 "Channel::RegisterDeadOrAliveObserver()");
22129a065d1eae9ed296e1e2eaaad73d7ca1223bfe79mflodman@webrtc.org    CriticalSectionScoped cs(&_callbackCritSect);
2213470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
2214470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    if (_connectionObserverPtr)
2215470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
2216470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        _engineStatisticsPtr->SetLastError(VE_INVALID_OPERATION, kTraceError,
2217470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            "RegisterDeadOrAliveObserver() observer already enabled");
2218470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        return -1;
2219470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
2220470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
2221470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    _connectionObserverPtr = &observer;
2222470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    _connectionObserver = true;
2223470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
2224470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    return 0;
2225470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com}
2226470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
22276141e13873d0fdea626de08dfec2efa2c9171c76pbos@webrtc.orgint32_t
2228470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.comChannel::DeRegisterDeadOrAliveObserver()
2229470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com{
2230470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2231470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                 "Channel::DeRegisterDeadOrAliveObserver()");
22329a065d1eae9ed296e1e2eaaad73d7ca1223bfe79mflodman@webrtc.org    CriticalSectionScoped cs(&_callbackCritSect);
2233470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
2234470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    if (!_connectionObserverPtr)
2235470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
2236470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        _engineStatisticsPtr->SetLastError(
2237470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            VE_INVALID_OPERATION, kTraceWarning,
2238470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            "DeRegisterDeadOrAliveObserver() observer already disabled");
2239470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        return 0;
2240470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
2241470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
2242470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    _connectionObserver = false;
2243470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    _connectionObserverPtr = NULL;
2244470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
2245470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    return 0;
2246470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com}
2247470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
22486141e13873d0fdea626de08dfec2efa2c9171c76pbos@webrtc.orgint32_t
2249470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.comChannel::SetPeriodicDeadOrAliveStatus(bool enable, int sampleTimeSeconds)
2250470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com{
2251470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2252470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                 "Channel::SetPeriodicDeadOrAliveStatus()");
2253470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    if (!_connectionObserverPtr)
2254470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
2255470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        WEBRTC_TRACE(kTraceWarning, kTraceVoice, VoEId(_instanceId,_channelId),
2256470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                     "SetPeriodicDeadOrAliveStatus() connection observer has"
2257470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                     " not been registered");
2258470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
2259470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    if (enable)
2260470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
2261470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        ResetDeadOrAliveCounters();
2262470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
2263470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    bool enabled(false);
22646141e13873d0fdea626de08dfec2efa2c9171c76pbos@webrtc.org    uint8_t currentSampleTimeSec(0);
2265470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    // Store last state (will be used later if dead-or-alive is disabled).
22662853dde5201d9ddc284ce5efb9688f6340487acepwestin@webrtc.org    _rtpRtcpModule->PeriodicDeadOrAliveStatus(enabled, currentSampleTimeSec);
2267470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    // Update the dead-or-alive state.
22682853dde5201d9ddc284ce5efb9688f6340487acepwestin@webrtc.org    if (_rtpRtcpModule->SetPeriodicDeadOrAliveStatus(
22696141e13873d0fdea626de08dfec2efa2c9171c76pbos@webrtc.org        enable, (uint8_t)sampleTimeSeconds) != 0)
2270470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
2271470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        _engineStatisticsPtr->SetLastError(
2272470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                VE_RTP_RTCP_MODULE_ERROR,
2273470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                kTraceError,
2274470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                "SetPeriodicDeadOrAliveStatus() failed to set dead-or-alive "
2275470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                "status");
2276470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        return -1;
2277470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
2278470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    if (!enable)
2279470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
2280470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        // Restore last utilized sample time.
2281470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        // Without this, the sample time would always be reset to default
2282470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        // (2 sec), each time dead-or-alived was disabled without sample-time
2283470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        // parameter.
22842853dde5201d9ddc284ce5efb9688f6340487acepwestin@webrtc.org        _rtpRtcpModule->SetPeriodicDeadOrAliveStatus(enable,
2285470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                                                    currentSampleTimeSec);
2286470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
2287470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    return 0;
2288470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com}
2289470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
22906141e13873d0fdea626de08dfec2efa2c9171c76pbos@webrtc.orgint32_t
2291470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.comChannel::GetPeriodicDeadOrAliveStatus(bool& enabled, int& sampleTimeSeconds)
2292470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com{
22932853dde5201d9ddc284ce5efb9688f6340487acepwestin@webrtc.org    _rtpRtcpModule->PeriodicDeadOrAliveStatus(
2294470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        enabled,
22956141e13873d0fdea626de08dfec2efa2c9171c76pbos@webrtc.org        (uint8_t&)sampleTimeSeconds);
2296470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    WEBRTC_TRACE(kTraceStateInfo, kTraceVoice, VoEId(_instanceId,-1),
2297470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                 "GetPeriodicDeadOrAliveStatus() => enabled=%d,"
2298470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                 " sampleTimeSeconds=%d",
2299470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                 enabled, sampleTimeSeconds);
2300470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    return 0;
2301470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com}
2302470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
2303470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.comint Channel::StartPlayingFileLocally(const char* fileName,
23049213521ea98b0977c7cdabd2853060835af226f3pbos@webrtc.org                                     bool loop,
23059213521ea98b0977c7cdabd2853060835af226f3pbos@webrtc.org                                     FileFormats format,
23069213521ea98b0977c7cdabd2853060835af226f3pbos@webrtc.org                                     int startPosition,
23079213521ea98b0977c7cdabd2853060835af226f3pbos@webrtc.org                                     float volumeScaling,
23089213521ea98b0977c7cdabd2853060835af226f3pbos@webrtc.org                                     int stopPosition,
2309470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                                     const CodecInst* codecInst)
2310470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com{
2311470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2312470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                 "Channel::StartPlayingFileLocally(fileNameUTF8[]=%s, loop=%d,"
2313470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                 " format=%d, volumeScaling=%5.3f, startPosition=%d, "
2314470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                 "stopPosition=%d)", fileName, loop, format, volumeScaling,
2315470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                 startPosition, stopPosition);
2316470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
2317470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    if (_outputFilePlaying)
2318470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
2319470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        _engineStatisticsPtr->SetLastError(
2320470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            VE_ALREADY_PLAYING, kTraceError,
2321470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            "StartPlayingFileLocally() is already playing");
2322470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        return -1;
2323470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
2324470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
2325470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
23269a065d1eae9ed296e1e2eaaad73d7ca1223bfe79mflodman@webrtc.org        CriticalSectionScoped cs(&_fileCritSect);
2327470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
2328b37c628ae43a9086da607a638785723306bd9aedhenrike@webrtc.org        if (_outputFilePlayerPtr)
2329b37c628ae43a9086da607a638785723306bd9aedhenrike@webrtc.org        {
2330b37c628ae43a9086da607a638785723306bd9aedhenrike@webrtc.org            _outputFilePlayerPtr->RegisterModuleFileCallback(NULL);
2331b37c628ae43a9086da607a638785723306bd9aedhenrike@webrtc.org            FilePlayer::DestroyFilePlayer(_outputFilePlayerPtr);
2332b37c628ae43a9086da607a638785723306bd9aedhenrike@webrtc.org            _outputFilePlayerPtr = NULL;
2333b37c628ae43a9086da607a638785723306bd9aedhenrike@webrtc.org        }
2334470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
2335b37c628ae43a9086da607a638785723306bd9aedhenrike@webrtc.org        _outputFilePlayerPtr = FilePlayer::CreateFilePlayer(
2336b37c628ae43a9086da607a638785723306bd9aedhenrike@webrtc.org            _outputFilePlayerId, (const FileFormats)format);
2337b37c628ae43a9086da607a638785723306bd9aedhenrike@webrtc.org
2338b37c628ae43a9086da607a638785723306bd9aedhenrike@webrtc.org        if (_outputFilePlayerPtr == NULL)
2339b37c628ae43a9086da607a638785723306bd9aedhenrike@webrtc.org        {
2340b37c628ae43a9086da607a638785723306bd9aedhenrike@webrtc.org            _engineStatisticsPtr->SetLastError(
2341b37c628ae43a9086da607a638785723306bd9aedhenrike@webrtc.org                VE_INVALID_ARGUMENT, kTraceError,
234231d30700d638c4cfa47c26cac7cb00c7232874c9henrike@webrtc.org                "StartPlayingFileLocally() filePlayer format is not correct");
2343b37c628ae43a9086da607a638785723306bd9aedhenrike@webrtc.org            return -1;
2344b37c628ae43a9086da607a638785723306bd9aedhenrike@webrtc.org        }
2345470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
23466141e13873d0fdea626de08dfec2efa2c9171c76pbos@webrtc.org        const uint32_t notificationTime(0);
2347470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
2348b37c628ae43a9086da607a638785723306bd9aedhenrike@webrtc.org        if (_outputFilePlayerPtr->StartPlayingFile(
2349b37c628ae43a9086da607a638785723306bd9aedhenrike@webrtc.org                fileName,
2350b37c628ae43a9086da607a638785723306bd9aedhenrike@webrtc.org                loop,
2351b37c628ae43a9086da607a638785723306bd9aedhenrike@webrtc.org                startPosition,
2352b37c628ae43a9086da607a638785723306bd9aedhenrike@webrtc.org                volumeScaling,
2353b37c628ae43a9086da607a638785723306bd9aedhenrike@webrtc.org                notificationTime,
2354b37c628ae43a9086da607a638785723306bd9aedhenrike@webrtc.org                stopPosition,
2355b37c628ae43a9086da607a638785723306bd9aedhenrike@webrtc.org                (const CodecInst*)codecInst) != 0)
2356b37c628ae43a9086da607a638785723306bd9aedhenrike@webrtc.org        {
2357b37c628ae43a9086da607a638785723306bd9aedhenrike@webrtc.org            _engineStatisticsPtr->SetLastError(
2358b37c628ae43a9086da607a638785723306bd9aedhenrike@webrtc.org                VE_BAD_FILE, kTraceError,
2359b37c628ae43a9086da607a638785723306bd9aedhenrike@webrtc.org                "StartPlayingFile() failed to start file playout");
2360b37c628ae43a9086da607a638785723306bd9aedhenrike@webrtc.org            _outputFilePlayerPtr->StopPlayingFile();
2361b37c628ae43a9086da607a638785723306bd9aedhenrike@webrtc.org            FilePlayer::DestroyFilePlayer(_outputFilePlayerPtr);
2362b37c628ae43a9086da607a638785723306bd9aedhenrike@webrtc.org            _outputFilePlayerPtr = NULL;
2363b37c628ae43a9086da607a638785723306bd9aedhenrike@webrtc.org            return -1;
2364b37c628ae43a9086da607a638785723306bd9aedhenrike@webrtc.org        }
2365b37c628ae43a9086da607a638785723306bd9aedhenrike@webrtc.org        _outputFilePlayerPtr->RegisterModuleFileCallback(this);
2366b37c628ae43a9086da607a638785723306bd9aedhenrike@webrtc.org        _outputFilePlaying = true;
2367470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
2368ab12990b1b8c2410b34c055e73ed04e8a7ee1d85braveyao@webrtc.org
2369ab12990b1b8c2410b34c055e73ed04e8a7ee1d85braveyao@webrtc.org    if (RegisterFilePlayingToMixer() != 0)
2370066f9e5a2fbb8e83ef88ceca0ab5a4ea057cc619henrike@webrtc.org        return -1;
2371470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
2372470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    return 0;
2373470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com}
2374470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
2375470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.comint Channel::StartPlayingFileLocally(InStream* stream,
23769213521ea98b0977c7cdabd2853060835af226f3pbos@webrtc.org                                     FileFormats format,
23779213521ea98b0977c7cdabd2853060835af226f3pbos@webrtc.org                                     int startPosition,
23789213521ea98b0977c7cdabd2853060835af226f3pbos@webrtc.org                                     float volumeScaling,
23799213521ea98b0977c7cdabd2853060835af226f3pbos@webrtc.org                                     int stopPosition,
2380470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                                     const CodecInst* codecInst)
2381470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com{
2382470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2383470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                 "Channel::StartPlayingFileLocally(format=%d,"
2384470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                 " volumeScaling=%5.3f, startPosition=%d, stopPosition=%d)",
2385470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                 format, volumeScaling, startPosition, stopPosition);
2386470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
2387470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    if(stream == NULL)
2388470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
2389470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        _engineStatisticsPtr->SetLastError(
2390470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            VE_BAD_FILE, kTraceError,
2391470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            "StartPlayingFileLocally() NULL as input stream");
2392470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        return -1;
2393470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
2394470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
2395470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
2396470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    if (_outputFilePlaying)
2397470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
2398470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        _engineStatisticsPtr->SetLastError(
2399470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            VE_ALREADY_PLAYING, kTraceError,
2400470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            "StartPlayingFileLocally() is already playing");
2401470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        return -1;
2402470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
2403470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
2404470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
24059a065d1eae9ed296e1e2eaaad73d7ca1223bfe79mflodman@webrtc.org      CriticalSectionScoped cs(&_fileCritSect);
2406b37c628ae43a9086da607a638785723306bd9aedhenrike@webrtc.org
2407b37c628ae43a9086da607a638785723306bd9aedhenrike@webrtc.org      // Destroy the old instance
2408b37c628ae43a9086da607a638785723306bd9aedhenrike@webrtc.org      if (_outputFilePlayerPtr)
2409b37c628ae43a9086da607a638785723306bd9aedhenrike@webrtc.org      {
2410b37c628ae43a9086da607a638785723306bd9aedhenrike@webrtc.org          _outputFilePlayerPtr->RegisterModuleFileCallback(NULL);
2411b37c628ae43a9086da607a638785723306bd9aedhenrike@webrtc.org          FilePlayer::DestroyFilePlayer(_outputFilePlayerPtr);
2412b37c628ae43a9086da607a638785723306bd9aedhenrike@webrtc.org          _outputFilePlayerPtr = NULL;
2413b37c628ae43a9086da607a638785723306bd9aedhenrike@webrtc.org      }
2414b37c628ae43a9086da607a638785723306bd9aedhenrike@webrtc.org
2415b37c628ae43a9086da607a638785723306bd9aedhenrike@webrtc.org      // Create the instance
2416b37c628ae43a9086da607a638785723306bd9aedhenrike@webrtc.org      _outputFilePlayerPtr = FilePlayer::CreateFilePlayer(
2417b37c628ae43a9086da607a638785723306bd9aedhenrike@webrtc.org          _outputFilePlayerId,
2418b37c628ae43a9086da607a638785723306bd9aedhenrike@webrtc.org          (const FileFormats)format);
2419b37c628ae43a9086da607a638785723306bd9aedhenrike@webrtc.org
2420b37c628ae43a9086da607a638785723306bd9aedhenrike@webrtc.org      if (_outputFilePlayerPtr == NULL)
2421b37c628ae43a9086da607a638785723306bd9aedhenrike@webrtc.org      {
2422b37c628ae43a9086da607a638785723306bd9aedhenrike@webrtc.org          _engineStatisticsPtr->SetLastError(
2423b37c628ae43a9086da607a638785723306bd9aedhenrike@webrtc.org              VE_INVALID_ARGUMENT, kTraceError,
2424b37c628ae43a9086da607a638785723306bd9aedhenrike@webrtc.org              "StartPlayingFileLocally() filePlayer format isnot correct");
2425b37c628ae43a9086da607a638785723306bd9aedhenrike@webrtc.org          return -1;
2426b37c628ae43a9086da607a638785723306bd9aedhenrike@webrtc.org      }
2427b37c628ae43a9086da607a638785723306bd9aedhenrike@webrtc.org
24286141e13873d0fdea626de08dfec2efa2c9171c76pbos@webrtc.org      const uint32_t notificationTime(0);
2429b37c628ae43a9086da607a638785723306bd9aedhenrike@webrtc.org
2430b37c628ae43a9086da607a638785723306bd9aedhenrike@webrtc.org      if (_outputFilePlayerPtr->StartPlayingFile(*stream, startPosition,
2431b37c628ae43a9086da607a638785723306bd9aedhenrike@webrtc.org                                                 volumeScaling,
2432b37c628ae43a9086da607a638785723306bd9aedhenrike@webrtc.org                                                 notificationTime,
2433b37c628ae43a9086da607a638785723306bd9aedhenrike@webrtc.org                                                 stopPosition, codecInst) != 0)
2434b37c628ae43a9086da607a638785723306bd9aedhenrike@webrtc.org      {
2435b37c628ae43a9086da607a638785723306bd9aedhenrike@webrtc.org          _engineStatisticsPtr->SetLastError(VE_BAD_FILE, kTraceError,
2436b37c628ae43a9086da607a638785723306bd9aedhenrike@webrtc.org                                             "StartPlayingFile() failed to "
2437b37c628ae43a9086da607a638785723306bd9aedhenrike@webrtc.org                                             "start file playout");
2438b37c628ae43a9086da607a638785723306bd9aedhenrike@webrtc.org          _outputFilePlayerPtr->StopPlayingFile();
2439b37c628ae43a9086da607a638785723306bd9aedhenrike@webrtc.org          FilePlayer::DestroyFilePlayer(_outputFilePlayerPtr);
2440b37c628ae43a9086da607a638785723306bd9aedhenrike@webrtc.org          _outputFilePlayerPtr = NULL;
2441b37c628ae43a9086da607a638785723306bd9aedhenrike@webrtc.org          return -1;
2442b37c628ae43a9086da607a638785723306bd9aedhenrike@webrtc.org      }
2443b37c628ae43a9086da607a638785723306bd9aedhenrike@webrtc.org      _outputFilePlayerPtr->RegisterModuleFileCallback(this);
2444b37c628ae43a9086da607a638785723306bd9aedhenrike@webrtc.org      _outputFilePlaying = true;
2445b37c628ae43a9086da607a638785723306bd9aedhenrike@webrtc.org    }
2446ab12990b1b8c2410b34c055e73ed04e8a7ee1d85braveyao@webrtc.org
2447ab12990b1b8c2410b34c055e73ed04e8a7ee1d85braveyao@webrtc.org    if (RegisterFilePlayingToMixer() != 0)
2448066f9e5a2fbb8e83ef88ceca0ab5a4ea057cc619henrike@webrtc.org        return -1;
2449470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
2450470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    return 0;
2451470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com}
2452470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
2453470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.comint Channel::StopPlayingFileLocally()
2454470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com{
2455470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2456470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                 "Channel::StopPlayingFileLocally()");
2457470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
2458470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    if (!_outputFilePlaying)
2459470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
2460470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        _engineStatisticsPtr->SetLastError(
2461470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            VE_INVALID_OPERATION, kTraceWarning,
2462470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            "StopPlayingFileLocally() isnot playing");
2463470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        return 0;
2464470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
2465470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
2466470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
24679a065d1eae9ed296e1e2eaaad73d7ca1223bfe79mflodman@webrtc.org        CriticalSectionScoped cs(&_fileCritSect);
2468b37c628ae43a9086da607a638785723306bd9aedhenrike@webrtc.org
2469b37c628ae43a9086da607a638785723306bd9aedhenrike@webrtc.org        if (_outputFilePlayerPtr->StopPlayingFile() != 0)
2470b37c628ae43a9086da607a638785723306bd9aedhenrike@webrtc.org        {
2471b37c628ae43a9086da607a638785723306bd9aedhenrike@webrtc.org            _engineStatisticsPtr->SetLastError(
2472b37c628ae43a9086da607a638785723306bd9aedhenrike@webrtc.org                VE_STOP_RECORDING_FAILED, kTraceError,
2473b37c628ae43a9086da607a638785723306bd9aedhenrike@webrtc.org                "StopPlayingFile() could not stop playing");
2474b37c628ae43a9086da607a638785723306bd9aedhenrike@webrtc.org            return -1;
2475b37c628ae43a9086da607a638785723306bd9aedhenrike@webrtc.org        }
2476b37c628ae43a9086da607a638785723306bd9aedhenrike@webrtc.org        _outputFilePlayerPtr->RegisterModuleFileCallback(NULL);
2477b37c628ae43a9086da607a638785723306bd9aedhenrike@webrtc.org        FilePlayer::DestroyFilePlayer(_outputFilePlayerPtr);
2478b37c628ae43a9086da607a638785723306bd9aedhenrike@webrtc.org        _outputFilePlayerPtr = NULL;
2479b37c628ae43a9086da607a638785723306bd9aedhenrike@webrtc.org        _outputFilePlaying = false;
2480470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
2481b37c628ae43a9086da607a638785723306bd9aedhenrike@webrtc.org    // _fileCritSect cannot be taken while calling
2482b37c628ae43a9086da607a638785723306bd9aedhenrike@webrtc.org    // SetAnonymousMixibilityStatus. Refer to comments in
2483b37c628ae43a9086da607a638785723306bd9aedhenrike@webrtc.org    // StartPlayingFileLocally(const char* ...) for more details.
2484066f9e5a2fbb8e83ef88ceca0ab5a4ea057cc619henrike@webrtc.org    if (_outputMixerPtr->SetAnonymousMixabilityStatus(*this, false) != 0)
2485066f9e5a2fbb8e83ef88ceca0ab5a4ea057cc619henrike@webrtc.org    {
2486066f9e5a2fbb8e83ef88ceca0ab5a4ea057cc619henrike@webrtc.org        _engineStatisticsPtr->SetLastError(
2487066f9e5a2fbb8e83ef88ceca0ab5a4ea057cc619henrike@webrtc.org            VE_AUDIO_CONF_MIX_MODULE_ERROR, kTraceError,
2488b37c628ae43a9086da607a638785723306bd9aedhenrike@webrtc.org            "StopPlayingFile() failed to stop participant from playing as"
2489b37c628ae43a9086da607a638785723306bd9aedhenrike@webrtc.org            "file in the mixer");
2490066f9e5a2fbb8e83ef88ceca0ab5a4ea057cc619henrike@webrtc.org        return -1;
2491066f9e5a2fbb8e83ef88ceca0ab5a4ea057cc619henrike@webrtc.org    }
2492470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
2493470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    return 0;
2494470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com}
2495470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
2496470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.comint Channel::IsPlayingFileLocally() const
2497470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com{
2498470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2499470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                 "Channel::IsPlayingFileLocally()");
2500470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
25016141e13873d0fdea626de08dfec2efa2c9171c76pbos@webrtc.org    return (int32_t)_outputFilePlaying;
2502470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com}
2503470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
2504ab12990b1b8c2410b34c055e73ed04e8a7ee1d85braveyao@webrtc.orgint Channel::RegisterFilePlayingToMixer()
2505ab12990b1b8c2410b34c055e73ed04e8a7ee1d85braveyao@webrtc.org{
2506ab12990b1b8c2410b34c055e73ed04e8a7ee1d85braveyao@webrtc.org    // Return success for not registering for file playing to mixer if:
2507ab12990b1b8c2410b34c055e73ed04e8a7ee1d85braveyao@webrtc.org    // 1. playing file before playout is started on that channel.
2508ab12990b1b8c2410b34c055e73ed04e8a7ee1d85braveyao@webrtc.org    // 2. starting playout without file playing on that channel.
2509ab12990b1b8c2410b34c055e73ed04e8a7ee1d85braveyao@webrtc.org    if (!_playing || !_outputFilePlaying)
2510ab12990b1b8c2410b34c055e73ed04e8a7ee1d85braveyao@webrtc.org    {
2511ab12990b1b8c2410b34c055e73ed04e8a7ee1d85braveyao@webrtc.org        return 0;
2512ab12990b1b8c2410b34c055e73ed04e8a7ee1d85braveyao@webrtc.org    }
2513ab12990b1b8c2410b34c055e73ed04e8a7ee1d85braveyao@webrtc.org
2514ab12990b1b8c2410b34c055e73ed04e8a7ee1d85braveyao@webrtc.org    // |_fileCritSect| cannot be taken while calling
2515ab12990b1b8c2410b34c055e73ed04e8a7ee1d85braveyao@webrtc.org    // SetAnonymousMixabilityStatus() since as soon as the participant is added
2516ab12990b1b8c2410b34c055e73ed04e8a7ee1d85braveyao@webrtc.org    // frames can be pulled by the mixer. Since the frames are generated from
2517ab12990b1b8c2410b34c055e73ed04e8a7ee1d85braveyao@webrtc.org    // the file, _fileCritSect will be taken. This would result in a deadlock.
2518ab12990b1b8c2410b34c055e73ed04e8a7ee1d85braveyao@webrtc.org    if (_outputMixerPtr->SetAnonymousMixabilityStatus(*this, true) != 0)
2519ab12990b1b8c2410b34c055e73ed04e8a7ee1d85braveyao@webrtc.org    {
2520ab12990b1b8c2410b34c055e73ed04e8a7ee1d85braveyao@webrtc.org        CriticalSectionScoped cs(&_fileCritSect);
2521ab12990b1b8c2410b34c055e73ed04e8a7ee1d85braveyao@webrtc.org        _outputFilePlaying = false;
2522ab12990b1b8c2410b34c055e73ed04e8a7ee1d85braveyao@webrtc.org        _engineStatisticsPtr->SetLastError(
2523ab12990b1b8c2410b34c055e73ed04e8a7ee1d85braveyao@webrtc.org            VE_AUDIO_CONF_MIX_MODULE_ERROR, kTraceError,
2524ab12990b1b8c2410b34c055e73ed04e8a7ee1d85braveyao@webrtc.org            "StartPlayingFile() failed to add participant as file to mixer");
2525ab12990b1b8c2410b34c055e73ed04e8a7ee1d85braveyao@webrtc.org        _outputFilePlayerPtr->StopPlayingFile();
2526ab12990b1b8c2410b34c055e73ed04e8a7ee1d85braveyao@webrtc.org        FilePlayer::DestroyFilePlayer(_outputFilePlayerPtr);
2527ab12990b1b8c2410b34c055e73ed04e8a7ee1d85braveyao@webrtc.org        _outputFilePlayerPtr = NULL;
2528ab12990b1b8c2410b34c055e73ed04e8a7ee1d85braveyao@webrtc.org        return -1;
2529ab12990b1b8c2410b34c055e73ed04e8a7ee1d85braveyao@webrtc.org    }
2530ab12990b1b8c2410b34c055e73ed04e8a7ee1d85braveyao@webrtc.org
2531ab12990b1b8c2410b34c055e73ed04e8a7ee1d85braveyao@webrtc.org    return 0;
2532ab12990b1b8c2410b34c055e73ed04e8a7ee1d85braveyao@webrtc.org}
2533ab12990b1b8c2410b34c055e73ed04e8a7ee1d85braveyao@webrtc.org
25349213521ea98b0977c7cdabd2853060835af226f3pbos@webrtc.orgint Channel::ScaleLocalFilePlayout(float scale)
2535470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com{
2536470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2537470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                 "Channel::ScaleLocalFilePlayout(scale=%5.3f)", scale);
2538470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
25399a065d1eae9ed296e1e2eaaad73d7ca1223bfe79mflodman@webrtc.org    CriticalSectionScoped cs(&_fileCritSect);
2540470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
2541470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    if (!_outputFilePlaying)
2542470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
2543470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        _engineStatisticsPtr->SetLastError(
2544470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            VE_INVALID_OPERATION, kTraceError,
2545470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            "ScaleLocalFilePlayout() isnot playing");
2546470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        return -1;
2547470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
2548470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    if ((_outputFilePlayerPtr == NULL) ||
2549470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        (_outputFilePlayerPtr->SetAudioScaling(scale) != 0))
2550470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
2551470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        _engineStatisticsPtr->SetLastError(
2552470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            VE_BAD_ARGUMENT, kTraceError,
2553470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            "SetAudioScaling() failed to scale the playout");
2554470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        return -1;
2555470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
2556470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
2557470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    return 0;
2558470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com}
2559470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
2560470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.comint Channel::GetLocalPlayoutPosition(int& positionMs)
2561470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com{
2562470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2563470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                 "Channel::GetLocalPlayoutPosition(position=?)");
2564470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
25656141e13873d0fdea626de08dfec2efa2c9171c76pbos@webrtc.org    uint32_t position;
2566470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
25679a065d1eae9ed296e1e2eaaad73d7ca1223bfe79mflodman@webrtc.org    CriticalSectionScoped cs(&_fileCritSect);
2568470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
2569470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    if (_outputFilePlayerPtr == NULL)
2570470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
2571470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        _engineStatisticsPtr->SetLastError(
2572470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            VE_INVALID_OPERATION, kTraceError,
2573470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            "GetLocalPlayoutPosition() filePlayer instance doesnot exist");
2574470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        return -1;
2575470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
2576470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
2577470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    if (_outputFilePlayerPtr->GetPlayoutPosition(position) != 0)
2578470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
2579470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        _engineStatisticsPtr->SetLastError(
2580470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            VE_BAD_FILE, kTraceError,
2581470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            "GetLocalPlayoutPosition() failed");
2582470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        return -1;
2583470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
2584470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    positionMs = position;
2585470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
2586470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    return 0;
2587470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com}
2588470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
2589470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.comint Channel::StartPlayingFileAsMicrophone(const char* fileName,
25909213521ea98b0977c7cdabd2853060835af226f3pbos@webrtc.org                                          bool loop,
25919213521ea98b0977c7cdabd2853060835af226f3pbos@webrtc.org                                          FileFormats format,
25929213521ea98b0977c7cdabd2853060835af226f3pbos@webrtc.org                                          int startPosition,
25939213521ea98b0977c7cdabd2853060835af226f3pbos@webrtc.org                                          float volumeScaling,
25949213521ea98b0977c7cdabd2853060835af226f3pbos@webrtc.org                                          int stopPosition,
2595470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                                          const CodecInst* codecInst)
2596470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com{
2597470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2598470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                 "Channel::StartPlayingFileAsMicrophone(fileNameUTF8[]=%s, "
2599470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                 "loop=%d, format=%d, volumeScaling=%5.3f, startPosition=%d, "
2600470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                 "stopPosition=%d)", fileName, loop, format, volumeScaling,
2601470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                 startPosition, stopPosition);
2602470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
2603470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    if (_inputFilePlaying)
2604470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
2605470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        _engineStatisticsPtr->SetLastError(
2606470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            VE_ALREADY_PLAYING, kTraceWarning,
2607470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            "StartPlayingFileAsMicrophone() filePlayer is playing");
2608470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        return 0;
2609470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
2610470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
26119a065d1eae9ed296e1e2eaaad73d7ca1223bfe79mflodman@webrtc.org    CriticalSectionScoped cs(&_fileCritSect);
2612470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
2613470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    // Destroy the old instance
2614470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    if (_inputFilePlayerPtr)
2615470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
2616470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        _inputFilePlayerPtr->RegisterModuleFileCallback(NULL);
2617470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        FilePlayer::DestroyFilePlayer(_inputFilePlayerPtr);
2618470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        _inputFilePlayerPtr = NULL;
2619470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
2620470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
2621470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    // Create the instance
2622470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    _inputFilePlayerPtr = FilePlayer::CreateFilePlayer(
2623470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        _inputFilePlayerId, (const FileFormats)format);
2624470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
2625470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    if (_inputFilePlayerPtr == NULL)
2626470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
2627470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        _engineStatisticsPtr->SetLastError(
2628470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            VE_INVALID_ARGUMENT, kTraceError,
2629470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            "StartPlayingFileAsMicrophone() filePlayer format isnot correct");
2630470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        return -1;
2631470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
2632470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
26336141e13873d0fdea626de08dfec2efa2c9171c76pbos@webrtc.org    const uint32_t notificationTime(0);
2634470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
2635470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    if (_inputFilePlayerPtr->StartPlayingFile(
2636470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        fileName,
2637470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        loop,
2638470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        startPosition,
2639470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        volumeScaling,
2640470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        notificationTime,
2641470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        stopPosition,
2642470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        (const CodecInst*)codecInst) != 0)
2643470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
2644470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        _engineStatisticsPtr->SetLastError(
2645470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            VE_BAD_FILE, kTraceError,
2646470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            "StartPlayingFile() failed to start file playout");
2647470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        _inputFilePlayerPtr->StopPlayingFile();
2648470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        FilePlayer::DestroyFilePlayer(_inputFilePlayerPtr);
2649470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        _inputFilePlayerPtr = NULL;
2650470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        return -1;
2651470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
2652470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    _inputFilePlayerPtr->RegisterModuleFileCallback(this);
2653470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    _inputFilePlaying = true;
2654470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
2655470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    return 0;
2656470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com}
2657470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
2658470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.comint Channel::StartPlayingFileAsMicrophone(InStream* stream,
26599213521ea98b0977c7cdabd2853060835af226f3pbos@webrtc.org                                          FileFormats format,
26609213521ea98b0977c7cdabd2853060835af226f3pbos@webrtc.org                                          int startPosition,
26619213521ea98b0977c7cdabd2853060835af226f3pbos@webrtc.org                                          float volumeScaling,
26629213521ea98b0977c7cdabd2853060835af226f3pbos@webrtc.org                                          int stopPosition,
2663470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                                          const CodecInst* codecInst)
2664470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com{
2665470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2666470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                 "Channel::StartPlayingFileAsMicrophone(format=%d, "
2667470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                 "volumeScaling=%5.3f, startPosition=%d, stopPosition=%d)",
2668470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                 format, volumeScaling, startPosition, stopPosition);
2669470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
2670470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    if(stream == NULL)
2671470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
2672470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        _engineStatisticsPtr->SetLastError(
2673470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            VE_BAD_FILE, kTraceError,
2674470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            "StartPlayingFileAsMicrophone NULL as input stream");
2675470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        return -1;
2676470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
2677470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
2678470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    if (_inputFilePlaying)
2679470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
2680470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        _engineStatisticsPtr->SetLastError(
2681470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            VE_ALREADY_PLAYING, kTraceWarning,
2682470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            "StartPlayingFileAsMicrophone() is playing");
2683470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        return 0;
2684470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
2685470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
26869a065d1eae9ed296e1e2eaaad73d7ca1223bfe79mflodman@webrtc.org    CriticalSectionScoped cs(&_fileCritSect);
2687470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
2688470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    // Destroy the old instance
2689470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    if (_inputFilePlayerPtr)
2690470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
2691470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        _inputFilePlayerPtr->RegisterModuleFileCallback(NULL);
2692470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        FilePlayer::DestroyFilePlayer(_inputFilePlayerPtr);
2693470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        _inputFilePlayerPtr = NULL;
2694470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
2695470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
2696470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    // Create the instance
2697470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    _inputFilePlayerPtr = FilePlayer::CreateFilePlayer(
2698470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        _inputFilePlayerId, (const FileFormats)format);
2699470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
2700470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    if (_inputFilePlayerPtr == NULL)
2701470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
2702470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        _engineStatisticsPtr->SetLastError(
2703470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            VE_INVALID_ARGUMENT, kTraceError,
2704470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            "StartPlayingInputFile() filePlayer format isnot correct");
2705470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        return -1;
2706470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
2707470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
27086141e13873d0fdea626de08dfec2efa2c9171c76pbos@webrtc.org    const uint32_t notificationTime(0);
2709470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
2710470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    if (_inputFilePlayerPtr->StartPlayingFile(*stream, startPosition,
2711470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                                              volumeScaling, notificationTime,
2712470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                                              stopPosition, codecInst) != 0)
2713470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
2714470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        _engineStatisticsPtr->SetLastError(VE_BAD_FILE, kTraceError,
2715470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                                           "StartPlayingFile() failed to start "
2716470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                                           "file playout");
2717470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        _inputFilePlayerPtr->StopPlayingFile();
2718470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        FilePlayer::DestroyFilePlayer(_inputFilePlayerPtr);
2719470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        _inputFilePlayerPtr = NULL;
2720470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        return -1;
2721470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
2722ae1a58bba4f926d149a5f39243269c3f6625f494andrew@webrtc.org
2723470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    _inputFilePlayerPtr->RegisterModuleFileCallback(this);
2724470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    _inputFilePlaying = true;
2725470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
2726470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    return 0;
2727470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com}
2728470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
2729470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.comint Channel::StopPlayingFileAsMicrophone()
2730470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com{
2731470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2732470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                 "Channel::StopPlayingFileAsMicrophone()");
2733470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
2734470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    if (!_inputFilePlaying)
2735470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
2736470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        _engineStatisticsPtr->SetLastError(
2737470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            VE_INVALID_OPERATION, kTraceWarning,
2738470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            "StopPlayingFileAsMicrophone() isnot playing");
2739470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        return 0;
2740470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
2741470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
27429a065d1eae9ed296e1e2eaaad73d7ca1223bfe79mflodman@webrtc.org    CriticalSectionScoped cs(&_fileCritSect);
2743470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    if (_inputFilePlayerPtr->StopPlayingFile() != 0)
2744470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
2745470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        _engineStatisticsPtr->SetLastError(
2746470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            VE_STOP_RECORDING_FAILED, kTraceError,
2747470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            "StopPlayingFile() could not stop playing");
2748470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        return -1;
2749470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
2750470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    _inputFilePlayerPtr->RegisterModuleFileCallback(NULL);
2751470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    FilePlayer::DestroyFilePlayer(_inputFilePlayerPtr);
2752470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    _inputFilePlayerPtr = NULL;
2753470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    _inputFilePlaying = false;
2754470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
2755470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    return 0;
2756470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com}
2757470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
2758470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.comint Channel::IsPlayingFileAsMicrophone() const
2759470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com{
2760470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2761470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                 "Channel::IsPlayingFileAsMicrophone()");
2762470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
2763470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    return _inputFilePlaying;
2764470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com}
2765470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
27669213521ea98b0977c7cdabd2853060835af226f3pbos@webrtc.orgint Channel::ScaleFileAsMicrophonePlayout(float scale)
2767470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com{
2768470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2769470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                 "Channel::ScaleFileAsMicrophonePlayout(scale=%5.3f)", scale);
2770470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
27719a065d1eae9ed296e1e2eaaad73d7ca1223bfe79mflodman@webrtc.org    CriticalSectionScoped cs(&_fileCritSect);
2772470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
2773470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    if (!_inputFilePlaying)
2774470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
2775470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        _engineStatisticsPtr->SetLastError(
2776470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            VE_INVALID_OPERATION, kTraceError,
2777470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            "ScaleFileAsMicrophonePlayout() isnot playing");
2778470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        return -1;
2779470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
2780470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
2781470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    if ((_inputFilePlayerPtr == NULL) ||
2782470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        (_inputFilePlayerPtr->SetAudioScaling(scale) != 0))
2783470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
2784470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        _engineStatisticsPtr->SetLastError(
2785470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            VE_BAD_ARGUMENT, kTraceError,
2786470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            "SetAudioScaling() failed to scale playout");
2787470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        return -1;
2788470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
2789470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
2790470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    return 0;
2791470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com}
2792470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
2793813e4b0af06272dada388c2d8383b2e36a1da6a6leozwang@webrtc.orgint Channel::StartRecordingPlayout(const char* fileName,
2794470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                                   const CodecInst* codecInst)
2795470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com{
2796470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2797470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                 "Channel::StartRecordingPlayout(fileName=%s)", fileName);
2798470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
2799470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    if (_outputFileRecording)
2800470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
2801470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        WEBRTC_TRACE(kTraceWarning, kTraceVoice, VoEId(_instanceId,-1),
2802470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                     "StartRecordingPlayout() is already recording");
2803470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        return 0;
2804470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
2805470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
2806470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    FileFormats format;
28076141e13873d0fdea626de08dfec2efa2c9171c76pbos@webrtc.org    const uint32_t notificationTime(0); // Not supported in VoE
2808470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    CodecInst dummyCodec={100,"L16",16000,320,1,320000};
2809470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
281040197d7b3b347f05b299a930641dad131c853e01niklas.enbom@webrtc.org    if ((codecInst != NULL) &&
281140197d7b3b347f05b299a930641dad131c853e01niklas.enbom@webrtc.org      ((codecInst->channels < 1) || (codecInst->channels > 2)))
2812470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
2813470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        _engineStatisticsPtr->SetLastError(
2814470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            VE_BAD_ARGUMENT, kTraceError,
2815470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            "StartRecordingPlayout() invalid compression");
2816470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        return(-1);
2817470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
2818470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    if(codecInst == NULL)
2819470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
2820470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        format = kFileFormatPcm16kHzFile;
2821470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        codecInst=&dummyCodec;
2822470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
2823470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    else if((STR_CASE_CMP(codecInst->plname,"L16") == 0) ||
2824470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        (STR_CASE_CMP(codecInst->plname,"PCMU") == 0) ||
2825470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        (STR_CASE_CMP(codecInst->plname,"PCMA") == 0))
2826470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
2827470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        format = kFileFormatWavFile;
2828470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
2829470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    else
2830470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
2831470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        format = kFileFormatCompressedFile;
2832470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
2833470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
28349a065d1eae9ed296e1e2eaaad73d7ca1223bfe79mflodman@webrtc.org    CriticalSectionScoped cs(&_fileCritSect);
2835470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
2836470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    // Destroy the old instance
2837470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    if (_outputFileRecorderPtr)
2838470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
2839470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        _outputFileRecorderPtr->RegisterModuleFileCallback(NULL);
2840470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        FileRecorder::DestroyFileRecorder(_outputFileRecorderPtr);
2841470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        _outputFileRecorderPtr = NULL;
2842470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
2843470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
2844470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    _outputFileRecorderPtr = FileRecorder::CreateFileRecorder(
2845470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        _outputFileRecorderId, (const FileFormats)format);
2846470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    if (_outputFileRecorderPtr == NULL)
2847470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
2848470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        _engineStatisticsPtr->SetLastError(
2849470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            VE_INVALID_ARGUMENT, kTraceError,
2850470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            "StartRecordingPlayout() fileRecorder format isnot correct");
2851470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        return -1;
2852470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
2853470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
2854470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    if (_outputFileRecorderPtr->StartRecordingAudioFile(
2855470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        fileName, (const CodecInst&)*codecInst, notificationTime) != 0)
2856470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
2857470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        _engineStatisticsPtr->SetLastError(
2858470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            VE_BAD_FILE, kTraceError,
2859470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            "StartRecordingAudioFile() failed to start file recording");
2860470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        _outputFileRecorderPtr->StopRecording();
2861470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        FileRecorder::DestroyFileRecorder(_outputFileRecorderPtr);
2862470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        _outputFileRecorderPtr = NULL;
2863470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        return -1;
2864470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
2865470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    _outputFileRecorderPtr->RegisterModuleFileCallback(this);
2866470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    _outputFileRecording = true;
2867470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
2868470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    return 0;
2869470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com}
2870470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
2871470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.comint Channel::StartRecordingPlayout(OutStream* stream,
2872470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                                   const CodecInst* codecInst)
2873470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com{
2874470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2875470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                 "Channel::StartRecordingPlayout()");
2876470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
2877470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    if (_outputFileRecording)
2878470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
2879470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        WEBRTC_TRACE(kTraceWarning, kTraceVoice, VoEId(_instanceId,-1),
2880470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                     "StartRecordingPlayout() is already recording");
2881470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        return 0;
2882470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
2883470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
2884470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    FileFormats format;
28856141e13873d0fdea626de08dfec2efa2c9171c76pbos@webrtc.org    const uint32_t notificationTime(0); // Not supported in VoE
2886470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    CodecInst dummyCodec={100,"L16",16000,320,1,320000};
2887470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
2888470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    if (codecInst != NULL && codecInst->channels != 1)
2889470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
2890470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        _engineStatisticsPtr->SetLastError(
2891470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            VE_BAD_ARGUMENT, kTraceError,
2892470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            "StartRecordingPlayout() invalid compression");
2893470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        return(-1);
2894470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
2895470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    if(codecInst == NULL)
2896470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
2897470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        format = kFileFormatPcm16kHzFile;
2898470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        codecInst=&dummyCodec;
2899470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
2900470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    else if((STR_CASE_CMP(codecInst->plname,"L16") == 0) ||
2901470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        (STR_CASE_CMP(codecInst->plname,"PCMU") == 0) ||
2902470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        (STR_CASE_CMP(codecInst->plname,"PCMA") == 0))
2903470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
2904470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        format = kFileFormatWavFile;
2905470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
2906470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    else
2907470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
2908470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        format = kFileFormatCompressedFile;
2909470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
2910470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
29119a065d1eae9ed296e1e2eaaad73d7ca1223bfe79mflodman@webrtc.org    CriticalSectionScoped cs(&_fileCritSect);
2912470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
2913470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    // Destroy the old instance
2914470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    if (_outputFileRecorderPtr)
2915470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
2916470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        _outputFileRecorderPtr->RegisterModuleFileCallback(NULL);
2917470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        FileRecorder::DestroyFileRecorder(_outputFileRecorderPtr);
2918470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        _outputFileRecorderPtr = NULL;
2919470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
2920470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
2921470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    _outputFileRecorderPtr = FileRecorder::CreateFileRecorder(
2922470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        _outputFileRecorderId, (const FileFormats)format);
2923470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    if (_outputFileRecorderPtr == NULL)
2924470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
2925470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        _engineStatisticsPtr->SetLastError(
2926470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            VE_INVALID_ARGUMENT, kTraceError,
2927470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            "StartRecordingPlayout() fileRecorder format isnot correct");
2928470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        return -1;
2929470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
2930470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
2931470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    if (_outputFileRecorderPtr->StartRecordingAudioFile(*stream, *codecInst,
2932470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                                                        notificationTime) != 0)
2933470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
2934470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        _engineStatisticsPtr->SetLastError(VE_BAD_FILE, kTraceError,
2935470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                                           "StartRecordingPlayout() failed to "
2936470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                                           "start file recording");
2937470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        _outputFileRecorderPtr->StopRecording();
2938470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        FileRecorder::DestroyFileRecorder(_outputFileRecorderPtr);
2939470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        _outputFileRecorderPtr = NULL;
2940470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        return -1;
2941470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
2942ae1a58bba4f926d149a5f39243269c3f6625f494andrew@webrtc.org
2943470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    _outputFileRecorderPtr->RegisterModuleFileCallback(this);
2944470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    _outputFileRecording = true;
2945470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
2946470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    return 0;
2947470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com}
2948470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
2949470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.comint Channel::StopRecordingPlayout()
2950470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com{
2951470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,-1),
2952470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                 "Channel::StopRecordingPlayout()");
2953470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
2954470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    if (!_outputFileRecording)
2955470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
2956470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        WEBRTC_TRACE(kTraceError, kTraceVoice, VoEId(_instanceId,-1),
2957470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                     "StopRecordingPlayout() isnot recording");
2958470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        return -1;
2959470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
2960470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
2961470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
29629a065d1eae9ed296e1e2eaaad73d7ca1223bfe79mflodman@webrtc.org    CriticalSectionScoped cs(&_fileCritSect);
2963470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
2964470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    if (_outputFileRecorderPtr->StopRecording() != 0)
2965470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
2966470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        _engineStatisticsPtr->SetLastError(
2967470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            VE_STOP_RECORDING_FAILED, kTraceError,
2968470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            "StopRecording() could not stop recording");
2969470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        return(-1);
2970470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
2971470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    _outputFileRecorderPtr->RegisterModuleFileCallback(NULL);
2972470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    FileRecorder::DestroyFileRecorder(_outputFileRecorderPtr);
2973470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    _outputFileRecorderPtr = NULL;
2974470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    _outputFileRecording = false;
2975470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
2976470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    return 0;
2977470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com}
2978470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
2979470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.comvoid
2980470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.comChannel::SetMixWithMicStatus(bool mix)
2981470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com{
2982470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    _mixFileWithMicrophone=mix;
2983470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com}
2984470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
2985470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.comint
29866141e13873d0fdea626de08dfec2efa2c9171c76pbos@webrtc.orgChannel::GetSpeechOutputLevel(uint32_t& level) const
2987470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com{
29886141e13873d0fdea626de08dfec2efa2c9171c76pbos@webrtc.org    int8_t currentLevel = _outputAudioLevel.Level();
29896141e13873d0fdea626de08dfec2efa2c9171c76pbos@webrtc.org    level = static_cast<int32_t> (currentLevel);
2990470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
2991470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com               VoEId(_instanceId,_channelId),
2992470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com               "GetSpeechOutputLevel() => level=%u", level);
2993470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    return 0;
2994470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com}
2995470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
2996470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.comint
29976141e13873d0fdea626de08dfec2efa2c9171c76pbos@webrtc.orgChannel::GetSpeechOutputLevelFullRange(uint32_t& level) const
2998470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com{
29996141e13873d0fdea626de08dfec2efa2c9171c76pbos@webrtc.org    int16_t currentLevel = _outputAudioLevel.LevelFullRange();
30006141e13873d0fdea626de08dfec2efa2c9171c76pbos@webrtc.org    level = static_cast<int32_t> (currentLevel);
3001470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3002470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com               VoEId(_instanceId,_channelId),
3003470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com               "GetSpeechOutputLevelFullRange() => level=%u", level);
3004470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    return 0;
3005470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com}
3006470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
3007470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.comint
3008470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.comChannel::SetMute(bool enable)
3009470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com{
3010470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3011470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com               "Channel::SetMute(enable=%d)", enable);
3012470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    _mute = enable;
3013470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    return 0;
3014470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com}
3015470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
3016470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.combool
3017470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.comChannel::Mute() const
3018470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com{
3019470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    return _mute;
3020470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com}
3021470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
3022470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.comint
3023470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.comChannel::SetOutputVolumePan(float left, float right)
3024470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com{
3025470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3026470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com               "Channel::SetOutputVolumePan()");
3027470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    _panLeft = left;
3028470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    _panRight = right;
3029470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    return 0;
3030470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com}
3031470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
3032470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.comint
3033470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.comChannel::GetOutputVolumePan(float& left, float& right) const
3034470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com{
3035470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    left = _panLeft;
3036470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    right = _panRight;
3037470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3038470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com               VoEId(_instanceId,_channelId),
3039470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com               "GetOutputVolumePan() => left=%3.2f, right=%3.2f", left, right);
3040470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    return 0;
3041470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com}
3042470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
3043470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.comint
3044470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.comChannel::SetChannelOutputVolumeScaling(float scaling)
3045470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com{
3046470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3047470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com               "Channel::SetChannelOutputVolumeScaling()");
3048470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    _outputGain = scaling;
3049470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    return 0;
3050470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com}
3051470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
3052470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.comint
3053470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.comChannel::GetChannelOutputVolumeScaling(float& scaling) const
3054470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com{
3055470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    scaling = _outputGain;
3056470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3057470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com               VoEId(_instanceId,_channelId),
3058470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com               "GetChannelOutputVolumeScaling() => scaling=%3.2f", scaling);
3059470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    return 0;
3060470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com}
3061470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
3062470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.comint
3063470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.comChannel::RegisterExternalEncryption(Encryption& encryption)
3064470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com{
3065470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3066470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com               "Channel::RegisterExternalEncryption()");
3067470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
30689a065d1eae9ed296e1e2eaaad73d7ca1223bfe79mflodman@webrtc.org    CriticalSectionScoped cs(&_callbackCritSect);
3069470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
3070470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    if (_encryptionPtr)
3071470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
3072470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        _engineStatisticsPtr->SetLastError(
3073470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            VE_INVALID_OPERATION, kTraceError,
3074470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            "RegisterExternalEncryption() encryption already enabled");
3075470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        return -1;
3076470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
3077470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
3078470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    _encryptionPtr = &encryption;
3079470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
3080470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    _decrypting = true;
3081470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    _encrypting = true;
3082470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
3083470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    return 0;
3084470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com}
3085470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
3086470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.comint
3087470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.comChannel::DeRegisterExternalEncryption()
3088470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com{
3089470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3090470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com               "Channel::DeRegisterExternalEncryption()");
3091470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
30929a065d1eae9ed296e1e2eaaad73d7ca1223bfe79mflodman@webrtc.org    CriticalSectionScoped cs(&_callbackCritSect);
3093470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
3094470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    if (!_encryptionPtr)
3095470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
3096470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        _engineStatisticsPtr->SetLastError(
3097470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            VE_INVALID_OPERATION, kTraceWarning,
3098470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            "DeRegisterExternalEncryption() encryption already disabled");
3099470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        return 0;
3100470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
3101470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
3102470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    _decrypting = false;
3103470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    _encrypting = false;
3104470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
3105470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    _encryptionPtr = NULL;
3106470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
3107470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    return 0;
3108470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com}
3109470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
3110470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.comint Channel::SendTelephoneEventOutband(unsigned char eventCode,
3111470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                                          int lengthMs, int attenuationDb,
3112470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                                          bool playDtmfEvent)
3113470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com{
3114470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
3115470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com               "Channel::SendTelephoneEventOutband(..., playDtmfEvent=%d)",
3116470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com               playDtmfEvent);
3117470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
3118470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    _playOutbandDtmfEvent = playDtmfEvent;
3119470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
31202853dde5201d9ddc284ce5efb9688f6340487acepwestin@webrtc.org    if (_rtpRtcpModule->SendTelephoneEventOutband(eventCode, lengthMs,
3121470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                                                 attenuationDb) != 0)
3122470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
3123470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        _engineStatisticsPtr->SetLastError(
3124470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            VE_SEND_DTMF_FAILED,
3125470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            kTraceWarning,
3126470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            "SendTelephoneEventOutband() failed to send event");
3127470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        return -1;
3128470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
3129470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    return 0;
3130470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com}
3131470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
3132470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.comint Channel::SendTelephoneEventInband(unsigned char eventCode,
3133470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                                         int lengthMs,
3134470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                                         int attenuationDb,
3135470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                                         bool playDtmfEvent)
3136470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com{
3137470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
3138470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com               "Channel::SendTelephoneEventInband(..., playDtmfEvent=%d)",
3139470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com               playDtmfEvent);
3140470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
3141470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    _playInbandDtmfEvent = playDtmfEvent;
3142470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    _inbandDtmfQueue.AddDtmf(eventCode, lengthMs, attenuationDb);
3143470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
3144470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    return 0;
3145470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com}
3146470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
3147470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.comint
3148470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.comChannel::SetDtmfPlayoutStatus(bool enable)
3149470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com{
3150470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3151470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com               "Channel::SetDtmfPlayoutStatus()");
3152470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    if (_audioCodingModule.SetDtmfPlayoutStatus(enable) != 0)
3153470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
3154470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        _engineStatisticsPtr->SetLastError(
3155470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            VE_AUDIO_CODING_MODULE_ERROR, kTraceWarning,
3156470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            "SetDtmfPlayoutStatus() failed to set Dtmf playout");
3157470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        return -1;
3158470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
3159470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    return 0;
3160470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com}
3161470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
3162470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.combool
3163470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.comChannel::DtmfPlayoutStatus() const
3164470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com{
3165470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    return _audioCodingModule.DtmfPlayoutStatus();
3166470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com}
3167470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
3168470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.comint
3169470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.comChannel::SetSendTelephoneEventPayloadType(unsigned char type)
3170470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com{
3171470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3172470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com               "Channel::SetSendTelephoneEventPayloadType()");
3173f81f9f8c2a18fb20ee60406ece45ff3210367ff9andrew@webrtc.org    if (type > 127)
3174470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
3175470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        _engineStatisticsPtr->SetLastError(
3176470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            VE_INVALID_ARGUMENT, kTraceError,
3177470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            "SetSendTelephoneEventPayloadType() invalid type");
3178470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        return -1;
3179470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
31801da1ce0da5fcc029dbc2a134a9760e1b398b02d7pwestin@webrtc.org    CodecInst codec;
31811da1ce0da5fcc029dbc2a134a9760e1b398b02d7pwestin@webrtc.org    codec.plfreq = 8000;
31821da1ce0da5fcc029dbc2a134a9760e1b398b02d7pwestin@webrtc.org    codec.pltype = type;
31831da1ce0da5fcc029dbc2a134a9760e1b398b02d7pwestin@webrtc.org    memcpy(codec.plname, "telephone-event", 16);
31842853dde5201d9ddc284ce5efb9688f6340487acepwestin@webrtc.org    if (_rtpRtcpModule->RegisterSendPayload(codec) != 0)
3185470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
31864392d5f9f859b5d55b8017fafb09a496a110beb3henrika@webrtc.org        _rtpRtcpModule->DeRegisterSendPayload(codec.pltype);
31874392d5f9f859b5d55b8017fafb09a496a110beb3henrika@webrtc.org        if (_rtpRtcpModule->RegisterSendPayload(codec) != 0) {
31884392d5f9f859b5d55b8017fafb09a496a110beb3henrika@webrtc.org            _engineStatisticsPtr->SetLastError(
31894392d5f9f859b5d55b8017fafb09a496a110beb3henrika@webrtc.org                VE_RTP_RTCP_MODULE_ERROR, kTraceError,
31904392d5f9f859b5d55b8017fafb09a496a110beb3henrika@webrtc.org                "SetSendTelephoneEventPayloadType() failed to register send"
31914392d5f9f859b5d55b8017fafb09a496a110beb3henrika@webrtc.org                "payload type");
31924392d5f9f859b5d55b8017fafb09a496a110beb3henrika@webrtc.org            return -1;
31934392d5f9f859b5d55b8017fafb09a496a110beb3henrika@webrtc.org        }
3194470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
3195470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    _sendTelephoneEventPayloadType = type;
3196470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    return 0;
3197470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com}
3198470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
3199470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.comint
3200470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.comChannel::GetSendTelephoneEventPayloadType(unsigned char& type)
3201470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com{
3202470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3203470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                 "Channel::GetSendTelephoneEventPayloadType()");
3204470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    type = _sendTelephoneEventPayloadType;
3205470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3206470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com               VoEId(_instanceId,_channelId),
3207470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com               "GetSendTelephoneEventPayloadType() => type=%u", type);
3208470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    return 0;
3209470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com}
3210470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
3211470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.comint
3212470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.comChannel::UpdateRxVadDetection(AudioFrame& audioFrame)
3213470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com{
3214470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
3215470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                 "Channel::UpdateRxVadDetection()");
3216470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
3217470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    int vadDecision = 1;
3218470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
321963a509858d3988299726640c664b699d6229a1d4andrew@webrtc.org    vadDecision = (audioFrame.vad_activity_ == AudioFrame::kVadActive)? 1 : 0;
3220470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
3221470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    if ((vadDecision != _oldVadDecision) && _rxVadObserverPtr)
3222470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
3223470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        OnRxVadDetected(vadDecision);
3224470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        _oldVadDecision = vadDecision;
3225470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
3226470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
3227470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
3228470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                 "Channel::UpdateRxVadDetection() => vadDecision=%d",
3229470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                 vadDecision);
3230470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    return 0;
3231470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com}
3232470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
3233470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.comint
3234470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.comChannel::RegisterRxVadObserver(VoERxVadCallback &observer)
3235470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com{
3236470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3237470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                 "Channel::RegisterRxVadObserver()");
32389a065d1eae9ed296e1e2eaaad73d7ca1223bfe79mflodman@webrtc.org    CriticalSectionScoped cs(&_callbackCritSect);
3239470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
3240470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    if (_rxVadObserverPtr)
3241470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
3242470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        _engineStatisticsPtr->SetLastError(
3243470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            VE_INVALID_OPERATION, kTraceError,
3244470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            "RegisterRxVadObserver() observer already enabled");
3245470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        return -1;
3246470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
3247470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    _rxVadObserverPtr = &observer;
3248470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    _RxVadDetection = true;
3249470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    return 0;
3250470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com}
3251470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
3252470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.comint
3253470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.comChannel::DeRegisterRxVadObserver()
3254470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com{
3255470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3256470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                 "Channel::DeRegisterRxVadObserver()");
32579a065d1eae9ed296e1e2eaaad73d7ca1223bfe79mflodman@webrtc.org    CriticalSectionScoped cs(&_callbackCritSect);
3258470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
3259470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    if (!_rxVadObserverPtr)
3260470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
3261470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        _engineStatisticsPtr->SetLastError(
3262470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            VE_INVALID_OPERATION, kTraceWarning,
3263470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            "DeRegisterRxVadObserver() observer already disabled");
3264470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        return 0;
3265470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
3266470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    _rxVadObserverPtr = NULL;
3267470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    _RxVadDetection = false;
3268470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    return 0;
3269470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com}
3270470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
3271470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.comint
3272470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.comChannel::VoiceActivityIndicator(int &activity)
3273470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com{
3274470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    activity = _sendFrameType;
3275470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
3276470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3277470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com               "Channel::VoiceActivityIndicator(indicator=%d)", activity);
3278470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    return 0;
3279470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com}
3280470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
3281470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com#ifdef WEBRTC_VOICE_ENGINE_AGC
3282470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
3283470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.comint
32849213521ea98b0977c7cdabd2853060835af226f3pbos@webrtc.orgChannel::SetRxAgcStatus(bool enable, AgcModes mode)
3285470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com{
3286470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3287470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                 "Channel::SetRxAgcStatus(enable=%d, mode=%d)",
3288470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                 (int)enable, (int)mode);
3289470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
3290470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    GainControl::Mode agcMode(GainControl::kFixedDigital);
3291470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    switch (mode)
3292470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
3293470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        case kAgcDefault:
3294470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            agcMode = GainControl::kAdaptiveDigital;
3295470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            break;
3296470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        case kAgcUnchanged:
3297470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            agcMode = _rxAudioProcessingModulePtr->gain_control()->mode();
3298470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            break;
3299470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        case kAgcFixedDigital:
3300470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            agcMode = GainControl::kFixedDigital;
3301470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            break;
3302470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        case kAgcAdaptiveDigital:
3303470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            agcMode =GainControl::kAdaptiveDigital;
3304470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            break;
3305470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        default:
3306470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            _engineStatisticsPtr->SetLastError(
3307470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                VE_INVALID_ARGUMENT, kTraceError,
3308470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                "SetRxAgcStatus() invalid Agc mode");
3309470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            return -1;
3310470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
3311470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
3312470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    if (_rxAudioProcessingModulePtr->gain_control()->set_mode(agcMode) != 0)
3313470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
3314470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        _engineStatisticsPtr->SetLastError(
3315470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            VE_APM_ERROR, kTraceError,
3316470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            "SetRxAgcStatus() failed to set Agc mode");
3317470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        return -1;
3318470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
3319470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    if (_rxAudioProcessingModulePtr->gain_control()->Enable(enable) != 0)
3320470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
3321470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        _engineStatisticsPtr->SetLastError(
3322470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            VE_APM_ERROR, kTraceError,
3323470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            "SetRxAgcStatus() failed to set Agc state");
3324470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        return -1;
3325470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
3326470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
3327470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    _rxAgcIsEnabled = enable;
3328470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    _rxApmIsEnabled = ((_rxAgcIsEnabled == true) || (_rxNsIsEnabled == true));
3329470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
3330470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    return 0;
3331470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com}
3332470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
3333470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.comint
3334470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.comChannel::GetRxAgcStatus(bool& enabled, AgcModes& mode)
3335470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com{
3336470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3337470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                     "Channel::GetRxAgcStatus(enable=?, mode=?)");
3338470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
3339470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    bool enable = _rxAudioProcessingModulePtr->gain_control()->is_enabled();
3340470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    GainControl::Mode agcMode =
3341470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        _rxAudioProcessingModulePtr->gain_control()->mode();
3342470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
3343470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    enabled = enable;
3344470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
3345470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    switch (agcMode)
3346470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
3347470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        case GainControl::kFixedDigital:
3348470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            mode = kAgcFixedDigital;
3349470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            break;
3350470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        case GainControl::kAdaptiveDigital:
3351470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            mode = kAgcAdaptiveDigital;
3352470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            break;
3353470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        default:
3354470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            _engineStatisticsPtr->SetLastError(
3355470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                VE_APM_ERROR, kTraceError,
3356470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                "GetRxAgcStatus() invalid Agc mode");
3357470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            return -1;
3358470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
3359470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
3360470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    return 0;
3361470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com}
3362470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
3363470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.comint
33649213521ea98b0977c7cdabd2853060835af226f3pbos@webrtc.orgChannel::SetRxAgcConfig(AgcConfig config)
3365470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com{
3366470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3367470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                 "Channel::SetRxAgcConfig()");
3368470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
3369470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    if (_rxAudioProcessingModulePtr->gain_control()->set_target_level_dbfs(
3370470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        config.targetLeveldBOv) != 0)
3371470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
3372470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        _engineStatisticsPtr->SetLastError(
3373470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            VE_APM_ERROR, kTraceError,
3374470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            "SetRxAgcConfig() failed to set target peak |level|"
3375470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            "(or envelope) of the Agc");
3376470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        return -1;
3377470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
3378470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    if (_rxAudioProcessingModulePtr->gain_control()->set_compression_gain_db(
3379470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        config.digitalCompressionGaindB) != 0)
3380470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
3381470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        _engineStatisticsPtr->SetLastError(
3382470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            VE_APM_ERROR, kTraceError,
3383470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            "SetRxAgcConfig() failed to set the range in |gain| the"
3384470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            " digital compression stage may apply");
3385470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        return -1;
3386470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
3387470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    if (_rxAudioProcessingModulePtr->gain_control()->enable_limiter(
3388470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        config.limiterEnable) != 0)
3389470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
3390470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        _engineStatisticsPtr->SetLastError(
3391470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            VE_APM_ERROR, kTraceError,
3392470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            "SetRxAgcConfig() failed to set hard limiter to the signal");
3393470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        return -1;
3394470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
3395470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
3396470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    return 0;
3397470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com}
3398470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
3399470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.comint
3400470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.comChannel::GetRxAgcConfig(AgcConfig& config)
3401470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com{
3402470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3403470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                 "Channel::GetRxAgcConfig(config=%?)");
3404470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
3405470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    config.targetLeveldBOv =
3406470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        _rxAudioProcessingModulePtr->gain_control()->target_level_dbfs();
3407470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    config.digitalCompressionGaindB =
3408470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        _rxAudioProcessingModulePtr->gain_control()->compression_gain_db();
3409470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    config.limiterEnable =
3410470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        _rxAudioProcessingModulePtr->gain_control()->is_limiter_enabled();
3411470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
3412470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3413470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com               VoEId(_instanceId,_channelId), "GetRxAgcConfig() => "
3414470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                   "targetLeveldBOv=%u, digitalCompressionGaindB=%u,"
3415470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                   " limiterEnable=%d",
3416470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                   config.targetLeveldBOv,
3417470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                   config.digitalCompressionGaindB,
3418470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                   config.limiterEnable);
3419470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
3420470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    return 0;
3421470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com}
3422470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
3423470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com#endif // #ifdef WEBRTC_VOICE_ENGINE_AGC
3424470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
3425470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com#ifdef WEBRTC_VOICE_ENGINE_NR
3426470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
3427470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.comint
34289213521ea98b0977c7cdabd2853060835af226f3pbos@webrtc.orgChannel::SetRxNsStatus(bool enable, NsModes mode)
3429470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com{
3430470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3431470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                 "Channel::SetRxNsStatus(enable=%d, mode=%d)",
3432470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                 (int)enable, (int)mode);
3433470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
3434470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    NoiseSuppression::Level nsLevel(
3435470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        (NoiseSuppression::Level)WEBRTC_VOICE_ENGINE_RX_NS_DEFAULT_MODE);
3436470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    switch (mode)
3437470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
3438470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
3439470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        case kNsDefault:
3440470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            nsLevel = (NoiseSuppression::Level)
3441470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                WEBRTC_VOICE_ENGINE_RX_NS_DEFAULT_MODE;
3442470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            break;
3443470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        case kNsUnchanged:
3444470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            nsLevel = _rxAudioProcessingModulePtr->noise_suppression()->level();
3445470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            break;
3446470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        case kNsConference:
3447470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            nsLevel = NoiseSuppression::kHigh;
3448470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            break;
3449470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        case kNsLowSuppression:
3450470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            nsLevel = NoiseSuppression::kLow;
3451470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            break;
3452470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        case kNsModerateSuppression:
3453470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            nsLevel = NoiseSuppression::kModerate;
3454470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            break;
3455470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        case kNsHighSuppression:
3456470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            nsLevel = NoiseSuppression::kHigh;
3457470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            break;
3458470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        case kNsVeryHighSuppression:
3459470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            nsLevel = NoiseSuppression::kVeryHigh;
3460470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            break;
3461470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
3462470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
3463470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    if (_rxAudioProcessingModulePtr->noise_suppression()->set_level(nsLevel)
3464470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        != 0)
3465470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
3466470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        _engineStatisticsPtr->SetLastError(
3467470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            VE_APM_ERROR, kTraceError,
3468470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            "SetRxAgcStatus() failed to set Ns level");
3469470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        return -1;
3470470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
3471470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    if (_rxAudioProcessingModulePtr->noise_suppression()->Enable(enable) != 0)
3472470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
3473470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        _engineStatisticsPtr->SetLastError(
3474470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            VE_APM_ERROR, kTraceError,
3475470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            "SetRxAgcStatus() failed to set Agc state");
3476470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        return -1;
3477470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
3478470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
3479470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    _rxNsIsEnabled = enable;
3480470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    _rxApmIsEnabled = ((_rxAgcIsEnabled == true) || (_rxNsIsEnabled == true));
3481470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
3482470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    return 0;
3483470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com}
3484470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
3485470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.comint
3486470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.comChannel::GetRxNsStatus(bool& enabled, NsModes& mode)
3487470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com{
3488470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3489470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                 "Channel::GetRxNsStatus(enable=?, mode=?)");
3490470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
3491470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    bool enable =
3492470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        _rxAudioProcessingModulePtr->noise_suppression()->is_enabled();
3493470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    NoiseSuppression::Level ncLevel =
3494470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        _rxAudioProcessingModulePtr->noise_suppression()->level();
3495470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
3496470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    enabled = enable;
3497470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
3498470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    switch (ncLevel)
3499470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
3500470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        case NoiseSuppression::kLow:
3501470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            mode = kNsLowSuppression;
3502470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            break;
3503470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        case NoiseSuppression::kModerate:
3504470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            mode = kNsModerateSuppression;
3505470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            break;
3506470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        case NoiseSuppression::kHigh:
3507470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            mode = kNsHighSuppression;
3508470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            break;
3509470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        case NoiseSuppression::kVeryHigh:
3510470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            mode = kNsVeryHighSuppression;
3511470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            break;
3512470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
3513470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
3514470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3515470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com               VoEId(_instanceId,_channelId),
3516470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com               "GetRxNsStatus() => enabled=%d, mode=%d", enabled, mode);
3517470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    return 0;
3518470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com}
3519470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
3520470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com#endif // #ifdef WEBRTC_VOICE_ENGINE_NR
3521470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
3522470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.comint
3523470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.comChannel::RegisterRTPObserver(VoERTPObserver& observer)
3524470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com{
3525470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
3526470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                 "Channel::RegisterRTPObserver()");
35279a065d1eae9ed296e1e2eaaad73d7ca1223bfe79mflodman@webrtc.org    CriticalSectionScoped cs(&_callbackCritSect);
3528470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
3529470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    if (_rtpObserverPtr)
3530470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
3531470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        _engineStatisticsPtr->SetLastError(
3532470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            VE_INVALID_OPERATION, kTraceError,
3533470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            "RegisterRTPObserver() observer already enabled");
3534470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        return -1;
3535470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
3536470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
3537470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    _rtpObserverPtr = &observer;
3538470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    _rtpObserver = true;
3539470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
3540470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    return 0;
3541470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com}
3542470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
3543470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.comint
3544470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.comChannel::DeRegisterRTPObserver()
3545470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com{
3546470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3547470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                 "Channel::DeRegisterRTPObserver()");
35489a065d1eae9ed296e1e2eaaad73d7ca1223bfe79mflodman@webrtc.org    CriticalSectionScoped cs(&_callbackCritSect);
3549470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
3550470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    if (!_rtpObserverPtr)
3551470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
3552470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        _engineStatisticsPtr->SetLastError(
3553470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            VE_INVALID_OPERATION, kTraceWarning,
3554470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            "DeRegisterRTPObserver() observer already disabled");
3555470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        return 0;
3556470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
3557470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
3558470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    _rtpObserver = false;
3559470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    _rtpObserverPtr = NULL;
3560470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
3561470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    return 0;
3562470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com}
3563470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
3564470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.comint
3565470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.comChannel::RegisterRTCPObserver(VoERTCPObserver& observer)
3566470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com{
3567470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3568470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                 "Channel::RegisterRTCPObserver()");
35699a065d1eae9ed296e1e2eaaad73d7ca1223bfe79mflodman@webrtc.org    CriticalSectionScoped cs(&_callbackCritSect);
3570470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
3571470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    if (_rtcpObserverPtr)
3572470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
3573470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        _engineStatisticsPtr->SetLastError(
3574470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            VE_INVALID_OPERATION, kTraceError,
3575470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            "RegisterRTCPObserver() observer already enabled");
3576470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        return -1;
3577470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
3578470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
3579470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    _rtcpObserverPtr = &observer;
3580470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    _rtcpObserver = true;
3581470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
3582470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    return 0;
3583470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com}
3584470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
3585470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.comint
3586470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.comChannel::DeRegisterRTCPObserver()
3587470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com{
3588470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
3589470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                 "Channel::DeRegisterRTCPObserver()");
35909a065d1eae9ed296e1e2eaaad73d7ca1223bfe79mflodman@webrtc.org    CriticalSectionScoped cs(&_callbackCritSect);
3591470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
3592470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    if (!_rtcpObserverPtr)
3593470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
3594470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        _engineStatisticsPtr->SetLastError(
3595470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            VE_INVALID_OPERATION, kTraceWarning,
3596470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            "DeRegisterRTCPObserver() observer already disabled");
3597470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        return 0;
3598470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
3599470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
3600470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    _rtcpObserver = false;
3601470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    _rtcpObserverPtr = NULL;
3602470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
3603470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    return 0;
3604470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com}
3605470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
3606470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.comint
3607470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.comChannel::SetLocalSSRC(unsigned int ssrc)
3608470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com{
3609470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
3610470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                 "Channel::SetLocalSSRC()");
3611470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    if (_sending)
3612470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
3613470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        _engineStatisticsPtr->SetLastError(
3614470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            VE_ALREADY_SENDING, kTraceError,
3615470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            "SetLocalSSRC() already sending");
3616470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        return -1;
3617470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
36182853dde5201d9ddc284ce5efb9688f6340487acepwestin@webrtc.org    if (_rtpRtcpModule->SetSSRC(ssrc) != 0)
3619470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
3620470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        _engineStatisticsPtr->SetLastError(
3621470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            VE_RTP_RTCP_MODULE_ERROR, kTraceError,
3622470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            "SetLocalSSRC() failed to set SSRC");
3623470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        return -1;
3624470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
3625470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    return 0;
3626470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com}
3627470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
3628470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.comint
3629470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.comChannel::GetLocalSSRC(unsigned int& ssrc)
3630470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com{
36312853dde5201d9ddc284ce5efb9688f6340487acepwestin@webrtc.org    ssrc = _rtpRtcpModule->SSRC();
3632470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3633470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                 VoEId(_instanceId,_channelId),
3634470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                 "GetLocalSSRC() => ssrc=%lu", ssrc);
3635470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    return 0;
3636470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com}
3637470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
3638470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.comint
3639470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.comChannel::GetRemoteSSRC(unsigned int& ssrc)
3640470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com{
36412853dde5201d9ddc284ce5efb9688f6340487acepwestin@webrtc.org    ssrc = _rtpRtcpModule->RemoteSSRC();
3642470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3643470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                 VoEId(_instanceId,_channelId),
3644470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                 "GetRemoteSSRC() => ssrc=%lu", ssrc);
3645470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    return 0;
3646470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com}
3647470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
3648470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.comint
3649470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.comChannel::GetRemoteCSRCs(unsigned int arrCSRC[15])
3650470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com{
3651470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    if (arrCSRC == NULL)
3652470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
3653470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        _engineStatisticsPtr->SetLastError(
3654470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            VE_INVALID_ARGUMENT, kTraceError,
3655470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            "GetRemoteCSRCs() invalid array argument");
3656470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        return -1;
3657470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
36586141e13873d0fdea626de08dfec2efa2c9171c76pbos@webrtc.org    uint32_t arrOfCSRC[kRtpCsrcSize];
36596141e13873d0fdea626de08dfec2efa2c9171c76pbos@webrtc.org    int32_t CSRCs(0);
36602853dde5201d9ddc284ce5efb9688f6340487acepwestin@webrtc.org    CSRCs = _rtpRtcpModule->CSRCs(arrOfCSRC);
3661470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    if (CSRCs > 0)
3662470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
36636141e13873d0fdea626de08dfec2efa2c9171c76pbos@webrtc.org        memcpy(arrCSRC, arrOfCSRC, CSRCs * sizeof(uint32_t));
3664470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        for (int i = 0; i < (int) CSRCs; i++)
3665470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        {
3666470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3667470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                       VoEId(_instanceId, _channelId),
3668470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                       "GetRemoteCSRCs() => arrCSRC[%d]=%lu", i, arrCSRC[i]);
3669470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        }
3670470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    } else
3671470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
3672470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3673470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                   VoEId(_instanceId, _channelId),
3674470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                   "GetRemoteCSRCs() => list is empty!");
3675470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
3676470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    return CSRCs;
3677470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com}
3678470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
3679470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.comint
3680470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.comChannel::SetRTPAudioLevelIndicationStatus(bool enable, unsigned char ID)
3681470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com{
3682755b04a06ec4ae91ae7fb601c641e683f4e9e87dandrew@webrtc.org    if (_rtpAudioProc.get() == NULL)
3683755b04a06ec4ae91ae7fb601c641e683f4e9e87dandrew@webrtc.org    {
3684755b04a06ec4ae91ae7fb601c641e683f4e9e87dandrew@webrtc.org        _rtpAudioProc.reset(AudioProcessing::Create(VoEModuleId(_instanceId,
3685755b04a06ec4ae91ae7fb601c641e683f4e9e87dandrew@webrtc.org                                                                _channelId)));
3686755b04a06ec4ae91ae7fb601c641e683f4e9e87dandrew@webrtc.org        if (_rtpAudioProc.get() == NULL)
3687755b04a06ec4ae91ae7fb601c641e683f4e9e87dandrew@webrtc.org        {
3688755b04a06ec4ae91ae7fb601c641e683f4e9e87dandrew@webrtc.org            _engineStatisticsPtr->SetLastError(VE_NO_MEMORY, kTraceCritical,
3689755b04a06ec4ae91ae7fb601c641e683f4e9e87dandrew@webrtc.org                "Failed to create AudioProcessing");
3690755b04a06ec4ae91ae7fb601c641e683f4e9e87dandrew@webrtc.org            return -1;
3691755b04a06ec4ae91ae7fb601c641e683f4e9e87dandrew@webrtc.org        }
3692755b04a06ec4ae91ae7fb601c641e683f4e9e87dandrew@webrtc.org    }
3693755b04a06ec4ae91ae7fb601c641e683f4e9e87dandrew@webrtc.org
3694755b04a06ec4ae91ae7fb601c641e683f4e9e87dandrew@webrtc.org    if (_rtpAudioProc->level_estimator()->Enable(enable) !=
3695755b04a06ec4ae91ae7fb601c641e683f4e9e87dandrew@webrtc.org        AudioProcessing::kNoError)
3696755b04a06ec4ae91ae7fb601c641e683f4e9e87dandrew@webrtc.org    {
3697755b04a06ec4ae91ae7fb601c641e683f4e9e87dandrew@webrtc.org        _engineStatisticsPtr->SetLastError(VE_APM_ERROR, kTraceWarning,
3698755b04a06ec4ae91ae7fb601c641e683f4e9e87dandrew@webrtc.org            "Failed to enable AudioProcessing::level_estimator()");
3699755b04a06ec4ae91ae7fb601c641e683f4e9e87dandrew@webrtc.org    }
3700755b04a06ec4ae91ae7fb601c641e683f4e9e87dandrew@webrtc.org
3701470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    _includeAudioLevelIndication = enable;
37022853dde5201d9ddc284ce5efb9688f6340487acepwestin@webrtc.org    return _rtpRtcpModule->SetRTPAudioLevelIndicationStatus(enable, ID);
3703470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com}
3704470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.comint
3705470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.comChannel::GetRTPAudioLevelIndicationStatus(bool& enabled, unsigned char& ID)
3706470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com{
3707470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3708470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                 VoEId(_instanceId,_channelId),
3709470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                 "GetRTPAudioLevelIndicationStatus() => enabled=%d, ID=%u",
3710470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                 enabled, ID);
37112853dde5201d9ddc284ce5efb9688f6340487acepwestin@webrtc.org    return _rtpRtcpModule->GetRTPAudioLevelIndicationStatus(enabled, ID);
3712470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com}
3713470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
3714470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.comint
3715470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.comChannel::SetRTCPStatus(bool enable)
3716470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com{
3717470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3718470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                 "Channel::SetRTCPStatus()");
37192853dde5201d9ddc284ce5efb9688f6340487acepwestin@webrtc.org    if (_rtpRtcpModule->SetRTCPStatus(enable ?
3720470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        kRtcpCompound : kRtcpOff) != 0)
3721470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
3722470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        _engineStatisticsPtr->SetLastError(
3723470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            VE_RTP_RTCP_MODULE_ERROR, kTraceError,
3724470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            "SetRTCPStatus() failed to set RTCP status");
3725470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        return -1;
3726470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
3727470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    return 0;
3728470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com}
3729470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
3730470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.comint
3731470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.comChannel::GetRTCPStatus(bool& enabled)
3732470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com{
37332853dde5201d9ddc284ce5efb9688f6340487acepwestin@webrtc.org    RTCPMethod method = _rtpRtcpModule->RTCP();
3734470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    enabled = (method != kRtcpOff);
3735470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3736470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                 VoEId(_instanceId,_channelId),
3737470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                 "GetRTCPStatus() => enabled=%d", enabled);
3738470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    return 0;
3739470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com}
3740470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
3741470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.comint
3742470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.comChannel::SetRTCP_CNAME(const char cName[256])
3743470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com{
3744470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
3745470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                 "Channel::SetRTCP_CNAME()");
37462853dde5201d9ddc284ce5efb9688f6340487acepwestin@webrtc.org    if (_rtpRtcpModule->SetCNAME(cName) != 0)
3747470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
3748470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        _engineStatisticsPtr->SetLastError(
3749470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            VE_RTP_RTCP_MODULE_ERROR, kTraceError,
3750470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            "SetRTCP_CNAME() failed to set RTCP CNAME");
3751470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        return -1;
3752470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
3753470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    return 0;
3754470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com}
3755470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
3756470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.comint
3757470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.comChannel::GetRTCP_CNAME(char cName[256])
3758470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com{
37592853dde5201d9ddc284ce5efb9688f6340487acepwestin@webrtc.org    if (_rtpRtcpModule->CNAME(cName) != 0)
3760470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
3761470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        _engineStatisticsPtr->SetLastError(
3762470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            VE_RTP_RTCP_MODULE_ERROR, kTraceError,
3763470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            "GetRTCP_CNAME() failed to retrieve RTCP CNAME");
3764470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        return -1;
3765470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
3766470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3767470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                 VoEId(_instanceId, _channelId),
3768470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                 "GetRTCP_CNAME() => cName=%s", cName);
3769470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    return 0;
3770470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com}
3771470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
3772470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.comint
3773470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.comChannel::GetRemoteRTCP_CNAME(char cName[256])
3774470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com{
3775470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    if (cName == NULL)
3776470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
3777470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        _engineStatisticsPtr->SetLastError(
3778470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            VE_INVALID_ARGUMENT, kTraceError,
3779470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            "GetRemoteRTCP_CNAME() invalid CNAME input buffer");
3780470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        return -1;
3781470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
3782813e4b0af06272dada388c2d8383b2e36a1da6a6leozwang@webrtc.org    char cname[RTCP_CNAME_SIZE];
37836141e13873d0fdea626de08dfec2efa2c9171c76pbos@webrtc.org    const uint32_t remoteSSRC = _rtpRtcpModule->RemoteSSRC();
37842853dde5201d9ddc284ce5efb9688f6340487acepwestin@webrtc.org    if (_rtpRtcpModule->RemoteCNAME(remoteSSRC, cname) != 0)
3785470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
3786470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        _engineStatisticsPtr->SetLastError(
3787470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            VE_CANNOT_RETRIEVE_CNAME, kTraceError,
3788470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            "GetRemoteRTCP_CNAME() failed to retrieve remote RTCP CNAME");
3789470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        return -1;
3790470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
3791470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    strcpy(cName, cname);
3792470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3793470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                 VoEId(_instanceId, _channelId),
3794470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                 "GetRemoteRTCP_CNAME() => cName=%s", cName);
3795470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    return 0;
3796470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com}
3797470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
3798470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.comint
3799470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.comChannel::GetRemoteRTCPData(
3800470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    unsigned int& NTPHigh,
3801470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    unsigned int& NTPLow,
3802470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    unsigned int& timestamp,
3803470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    unsigned int& playoutTimestamp,
3804470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    unsigned int* jitter,
3805470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    unsigned short* fractionLost)
3806470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com{
3807470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    // --- Information from sender info in received Sender Reports
3808470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
3809470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    RTCPSenderInfo senderInfo;
38102853dde5201d9ddc284ce5efb9688f6340487acepwestin@webrtc.org    if (_rtpRtcpModule->RemoteRTCPStat(&senderInfo) != 0)
3811470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
3812470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        _engineStatisticsPtr->SetLastError(
3813470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            VE_RTP_RTCP_MODULE_ERROR, kTraceError,
3814fcd12b3b7d7e92d6f8cdfdf8277808ae52a07c36wu@webrtc.org            "GetRemoteRTCPData() failed to retrieve sender info for remote "
3815470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            "side");
3816470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        return -1;
3817470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
3818470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
3819470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    // We only utilize 12 out of 20 bytes in the sender info (ignores packet
3820470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    // and octet count)
3821470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    NTPHigh = senderInfo.NTPseconds;
3822470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    NTPLow = senderInfo.NTPfraction;
3823470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    timestamp = senderInfo.RTPtimeStamp;
3824470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
3825470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3826470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                 VoEId(_instanceId, _channelId),
3827470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                 "GetRemoteRTCPData() => NTPHigh=%lu, NTPLow=%lu, "
3828470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                 "timestamp=%lu",
3829470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                 NTPHigh, NTPLow, timestamp);
3830470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
3831470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    // --- Locally derived information
3832470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
3833470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    // This value is updated on each incoming RTCP packet (0 when no packet
3834470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    // has been received)
38351de01354e68da71bc62c81af17afeac8ed374a18pwestin@webrtc.org    playoutTimestamp = playout_timestamp_rtcp_;
3836470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
3837470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3838470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                 VoEId(_instanceId, _channelId),
3839470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                 "GetRemoteRTCPData() => playoutTimestamp=%lu",
38401de01354e68da71bc62c81af17afeac8ed374a18pwestin@webrtc.org                 playout_timestamp_rtcp_);
3841470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
3842470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    if (NULL != jitter || NULL != fractionLost)
3843470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
3844ce5990cb0bbfbf5ee5306cf990e975a2faa090b7perkj@webrtc.org        // Get all RTCP receiver report blocks that have been received on this
3845ce5990cb0bbfbf5ee5306cf990e975a2faa090b7perkj@webrtc.org        // channel. If we receive RTP packets from a remote source we know the
3846ce5990cb0bbfbf5ee5306cf990e975a2faa090b7perkj@webrtc.org        // remote SSRC and use the report block from him.
3847ce5990cb0bbfbf5ee5306cf990e975a2faa090b7perkj@webrtc.org        // Otherwise use the first report block.
3848ce5990cb0bbfbf5ee5306cf990e975a2faa090b7perkj@webrtc.org        std::vector<RTCPReportBlock> remote_stats;
38492853dde5201d9ddc284ce5efb9688f6340487acepwestin@webrtc.org        if (_rtpRtcpModule->RemoteRTCPStat(&remote_stats) != 0 ||
3850ce5990cb0bbfbf5ee5306cf990e975a2faa090b7perkj@webrtc.org            remote_stats.empty()) {
3851ce5990cb0bbfbf5ee5306cf990e975a2faa090b7perkj@webrtc.org          WEBRTC_TRACE(kTraceWarning, kTraceVoice,
3852ce5990cb0bbfbf5ee5306cf990e975a2faa090b7perkj@webrtc.org                       VoEId(_instanceId, _channelId),
3853ce5990cb0bbfbf5ee5306cf990e975a2faa090b7perkj@webrtc.org                       "GetRemoteRTCPData() failed to measure statistics due"
3854ce5990cb0bbfbf5ee5306cf990e975a2faa090b7perkj@webrtc.org                       " to lack of received RTP and/or RTCP packets");
3855ce5990cb0bbfbf5ee5306cf990e975a2faa090b7perkj@webrtc.org          return -1;
3856470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        }
3857ce5990cb0bbfbf5ee5306cf990e975a2faa090b7perkj@webrtc.org
38586141e13873d0fdea626de08dfec2efa2c9171c76pbos@webrtc.org        uint32_t remoteSSRC = _rtpRtcpModule->RemoteSSRC();
3859ce5990cb0bbfbf5ee5306cf990e975a2faa090b7perkj@webrtc.org        std::vector<RTCPReportBlock>::const_iterator it = remote_stats.begin();
3860ce5990cb0bbfbf5ee5306cf990e975a2faa090b7perkj@webrtc.org        for (; it != remote_stats.end(); ++it) {
3861ce5990cb0bbfbf5ee5306cf990e975a2faa090b7perkj@webrtc.org          if (it->remoteSSRC == remoteSSRC)
3862ce5990cb0bbfbf5ee5306cf990e975a2faa090b7perkj@webrtc.org            break;
3863470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        }
3864ce5990cb0bbfbf5ee5306cf990e975a2faa090b7perkj@webrtc.org
3865ce5990cb0bbfbf5ee5306cf990e975a2faa090b7perkj@webrtc.org        if (it == remote_stats.end()) {
3866ce5990cb0bbfbf5ee5306cf990e975a2faa090b7perkj@webrtc.org          // If we have not received any RTCP packets from this SSRC it probably
3867ce5990cb0bbfbf5ee5306cf990e975a2faa090b7perkj@webrtc.org          // means that we have not received any RTP packets.
3868ce5990cb0bbfbf5ee5306cf990e975a2faa090b7perkj@webrtc.org          // Use the first received report block instead.
3869ce5990cb0bbfbf5ee5306cf990e975a2faa090b7perkj@webrtc.org          it = remote_stats.begin();
3870ce5990cb0bbfbf5ee5306cf990e975a2faa090b7perkj@webrtc.org          remoteSSRC = it->remoteSSRC;
3871470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        }
3872ce5990cb0bbfbf5ee5306cf990e975a2faa090b7perkj@webrtc.org
387379af734807109d119573ce23daa1a2bff0f0eecaxians@webrtc.org        if (jitter) {
387479af734807109d119573ce23daa1a2bff0f0eecaxians@webrtc.org          *jitter = it->jitter;
387579af734807109d119573ce23daa1a2bff0f0eecaxians@webrtc.org          WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
387679af734807109d119573ce23daa1a2bff0f0eecaxians@webrtc.org                       VoEId(_instanceId, _channelId),
387779af734807109d119573ce23daa1a2bff0f0eecaxians@webrtc.org                       "GetRemoteRTCPData() => jitter = %lu", *jitter);
387879af734807109d119573ce23daa1a2bff0f0eecaxians@webrtc.org        }
3879ce5990cb0bbfbf5ee5306cf990e975a2faa090b7perkj@webrtc.org
388079af734807109d119573ce23daa1a2bff0f0eecaxians@webrtc.org        if (fractionLost) {
388179af734807109d119573ce23daa1a2bff0f0eecaxians@webrtc.org          *fractionLost = it->fractionLost;
388279af734807109d119573ce23daa1a2bff0f0eecaxians@webrtc.org          WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
388379af734807109d119573ce23daa1a2bff0f0eecaxians@webrtc.org                       VoEId(_instanceId, _channelId),
388479af734807109d119573ce23daa1a2bff0f0eecaxians@webrtc.org                       "GetRemoteRTCPData() => fractionLost = %lu",
388579af734807109d119573ce23daa1a2bff0f0eecaxians@webrtc.org                       *fractionLost);
388679af734807109d119573ce23daa1a2bff0f0eecaxians@webrtc.org        }
3887470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
3888470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    return 0;
3889470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com}
3890470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
3891470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.comint
38929213521ea98b0977c7cdabd2853060835af226f3pbos@webrtc.orgChannel::SendApplicationDefinedRTCPPacket(unsigned char subType,
3893470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                                             unsigned int name,
3894470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                                             const char* data,
3895470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                                             unsigned short dataLengthInBytes)
3896470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com{
3897470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
3898470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                 "Channel::SendApplicationDefinedRTCPPacket()");
3899470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    if (!_sending)
3900470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
3901470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        _engineStatisticsPtr->SetLastError(
3902470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            VE_NOT_SENDING, kTraceError,
3903470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            "SendApplicationDefinedRTCPPacket() not sending");
3904470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        return -1;
3905470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
3906470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    if (NULL == data)
3907470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
3908470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        _engineStatisticsPtr->SetLastError(
3909470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            VE_INVALID_ARGUMENT, kTraceError,
3910470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            "SendApplicationDefinedRTCPPacket() invalid data value");
3911470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        return -1;
3912470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
3913470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    if (dataLengthInBytes % 4 != 0)
3914470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
3915470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        _engineStatisticsPtr->SetLastError(
3916470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            VE_INVALID_ARGUMENT, kTraceError,
3917470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            "SendApplicationDefinedRTCPPacket() invalid length value");
3918470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        return -1;
3919470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
39202853dde5201d9ddc284ce5efb9688f6340487acepwestin@webrtc.org    RTCPMethod status = _rtpRtcpModule->RTCP();
3921470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    if (status == kRtcpOff)
3922470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
3923470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        _engineStatisticsPtr->SetLastError(
3924470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            VE_RTCP_ERROR, kTraceError,
3925470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            "SendApplicationDefinedRTCPPacket() RTCP is disabled");
3926470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        return -1;
3927470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
3928470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
3929470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    // Create and schedule the RTCP APP packet for transmission
39302853dde5201d9ddc284ce5efb9688f6340487acepwestin@webrtc.org    if (_rtpRtcpModule->SetRTCPApplicationSpecificData(
3931470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        subType,
3932470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        name,
3933470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        (const unsigned char*) data,
3934470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        dataLengthInBytes) != 0)
3935470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
3936470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        _engineStatisticsPtr->SetLastError(
3937470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            VE_SEND_ERROR, kTraceError,
3938470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            "SendApplicationDefinedRTCPPacket() failed to send RTCP packet");
3939470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        return -1;
3940470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
3941470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    return 0;
3942470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com}
3943470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
3944470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.comint
3945470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.comChannel::GetRTPStatistics(
3946470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        unsigned int& averageJitterMs,
3947470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        unsigned int& maxJitterMs,
3948470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        unsigned int& discardedPackets)
3949470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com{
39506141e13873d0fdea626de08dfec2efa2c9171c76pbos@webrtc.org    uint8_t fraction_lost(0);
39516141e13873d0fdea626de08dfec2efa2c9171c76pbos@webrtc.org    uint32_t cum_lost(0);
39526141e13873d0fdea626de08dfec2efa2c9171c76pbos@webrtc.org    uint32_t ext_max(0);
39536141e13873d0fdea626de08dfec2efa2c9171c76pbos@webrtc.org    uint32_t jitter(0);
39546141e13873d0fdea626de08dfec2efa2c9171c76pbos@webrtc.org    uint32_t max_jitter(0);
3955470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
3956470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    // The jitter statistics is updated for each received RTP packet and is
3957470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    // based on received packets.
39582853dde5201d9ddc284ce5efb9688f6340487acepwestin@webrtc.org    if (_rtpRtcpModule->StatisticsRTP(&fraction_lost,
3959470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                                     &cum_lost,
3960470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                                     &ext_max,
3961470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                                     &jitter,
3962470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                                     &max_jitter) != 0)
3963470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
3964470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        _engineStatisticsPtr->SetLastError(
3965470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            VE_CANNOT_RETRIEVE_RTP_STAT, kTraceWarning,
3966fcd12b3b7d7e92d6f8cdfdf8277808ae52a07c36wu@webrtc.org            "GetRTPStatistics() failed to read RTP statistics from the "
3967470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            "RTP/RTCP module");
3968470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
3969470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
39706141e13873d0fdea626de08dfec2efa2c9171c76pbos@webrtc.org    const int32_t playoutFrequency =
3971470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        _audioCodingModule.PlayoutFrequency();
3972470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    if (playoutFrequency > 0)
3973470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
3974470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        // Scale RTP statistics given the current playout frequency
3975470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        maxJitterMs = max_jitter / (playoutFrequency / 1000);
3976470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        averageJitterMs = jitter / (playoutFrequency / 1000);
3977470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
3978470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
3979470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    discardedPackets = _numberOfDiscardedPackets;
3980470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
3981470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3982470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com               VoEId(_instanceId, _channelId),
3983470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com               "GetRTPStatistics() => averageJitterMs = %lu, maxJitterMs = %lu,"
3984fcd12b3b7d7e92d6f8cdfdf8277808ae52a07c36wu@webrtc.org               " discardedPackets = %lu)",
3985470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com               averageJitterMs, maxJitterMs, discardedPackets);
3986470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    return 0;
3987470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com}
3988470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
39898a2fc88459dc507a67594e3127143e16af612fc9henrika@webrtc.orgint Channel::GetRemoteRTCPSenderInfo(SenderInfo* sender_info) {
39908a2fc88459dc507a67594e3127143e16af612fc9henrika@webrtc.org  if (sender_info == NULL) {
39918a2fc88459dc507a67594e3127143e16af612fc9henrika@webrtc.org    _engineStatisticsPtr->SetLastError(VE_INVALID_ARGUMENT, kTraceError,
39928a2fc88459dc507a67594e3127143e16af612fc9henrika@webrtc.org        "GetRemoteRTCPSenderInfo() invalid sender_info.");
39938a2fc88459dc507a67594e3127143e16af612fc9henrika@webrtc.org    return -1;
39948a2fc88459dc507a67594e3127143e16af612fc9henrika@webrtc.org  }
39958a2fc88459dc507a67594e3127143e16af612fc9henrika@webrtc.org
39968a2fc88459dc507a67594e3127143e16af612fc9henrika@webrtc.org  // Get the sender info from the latest received RTCP Sender Report.
39978a2fc88459dc507a67594e3127143e16af612fc9henrika@webrtc.org  RTCPSenderInfo rtcp_sender_info;
39988a2fc88459dc507a67594e3127143e16af612fc9henrika@webrtc.org  if (_rtpRtcpModule->RemoteRTCPStat(&rtcp_sender_info) != 0) {
39998a2fc88459dc507a67594e3127143e16af612fc9henrika@webrtc.org    _engineStatisticsPtr->SetLastError(VE_RTP_RTCP_MODULE_ERROR, kTraceError,
40008a2fc88459dc507a67594e3127143e16af612fc9henrika@webrtc.org        "GetRemoteRTCPSenderInfo() failed to read RTCP SR sender info.");
40018a2fc88459dc507a67594e3127143e16af612fc9henrika@webrtc.org    return -1;
40028a2fc88459dc507a67594e3127143e16af612fc9henrika@webrtc.org  }
40038a2fc88459dc507a67594e3127143e16af612fc9henrika@webrtc.org
40048a2fc88459dc507a67594e3127143e16af612fc9henrika@webrtc.org  sender_info->NTP_timestamp_high = rtcp_sender_info.NTPseconds;
40058a2fc88459dc507a67594e3127143e16af612fc9henrika@webrtc.org  sender_info->NTP_timestamp_low = rtcp_sender_info.NTPfraction;
40068a2fc88459dc507a67594e3127143e16af612fc9henrika@webrtc.org  sender_info->RTP_timestamp = rtcp_sender_info.RTPtimeStamp;
40078a2fc88459dc507a67594e3127143e16af612fc9henrika@webrtc.org  sender_info->sender_packet_count = rtcp_sender_info.sendPacketCount;
40088a2fc88459dc507a67594e3127143e16af612fc9henrika@webrtc.org  sender_info->sender_octet_count = rtcp_sender_info.sendOctetCount;
40098a2fc88459dc507a67594e3127143e16af612fc9henrika@webrtc.org  return 0;
40108a2fc88459dc507a67594e3127143e16af612fc9henrika@webrtc.org}
40118a2fc88459dc507a67594e3127143e16af612fc9henrika@webrtc.org
40128a2fc88459dc507a67594e3127143e16af612fc9henrika@webrtc.orgint Channel::GetRemoteRTCPReportBlocks(
40138a2fc88459dc507a67594e3127143e16af612fc9henrika@webrtc.org    std::vector<ReportBlock>* report_blocks) {
40148a2fc88459dc507a67594e3127143e16af612fc9henrika@webrtc.org  if (report_blocks == NULL) {
40158a2fc88459dc507a67594e3127143e16af612fc9henrika@webrtc.org    _engineStatisticsPtr->SetLastError(VE_INVALID_ARGUMENT, kTraceError,
40168a2fc88459dc507a67594e3127143e16af612fc9henrika@webrtc.org      "GetRemoteRTCPReportBlock()s invalid report_blocks.");
40178a2fc88459dc507a67594e3127143e16af612fc9henrika@webrtc.org    return -1;
40188a2fc88459dc507a67594e3127143e16af612fc9henrika@webrtc.org  }
40198a2fc88459dc507a67594e3127143e16af612fc9henrika@webrtc.org
40208a2fc88459dc507a67594e3127143e16af612fc9henrika@webrtc.org  // Get the report blocks from the latest received RTCP Sender or Receiver
40218a2fc88459dc507a67594e3127143e16af612fc9henrika@webrtc.org  // Report. Each element in the vector contains the sender's SSRC and a
40228a2fc88459dc507a67594e3127143e16af612fc9henrika@webrtc.org  // report block according to RFC 3550.
40238a2fc88459dc507a67594e3127143e16af612fc9henrika@webrtc.org  std::vector<RTCPReportBlock> rtcp_report_blocks;
40248a2fc88459dc507a67594e3127143e16af612fc9henrika@webrtc.org  if (_rtpRtcpModule->RemoteRTCPStat(&rtcp_report_blocks) != 0) {
40258a2fc88459dc507a67594e3127143e16af612fc9henrika@webrtc.org    _engineStatisticsPtr->SetLastError(VE_RTP_RTCP_MODULE_ERROR, kTraceError,
40268a2fc88459dc507a67594e3127143e16af612fc9henrika@webrtc.org        "GetRemoteRTCPReportBlocks() failed to read RTCP SR/RR report block.");
40278a2fc88459dc507a67594e3127143e16af612fc9henrika@webrtc.org    return -1;
40288a2fc88459dc507a67594e3127143e16af612fc9henrika@webrtc.org  }
40298a2fc88459dc507a67594e3127143e16af612fc9henrika@webrtc.org
40308a2fc88459dc507a67594e3127143e16af612fc9henrika@webrtc.org  if (rtcp_report_blocks.empty())
40318a2fc88459dc507a67594e3127143e16af612fc9henrika@webrtc.org    return 0;
40328a2fc88459dc507a67594e3127143e16af612fc9henrika@webrtc.org
40338a2fc88459dc507a67594e3127143e16af612fc9henrika@webrtc.org  std::vector<RTCPReportBlock>::const_iterator it = rtcp_report_blocks.begin();
40348a2fc88459dc507a67594e3127143e16af612fc9henrika@webrtc.org  for (; it != rtcp_report_blocks.end(); ++it) {
40358a2fc88459dc507a67594e3127143e16af612fc9henrika@webrtc.org    ReportBlock report_block;
40368a2fc88459dc507a67594e3127143e16af612fc9henrika@webrtc.org    report_block.sender_SSRC = it->remoteSSRC;
40378a2fc88459dc507a67594e3127143e16af612fc9henrika@webrtc.org    report_block.source_SSRC = it->sourceSSRC;
40388a2fc88459dc507a67594e3127143e16af612fc9henrika@webrtc.org    report_block.fraction_lost = it->fractionLost;
40398a2fc88459dc507a67594e3127143e16af612fc9henrika@webrtc.org    report_block.cumulative_num_packets_lost = it->cumulativeLost;
40408a2fc88459dc507a67594e3127143e16af612fc9henrika@webrtc.org    report_block.extended_highest_sequence_number = it->extendedHighSeqNum;
40418a2fc88459dc507a67594e3127143e16af612fc9henrika@webrtc.org    report_block.interarrival_jitter = it->jitter;
40428a2fc88459dc507a67594e3127143e16af612fc9henrika@webrtc.org    report_block.last_SR_timestamp = it->lastSR;
40438a2fc88459dc507a67594e3127143e16af612fc9henrika@webrtc.org    report_block.delay_since_last_SR = it->delaySinceLastSR;
40448a2fc88459dc507a67594e3127143e16af612fc9henrika@webrtc.org    report_blocks->push_back(report_block);
40458a2fc88459dc507a67594e3127143e16af612fc9henrika@webrtc.org  }
40468a2fc88459dc507a67594e3127143e16af612fc9henrika@webrtc.org  return 0;
40478a2fc88459dc507a67594e3127143e16af612fc9henrika@webrtc.org}
40488a2fc88459dc507a67594e3127143e16af612fc9henrika@webrtc.org
4049470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.comint
4050470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.comChannel::GetRTPStatistics(CallStatistics& stats)
4051470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com{
40526141e13873d0fdea626de08dfec2efa2c9171c76pbos@webrtc.org    uint8_t fraction_lost(0);
40536141e13873d0fdea626de08dfec2efa2c9171c76pbos@webrtc.org    uint32_t cum_lost(0);
40546141e13873d0fdea626de08dfec2efa2c9171c76pbos@webrtc.org    uint32_t ext_max(0);
40556141e13873d0fdea626de08dfec2efa2c9171c76pbos@webrtc.org    uint32_t jitter(0);
40566141e13873d0fdea626de08dfec2efa2c9171c76pbos@webrtc.org    uint32_t max_jitter(0);
4057470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
4058470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    // --- Part one of the final structure (four values)
4059470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
4060470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    // The jitter statistics is updated for each received RTP packet and is
4061470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    // based on received packets.
40622853dde5201d9ddc284ce5efb9688f6340487acepwestin@webrtc.org    if (_rtpRtcpModule->StatisticsRTP(&fraction_lost,
4063470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                                     &cum_lost,
4064470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                                     &ext_max,
4065470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                                     &jitter,
4066470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                                     &max_jitter) != 0)
4067470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
4068470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        _engineStatisticsPtr->SetLastError(
4069470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            VE_CANNOT_RETRIEVE_RTP_STAT, kTraceWarning,
4070470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            "GetRTPStatistics() failed to read RTP statistics from the "
4071470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            "RTP/RTCP module");
4072470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
4073470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
4074470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    stats.fractionLost = fraction_lost;
4075470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    stats.cumulativeLost = cum_lost;
4076470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    stats.extendedMax = ext_max;
4077470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    stats.jitterSamples = jitter;
4078470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
4079470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
4080470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                 VoEId(_instanceId, _channelId),
4081470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                 "GetRTPStatistics() => fractionLost=%lu, cumulativeLost=%lu,"
4082fcd12b3b7d7e92d6f8cdfdf8277808ae52a07c36wu@webrtc.org                 " extendedMax=%lu, jitterSamples=%li)",
4083470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                 stats.fractionLost, stats.cumulativeLost, stats.extendedMax,
4084470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                 stats.jitterSamples);
4085470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
4086470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    // --- Part two of the final structure (one value)
4087470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
40886141e13873d0fdea626de08dfec2efa2c9171c76pbos@webrtc.org    uint16_t RTT(0);
40892853dde5201d9ddc284ce5efb9688f6340487acepwestin@webrtc.org    RTCPMethod method = _rtpRtcpModule->RTCP();
4090470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    if (method == kRtcpOff)
4091470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
4092470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        WEBRTC_TRACE(kTraceWarning, kTraceVoice,
4093470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                     VoEId(_instanceId, _channelId),
4094fcd12b3b7d7e92d6f8cdfdf8277808ae52a07c36wu@webrtc.org                     "GetRTPStatistics() RTCP is disabled => valid RTT "
4095470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                     "measurements cannot be retrieved");
4096470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    } else
4097470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
4098470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        // The remote SSRC will be zero if no RTP packet has been received.
40996141e13873d0fdea626de08dfec2efa2c9171c76pbos@webrtc.org        uint32_t remoteSSRC = _rtpRtcpModule->RemoteSSRC();
4100470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        if (remoteSSRC > 0)
4101470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        {
41026141e13873d0fdea626de08dfec2efa2c9171c76pbos@webrtc.org            uint16_t avgRTT(0);
41036141e13873d0fdea626de08dfec2efa2c9171c76pbos@webrtc.org            uint16_t maxRTT(0);
41046141e13873d0fdea626de08dfec2efa2c9171c76pbos@webrtc.org            uint16_t minRTT(0);
4105470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
41062853dde5201d9ddc284ce5efb9688f6340487acepwestin@webrtc.org            if (_rtpRtcpModule->RTT(remoteSSRC, &RTT, &avgRTT, &minRTT, &maxRTT)
4107470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                != 0)
4108470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            {
4109470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                WEBRTC_TRACE(kTraceWarning, kTraceVoice,
4110470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                             VoEId(_instanceId, _channelId),
4111fcd12b3b7d7e92d6f8cdfdf8277808ae52a07c36wu@webrtc.org                             "GetRTPStatistics() failed to retrieve RTT from "
4112470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                             "the RTP/RTCP module");
4113470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            }
4114470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        } else
4115470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        {
4116470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            WEBRTC_TRACE(kTraceWarning, kTraceVoice,
4117470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                         VoEId(_instanceId, _channelId),
4118fcd12b3b7d7e92d6f8cdfdf8277808ae52a07c36wu@webrtc.org                         "GetRTPStatistics() failed to measure RTT since no "
4119470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                         "RTP packets have been received yet");
4120470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        }
4121470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
4122470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
4123470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    stats.rttMs = static_cast<int> (RTT);
4124470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
4125470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
4126470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                 VoEId(_instanceId, _channelId),
4127470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                 "GetRTPStatistics() => rttMs=%d", stats.rttMs);
4128470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
4129470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    // --- Part three of the final structure (four values)
4130470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
41316141e13873d0fdea626de08dfec2efa2c9171c76pbos@webrtc.org    uint32_t bytesSent(0);
41326141e13873d0fdea626de08dfec2efa2c9171c76pbos@webrtc.org    uint32_t packetsSent(0);
41336141e13873d0fdea626de08dfec2efa2c9171c76pbos@webrtc.org    uint32_t bytesReceived(0);
41346141e13873d0fdea626de08dfec2efa2c9171c76pbos@webrtc.org    uint32_t packetsReceived(0);
4135470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
41362853dde5201d9ddc284ce5efb9688f6340487acepwestin@webrtc.org    if (_rtpRtcpModule->DataCountersRTP(&bytesSent,
4137470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                                       &packetsSent,
4138470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                                       &bytesReceived,
4139470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                                       &packetsReceived) != 0)
4140470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
4141470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        WEBRTC_TRACE(kTraceWarning, kTraceVoice,
4142470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                     VoEId(_instanceId, _channelId),
4143470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                     "GetRTPStatistics() failed to retrieve RTP datacounters =>"
4144fcd12b3b7d7e92d6f8cdfdf8277808ae52a07c36wu@webrtc.org                     " output will not be complete");
4145470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
4146470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
4147470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    stats.bytesSent = bytesSent;
4148470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    stats.packetsSent = packetsSent;
4149470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    stats.bytesReceived = bytesReceived;
4150470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    stats.packetsReceived = packetsReceived;
4151470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
4152470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
4153470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                 VoEId(_instanceId, _channelId),
4154470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                 "GetRTPStatistics() => bytesSent=%d, packetsSent=%d,"
4155fcd12b3b7d7e92d6f8cdfdf8277808ae52a07c36wu@webrtc.org                 " bytesReceived=%d, packetsReceived=%d)",
4156470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                 stats.bytesSent, stats.packetsSent, stats.bytesReceived,
4157470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                 stats.packetsReceived);
4158470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
4159470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    return 0;
4160470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com}
4161470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
416242259e7ebc7126f5a7036940fcab65b3f8d2af38turaj@webrtc.orgint Channel::SetFECStatus(bool enable, int redPayloadtype) {
416342259e7ebc7126f5a7036940fcab65b3f8d2af38turaj@webrtc.org  WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
416442259e7ebc7126f5a7036940fcab65b3f8d2af38turaj@webrtc.org               "Channel::SetFECStatus()");
416542259e7ebc7126f5a7036940fcab65b3f8d2af38turaj@webrtc.org
41668c8ad85c5d70c38cea82f5b17794a4e7ab4cf531turaj@webrtc.org  if (enable) {
41678c8ad85c5d70c38cea82f5b17794a4e7ab4cf531turaj@webrtc.org    if (redPayloadtype < 0 || redPayloadtype > 127) {
41688c8ad85c5d70c38cea82f5b17794a4e7ab4cf531turaj@webrtc.org      _engineStatisticsPtr->SetLastError(
41698c8ad85c5d70c38cea82f5b17794a4e7ab4cf531turaj@webrtc.org          VE_PLTYPE_ERROR, kTraceError,
41708c8ad85c5d70c38cea82f5b17794a4e7ab4cf531turaj@webrtc.org          "SetFECStatus() invalid RED payload type");
41718c8ad85c5d70c38cea82f5b17794a4e7ab4cf531turaj@webrtc.org      return -1;
41728c8ad85c5d70c38cea82f5b17794a4e7ab4cf531turaj@webrtc.org    }
41738c8ad85c5d70c38cea82f5b17794a4e7ab4cf531turaj@webrtc.org
41748c8ad85c5d70c38cea82f5b17794a4e7ab4cf531turaj@webrtc.org    if (SetRedPayloadType(redPayloadtype) < 0) {
41758c8ad85c5d70c38cea82f5b17794a4e7ab4cf531turaj@webrtc.org      _engineStatisticsPtr->SetLastError(
41768c8ad85c5d70c38cea82f5b17794a4e7ab4cf531turaj@webrtc.org          VE_CODEC_ERROR, kTraceError,
41778c8ad85c5d70c38cea82f5b17794a4e7ab4cf531turaj@webrtc.org          "SetSecondarySendCodec() Failed to register RED ACM");
41788c8ad85c5d70c38cea82f5b17794a4e7ab4cf531turaj@webrtc.org      return -1;
41798c8ad85c5d70c38cea82f5b17794a4e7ab4cf531turaj@webrtc.org    }
418042259e7ebc7126f5a7036940fcab65b3f8d2af38turaj@webrtc.org  }
41812cf22a6abce2d38e673505a4cfd5624a3710b5cdperkj@webrtc.org
418242259e7ebc7126f5a7036940fcab65b3f8d2af38turaj@webrtc.org  if (_audioCodingModule.SetFECStatus(enable) != 0) {
418342259e7ebc7126f5a7036940fcab65b3f8d2af38turaj@webrtc.org    _engineStatisticsPtr->SetLastError(
418442259e7ebc7126f5a7036940fcab65b3f8d2af38turaj@webrtc.org        VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
418542259e7ebc7126f5a7036940fcab65b3f8d2af38turaj@webrtc.org        "SetFECStatus() failed to set FEC state in the ACM");
418642259e7ebc7126f5a7036940fcab65b3f8d2af38turaj@webrtc.org    return -1;
418742259e7ebc7126f5a7036940fcab65b3f8d2af38turaj@webrtc.org  }
418842259e7ebc7126f5a7036940fcab65b3f8d2af38turaj@webrtc.org  return 0;
4189470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com}
4190470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
4191470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.comint
4192470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.comChannel::GetFECStatus(bool& enabled, int& redPayloadtype)
4193470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com{
4194470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    enabled = _audioCodingModule.FECStatus();
4195470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    if (enabled)
4196470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
41976141e13873d0fdea626de08dfec2efa2c9171c76pbos@webrtc.org        int8_t payloadType(0);
41982853dde5201d9ddc284ce5efb9688f6340487acepwestin@webrtc.org        if (_rtpRtcpModule->SendREDPayloadType(payloadType) != 0)
4199470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        {
4200470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            _engineStatisticsPtr->SetLastError(
4201470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                VE_RTP_RTCP_MODULE_ERROR, kTraceError,
4202470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                "GetFECStatus() failed to retrieve RED PT from RTP/RTCP "
4203470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                "module");
4204470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            return -1;
4205470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        }
4206470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
4207470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                   VoEId(_instanceId, _channelId),
4208470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                   "GetFECStatus() => enabled=%d, redPayloadtype=%d",
4209470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                   enabled, redPayloadtype);
4210470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        return 0;
4211470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
4212470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
4213470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                 VoEId(_instanceId, _channelId),
4214470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                 "GetFECStatus() => enabled=%d", enabled);
4215470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    return 0;
4216470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com}
4217470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
4218470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.comint
4219470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.comChannel::StartRTPDump(const char fileNameUTF8[1024],
4220470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                      RTPDirections direction)
4221470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com{
4222470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
4223470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                 "Channel::StartRTPDump()");
4224470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    if ((direction != kRtpIncoming) && (direction != kRtpOutgoing))
4225470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
4226470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        _engineStatisticsPtr->SetLastError(
4227470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            VE_INVALID_ARGUMENT, kTraceError,
4228470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            "StartRTPDump() invalid RTP direction");
4229470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        return -1;
4230470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
4231470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    RtpDump* rtpDumpPtr = (direction == kRtpIncoming) ?
4232470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        &_rtpDumpIn : &_rtpDumpOut;
4233470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    if (rtpDumpPtr == NULL)
4234470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
4235470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        assert(false);
4236470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        return -1;
4237470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
4238470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    if (rtpDumpPtr->IsActive())
4239470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
4240470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        rtpDumpPtr->Stop();
4241470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
4242470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    if (rtpDumpPtr->Start(fileNameUTF8) != 0)
4243470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
4244470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        _engineStatisticsPtr->SetLastError(
4245470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            VE_BAD_FILE, kTraceError,
4246470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            "StartRTPDump() failed to create file");
4247470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        return -1;
4248470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
4249470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    return 0;
4250470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com}
4251470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
4252470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.comint
4253470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.comChannel::StopRTPDump(RTPDirections direction)
4254470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com{
4255470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
4256470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                 "Channel::StopRTPDump()");
4257470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    if ((direction != kRtpIncoming) && (direction != kRtpOutgoing))
4258470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
4259470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        _engineStatisticsPtr->SetLastError(
4260470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            VE_INVALID_ARGUMENT, kTraceError,
4261470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            "StopRTPDump() invalid RTP direction");
4262470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        return -1;
4263470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
4264470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    RtpDump* rtpDumpPtr = (direction == kRtpIncoming) ?
4265470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        &_rtpDumpIn : &_rtpDumpOut;
4266470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    if (rtpDumpPtr == NULL)
4267470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
4268470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        assert(false);
4269470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        return -1;
4270470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
4271470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    if (!rtpDumpPtr->IsActive())
4272470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
4273470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        return 0;
4274470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
4275470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    return rtpDumpPtr->Stop();
4276470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com}
4277470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
4278470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.combool
4279470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.comChannel::RTPDumpIsActive(RTPDirections direction)
4280470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com{
4281470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    if ((direction != kRtpIncoming) &&
4282470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        (direction != kRtpOutgoing))
4283470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
4284470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        _engineStatisticsPtr->SetLastError(
4285470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            VE_INVALID_ARGUMENT, kTraceError,
4286470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            "RTPDumpIsActive() invalid RTP direction");
4287470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        return false;
4288470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
4289470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    RtpDump* rtpDumpPtr = (direction == kRtpIncoming) ?
4290470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        &_rtpDumpIn : &_rtpDumpOut;
4291470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    return rtpDumpPtr->IsActive();
4292470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com}
4293470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
4294470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.comint
4295470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.comChannel::InsertExtraRTPPacket(unsigned char payloadType,
4296470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                              bool markerBit,
4297470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                              const char* payloadData,
4298470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                              unsigned short payloadSize)
4299470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com{
4300470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
4301470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com               "Channel::InsertExtraRTPPacket()");
4302470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    if (payloadType > 127)
4303470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
4304470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        _engineStatisticsPtr->SetLastError(
4305470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            VE_INVALID_PLTYPE, kTraceError,
4306470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            "InsertExtraRTPPacket() invalid payload type");
4307470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        return -1;
4308470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
4309470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    if (payloadData == NULL)
4310470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
4311470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        _engineStatisticsPtr->SetLastError(
4312470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            VE_INVALID_ARGUMENT, kTraceError,
4313470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            "InsertExtraRTPPacket() invalid payload data");
4314470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        return -1;
4315470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
43162853dde5201d9ddc284ce5efb9688f6340487acepwestin@webrtc.org    if (payloadSize > _rtpRtcpModule->MaxDataPayloadLength())
4317470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
4318470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        _engineStatisticsPtr->SetLastError(
4319470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            VE_INVALID_ARGUMENT, kTraceError,
4320470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            "InsertExtraRTPPacket() invalid payload size");
4321470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        return -1;
4322470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
4323470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    if (!_sending)
4324470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
4325470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        _engineStatisticsPtr->SetLastError(
4326470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            VE_NOT_SENDING, kTraceError,
4327470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            "InsertExtraRTPPacket() not sending");
4328470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        return -1;
4329470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
4330470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
4331470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    // Create extra RTP packet by calling RtpRtcp::SendOutgoingData().
4332470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    // Transport::SendPacket() will be called by the module when the RTP packet
4333470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    // is created.
4334470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    // The call to SendOutgoingData() does *not* modify the timestamp and
4335470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    // payloadtype to ensure that the RTP module generates a valid RTP packet
4336470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    // (user might utilize a non-registered payload type).
4337470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    // The marker bit and payload type will be replaced just before the actual
4338470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    // transmission, i.e., the actual modification is done *after* the RTP
4339470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    // module has delivered its RTP packet back to the VoE.
4340470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    // We will use the stored values above when the packet is modified
4341470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    // (see Channel::SendPacket()).
4342470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
4343470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    _extraPayloadType = payloadType;
4344470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    _extraMarkerBit = markerBit;
4345470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    _insertExtraRTPPacket = true;
4346470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
43472853dde5201d9ddc284ce5efb9688f6340487acepwestin@webrtc.org    if (_rtpRtcpModule->SendOutgoingData(kAudioFrameSpeech,
4348470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                                        _lastPayloadType,
4349470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                                        _lastLocalTimeStamp,
4350ddfdfed3b55de3da5fda9a55d34e46d6e422baafstefan@webrtc.org                                        // Leaving the time when this frame was
4351ddfdfed3b55de3da5fda9a55d34e46d6e422baafstefan@webrtc.org                                        // received from the capture device as
4352ddfdfed3b55de3da5fda9a55d34e46d6e422baafstefan@webrtc.org                                        // undefined for voice for now.
4353ddfdfed3b55de3da5fda9a55d34e46d6e422baafstefan@webrtc.org                                        -1,
43546141e13873d0fdea626de08dfec2efa2c9171c76pbos@webrtc.org                                        (const uint8_t*) payloadData,
4355470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                                        payloadSize) != 0)
4356470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
4357470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        _engineStatisticsPtr->SetLastError(
4358470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            VE_RTP_RTCP_MODULE_ERROR, kTraceError,
4359470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            "InsertExtraRTPPacket() failed to send extra RTP packet");
4360470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        return -1;
4361470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
4362470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
4363470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    return 0;
4364470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com}
4365470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
43666141e13873d0fdea626de08dfec2efa2c9171c76pbos@webrtc.orguint32_t
4367755b04a06ec4ae91ae7fb601c641e683f4e9e87dandrew@webrtc.orgChannel::Demultiplex(const AudioFrame& audioFrame)
4368470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com{
4369470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
4370755b04a06ec4ae91ae7fb601c641e683f4e9e87dandrew@webrtc.org                 "Channel::Demultiplex()");
4371ae1a58bba4f926d149a5f39243269c3f6625f494andrew@webrtc.org    _audioFrame.CopyFrom(audioFrame);
437263a509858d3988299726640c664b699d6229a1d4andrew@webrtc.org    _audioFrame.id_ = _channelId;
4373470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    return 0;
4374470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com}
4375470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
43766141e13873d0fdea626de08dfec2efa2c9171c76pbos@webrtc.orguint32_t
43770b0665acc1464d68e878f203bbc8772a0e32402dxians@google.comChannel::PrepareEncodeAndSend(int mixingFrequency)
4378470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com{
4379470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
4380470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                 "Channel::PrepareEncodeAndSend()");
4381470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
438263a509858d3988299726640c664b699d6229a1d4andrew@webrtc.org    if (_audioFrame.samples_per_channel_ == 0)
4383470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
4384470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        WEBRTC_TRACE(kTraceWarning, kTraceVoice, VoEId(_instanceId,_channelId),
4385470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                     "Channel::PrepareEncodeAndSend() invalid audio frame");
4386470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        return -1;
4387470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
4388470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
4389470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    if (_inputFilePlaying)
4390470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
4391470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        MixOrReplaceAudioWithFile(mixingFrequency);
4392470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
4393470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
4394470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    if (_mute)
4395470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
4396470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        AudioFrameOperations::Mute(_audioFrame);
4397470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
4398470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
4399470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    if (_inputExternalMedia)
4400470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
44019a065d1eae9ed296e1e2eaaad73d7ca1223bfe79mflodman@webrtc.org        CriticalSectionScoped cs(&_callbackCritSect);
440263a509858d3988299726640c664b699d6229a1d4andrew@webrtc.org        const bool isStereo = (_audioFrame.num_channels_ == 2);
4403470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        if (_inputExternalMediaCallbackPtr)
4404470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        {
4405470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            _inputExternalMediaCallbackPtr->Process(
4406470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                _channelId,
4407470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                kRecordingPerChannel,
44086141e13873d0fdea626de08dfec2efa2c9171c76pbos@webrtc.org               (int16_t*)_audioFrame.data_,
440963a509858d3988299726640c664b699d6229a1d4andrew@webrtc.org                _audioFrame.samples_per_channel_,
441063a509858d3988299726640c664b699d6229a1d4andrew@webrtc.org                _audioFrame.sample_rate_hz_,
4411470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                isStereo);
4412470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        }
4413470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
4414470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
4415470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    InsertInbandDtmfTone();
4416470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
4417755b04a06ec4ae91ae7fb601c641e683f4e9e87dandrew@webrtc.org    if (_includeAudioLevelIndication)
4418755b04a06ec4ae91ae7fb601c641e683f4e9e87dandrew@webrtc.org    {
4419755b04a06ec4ae91ae7fb601c641e683f4e9e87dandrew@webrtc.org        assert(_rtpAudioProc.get() != NULL);
4420755b04a06ec4ae91ae7fb601c641e683f4e9e87dandrew@webrtc.org
4421755b04a06ec4ae91ae7fb601c641e683f4e9e87dandrew@webrtc.org        // Check if settings need to be updated.
442263a509858d3988299726640c664b699d6229a1d4andrew@webrtc.org        if (_rtpAudioProc->sample_rate_hz() != _audioFrame.sample_rate_hz_)
4423755b04a06ec4ae91ae7fb601c641e683f4e9e87dandrew@webrtc.org        {
442463a509858d3988299726640c664b699d6229a1d4andrew@webrtc.org            if (_rtpAudioProc->set_sample_rate_hz(_audioFrame.sample_rate_hz_) !=
4425755b04a06ec4ae91ae7fb601c641e683f4e9e87dandrew@webrtc.org                AudioProcessing::kNoError)
4426755b04a06ec4ae91ae7fb601c641e683f4e9e87dandrew@webrtc.org            {
4427755b04a06ec4ae91ae7fb601c641e683f4e9e87dandrew@webrtc.org                WEBRTC_TRACE(kTraceWarning, kTraceVoice,
4428755b04a06ec4ae91ae7fb601c641e683f4e9e87dandrew@webrtc.org                             VoEId(_instanceId, _channelId),
4429755b04a06ec4ae91ae7fb601c641e683f4e9e87dandrew@webrtc.org                             "Error setting AudioProcessing sample rate");
4430755b04a06ec4ae91ae7fb601c641e683f4e9e87dandrew@webrtc.org                return -1;
4431755b04a06ec4ae91ae7fb601c641e683f4e9e87dandrew@webrtc.org            }
4432755b04a06ec4ae91ae7fb601c641e683f4e9e87dandrew@webrtc.org        }
4433755b04a06ec4ae91ae7fb601c641e683f4e9e87dandrew@webrtc.org
443463a509858d3988299726640c664b699d6229a1d4andrew@webrtc.org        if (_rtpAudioProc->num_input_channels() != _audioFrame.num_channels_)
4435755b04a06ec4ae91ae7fb601c641e683f4e9e87dandrew@webrtc.org        {
443663a509858d3988299726640c664b699d6229a1d4andrew@webrtc.org            if (_rtpAudioProc->set_num_channels(_audioFrame.num_channels_,
443763a509858d3988299726640c664b699d6229a1d4andrew@webrtc.org                                                _audioFrame.num_channels_)
4438755b04a06ec4ae91ae7fb601c641e683f4e9e87dandrew@webrtc.org                != AudioProcessing::kNoError)
4439755b04a06ec4ae91ae7fb601c641e683f4e9e87dandrew@webrtc.org            {
4440755b04a06ec4ae91ae7fb601c641e683f4e9e87dandrew@webrtc.org                WEBRTC_TRACE(kTraceWarning, kTraceVoice,
4441755b04a06ec4ae91ae7fb601c641e683f4e9e87dandrew@webrtc.org                             VoEId(_instanceId, _channelId),
4442755b04a06ec4ae91ae7fb601c641e683f4e9e87dandrew@webrtc.org                             "Error setting AudioProcessing channels");
4443755b04a06ec4ae91ae7fb601c641e683f4e9e87dandrew@webrtc.org                return -1;
4444755b04a06ec4ae91ae7fb601c641e683f4e9e87dandrew@webrtc.org            }
4445755b04a06ec4ae91ae7fb601c641e683f4e9e87dandrew@webrtc.org        }
4446755b04a06ec4ae91ae7fb601c641e683f4e9e87dandrew@webrtc.org
4447755b04a06ec4ae91ae7fb601c641e683f4e9e87dandrew@webrtc.org        // Performs level analysis only; does not affect the signal.
4448755b04a06ec4ae91ae7fb601c641e683f4e9e87dandrew@webrtc.org        _rtpAudioProc->ProcessStream(&_audioFrame);
4449755b04a06ec4ae91ae7fb601c641e683f4e9e87dandrew@webrtc.org    }
4450755b04a06ec4ae91ae7fb601c641e683f4e9e87dandrew@webrtc.org
4451470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    return 0;
4452470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com}
4453470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
44546141e13873d0fdea626de08dfec2efa2c9171c76pbos@webrtc.orguint32_t
4455470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.comChannel::EncodeAndSend()
4456470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com{
4457470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
4458470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                 "Channel::EncodeAndSend()");
4459470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
446063a509858d3988299726640c664b699d6229a1d4andrew@webrtc.org    assert(_audioFrame.num_channels_ <= 2);
446163a509858d3988299726640c664b699d6229a1d4andrew@webrtc.org    if (_audioFrame.samples_per_channel_ == 0)
4462470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
4463470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        WEBRTC_TRACE(kTraceWarning, kTraceVoice, VoEId(_instanceId,_channelId),
4464470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                     "Channel::EncodeAndSend() invalid audio frame");
4465470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        return -1;
4466470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
4467470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
446863a509858d3988299726640c664b699d6229a1d4andrew@webrtc.org    _audioFrame.id_ = _channelId;
4469470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
4470470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    // --- Add 10ms of raw (PCM) audio data to the encoder @ 32kHz.
4471470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
4472470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    // The ACM resamples internally.
447363a509858d3988299726640c664b699d6229a1d4andrew@webrtc.org    _audioFrame.timestamp_ = _timeStamp;
4474470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    if (_audioCodingModule.Add10MsData((AudioFrame&)_audioFrame) != 0)
4475470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
4476470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        WEBRTC_TRACE(kTraceError, kTraceVoice, VoEId(_instanceId,_channelId),
4477470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                     "Channel::EncodeAndSend() ACM encoding failed");
4478470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        return -1;
4479470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
4480470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
448163a509858d3988299726640c664b699d6229a1d4andrew@webrtc.org    _timeStamp += _audioFrame.samples_per_channel_;
4482470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
4483470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    // --- Encode if complete frame is ready
4484470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
4485470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    // This call will trigger AudioPacketizationCallback::SendData if encoding
4486470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    // is done and payload is ready for packetization and transmission.
4487470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    return _audioCodingModule.Process();
4488470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com}
4489470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
4490470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.comint Channel::RegisterExternalMediaProcessing(
4491470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    ProcessingTypes type,
4492470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    VoEMediaProcess& processObject)
4493470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com{
4494470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
4495470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                 "Channel::RegisterExternalMediaProcessing()");
4496470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
44979a065d1eae9ed296e1e2eaaad73d7ca1223bfe79mflodman@webrtc.org    CriticalSectionScoped cs(&_callbackCritSect);
4498470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
4499470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    if (kPlaybackPerChannel == type)
4500470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
4501470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        if (_outputExternalMediaCallbackPtr)
4502470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        {
4503470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            _engineStatisticsPtr->SetLastError(
4504470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                VE_INVALID_OPERATION, kTraceError,
4505470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                "Channel::RegisterExternalMediaProcessing() "
4506470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                "output external media already enabled");
4507470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            return -1;
4508470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        }
4509470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        _outputExternalMediaCallbackPtr = &processObject;
4510470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        _outputExternalMedia = true;
4511470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
4512470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    else if (kRecordingPerChannel == type)
4513470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
4514470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        if (_inputExternalMediaCallbackPtr)
4515470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        {
4516470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            _engineStatisticsPtr->SetLastError(
4517470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                VE_INVALID_OPERATION, kTraceError,
4518470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                "Channel::RegisterExternalMediaProcessing() "
4519470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                "output external media already enabled");
4520470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            return -1;
4521470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        }
4522470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        _inputExternalMediaCallbackPtr = &processObject;
4523470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        _inputExternalMedia = true;
4524470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
4525470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    return 0;
4526470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com}
4527470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
4528470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.comint Channel::DeRegisterExternalMediaProcessing(ProcessingTypes type)
4529470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com{
4530470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
4531470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                 "Channel::DeRegisterExternalMediaProcessing()");
4532470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
45339a065d1eae9ed296e1e2eaaad73d7ca1223bfe79mflodman@webrtc.org    CriticalSectionScoped cs(&_callbackCritSect);
4534470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
4535470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    if (kPlaybackPerChannel == type)
4536470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
4537470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        if (!_outputExternalMediaCallbackPtr)
4538470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        {
4539470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            _engineStatisticsPtr->SetLastError(
4540470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                VE_INVALID_OPERATION, kTraceWarning,
4541470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                "Channel::DeRegisterExternalMediaProcessing() "
4542470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                "output external media already disabled");
4543470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            return 0;
4544470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        }
4545470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        _outputExternalMedia = false;
4546470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        _outputExternalMediaCallbackPtr = NULL;
4547470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
4548470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    else if (kRecordingPerChannel == type)
4549470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
4550470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        if (!_inputExternalMediaCallbackPtr)
4551470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        {
4552470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            _engineStatisticsPtr->SetLastError(
4553470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                VE_INVALID_OPERATION, kTraceWarning,
4554470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                "Channel::DeRegisterExternalMediaProcessing() "
4555470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                "input external media already disabled");
4556470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            return 0;
4557470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        }
4558470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        _inputExternalMedia = false;
4559470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        _inputExternalMediaCallbackPtr = NULL;
4560470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
4561470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
4562470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    return 0;
4563470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com}
4564470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
45651b60ceb499ee35460886f2bfaecee1f47319f925roosa@google.comint Channel::SetExternalMixing(bool enabled) {
45661b60ceb499ee35460886f2bfaecee1f47319f925roosa@google.com    WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
45671b60ceb499ee35460886f2bfaecee1f47319f925roosa@google.com                 "Channel::SetExternalMixing(enabled=%d)", enabled);
45681b60ceb499ee35460886f2bfaecee1f47319f925roosa@google.com
45691b60ceb499ee35460886f2bfaecee1f47319f925roosa@google.com    if (_playing)
45701b60ceb499ee35460886f2bfaecee1f47319f925roosa@google.com    {
45711b60ceb499ee35460886f2bfaecee1f47319f925roosa@google.com        _engineStatisticsPtr->SetLastError(
45721b60ceb499ee35460886f2bfaecee1f47319f925roosa@google.com            VE_INVALID_OPERATION, kTraceError,
45731b60ceb499ee35460886f2bfaecee1f47319f925roosa@google.com            "Channel::SetExternalMixing() "
45741b60ceb499ee35460886f2bfaecee1f47319f925roosa@google.com            "external mixing cannot be changed while playing.");
45751b60ceb499ee35460886f2bfaecee1f47319f925roosa@google.com        return -1;
45761b60ceb499ee35460886f2bfaecee1f47319f925roosa@google.com    }
45771b60ceb499ee35460886f2bfaecee1f47319f925roosa@google.com
45781b60ceb499ee35460886f2bfaecee1f47319f925roosa@google.com    _externalMixing = enabled;
45791b60ceb499ee35460886f2bfaecee1f47319f925roosa@google.com
45801b60ceb499ee35460886f2bfaecee1f47319f925roosa@google.com    return 0;
45811b60ceb499ee35460886f2bfaecee1f47319f925roosa@google.com}
45821b60ceb499ee35460886f2bfaecee1f47319f925roosa@google.com
4583470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.comint
4584470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.comChannel::ResetRTCPStatistics()
4585470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com{
4586470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
4587470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                 "Channel::ResetRTCPStatistics()");
45886141e13873d0fdea626de08dfec2efa2c9171c76pbos@webrtc.org    uint32_t remoteSSRC(0);
45892853dde5201d9ddc284ce5efb9688f6340487acepwestin@webrtc.org    remoteSSRC = _rtpRtcpModule->RemoteSSRC();
45902853dde5201d9ddc284ce5efb9688f6340487acepwestin@webrtc.org    return _rtpRtcpModule->ResetRTT(remoteSSRC);
4591470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com}
4592470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
4593470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.comint
4594470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.comChannel::GetRoundTripTimeSummary(StatVal& delaysMs) const
4595470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com{
4596470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
4597470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                 "Channel::GetRoundTripTimeSummary()");
4598470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    // Override default module outputs for the case when RTCP is disabled.
4599470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    // This is done to ensure that we are backward compatible with the
4600470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    // VoiceEngine where we did not use RTP/RTCP module.
46012853dde5201d9ddc284ce5efb9688f6340487acepwestin@webrtc.org    if (!_rtpRtcpModule->RTCP())
4602470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
4603470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        delaysMs.min = -1;
4604470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        delaysMs.max = -1;
4605470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        delaysMs.average = -1;
4606470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        WEBRTC_TRACE(kTraceWarning, kTraceVoice, VoEId(_instanceId,_channelId),
4607470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                     "Channel::GetRoundTripTimeSummary() RTCP is disabled =>"
4608470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                     " valid RTT measurements cannot be retrieved");
4609470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        return 0;
4610470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
4611470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
46126141e13873d0fdea626de08dfec2efa2c9171c76pbos@webrtc.org    uint32_t remoteSSRC;
46136141e13873d0fdea626de08dfec2efa2c9171c76pbos@webrtc.org    uint16_t RTT;
46146141e13873d0fdea626de08dfec2efa2c9171c76pbos@webrtc.org    uint16_t avgRTT;
46156141e13873d0fdea626de08dfec2efa2c9171c76pbos@webrtc.org    uint16_t maxRTT;
46166141e13873d0fdea626de08dfec2efa2c9171c76pbos@webrtc.org    uint16_t minRTT;
4617470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    // The remote SSRC will be zero if no RTP packet has been received.
46182853dde5201d9ddc284ce5efb9688f6340487acepwestin@webrtc.org    remoteSSRC = _rtpRtcpModule->RemoteSSRC();
4619470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    if (remoteSSRC == 0)
4620470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
4621470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        WEBRTC_TRACE(kTraceWarning, kTraceVoice, VoEId(_instanceId,_channelId),
4622470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                     "Channel::GetRoundTripTimeSummary() unable to measure RTT"
4623470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                     " since no RTP packet has been received yet");
4624470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
4625470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
4626470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    // Retrieve RTT statistics from the RTP/RTCP module for the specified
4627470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    // channel and SSRC. The SSRC is required to parse out the correct source
4628470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    // in conference scenarios.
46292853dde5201d9ddc284ce5efb9688f6340487acepwestin@webrtc.org    if (_rtpRtcpModule->RTT(remoteSSRC, &RTT, &avgRTT, &minRTT,&maxRTT) != 0)
4630470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
4631470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        WEBRTC_TRACE(kTraceWarning, kTraceVoice, VoEId(_instanceId,_channelId),
4632470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                     "GetRoundTripTimeSummary unable to retrieve RTT values"
4633470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                     " from the RTCP layer");
4634470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        delaysMs.min = -1; delaysMs.max = -1; delaysMs.average = -1;
4635470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
4636470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    else
4637470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
4638470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        delaysMs.min = minRTT;
4639470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        delaysMs.max = maxRTT;
4640470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        delaysMs.average = avgRTT;
4641470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
4642470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    return 0;
4643470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com}
4644470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
4645470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.comint
4646470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.comChannel::GetNetworkStatistics(NetworkStatistics& stats)
4647470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com{
4648470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
4649470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                 "Channel::GetNetworkStatistics()");
46507a7a008031d43013b01176cfe40b0fd68c0d83b5tina.legrand@webrtc.org    ACMNetworkStatistics acm_stats;
46517a7a008031d43013b01176cfe40b0fd68c0d83b5tina.legrand@webrtc.org    int return_value = _audioCodingModule.NetworkStatistics(&acm_stats);
46527a7a008031d43013b01176cfe40b0fd68c0d83b5tina.legrand@webrtc.org    if (return_value >= 0) {
46537a7a008031d43013b01176cfe40b0fd68c0d83b5tina.legrand@webrtc.org      memcpy(&stats, &acm_stats, sizeof(NetworkStatistics));
46547a7a008031d43013b01176cfe40b0fd68c0d83b5tina.legrand@webrtc.org    }
46557a7a008031d43013b01176cfe40b0fd68c0d83b5tina.legrand@webrtc.org    return return_value;
4656470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com}
4657470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
46581de01354e68da71bc62c81af17afeac8ed374a18pwestin@webrtc.orgbool Channel::GetDelayEstimate(int* jitter_buffer_delay_ms,
46591de01354e68da71bc62c81af17afeac8ed374a18pwestin@webrtc.org                               int* playout_buffer_delay_ms) const {
46601de01354e68da71bc62c81af17afeac8ed374a18pwestin@webrtc.org  if (_average_jitter_buffer_delay_us == 0) {
4661470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
46621de01354e68da71bc62c81af17afeac8ed374a18pwestin@webrtc.org                 "Channel::GetDelayEstimate() no valid estimate.");
46631de01354e68da71bc62c81af17afeac8ed374a18pwestin@webrtc.org    return false;
46641de01354e68da71bc62c81af17afeac8ed374a18pwestin@webrtc.org  }
46651de01354e68da71bc62c81af17afeac8ed374a18pwestin@webrtc.org  *jitter_buffer_delay_ms = (_average_jitter_buffer_delay_us + 500) / 1000 +
46661de01354e68da71bc62c81af17afeac8ed374a18pwestin@webrtc.org      _recPacketDelayMs;
46671de01354e68da71bc62c81af17afeac8ed374a18pwestin@webrtc.org  *playout_buffer_delay_ms = playout_delay_ms_;
46681de01354e68da71bc62c81af17afeac8ed374a18pwestin@webrtc.org  WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
46691de01354e68da71bc62c81af17afeac8ed374a18pwestin@webrtc.org               "Channel::GetDelayEstimate()");
46701de01354e68da71bc62c81af17afeac8ed374a18pwestin@webrtc.org  return true;
4671470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com}
4672470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
46736388c3e2fdfc91b3648fb7d408a14ddb25e41cd1turaj@webrtc.orgint Channel::SetInitialPlayoutDelay(int delay_ms)
46746388c3e2fdfc91b3648fb7d408a14ddb25e41cd1turaj@webrtc.org{
46756388c3e2fdfc91b3648fb7d408a14ddb25e41cd1turaj@webrtc.org  WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
46766388c3e2fdfc91b3648fb7d408a14ddb25e41cd1turaj@webrtc.org               "Channel::SetInitialPlayoutDelay()");
46776388c3e2fdfc91b3648fb7d408a14ddb25e41cd1turaj@webrtc.org  if ((delay_ms < kVoiceEngineMinMinPlayoutDelayMs) ||
46786388c3e2fdfc91b3648fb7d408a14ddb25e41cd1turaj@webrtc.org      (delay_ms > kVoiceEngineMaxMinPlayoutDelayMs))
46796388c3e2fdfc91b3648fb7d408a14ddb25e41cd1turaj@webrtc.org  {
46806388c3e2fdfc91b3648fb7d408a14ddb25e41cd1turaj@webrtc.org    _engineStatisticsPtr->SetLastError(
46816388c3e2fdfc91b3648fb7d408a14ddb25e41cd1turaj@webrtc.org        VE_INVALID_ARGUMENT, kTraceError,
46826388c3e2fdfc91b3648fb7d408a14ddb25e41cd1turaj@webrtc.org        "SetInitialPlayoutDelay() invalid min delay");
46836388c3e2fdfc91b3648fb7d408a14ddb25e41cd1turaj@webrtc.org    return -1;
46846388c3e2fdfc91b3648fb7d408a14ddb25e41cd1turaj@webrtc.org  }
46856388c3e2fdfc91b3648fb7d408a14ddb25e41cd1turaj@webrtc.org  if (_audioCodingModule.SetInitialPlayoutDelay(delay_ms) != 0)
46866388c3e2fdfc91b3648fb7d408a14ddb25e41cd1turaj@webrtc.org  {
46876388c3e2fdfc91b3648fb7d408a14ddb25e41cd1turaj@webrtc.org    _engineStatisticsPtr->SetLastError(
46886388c3e2fdfc91b3648fb7d408a14ddb25e41cd1turaj@webrtc.org        VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
46896388c3e2fdfc91b3648fb7d408a14ddb25e41cd1turaj@webrtc.org        "SetInitialPlayoutDelay() failed to set min playout delay");
46906388c3e2fdfc91b3648fb7d408a14ddb25e41cd1turaj@webrtc.org    return -1;
46916388c3e2fdfc91b3648fb7d408a14ddb25e41cd1turaj@webrtc.org  }
46926388c3e2fdfc91b3648fb7d408a14ddb25e41cd1turaj@webrtc.org  return 0;
46936388c3e2fdfc91b3648fb7d408a14ddb25e41cd1turaj@webrtc.org}
46946388c3e2fdfc91b3648fb7d408a14ddb25e41cd1turaj@webrtc.org
46956388c3e2fdfc91b3648fb7d408a14ddb25e41cd1turaj@webrtc.org
4696470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.comint
4697470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.comChannel::SetMinimumPlayoutDelay(int delayMs)
4698470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com{
4699470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
4700470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                 "Channel::SetMinimumPlayoutDelay()");
4701470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    if ((delayMs < kVoiceEngineMinMinPlayoutDelayMs) ||
4702470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        (delayMs > kVoiceEngineMaxMinPlayoutDelayMs))
4703470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
4704470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        _engineStatisticsPtr->SetLastError(
4705470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            VE_INVALID_ARGUMENT, kTraceError,
4706470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            "SetMinimumPlayoutDelay() invalid min delay");
4707470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        return -1;
4708470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
4709470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    if (_audioCodingModule.SetMinimumPlayoutDelay(delayMs) != 0)
4710470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
4711470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        _engineStatisticsPtr->SetLastError(
4712470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
4713470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            "SetMinimumPlayoutDelay() failed to set min playout delay");
4714470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        return -1;
4715470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
4716470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    return 0;
4717470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com}
4718470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
47191de01354e68da71bc62c81af17afeac8ed374a18pwestin@webrtc.orgvoid Channel::UpdatePlayoutTimestamp(bool rtcp) {
47201de01354e68da71bc62c81af17afeac8ed374a18pwestin@webrtc.org  uint32_t playout_timestamp = 0;
47211de01354e68da71bc62c81af17afeac8ed374a18pwestin@webrtc.org
47221de01354e68da71bc62c81af17afeac8ed374a18pwestin@webrtc.org  if (_audioCodingModule.PlayoutTimestamp(&playout_timestamp) == -1)  {
47231de01354e68da71bc62c81af17afeac8ed374a18pwestin@webrtc.org    WEBRTC_TRACE(kTraceWarning, kTraceVoice, VoEId(_instanceId,_channelId),
47241de01354e68da71bc62c81af17afeac8ed374a18pwestin@webrtc.org                 "Channel::UpdatePlayoutTimestamp() failed to read playout"
47251de01354e68da71bc62c81af17afeac8ed374a18pwestin@webrtc.org                 " timestamp from the ACM");
47261de01354e68da71bc62c81af17afeac8ed374a18pwestin@webrtc.org    _engineStatisticsPtr->SetLastError(
47271de01354e68da71bc62c81af17afeac8ed374a18pwestin@webrtc.org        VE_CANNOT_RETRIEVE_VALUE, kTraceError,
47281de01354e68da71bc62c81af17afeac8ed374a18pwestin@webrtc.org        "UpdatePlayoutTimestamp() failed to retrieve timestamp");
47291de01354e68da71bc62c81af17afeac8ed374a18pwestin@webrtc.org    return;
47301de01354e68da71bc62c81af17afeac8ed374a18pwestin@webrtc.org  }
47311de01354e68da71bc62c81af17afeac8ed374a18pwestin@webrtc.org
47321de01354e68da71bc62c81af17afeac8ed374a18pwestin@webrtc.org  uint16_t delay_ms = 0;
47331de01354e68da71bc62c81af17afeac8ed374a18pwestin@webrtc.org  if (_audioDeviceModulePtr->PlayoutDelay(&delay_ms) == -1) {
47341de01354e68da71bc62c81af17afeac8ed374a18pwestin@webrtc.org    WEBRTC_TRACE(kTraceWarning, kTraceVoice, VoEId(_instanceId,_channelId),
47351de01354e68da71bc62c81af17afeac8ed374a18pwestin@webrtc.org                 "Channel::UpdatePlayoutTimestamp() failed to read playout"
47361de01354e68da71bc62c81af17afeac8ed374a18pwestin@webrtc.org                 " delay from the ADM");
47371de01354e68da71bc62c81af17afeac8ed374a18pwestin@webrtc.org    _engineStatisticsPtr->SetLastError(
47381de01354e68da71bc62c81af17afeac8ed374a18pwestin@webrtc.org        VE_CANNOT_RETRIEVE_VALUE, kTraceError,
47391de01354e68da71bc62c81af17afeac8ed374a18pwestin@webrtc.org        "UpdatePlayoutTimestamp() failed to retrieve playout delay");
47401de01354e68da71bc62c81af17afeac8ed374a18pwestin@webrtc.org    return;
47411de01354e68da71bc62c81af17afeac8ed374a18pwestin@webrtc.org  }
47421de01354e68da71bc62c81af17afeac8ed374a18pwestin@webrtc.org
47431de01354e68da71bc62c81af17afeac8ed374a18pwestin@webrtc.org  int32_t playout_frequency = _audioCodingModule.PlayoutFrequency();
47441de01354e68da71bc62c81af17afeac8ed374a18pwestin@webrtc.org  CodecInst current_recive_codec;
47451de01354e68da71bc62c81af17afeac8ed374a18pwestin@webrtc.org  if (_audioCodingModule.ReceiveCodec(&current_recive_codec) == 0) {
47461de01354e68da71bc62c81af17afeac8ed374a18pwestin@webrtc.org    if (STR_CASE_CMP("G722", current_recive_codec.plname) == 0) {
47471de01354e68da71bc62c81af17afeac8ed374a18pwestin@webrtc.org      playout_frequency = 8000;
47481de01354e68da71bc62c81af17afeac8ed374a18pwestin@webrtc.org    } else if (STR_CASE_CMP("opus", current_recive_codec.plname) == 0) {
47491de01354e68da71bc62c81af17afeac8ed374a18pwestin@webrtc.org      playout_frequency = 48000;
4750470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
47511de01354e68da71bc62c81af17afeac8ed374a18pwestin@webrtc.org  }
47521de01354e68da71bc62c81af17afeac8ed374a18pwestin@webrtc.org
47531de01354e68da71bc62c81af17afeac8ed374a18pwestin@webrtc.org  // Remove the playout delay.
47541de01354e68da71bc62c81af17afeac8ed374a18pwestin@webrtc.org  playout_timestamp -= (delay_ms * (playout_frequency / 1000));
47551de01354e68da71bc62c81af17afeac8ed374a18pwestin@webrtc.org
47561de01354e68da71bc62c81af17afeac8ed374a18pwestin@webrtc.org  WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
47571de01354e68da71bc62c81af17afeac8ed374a18pwestin@webrtc.org               "Channel::UpdatePlayoutTimestamp() => playoutTimestamp = %lu",
47581de01354e68da71bc62c81af17afeac8ed374a18pwestin@webrtc.org               playout_timestamp);
47591de01354e68da71bc62c81af17afeac8ed374a18pwestin@webrtc.org
47601de01354e68da71bc62c81af17afeac8ed374a18pwestin@webrtc.org  if (rtcp) {
47611de01354e68da71bc62c81af17afeac8ed374a18pwestin@webrtc.org    playout_timestamp_rtcp_ = playout_timestamp;
47621de01354e68da71bc62c81af17afeac8ed374a18pwestin@webrtc.org  } else {
47631de01354e68da71bc62c81af17afeac8ed374a18pwestin@webrtc.org    playout_timestamp_rtp_ = playout_timestamp;
47641de01354e68da71bc62c81af17afeac8ed374a18pwestin@webrtc.org  }
47651de01354e68da71bc62c81af17afeac8ed374a18pwestin@webrtc.org  playout_delay_ms_ = delay_ms;
47661de01354e68da71bc62c81af17afeac8ed374a18pwestin@webrtc.org}
47671de01354e68da71bc62c81af17afeac8ed374a18pwestin@webrtc.org
47681de01354e68da71bc62c81af17afeac8ed374a18pwestin@webrtc.orgint Channel::GetPlayoutTimestamp(unsigned int& timestamp) {
47691de01354e68da71bc62c81af17afeac8ed374a18pwestin@webrtc.org  WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
47701de01354e68da71bc62c81af17afeac8ed374a18pwestin@webrtc.org               "Channel::GetPlayoutTimestamp()");
47711de01354e68da71bc62c81af17afeac8ed374a18pwestin@webrtc.org  if (playout_timestamp_rtp_ == 0)  {
47721de01354e68da71bc62c81af17afeac8ed374a18pwestin@webrtc.org    _engineStatisticsPtr->SetLastError(
47731de01354e68da71bc62c81af17afeac8ed374a18pwestin@webrtc.org        VE_CANNOT_RETRIEVE_VALUE, kTraceError,
47741de01354e68da71bc62c81af17afeac8ed374a18pwestin@webrtc.org        "GetPlayoutTimestamp() failed to retrieve timestamp");
47751de01354e68da71bc62c81af17afeac8ed374a18pwestin@webrtc.org    return -1;
47761de01354e68da71bc62c81af17afeac8ed374a18pwestin@webrtc.org  }
47771de01354e68da71bc62c81af17afeac8ed374a18pwestin@webrtc.org  timestamp = playout_timestamp_rtp_;
47781de01354e68da71bc62c81af17afeac8ed374a18pwestin@webrtc.org  WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
47791de01354e68da71bc62c81af17afeac8ed374a18pwestin@webrtc.org               VoEId(_instanceId,_channelId),
47801de01354e68da71bc62c81af17afeac8ed374a18pwestin@webrtc.org               "GetPlayoutTimestamp() => timestamp=%u", timestamp);
47811de01354e68da71bc62c81af17afeac8ed374a18pwestin@webrtc.org  return 0;
4782470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com}
4783470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
4784470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.comint
4785470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.comChannel::SetInitTimestamp(unsigned int timestamp)
4786470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com{
4787470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
4788470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com               "Channel::SetInitTimestamp()");
4789470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    if (_sending)
4790470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
4791470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        _engineStatisticsPtr->SetLastError(
4792470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            VE_SENDING, kTraceError, "SetInitTimestamp() already sending");
4793470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        return -1;
4794470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
47952853dde5201d9ddc284ce5efb9688f6340487acepwestin@webrtc.org    if (_rtpRtcpModule->SetStartTimestamp(timestamp) != 0)
4796470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
4797470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        _engineStatisticsPtr->SetLastError(
4798470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            VE_RTP_RTCP_MODULE_ERROR, kTraceError,
4799470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            "SetInitTimestamp() failed to set timestamp");
4800470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        return -1;
4801470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
4802470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    return 0;
4803470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com}
4804470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
4805470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.comint
4806470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.comChannel::SetInitSequenceNumber(short sequenceNumber)
4807470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com{
4808470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
4809470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                 "Channel::SetInitSequenceNumber()");
4810470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    if (_sending)
4811470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
4812470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        _engineStatisticsPtr->SetLastError(
4813470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            VE_SENDING, kTraceError,
4814470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            "SetInitSequenceNumber() already sending");
4815470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        return -1;
4816470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
48172853dde5201d9ddc284ce5efb9688f6340487acepwestin@webrtc.org    if (_rtpRtcpModule->SetSequenceNumber(sequenceNumber) != 0)
4818470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
4819470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        _engineStatisticsPtr->SetLastError(
4820470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            VE_RTP_RTCP_MODULE_ERROR, kTraceError,
4821470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            "SetInitSequenceNumber() failed to set sequence number");
4822470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        return -1;
4823470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
4824470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    return 0;
4825470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com}
4826470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
4827470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.comint
4828470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.comChannel::GetRtpRtcp(RtpRtcp* &rtpRtcpModule) const
4829470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com{
4830470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
4831470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                 "Channel::GetRtpRtcp()");
48322853dde5201d9ddc284ce5efb9688f6340487acepwestin@webrtc.org    rtpRtcpModule = _rtpRtcpModule.get();
4833470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    return 0;
4834470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com}
4835470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
4836e59a0aca6a0762592644ebc0282dbe244162eb8dandrew@webrtc.org// TODO(andrew): refactor Mix functions here and in transmit_mixer.cc to use
4837e59a0aca6a0762592644ebc0282dbe244162eb8dandrew@webrtc.org// a shared helper.
48386141e13873d0fdea626de08dfec2efa2c9171c76pbos@webrtc.orgint32_t
48399213521ea98b0977c7cdabd2853060835af226f3pbos@webrtc.orgChannel::MixOrReplaceAudioWithFile(int mixingFrequency)
4840470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com{
48416141e13873d0fdea626de08dfec2efa2c9171c76pbos@webrtc.org    scoped_array<int16_t> fileBuffer(new int16_t[640]);
4842e59a0aca6a0762592644ebc0282dbe244162eb8dandrew@webrtc.org    int fileSamples(0);
4843470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
4844470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
48459a065d1eae9ed296e1e2eaaad73d7ca1223bfe79mflodman@webrtc.org        CriticalSectionScoped cs(&_fileCritSect);
4846470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
4847470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        if (_inputFilePlayerPtr == NULL)
4848470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        {
4849470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            WEBRTC_TRACE(kTraceWarning, kTraceVoice,
4850470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                         VoEId(_instanceId, _channelId),
4851470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                         "Channel::MixOrReplaceAudioWithFile() fileplayer"
4852470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                             " doesnt exist");
4853470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            return -1;
4854470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        }
4855470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
4856d713143d99b205aaaa589b96443d82b36c3843e4braveyao@webrtc.org        if (_inputFilePlayerPtr->Get10msAudioFromFile(fileBuffer.get(),
4857470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                                                      fileSamples,
4858470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                                                      mixingFrequency) == -1)
4859470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        {
4860470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            WEBRTC_TRACE(kTraceWarning, kTraceVoice,
4861470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                         VoEId(_instanceId, _channelId),
4862470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                         "Channel::MixOrReplaceAudioWithFile() file mixing "
4863470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                         "failed");
4864470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            return -1;
4865470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        }
4866470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        if (fileSamples == 0)
4867470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        {
4868470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            WEBRTC_TRACE(kTraceWarning, kTraceVoice,
4869470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                         VoEId(_instanceId, _channelId),
4870470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                         "Channel::MixOrReplaceAudioWithFile() file is ended");
4871470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            return 0;
4872470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        }
4873470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
4874470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
487563a509858d3988299726640c664b699d6229a1d4andrew@webrtc.org    assert(_audioFrame.samples_per_channel_ == fileSamples);
4876470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
4877470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    if (_mixFileWithMicrophone)
4878470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
4879d713143d99b205aaaa589b96443d82b36c3843e4braveyao@webrtc.org        // Currently file stream is always mono.
4880d713143d99b205aaaa589b96443d82b36c3843e4braveyao@webrtc.org        // TODO(xians): Change the code when FilePlayer supports real stereo.
488163a509858d3988299726640c664b699d6229a1d4andrew@webrtc.org        Utility::MixWithSat(_audioFrame.data_,
4882e59a0aca6a0762592644ebc0282dbe244162eb8dandrew@webrtc.org                            _audioFrame.num_channels_,
4883d713143d99b205aaaa589b96443d82b36c3843e4braveyao@webrtc.org                            fileBuffer.get(),
4884d713143d99b205aaaa589b96443d82b36c3843e4braveyao@webrtc.org                            1,
4885e59a0aca6a0762592644ebc0282dbe244162eb8dandrew@webrtc.org                            fileSamples);
4886470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
4887470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    else
4888470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
4889d713143d99b205aaaa589b96443d82b36c3843e4braveyao@webrtc.org        // Replace ACM audio with file.
4890d713143d99b205aaaa589b96443d82b36c3843e4braveyao@webrtc.org        // Currently file stream is always mono.
4891d713143d99b205aaaa589b96443d82b36c3843e4braveyao@webrtc.org        // TODO(xians): Change the code when FilePlayer supports real stereo.
4892470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        _audioFrame.UpdateFrame(_channelId,
4893470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                                -1,
4894d713143d99b205aaaa589b96443d82b36c3843e4braveyao@webrtc.org                                fileBuffer.get(),
4895e59a0aca6a0762592644ebc0282dbe244162eb8dandrew@webrtc.org                                fileSamples,
4896470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                                mixingFrequency,
4897470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                                AudioFrame::kNormalSpeech,
4898470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                                AudioFrame::kVadUnknown,
4899470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                                1);
4900470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
4901470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
4902470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    return 0;
4903470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com}
4904470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
49056141e13873d0fdea626de08dfec2efa2c9171c76pbos@webrtc.orgint32_t
4906470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.comChannel::MixAudioWithFile(AudioFrame& audioFrame,
49079213521ea98b0977c7cdabd2853060835af226f3pbos@webrtc.org                          int mixingFrequency)
4908470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com{
4909470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    assert(mixingFrequency <= 32000);
4910470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
49116141e13873d0fdea626de08dfec2efa2c9171c76pbos@webrtc.org    scoped_array<int16_t> fileBuffer(new int16_t[640]);
4912e59a0aca6a0762592644ebc0282dbe244162eb8dandrew@webrtc.org    int fileSamples(0);
4913470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
4914470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
49159a065d1eae9ed296e1e2eaaad73d7ca1223bfe79mflodman@webrtc.org        CriticalSectionScoped cs(&_fileCritSect);
4916470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
4917470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        if (_outputFilePlayerPtr == NULL)
4918470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        {
4919470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            WEBRTC_TRACE(kTraceWarning, kTraceVoice,
4920470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                         VoEId(_instanceId, _channelId),
4921470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                         "Channel::MixAudioWithFile() file mixing failed");
4922470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            return -1;
4923470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        }
4924470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
4925470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        // We should get the frequency we ask for.
4926d713143d99b205aaaa589b96443d82b36c3843e4braveyao@webrtc.org        if (_outputFilePlayerPtr->Get10msAudioFromFile(fileBuffer.get(),
4927470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                                                       fileSamples,
4928470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                                                       mixingFrequency) == -1)
4929470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        {
4930470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            WEBRTC_TRACE(kTraceWarning, kTraceVoice,
4931470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                         VoEId(_instanceId, _channelId),
4932470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                         "Channel::MixAudioWithFile() file mixing failed");
4933470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            return -1;
4934470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        }
4935470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
4936470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
493763a509858d3988299726640c664b699d6229a1d4andrew@webrtc.org    if (audioFrame.samples_per_channel_ == fileSamples)
4938470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
4939d713143d99b205aaaa589b96443d82b36c3843e4braveyao@webrtc.org        // Currently file stream is always mono.
4940d713143d99b205aaaa589b96443d82b36c3843e4braveyao@webrtc.org        // TODO(xians): Change the code when FilePlayer supports real stereo.
494163a509858d3988299726640c664b699d6229a1d4andrew@webrtc.org        Utility::MixWithSat(audioFrame.data_,
4942e59a0aca6a0762592644ebc0282dbe244162eb8dandrew@webrtc.org                            audioFrame.num_channels_,
4943d713143d99b205aaaa589b96443d82b36c3843e4braveyao@webrtc.org                            fileBuffer.get(),
4944d713143d99b205aaaa589b96443d82b36c3843e4braveyao@webrtc.org                            1,
4945e59a0aca6a0762592644ebc0282dbe244162eb8dandrew@webrtc.org                            fileSamples);
4946470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
4947470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    else
4948470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
4949470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        WEBRTC_TRACE(kTraceWarning, kTraceVoice, VoEId(_instanceId,_channelId),
495063a509858d3988299726640c664b699d6229a1d4andrew@webrtc.org            "Channel::MixAudioWithFile() samples_per_channel_(%d) != "
4951470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            "fileSamples(%d)",
495263a509858d3988299726640c664b699d6229a1d4andrew@webrtc.org            audioFrame.samples_per_channel_, fileSamples);
4953470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        return -1;
4954470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
4955470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
4956470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    return 0;
4957470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com}
4958470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
4959470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.comint
4960470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.comChannel::InsertInbandDtmfTone()
4961470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com{
4962af26f646165e7e2a8747fd54e92e73f48118a807niklas.enbom@webrtc.org    // Check if we should start a new tone.
4963470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    if (_inbandDtmfQueue.PendingDtmf() &&
4964470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        !_inbandDtmfGenerator.IsAddingTone() &&
4965470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        _inbandDtmfGenerator.DelaySinceLastTone() >
4966470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        kMinTelephoneEventSeparationMs)
4967470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
49686141e13873d0fdea626de08dfec2efa2c9171c76pbos@webrtc.org        int8_t eventCode(0);
49696141e13873d0fdea626de08dfec2efa2c9171c76pbos@webrtc.org        uint16_t lengthMs(0);
49706141e13873d0fdea626de08dfec2efa2c9171c76pbos@webrtc.org        uint8_t attenuationDb(0);
4971470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
4972470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        eventCode = _inbandDtmfQueue.NextDtmf(&lengthMs, &attenuationDb);
4973470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        _inbandDtmfGenerator.AddTone(eventCode, lengthMs, attenuationDb);
4974470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        if (_playInbandDtmfEvent)
4975470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        {
4976470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            // Add tone to output mixer using a reduced length to minimize
4977470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            // risk of echo.
4978470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            _outputMixerPtr->PlayDtmfTone(eventCode, lengthMs - 80,
4979470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                                          attenuationDb);
4980470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        }
4981470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
4982470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
4983470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    if (_inbandDtmfGenerator.IsAddingTone())
4984470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
49856141e13873d0fdea626de08dfec2efa2c9171c76pbos@webrtc.org        uint16_t frequency(0);
4986470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        _inbandDtmfGenerator.GetSampleRate(frequency);
4987470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
498863a509858d3988299726640c664b699d6229a1d4andrew@webrtc.org        if (frequency != _audioFrame.sample_rate_hz_)
4989470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        {
4990470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            // Update sample rate of Dtmf tone since the mixing frequency
4991470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            // has changed.
4992470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            _inbandDtmfGenerator.SetSampleRate(
49936141e13873d0fdea626de08dfec2efa2c9171c76pbos@webrtc.org                (uint16_t) (_audioFrame.sample_rate_hz_));
4994470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            // Reset the tone to be added taking the new sample rate into
4995470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            // account.
4996470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            _inbandDtmfGenerator.ResetTone();
4997470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        }
4998ae1a58bba4f926d149a5f39243269c3f6625f494andrew@webrtc.org
49996141e13873d0fdea626de08dfec2efa2c9171c76pbos@webrtc.org        int16_t toneBuffer[320];
50006141e13873d0fdea626de08dfec2efa2c9171c76pbos@webrtc.org        uint16_t toneSamples(0);
5001470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        // Get 10ms tone segment and set time since last tone to zero
5002470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        if (_inbandDtmfGenerator.Get10msTone(toneBuffer, toneSamples) == -1)
5003470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        {
5004470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            WEBRTC_TRACE(kTraceWarning, kTraceVoice,
5005470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                       VoEId(_instanceId, _channelId),
5006470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                       "Channel::EncodeAndSend() inserting Dtmf failed");
5007470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            return -1;
5008470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        }
5009470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
5010af26f646165e7e2a8747fd54e92e73f48118a807niklas.enbom@webrtc.org        // Replace mixed audio with DTMF tone.
5011ae1a58bba4f926d149a5f39243269c3f6625f494andrew@webrtc.org        for (int sample = 0;
501263a509858d3988299726640c664b699d6229a1d4andrew@webrtc.org            sample < _audioFrame.samples_per_channel_;
5013af26f646165e7e2a8747fd54e92e73f48118a807niklas.enbom@webrtc.org            sample++)
5014af26f646165e7e2a8747fd54e92e73f48118a807niklas.enbom@webrtc.org        {
5015ae1a58bba4f926d149a5f39243269c3f6625f494andrew@webrtc.org            for (int channel = 0;
5016ae1a58bba4f926d149a5f39243269c3f6625f494andrew@webrtc.org                channel < _audioFrame.num_channels_;
5017af26f646165e7e2a8747fd54e92e73f48118a807niklas.enbom@webrtc.org                channel++)
5018af26f646165e7e2a8747fd54e92e73f48118a807niklas.enbom@webrtc.org            {
5019ae1a58bba4f926d149a5f39243269c3f6625f494andrew@webrtc.org                const int index = sample * _audioFrame.num_channels_ + channel;
5020ae1a58bba4f926d149a5f39243269c3f6625f494andrew@webrtc.org                _audioFrame.data_[index] = toneBuffer[sample];
5021af26f646165e7e2a8747fd54e92e73f48118a807niklas.enbom@webrtc.org            }
5022af26f646165e7e2a8747fd54e92e73f48118a807niklas.enbom@webrtc.org        }
5023ae1a58bba4f926d149a5f39243269c3f6625f494andrew@webrtc.org
502463a509858d3988299726640c664b699d6229a1d4andrew@webrtc.org        assert(_audioFrame.samples_per_channel_ == toneSamples);
5025470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    } else
5026470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
5027470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        // Add 10ms to "delay-since-last-tone" counter
5028470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        _inbandDtmfGenerator.UpdateDelaySinceLastTone();
5029470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
5030470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    return 0;
5031470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com}
5032470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
5033470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.comvoid
5034470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.comChannel::ResetDeadOrAliveCounters()
5035470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com{
5036470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    _countDeadDetections = 0;
5037470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    _countAliveDetections = 0;
5038470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com}
5039470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
5040470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.comvoid
5041470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.comChannel::UpdateDeadOrAliveCounters(bool alive)
5042470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com{
5043470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    if (alive)
5044470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        _countAliveDetections++;
5045470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    else
5046470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        _countDeadDetections++;
5047470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com}
5048470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
5049470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.comint
5050470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.comChannel::GetDeadOrAliveCounters(int& countDead, int& countAlive) const
5051470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com{
5052470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    bool enabled;
50536141e13873d0fdea626de08dfec2efa2c9171c76pbos@webrtc.org    uint8_t timeSec;
5054470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
50552853dde5201d9ddc284ce5efb9688f6340487acepwestin@webrtc.org    _rtpRtcpModule->PeriodicDeadOrAliveStatus(enabled, timeSec);
5056470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    if (!enabled)
5057470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        return (-1);
5058470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
5059470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    countDead = static_cast<int> (_countDeadDetections);
5060470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    countAlive = static_cast<int> (_countAliveDetections);
5061470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    return 0;
5062470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com}
5063470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
50646141e13873d0fdea626de08dfec2efa2c9171c76pbos@webrtc.orgint32_t
5065470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.comChannel::SendPacketRaw(const void *data, int len, bool RTCP)
5066470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com{
5067470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    if (_transportPtr == NULL)
5068470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
5069470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        return -1;
5070470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
5071470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    if (!RTCP)
5072470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
5073470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        return _transportPtr->SendPacket(_channelId, data, len);
5074470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
5075470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    else
5076470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
5077470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        return _transportPtr->SendRTCPPacket(_channelId, data, len);
5078470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
5079470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com}
5080470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
50811de01354e68da71bc62c81af17afeac8ed374a18pwestin@webrtc.org// Called for incoming RTP packets after successful RTP header parsing.
50821de01354e68da71bc62c81af17afeac8ed374a18pwestin@webrtc.orgvoid Channel::UpdatePacketDelay(uint32_t rtp_timestamp,
50831de01354e68da71bc62c81af17afeac8ed374a18pwestin@webrtc.org                                uint16_t sequence_number) {
50841de01354e68da71bc62c81af17afeac8ed374a18pwestin@webrtc.org  WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
50851de01354e68da71bc62c81af17afeac8ed374a18pwestin@webrtc.org               "Channel::UpdatePacketDelay(timestamp=%lu, sequenceNumber=%u)",
50861de01354e68da71bc62c81af17afeac8ed374a18pwestin@webrtc.org               rtp_timestamp, sequence_number);
5087470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
50881de01354e68da71bc62c81af17afeac8ed374a18pwestin@webrtc.org  // Get frequency of last received payload
50891de01354e68da71bc62c81af17afeac8ed374a18pwestin@webrtc.org  int rtp_receive_frequency = _audioCodingModule.ReceiveFrequency();
5090470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
50911de01354e68da71bc62c81af17afeac8ed374a18pwestin@webrtc.org  CodecInst current_receive_codec;
50921de01354e68da71bc62c81af17afeac8ed374a18pwestin@webrtc.org  if (_audioCodingModule.ReceiveCodec(&current_receive_codec) != 0) {
50931de01354e68da71bc62c81af17afeac8ed374a18pwestin@webrtc.org    return;
50941de01354e68da71bc62c81af17afeac8ed374a18pwestin@webrtc.org  }
5095470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
5096e46c8d387587ba148e229a7bb18f1cc0708a2a87turaj@webrtc.org  // Update the least required delay.
5097e46c8d387587ba148e229a7bb18f1cc0708a2a87turaj@webrtc.org  least_required_delay_ms_ = _audioCodingModule.LeastRequiredDelayMs();
5098e46c8d387587ba148e229a7bb18f1cc0708a2a87turaj@webrtc.org
50991de01354e68da71bc62c81af17afeac8ed374a18pwestin@webrtc.org  if (STR_CASE_CMP("G722", current_receive_codec.plname) == 0) {
51001de01354e68da71bc62c81af17afeac8ed374a18pwestin@webrtc.org    // Even though the actual sampling rate for G.722 audio is
51011de01354e68da71bc62c81af17afeac8ed374a18pwestin@webrtc.org    // 16,000 Hz, the RTP clock rate for the G722 payload format is
51021de01354e68da71bc62c81af17afeac8ed374a18pwestin@webrtc.org    // 8,000 Hz because that value was erroneously assigned in
51031de01354e68da71bc62c81af17afeac8ed374a18pwestin@webrtc.org    // RFC 1890 and must remain unchanged for backward compatibility.
51041de01354e68da71bc62c81af17afeac8ed374a18pwestin@webrtc.org    rtp_receive_frequency = 8000;
51051de01354e68da71bc62c81af17afeac8ed374a18pwestin@webrtc.org  } else if (STR_CASE_CMP("opus", current_receive_codec.plname) == 0) {
51061de01354e68da71bc62c81af17afeac8ed374a18pwestin@webrtc.org    // We are resampling Opus internally to 32,000 Hz until all our
51071de01354e68da71bc62c81af17afeac8ed374a18pwestin@webrtc.org    // DSP routines can operate at 48,000 Hz, but the RTP clock
51081de01354e68da71bc62c81af17afeac8ed374a18pwestin@webrtc.org    // rate for the Opus payload format is standardized to 48,000 Hz,
51091de01354e68da71bc62c81af17afeac8ed374a18pwestin@webrtc.org    // because that is the maximum supported decoding sampling rate.
51101de01354e68da71bc62c81af17afeac8ed374a18pwestin@webrtc.org    rtp_receive_frequency = 48000;
51111de01354e68da71bc62c81af17afeac8ed374a18pwestin@webrtc.org  }
5112470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
51131de01354e68da71bc62c81af17afeac8ed374a18pwestin@webrtc.org  // playout_timestamp_rtp_ updated in UpdatePlayoutTimestamp for every incoming
51141de01354e68da71bc62c81af17afeac8ed374a18pwestin@webrtc.org  // packet.
51151de01354e68da71bc62c81af17afeac8ed374a18pwestin@webrtc.org  uint32_t timestamp_diff_ms = (rtp_timestamp - playout_timestamp_rtp_) /
51161de01354e68da71bc62c81af17afeac8ed374a18pwestin@webrtc.org      (rtp_receive_frequency / 1000);
5117470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
51181de01354e68da71bc62c81af17afeac8ed374a18pwestin@webrtc.org  uint16_t packet_delay_ms = (rtp_timestamp - _previousTimestamp) /
51191de01354e68da71bc62c81af17afeac8ed374a18pwestin@webrtc.org      (rtp_receive_frequency / 1000);
5120470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
51211de01354e68da71bc62c81af17afeac8ed374a18pwestin@webrtc.org  _previousTimestamp = rtp_timestamp;
5122470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
51231de01354e68da71bc62c81af17afeac8ed374a18pwestin@webrtc.org  if (timestamp_diff_ms > (2 * kVoiceEngineMaxMinPlayoutDelayMs)) {
51241de01354e68da71bc62c81af17afeac8ed374a18pwestin@webrtc.org    timestamp_diff_ms = 0;
51251de01354e68da71bc62c81af17afeac8ed374a18pwestin@webrtc.org  }
51261de01354e68da71bc62c81af17afeac8ed374a18pwestin@webrtc.org
51271de01354e68da71bc62c81af17afeac8ed374a18pwestin@webrtc.org  if (timestamp_diff_ms == 0) return;
51281de01354e68da71bc62c81af17afeac8ed374a18pwestin@webrtc.org
51291de01354e68da71bc62c81af17afeac8ed374a18pwestin@webrtc.org  if (packet_delay_ms >= 10 && packet_delay_ms <= 60) {
51301de01354e68da71bc62c81af17afeac8ed374a18pwestin@webrtc.org    _recPacketDelayMs = packet_delay_ms;
51311de01354e68da71bc62c81af17afeac8ed374a18pwestin@webrtc.org  }
51321de01354e68da71bc62c81af17afeac8ed374a18pwestin@webrtc.org
51331de01354e68da71bc62c81af17afeac8ed374a18pwestin@webrtc.org  if (_average_jitter_buffer_delay_us == 0) {
51341de01354e68da71bc62c81af17afeac8ed374a18pwestin@webrtc.org    _average_jitter_buffer_delay_us = timestamp_diff_ms * 1000;
51351de01354e68da71bc62c81af17afeac8ed374a18pwestin@webrtc.org    return;
51361de01354e68da71bc62c81af17afeac8ed374a18pwestin@webrtc.org  }
51371de01354e68da71bc62c81af17afeac8ed374a18pwestin@webrtc.org
51381de01354e68da71bc62c81af17afeac8ed374a18pwestin@webrtc.org  // Filter average delay value using exponential filter (alpha is
51391de01354e68da71bc62c81af17afeac8ed374a18pwestin@webrtc.org  // 7/8). We derive 1000 *_average_jitter_buffer_delay_us here (reduces
51401de01354e68da71bc62c81af17afeac8ed374a18pwestin@webrtc.org  // risk of rounding error) and compensate for it in GetDelayEstimate()
51411de01354e68da71bc62c81af17afeac8ed374a18pwestin@webrtc.org  // later.
51421de01354e68da71bc62c81af17afeac8ed374a18pwestin@webrtc.org  _average_jitter_buffer_delay_us = (_average_jitter_buffer_delay_us * 7 +
51431de01354e68da71bc62c81af17afeac8ed374a18pwestin@webrtc.org      1000 * timestamp_diff_ms + 500) / 8;
5144470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com}
5145470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
5146470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.comvoid
5147470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.comChannel::RegisterReceiveCodecsToRTPModule()
5148470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com{
5149470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
5150470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                 "Channel::RegisterReceiveCodecsToRTPModule()");
5151470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
5152470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
5153470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    CodecInst codec;
51546141e13873d0fdea626de08dfec2efa2c9171c76pbos@webrtc.org    const uint8_t nSupportedCodecs = AudioCodingModule::NumberOfCodecs();
5155470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
5156470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    for (int idx = 0; idx < nSupportedCodecs; idx++)
5157470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
5158470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        // Open up the RTP/RTCP receiver for all supported codecs
51597a7a008031d43013b01176cfe40b0fd68c0d83b5tina.legrand@webrtc.org        if ((_audioCodingModule.Codec(idx, &codec) == -1) ||
51602853dde5201d9ddc284ce5efb9688f6340487acepwestin@webrtc.org            (_rtpRtcpModule->RegisterReceivePayload(codec) == -1))
5161470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        {
5162470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            WEBRTC_TRACE(
5163470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                         kTraceWarning,
5164470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                         kTraceVoice,
5165470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                         VoEId(_instanceId, _channelId),
5166470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                         "Channel::RegisterReceiveCodecsToRTPModule() unable"
5167470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                         " to register %s (%d/%d/%d/%d) to RTP/RTCP receiver",
5168470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                         codec.plname, codec.pltype, codec.plfreq,
5169470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                         codec.channels, codec.rate);
5170470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        }
5171470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        else
5172470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        {
5173470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            WEBRTC_TRACE(
5174470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                         kTraceInfo,
5175470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                         kTraceVoice,
5176470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                         VoEId(_instanceId, _channelId),
5177470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                         "Channel::RegisterReceiveCodecsToRTPModule() %s "
5178fcd12b3b7d7e92d6f8cdfdf8277808ae52a07c36wu@webrtc.org                         "(%d/%d/%d/%d) has been added to the RTP/RTCP "
5179470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                         "receiver",
5180470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                         codec.plname, codec.pltype, codec.plfreq,
5181470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                         codec.channels, codec.rate);
5182470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        }
5183470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
5184470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com}
5185470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
518650419b07772de974964072478886c4c35ab9c8ccandrew@webrtc.orgint Channel::ApmProcessRx(AudioFrame& frame) {
518750419b07772de974964072478886c4c35ab9c8ccandrew@webrtc.org  AudioProcessing* audioproc = _rxAudioProcessingModulePtr;
518850419b07772de974964072478886c4c35ab9c8ccandrew@webrtc.org  // Register the (possibly new) frame parameters.
518950419b07772de974964072478886c4c35ab9c8ccandrew@webrtc.org  if (audioproc->set_sample_rate_hz(frame.sample_rate_hz_) != 0) {
5190655d8f56f61eef7bd074748e1f6f5c5d2cd767d5andrew@webrtc.org    LOG_FERR1(LS_WARNING, set_sample_rate_hz, frame.sample_rate_hz_);
519150419b07772de974964072478886c4c35ab9c8ccandrew@webrtc.org  }
519250419b07772de974964072478886c4c35ab9c8ccandrew@webrtc.org  if (audioproc->set_num_channels(frame.num_channels_,
519350419b07772de974964072478886c4c35ab9c8ccandrew@webrtc.org                                  frame.num_channels_) != 0) {
5194655d8f56f61eef7bd074748e1f6f5c5d2cd767d5andrew@webrtc.org    LOG_FERR1(LS_WARNING, set_num_channels, frame.num_channels_);
519550419b07772de974964072478886c4c35ab9c8ccandrew@webrtc.org  }
519650419b07772de974964072478886c4c35ab9c8ccandrew@webrtc.org  if (audioproc->ProcessStream(&frame) != 0) {
5197655d8f56f61eef7bd074748e1f6f5c5d2cd767d5andrew@webrtc.org    LOG_FERR0(LS_WARNING, ProcessStream);
519850419b07772de974964072478886c4c35ab9c8ccandrew@webrtc.org  }
519950419b07772de974964072478886c4c35ab9c8ccandrew@webrtc.org  return 0;
5200470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com}
5201470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
520242259e7ebc7126f5a7036940fcab65b3f8d2af38turaj@webrtc.orgint Channel::SetSecondarySendCodec(const CodecInst& codec,
520342259e7ebc7126f5a7036940fcab65b3f8d2af38turaj@webrtc.org                                   int red_payload_type) {
52048c8ad85c5d70c38cea82f5b17794a4e7ab4cf531turaj@webrtc.org  // Sanity check for payload type.
52058c8ad85c5d70c38cea82f5b17794a4e7ab4cf531turaj@webrtc.org  if (red_payload_type < 0 || red_payload_type > 127) {
52068c8ad85c5d70c38cea82f5b17794a4e7ab4cf531turaj@webrtc.org    _engineStatisticsPtr->SetLastError(
52078c8ad85c5d70c38cea82f5b17794a4e7ab4cf531turaj@webrtc.org        VE_PLTYPE_ERROR, kTraceError,
52088c8ad85c5d70c38cea82f5b17794a4e7ab4cf531turaj@webrtc.org        "SetRedPayloadType() invalid RED payload type");
52098c8ad85c5d70c38cea82f5b17794a4e7ab4cf531turaj@webrtc.org    return -1;
52108c8ad85c5d70c38cea82f5b17794a4e7ab4cf531turaj@webrtc.org  }
52118c8ad85c5d70c38cea82f5b17794a4e7ab4cf531turaj@webrtc.org
521242259e7ebc7126f5a7036940fcab65b3f8d2af38turaj@webrtc.org  if (SetRedPayloadType(red_payload_type) < 0) {
521342259e7ebc7126f5a7036940fcab65b3f8d2af38turaj@webrtc.org    _engineStatisticsPtr->SetLastError(
521442259e7ebc7126f5a7036940fcab65b3f8d2af38turaj@webrtc.org        VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
521542259e7ebc7126f5a7036940fcab65b3f8d2af38turaj@webrtc.org        "SetSecondarySendCodec() Failed to register RED ACM");
521642259e7ebc7126f5a7036940fcab65b3f8d2af38turaj@webrtc.org    return -1;
521742259e7ebc7126f5a7036940fcab65b3f8d2af38turaj@webrtc.org  }
521842259e7ebc7126f5a7036940fcab65b3f8d2af38turaj@webrtc.org  if (_audioCodingModule.RegisterSecondarySendCodec(codec) < 0) {
521942259e7ebc7126f5a7036940fcab65b3f8d2af38turaj@webrtc.org    _engineStatisticsPtr->SetLastError(
522042259e7ebc7126f5a7036940fcab65b3f8d2af38turaj@webrtc.org        VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
522142259e7ebc7126f5a7036940fcab65b3f8d2af38turaj@webrtc.org        "SetSecondarySendCodec() Failed to register secondary send codec in "
522242259e7ebc7126f5a7036940fcab65b3f8d2af38turaj@webrtc.org        "ACM");
522342259e7ebc7126f5a7036940fcab65b3f8d2af38turaj@webrtc.org    return -1;
522442259e7ebc7126f5a7036940fcab65b3f8d2af38turaj@webrtc.org  }
522542259e7ebc7126f5a7036940fcab65b3f8d2af38turaj@webrtc.org
522642259e7ebc7126f5a7036940fcab65b3f8d2af38turaj@webrtc.org  return 0;
522742259e7ebc7126f5a7036940fcab65b3f8d2af38turaj@webrtc.org}
522842259e7ebc7126f5a7036940fcab65b3f8d2af38turaj@webrtc.org
522942259e7ebc7126f5a7036940fcab65b3f8d2af38turaj@webrtc.orgvoid Channel::RemoveSecondarySendCodec() {
523042259e7ebc7126f5a7036940fcab65b3f8d2af38turaj@webrtc.org  _audioCodingModule.UnregisterSecondarySendCodec();
523142259e7ebc7126f5a7036940fcab65b3f8d2af38turaj@webrtc.org}
523242259e7ebc7126f5a7036940fcab65b3f8d2af38turaj@webrtc.org
523342259e7ebc7126f5a7036940fcab65b3f8d2af38turaj@webrtc.orgint Channel::GetSecondarySendCodec(CodecInst* codec) {
523442259e7ebc7126f5a7036940fcab65b3f8d2af38turaj@webrtc.org  if (_audioCodingModule.SecondarySendCodec(codec) < 0) {
523542259e7ebc7126f5a7036940fcab65b3f8d2af38turaj@webrtc.org    _engineStatisticsPtr->SetLastError(
523642259e7ebc7126f5a7036940fcab65b3f8d2af38turaj@webrtc.org        VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
523742259e7ebc7126f5a7036940fcab65b3f8d2af38turaj@webrtc.org        "GetSecondarySendCodec() Failed to get secondary sent codec from ACM");
523842259e7ebc7126f5a7036940fcab65b3f8d2af38turaj@webrtc.org    return -1;
523942259e7ebc7126f5a7036940fcab65b3f8d2af38turaj@webrtc.org  }
524042259e7ebc7126f5a7036940fcab65b3f8d2af38turaj@webrtc.org  return 0;
524142259e7ebc7126f5a7036940fcab65b3f8d2af38turaj@webrtc.org}
524242259e7ebc7126f5a7036940fcab65b3f8d2af38turaj@webrtc.org
52438c8ad85c5d70c38cea82f5b17794a4e7ab4cf531turaj@webrtc.org// Assuming this method is called with valid payload type.
524442259e7ebc7126f5a7036940fcab65b3f8d2af38turaj@webrtc.orgint Channel::SetRedPayloadType(int red_payload_type) {
524542259e7ebc7126f5a7036940fcab65b3f8d2af38turaj@webrtc.org  CodecInst codec;
524642259e7ebc7126f5a7036940fcab65b3f8d2af38turaj@webrtc.org  bool found_red = false;
524742259e7ebc7126f5a7036940fcab65b3f8d2af38turaj@webrtc.org
524842259e7ebc7126f5a7036940fcab65b3f8d2af38turaj@webrtc.org  // Get default RED settings from the ACM database
524942259e7ebc7126f5a7036940fcab65b3f8d2af38turaj@webrtc.org  const int num_codecs = AudioCodingModule::NumberOfCodecs();
525042259e7ebc7126f5a7036940fcab65b3f8d2af38turaj@webrtc.org  for (int idx = 0; idx < num_codecs; idx++) {
52517a7a008031d43013b01176cfe40b0fd68c0d83b5tina.legrand@webrtc.org    _audioCodingModule.Codec(idx, &codec);
525242259e7ebc7126f5a7036940fcab65b3f8d2af38turaj@webrtc.org    if (!STR_CASE_CMP(codec.plname, "RED")) {
525342259e7ebc7126f5a7036940fcab65b3f8d2af38turaj@webrtc.org      found_red = true;
525442259e7ebc7126f5a7036940fcab65b3f8d2af38turaj@webrtc.org      break;
525542259e7ebc7126f5a7036940fcab65b3f8d2af38turaj@webrtc.org    }
525642259e7ebc7126f5a7036940fcab65b3f8d2af38turaj@webrtc.org  }
525742259e7ebc7126f5a7036940fcab65b3f8d2af38turaj@webrtc.org
525842259e7ebc7126f5a7036940fcab65b3f8d2af38turaj@webrtc.org  if (!found_red) {
525942259e7ebc7126f5a7036940fcab65b3f8d2af38turaj@webrtc.org    _engineStatisticsPtr->SetLastError(
526042259e7ebc7126f5a7036940fcab65b3f8d2af38turaj@webrtc.org        VE_CODEC_ERROR, kTraceError,
526142259e7ebc7126f5a7036940fcab65b3f8d2af38turaj@webrtc.org        "SetRedPayloadType() RED is not supported");
526242259e7ebc7126f5a7036940fcab65b3f8d2af38turaj@webrtc.org    return -1;
526342259e7ebc7126f5a7036940fcab65b3f8d2af38turaj@webrtc.org  }
526442259e7ebc7126f5a7036940fcab65b3f8d2af38turaj@webrtc.org
52659d532fd2752290e85aa804f29ab9aa6c017c9208turaj@webrtc.org  codec.pltype = red_payload_type;
526642259e7ebc7126f5a7036940fcab65b3f8d2af38turaj@webrtc.org  if (_audioCodingModule.RegisterSendCodec(codec) < 0) {
526742259e7ebc7126f5a7036940fcab65b3f8d2af38turaj@webrtc.org    _engineStatisticsPtr->SetLastError(
526842259e7ebc7126f5a7036940fcab65b3f8d2af38turaj@webrtc.org        VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
526942259e7ebc7126f5a7036940fcab65b3f8d2af38turaj@webrtc.org        "SetRedPayloadType() RED registration in ACM module failed");
527042259e7ebc7126f5a7036940fcab65b3f8d2af38turaj@webrtc.org    return -1;
527142259e7ebc7126f5a7036940fcab65b3f8d2af38turaj@webrtc.org  }
527242259e7ebc7126f5a7036940fcab65b3f8d2af38turaj@webrtc.org
527342259e7ebc7126f5a7036940fcab65b3f8d2af38turaj@webrtc.org  if (_rtpRtcpModule->SetSendREDPayloadType(red_payload_type) != 0) {
527442259e7ebc7126f5a7036940fcab65b3f8d2af38turaj@webrtc.org    _engineStatisticsPtr->SetLastError(
527542259e7ebc7126f5a7036940fcab65b3f8d2af38turaj@webrtc.org        VE_RTP_RTCP_MODULE_ERROR, kTraceError,
527642259e7ebc7126f5a7036940fcab65b3f8d2af38turaj@webrtc.org        "SetRedPayloadType() RED registration in RTP/RTCP module failed");
527742259e7ebc7126f5a7036940fcab65b3f8d2af38turaj@webrtc.org    return -1;
527842259e7ebc7126f5a7036940fcab65b3f8d2af38turaj@webrtc.org  }
527942259e7ebc7126f5a7036940fcab65b3f8d2af38turaj@webrtc.org  return 0;
528042259e7ebc7126f5a7036940fcab65b3f8d2af38turaj@webrtc.org}
528142259e7ebc7126f5a7036940fcab65b3f8d2af38turaj@webrtc.org
5282470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com} // namespace voe
5283470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com} // namespace webrtc
5284