channel.cc revision ac547a653862744d0aae560713f8418ad2852085
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
1364dad838e61e92e4a72437b153c5eba7a200fb4aHenrik Lundin#include <algorithm>
1464dad838e61e92e4a72437b153c5eba7a200fb4aHenrik Lundin
15ae856f2c9fc358e5cd68d8a595136dcef017ed96Ivo Creusen#include "webrtc/base/checks.h"
164591fbd09f9cb6e83433c49a12dd8524c2806502pkasting@chromium.org#include "webrtc/base/format_macros.h"
1794454b71adc37e15fd3f5a5fc432063f05caabcbwu@webrtc.org#include "webrtc/base/timeutils.h"
18e509f943eded156f7a8365b0b001abe73646acfaminyue@webrtc.org#include "webrtc/common.h"
1964dad838e61e92e4a72437b153c5eba7a200fb4aHenrik Lundin#include "webrtc/config.h"
206388c3e2fdfc91b3648fb7d408a14ddb25e41cd1turaj@webrtc.org#include "webrtc/modules/audio_device/include/audio_device.h"
216388c3e2fdfc91b3648fb7d408a14ddb25e41cd1turaj@webrtc.org#include "webrtc/modules/audio_processing/include/audio_processing.h"
22d66929995ff62e92c6cb5177d059e85b902fd388henrik.lundin@webrtc.org#include "webrtc/modules/interface/module_common_types.h"
23822fbd8b68ffdb481b9557e2950ae8d6657c8ce6wu@webrtc.org#include "webrtc/modules/rtp_rtcp/interface/receive_statistics.h"
24822fbd8b68ffdb481b9557e2950ae8d6657c8ce6wu@webrtc.org#include "webrtc/modules/rtp_rtcp/interface/rtp_payload_registry.h"
25822fbd8b68ffdb481b9557e2950ae8d6657c8ce6wu@webrtc.org#include "webrtc/modules/rtp_rtcp/interface/rtp_receiver.h"
26822fbd8b68ffdb481b9557e2950ae8d6657c8ce6wu@webrtc.org#include "webrtc/modules/rtp_rtcp/source/rtp_receiver_strategy.h"
276388c3e2fdfc91b3648fb7d408a14ddb25e41cd1turaj@webrtc.org#include "webrtc/modules/utility/interface/audio_frame_operations.h"
286388c3e2fdfc91b3648fb7d408a14ddb25e41cd1turaj@webrtc.org#include "webrtc/modules/utility/interface/process_thread.h"
296388c3e2fdfc91b3648fb7d408a14ddb25e41cd1turaj@webrtc.org#include "webrtc/system_wrappers/interface/critical_section_wrapper.h"
306388c3e2fdfc91b3648fb7d408a14ddb25e41cd1turaj@webrtc.org#include "webrtc/system_wrappers/interface/logging.h"
316388c3e2fdfc91b3648fb7d408a14ddb25e41cd1turaj@webrtc.org#include "webrtc/system_wrappers/interface/trace.h"
326388c3e2fdfc91b3648fb7d408a14ddb25e41cd1turaj@webrtc.org#include "webrtc/voice_engine/include/voe_base.h"
336388c3e2fdfc91b3648fb7d408a14ddb25e41cd1turaj@webrtc.org#include "webrtc/voice_engine/include/voe_external_media.h"
346388c3e2fdfc91b3648fb7d408a14ddb25e41cd1turaj@webrtc.org#include "webrtc/voice_engine/include/voe_rtp_rtcp.h"
356388c3e2fdfc91b3648fb7d408a14ddb25e41cd1turaj@webrtc.org#include "webrtc/voice_engine/output_mixer.h"
366388c3e2fdfc91b3648fb7d408a14ddb25e41cd1turaj@webrtc.org#include "webrtc/voice_engine/statistics.h"
376388c3e2fdfc91b3648fb7d408a14ddb25e41cd1turaj@webrtc.org#include "webrtc/voice_engine/transmit_mixer.h"
386388c3e2fdfc91b3648fb7d408a14ddb25e41cd1turaj@webrtc.org#include "webrtc/voice_engine/utility.h"
39470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
40470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com#if defined(_WIN32)
41470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com#include <Qos.h>
42470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com#endif
43470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
4450419b07772de974964072478886c4c35ab9c8ccandrew@webrtc.orgnamespace webrtc {
4550419b07772de974964072478886c4c35ab9c8ccandrew@webrtc.orgnamespace voe {
46470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
4754ae4ffb9e235a9742e2b11298327e02d870571csprang@webrtc.org// Extend the default RTCP statistics struct with max_jitter, defined as the
4854ae4ffb9e235a9742e2b11298327e02d870571csprang@webrtc.org// maximum jitter value seen in an RTCP report block.
4954ae4ffb9e235a9742e2b11298327e02d870571csprang@webrtc.orgstruct ChannelStatistics : public RtcpStatistics {
5054ae4ffb9e235a9742e2b11298327e02d870571csprang@webrtc.org  ChannelStatistics() : rtcp(), max_jitter(0) {}
5154ae4ffb9e235a9742e2b11298327e02d870571csprang@webrtc.org
5254ae4ffb9e235a9742e2b11298327e02d870571csprang@webrtc.org  RtcpStatistics rtcp;
5354ae4ffb9e235a9742e2b11298327e02d870571csprang@webrtc.org  uint32_t max_jitter;
5454ae4ffb9e235a9742e2b11298327e02d870571csprang@webrtc.org};
5554ae4ffb9e235a9742e2b11298327e02d870571csprang@webrtc.org
5654ae4ffb9e235a9742e2b11298327e02d870571csprang@webrtc.org// Statistics callback, called at each generation of a new RTCP report block.
5754ae4ffb9e235a9742e2b11298327e02d870571csprang@webrtc.orgclass StatisticsProxy : public RtcpStatisticsCallback {
5854ae4ffb9e235a9742e2b11298327e02d870571csprang@webrtc.org public:
5954ae4ffb9e235a9742e2b11298327e02d870571csprang@webrtc.org  StatisticsProxy(uint32_t ssrc)
6054ae4ffb9e235a9742e2b11298327e02d870571csprang@webrtc.org   : stats_lock_(CriticalSectionWrapper::CreateCriticalSection()),
6154ae4ffb9e235a9742e2b11298327e02d870571csprang@webrtc.org     ssrc_(ssrc) {}
6254ae4ffb9e235a9742e2b11298327e02d870571csprang@webrtc.org  virtual ~StatisticsProxy() {}
6354ae4ffb9e235a9742e2b11298327e02d870571csprang@webrtc.org
6414665ff7d4024d07e58622f498b23fd980001871kjellander@webrtc.org  void StatisticsUpdated(const RtcpStatistics& statistics,
6514665ff7d4024d07e58622f498b23fd980001871kjellander@webrtc.org                         uint32_t ssrc) override {
6654ae4ffb9e235a9742e2b11298327e02d870571csprang@webrtc.org    if (ssrc != ssrc_)
6754ae4ffb9e235a9742e2b11298327e02d870571csprang@webrtc.org      return;
6854ae4ffb9e235a9742e2b11298327e02d870571csprang@webrtc.org
6954ae4ffb9e235a9742e2b11298327e02d870571csprang@webrtc.org    CriticalSectionScoped cs(stats_lock_.get());
7054ae4ffb9e235a9742e2b11298327e02d870571csprang@webrtc.org    stats_.rtcp = statistics;
7154ae4ffb9e235a9742e2b11298327e02d870571csprang@webrtc.org    if (statistics.jitter > stats_.max_jitter) {
7254ae4ffb9e235a9742e2b11298327e02d870571csprang@webrtc.org      stats_.max_jitter = statistics.jitter;
7354ae4ffb9e235a9742e2b11298327e02d870571csprang@webrtc.org    }
7454ae4ffb9e235a9742e2b11298327e02d870571csprang@webrtc.org  }
7554ae4ffb9e235a9742e2b11298327e02d870571csprang@webrtc.org
7614665ff7d4024d07e58622f498b23fd980001871kjellander@webrtc.org  void CNameChanged(const char* cname, uint32_t ssrc) override {}
77ce4e9a356200170abcdd44ff2af95f87a6781b8epbos@webrtc.org
7854ae4ffb9e235a9742e2b11298327e02d870571csprang@webrtc.org  ChannelStatistics GetStats() {
7954ae4ffb9e235a9742e2b11298327e02d870571csprang@webrtc.org    CriticalSectionScoped cs(stats_lock_.get());
8054ae4ffb9e235a9742e2b11298327e02d870571csprang@webrtc.org    return stats_;
8154ae4ffb9e235a9742e2b11298327e02d870571csprang@webrtc.org  }
8254ae4ffb9e235a9742e2b11298327e02d870571csprang@webrtc.org
8354ae4ffb9e235a9742e2b11298327e02d870571csprang@webrtc.org private:
8454ae4ffb9e235a9742e2b11298327e02d870571csprang@webrtc.org  // StatisticsUpdated calls are triggered from threads in the RTP module,
8554ae4ffb9e235a9742e2b11298327e02d870571csprang@webrtc.org  // while GetStats calls can be triggered from the public voice engine API,
8654ae4ffb9e235a9742e2b11298327e02d870571csprang@webrtc.org  // hence synchronization is needed.
8700b8f6b3643332cce1ee711715f7fbb824d793cakwiberg@webrtc.org  rtc::scoped_ptr<CriticalSectionWrapper> stats_lock_;
8854ae4ffb9e235a9742e2b11298327e02d870571csprang@webrtc.org  const uint32_t ssrc_;
8954ae4ffb9e235a9742e2b11298327e02d870571csprang@webrtc.org  ChannelStatistics stats_;
9054ae4ffb9e235a9742e2b11298327e02d870571csprang@webrtc.org};
9154ae4ffb9e235a9742e2b11298327e02d870571csprang@webrtc.org
920a7d4eed98ccec0c2b3e7522e7b2dde1919a4ae3mflodman@webrtc.orgclass VoERtcpObserver : public RtcpBandwidthObserver {
93c1a40a7b68a8d253b0ba32b89f3126931eeaeab3minyue@webrtc.org public:
940a7d4eed98ccec0c2b3e7522e7b2dde1919a4ae3mflodman@webrtc.org  explicit VoERtcpObserver(Channel* owner) : owner_(owner) {}
950a7d4eed98ccec0c2b3e7522e7b2dde1919a4ae3mflodman@webrtc.org  virtual ~VoERtcpObserver() {}
960a7d4eed98ccec0c2b3e7522e7b2dde1919a4ae3mflodman@webrtc.org
970a7d4eed98ccec0c2b3e7522e7b2dde1919a4ae3mflodman@webrtc.org  void OnReceivedEstimatedBitrate(uint32_t bitrate) override {
980a7d4eed98ccec0c2b3e7522e7b2dde1919a4ae3mflodman@webrtc.org    // Not used for Voice Engine.
990a7d4eed98ccec0c2b3e7522e7b2dde1919a4ae3mflodman@webrtc.org  }
1000a7d4eed98ccec0c2b3e7522e7b2dde1919a4ae3mflodman@webrtc.org
10114665ff7d4024d07e58622f498b23fd980001871kjellander@webrtc.org  void OnReceivedRtcpReceiverReport(const ReportBlockList& report_blocks,
10214665ff7d4024d07e58622f498b23fd980001871kjellander@webrtc.org                                    int64_t rtt,
10314665ff7d4024d07e58622f498b23fd980001871kjellander@webrtc.org                                    int64_t now_ms) override {
1040a7d4eed98ccec0c2b3e7522e7b2dde1919a4ae3mflodman@webrtc.org    // TODO(mflodman): Do we need to aggregate reports here or can we jut send
1050a7d4eed98ccec0c2b3e7522e7b2dde1919a4ae3mflodman@webrtc.org    // what we get? I.e. do we ever get multiple reports bundled into one RTCP
1060a7d4eed98ccec0c2b3e7522e7b2dde1919a4ae3mflodman@webrtc.org    // report for VoiceEngine?
1070a7d4eed98ccec0c2b3e7522e7b2dde1919a4ae3mflodman@webrtc.org    if (report_blocks.empty())
1080a7d4eed98ccec0c2b3e7522e7b2dde1919a4ae3mflodman@webrtc.org      return;
1090a7d4eed98ccec0c2b3e7522e7b2dde1919a4ae3mflodman@webrtc.org
1100a7d4eed98ccec0c2b3e7522e7b2dde1919a4ae3mflodman@webrtc.org    int fraction_lost_aggregate = 0;
1110a7d4eed98ccec0c2b3e7522e7b2dde1919a4ae3mflodman@webrtc.org    int total_number_of_packets = 0;
1120a7d4eed98ccec0c2b3e7522e7b2dde1919a4ae3mflodman@webrtc.org
1130a7d4eed98ccec0c2b3e7522e7b2dde1919a4ae3mflodman@webrtc.org    // If receiving multiple report blocks, calculate the weighted average based
1140a7d4eed98ccec0c2b3e7522e7b2dde1919a4ae3mflodman@webrtc.org    // on the number of packets a report refers to.
1150a7d4eed98ccec0c2b3e7522e7b2dde1919a4ae3mflodman@webrtc.org    for (ReportBlockList::const_iterator block_it = report_blocks.begin();
1160a7d4eed98ccec0c2b3e7522e7b2dde1919a4ae3mflodman@webrtc.org         block_it != report_blocks.end(); ++block_it) {
1170a7d4eed98ccec0c2b3e7522e7b2dde1919a4ae3mflodman@webrtc.org      // Find the previous extended high sequence number for this remote SSRC,
1180a7d4eed98ccec0c2b3e7522e7b2dde1919a4ae3mflodman@webrtc.org      // to calculate the number of RTP packets this report refers to. Ignore if
1190a7d4eed98ccec0c2b3e7522e7b2dde1919a4ae3mflodman@webrtc.org      // we haven't seen this SSRC before.
1200a7d4eed98ccec0c2b3e7522e7b2dde1919a4ae3mflodman@webrtc.org      std::map<uint32_t, uint32_t>::iterator seq_num_it =
1210a7d4eed98ccec0c2b3e7522e7b2dde1919a4ae3mflodman@webrtc.org          extended_max_sequence_number_.find(block_it->sourceSSRC);
1220a7d4eed98ccec0c2b3e7522e7b2dde1919a4ae3mflodman@webrtc.org      int number_of_packets = 0;
1230a7d4eed98ccec0c2b3e7522e7b2dde1919a4ae3mflodman@webrtc.org      if (seq_num_it != extended_max_sequence_number_.end()) {
1240a7d4eed98ccec0c2b3e7522e7b2dde1919a4ae3mflodman@webrtc.org        number_of_packets = block_it->extendedHighSeqNum - seq_num_it->second;
1250a7d4eed98ccec0c2b3e7522e7b2dde1919a4ae3mflodman@webrtc.org      }
1260a7d4eed98ccec0c2b3e7522e7b2dde1919a4ae3mflodman@webrtc.org      fraction_lost_aggregate += number_of_packets * block_it->fractionLost;
1270a7d4eed98ccec0c2b3e7522e7b2dde1919a4ae3mflodman@webrtc.org      total_number_of_packets += number_of_packets;
1280a7d4eed98ccec0c2b3e7522e7b2dde1919a4ae3mflodman@webrtc.org
1290a7d4eed98ccec0c2b3e7522e7b2dde1919a4ae3mflodman@webrtc.org      extended_max_sequence_number_[block_it->sourceSSRC] =
1300a7d4eed98ccec0c2b3e7522e7b2dde1919a4ae3mflodman@webrtc.org          block_it->extendedHighSeqNum;
1310a7d4eed98ccec0c2b3e7522e7b2dde1919a4ae3mflodman@webrtc.org    }
1320a7d4eed98ccec0c2b3e7522e7b2dde1919a4ae3mflodman@webrtc.org    int weighted_fraction_lost = 0;
1330a7d4eed98ccec0c2b3e7522e7b2dde1919a4ae3mflodman@webrtc.org    if (total_number_of_packets > 0) {
1340a7d4eed98ccec0c2b3e7522e7b2dde1919a4ae3mflodman@webrtc.org      weighted_fraction_lost = (fraction_lost_aggregate +
1350a7d4eed98ccec0c2b3e7522e7b2dde1919a4ae3mflodman@webrtc.org          total_number_of_packets / 2) / total_number_of_packets;
1360a7d4eed98ccec0c2b3e7522e7b2dde1919a4ae3mflodman@webrtc.org    }
1370a7d4eed98ccec0c2b3e7522e7b2dde1919a4ae3mflodman@webrtc.org    owner_->OnIncomingFractionLoss(weighted_fraction_lost);
138c1a40a7b68a8d253b0ba32b89f3126931eeaeab3minyue@webrtc.org  }
139c1a40a7b68a8d253b0ba32b89f3126931eeaeab3minyue@webrtc.org
140c1a40a7b68a8d253b0ba32b89f3126931eeaeab3minyue@webrtc.org private:
141c1a40a7b68a8d253b0ba32b89f3126931eeaeab3minyue@webrtc.org  Channel* owner_;
1420a7d4eed98ccec0c2b3e7522e7b2dde1919a4ae3mflodman@webrtc.org  // Maps remote side ssrc to extended highest sequence number received.
1430a7d4eed98ccec0c2b3e7522e7b2dde1919a4ae3mflodman@webrtc.org  std::map<uint32_t, uint32_t> extended_max_sequence_number_;
144c1a40a7b68a8d253b0ba32b89f3126931eeaeab3minyue@webrtc.org};
145c1a40a7b68a8d253b0ba32b89f3126931eeaeab3minyue@webrtc.org
1466141e13873d0fdea626de08dfec2efa2c9171c76pbos@webrtc.orgint32_t
147470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.comChannel::SendData(FrameType frameType,
1486141e13873d0fdea626de08dfec2efa2c9171c76pbos@webrtc.org                  uint8_t   payloadType,
1496141e13873d0fdea626de08dfec2efa2c9171c76pbos@webrtc.org                  uint32_t  timeStamp,
1506141e13873d0fdea626de08dfec2efa2c9171c76pbos@webrtc.org                  const uint8_t*  payloadData,
1514591fbd09f9cb6e83433c49a12dd8524c2806502pkasting@chromium.org                  size_t    payloadSize,
152470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                  const RTPFragmentationHeader* fragmentation)
153470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com{
154470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
155470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                 "Channel::SendData(frameType=%u, payloadType=%u, timeStamp=%u,"
1564591fbd09f9cb6e83433c49a12dd8524c2806502pkasting@chromium.org                 " payloadSize=%" PRIuS ", fragmentation=0x%x)",
1574591fbd09f9cb6e83433c49a12dd8524c2806502pkasting@chromium.org                 frameType, payloadType, timeStamp,
1584591fbd09f9cb6e83433c49a12dd8524c2806502pkasting@chromium.org                 payloadSize, fragmentation);
159470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
160470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    if (_includeAudioLevelIndication)
161470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
162470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        // Store current audio level in the RTP/RTCP module.
163470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        // The level will be used in combination with voice-activity state
164470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        // (frameType) to add an RTP header extension
165382c0c209d323c1e6972d988a7b26f08fc2e8a6bandrew@webrtc.org        _rtpRtcpModule->SetAudioLevel(rms_level_.RMS());
166470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
167470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
168470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    // Push data from ACM to RTP/RTCP-module to deliver audio frame for
169470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    // packetization.
170470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    // This call will trigger Transport::SendPacket() from the RTP/RTCP module.
1712853dde5201d9ddc284ce5efb9688f6340487acepwestin@webrtc.org    if (_rtpRtcpModule->SendOutgoingData((FrameType&)frameType,
172470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                                        payloadType,
173470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                                        timeStamp,
174ddfdfed3b55de3da5fda9a55d34e46d6e422baafstefan@webrtc.org                                        // Leaving the time when this frame was
175ddfdfed3b55de3da5fda9a55d34e46d6e422baafstefan@webrtc.org                                        // received from the capture device as
176ddfdfed3b55de3da5fda9a55d34e46d6e422baafstefan@webrtc.org                                        // undefined for voice for now.
177ddfdfed3b55de3da5fda9a55d34e46d6e422baafstefan@webrtc.org                                        -1,
178470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                                        payloadData,
179470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                                        payloadSize,
180470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                                        fragmentation) == -1)
181470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
182470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        _engineStatisticsPtr->SetLastError(
183470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            VE_RTP_RTCP_MODULE_ERROR, kTraceWarning,
184470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            "Channel::SendData() failed to send data to RTP/RTCP module");
185470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        return -1;
186470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
187470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
188470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    _lastLocalTimeStamp = timeStamp;
189470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    _lastPayloadType = payloadType;
190470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
191470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    return 0;
192470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com}
193470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
1946141e13873d0fdea626de08dfec2efa2c9171c76pbos@webrtc.orgint32_t
195e9217b4bdbf9a8fd8b4882b2f995665927f28ad2henrik.lundin@webrtc.orgChannel::InFrameType(FrameType frame_type)
196470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com{
197470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
198e9217b4bdbf9a8fd8b4882b2f995665927f28ad2henrik.lundin@webrtc.org                 "Channel::InFrameType(frame_type=%d)", frame_type);
199470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
2009a065d1eae9ed296e1e2eaaad73d7ca1223bfe79mflodman@webrtc.org    CriticalSectionScoped cs(&_callbackCritSect);
201e9217b4bdbf9a8fd8b4882b2f995665927f28ad2henrik.lundin@webrtc.org    _sendFrameType = (frame_type == kAudioFrameSpeech);
202470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    return 0;
203470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com}
204470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
2056141e13873d0fdea626de08dfec2efa2c9171c76pbos@webrtc.orgint32_t
2069213521ea98b0977c7cdabd2853060835af226f3pbos@webrtc.orgChannel::OnRxVadDetected(int vadDecision)
207470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com{
208470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
209470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                 "Channel::OnRxVadDetected(vadDecision=%d)", vadDecision);
210470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
2119a065d1eae9ed296e1e2eaaad73d7ca1223bfe79mflodman@webrtc.org    CriticalSectionScoped cs(&_callbackCritSect);
212470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    if (_rxVadObserverPtr)
213470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
214470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        _rxVadObserverPtr->OnRxVad(_channelId, vadDecision);
215470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
216470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
217470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    return 0;
218470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com}
219470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
220470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.comint
221ac547a653862744d0aae560713f8418ad2852085Peter BoströmChannel::SendPacket(const void *data, size_t len)
222470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com{
223470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
224ac547a653862744d0aae560713f8418ad2852085Peter Boström                 "Channel::SendPacket(channel=%d, len=%" PRIuS ")", len);
225470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
226fb648da2b9d33e8641c88a7f0559508539104b6dwu@webrtc.org    CriticalSectionScoped cs(&_callbackCritSect);
227fb648da2b9d33e8641c88a7f0559508539104b6dwu@webrtc.org
228470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    if (_transportPtr == NULL)
229470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
230470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        WEBRTC_TRACE(kTraceError, kTraceVoice, VoEId(_instanceId,_channelId),
231470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                     "Channel::SendPacket() failed to send RTP packet due to"
232470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                     " invalid transport object");
233470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        return -1;
234470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
235470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
2366141e13873d0fdea626de08dfec2efa2c9171c76pbos@webrtc.org    uint8_t* bufferToSendPtr = (uint8_t*)data;
2374591fbd09f9cb6e83433c49a12dd8524c2806502pkasting@chromium.org    size_t bufferLength = len;
238470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
239ac547a653862744d0aae560713f8418ad2852085Peter Boström    int n = _transportPtr->SendPacket(bufferToSendPtr, bufferLength);
240fb648da2b9d33e8641c88a7f0559508539104b6dwu@webrtc.org    if (n < 0) {
241fb648da2b9d33e8641c88a7f0559508539104b6dwu@webrtc.org      std::string transport_name =
242fb648da2b9d33e8641c88a7f0559508539104b6dwu@webrtc.org          _externalTransport ? "external transport" : "WebRtc sockets";
243fb648da2b9d33e8641c88a7f0559508539104b6dwu@webrtc.org      WEBRTC_TRACE(kTraceError, kTraceVoice,
244fb648da2b9d33e8641c88a7f0559508539104b6dwu@webrtc.org                   VoEId(_instanceId,_channelId),
245fb648da2b9d33e8641c88a7f0559508539104b6dwu@webrtc.org                   "Channel::SendPacket() RTP transmission using %s failed",
246fb648da2b9d33e8641c88a7f0559508539104b6dwu@webrtc.org                   transport_name.c_str());
247fb648da2b9d33e8641c88a7f0559508539104b6dwu@webrtc.org      return -1;
248470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
249fb648da2b9d33e8641c88a7f0559508539104b6dwu@webrtc.org    return n;
250470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com}
251470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
252470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.comint
253ac547a653862744d0aae560713f8418ad2852085Peter BoströmChannel::SendRTCPPacket(const void *data, size_t len)
254470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com{
255470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
256ac547a653862744d0aae560713f8418ad2852085Peter Boström                 "Channel::SendRTCPPacket(len=%" PRIuS ")", len);
257470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
258fb648da2b9d33e8641c88a7f0559508539104b6dwu@webrtc.org    CriticalSectionScoped cs(&_callbackCritSect);
259fb648da2b9d33e8641c88a7f0559508539104b6dwu@webrtc.org    if (_transportPtr == NULL)
260470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
261fb648da2b9d33e8641c88a7f0559508539104b6dwu@webrtc.org        WEBRTC_TRACE(kTraceError, kTraceVoice,
262fb648da2b9d33e8641c88a7f0559508539104b6dwu@webrtc.org                     VoEId(_instanceId,_channelId),
263fb648da2b9d33e8641c88a7f0559508539104b6dwu@webrtc.org                     "Channel::SendRTCPPacket() failed to send RTCP packet"
264fb648da2b9d33e8641c88a7f0559508539104b6dwu@webrtc.org                     " due to invalid transport object");
265fb648da2b9d33e8641c88a7f0559508539104b6dwu@webrtc.org        return -1;
266470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
267470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
2686141e13873d0fdea626de08dfec2efa2c9171c76pbos@webrtc.org    uint8_t* bufferToSendPtr = (uint8_t*)data;
2694591fbd09f9cb6e83433c49a12dd8524c2806502pkasting@chromium.org    size_t bufferLength = len;
270470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
271ac547a653862744d0aae560713f8418ad2852085Peter Boström    int n = _transportPtr->SendRTCPPacket(bufferToSendPtr, bufferLength);
272fb648da2b9d33e8641c88a7f0559508539104b6dwu@webrtc.org    if (n < 0) {
273fb648da2b9d33e8641c88a7f0559508539104b6dwu@webrtc.org      std::string transport_name =
274fb648da2b9d33e8641c88a7f0559508539104b6dwu@webrtc.org          _externalTransport ? "external transport" : "WebRtc sockets";
275fb648da2b9d33e8641c88a7f0559508539104b6dwu@webrtc.org      WEBRTC_TRACE(kTraceInfo, kTraceVoice,
276fb648da2b9d33e8641c88a7f0559508539104b6dwu@webrtc.org                   VoEId(_instanceId,_channelId),
277fb648da2b9d33e8641c88a7f0559508539104b6dwu@webrtc.org                   "Channel::SendRTCPPacket() transmission using %s failed",
278fb648da2b9d33e8641c88a7f0559508539104b6dwu@webrtc.org                   transport_name.c_str());
279fb648da2b9d33e8641c88a7f0559508539104b6dwu@webrtc.org      return -1;
280470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
281fb648da2b9d33e8641c88a7f0559508539104b6dwu@webrtc.org    return n;
282470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com}
283470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
284ac547a653862744d0aae560713f8418ad2852085Peter Boströmvoid Channel::OnPlayTelephoneEvent(uint8_t event,
285ac547a653862744d0aae560713f8418ad2852085Peter Boström                                   uint16_t lengthMs,
286ac547a653862744d0aae560713f8418ad2852085Peter Boström                                   uint8_t volume) {
287470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
288ac547a653862744d0aae560713f8418ad2852085Peter Boström                 "Channel::OnPlayTelephoneEvent(event=%u, lengthMs=%u,"
289ac547a653862744d0aae560713f8418ad2852085Peter Boström                 " volume=%u)", event, lengthMs, volume);
290470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
291470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    if (!_playOutbandDtmfEvent || (event > 15))
292470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
293470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        // Ignore callback since feedback is disabled or event is not a
294470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        // Dtmf tone event.
295470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        return;
296470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
297470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
298470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    assert(_outputMixerPtr != NULL);
299470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
300470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    // Start playing out the Dtmf tone (if playout is enabled).
301470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    // Reduce length of tone with 80ms to the reduce risk of echo.
302470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    _outputMixerPtr->PlayDtmfTone(event, lengthMs - 80, volume);
303470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com}
304470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
305470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.comvoid
306ac547a653862744d0aae560713f8418ad2852085Peter BoströmChannel::OnIncomingSSRCChanged(uint32_t ssrc)
307470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com{
308470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
309ac547a653862744d0aae560713f8418ad2852085Peter Boström                 "Channel::OnIncomingSSRCChanged(SSRC=%d)", ssrc);
310470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
311b295a3f5920e2706d42c960c5180c7cc6e1f435edwkang@webrtc.org    // Update ssrc so that NTP for AV sync can be updated.
312b295a3f5920e2706d42c960c5180c7cc6e1f435edwkang@webrtc.org    _rtpRtcpModule->SetRemoteSSRC(ssrc);
313470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com}
314470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
315ac547a653862744d0aae560713f8418ad2852085Peter Boströmvoid Channel::OnIncomingCSRCChanged(uint32_t CSRC, bool added) {
316ac547a653862744d0aae560713f8418ad2852085Peter Boström  WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
317ac547a653862744d0aae560713f8418ad2852085Peter Boström               "Channel::OnIncomingCSRCChanged(CSRC=%d, added=%d)", CSRC,
318ac547a653862744d0aae560713f8418ad2852085Peter Boström               added);
319470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com}
320470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
321ac547a653862744d0aae560713f8418ad2852085Peter Boströmint32_t Channel::OnInitializeDecoder(
3229213521ea98b0977c7cdabd2853060835af226f3pbos@webrtc.org    int8_t payloadType,
323813e4b0af06272dada388c2d8383b2e36a1da6a6leozwang@webrtc.org    const char payloadName[RTP_PAYLOAD_NAME_SIZE],
3249213521ea98b0977c7cdabd2853060835af226f3pbos@webrtc.org    int frequency,
3259213521ea98b0977c7cdabd2853060835af226f3pbos@webrtc.org    uint8_t channels,
326ac547a653862744d0aae560713f8418ad2852085Peter Boström    uint32_t rate) {
327470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
328ac547a653862744d0aae560713f8418ad2852085Peter Boström                 "Channel::OnInitializeDecoder(payloadType=%d, "
329470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                 "payloadName=%s, frequency=%u, channels=%u, rate=%u)",
330ac547a653862744d0aae560713f8418ad2852085Peter Boström                 payloadType, payloadName, frequency, channels, rate);
331470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
332f75901fa4c5f9a1bcefc265b98a480c72119650chenrika@webrtc.org    CodecInst receiveCodec = {0};
333f75901fa4c5f9a1bcefc265b98a480c72119650chenrika@webrtc.org    CodecInst dummyCodec = {0};
334470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
335470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    receiveCodec.pltype = payloadType;
336470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    receiveCodec.plfreq = frequency;
337470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    receiveCodec.channels = channels;
338470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    receiveCodec.rate = rate;
339f75901fa4c5f9a1bcefc265b98a480c72119650chenrika@webrtc.org    strncpy(receiveCodec.plname, payloadName, RTP_PAYLOAD_NAME_SIZE - 1);
340ae1a58bba4f926d149a5f39243269c3f6625f494andrew@webrtc.org
341eb524d997b877ba9b0bcaf8c85eae52bd40c37e3andrew@webrtc.org    audio_coding_->Codec(payloadName, &dummyCodec, frequency, channels);
342470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    receiveCodec.pacsize = dummyCodec.pacsize;
343470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
344470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    // Register the new codec to the ACM
345eb524d997b877ba9b0bcaf8c85eae52bd40c37e3andrew@webrtc.org    if (audio_coding_->RegisterReceiveCodec(receiveCodec) == -1)
346470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
347470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        WEBRTC_TRACE(kTraceWarning, kTraceVoice,
348ceb148ce593627ed0d30a1a8c01752bdebf9172dandrew@webrtc.org                     VoEId(_instanceId, _channelId),
349470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                     "Channel::OnInitializeDecoder() invalid codec ("
350470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                     "pt=%d, name=%s) received - 1", payloadType, payloadName);
351470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        _engineStatisticsPtr->SetLastError(VE_AUDIO_CODING_MODULE_ERROR);
352470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        return -1;
353470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
354470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
355470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    return 0;
356470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com}
357470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
3586141e13873d0fdea626de08dfec2efa2c9171c76pbos@webrtc.orgint32_t
3596141e13873d0fdea626de08dfec2efa2c9171c76pbos@webrtc.orgChannel::OnReceivedPayloadData(const uint8_t* payloadData,
3604591fbd09f9cb6e83433c49a12dd8524c2806502pkasting@chromium.org                               size_t payloadSize,
361470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                               const WebRtcRTPHeader* rtpHeader)
362470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com{
363470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
3644591fbd09f9cb6e83433c49a12dd8524c2806502pkasting@chromium.org                 "Channel::OnReceivedPayloadData(payloadSize=%" PRIuS ","
365470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                 " payloadType=%u, audioChannel=%u)",
366470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                 payloadSize,
367470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                 rtpHeader->header.payloadType,
368470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                 rtpHeader->type.Audio.channel);
369470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
370944cbeb2926feb86a687e5fda9e2ac88ea8e3001henrika@webrtc.org    if (!channel_state_.Get().playing)
371470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
372470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        // Avoid inserting into NetEQ when we are not playing. Count the
373470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        // packet as discarded.
374470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        WEBRTC_TRACE(kTraceStream, kTraceVoice,
375470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                     VoEId(_instanceId, _channelId),
376470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                     "received packet is discarded since playing is not"
377470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                     " activated");
378470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        _numberOfDiscardedPackets++;
379470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        return 0;
380470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
381470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
382470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    // Push the incoming payload (parsed and ready for decoding) into the ACM
383eb524d997b877ba9b0bcaf8c85eae52bd40c37e3andrew@webrtc.org    if (audio_coding_->IncomingPacket(payloadData,
384eb524d997b877ba9b0bcaf8c85eae52bd40c37e3andrew@webrtc.org                                      payloadSize,
385eb524d997b877ba9b0bcaf8c85eae52bd40c37e3andrew@webrtc.org                                      *rtpHeader) != 0)
386470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
387470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        _engineStatisticsPtr->SetLastError(
388470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            VE_AUDIO_CODING_MODULE_ERROR, kTraceWarning,
389470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            "Channel::OnReceivedPayloadData() unable to push data to the ACM");
390470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        return -1;
391470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
392470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
393d30859e58e2c0b0676ab2b52b8a2723e10d49e28pwestin@webrtc.org    // Update the packet delay.
394470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    UpdatePacketDelay(rtpHeader->header.timestamp,
395470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                      rtpHeader->header.sequenceNumber);
396d30859e58e2c0b0676ab2b52b8a2723e10d49e28pwestin@webrtc.org
39716825b1a828bb4ff40f7682040e43a239b7b8ca3pkasting@chromium.org    int64_t round_trip_time = 0;
398822fbd8b68ffdb481b9557e2950ae8d6657c8ce6wu@webrtc.org    _rtpRtcpModule->RTT(rtp_receiver_->SSRC(), &round_trip_time,
399822fbd8b68ffdb481b9557e2950ae8d6657c8ce6wu@webrtc.org                        NULL, NULL, NULL);
400822fbd8b68ffdb481b9557e2950ae8d6657c8ce6wu@webrtc.org
401eb524d997b877ba9b0bcaf8c85eae52bd40c37e3andrew@webrtc.org    std::vector<uint16_t> nack_list = audio_coding_->GetNackList(
402822fbd8b68ffdb481b9557e2950ae8d6657c8ce6wu@webrtc.org        round_trip_time);
403822fbd8b68ffdb481b9557e2950ae8d6657c8ce6wu@webrtc.org    if (!nack_list.empty()) {
404822fbd8b68ffdb481b9557e2950ae8d6657c8ce6wu@webrtc.org      // Can't use nack_list.data() since it's not supported by all
405822fbd8b68ffdb481b9557e2950ae8d6657c8ce6wu@webrtc.org      // compilers.
406822fbd8b68ffdb481b9557e2950ae8d6657c8ce6wu@webrtc.org      ResendPackets(&(nack_list[0]), static_cast<int>(nack_list.size()));
407d30859e58e2c0b0676ab2b52b8a2723e10d49e28pwestin@webrtc.org    }
408470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    return 0;
409470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com}
410470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
4117bb8f02274ecbfa1f7ef134d708369a369a78c83stefan@webrtc.orgbool Channel::OnRecoveredPacket(const uint8_t* rtp_packet,
4124591fbd09f9cb6e83433c49a12dd8524c2806502pkasting@chromium.org                                size_t rtp_packet_length) {
4137bb8f02274ecbfa1f7ef134d708369a369a78c83stefan@webrtc.org  RTPHeader header;
4147bb8f02274ecbfa1f7ef134d708369a369a78c83stefan@webrtc.org  if (!rtp_header_parser_->Parse(rtp_packet, rtp_packet_length, &header)) {
4157bb8f02274ecbfa1f7ef134d708369a369a78c83stefan@webrtc.org    WEBRTC_TRACE(kTraceDebug, webrtc::kTraceVoice, _channelId,
4167bb8f02274ecbfa1f7ef134d708369a369a78c83stefan@webrtc.org                 "IncomingPacket invalid RTP header");
4177bb8f02274ecbfa1f7ef134d708369a369a78c83stefan@webrtc.org    return false;
4187bb8f02274ecbfa1f7ef134d708369a369a78c83stefan@webrtc.org  }
4197bb8f02274ecbfa1f7ef134d708369a369a78c83stefan@webrtc.org  header.payload_type_frequency =
4207bb8f02274ecbfa1f7ef134d708369a369a78c83stefan@webrtc.org      rtp_payload_registry_->GetPayloadTypeFrequency(header.payloadType);
4217bb8f02274ecbfa1f7ef134d708369a369a78c83stefan@webrtc.org  if (header.payload_type_frequency < 0)
4227bb8f02274ecbfa1f7ef134d708369a369a78c83stefan@webrtc.org    return false;
4237bb8f02274ecbfa1f7ef134d708369a369a78c83stefan@webrtc.org  return ReceivePacket(rtp_packet, rtp_packet_length, header, false);
4247bb8f02274ecbfa1f7ef134d708369a369a78c83stefan@webrtc.org}
4257bb8f02274ecbfa1f7ef134d708369a369a78c83stefan@webrtc.org
4260f4b3731c34e796da92572380855dbc7321c8cfeminyuelint32_t Channel::GetAudioFrame(int32_t id, AudioFrame* audioFrame)
427470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com{
428470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
429470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                 "Channel::GetAudioFrame(id=%d)", id);
430470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
431ae856f2c9fc358e5cd68d8a595136dcef017ed96Ivo Creusen    if (event_log_) {
432ae856f2c9fc358e5cd68d8a595136dcef017ed96Ivo Creusen      unsigned int ssrc;
433ae856f2c9fc358e5cd68d8a595136dcef017ed96Ivo Creusen      RTC_CHECK_EQ(GetLocalSSRC(ssrc), 0);
434ae856f2c9fc358e5cd68d8a595136dcef017ed96Ivo Creusen      event_log_->LogAudioPlayout(ssrc);
435ae856f2c9fc358e5cd68d8a595136dcef017ed96Ivo Creusen    }
436470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    // Get 10ms raw PCM data from the ACM (mixer limits output frequency)
4370f4b3731c34e796da92572380855dbc7321c8cfeminyuel    if (audio_coding_->PlayoutData10Ms(audioFrame->sample_rate_hz_,
4380f4b3731c34e796da92572380855dbc7321c8cfeminyuel                                       audioFrame) == -1)
439470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
440470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        WEBRTC_TRACE(kTraceError, kTraceVoice,
441470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                     VoEId(_instanceId,_channelId),
442470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                     "Channel::GetAudioFrame() PlayoutData10Ms() failed!");
4437859e109855b9536593892734aa65af974e6baa4andrew@webrtc.org        // In all likelihood, the audio in this frame is garbage. We return an
4447859e109855b9536593892734aa65af974e6baa4andrew@webrtc.org        // error so that the audio mixer module doesn't add it to the mix. As
4457859e109855b9536593892734aa65af974e6baa4andrew@webrtc.org        // a result, it won't be played out and the actions skipped here are
4467859e109855b9536593892734aa65af974e6baa4andrew@webrtc.org        // irrelevant.
4477859e109855b9536593892734aa65af974e6baa4andrew@webrtc.org        return -1;
448470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
449470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
450470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    if (_RxVadDetection)
451470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
4520f4b3731c34e796da92572380855dbc7321c8cfeminyuel        UpdateRxVadDetection(*audioFrame);
453470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
454470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
455470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    // Convert module ID to internal VoE channel ID
4560f4b3731c34e796da92572380855dbc7321c8cfeminyuel    audioFrame->id_ = VoEChannelId(audioFrame->id_);
457470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    // Store speech type for dead-or-alive detection
4580f4b3731c34e796da92572380855dbc7321c8cfeminyuel    _outputSpeechType = audioFrame->speech_type_;
459470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
460944cbeb2926feb86a687e5fda9e2ac88ea8e3001henrika@webrtc.org    ChannelState::State state = channel_state_.Get();
461944cbeb2926feb86a687e5fda9e2ac88ea8e3001henrika@webrtc.org
462944cbeb2926feb86a687e5fda9e2ac88ea8e3001henrika@webrtc.org    if (state.rx_apm_is_enabled) {
4630f4b3731c34e796da92572380855dbc7321c8cfeminyuel      int err = rx_audioproc_->ProcessStream(audioFrame);
46460730cfe3ce80e4023cd678373456cb703f000a4andrew@webrtc.org      if (err) {
46560730cfe3ce80e4023cd678373456cb703f000a4andrew@webrtc.org        LOG(LS_ERROR) << "ProcessStream() error: " << err;
46660730cfe3ce80e4023cd678373456cb703f000a4andrew@webrtc.org        assert(false);
46760730cfe3ce80e4023cd678373456cb703f000a4andrew@webrtc.org      }
468470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
469470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
47063420669746cfca6ed1d902c68c656b79ffa5a1bwu@webrtc.org    float output_gain = 1.0f;
47163420669746cfca6ed1d902c68c656b79ffa5a1bwu@webrtc.org    float left_pan =  1.0f;
47263420669746cfca6ed1d902c68c656b79ffa5a1bwu@webrtc.org    float right_pan =  1.0f;
47363420669746cfca6ed1d902c68c656b79ffa5a1bwu@webrtc.org    {
47463420669746cfca6ed1d902c68c656b79ffa5a1bwu@webrtc.org      CriticalSectionScoped cs(&volume_settings_critsect_);
47563420669746cfca6ed1d902c68c656b79ffa5a1bwu@webrtc.org      output_gain = _outputGain;
47663420669746cfca6ed1d902c68c656b79ffa5a1bwu@webrtc.org      left_pan = _panLeft;
47763420669746cfca6ed1d902c68c656b79ffa5a1bwu@webrtc.org      right_pan= _panRight;
47863420669746cfca6ed1d902c68c656b79ffa5a1bwu@webrtc.org    }
47963420669746cfca6ed1d902c68c656b79ffa5a1bwu@webrtc.org
480470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    // Output volume scaling
48163420669746cfca6ed1d902c68c656b79ffa5a1bwu@webrtc.org    if (output_gain < 0.99f || output_gain > 1.01f)
482470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
4830f4b3731c34e796da92572380855dbc7321c8cfeminyuel        AudioFrameOperations::ScaleWithSat(output_gain, *audioFrame);
484470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
485470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
486470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    // Scale left and/or right channel(s) if stereo and master balance is
487470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    // active
488470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
48963420669746cfca6ed1d902c68c656b79ffa5a1bwu@webrtc.org    if (left_pan != 1.0f || right_pan != 1.0f)
490470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
4910f4b3731c34e796da92572380855dbc7321c8cfeminyuel        if (audioFrame->num_channels_ == 1)
492470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        {
493470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            // Emulate stereo mode since panning is active.
494470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            // The mono signal is copied to both left and right channels here.
4950f4b3731c34e796da92572380855dbc7321c8cfeminyuel            AudioFrameOperations::MonoToStereo(audioFrame);
496470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        }
497470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        // For true stereo mode (when we are receiving a stereo signal), no
498470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        // action is needed.
499470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
500470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        // Do the panning operation (the audio frame contains stereo at this
501470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        // stage)
5020f4b3731c34e796da92572380855dbc7321c8cfeminyuel        AudioFrameOperations::Scale(left_pan, right_pan, *audioFrame);
503470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
504470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
505470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    // Mix decoded PCM output with file if file mixing is enabled
506944cbeb2926feb86a687e5fda9e2ac88ea8e3001henrika@webrtc.org    if (state.output_file_playing)
507470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
5080f4b3731c34e796da92572380855dbc7321c8cfeminyuel        MixAudioWithFile(*audioFrame, audioFrame->sample_rate_hz_);
509470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
510470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
511470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    // External media
512470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    if (_outputExternalMedia)
513470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
5149a065d1eae9ed296e1e2eaaad73d7ca1223bfe79mflodman@webrtc.org        CriticalSectionScoped cs(&_callbackCritSect);
5150f4b3731c34e796da92572380855dbc7321c8cfeminyuel        const bool isStereo = (audioFrame->num_channels_ == 2);
516470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        if (_outputExternalMediaCallbackPtr)
517470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        {
518470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            _outputExternalMediaCallbackPtr->Process(
519470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                _channelId,
520470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                kPlaybackPerChannel,
5210f4b3731c34e796da92572380855dbc7321c8cfeminyuel                (int16_t*)audioFrame->data_,
5220f4b3731c34e796da92572380855dbc7321c8cfeminyuel                audioFrame->samples_per_channel_,
5230f4b3731c34e796da92572380855dbc7321c8cfeminyuel                audioFrame->sample_rate_hz_,
524470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                isStereo);
525470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        }
526470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
527470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
528470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    // Record playout if enabled
529470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
5309a065d1eae9ed296e1e2eaaad73d7ca1223bfe79mflodman@webrtc.org        CriticalSectionScoped cs(&_fileCritSect);
531470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
532470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        if (_outputFileRecording && _outputFileRecorderPtr)
533470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        {
5340f4b3731c34e796da92572380855dbc7321c8cfeminyuel            _outputFileRecorderPtr->RecordAudioToFile(*audioFrame);
535470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        }
536470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
537470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
538470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    // Measure audio level (0-9)
5390f4b3731c34e796da92572380855dbc7321c8cfeminyuel    _outputAudioLevel.ComputeLevel(*audioFrame);
540470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
5410f4b3731c34e796da92572380855dbc7321c8cfeminyuel    if (capture_start_rtp_time_stamp_ < 0 && audioFrame->timestamp_ != 0) {
54294454b71adc37e15fd3f5a5fc432063f05caabcbwu@webrtc.org      // The first frame with a valid rtp timestamp.
5430f4b3731c34e796da92572380855dbc7321c8cfeminyuel      capture_start_rtp_time_stamp_ = audioFrame->timestamp_;
54494454b71adc37e15fd3f5a5fc432063f05caabcbwu@webrtc.org    }
54594454b71adc37e15fd3f5a5fc432063f05caabcbwu@webrtc.org
54694454b71adc37e15fd3f5a5fc432063f05caabcbwu@webrtc.org    if (capture_start_rtp_time_stamp_ >= 0) {
54794454b71adc37e15fd3f5a5fc432063f05caabcbwu@webrtc.org      // audioFrame.timestamp_ should be valid from now on.
54894454b71adc37e15fd3f5a5fc432063f05caabcbwu@webrtc.org
54994454b71adc37e15fd3f5a5fc432063f05caabcbwu@webrtc.org      // Compute elapsed time.
55094454b71adc37e15fd3f5a5fc432063f05caabcbwu@webrtc.org      int64_t unwrap_timestamp =
5510f4b3731c34e796da92572380855dbc7321c8cfeminyuel          rtp_ts_wraparound_handler_->Unwrap(audioFrame->timestamp_);
5520f4b3731c34e796da92572380855dbc7321c8cfeminyuel      audioFrame->elapsed_time_ms_ =
55394454b71adc37e15fd3f5a5fc432063f05caabcbwu@webrtc.org          (unwrap_timestamp - capture_start_rtp_time_stamp_) /
55494454b71adc37e15fd3f5a5fc432063f05caabcbwu@webrtc.org          (GetPlayoutFrequency() / 1000);
55594454b71adc37e15fd3f5a5fc432063f05caabcbwu@webrtc.org
5568e24d8777849951ed86fb01e0bf556d4eda65161stefan@webrtc.org      {
557cb711f77d2ff9ebd42678869a73353809b3af66ewu@webrtc.org        CriticalSectionScoped lock(ts_stats_lock_.get());
5588e24d8777849951ed86fb01e0bf556d4eda65161stefan@webrtc.org        // Compute ntp time.
5590f4b3731c34e796da92572380855dbc7321c8cfeminyuel        audioFrame->ntp_time_ms_ = ntp_estimator_.Estimate(
5600f4b3731c34e796da92572380855dbc7321c8cfeminyuel            audioFrame->timestamp_);
5618e24d8777849951ed86fb01e0bf556d4eda65161stefan@webrtc.org        // |ntp_time_ms_| won't be valid until at least 2 RTCP SRs are received.
5620f4b3731c34e796da92572380855dbc7321c8cfeminyuel        if (audioFrame->ntp_time_ms_ > 0) {
5638e24d8777849951ed86fb01e0bf556d4eda65161stefan@webrtc.org          // Compute |capture_start_ntp_time_ms_| so that
5648e24d8777849951ed86fb01e0bf556d4eda65161stefan@webrtc.org          // |capture_start_ntp_time_ms_| + |elapsed_time_ms_| == |ntp_time_ms_|
5658e24d8777849951ed86fb01e0bf556d4eda65161stefan@webrtc.org          capture_start_ntp_time_ms_ =
5660f4b3731c34e796da92572380855dbc7321c8cfeminyuel              audioFrame->ntp_time_ms_ - audioFrame->elapsed_time_ms_;
5678e24d8777849951ed86fb01e0bf556d4eda65161stefan@webrtc.org        }
568cb711f77d2ff9ebd42678869a73353809b3af66ewu@webrtc.org      }
569cb711f77d2ff9ebd42678869a73353809b3af66ewu@webrtc.org    }
570cb711f77d2ff9ebd42678869a73353809b3af66ewu@webrtc.org
571470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    return 0;
572470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com}
573470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
5746141e13873d0fdea626de08dfec2efa2c9171c76pbos@webrtc.orgint32_t
5750f4b3731c34e796da92572380855dbc7321c8cfeminyuelChannel::NeededFrequency(int32_t id) const
576470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com{
577470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
578470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                 "Channel::NeededFrequency(id=%d)", id);
579470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
580470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    int highestNeeded = 0;
581470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
582470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    // Determine highest needed receive frequency
583eb524d997b877ba9b0bcaf8c85eae52bd40c37e3andrew@webrtc.org    int32_t receiveFrequency = audio_coding_->ReceiveFrequency();
584470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
585470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    // Return the bigger of playout and receive frequency in the ACM.
586eb524d997b877ba9b0bcaf8c85eae52bd40c37e3andrew@webrtc.org    if (audio_coding_->PlayoutFrequency() > receiveFrequency)
587470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
588eb524d997b877ba9b0bcaf8c85eae52bd40c37e3andrew@webrtc.org        highestNeeded = audio_coding_->PlayoutFrequency();
589470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
590470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    else
591470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
592470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        highestNeeded = receiveFrequency;
593470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
594470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
595470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    // Special case, if we're playing a file on the playout side
596470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    // we take that frequency into consideration as well
597470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    // This is not needed on sending side, since the codec will
598470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    // limit the spectrum anyway.
599944cbeb2926feb86a687e5fda9e2ac88ea8e3001henrika@webrtc.org    if (channel_state_.Get().output_file_playing)
600470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
6019a065d1eae9ed296e1e2eaaad73d7ca1223bfe79mflodman@webrtc.org        CriticalSectionScoped cs(&_fileCritSect);
602944cbeb2926feb86a687e5fda9e2ac88ea8e3001henrika@webrtc.org        if (_outputFilePlayerPtr)
603470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        {
604470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            if(_outputFilePlayerPtr->Frequency()>highestNeeded)
605470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            {
606470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                highestNeeded=_outputFilePlayerPtr->Frequency();
607470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            }
608470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        }
609470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
610470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
611470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    return(highestNeeded);
612470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com}
613470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
614b04965ccf83c2bc6e2758abab9bea0c18551a54civocint32_t Channel::CreateChannel(Channel*& channel,
615b04965ccf83c2bc6e2758abab9bea0c18551a54civoc                               int32_t channelId,
616b04965ccf83c2bc6e2758abab9bea0c18551a54civoc                               uint32_t instanceId,
617b04965ccf83c2bc6e2758abab9bea0c18551a54civoc                               RtcEventLog* const event_log,
618b04965ccf83c2bc6e2758abab9bea0c18551a54civoc                               const Config& config) {
619470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    WEBRTC_TRACE(kTraceMemory, kTraceVoice, VoEId(instanceId,channelId),
620470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                 "Channel::CreateChannel(channelId=%d, instanceId=%d)",
621470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        channelId, instanceId);
622470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
623b04965ccf83c2bc6e2758abab9bea0c18551a54civoc    channel = new Channel(channelId, instanceId, event_log, config);
624470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    if (channel == NULL)
625470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
626470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        WEBRTC_TRACE(kTraceMemory, kTraceVoice,
627470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                     VoEId(instanceId,channelId),
628470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                     "Channel::CreateChannel() unable to allocate memory for"
629470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                     " channel");
630470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        return -1;
631470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
632470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    return 0;
633470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com}
634470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
635470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.comvoid
6369213521ea98b0977c7cdabd2853060835af226f3pbos@webrtc.orgChannel::PlayNotification(int32_t id, uint32_t durationMs)
637470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com{
638470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
639470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                 "Channel::PlayNotification(id=%d, durationMs=%d)",
640470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                 id, durationMs);
641470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
642470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    // Not implement yet
643470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com}
644470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
645470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.comvoid
6469213521ea98b0977c7cdabd2853060835af226f3pbos@webrtc.orgChannel::RecordNotification(int32_t id, uint32_t durationMs)
647470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com{
648470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
649470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                 "Channel::RecordNotification(id=%d, durationMs=%d)",
650470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                 id, durationMs);
651470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
652470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    // Not implement yet
653470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com}
654470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
655470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.comvoid
6569213521ea98b0977c7cdabd2853060835af226f3pbos@webrtc.orgChannel::PlayFileEnded(int32_t id)
657470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com{
658470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
659470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                 "Channel::PlayFileEnded(id=%d)", id);
660470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
661470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    if (id == _inputFilePlayerId)
662470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
663944cbeb2926feb86a687e5fda9e2ac88ea8e3001henrika@webrtc.org        channel_state_.SetInputFilePlaying(false);
664470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
665470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                     VoEId(_instanceId,_channelId),
666470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                     "Channel::PlayFileEnded() => input file player module is"
667470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                     " shutdown");
668470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
669470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    else if (id == _outputFilePlayerId)
670470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
671944cbeb2926feb86a687e5fda9e2ac88ea8e3001henrika@webrtc.org        channel_state_.SetOutputFilePlaying(false);
672470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
673470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                     VoEId(_instanceId,_channelId),
674470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                     "Channel::PlayFileEnded() => output file player module is"
675470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                     " shutdown");
676470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
677470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com}
678470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
679470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.comvoid
6809213521ea98b0977c7cdabd2853060835af226f3pbos@webrtc.orgChannel::RecordFileEnded(int32_t id)
681470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com{
682470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
683470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                 "Channel::RecordFileEnded(id=%d)", id);
684470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
685470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    assert(id == _outputFileRecorderId);
686470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
6879a065d1eae9ed296e1e2eaaad73d7ca1223bfe79mflodman@webrtc.org    CriticalSectionScoped cs(&_fileCritSect);
688470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
689470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    _outputFileRecording = false;
690470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
691470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                 VoEId(_instanceId,_channelId),
692470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                 "Channel::RecordFileEnded() => output file recorder module is"
693470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                 " shutdown");
694470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com}
695470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
6969213521ea98b0977c7cdabd2853060835af226f3pbos@webrtc.orgChannel::Channel(int32_t channelId,
697e509f943eded156f7a8365b0b001abe73646acfaminyue@webrtc.org                 uint32_t instanceId,
698b04965ccf83c2bc6e2758abab9bea0c18551a54civoc                 RtcEventLog* const event_log,
699b04965ccf83c2bc6e2758abab9bea0c18551a54civoc                 const Config& config)
700b04965ccf83c2bc6e2758abab9bea0c18551a54civoc  : _fileCritSect(*CriticalSectionWrapper::CreateCriticalSection()),
701470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    _callbackCritSect(*CriticalSectionWrapper::CreateCriticalSection()),
70263420669746cfca6ed1d902c68c656b79ffa5a1bwu@webrtc.org    volume_settings_critsect_(*CriticalSectionWrapper::CreateCriticalSection()),
703470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    _instanceId(instanceId),
70422963abffe4179e75f18a2e7be1d1c58c9518089xians@google.com    _channelId(channelId),
705ae856f2c9fc358e5cd68d8a595136dcef017ed96Ivo Creusen    event_log_(event_log),
706a5cb98cbbd11e93cb6d0a6232387814aac168c7dstefan@webrtc.org    rtp_header_parser_(RtpHeaderParser::Create()),
707822fbd8b68ffdb481b9557e2950ae8d6657c8ce6wu@webrtc.org    rtp_payload_registry_(
708dc80bae2a62a1bdbe0d342b3260a7e5b2cb958dfandresp@webrtc.org        new RTPPayloadRegistry(RTPPayloadStrategy::CreateStrategy(true))),
709b04965ccf83c2bc6e2758abab9bea0c18551a54civoc    rtp_receive_statistics_(
710b04965ccf83c2bc6e2758abab9bea0c18551a54civoc        ReceiveStatistics::Create(Clock::GetRealTimeClock())),
711b04965ccf83c2bc6e2758abab9bea0c18551a54civoc    rtp_receiver_(
712ac547a653862744d0aae560713f8418ad2852085Peter Boström        RtpReceiver::CreateAudioReceiver(Clock::GetRealTimeClock(),
713b04965ccf83c2bc6e2758abab9bea0c18551a54civoc                                         this,
714b04965ccf83c2bc6e2758abab9bea0c18551a54civoc                                         this,
715b04965ccf83c2bc6e2758abab9bea0c18551a54civoc                                         this,
716b04965ccf83c2bc6e2758abab9bea0c18551a54civoc                                         rtp_payload_registry_.get())),
717822fbd8b68ffdb481b9557e2950ae8d6657c8ce6wu@webrtc.org    telephone_event_handler_(rtp_receiver_->GetTelephoneEventHandler()),
718470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    _outputAudioLevel(),
719470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    _externalTransport(false),
720470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    _inputFilePlayerPtr(NULL),
721470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    _outputFilePlayerPtr(NULL),
722470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    _outputFileRecorderPtr(NULL),
723470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    // Avoid conflict with other channels by adding 1024 - 1026,
724470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    // won't use as much as 1024 channels.
725470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    _inputFilePlayerId(VoEModuleId(instanceId, channelId) + 1024),
726470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    _outputFilePlayerId(VoEModuleId(instanceId, channelId) + 1025),
727470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    _outputFileRecorderId(VoEModuleId(instanceId, channelId) + 1026),
728470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    _outputFileRecording(false),
72922963abffe4179e75f18a2e7be1d1c58c9518089xians@google.com    _inbandDtmfQueue(VoEModuleId(instanceId, channelId)),
73022963abffe4179e75f18a2e7be1d1c58c9518089xians@google.com    _inbandDtmfGenerator(VoEModuleId(instanceId, channelId)),
73122963abffe4179e75f18a2e7be1d1c58c9518089xians@google.com    _outputExternalMedia(false),
732470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    _inputExternalMediaCallbackPtr(NULL),
733470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    _outputExternalMediaCallbackPtr(NULL),
734b04965ccf83c2bc6e2758abab9bea0c18551a54civoc    _timeStamp(0),  // This is just an offset, RTP module will add it's own
735b04965ccf83c2bc6e2758abab9bea0c18551a54civoc                    // random offset
73622963abffe4179e75f18a2e7be1d1c58c9518089xians@google.com    _sendTelephoneEventPayloadType(106),
7378e24d8777849951ed86fb01e0bf556d4eda65161stefan@webrtc.org    ntp_estimator_(Clock::GetRealTimeClock()),
738167b6dfc73fc2f4c47713bcbd89b58c52612983bturaj@webrtc.org    jitter_buffer_playout_timestamp_(0),
7391de01354e68da71bc62c81af17afeac8ed374a18pwestin@webrtc.org    playout_timestamp_rtp_(0),
7401de01354e68da71bc62c81af17afeac8ed374a18pwestin@webrtc.org    playout_timestamp_rtcp_(0),
74154ae4ffb9e235a9742e2b11298327e02d870571csprang@webrtc.org    playout_delay_ms_(0),
74222963abffe4179e75f18a2e7be1d1c58c9518089xians@google.com    _numberOfDiscardedPackets(0),
74309e8c47ee5c58e5e86b09dc1950f8d3f9f24cd9fxians@webrtc.org    send_sequence_number_(0),
744cb711f77d2ff9ebd42678869a73353809b3af66ewu@webrtc.org    ts_stats_lock_(CriticalSectionWrapper::CreateCriticalSection()),
74594454b71adc37e15fd3f5a5fc432063f05caabcbwu@webrtc.org    rtp_ts_wraparound_handler_(new rtc::TimestampWrapAroundHandler()),
74694454b71adc37e15fd3f5a5fc432063f05caabcbwu@webrtc.org    capture_start_rtp_time_stamp_(-1),
747cb711f77d2ff9ebd42678869a73353809b3af66ewu@webrtc.org    capture_start_ntp_time_ms_(-1),
74822963abffe4179e75f18a2e7be1d1c58c9518089xians@google.com    _engineStatisticsPtr(NULL),
7492919e95c2a59a087ba8297c2f551c3ebc3754c9ehenrika@webrtc.org    _outputMixerPtr(NULL),
7502919e95c2a59a087ba8297c2f551c3ebc3754c9ehenrika@webrtc.org    _transmitMixerPtr(NULL),
75122963abffe4179e75f18a2e7be1d1c58c9518089xians@google.com    _moduleProcessThreadPtr(NULL),
75222963abffe4179e75f18a2e7be1d1c58c9518089xians@google.com    _audioDeviceModulePtr(NULL),
75322963abffe4179e75f18a2e7be1d1c58c9518089xians@google.com    _voiceEngineObserverPtr(NULL),
75422963abffe4179e75f18a2e7be1d1c58c9518089xians@google.com    _callbackCritSectPtr(NULL),
75522963abffe4179e75f18a2e7be1d1c58c9518089xians@google.com    _transportPtr(NULL),
75622963abffe4179e75f18a2e7be1d1c58c9518089xians@google.com    _rxVadObserverPtr(NULL),
75722963abffe4179e75f18a2e7be1d1c58c9518089xians@google.com    _oldVadDecision(-1),
75822963abffe4179e75f18a2e7be1d1c58c9518089xians@google.com    _sendFrameType(0),
7591b60ceb499ee35460886f2bfaecee1f47319f925roosa@google.com    _externalMixing(false),
76022963abffe4179e75f18a2e7be1d1c58c9518089xians@google.com    _mixFileWithMicrophone(false),
761470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    _mute(false),
762470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    _panLeft(1.0f),
763470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    _panRight(1.0f),
764470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    _outputGain(1.0f),
765470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    _playOutbandDtmfEvent(false),
766470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    _playInbandDtmfEvent(false),
767470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    _lastLocalTimeStamp(0),
768470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    _lastPayloadType(0),
76922963abffe4179e75f18a2e7be1d1c58c9518089xians@google.com    _includeAudioLevelIndication(false),
770470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    _outputSpeechType(AudioFrame::kNormalSpeech),
771743758816853df2040a21c5652b0d0e238b1512fdeadbeef    video_sync_lock_(CriticalSectionWrapper::CreateCriticalSection()),
7721de01354e68da71bc62c81af17afeac8ed374a18pwestin@webrtc.org    _average_jitter_buffer_delay_us(0),
773470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    _previousTimestamp(0),
774470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    _recPacketDelayMs(20),
775470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    _RxVadDetection(false),
776470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    _rxAgcIsEnabled(false),
7777bb8f02274ecbfa1f7ef134d708369a369a78c83stefan@webrtc.org    _rxNsIsEnabled(false),
778c1a40a7b68a8d253b0ba32b89f3126931eeaeab3minyue@webrtc.org    restored_packet_in_use_(false),
7790a7d4eed98ccec0c2b3e7522e7b2dde1919a4ae3mflodman@webrtc.org    rtcp_observer_(new VoERtcpObserver(this)),
7802013aeced2b7821a407f302802c4a16fd02728b1Minyue    network_predictor_(new NetworkPredictor(Clock::GetRealTimeClock())),
7812013aeced2b7821a407f302802c4a16fd02728b1Minyue    assoc_send_channel_lock_(CriticalSectionWrapper::CreateCriticalSection()),
782b04965ccf83c2bc6e2758abab9bea0c18551a54civoc    associate_send_channel_(ChannelOwner(nullptr)) {
783470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    WEBRTC_TRACE(kTraceMemory, kTraceVoice, VoEId(_instanceId,_channelId),
784470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                 "Channel::Channel() - ctor");
78564dad838e61e92e4a72437b153c5eba7a200fb4aHenrik Lundin    AudioCodingModule::Config acm_config;
78664dad838e61e92e4a72437b153c5eba7a200fb4aHenrik Lundin    acm_config.id = VoEModuleId(instanceId, channelId);
78764dad838e61e92e4a72437b153c5eba7a200fb4aHenrik Lundin    if (config.Get<NetEqCapacityConfig>().enabled) {
78864dad838e61e92e4a72437b153c5eba7a200fb4aHenrik Lundin      // Clamping the buffer capacity at 20 packets. While going lower will
78964dad838e61e92e4a72437b153c5eba7a200fb4aHenrik Lundin      // probably work, it makes little sense.
79064dad838e61e92e4a72437b153c5eba7a200fb4aHenrik Lundin      acm_config.neteq_config.max_packets_in_buffer =
79164dad838e61e92e4a72437b153c5eba7a200fb4aHenrik Lundin          std::max(20, config.Get<NetEqCapacityConfig>().capacity);
79264dad838e61e92e4a72437b153c5eba7a200fb4aHenrik Lundin    }
7935263b3c1ddb10ecca58d9f08364aad2d6ba1d95dHenrik Lundin    acm_config.neteq_config.enable_fast_accelerate =
7945263b3c1ddb10ecca58d9f08364aad2d6ba1d95dHenrik Lundin        config.Get<NetEqFastAccelerate>().enabled;
79564dad838e61e92e4a72437b153c5eba7a200fb4aHenrik Lundin    audio_coding_.reset(AudioCodingModule::Create(acm_config));
79664dad838e61e92e4a72437b153c5eba7a200fb4aHenrik Lundin
797470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    _inbandDtmfQueue.ResetDtmf();
798470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    _inbandDtmfGenerator.Init();
799470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    _outputAudioLevel.Clear();
800470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
8012853dde5201d9ddc284ce5efb9688f6340487acepwestin@webrtc.org    RtpRtcp::Configuration configuration;
8022853dde5201d9ddc284ce5efb9688f6340487acepwestin@webrtc.org    configuration.audio = true;
8032853dde5201d9ddc284ce5efb9688f6340487acepwestin@webrtc.org    configuration.outgoing_transport = this;
8042853dde5201d9ddc284ce5efb9688f6340487acepwestin@webrtc.org    configuration.audio_messages = this;
805822fbd8b68ffdb481b9557e2950ae8d6657c8ce6wu@webrtc.org    configuration.receive_statistics = rtp_receive_statistics_.get();
8060a7d4eed98ccec0c2b3e7522e7b2dde1919a4ae3mflodman@webrtc.org    configuration.bandwidth_callback = rtcp_observer_.get();
8072853dde5201d9ddc284ce5efb9688f6340487acepwestin@webrtc.org
8082853dde5201d9ddc284ce5efb9688f6340487acepwestin@webrtc.org    _rtpRtcpModule.reset(RtpRtcp::CreateRtpRtcp(configuration));
80954ae4ffb9e235a9742e2b11298327e02d870571csprang@webrtc.org
81054ae4ffb9e235a9742e2b11298327e02d870571csprang@webrtc.org    statistics_proxy_.reset(new StatisticsProxy(_rtpRtcpModule->SSRC()));
81154ae4ffb9e235a9742e2b11298327e02d870571csprang@webrtc.org    rtp_receive_statistics_->RegisterRtcpStatisticsCallback(
81254ae4ffb9e235a9742e2b11298327e02d870571csprang@webrtc.org        statistics_proxy_.get());
813f927fd64812b4a42a0f4e2686683a43d74b4bf08aluebs@webrtc.org
814f927fd64812b4a42a0f4e2686683a43d74b4bf08aluebs@webrtc.org    Config audioproc_config;
815f927fd64812b4a42a0f4e2686683a43d74b4bf08aluebs@webrtc.org    audioproc_config.Set<ExperimentalAgc>(new ExperimentalAgc(false));
816f927fd64812b4a42a0f4e2686683a43d74b4bf08aluebs@webrtc.org    rx_audioproc_.reset(AudioProcessing::Create(audioproc_config));
817470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com}
818470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
819470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.comChannel::~Channel()
820470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com{
82154ae4ffb9e235a9742e2b11298327e02d870571csprang@webrtc.org    rtp_receive_statistics_->RegisterRtcpStatisticsCallback(NULL);
822470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    WEBRTC_TRACE(kTraceMemory, kTraceVoice, VoEId(_instanceId,_channelId),
823470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                 "Channel::~Channel() - dtor");
824470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
825470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    if (_outputExternalMedia)
826470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
827470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        DeRegisterExternalMediaProcessing(kPlaybackPerChannel);
828470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
829944cbeb2926feb86a687e5fda9e2ac88ea8e3001henrika@webrtc.org    if (channel_state_.Get().input_external_media)
830470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
831470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        DeRegisterExternalMediaProcessing(kRecordingPerChannel);
832470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
833470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    StopSend();
834470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    StopPlayout();
835470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
836470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
8379a065d1eae9ed296e1e2eaaad73d7ca1223bfe79mflodman@webrtc.org        CriticalSectionScoped cs(&_fileCritSect);
838470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        if (_inputFilePlayerPtr)
839470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        {
840470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            _inputFilePlayerPtr->RegisterModuleFileCallback(NULL);
841470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            _inputFilePlayerPtr->StopPlayingFile();
842470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            FilePlayer::DestroyFilePlayer(_inputFilePlayerPtr);
843470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            _inputFilePlayerPtr = NULL;
844470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        }
845470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        if (_outputFilePlayerPtr)
846470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        {
847470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            _outputFilePlayerPtr->RegisterModuleFileCallback(NULL);
848470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            _outputFilePlayerPtr->StopPlayingFile();
849470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            FilePlayer::DestroyFilePlayer(_outputFilePlayerPtr);
850470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            _outputFilePlayerPtr = NULL;
851470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        }
852470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        if (_outputFileRecorderPtr)
853470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        {
854470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            _outputFileRecorderPtr->RegisterModuleFileCallback(NULL);
855470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            _outputFileRecorderPtr->StopRecording();
856470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            FileRecorder::DestroyFileRecorder(_outputFileRecorderPtr);
857470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            _outputFileRecorderPtr = NULL;
858470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        }
859470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
860470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
861470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    // The order to safely shutdown modules in a channel is:
862470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    // 1. De-register callbacks in modules
863470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    // 2. De-register modules in process thread
864470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    // 3. Destroy modules
865eb524d997b877ba9b0bcaf8c85eae52bd40c37e3andrew@webrtc.org    if (audio_coding_->RegisterTransportCallback(NULL) == -1)
866470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
867470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        WEBRTC_TRACE(kTraceWarning, kTraceVoice,
868470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                     VoEId(_instanceId,_channelId),
869470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                     "~Channel() failed to de-register transport callback"
870470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                     " (Audio coding module)");
871470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
872eb524d997b877ba9b0bcaf8c85eae52bd40c37e3andrew@webrtc.org    if (audio_coding_->RegisterVADCallback(NULL) == -1)
873470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
874470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        WEBRTC_TRACE(kTraceWarning, kTraceVoice,
875470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                     VoEId(_instanceId,_channelId),
876470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                     "~Channel() failed to de-register VAD callback"
877470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                     " (Audio coding module)");
878470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
879470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    // De-register modules in process thread
8803985f0151aff9b91418733795a98140079c19a73tommi@webrtc.org    _moduleProcessThreadPtr->DeRegisterModule(_rtpRtcpModule.get());
8813985f0151aff9b91418733795a98140079c19a73tommi@webrtc.org
882470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    // End of modules shutdown
883470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
884470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    // Delete other objects
885470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    delete &_callbackCritSect;
886470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    delete &_fileCritSect;
88763420669746cfca6ed1d902c68c656b79ffa5a1bwu@webrtc.org    delete &volume_settings_critsect_;
888470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com}
889470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
8906141e13873d0fdea626de08dfec2efa2c9171c76pbos@webrtc.orgint32_t
891470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.comChannel::Init()
892470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com{
893470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
894470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                 "Channel::Init()");
895470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
896944cbeb2926feb86a687e5fda9e2ac88ea8e3001henrika@webrtc.org    channel_state_.Reset();
897944cbeb2926feb86a687e5fda9e2ac88ea8e3001henrika@webrtc.org
898470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    // --- Initial sanity
899470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
900470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    if ((_engineStatisticsPtr == NULL) ||
901470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        (_moduleProcessThreadPtr == NULL))
902470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
903470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        WEBRTC_TRACE(kTraceError, kTraceVoice,
904470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                     VoEId(_instanceId,_channelId),
905470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                     "Channel::Init() must call SetEngineInformation() first");
906470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        return -1;
907470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
908470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
909470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    // --- Add modules to process thread (for periodic schedulation)
910470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
9113985f0151aff9b91418733795a98140079c19a73tommi@webrtc.org    _moduleProcessThreadPtr->RegisterModule(_rtpRtcpModule.get());
9123985f0151aff9b91418733795a98140079c19a73tommi@webrtc.org
913c450a1966965fbb3c16ec6d02c3d5cbec67df500pwestin@webrtc.org    // --- ACM initialization
914470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
91545c6449114ab69cab755410f69567fa7e20f8106Henrik Lundin    if ((audio_coding_->InitializeReceiver() == -1)
916470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        // out-of-band Dtmf tones are played out by default
9171f9baab753be55a7c6d31c84a5470fe646936eddkwiberg        || (audio_coding_->SetDtmfPlayoutStatus(true) == -1)) {
918470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        _engineStatisticsPtr->SetLastError(
919470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
920470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            "Channel::Init() unable to initialize the ACM - 1");
921470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        return -1;
922470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
923470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
924470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    // --- RTP/RTCP module initialization
925470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
926470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    // Ensure that RTCP is enabled by default for the created channel.
927470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    // Note that, the module will keep generating RTCP until it is explicitly
928470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    // disabled by the user.
929470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    // After StopListen (when no sockets exists), RTCP packets will no longer
930470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    // be transmitted since the Transport object will then be invalid.
931822fbd8b68ffdb481b9557e2950ae8d6657c8ce6wu@webrtc.org    telephone_event_handler_->SetTelephoneEventForwardToDecoder(true);
932822fbd8b68ffdb481b9557e2950ae8d6657c8ce6wu@webrtc.org    // RTCP is enabled by default.
933d16e839c6d29831e79312180085b6a19149df43fpbos@webrtc.org    _rtpRtcpModule->SetRTCPStatus(kRtcpCompound);
934d16e839c6d29831e79312180085b6a19149df43fpbos@webrtc.org    // --- Register all permanent callbacks
935470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    const bool fail =
936eb524d997b877ba9b0bcaf8c85eae52bd40c37e3andrew@webrtc.org        (audio_coding_->RegisterTransportCallback(this) == -1) ||
937eb524d997b877ba9b0bcaf8c85eae52bd40c37e3andrew@webrtc.org        (audio_coding_->RegisterVADCallback(this) == -1);
938470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
939470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    if (fail)
940470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
941470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        _engineStatisticsPtr->SetLastError(
942470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            VE_CANNOT_INIT_CHANNEL, kTraceError,
943470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            "Channel::Init() callbacks not registered");
944470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        return -1;
945470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
946470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
947470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    // --- Register all supported codecs to the receiving side of the
948470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    // RTP/RTCP module
949470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
950470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    CodecInst codec;
9516141e13873d0fdea626de08dfec2efa2c9171c76pbos@webrtc.org    const uint8_t nSupportedCodecs = AudioCodingModule::NumberOfCodecs();
952470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
953470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    for (int idx = 0; idx < nSupportedCodecs; idx++)
954470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
955470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        // Open up the RTP/RTCP receiver for all supported codecs
956eb524d997b877ba9b0bcaf8c85eae52bd40c37e3andrew@webrtc.org        if ((audio_coding_->Codec(idx, &codec) == -1) ||
957822fbd8b68ffdb481b9557e2950ae8d6657c8ce6wu@webrtc.org            (rtp_receiver_->RegisterReceivePayload(
958822fbd8b68ffdb481b9557e2950ae8d6657c8ce6wu@webrtc.org                codec.plname,
959822fbd8b68ffdb481b9557e2950ae8d6657c8ce6wu@webrtc.org                codec.pltype,
960822fbd8b68ffdb481b9557e2950ae8d6657c8ce6wu@webrtc.org                codec.plfreq,
961822fbd8b68ffdb481b9557e2950ae8d6657c8ce6wu@webrtc.org                codec.channels,
962822fbd8b68ffdb481b9557e2950ae8d6657c8ce6wu@webrtc.org                (codec.rate < 0) ? 0 : codec.rate) == -1))
963470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        {
964470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            WEBRTC_TRACE(kTraceWarning, kTraceVoice,
965470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                         VoEId(_instanceId,_channelId),
966470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                         "Channel::Init() unable to register %s (%d/%d/%d/%d) "
967470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                         "to RTP/RTCP receiver",
968470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                         codec.plname, codec.pltype, codec.plfreq,
969470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                         codec.channels, codec.rate);
970470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        }
971470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        else
972470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        {
973470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            WEBRTC_TRACE(kTraceInfo, kTraceVoice,
974470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                         VoEId(_instanceId,_channelId),
975470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                         "Channel::Init() %s (%d/%d/%d/%d) has been added to "
976470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                         "the RTP/RTCP receiver",
977470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                         codec.plname, codec.pltype, codec.plfreq,
978470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                         codec.channels, codec.rate);
979470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        }
980470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
981470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        // Ensure that PCMU is used as default codec on the sending side
9824517585db5f2f2a14fdd56a96f4b44f745967c8ctina.legrand@webrtc.org        if (!STR_CASE_CMP(codec.plname, "PCMU") && (codec.channels == 1))
983470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        {
984470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            SetSendCodec(codec);
985470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        }
986470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
987470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        // Register default PT for outband 'telephone-event'
988470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        if (!STR_CASE_CMP(codec.plname, "telephone-event"))
989470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        {
9902853dde5201d9ddc284ce5efb9688f6340487acepwestin@webrtc.org            if ((_rtpRtcpModule->RegisterSendPayload(codec) == -1) ||
991eb524d997b877ba9b0bcaf8c85eae52bd40c37e3andrew@webrtc.org                (audio_coding_->RegisterReceiveCodec(codec) == -1))
992470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            {
993470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                WEBRTC_TRACE(kTraceWarning, kTraceVoice,
994470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                             VoEId(_instanceId,_channelId),
995470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                             "Channel::Init() failed to register outband "
996470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                             "'telephone-event' (%d/%d) correctly",
997470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                             codec.pltype, codec.plfreq);
998470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            }
999470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        }
1000470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
1001470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        if (!STR_CASE_CMP(codec.plname, "CN"))
1002470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        {
1003eb524d997b877ba9b0bcaf8c85eae52bd40c37e3andrew@webrtc.org            if ((audio_coding_->RegisterSendCodec(codec) == -1) ||
1004eb524d997b877ba9b0bcaf8c85eae52bd40c37e3andrew@webrtc.org                (audio_coding_->RegisterReceiveCodec(codec) == -1) ||
10052853dde5201d9ddc284ce5efb9688f6340487acepwestin@webrtc.org                (_rtpRtcpModule->RegisterSendPayload(codec) == -1))
1006470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            {
1007470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                WEBRTC_TRACE(kTraceWarning, kTraceVoice,
1008470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                             VoEId(_instanceId,_channelId),
1009470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                             "Channel::Init() failed to register CN (%d/%d) "
1010470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                             "correctly - 1",
1011470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                             codec.pltype, codec.plfreq);
1012470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            }
1013470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        }
1014470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com#ifdef WEBRTC_CODEC_RED
1015470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        // Register RED to the receiving side of the ACM.
1016470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        // We will not receive an OnInitializeDecoder() callback for RED.
1017470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        if (!STR_CASE_CMP(codec.plname, "RED"))
1018470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        {
1019eb524d997b877ba9b0bcaf8c85eae52bd40c37e3andrew@webrtc.org            if (audio_coding_->RegisterReceiveCodec(codec) == -1)
1020470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            {
1021470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                WEBRTC_TRACE(kTraceWarning, kTraceVoice,
1022470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                             VoEId(_instanceId,_channelId),
1023470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                             "Channel::Init() failed to register RED (%d/%d) "
1024470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                             "correctly",
1025470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                             codec.pltype, codec.plfreq);
1026470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            }
1027470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        }
1028470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com#endif
1029470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
1030684f0577fbe4ea393fef1dddf2ca7d02e3205b49pwestin@webrtc.org
10316c264cc92eb554716814db200b84752d4dfb6ba3andrew@webrtc.org    if (rx_audioproc_->noise_suppression()->set_level(kDefaultNsMode) != 0) {
10326c264cc92eb554716814db200b84752d4dfb6ba3andrew@webrtc.org      LOG_FERR1(LS_ERROR, noise_suppression()->set_level, kDefaultNsMode);
10336c264cc92eb554716814db200b84752d4dfb6ba3andrew@webrtc.org      return -1;
1034470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
10356c264cc92eb554716814db200b84752d4dfb6ba3andrew@webrtc.org    if (rx_audioproc_->gain_control()->set_mode(kDefaultRxAgcMode) != 0) {
10366c264cc92eb554716814db200b84752d4dfb6ba3andrew@webrtc.org      LOG_FERR1(LS_ERROR, gain_control()->set_mode, kDefaultRxAgcMode);
10376c264cc92eb554716814db200b84752d4dfb6ba3andrew@webrtc.org      return -1;
1038470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
1039470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
1040470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    return 0;
1041470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com}
1042470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
10436141e13873d0fdea626de08dfec2efa2c9171c76pbos@webrtc.orgint32_t
1044470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.comChannel::SetEngineInformation(Statistics& engineStatistics,
1045470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                              OutputMixer& outputMixer,
1046470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                              voe::TransmitMixer& transmitMixer,
1047470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                              ProcessThread& moduleProcessThread,
1048470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                              AudioDeviceModule& audioDeviceModule,
1049470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                              VoiceEngineObserver* voiceEngineObserver,
1050470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                              CriticalSectionWrapper* callbackCritSect)
1051470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com{
1052470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1053470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                 "Channel::SetEngineInformation()");
1054470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    _engineStatisticsPtr = &engineStatistics;
1055470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    _outputMixerPtr = &outputMixer;
1056470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    _transmitMixerPtr = &transmitMixer,
1057470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    _moduleProcessThreadPtr = &moduleProcessThread;
1058470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    _audioDeviceModulePtr = &audioDeviceModule;
1059470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    _voiceEngineObserverPtr = voiceEngineObserver;
1060470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    _callbackCritSectPtr = callbackCritSect;
1061470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    return 0;
1062470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com}
1063470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
10646141e13873d0fdea626de08dfec2efa2c9171c76pbos@webrtc.orgint32_t
1065470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.comChannel::UpdateLocalTimeStamp()
1066470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com{
1067470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
1068b7e5054414ff524f9db81dab7917729b8c4c8bcbPeter Kasting    _timeStamp += static_cast<uint32_t>(_audioFrame.samples_per_channel_);
1069470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    return 0;
1070470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com}
1071470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
10726141e13873d0fdea626de08dfec2efa2c9171c76pbos@webrtc.orgint32_t
1073470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.comChannel::StartPlayout()
1074470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com{
1075470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1076470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                 "Channel::StartPlayout()");
1077944cbeb2926feb86a687e5fda9e2ac88ea8e3001henrika@webrtc.org    if (channel_state_.Get().playing)
1078470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
1079470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        return 0;
1080470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
10811b60ceb499ee35460886f2bfaecee1f47319f925roosa@google.com
10821b60ceb499ee35460886f2bfaecee1f47319f925roosa@google.com    if (!_externalMixing) {
10831b60ceb499ee35460886f2bfaecee1f47319f925roosa@google.com        // Add participant as candidates for mixing.
10841b60ceb499ee35460886f2bfaecee1f47319f925roosa@google.com        if (_outputMixerPtr->SetMixabilityStatus(*this, true) != 0)
10851b60ceb499ee35460886f2bfaecee1f47319f925roosa@google.com        {
10861b60ceb499ee35460886f2bfaecee1f47319f925roosa@google.com            _engineStatisticsPtr->SetLastError(
10871b60ceb499ee35460886f2bfaecee1f47319f925roosa@google.com                VE_AUDIO_CONF_MIX_MODULE_ERROR, kTraceError,
10881b60ceb499ee35460886f2bfaecee1f47319f925roosa@google.com                "StartPlayout() failed to add participant to mixer");
10891b60ceb499ee35460886f2bfaecee1f47319f925roosa@google.com            return -1;
10901b60ceb499ee35460886f2bfaecee1f47319f925roosa@google.com        }
1091470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
1092470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
1093944cbeb2926feb86a687e5fda9e2ac88ea8e3001henrika@webrtc.org    channel_state_.SetPlaying(true);
1094ab12990b1b8c2410b34c055e73ed04e8a7ee1d85braveyao@webrtc.org    if (RegisterFilePlayingToMixer() != 0)
1095ab12990b1b8c2410b34c055e73ed04e8a7ee1d85braveyao@webrtc.org        return -1;
1096ab12990b1b8c2410b34c055e73ed04e8a7ee1d85braveyao@webrtc.org
1097470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    return 0;
1098470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com}
1099470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
11006141e13873d0fdea626de08dfec2efa2c9171c76pbos@webrtc.orgint32_t
1101470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.comChannel::StopPlayout()
1102470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com{
1103470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1104470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                 "Channel::StopPlayout()");
1105944cbeb2926feb86a687e5fda9e2ac88ea8e3001henrika@webrtc.org    if (!channel_state_.Get().playing)
1106470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
1107470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        return 0;
1108470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
11091b60ceb499ee35460886f2bfaecee1f47319f925roosa@google.com
11101b60ceb499ee35460886f2bfaecee1f47319f925roosa@google.com    if (!_externalMixing) {
11111b60ceb499ee35460886f2bfaecee1f47319f925roosa@google.com        // Remove participant as candidates for mixing
11121b60ceb499ee35460886f2bfaecee1f47319f925roosa@google.com        if (_outputMixerPtr->SetMixabilityStatus(*this, false) != 0)
11131b60ceb499ee35460886f2bfaecee1f47319f925roosa@google.com        {
11141b60ceb499ee35460886f2bfaecee1f47319f925roosa@google.com            _engineStatisticsPtr->SetLastError(
11151b60ceb499ee35460886f2bfaecee1f47319f925roosa@google.com                VE_AUDIO_CONF_MIX_MODULE_ERROR, kTraceError,
11161b60ceb499ee35460886f2bfaecee1f47319f925roosa@google.com                "StopPlayout() failed to remove participant from mixer");
11171b60ceb499ee35460886f2bfaecee1f47319f925roosa@google.com            return -1;
11181b60ceb499ee35460886f2bfaecee1f47319f925roosa@google.com        }
1119470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
1120470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
1121944cbeb2926feb86a687e5fda9e2ac88ea8e3001henrika@webrtc.org    channel_state_.SetPlaying(false);
1122470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    _outputAudioLevel.Clear();
1123470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
1124470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    return 0;
1125470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com}
1126470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
11276141e13873d0fdea626de08dfec2efa2c9171c76pbos@webrtc.orgint32_t
1128470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.comChannel::StartSend()
1129470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com{
1130470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1131470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                 "Channel::StartSend()");
113209e8c47ee5c58e5e86b09dc1950f8d3f9f24cd9fxians@webrtc.org    // Resume the previous sequence number which was reset by StopSend().
1133944cbeb2926feb86a687e5fda9e2ac88ea8e3001henrika@webrtc.org    // This needs to be done before |sending| is set to true.
113409e8c47ee5c58e5e86b09dc1950f8d3f9f24cd9fxians@webrtc.org    if (send_sequence_number_)
113509e8c47ee5c58e5e86b09dc1950f8d3f9f24cd9fxians@webrtc.org      SetInitSequenceNumber(send_sequence_number_);
113609e8c47ee5c58e5e86b09dc1950f8d3f9f24cd9fxians@webrtc.org
1137944cbeb2926feb86a687e5fda9e2ac88ea8e3001henrika@webrtc.org    if (channel_state_.Get().sending)
1138470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
1139944cbeb2926feb86a687e5fda9e2ac88ea8e3001henrika@webrtc.org      return 0;
1140470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
1141944cbeb2926feb86a687e5fda9e2ac88ea8e3001henrika@webrtc.org    channel_state_.SetSending(true);
1142e07247af8d0888529e14156a9929cbd2376f8442xians@webrtc.org
11432853dde5201d9ddc284ce5efb9688f6340487acepwestin@webrtc.org    if (_rtpRtcpModule->SetSendingStatus(true) != 0)
1144470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
1145470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        _engineStatisticsPtr->SetLastError(
1146470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            VE_RTP_RTCP_MODULE_ERROR, kTraceError,
1147470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            "StartSend() RTP/RTCP failed to start sending");
11489a065d1eae9ed296e1e2eaaad73d7ca1223bfe79mflodman@webrtc.org        CriticalSectionScoped cs(&_callbackCritSect);
1149944cbeb2926feb86a687e5fda9e2ac88ea8e3001henrika@webrtc.org        channel_state_.SetSending(false);
1150470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        return -1;
1151470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
1152e07247af8d0888529e14156a9929cbd2376f8442xians@webrtc.org
1153470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    return 0;
1154470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com}
1155470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
11566141e13873d0fdea626de08dfec2efa2c9171c76pbos@webrtc.orgint32_t
1157470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.comChannel::StopSend()
1158470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com{
1159470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1160470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                 "Channel::StopSend()");
1161944cbeb2926feb86a687e5fda9e2ac88ea8e3001henrika@webrtc.org    if (!channel_state_.Get().sending)
1162470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
1163944cbeb2926feb86a687e5fda9e2ac88ea8e3001henrika@webrtc.org      return 0;
1164470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
1165944cbeb2926feb86a687e5fda9e2ac88ea8e3001henrika@webrtc.org    channel_state_.SetSending(false);
1166e07247af8d0888529e14156a9929cbd2376f8442xians@webrtc.org
116709e8c47ee5c58e5e86b09dc1950f8d3f9f24cd9fxians@webrtc.org    // Store the sequence number to be able to pick up the same sequence for
116809e8c47ee5c58e5e86b09dc1950f8d3f9f24cd9fxians@webrtc.org    // the next StartSend(). This is needed for restarting device, otherwise
116909e8c47ee5c58e5e86b09dc1950f8d3f9f24cd9fxians@webrtc.org    // it might cause libSRTP to complain about packets being replayed.
117009e8c47ee5c58e5e86b09dc1950f8d3f9f24cd9fxians@webrtc.org    // TODO(xians): Remove this workaround after RtpRtcpModule's refactoring
117109e8c47ee5c58e5e86b09dc1950f8d3f9f24cd9fxians@webrtc.org    // CL is landed. See issue
117209e8c47ee5c58e5e86b09dc1950f8d3f9f24cd9fxians@webrtc.org    // https://code.google.com/p/webrtc/issues/detail?id=2111 .
117309e8c47ee5c58e5e86b09dc1950f8d3f9f24cd9fxians@webrtc.org    send_sequence_number_ = _rtpRtcpModule->SequenceNumber();
117409e8c47ee5c58e5e86b09dc1950f8d3f9f24cd9fxians@webrtc.org
1175470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    // Reset sending SSRC and sequence number and triggers direct transmission
1176470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    // of RTCP BYE
1177d436298332c7a7ecb51241f3a66588539c2ece83pbos    if (_rtpRtcpModule->SetSendingStatus(false) == -1)
1178470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
1179470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        _engineStatisticsPtr->SetLastError(
1180470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            VE_RTP_RTCP_MODULE_ERROR, kTraceWarning,
1181470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            "StartSend() RTP/RTCP failed to stop sending");
1182470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
1183470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
1184470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    return 0;
1185470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com}
1186470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
11876141e13873d0fdea626de08dfec2efa2c9171c76pbos@webrtc.orgint32_t
1188470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.comChannel::StartReceiving()
1189470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com{
1190470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1191470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                 "Channel::StartReceiving()");
1192944cbeb2926feb86a687e5fda9e2ac88ea8e3001henrika@webrtc.org    if (channel_state_.Get().receiving)
1193470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
1194470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        return 0;
1195470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
1196944cbeb2926feb86a687e5fda9e2ac88ea8e3001henrika@webrtc.org    channel_state_.SetReceiving(true);
1197470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    _numberOfDiscardedPackets = 0;
1198470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    return 0;
1199470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com}
1200470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
12016141e13873d0fdea626de08dfec2efa2c9171c76pbos@webrtc.orgint32_t
1202470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.comChannel::StopReceiving()
1203470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com{
1204470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1205470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                 "Channel::StopReceiving()");
1206944cbeb2926feb86a687e5fda9e2ac88ea8e3001henrika@webrtc.org    if (!channel_state_.Get().receiving)
1207470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
1208470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        return 0;
1209470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
1210684f0577fbe4ea393fef1dddf2ca7d02e3205b49pwestin@webrtc.org
1211944cbeb2926feb86a687e5fda9e2ac88ea8e3001henrika@webrtc.org    channel_state_.SetReceiving(false);
1212470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    return 0;
1213470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com}
1214470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
12156141e13873d0fdea626de08dfec2efa2c9171c76pbos@webrtc.orgint32_t
1216470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.comChannel::RegisterVoiceEngineObserver(VoiceEngineObserver& observer)
1217470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com{
1218470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1219470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                 "Channel::RegisterVoiceEngineObserver()");
12209a065d1eae9ed296e1e2eaaad73d7ca1223bfe79mflodman@webrtc.org    CriticalSectionScoped cs(&_callbackCritSect);
1221470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
1222470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    if (_voiceEngineObserverPtr)
1223470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
1224470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        _engineStatisticsPtr->SetLastError(
1225470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            VE_INVALID_OPERATION, kTraceError,
1226470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            "RegisterVoiceEngineObserver() observer already enabled");
1227470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        return -1;
1228470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
1229470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    _voiceEngineObserverPtr = &observer;
1230470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    return 0;
1231470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com}
1232470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
12336141e13873d0fdea626de08dfec2efa2c9171c76pbos@webrtc.orgint32_t
1234470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.comChannel::DeRegisterVoiceEngineObserver()
1235470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com{
1236470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1237470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                 "Channel::DeRegisterVoiceEngineObserver()");
12389a065d1eae9ed296e1e2eaaad73d7ca1223bfe79mflodman@webrtc.org    CriticalSectionScoped cs(&_callbackCritSect);
1239470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
1240470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    if (!_voiceEngineObserverPtr)
1241470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
1242470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        _engineStatisticsPtr->SetLastError(
1243470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            VE_INVALID_OPERATION, kTraceWarning,
1244470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            "DeRegisterVoiceEngineObserver() observer already disabled");
1245470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        return 0;
1246470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
1247470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    _voiceEngineObserverPtr = NULL;
1248470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    return 0;
1249470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com}
1250470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
12516141e13873d0fdea626de08dfec2efa2c9171c76pbos@webrtc.orgint32_t
1252470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.comChannel::GetSendCodec(CodecInst& codec)
1253470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com{
1254eb524d997b877ba9b0bcaf8c85eae52bd40c37e3andrew@webrtc.org    return (audio_coding_->SendCodec(&codec));
1255470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com}
1256470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
12576141e13873d0fdea626de08dfec2efa2c9171c76pbos@webrtc.orgint32_t
1258470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.comChannel::GetRecCodec(CodecInst& codec)
1259470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com{
1260eb524d997b877ba9b0bcaf8c85eae52bd40c37e3andrew@webrtc.org    return (audio_coding_->ReceiveCodec(&codec));
1261470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com}
1262470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
12636141e13873d0fdea626de08dfec2efa2c9171c76pbos@webrtc.orgint32_t
1264470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.comChannel::SetSendCodec(const CodecInst& codec)
1265470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com{
1266470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1267470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                 "Channel::SetSendCodec()");
1268470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
1269eb524d997b877ba9b0bcaf8c85eae52bd40c37e3andrew@webrtc.org    if (audio_coding_->RegisterSendCodec(codec) != 0)
1270470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
1271470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        WEBRTC_TRACE(kTraceError, kTraceVoice, VoEId(_instanceId,_channelId),
1272470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                     "SetSendCodec() failed to register codec to ACM");
1273470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        return -1;
1274470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
1275470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
12762853dde5201d9ddc284ce5efb9688f6340487acepwestin@webrtc.org    if (_rtpRtcpModule->RegisterSendPayload(codec) != 0)
1277470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
12782853dde5201d9ddc284ce5efb9688f6340487acepwestin@webrtc.org        _rtpRtcpModule->DeRegisterSendPayload(codec.pltype);
12792853dde5201d9ddc284ce5efb9688f6340487acepwestin@webrtc.org        if (_rtpRtcpModule->RegisterSendPayload(codec) != 0)
1280470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        {
1281470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            WEBRTC_TRACE(
1282470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                    kTraceError, kTraceVoice, VoEId(_instanceId,_channelId),
1283470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                    "SetSendCodec() failed to register codec to"
1284470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                    " RTP/RTCP module");
1285470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            return -1;
1286470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        }
1287470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
1288470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
12892853dde5201d9ddc284ce5efb9688f6340487acepwestin@webrtc.org    if (_rtpRtcpModule->SetAudioPacketSize(codec.pacsize) != 0)
1290470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
1291470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        WEBRTC_TRACE(kTraceError, kTraceVoice, VoEId(_instanceId,_channelId),
1292470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                     "SetSendCodec() failed to set audio packet size");
1293470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        return -1;
1294470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
1295470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
1296470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    return 0;
1297470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com}
1298470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
1299adf89b7e33cc54dab9365dddead687a46a074cf0Ivo Creusenvoid Channel::SetBitRate(int bitrate_bps) {
1300adf89b7e33cc54dab9365dddead687a46a074cf0Ivo Creusen  WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
1301adf89b7e33cc54dab9365dddead687a46a074cf0Ivo Creusen               "Channel::SetBitRate(bitrate_bps=%d)", bitrate_bps);
1302adf89b7e33cc54dab9365dddead687a46a074cf0Ivo Creusen  audio_coding_->SetBitRate(bitrate_bps);
1303adf89b7e33cc54dab9365dddead687a46a074cf0Ivo Creusen}
1304adf89b7e33cc54dab9365dddead687a46a074cf0Ivo Creusen
13050a7d4eed98ccec0c2b3e7522e7b2dde1919a4ae3mflodman@webrtc.orgvoid Channel::OnIncomingFractionLoss(int fraction_lost) {
130674aaf29a0ff1b211dbfdbb6309791111a7871779minyue@webrtc.org  network_predictor_->UpdatePacketLossRate(fraction_lost);
13070a7d4eed98ccec0c2b3e7522e7b2dde1919a4ae3mflodman@webrtc.org  uint8_t average_fraction_loss = network_predictor_->GetLossRate();
13080a7d4eed98ccec0c2b3e7522e7b2dde1919a4ae3mflodman@webrtc.org
1309c1a40a7b68a8d253b0ba32b89f3126931eeaeab3minyue@webrtc.org  // Normalizes rate to 0 - 100.
13100a7d4eed98ccec0c2b3e7522e7b2dde1919a4ae3mflodman@webrtc.org  if (audio_coding_->SetPacketLossRate(
13110a7d4eed98ccec0c2b3e7522e7b2dde1919a4ae3mflodman@webrtc.org      100 * average_fraction_loss / 255) != 0) {
1312c1a40a7b68a8d253b0ba32b89f3126931eeaeab3minyue@webrtc.org    assert(false);  // This should not happen.
1313c1a40a7b68a8d253b0ba32b89f3126931eeaeab3minyue@webrtc.org  }
1314c1a40a7b68a8d253b0ba32b89f3126931eeaeab3minyue@webrtc.org}
1315c1a40a7b68a8d253b0ba32b89f3126931eeaeab3minyue@webrtc.org
13166141e13873d0fdea626de08dfec2efa2c9171c76pbos@webrtc.orgint32_t
1317470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.comChannel::SetVADStatus(bool enableVAD, ACMVADMode mode, bool disableDTX)
1318470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com{
1319470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1320470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                 "Channel::SetVADStatus(mode=%d)", mode);
1321664ccb7d8da3adfffdb7c56f885b633224555e6ehenrik.lundin@webrtc.org    assert(!(disableDTX && enableVAD));  // disableDTX mode is deprecated.
1322470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    // To disable VAD, DTX must be disabled too
1323470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    disableDTX = ((enableVAD == false) ? true : disableDTX);
1324eb524d997b877ba9b0bcaf8c85eae52bd40c37e3andrew@webrtc.org    if (audio_coding_->SetVAD(!disableDTX, enableVAD, mode) != 0)
1325470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
1326470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        _engineStatisticsPtr->SetLastError(
1327470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
1328470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            "SetVADStatus() failed to set VAD");
1329470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        return -1;
1330470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
1331470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    return 0;
1332470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com}
1333470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
13346141e13873d0fdea626de08dfec2efa2c9171c76pbos@webrtc.orgint32_t
1335470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.comChannel::GetVADStatus(bool& enabledVAD, ACMVADMode& mode, bool& disabledDTX)
1336470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com{
1337470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1338470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                 "Channel::GetVADStatus");
1339eb524d997b877ba9b0bcaf8c85eae52bd40c37e3andrew@webrtc.org    if (audio_coding_->VAD(&disabledDTX, &enabledVAD, &mode) != 0)
1340470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
1341470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        _engineStatisticsPtr->SetLastError(
1342470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
1343470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            "GetVADStatus() failed to get VAD status");
1344470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        return -1;
1345470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
1346470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    disabledDTX = !disabledDTX;
1347470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    return 0;
1348470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com}
1349470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
13506141e13873d0fdea626de08dfec2efa2c9171c76pbos@webrtc.orgint32_t
1351470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.comChannel::SetRecPayloadType(const CodecInst& codec)
1352470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com{
1353470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1354470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                 "Channel::SetRecPayloadType()");
1355470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
1356944cbeb2926feb86a687e5fda9e2ac88ea8e3001henrika@webrtc.org    if (channel_state_.Get().playing)
1357470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
1358470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        _engineStatisticsPtr->SetLastError(
1359470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            VE_ALREADY_PLAYING, kTraceError,
1360470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            "SetRecPayloadType() unable to set PT while playing");
1361470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        return -1;
1362470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
1363944cbeb2926feb86a687e5fda9e2ac88ea8e3001henrika@webrtc.org    if (channel_state_.Get().receiving)
1364470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
1365470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        _engineStatisticsPtr->SetLastError(
1366470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            VE_ALREADY_LISTENING, kTraceError,
1367470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            "SetRecPayloadType() unable to set PT while listening");
1368470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        return -1;
1369470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
1370470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
1371470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    if (codec.pltype == -1)
1372470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
1373470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        // De-register the selected codec (RTP/RTCP module and ACM)
1374470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
13756141e13873d0fdea626de08dfec2efa2c9171c76pbos@webrtc.org        int8_t pltype(-1);
1376470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        CodecInst rxCodec = codec;
1377470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
1378470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        // Get payload type for the given codec
1379822fbd8b68ffdb481b9557e2950ae8d6657c8ce6wu@webrtc.org        rtp_payload_registry_->ReceivePayloadType(
1380822fbd8b68ffdb481b9557e2950ae8d6657c8ce6wu@webrtc.org            rxCodec.plname,
1381822fbd8b68ffdb481b9557e2950ae8d6657c8ce6wu@webrtc.org            rxCodec.plfreq,
1382822fbd8b68ffdb481b9557e2950ae8d6657c8ce6wu@webrtc.org            rxCodec.channels,
1383822fbd8b68ffdb481b9557e2950ae8d6657c8ce6wu@webrtc.org            (rxCodec.rate < 0) ? 0 : rxCodec.rate,
1384822fbd8b68ffdb481b9557e2950ae8d6657c8ce6wu@webrtc.org            &pltype);
1385470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        rxCodec.pltype = pltype;
1386470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
1387822fbd8b68ffdb481b9557e2950ae8d6657c8ce6wu@webrtc.org        if (rtp_receiver_->DeRegisterReceivePayload(pltype) != 0)
1388470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        {
1389470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            _engineStatisticsPtr->SetLastError(
1390470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                    VE_RTP_RTCP_MODULE_ERROR,
1391470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                    kTraceError,
1392470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                    "SetRecPayloadType() RTP/RTCP-module deregistration "
1393470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                    "failed");
1394470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            return -1;
1395470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        }
1396eb524d997b877ba9b0bcaf8c85eae52bd40c37e3andrew@webrtc.org        if (audio_coding_->UnregisterReceiveCodec(rxCodec.pltype) != 0)
1397470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        {
1398470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            _engineStatisticsPtr->SetLastError(
1399470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
1400470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                "SetRecPayloadType() ACM deregistration failed - 1");
1401470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            return -1;
1402470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        }
1403470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        return 0;
1404470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
1405470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
1406822fbd8b68ffdb481b9557e2950ae8d6657c8ce6wu@webrtc.org    if (rtp_receiver_->RegisterReceivePayload(
1407822fbd8b68ffdb481b9557e2950ae8d6657c8ce6wu@webrtc.org        codec.plname,
1408822fbd8b68ffdb481b9557e2950ae8d6657c8ce6wu@webrtc.org        codec.pltype,
1409822fbd8b68ffdb481b9557e2950ae8d6657c8ce6wu@webrtc.org        codec.plfreq,
1410822fbd8b68ffdb481b9557e2950ae8d6657c8ce6wu@webrtc.org        codec.channels,
1411822fbd8b68ffdb481b9557e2950ae8d6657c8ce6wu@webrtc.org        (codec.rate < 0) ? 0 : codec.rate) != 0)
1412470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
1413470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        // First attempt to register failed => de-register and try again
1414822fbd8b68ffdb481b9557e2950ae8d6657c8ce6wu@webrtc.org        rtp_receiver_->DeRegisterReceivePayload(codec.pltype);
1415822fbd8b68ffdb481b9557e2950ae8d6657c8ce6wu@webrtc.org        if (rtp_receiver_->RegisterReceivePayload(
1416822fbd8b68ffdb481b9557e2950ae8d6657c8ce6wu@webrtc.org            codec.plname,
1417822fbd8b68ffdb481b9557e2950ae8d6657c8ce6wu@webrtc.org            codec.pltype,
1418822fbd8b68ffdb481b9557e2950ae8d6657c8ce6wu@webrtc.org            codec.plfreq,
1419822fbd8b68ffdb481b9557e2950ae8d6657c8ce6wu@webrtc.org            codec.channels,
1420822fbd8b68ffdb481b9557e2950ae8d6657c8ce6wu@webrtc.org            (codec.rate < 0) ? 0 : codec.rate) != 0)
1421470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        {
1422470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            _engineStatisticsPtr->SetLastError(
1423470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                VE_RTP_RTCP_MODULE_ERROR, kTraceError,
1424470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                "SetRecPayloadType() RTP/RTCP-module registration failed");
1425470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            return -1;
1426470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        }
1427470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
1428eb524d997b877ba9b0bcaf8c85eae52bd40c37e3andrew@webrtc.org    if (audio_coding_->RegisterReceiveCodec(codec) != 0)
1429470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
1430eb524d997b877ba9b0bcaf8c85eae52bd40c37e3andrew@webrtc.org        audio_coding_->UnregisterReceiveCodec(codec.pltype);
1431eb524d997b877ba9b0bcaf8c85eae52bd40c37e3andrew@webrtc.org        if (audio_coding_->RegisterReceiveCodec(codec) != 0)
1432470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        {
1433470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            _engineStatisticsPtr->SetLastError(
1434470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
1435470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                "SetRecPayloadType() ACM registration failed - 1");
1436470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            return -1;
1437470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        }
1438470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
1439470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    return 0;
1440470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com}
1441470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
14426141e13873d0fdea626de08dfec2efa2c9171c76pbos@webrtc.orgint32_t
1443470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.comChannel::GetRecPayloadType(CodecInst& codec)
1444470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com{
1445470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1446470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                 "Channel::GetRecPayloadType()");
14476141e13873d0fdea626de08dfec2efa2c9171c76pbos@webrtc.org    int8_t payloadType(-1);
1448822fbd8b68ffdb481b9557e2950ae8d6657c8ce6wu@webrtc.org    if (rtp_payload_registry_->ReceivePayloadType(
1449822fbd8b68ffdb481b9557e2950ae8d6657c8ce6wu@webrtc.org        codec.plname,
1450822fbd8b68ffdb481b9557e2950ae8d6657c8ce6wu@webrtc.org        codec.plfreq,
1451822fbd8b68ffdb481b9557e2950ae8d6657c8ce6wu@webrtc.org        codec.channels,
1452822fbd8b68ffdb481b9557e2950ae8d6657c8ce6wu@webrtc.org        (codec.rate < 0) ? 0 : codec.rate,
1453822fbd8b68ffdb481b9557e2950ae8d6657c8ce6wu@webrtc.org        &payloadType) != 0)
1454470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
1455470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        _engineStatisticsPtr->SetLastError(
145637198007eab6731fa0f77866155dd4f2b332a262henrika@webrtc.org            VE_RTP_RTCP_MODULE_ERROR, kTraceWarning,
1457470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            "GetRecPayloadType() failed to retrieve RX payload type");
1458470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        return -1;
1459470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
1460470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    codec.pltype = payloadType;
1461470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    WEBRTC_TRACE(kTraceStateInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1462d324546ced76d4e792338af4f7d02a5cd8819f92pkasting@chromium.org                 "Channel::GetRecPayloadType() => pltype=%d", codec.pltype);
1463470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    return 0;
1464470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com}
1465470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
14666141e13873d0fdea626de08dfec2efa2c9171c76pbos@webrtc.orgint32_t
1467470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.comChannel::SetSendCNPayloadType(int type, PayloadFrequencies frequency)
1468470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com{
1469470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1470470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                 "Channel::SetSendCNPayloadType()");
1471470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
1472470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    CodecInst codec;
14736141e13873d0fdea626de08dfec2efa2c9171c76pbos@webrtc.org    int32_t samplingFreqHz(-1);
14744517585db5f2f2a14fdd56a96f4b44f745967c8ctina.legrand@webrtc.org    const int kMono = 1;
1475470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    if (frequency == kFreq32000Hz)
1476470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        samplingFreqHz = 32000;
1477470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    else if (frequency == kFreq16000Hz)
1478470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        samplingFreqHz = 16000;
1479470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
1480eb524d997b877ba9b0bcaf8c85eae52bd40c37e3andrew@webrtc.org    if (audio_coding_->Codec("CN", &codec, samplingFreqHz, kMono) == -1)
1481470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
1482470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        _engineStatisticsPtr->SetLastError(
1483470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
1484470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            "SetSendCNPayloadType() failed to retrieve default CN codec "
1485470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            "settings");
1486470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        return -1;
1487470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
1488470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
1489470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    // Modify the payload type (must be set to dynamic range)
1490470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    codec.pltype = type;
1491470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
1492eb524d997b877ba9b0bcaf8c85eae52bd40c37e3andrew@webrtc.org    if (audio_coding_->RegisterSendCodec(codec) != 0)
1493470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
1494470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        _engineStatisticsPtr->SetLastError(
1495470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
1496470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            "SetSendCNPayloadType() failed to register CN to ACM");
1497470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        return -1;
1498470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
1499470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
15002853dde5201d9ddc284ce5efb9688f6340487acepwestin@webrtc.org    if (_rtpRtcpModule->RegisterSendPayload(codec) != 0)
1501470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
15022853dde5201d9ddc284ce5efb9688f6340487acepwestin@webrtc.org        _rtpRtcpModule->DeRegisterSendPayload(codec.pltype);
15032853dde5201d9ddc284ce5efb9688f6340487acepwestin@webrtc.org        if (_rtpRtcpModule->RegisterSendPayload(codec) != 0)
1504470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        {
1505470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            _engineStatisticsPtr->SetLastError(
1506470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                VE_RTP_RTCP_MODULE_ERROR, kTraceError,
1507470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                "SetSendCNPayloadType() failed to register CN to RTP/RTCP "
1508470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                "module");
1509470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            return -1;
1510470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        }
1511470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
1512470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    return 0;
1513470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com}
1514470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
1515adee8f924224e116f041564ddde83c979880e35fminyue@webrtc.orgint Channel::SetOpusMaxPlaybackRate(int frequency_hz) {
15166aac93bd9c3da92e92b016d83c8f84c65aae65b6minyue@webrtc.org  WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
1517adee8f924224e116f041564ddde83c979880e35fminyue@webrtc.org               "Channel::SetOpusMaxPlaybackRate()");
15186aac93bd9c3da92e92b016d83c8f84c65aae65b6minyue@webrtc.org
1519adee8f924224e116f041564ddde83c979880e35fminyue@webrtc.org  if (audio_coding_->SetOpusMaxPlaybackRate(frequency_hz) != 0) {
15206aac93bd9c3da92e92b016d83c8f84c65aae65b6minyue@webrtc.org    _engineStatisticsPtr->SetLastError(
15216aac93bd9c3da92e92b016d83c8f84c65aae65b6minyue@webrtc.org        VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
1522adee8f924224e116f041564ddde83c979880e35fminyue@webrtc.org        "SetOpusMaxPlaybackRate() failed to set maximum playback rate");
15236aac93bd9c3da92e92b016d83c8f84c65aae65b6minyue@webrtc.org    return -1;
15246aac93bd9c3da92e92b016d83c8f84c65aae65b6minyue@webrtc.org  }
15256aac93bd9c3da92e92b016d83c8f84c65aae65b6minyue@webrtc.org  return 0;
15266aac93bd9c3da92e92b016d83c8f84c65aae65b6minyue@webrtc.org}
15276aac93bd9c3da92e92b016d83c8f84c65aae65b6minyue@webrtc.org
15289b2e1144df6e3622354caca00baf4a7462a0809cminyue@webrtc.orgint Channel::SetOpusDtx(bool enable_dtx) {
15299b2e1144df6e3622354caca00baf4a7462a0809cminyue@webrtc.org  WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
15309b2e1144df6e3622354caca00baf4a7462a0809cminyue@webrtc.org               "Channel::SetOpusDtx(%d)", enable_dtx);
1531092041c1cdadeb82463ee79dfc291d60b41d35efMinyue Li  int ret = enable_dtx ? audio_coding_->EnableOpusDtx()
15329b2e1144df6e3622354caca00baf4a7462a0809cminyue@webrtc.org                       : audio_coding_->DisableOpusDtx();
15339b2e1144df6e3622354caca00baf4a7462a0809cminyue@webrtc.org  if (ret != 0) {
15349b2e1144df6e3622354caca00baf4a7462a0809cminyue@webrtc.org    _engineStatisticsPtr->SetLastError(
15359b2e1144df6e3622354caca00baf4a7462a0809cminyue@webrtc.org        VE_AUDIO_CODING_MODULE_ERROR, kTraceError, "SetOpusDtx() failed");
15369b2e1144df6e3622354caca00baf4a7462a0809cminyue@webrtc.org    return -1;
15379b2e1144df6e3622354caca00baf4a7462a0809cminyue@webrtc.org  }
15389b2e1144df6e3622354caca00baf4a7462a0809cminyue@webrtc.org  return 0;
15399b2e1144df6e3622354caca00baf4a7462a0809cminyue@webrtc.org}
15409b2e1144df6e3622354caca00baf4a7462a0809cminyue@webrtc.org
15416141e13873d0fdea626de08dfec2efa2c9171c76pbos@webrtc.orgint32_t Channel::RegisterExternalTransport(Transport& transport)
1542470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com{
1543470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
1544470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com               "Channel::RegisterExternalTransport()");
1545470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
15469a065d1eae9ed296e1e2eaaad73d7ca1223bfe79mflodman@webrtc.org    CriticalSectionScoped cs(&_callbackCritSect);
1547470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
1548470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    if (_externalTransport)
1549470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
1550470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        _engineStatisticsPtr->SetLastError(VE_INVALID_OPERATION,
1551470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                                           kTraceError,
1552470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com              "RegisterExternalTransport() external transport already enabled");
1553470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com       return -1;
1554470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
1555470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    _externalTransport = true;
1556470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    _transportPtr = &transport;
1557470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    return 0;
1558470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com}
1559470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
15606141e13873d0fdea626de08dfec2efa2c9171c76pbos@webrtc.orgint32_t
1561470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.comChannel::DeRegisterExternalTransport()
1562470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com{
1563470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1564470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                 "Channel::DeRegisterExternalTransport()");
1565470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
15669a065d1eae9ed296e1e2eaaad73d7ca1223bfe79mflodman@webrtc.org    CriticalSectionScoped cs(&_callbackCritSect);
156783661f534e56dfaf3542963b54b1e208f223a377xians@webrtc.org
1568470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    if (!_transportPtr)
1569470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
1570470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        _engineStatisticsPtr->SetLastError(
1571470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            VE_INVALID_OPERATION, kTraceWarning,
1572470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            "DeRegisterExternalTransport() external transport already "
1573470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            "disabled");
1574470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        return 0;
1575470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
1576470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    _externalTransport = false;
1577470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    _transportPtr = NULL;
1578470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1579470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                 "DeRegisterExternalTransport() all transport is disabled");
1580684f0577fbe4ea393fef1dddf2ca7d02e3205b49pwestin@webrtc.org    return 0;
1581684f0577fbe4ea393fef1dddf2ca7d02e3205b49pwestin@webrtc.org}
1582684f0577fbe4ea393fef1dddf2ca7d02e3205b49pwestin@webrtc.org
15834591fbd09f9cb6e83433c49a12dd8524c2806502pkasting@chromium.orgint32_t Channel::ReceivedRTPPacket(const int8_t* data, size_t length,
1584b1f50100757036cf475072c26f5f374eee9588casolenberg@webrtc.org                                   const PacketTime& packet_time) {
15850c45957e3a6963e1460c0b5b62a6adf43cf44314pwestin@webrtc.org  WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
15860c45957e3a6963e1460c0b5b62a6adf43cf44314pwestin@webrtc.org               "Channel::ReceivedRTPPacket()");
1587684f0577fbe4ea393fef1dddf2ca7d02e3205b49pwestin@webrtc.org
15880c45957e3a6963e1460c0b5b62a6adf43cf44314pwestin@webrtc.org  // Store playout timestamp for the received RTP packet
15891de01354e68da71bc62c81af17afeac8ed374a18pwestin@webrtc.org  UpdatePlayoutTimestamp(false);
1590684f0577fbe4ea393fef1dddf2ca7d02e3205b49pwestin@webrtc.org
15917bb8f02274ecbfa1f7ef134d708369a369a78c83stefan@webrtc.org  const uint8_t* received_packet = reinterpret_cast<const uint8_t*>(data);
1592a5cb98cbbd11e93cb6d0a6232387814aac168c7dstefan@webrtc.org  RTPHeader header;
15937bb8f02274ecbfa1f7ef134d708369a369a78c83stefan@webrtc.org  if (!rtp_header_parser_->Parse(received_packet, length, &header)) {
15947bb8f02274ecbfa1f7ef134d708369a369a78c83stefan@webrtc.org    WEBRTC_TRACE(webrtc::kTraceDebug, webrtc::kTraceVoice, _channelId,
15957bb8f02274ecbfa1f7ef134d708369a369a78c83stefan@webrtc.org                 "Incoming packet: invalid RTP header");
1596a5cb98cbbd11e93cb6d0a6232387814aac168c7dstefan@webrtc.org    return -1;
1597a5cb98cbbd11e93cb6d0a6232387814aac168c7dstefan@webrtc.org  }
1598822fbd8b68ffdb481b9557e2950ae8d6657c8ce6wu@webrtc.org  header.payload_type_frequency =
1599822fbd8b68ffdb481b9557e2950ae8d6657c8ce6wu@webrtc.org      rtp_payload_registry_->GetPayloadTypeFrequency(header.payloadType);
16007bb8f02274ecbfa1f7ef134d708369a369a78c83stefan@webrtc.org  if (header.payload_type_frequency < 0)
1601822fbd8b68ffdb481b9557e2950ae8d6657c8ce6wu@webrtc.org    return -1;
160248df38114d9502f4b4ad700c011190c608a702d5stefan@webrtc.org  bool in_order = IsPacketInOrder(header);
16037bb8f02274ecbfa1f7ef134d708369a369a78c83stefan@webrtc.org  rtp_receive_statistics_->IncomingPacket(header, length,
160448df38114d9502f4b4ad700c011190c608a702d5stefan@webrtc.org      IsPacketRetransmitted(header, in_order));
16057bb8f02274ecbfa1f7ef134d708369a369a78c83stefan@webrtc.org  rtp_payload_registry_->SetIncomingPayloadType(header);
1606b1f50100757036cf475072c26f5f374eee9588casolenberg@webrtc.org
160748df38114d9502f4b4ad700c011190c608a702d5stefan@webrtc.org  return ReceivePacket(received_packet, length, header, in_order) ? 0 : -1;
16087bb8f02274ecbfa1f7ef134d708369a369a78c83stefan@webrtc.org}
16097bb8f02274ecbfa1f7ef134d708369a369a78c83stefan@webrtc.org
16107bb8f02274ecbfa1f7ef134d708369a369a78c83stefan@webrtc.orgbool Channel::ReceivePacket(const uint8_t* packet,
16114591fbd09f9cb6e83433c49a12dd8524c2806502pkasting@chromium.org                            size_t packet_length,
16127bb8f02274ecbfa1f7ef134d708369a369a78c83stefan@webrtc.org                            const RTPHeader& header,
16137bb8f02274ecbfa1f7ef134d708369a369a78c83stefan@webrtc.org                            bool in_order) {
1614456f01441aa4f8c0c8b98aa6d9c2af4a4817e8dbminyue@webrtc.org  if (rtp_payload_registry_->IsRtx(header)) {
1615456f01441aa4f8c0c8b98aa6d9c2af4a4817e8dbminyue@webrtc.org    return HandleRtxPacket(packet, packet_length, header);
1616822fbd8b68ffdb481b9557e2950ae8d6657c8ce6wu@webrtc.org  }
16177bb8f02274ecbfa1f7ef134d708369a369a78c83stefan@webrtc.org  const uint8_t* payload = packet + header.headerLength;
16184591fbd09f9cb6e83433c49a12dd8524c2806502pkasting@chromium.org  assert(packet_length >= header.headerLength);
16194591fbd09f9cb6e83433c49a12dd8524c2806502pkasting@chromium.org  size_t payload_length = packet_length - header.headerLength;
1620822fbd8b68ffdb481b9557e2950ae8d6657c8ce6wu@webrtc.org  PayloadUnion payload_specific;
1621822fbd8b68ffdb481b9557e2950ae8d6657c8ce6wu@webrtc.org  if (!rtp_payload_registry_->GetPayloadSpecifics(header.payloadType,
16227bb8f02274ecbfa1f7ef134d708369a369a78c83stefan@webrtc.org                                                  &payload_specific)) {
16237bb8f02274ecbfa1f7ef134d708369a369a78c83stefan@webrtc.org    return false;
1624822fbd8b68ffdb481b9557e2950ae8d6657c8ce6wu@webrtc.org  }
16257bb8f02274ecbfa1f7ef134d708369a369a78c83stefan@webrtc.org  return rtp_receiver_->IncomingRtpPacket(header, payload, payload_length,
16267bb8f02274ecbfa1f7ef134d708369a369a78c83stefan@webrtc.org                                          payload_specific, in_order);
16277bb8f02274ecbfa1f7ef134d708369a369a78c83stefan@webrtc.org}
16287bb8f02274ecbfa1f7ef134d708369a369a78c83stefan@webrtc.org
1629456f01441aa4f8c0c8b98aa6d9c2af4a4817e8dbminyue@webrtc.orgbool Channel::HandleRtxPacket(const uint8_t* packet,
1630456f01441aa4f8c0c8b98aa6d9c2af4a4817e8dbminyue@webrtc.org                              size_t packet_length,
1631456f01441aa4f8c0c8b98aa6d9c2af4a4817e8dbminyue@webrtc.org                              const RTPHeader& header) {
16327bb8f02274ecbfa1f7ef134d708369a369a78c83stefan@webrtc.org  if (!rtp_payload_registry_->IsRtx(header))
16337bb8f02274ecbfa1f7ef134d708369a369a78c83stefan@webrtc.org    return false;
16347bb8f02274ecbfa1f7ef134d708369a369a78c83stefan@webrtc.org
16357bb8f02274ecbfa1f7ef134d708369a369a78c83stefan@webrtc.org  // Remove the RTX header and parse the original RTP header.
16367bb8f02274ecbfa1f7ef134d708369a369a78c83stefan@webrtc.org  if (packet_length < header.headerLength)
16377bb8f02274ecbfa1f7ef134d708369a369a78c83stefan@webrtc.org    return false;
16387bb8f02274ecbfa1f7ef134d708369a369a78c83stefan@webrtc.org  if (packet_length > kVoiceEngineMaxIpPacketSizeBytes)
16397bb8f02274ecbfa1f7ef134d708369a369a78c83stefan@webrtc.org    return false;
16407bb8f02274ecbfa1f7ef134d708369a369a78c83stefan@webrtc.org  if (restored_packet_in_use_) {
16417bb8f02274ecbfa1f7ef134d708369a369a78c83stefan@webrtc.org    WEBRTC_TRACE(webrtc::kTraceDebug, webrtc::kTraceVoice, _channelId,
16427bb8f02274ecbfa1f7ef134d708369a369a78c83stefan@webrtc.org                 "Multiple RTX headers detected, dropping packet");
16437bb8f02274ecbfa1f7ef134d708369a369a78c83stefan@webrtc.org    return false;
16440c45957e3a6963e1460c0b5b62a6adf43cf44314pwestin@webrtc.org  }
16457bb8f02274ecbfa1f7ef134d708369a369a78c83stefan@webrtc.org  uint8_t* restored_packet_ptr = restored_packet_;
16467bb8f02274ecbfa1f7ef134d708369a369a78c83stefan@webrtc.org  if (!rtp_payload_registry_->RestoreOriginalPacket(
16477bb8f02274ecbfa1f7ef134d708369a369a78c83stefan@webrtc.org      &restored_packet_ptr, packet, &packet_length, rtp_receiver_->SSRC(),
16487bb8f02274ecbfa1f7ef134d708369a369a78c83stefan@webrtc.org      header)) {
16497bb8f02274ecbfa1f7ef134d708369a369a78c83stefan@webrtc.org    WEBRTC_TRACE(webrtc::kTraceDebug, webrtc::kTraceVoice, _channelId,
16507bb8f02274ecbfa1f7ef134d708369a369a78c83stefan@webrtc.org                 "Incoming RTX packet: invalid RTP header");
16517bb8f02274ecbfa1f7ef134d708369a369a78c83stefan@webrtc.org    return false;
16527bb8f02274ecbfa1f7ef134d708369a369a78c83stefan@webrtc.org  }
16537bb8f02274ecbfa1f7ef134d708369a369a78c83stefan@webrtc.org  restored_packet_in_use_ = true;
16547bb8f02274ecbfa1f7ef134d708369a369a78c83stefan@webrtc.org  bool ret = OnRecoveredPacket(restored_packet_ptr, packet_length);
16557bb8f02274ecbfa1f7ef134d708369a369a78c83stefan@webrtc.org  restored_packet_in_use_ = false;
16567bb8f02274ecbfa1f7ef134d708369a369a78c83stefan@webrtc.org  return ret;
16577bb8f02274ecbfa1f7ef134d708369a369a78c83stefan@webrtc.org}
16587bb8f02274ecbfa1f7ef134d708369a369a78c83stefan@webrtc.org
16597bb8f02274ecbfa1f7ef134d708369a369a78c83stefan@webrtc.orgbool Channel::IsPacketInOrder(const RTPHeader& header) const {
16607bb8f02274ecbfa1f7ef134d708369a369a78c83stefan@webrtc.org  StreamStatistician* statistician =
16617bb8f02274ecbfa1f7ef134d708369a369a78c83stefan@webrtc.org      rtp_receive_statistics_->GetStatistician(header.ssrc);
16627bb8f02274ecbfa1f7ef134d708369a369a78c83stefan@webrtc.org  if (!statistician)
16637bb8f02274ecbfa1f7ef134d708369a369a78c83stefan@webrtc.org    return false;
16647bb8f02274ecbfa1f7ef134d708369a369a78c83stefan@webrtc.org  return statistician->IsPacketInOrder(header.sequenceNumber);
16650c45957e3a6963e1460c0b5b62a6adf43cf44314pwestin@webrtc.org}
16660c45957e3a6963e1460c0b5b62a6adf43cf44314pwestin@webrtc.org
166748df38114d9502f4b4ad700c011190c608a702d5stefan@webrtc.orgbool Channel::IsPacketRetransmitted(const RTPHeader& header,
166848df38114d9502f4b4ad700c011190c608a702d5stefan@webrtc.org                                    bool in_order) const {
16697bb8f02274ecbfa1f7ef134d708369a369a78c83stefan@webrtc.org  // Retransmissions are handled separately if RTX is enabled.
16707bb8f02274ecbfa1f7ef134d708369a369a78c83stefan@webrtc.org  if (rtp_payload_registry_->RtxEnabled())
16717bb8f02274ecbfa1f7ef134d708369a369a78c83stefan@webrtc.org    return false;
16727bb8f02274ecbfa1f7ef134d708369a369a78c83stefan@webrtc.org  StreamStatistician* statistician =
16737bb8f02274ecbfa1f7ef134d708369a369a78c83stefan@webrtc.org      rtp_receive_statistics_->GetStatistician(header.ssrc);
16747bb8f02274ecbfa1f7ef134d708369a369a78c83stefan@webrtc.org  if (!statistician)
16757bb8f02274ecbfa1f7ef134d708369a369a78c83stefan@webrtc.org    return false;
16767bb8f02274ecbfa1f7ef134d708369a369a78c83stefan@webrtc.org  // Check if this is a retransmission.
167716825b1a828bb4ff40f7682040e43a239b7b8ca3pkasting@chromium.org  int64_t min_rtt = 0;
16787bb8f02274ecbfa1f7ef134d708369a369a78c83stefan@webrtc.org  _rtpRtcpModule->RTT(rtp_receiver_->SSRC(), NULL, NULL, &min_rtt, NULL);
167948df38114d9502f4b4ad700c011190c608a702d5stefan@webrtc.org  return !in_order &&
16807bb8f02274ecbfa1f7ef134d708369a369a78c83stefan@webrtc.org      statistician->IsRetransmitOfOldPacket(header, min_rtt);
1681822fbd8b68ffdb481b9557e2950ae8d6657c8ce6wu@webrtc.org}
1682822fbd8b68ffdb481b9557e2950ae8d6657c8ce6wu@webrtc.org
16834591fbd09f9cb6e83433c49a12dd8524c2806502pkasting@chromium.orgint32_t Channel::ReceivedRTCPPacket(const int8_t* data, size_t length) {
16840c45957e3a6963e1460c0b5b62a6adf43cf44314pwestin@webrtc.org  WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
16850c45957e3a6963e1460c0b5b62a6adf43cf44314pwestin@webrtc.org               "Channel::ReceivedRTCPPacket()");
16860c45957e3a6963e1460c0b5b62a6adf43cf44314pwestin@webrtc.org  // Store playout timestamp for the received RTCP packet
16871de01354e68da71bc62c81af17afeac8ed374a18pwestin@webrtc.org  UpdatePlayoutTimestamp(true);
16880c45957e3a6963e1460c0b5b62a6adf43cf44314pwestin@webrtc.org
16890c45957e3a6963e1460c0b5b62a6adf43cf44314pwestin@webrtc.org  // Deliver RTCP packet to RTP/RTCP module for parsing
16904591fbd09f9cb6e83433c49a12dd8524c2806502pkasting@chromium.org  if (_rtpRtcpModule->IncomingRtcpPacket((const uint8_t*)data, length) == -1) {
16910c45957e3a6963e1460c0b5b62a6adf43cf44314pwestin@webrtc.org    _engineStatisticsPtr->SetLastError(
16920c45957e3a6963e1460c0b5b62a6adf43cf44314pwestin@webrtc.org        VE_SOCKET_TRANSPORT_MODULE_ERROR, kTraceWarning,
16930c45957e3a6963e1460c0b5b62a6adf43cf44314pwestin@webrtc.org        "Channel::IncomingRTPPacket() RTCP packet is invalid");
16940c45957e3a6963e1460c0b5b62a6adf43cf44314pwestin@webrtc.org  }
169582c4b8531c2c4c2aaf82ff57ee1805037a43ed50wu@webrtc.org
16962013aeced2b7821a407f302802c4a16fd02728b1Minyue  int64_t rtt = GetRTT(true);
16972013aeced2b7821a407f302802c4a16fd02728b1Minyue  if (rtt == 0) {
16982013aeced2b7821a407f302802c4a16fd02728b1Minyue    // Waiting for valid RTT.
16992013aeced2b7821a407f302802c4a16fd02728b1Minyue    return 0;
17002013aeced2b7821a407f302802c4a16fd02728b1Minyue  }
17012013aeced2b7821a407f302802c4a16fd02728b1Minyue  uint32_t ntp_secs = 0;
17022013aeced2b7821a407f302802c4a16fd02728b1Minyue  uint32_t ntp_frac = 0;
17032013aeced2b7821a407f302802c4a16fd02728b1Minyue  uint32_t rtp_timestamp = 0;
17042013aeced2b7821a407f302802c4a16fd02728b1Minyue  if (0 != _rtpRtcpModule->RemoteNTP(&ntp_secs, &ntp_frac, NULL, NULL,
17052013aeced2b7821a407f302802c4a16fd02728b1Minyue                                     &rtp_timestamp)) {
17062013aeced2b7821a407f302802c4a16fd02728b1Minyue    // Waiting for RTCP.
17072013aeced2b7821a407f302802c4a16fd02728b1Minyue    return 0;
17082013aeced2b7821a407f302802c4a16fd02728b1Minyue  }
17092013aeced2b7821a407f302802c4a16fd02728b1Minyue
17108e24d8777849951ed86fb01e0bf556d4eda65161stefan@webrtc.org  {
17118e24d8777849951ed86fb01e0bf556d4eda65161stefan@webrtc.org    CriticalSectionScoped lock(ts_stats_lock_.get());
17122c0cdbce226137a8f755ae0fb51c28a335b2ea5dminyue@webrtc.org    ntp_estimator_.UpdateRtcpTimestamp(rtt, ntp_secs, ntp_frac, rtp_timestamp);
17138e24d8777849951ed86fb01e0bf556d4eda65161stefan@webrtc.org  }
17140c45957e3a6963e1460c0b5b62a6adf43cf44314pwestin@webrtc.org  return 0;
1715684f0577fbe4ea393fef1dddf2ca7d02e3205b49pwestin@webrtc.org}
1716684f0577fbe4ea393fef1dddf2ca7d02e3205b49pwestin@webrtc.org
1717470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.comint Channel::StartPlayingFileLocally(const char* fileName,
17189213521ea98b0977c7cdabd2853060835af226f3pbos@webrtc.org                                     bool loop,
17199213521ea98b0977c7cdabd2853060835af226f3pbos@webrtc.org                                     FileFormats format,
17209213521ea98b0977c7cdabd2853060835af226f3pbos@webrtc.org                                     int startPosition,
17219213521ea98b0977c7cdabd2853060835af226f3pbos@webrtc.org                                     float volumeScaling,
17229213521ea98b0977c7cdabd2853060835af226f3pbos@webrtc.org                                     int stopPosition,
1723470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                                     const CodecInst* codecInst)
1724470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com{
1725470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1726470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                 "Channel::StartPlayingFileLocally(fileNameUTF8[]=%s, loop=%d,"
1727470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                 " format=%d, volumeScaling=%5.3f, startPosition=%d, "
1728470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                 "stopPosition=%d)", fileName, loop, format, volumeScaling,
1729470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                 startPosition, stopPosition);
1730470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
1731944cbeb2926feb86a687e5fda9e2ac88ea8e3001henrika@webrtc.org    if (channel_state_.Get().output_file_playing)
1732470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
1733470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        _engineStatisticsPtr->SetLastError(
1734470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            VE_ALREADY_PLAYING, kTraceError,
1735470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            "StartPlayingFileLocally() is already playing");
1736470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        return -1;
1737470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
1738470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
1739470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
17409a065d1eae9ed296e1e2eaaad73d7ca1223bfe79mflodman@webrtc.org        CriticalSectionScoped cs(&_fileCritSect);
1741470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
1742b37c628ae43a9086da607a638785723306bd9aedhenrike@webrtc.org        if (_outputFilePlayerPtr)
1743b37c628ae43a9086da607a638785723306bd9aedhenrike@webrtc.org        {
1744b37c628ae43a9086da607a638785723306bd9aedhenrike@webrtc.org            _outputFilePlayerPtr->RegisterModuleFileCallback(NULL);
1745b37c628ae43a9086da607a638785723306bd9aedhenrike@webrtc.org            FilePlayer::DestroyFilePlayer(_outputFilePlayerPtr);
1746b37c628ae43a9086da607a638785723306bd9aedhenrike@webrtc.org            _outputFilePlayerPtr = NULL;
1747b37c628ae43a9086da607a638785723306bd9aedhenrike@webrtc.org        }
1748470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
1749b37c628ae43a9086da607a638785723306bd9aedhenrike@webrtc.org        _outputFilePlayerPtr = FilePlayer::CreateFilePlayer(
1750b37c628ae43a9086da607a638785723306bd9aedhenrike@webrtc.org            _outputFilePlayerId, (const FileFormats)format);
1751b37c628ae43a9086da607a638785723306bd9aedhenrike@webrtc.org
1752b37c628ae43a9086da607a638785723306bd9aedhenrike@webrtc.org        if (_outputFilePlayerPtr == NULL)
1753b37c628ae43a9086da607a638785723306bd9aedhenrike@webrtc.org        {
1754b37c628ae43a9086da607a638785723306bd9aedhenrike@webrtc.org            _engineStatisticsPtr->SetLastError(
1755b37c628ae43a9086da607a638785723306bd9aedhenrike@webrtc.org                VE_INVALID_ARGUMENT, kTraceError,
175631d30700d638c4cfa47c26cac7cb00c7232874c9henrike@webrtc.org                "StartPlayingFileLocally() filePlayer format is not correct");
1757b37c628ae43a9086da607a638785723306bd9aedhenrike@webrtc.org            return -1;
1758b37c628ae43a9086da607a638785723306bd9aedhenrike@webrtc.org        }
1759470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
17606141e13873d0fdea626de08dfec2efa2c9171c76pbos@webrtc.org        const uint32_t notificationTime(0);
1761470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
1762b37c628ae43a9086da607a638785723306bd9aedhenrike@webrtc.org        if (_outputFilePlayerPtr->StartPlayingFile(
1763b37c628ae43a9086da607a638785723306bd9aedhenrike@webrtc.org                fileName,
1764b37c628ae43a9086da607a638785723306bd9aedhenrike@webrtc.org                loop,
1765b37c628ae43a9086da607a638785723306bd9aedhenrike@webrtc.org                startPosition,
1766b37c628ae43a9086da607a638785723306bd9aedhenrike@webrtc.org                volumeScaling,
1767b37c628ae43a9086da607a638785723306bd9aedhenrike@webrtc.org                notificationTime,
1768b37c628ae43a9086da607a638785723306bd9aedhenrike@webrtc.org                stopPosition,
1769b37c628ae43a9086da607a638785723306bd9aedhenrike@webrtc.org                (const CodecInst*)codecInst) != 0)
1770b37c628ae43a9086da607a638785723306bd9aedhenrike@webrtc.org        {
1771b37c628ae43a9086da607a638785723306bd9aedhenrike@webrtc.org            _engineStatisticsPtr->SetLastError(
1772b37c628ae43a9086da607a638785723306bd9aedhenrike@webrtc.org                VE_BAD_FILE, kTraceError,
1773b37c628ae43a9086da607a638785723306bd9aedhenrike@webrtc.org                "StartPlayingFile() failed to start file playout");
1774b37c628ae43a9086da607a638785723306bd9aedhenrike@webrtc.org            _outputFilePlayerPtr->StopPlayingFile();
1775b37c628ae43a9086da607a638785723306bd9aedhenrike@webrtc.org            FilePlayer::DestroyFilePlayer(_outputFilePlayerPtr);
1776b37c628ae43a9086da607a638785723306bd9aedhenrike@webrtc.org            _outputFilePlayerPtr = NULL;
1777b37c628ae43a9086da607a638785723306bd9aedhenrike@webrtc.org            return -1;
1778b37c628ae43a9086da607a638785723306bd9aedhenrike@webrtc.org        }
1779b37c628ae43a9086da607a638785723306bd9aedhenrike@webrtc.org        _outputFilePlayerPtr->RegisterModuleFileCallback(this);
1780944cbeb2926feb86a687e5fda9e2ac88ea8e3001henrika@webrtc.org        channel_state_.SetOutputFilePlaying(true);
1781470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
1782ab12990b1b8c2410b34c055e73ed04e8a7ee1d85braveyao@webrtc.org
1783ab12990b1b8c2410b34c055e73ed04e8a7ee1d85braveyao@webrtc.org    if (RegisterFilePlayingToMixer() != 0)
1784066f9e5a2fbb8e83ef88ceca0ab5a4ea057cc619henrike@webrtc.org        return -1;
1785470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
1786470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    return 0;
1787470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com}
1788470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
1789470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.comint Channel::StartPlayingFileLocally(InStream* stream,
17909213521ea98b0977c7cdabd2853060835af226f3pbos@webrtc.org                                     FileFormats format,
17919213521ea98b0977c7cdabd2853060835af226f3pbos@webrtc.org                                     int startPosition,
17929213521ea98b0977c7cdabd2853060835af226f3pbos@webrtc.org                                     float volumeScaling,
17939213521ea98b0977c7cdabd2853060835af226f3pbos@webrtc.org                                     int stopPosition,
1794470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                                     const CodecInst* codecInst)
1795470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com{
1796470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1797470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                 "Channel::StartPlayingFileLocally(format=%d,"
1798470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                 " volumeScaling=%5.3f, startPosition=%d, stopPosition=%d)",
1799470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                 format, volumeScaling, startPosition, stopPosition);
1800470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
1801470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    if(stream == NULL)
1802470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
1803470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        _engineStatisticsPtr->SetLastError(
1804470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            VE_BAD_FILE, kTraceError,
1805470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            "StartPlayingFileLocally() NULL as input stream");
1806470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        return -1;
1807470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
1808470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
1809470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
1810944cbeb2926feb86a687e5fda9e2ac88ea8e3001henrika@webrtc.org    if (channel_state_.Get().output_file_playing)
1811470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
1812470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        _engineStatisticsPtr->SetLastError(
1813470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            VE_ALREADY_PLAYING, kTraceError,
1814470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            "StartPlayingFileLocally() is already playing");
1815470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        return -1;
1816470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
1817470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
1818470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
18199a065d1eae9ed296e1e2eaaad73d7ca1223bfe79mflodman@webrtc.org      CriticalSectionScoped cs(&_fileCritSect);
1820b37c628ae43a9086da607a638785723306bd9aedhenrike@webrtc.org
1821b37c628ae43a9086da607a638785723306bd9aedhenrike@webrtc.org      // Destroy the old instance
1822b37c628ae43a9086da607a638785723306bd9aedhenrike@webrtc.org      if (_outputFilePlayerPtr)
1823b37c628ae43a9086da607a638785723306bd9aedhenrike@webrtc.org      {
1824b37c628ae43a9086da607a638785723306bd9aedhenrike@webrtc.org          _outputFilePlayerPtr->RegisterModuleFileCallback(NULL);
1825b37c628ae43a9086da607a638785723306bd9aedhenrike@webrtc.org          FilePlayer::DestroyFilePlayer(_outputFilePlayerPtr);
1826b37c628ae43a9086da607a638785723306bd9aedhenrike@webrtc.org          _outputFilePlayerPtr = NULL;
1827b37c628ae43a9086da607a638785723306bd9aedhenrike@webrtc.org      }
1828b37c628ae43a9086da607a638785723306bd9aedhenrike@webrtc.org
1829b37c628ae43a9086da607a638785723306bd9aedhenrike@webrtc.org      // Create the instance
1830b37c628ae43a9086da607a638785723306bd9aedhenrike@webrtc.org      _outputFilePlayerPtr = FilePlayer::CreateFilePlayer(
1831b37c628ae43a9086da607a638785723306bd9aedhenrike@webrtc.org          _outputFilePlayerId,
1832b37c628ae43a9086da607a638785723306bd9aedhenrike@webrtc.org          (const FileFormats)format);
1833b37c628ae43a9086da607a638785723306bd9aedhenrike@webrtc.org
1834b37c628ae43a9086da607a638785723306bd9aedhenrike@webrtc.org      if (_outputFilePlayerPtr == NULL)
1835b37c628ae43a9086da607a638785723306bd9aedhenrike@webrtc.org      {
1836b37c628ae43a9086da607a638785723306bd9aedhenrike@webrtc.org          _engineStatisticsPtr->SetLastError(
1837b37c628ae43a9086da607a638785723306bd9aedhenrike@webrtc.org              VE_INVALID_ARGUMENT, kTraceError,
1838b37c628ae43a9086da607a638785723306bd9aedhenrike@webrtc.org              "StartPlayingFileLocally() filePlayer format isnot correct");
1839b37c628ae43a9086da607a638785723306bd9aedhenrike@webrtc.org          return -1;
1840b37c628ae43a9086da607a638785723306bd9aedhenrike@webrtc.org      }
1841b37c628ae43a9086da607a638785723306bd9aedhenrike@webrtc.org
18426141e13873d0fdea626de08dfec2efa2c9171c76pbos@webrtc.org      const uint32_t notificationTime(0);
1843b37c628ae43a9086da607a638785723306bd9aedhenrike@webrtc.org
1844b37c628ae43a9086da607a638785723306bd9aedhenrike@webrtc.org      if (_outputFilePlayerPtr->StartPlayingFile(*stream, startPosition,
1845b37c628ae43a9086da607a638785723306bd9aedhenrike@webrtc.org                                                 volumeScaling,
1846b37c628ae43a9086da607a638785723306bd9aedhenrike@webrtc.org                                                 notificationTime,
1847b37c628ae43a9086da607a638785723306bd9aedhenrike@webrtc.org                                                 stopPosition, codecInst) != 0)
1848b37c628ae43a9086da607a638785723306bd9aedhenrike@webrtc.org      {
1849b37c628ae43a9086da607a638785723306bd9aedhenrike@webrtc.org          _engineStatisticsPtr->SetLastError(VE_BAD_FILE, kTraceError,
1850b37c628ae43a9086da607a638785723306bd9aedhenrike@webrtc.org                                             "StartPlayingFile() failed to "
1851b37c628ae43a9086da607a638785723306bd9aedhenrike@webrtc.org                                             "start file playout");
1852b37c628ae43a9086da607a638785723306bd9aedhenrike@webrtc.org          _outputFilePlayerPtr->StopPlayingFile();
1853b37c628ae43a9086da607a638785723306bd9aedhenrike@webrtc.org          FilePlayer::DestroyFilePlayer(_outputFilePlayerPtr);
1854b37c628ae43a9086da607a638785723306bd9aedhenrike@webrtc.org          _outputFilePlayerPtr = NULL;
1855b37c628ae43a9086da607a638785723306bd9aedhenrike@webrtc.org          return -1;
1856b37c628ae43a9086da607a638785723306bd9aedhenrike@webrtc.org      }
1857b37c628ae43a9086da607a638785723306bd9aedhenrike@webrtc.org      _outputFilePlayerPtr->RegisterModuleFileCallback(this);
1858944cbeb2926feb86a687e5fda9e2ac88ea8e3001henrika@webrtc.org      channel_state_.SetOutputFilePlaying(true);
1859b37c628ae43a9086da607a638785723306bd9aedhenrike@webrtc.org    }
1860ab12990b1b8c2410b34c055e73ed04e8a7ee1d85braveyao@webrtc.org
1861ab12990b1b8c2410b34c055e73ed04e8a7ee1d85braveyao@webrtc.org    if (RegisterFilePlayingToMixer() != 0)
1862066f9e5a2fbb8e83ef88ceca0ab5a4ea057cc619henrike@webrtc.org        return -1;
1863470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
1864470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    return 0;
1865470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com}
1866470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
1867470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.comint Channel::StopPlayingFileLocally()
1868470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com{
1869470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1870470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                 "Channel::StopPlayingFileLocally()");
1871470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
1872944cbeb2926feb86a687e5fda9e2ac88ea8e3001henrika@webrtc.org    if (!channel_state_.Get().output_file_playing)
1873470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
1874470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        _engineStatisticsPtr->SetLastError(
1875470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            VE_INVALID_OPERATION, kTraceWarning,
1876470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            "StopPlayingFileLocally() isnot playing");
1877470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        return 0;
1878470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
1879470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
1880470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
18819a065d1eae9ed296e1e2eaaad73d7ca1223bfe79mflodman@webrtc.org        CriticalSectionScoped cs(&_fileCritSect);
1882b37c628ae43a9086da607a638785723306bd9aedhenrike@webrtc.org
1883b37c628ae43a9086da607a638785723306bd9aedhenrike@webrtc.org        if (_outputFilePlayerPtr->StopPlayingFile() != 0)
1884b37c628ae43a9086da607a638785723306bd9aedhenrike@webrtc.org        {
1885b37c628ae43a9086da607a638785723306bd9aedhenrike@webrtc.org            _engineStatisticsPtr->SetLastError(
1886b37c628ae43a9086da607a638785723306bd9aedhenrike@webrtc.org                VE_STOP_RECORDING_FAILED, kTraceError,
1887b37c628ae43a9086da607a638785723306bd9aedhenrike@webrtc.org                "StopPlayingFile() could not stop playing");
1888b37c628ae43a9086da607a638785723306bd9aedhenrike@webrtc.org            return -1;
1889b37c628ae43a9086da607a638785723306bd9aedhenrike@webrtc.org        }
1890b37c628ae43a9086da607a638785723306bd9aedhenrike@webrtc.org        _outputFilePlayerPtr->RegisterModuleFileCallback(NULL);
1891b37c628ae43a9086da607a638785723306bd9aedhenrike@webrtc.org        FilePlayer::DestroyFilePlayer(_outputFilePlayerPtr);
1892b37c628ae43a9086da607a638785723306bd9aedhenrike@webrtc.org        _outputFilePlayerPtr = NULL;
1893944cbeb2926feb86a687e5fda9e2ac88ea8e3001henrika@webrtc.org        channel_state_.SetOutputFilePlaying(false);
1894470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
1895b37c628ae43a9086da607a638785723306bd9aedhenrike@webrtc.org    // _fileCritSect cannot be taken while calling
1896b37c628ae43a9086da607a638785723306bd9aedhenrike@webrtc.org    // SetAnonymousMixibilityStatus. Refer to comments in
1897b37c628ae43a9086da607a638785723306bd9aedhenrike@webrtc.org    // StartPlayingFileLocally(const char* ...) for more details.
1898066f9e5a2fbb8e83ef88ceca0ab5a4ea057cc619henrike@webrtc.org    if (_outputMixerPtr->SetAnonymousMixabilityStatus(*this, false) != 0)
1899066f9e5a2fbb8e83ef88ceca0ab5a4ea057cc619henrike@webrtc.org    {
1900066f9e5a2fbb8e83ef88ceca0ab5a4ea057cc619henrike@webrtc.org        _engineStatisticsPtr->SetLastError(
1901066f9e5a2fbb8e83ef88ceca0ab5a4ea057cc619henrike@webrtc.org            VE_AUDIO_CONF_MIX_MODULE_ERROR, kTraceError,
1902b37c628ae43a9086da607a638785723306bd9aedhenrike@webrtc.org            "StopPlayingFile() failed to stop participant from playing as"
1903b37c628ae43a9086da607a638785723306bd9aedhenrike@webrtc.org            "file in the mixer");
1904066f9e5a2fbb8e83ef88ceca0ab5a4ea057cc619henrike@webrtc.org        return -1;
1905066f9e5a2fbb8e83ef88ceca0ab5a4ea057cc619henrike@webrtc.org    }
1906470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
1907470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    return 0;
1908470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com}
1909470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
1910470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.comint Channel::IsPlayingFileLocally() const
1911470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com{
1912470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1913470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                 "Channel::IsPlayingFileLocally()");
1914470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
1915944cbeb2926feb86a687e5fda9e2ac88ea8e3001henrika@webrtc.org    return channel_state_.Get().output_file_playing;
1916470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com}
1917470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
1918ab12990b1b8c2410b34c055e73ed04e8a7ee1d85braveyao@webrtc.orgint Channel::RegisterFilePlayingToMixer()
1919ab12990b1b8c2410b34c055e73ed04e8a7ee1d85braveyao@webrtc.org{
1920ab12990b1b8c2410b34c055e73ed04e8a7ee1d85braveyao@webrtc.org    // Return success for not registering for file playing to mixer if:
1921ab12990b1b8c2410b34c055e73ed04e8a7ee1d85braveyao@webrtc.org    // 1. playing file before playout is started on that channel.
1922ab12990b1b8c2410b34c055e73ed04e8a7ee1d85braveyao@webrtc.org    // 2. starting playout without file playing on that channel.
1923944cbeb2926feb86a687e5fda9e2ac88ea8e3001henrika@webrtc.org    if (!channel_state_.Get().playing ||
1924944cbeb2926feb86a687e5fda9e2ac88ea8e3001henrika@webrtc.org        !channel_state_.Get().output_file_playing)
1925ab12990b1b8c2410b34c055e73ed04e8a7ee1d85braveyao@webrtc.org    {
1926ab12990b1b8c2410b34c055e73ed04e8a7ee1d85braveyao@webrtc.org        return 0;
1927ab12990b1b8c2410b34c055e73ed04e8a7ee1d85braveyao@webrtc.org    }
1928ab12990b1b8c2410b34c055e73ed04e8a7ee1d85braveyao@webrtc.org
1929ab12990b1b8c2410b34c055e73ed04e8a7ee1d85braveyao@webrtc.org    // |_fileCritSect| cannot be taken while calling
1930ab12990b1b8c2410b34c055e73ed04e8a7ee1d85braveyao@webrtc.org    // SetAnonymousMixabilityStatus() since as soon as the participant is added
1931ab12990b1b8c2410b34c055e73ed04e8a7ee1d85braveyao@webrtc.org    // frames can be pulled by the mixer. Since the frames are generated from
1932ab12990b1b8c2410b34c055e73ed04e8a7ee1d85braveyao@webrtc.org    // the file, _fileCritSect will be taken. This would result in a deadlock.
1933ab12990b1b8c2410b34c055e73ed04e8a7ee1d85braveyao@webrtc.org    if (_outputMixerPtr->SetAnonymousMixabilityStatus(*this, true) != 0)
1934ab12990b1b8c2410b34c055e73ed04e8a7ee1d85braveyao@webrtc.org    {
1935944cbeb2926feb86a687e5fda9e2ac88ea8e3001henrika@webrtc.org        channel_state_.SetOutputFilePlaying(false);
1936ab12990b1b8c2410b34c055e73ed04e8a7ee1d85braveyao@webrtc.org        CriticalSectionScoped cs(&_fileCritSect);
1937ab12990b1b8c2410b34c055e73ed04e8a7ee1d85braveyao@webrtc.org        _engineStatisticsPtr->SetLastError(
1938ab12990b1b8c2410b34c055e73ed04e8a7ee1d85braveyao@webrtc.org            VE_AUDIO_CONF_MIX_MODULE_ERROR, kTraceError,
1939ab12990b1b8c2410b34c055e73ed04e8a7ee1d85braveyao@webrtc.org            "StartPlayingFile() failed to add participant as file to mixer");
1940ab12990b1b8c2410b34c055e73ed04e8a7ee1d85braveyao@webrtc.org        _outputFilePlayerPtr->StopPlayingFile();
1941ab12990b1b8c2410b34c055e73ed04e8a7ee1d85braveyao@webrtc.org        FilePlayer::DestroyFilePlayer(_outputFilePlayerPtr);
1942ab12990b1b8c2410b34c055e73ed04e8a7ee1d85braveyao@webrtc.org        _outputFilePlayerPtr = NULL;
1943ab12990b1b8c2410b34c055e73ed04e8a7ee1d85braveyao@webrtc.org        return -1;
1944ab12990b1b8c2410b34c055e73ed04e8a7ee1d85braveyao@webrtc.org    }
1945ab12990b1b8c2410b34c055e73ed04e8a7ee1d85braveyao@webrtc.org
1946ab12990b1b8c2410b34c055e73ed04e8a7ee1d85braveyao@webrtc.org    return 0;
1947ab12990b1b8c2410b34c055e73ed04e8a7ee1d85braveyao@webrtc.org}
1948ab12990b1b8c2410b34c055e73ed04e8a7ee1d85braveyao@webrtc.org
1949470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.comint Channel::StartPlayingFileAsMicrophone(const char* fileName,
19509213521ea98b0977c7cdabd2853060835af226f3pbos@webrtc.org                                          bool loop,
19519213521ea98b0977c7cdabd2853060835af226f3pbos@webrtc.org                                          FileFormats format,
19529213521ea98b0977c7cdabd2853060835af226f3pbos@webrtc.org                                          int startPosition,
19539213521ea98b0977c7cdabd2853060835af226f3pbos@webrtc.org                                          float volumeScaling,
19549213521ea98b0977c7cdabd2853060835af226f3pbos@webrtc.org                                          int stopPosition,
1955470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                                          const CodecInst* codecInst)
1956470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com{
1957470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1958470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                 "Channel::StartPlayingFileAsMicrophone(fileNameUTF8[]=%s, "
1959470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                 "loop=%d, format=%d, volumeScaling=%5.3f, startPosition=%d, "
1960470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                 "stopPosition=%d)", fileName, loop, format, volumeScaling,
1961470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                 startPosition, stopPosition);
1962470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
1963944cbeb2926feb86a687e5fda9e2ac88ea8e3001henrika@webrtc.org    CriticalSectionScoped cs(&_fileCritSect);
1964944cbeb2926feb86a687e5fda9e2ac88ea8e3001henrika@webrtc.org
1965944cbeb2926feb86a687e5fda9e2ac88ea8e3001henrika@webrtc.org    if (channel_state_.Get().input_file_playing)
1966470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
1967470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        _engineStatisticsPtr->SetLastError(
1968470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            VE_ALREADY_PLAYING, kTraceWarning,
1969470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            "StartPlayingFileAsMicrophone() filePlayer is playing");
1970470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        return 0;
1971470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
1972470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
1973470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    // Destroy the old instance
1974470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    if (_inputFilePlayerPtr)
1975470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
1976470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        _inputFilePlayerPtr->RegisterModuleFileCallback(NULL);
1977470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        FilePlayer::DestroyFilePlayer(_inputFilePlayerPtr);
1978470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        _inputFilePlayerPtr = NULL;
1979470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
1980470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
1981470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    // Create the instance
1982470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    _inputFilePlayerPtr = FilePlayer::CreateFilePlayer(
1983470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        _inputFilePlayerId, (const FileFormats)format);
1984470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
1985470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    if (_inputFilePlayerPtr == NULL)
1986470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
1987470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        _engineStatisticsPtr->SetLastError(
1988470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            VE_INVALID_ARGUMENT, kTraceError,
1989470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            "StartPlayingFileAsMicrophone() filePlayer format isnot correct");
1990470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        return -1;
1991470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
1992470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
19936141e13873d0fdea626de08dfec2efa2c9171c76pbos@webrtc.org    const uint32_t notificationTime(0);
1994470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
1995470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    if (_inputFilePlayerPtr->StartPlayingFile(
1996470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        fileName,
1997470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        loop,
1998470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        startPosition,
1999470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        volumeScaling,
2000470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        notificationTime,
2001470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        stopPosition,
2002470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        (const CodecInst*)codecInst) != 0)
2003470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
2004470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        _engineStatisticsPtr->SetLastError(
2005470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            VE_BAD_FILE, kTraceError,
2006470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            "StartPlayingFile() failed to start file playout");
2007470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        _inputFilePlayerPtr->StopPlayingFile();
2008470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        FilePlayer::DestroyFilePlayer(_inputFilePlayerPtr);
2009470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        _inputFilePlayerPtr = NULL;
2010470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        return -1;
2011470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
2012470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    _inputFilePlayerPtr->RegisterModuleFileCallback(this);
2013944cbeb2926feb86a687e5fda9e2ac88ea8e3001henrika@webrtc.org    channel_state_.SetInputFilePlaying(true);
2014470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
2015470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    return 0;
2016470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com}
2017470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
2018470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.comint Channel::StartPlayingFileAsMicrophone(InStream* stream,
20199213521ea98b0977c7cdabd2853060835af226f3pbos@webrtc.org                                          FileFormats format,
20209213521ea98b0977c7cdabd2853060835af226f3pbos@webrtc.org                                          int startPosition,
20219213521ea98b0977c7cdabd2853060835af226f3pbos@webrtc.org                                          float volumeScaling,
20229213521ea98b0977c7cdabd2853060835af226f3pbos@webrtc.org                                          int stopPosition,
2023470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                                          const CodecInst* codecInst)
2024470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com{
2025470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2026470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                 "Channel::StartPlayingFileAsMicrophone(format=%d, "
2027470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                 "volumeScaling=%5.3f, startPosition=%d, stopPosition=%d)",
2028470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                 format, volumeScaling, startPosition, stopPosition);
2029470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
2030470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    if(stream == NULL)
2031470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
2032470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        _engineStatisticsPtr->SetLastError(
2033470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            VE_BAD_FILE, kTraceError,
2034470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            "StartPlayingFileAsMicrophone NULL as input stream");
2035470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        return -1;
2036470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
2037470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
2038944cbeb2926feb86a687e5fda9e2ac88ea8e3001henrika@webrtc.org    CriticalSectionScoped cs(&_fileCritSect);
2039944cbeb2926feb86a687e5fda9e2ac88ea8e3001henrika@webrtc.org
2040944cbeb2926feb86a687e5fda9e2ac88ea8e3001henrika@webrtc.org    if (channel_state_.Get().input_file_playing)
2041470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
2042470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        _engineStatisticsPtr->SetLastError(
2043470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            VE_ALREADY_PLAYING, kTraceWarning,
2044470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            "StartPlayingFileAsMicrophone() is playing");
2045470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        return 0;
2046470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
2047470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
2048470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    // Destroy the old instance
2049470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    if (_inputFilePlayerPtr)
2050470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
2051470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        _inputFilePlayerPtr->RegisterModuleFileCallback(NULL);
2052470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        FilePlayer::DestroyFilePlayer(_inputFilePlayerPtr);
2053470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        _inputFilePlayerPtr = NULL;
2054470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
2055470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
2056470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    // Create the instance
2057470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    _inputFilePlayerPtr = FilePlayer::CreateFilePlayer(
2058470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        _inputFilePlayerId, (const FileFormats)format);
2059470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
2060470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    if (_inputFilePlayerPtr == NULL)
2061470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
2062470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        _engineStatisticsPtr->SetLastError(
2063470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            VE_INVALID_ARGUMENT, kTraceError,
2064470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            "StartPlayingInputFile() filePlayer format isnot correct");
2065470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        return -1;
2066470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
2067470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
20686141e13873d0fdea626de08dfec2efa2c9171c76pbos@webrtc.org    const uint32_t notificationTime(0);
2069470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
2070470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    if (_inputFilePlayerPtr->StartPlayingFile(*stream, startPosition,
2071470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                                              volumeScaling, notificationTime,
2072470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                                              stopPosition, codecInst) != 0)
2073470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
2074470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        _engineStatisticsPtr->SetLastError(VE_BAD_FILE, kTraceError,
2075470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                                           "StartPlayingFile() failed to start "
2076470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                                           "file playout");
2077470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        _inputFilePlayerPtr->StopPlayingFile();
2078470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        FilePlayer::DestroyFilePlayer(_inputFilePlayerPtr);
2079470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        _inputFilePlayerPtr = NULL;
2080470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        return -1;
2081470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
2082ae1a58bba4f926d149a5f39243269c3f6625f494andrew@webrtc.org
2083470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    _inputFilePlayerPtr->RegisterModuleFileCallback(this);
2084944cbeb2926feb86a687e5fda9e2ac88ea8e3001henrika@webrtc.org    channel_state_.SetInputFilePlaying(true);
2085470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
2086470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    return 0;
2087470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com}
2088470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
2089470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.comint Channel::StopPlayingFileAsMicrophone()
2090470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com{
2091470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2092470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                 "Channel::StopPlayingFileAsMicrophone()");
2093470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
2094944cbeb2926feb86a687e5fda9e2ac88ea8e3001henrika@webrtc.org    CriticalSectionScoped cs(&_fileCritSect);
2095944cbeb2926feb86a687e5fda9e2ac88ea8e3001henrika@webrtc.org
2096944cbeb2926feb86a687e5fda9e2ac88ea8e3001henrika@webrtc.org    if (!channel_state_.Get().input_file_playing)
2097470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
2098470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        _engineStatisticsPtr->SetLastError(
2099470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            VE_INVALID_OPERATION, kTraceWarning,
2100470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            "StopPlayingFileAsMicrophone() isnot playing");
2101470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        return 0;
2102470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
2103470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
2104470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    if (_inputFilePlayerPtr->StopPlayingFile() != 0)
2105470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
2106470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        _engineStatisticsPtr->SetLastError(
2107470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            VE_STOP_RECORDING_FAILED, kTraceError,
2108470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            "StopPlayingFile() could not stop playing");
2109470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        return -1;
2110470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
2111470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    _inputFilePlayerPtr->RegisterModuleFileCallback(NULL);
2112470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    FilePlayer::DestroyFilePlayer(_inputFilePlayerPtr);
2113470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    _inputFilePlayerPtr = NULL;
2114944cbeb2926feb86a687e5fda9e2ac88ea8e3001henrika@webrtc.org    channel_state_.SetInputFilePlaying(false);
2115470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
2116470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    return 0;
2117470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com}
2118470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
2119470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.comint Channel::IsPlayingFileAsMicrophone() const
2120470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com{
2121470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2122470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                 "Channel::IsPlayingFileAsMicrophone()");
2123944cbeb2926feb86a687e5fda9e2ac88ea8e3001henrika@webrtc.org    return channel_state_.Get().input_file_playing;
2124470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com}
2125470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
2126813e4b0af06272dada388c2d8383b2e36a1da6a6leozwang@webrtc.orgint Channel::StartRecordingPlayout(const char* fileName,
2127470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                                   const CodecInst* codecInst)
2128470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com{
2129470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2130470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                 "Channel::StartRecordingPlayout(fileName=%s)", fileName);
2131470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
2132470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    if (_outputFileRecording)
2133470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
2134470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        WEBRTC_TRACE(kTraceWarning, kTraceVoice, VoEId(_instanceId,-1),
2135470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                     "StartRecordingPlayout() is already recording");
2136470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        return 0;
2137470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
2138470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
2139470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    FileFormats format;
21406141e13873d0fdea626de08dfec2efa2c9171c76pbos@webrtc.org    const uint32_t notificationTime(0); // Not supported in VoE
2141470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    CodecInst dummyCodec={100,"L16",16000,320,1,320000};
2142470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
214340197d7b3b347f05b299a930641dad131c853e01niklas.enbom@webrtc.org    if ((codecInst != NULL) &&
214440197d7b3b347f05b299a930641dad131c853e01niklas.enbom@webrtc.org      ((codecInst->channels < 1) || (codecInst->channels > 2)))
2145470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
2146470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        _engineStatisticsPtr->SetLastError(
2147470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            VE_BAD_ARGUMENT, kTraceError,
2148470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            "StartRecordingPlayout() invalid compression");
2149470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        return(-1);
2150470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
2151470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    if(codecInst == NULL)
2152470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
2153470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        format = kFileFormatPcm16kHzFile;
2154470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        codecInst=&dummyCodec;
2155470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
2156470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    else if((STR_CASE_CMP(codecInst->plname,"L16") == 0) ||
2157470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        (STR_CASE_CMP(codecInst->plname,"PCMU") == 0) ||
2158470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        (STR_CASE_CMP(codecInst->plname,"PCMA") == 0))
2159470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
2160470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        format = kFileFormatWavFile;
2161470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
2162470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    else
2163470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
2164470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        format = kFileFormatCompressedFile;
2165470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
2166470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
21679a065d1eae9ed296e1e2eaaad73d7ca1223bfe79mflodman@webrtc.org    CriticalSectionScoped cs(&_fileCritSect);
2168470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
2169470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    // Destroy the old instance
2170470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    if (_outputFileRecorderPtr)
2171470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
2172470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        _outputFileRecorderPtr->RegisterModuleFileCallback(NULL);
2173470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        FileRecorder::DestroyFileRecorder(_outputFileRecorderPtr);
2174470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        _outputFileRecorderPtr = NULL;
2175470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
2176470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
2177470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    _outputFileRecorderPtr = FileRecorder::CreateFileRecorder(
2178470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        _outputFileRecorderId, (const FileFormats)format);
2179470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    if (_outputFileRecorderPtr == NULL)
2180470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
2181470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        _engineStatisticsPtr->SetLastError(
2182470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            VE_INVALID_ARGUMENT, kTraceError,
2183470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            "StartRecordingPlayout() fileRecorder format isnot correct");
2184470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        return -1;
2185470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
2186470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
2187470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    if (_outputFileRecorderPtr->StartRecordingAudioFile(
2188470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        fileName, (const CodecInst&)*codecInst, notificationTime) != 0)
2189470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
2190470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        _engineStatisticsPtr->SetLastError(
2191470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            VE_BAD_FILE, kTraceError,
2192470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            "StartRecordingAudioFile() failed to start file recording");
2193470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        _outputFileRecorderPtr->StopRecording();
2194470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        FileRecorder::DestroyFileRecorder(_outputFileRecorderPtr);
2195470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        _outputFileRecorderPtr = NULL;
2196470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        return -1;
2197470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
2198470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    _outputFileRecorderPtr->RegisterModuleFileCallback(this);
2199470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    _outputFileRecording = true;
2200470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
2201470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    return 0;
2202470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com}
2203470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
2204470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.comint Channel::StartRecordingPlayout(OutStream* stream,
2205470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                                   const CodecInst* codecInst)
2206470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com{
2207470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2208470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                 "Channel::StartRecordingPlayout()");
2209470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
2210470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    if (_outputFileRecording)
2211470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
2212470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        WEBRTC_TRACE(kTraceWarning, kTraceVoice, VoEId(_instanceId,-1),
2213470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                     "StartRecordingPlayout() is already recording");
2214470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        return 0;
2215470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
2216470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
2217470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    FileFormats format;
22186141e13873d0fdea626de08dfec2efa2c9171c76pbos@webrtc.org    const uint32_t notificationTime(0); // Not supported in VoE
2219470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    CodecInst dummyCodec={100,"L16",16000,320,1,320000};
2220470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
2221470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    if (codecInst != NULL && codecInst->channels != 1)
2222470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
2223470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        _engineStatisticsPtr->SetLastError(
2224470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            VE_BAD_ARGUMENT, kTraceError,
2225470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            "StartRecordingPlayout() invalid compression");
2226470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        return(-1);
2227470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
2228470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    if(codecInst == NULL)
2229470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
2230470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        format = kFileFormatPcm16kHzFile;
2231470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        codecInst=&dummyCodec;
2232470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
2233470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    else if((STR_CASE_CMP(codecInst->plname,"L16") == 0) ||
2234470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        (STR_CASE_CMP(codecInst->plname,"PCMU") == 0) ||
2235470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        (STR_CASE_CMP(codecInst->plname,"PCMA") == 0))
2236470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
2237470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        format = kFileFormatWavFile;
2238470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
2239470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    else
2240470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
2241470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        format = kFileFormatCompressedFile;
2242470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
2243470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
22449a065d1eae9ed296e1e2eaaad73d7ca1223bfe79mflodman@webrtc.org    CriticalSectionScoped cs(&_fileCritSect);
2245470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
2246470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    // Destroy the old instance
2247470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    if (_outputFileRecorderPtr)
2248470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
2249470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        _outputFileRecorderPtr->RegisterModuleFileCallback(NULL);
2250470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        FileRecorder::DestroyFileRecorder(_outputFileRecorderPtr);
2251470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        _outputFileRecorderPtr = NULL;
2252470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
2253470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
2254470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    _outputFileRecorderPtr = FileRecorder::CreateFileRecorder(
2255470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        _outputFileRecorderId, (const FileFormats)format);
2256470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    if (_outputFileRecorderPtr == NULL)
2257470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
2258470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        _engineStatisticsPtr->SetLastError(
2259470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            VE_INVALID_ARGUMENT, kTraceError,
2260470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            "StartRecordingPlayout() fileRecorder format isnot correct");
2261470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        return -1;
2262470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
2263470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
2264470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    if (_outputFileRecorderPtr->StartRecordingAudioFile(*stream, *codecInst,
2265470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                                                        notificationTime) != 0)
2266470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
2267470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        _engineStatisticsPtr->SetLastError(VE_BAD_FILE, kTraceError,
2268470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                                           "StartRecordingPlayout() failed to "
2269470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                                           "start file recording");
2270470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        _outputFileRecorderPtr->StopRecording();
2271470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        FileRecorder::DestroyFileRecorder(_outputFileRecorderPtr);
2272470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        _outputFileRecorderPtr = NULL;
2273470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        return -1;
2274470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
2275ae1a58bba4f926d149a5f39243269c3f6625f494andrew@webrtc.org
2276470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    _outputFileRecorderPtr->RegisterModuleFileCallback(this);
2277470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    _outputFileRecording = true;
2278470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
2279470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    return 0;
2280470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com}
2281470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
2282470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.comint Channel::StopRecordingPlayout()
2283470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com{
2284470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,-1),
2285470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                 "Channel::StopRecordingPlayout()");
2286470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
2287470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    if (!_outputFileRecording)
2288470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
2289470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        WEBRTC_TRACE(kTraceError, kTraceVoice, VoEId(_instanceId,-1),
2290470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                     "StopRecordingPlayout() isnot recording");
2291470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        return -1;
2292470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
2293470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
2294470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
22959a065d1eae9ed296e1e2eaaad73d7ca1223bfe79mflodman@webrtc.org    CriticalSectionScoped cs(&_fileCritSect);
2296470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
2297470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    if (_outputFileRecorderPtr->StopRecording() != 0)
2298470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
2299470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        _engineStatisticsPtr->SetLastError(
2300470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            VE_STOP_RECORDING_FAILED, kTraceError,
2301470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            "StopRecording() could not stop recording");
2302470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        return(-1);
2303470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
2304470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    _outputFileRecorderPtr->RegisterModuleFileCallback(NULL);
2305470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    FileRecorder::DestroyFileRecorder(_outputFileRecorderPtr);
2306470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    _outputFileRecorderPtr = NULL;
2307470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    _outputFileRecording = false;
2308470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
2309470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    return 0;
2310470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com}
2311470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
2312470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.comvoid
2313470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.comChannel::SetMixWithMicStatus(bool mix)
2314470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com{
2315944cbeb2926feb86a687e5fda9e2ac88ea8e3001henrika@webrtc.org    CriticalSectionScoped cs(&_fileCritSect);
2316470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    _mixFileWithMicrophone=mix;
2317470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com}
2318470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
2319470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.comint
23206141e13873d0fdea626de08dfec2efa2c9171c76pbos@webrtc.orgChannel::GetSpeechOutputLevel(uint32_t& level) const
2321470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com{
23226141e13873d0fdea626de08dfec2efa2c9171c76pbos@webrtc.org    int8_t currentLevel = _outputAudioLevel.Level();
23236141e13873d0fdea626de08dfec2efa2c9171c76pbos@webrtc.org    level = static_cast<int32_t> (currentLevel);
2324470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
2325470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com               VoEId(_instanceId,_channelId),
2326470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com               "GetSpeechOutputLevel() => level=%u", level);
2327470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    return 0;
2328470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com}
2329470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
2330470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.comint
23316141e13873d0fdea626de08dfec2efa2c9171c76pbos@webrtc.orgChannel::GetSpeechOutputLevelFullRange(uint32_t& level) const
2332470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com{
23336141e13873d0fdea626de08dfec2efa2c9171c76pbos@webrtc.org    int16_t currentLevel = _outputAudioLevel.LevelFullRange();
23346141e13873d0fdea626de08dfec2efa2c9171c76pbos@webrtc.org    level = static_cast<int32_t> (currentLevel);
2335470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
2336470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com               VoEId(_instanceId,_channelId),
2337470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com               "GetSpeechOutputLevelFullRange() => level=%u", level);
2338470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    return 0;
2339470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com}
2340470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
2341470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.comint
2342470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.comChannel::SetMute(bool enable)
2343470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com{
234463420669746cfca6ed1d902c68c656b79ffa5a1bwu@webrtc.org    CriticalSectionScoped cs(&volume_settings_critsect_);
2345470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2346470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com               "Channel::SetMute(enable=%d)", enable);
2347470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    _mute = enable;
2348470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    return 0;
2349470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com}
2350470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
2351470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.combool
2352470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.comChannel::Mute() const
2353470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com{
235463420669746cfca6ed1d902c68c656b79ffa5a1bwu@webrtc.org    CriticalSectionScoped cs(&volume_settings_critsect_);
2355470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    return _mute;
2356470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com}
2357470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
2358470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.comint
2359470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.comChannel::SetOutputVolumePan(float left, float right)
2360470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com{
236163420669746cfca6ed1d902c68c656b79ffa5a1bwu@webrtc.org    CriticalSectionScoped cs(&volume_settings_critsect_);
2362470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2363470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com               "Channel::SetOutputVolumePan()");
2364470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    _panLeft = left;
2365470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    _panRight = right;
2366470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    return 0;
2367470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com}
2368470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
2369470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.comint
2370470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.comChannel::GetOutputVolumePan(float& left, float& right) const
2371470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com{
237263420669746cfca6ed1d902c68c656b79ffa5a1bwu@webrtc.org    CriticalSectionScoped cs(&volume_settings_critsect_);
2373470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    left = _panLeft;
2374470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    right = _panRight;
2375470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
2376470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com               VoEId(_instanceId,_channelId),
2377470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com               "GetOutputVolumePan() => left=%3.2f, right=%3.2f", left, right);
2378470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    return 0;
2379470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com}
2380470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
2381470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.comint
2382470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.comChannel::SetChannelOutputVolumeScaling(float scaling)
2383470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com{
238463420669746cfca6ed1d902c68c656b79ffa5a1bwu@webrtc.org    CriticalSectionScoped cs(&volume_settings_critsect_);
2385470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2386470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com               "Channel::SetChannelOutputVolumeScaling()");
2387470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    _outputGain = scaling;
2388470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    return 0;
2389470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com}
2390470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
2391470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.comint
2392470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.comChannel::GetChannelOutputVolumeScaling(float& scaling) const
2393470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com{
239463420669746cfca6ed1d902c68c656b79ffa5a1bwu@webrtc.org    CriticalSectionScoped cs(&volume_settings_critsect_);
2395470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    scaling = _outputGain;
2396470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
2397470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com               VoEId(_instanceId,_channelId),
2398470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com               "GetChannelOutputVolumeScaling() => scaling=%3.2f", scaling);
2399470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    return 0;
2400470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com}
2401470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
2402470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.comint Channel::SendTelephoneEventOutband(unsigned char eventCode,
2403822fbd8b68ffdb481b9557e2950ae8d6657c8ce6wu@webrtc.org                                       int lengthMs, int attenuationDb,
2404822fbd8b68ffdb481b9557e2950ae8d6657c8ce6wu@webrtc.org                                       bool playDtmfEvent)
2405470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com{
2406470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
2407470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com               "Channel::SendTelephoneEventOutband(..., playDtmfEvent=%d)",
2408470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com               playDtmfEvent);
2409470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
2410470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    _playOutbandDtmfEvent = playDtmfEvent;
2411470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
24122853dde5201d9ddc284ce5efb9688f6340487acepwestin@webrtc.org    if (_rtpRtcpModule->SendTelephoneEventOutband(eventCode, lengthMs,
2413470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                                                 attenuationDb) != 0)
2414470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
2415470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        _engineStatisticsPtr->SetLastError(
2416470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            VE_SEND_DTMF_FAILED,
2417470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            kTraceWarning,
2418470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            "SendTelephoneEventOutband() failed to send event");
2419470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        return -1;
2420470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
2421470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    return 0;
2422470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com}
2423470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
2424470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.comint Channel::SendTelephoneEventInband(unsigned char eventCode,
2425470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                                         int lengthMs,
2426470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                                         int attenuationDb,
2427470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                                         bool playDtmfEvent)
2428470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com{
2429470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
2430470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com               "Channel::SendTelephoneEventInband(..., playDtmfEvent=%d)",
2431470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com               playDtmfEvent);
2432470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
2433470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    _playInbandDtmfEvent = playDtmfEvent;
2434470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    _inbandDtmfQueue.AddDtmf(eventCode, lengthMs, attenuationDb);
2435470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
2436470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    return 0;
2437470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com}
2438470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
2439470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.comint
2440470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.comChannel::SetSendTelephoneEventPayloadType(unsigned char type)
2441470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com{
2442470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2443470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com               "Channel::SetSendTelephoneEventPayloadType()");
2444f81f9f8c2a18fb20ee60406ece45ff3210367ff9andrew@webrtc.org    if (type > 127)
2445470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
2446470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        _engineStatisticsPtr->SetLastError(
2447470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            VE_INVALID_ARGUMENT, kTraceError,
2448470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            "SetSendTelephoneEventPayloadType() invalid type");
2449470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        return -1;
2450470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
24515b10d8fb184db0192091bf407c8166b5d03b932epbos@webrtc.org    CodecInst codec = {};
24521da1ce0da5fcc029dbc2a134a9760e1b398b02d7pwestin@webrtc.org    codec.plfreq = 8000;
24531da1ce0da5fcc029dbc2a134a9760e1b398b02d7pwestin@webrtc.org    codec.pltype = type;
24541da1ce0da5fcc029dbc2a134a9760e1b398b02d7pwestin@webrtc.org    memcpy(codec.plname, "telephone-event", 16);
24552853dde5201d9ddc284ce5efb9688f6340487acepwestin@webrtc.org    if (_rtpRtcpModule->RegisterSendPayload(codec) != 0)
2456470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
24574392d5f9f859b5d55b8017fafb09a496a110beb3henrika@webrtc.org        _rtpRtcpModule->DeRegisterSendPayload(codec.pltype);
24584392d5f9f859b5d55b8017fafb09a496a110beb3henrika@webrtc.org        if (_rtpRtcpModule->RegisterSendPayload(codec) != 0) {
24594392d5f9f859b5d55b8017fafb09a496a110beb3henrika@webrtc.org            _engineStatisticsPtr->SetLastError(
24604392d5f9f859b5d55b8017fafb09a496a110beb3henrika@webrtc.org                VE_RTP_RTCP_MODULE_ERROR, kTraceError,
24614392d5f9f859b5d55b8017fafb09a496a110beb3henrika@webrtc.org                "SetSendTelephoneEventPayloadType() failed to register send"
24624392d5f9f859b5d55b8017fafb09a496a110beb3henrika@webrtc.org                "payload type");
24634392d5f9f859b5d55b8017fafb09a496a110beb3henrika@webrtc.org            return -1;
24644392d5f9f859b5d55b8017fafb09a496a110beb3henrika@webrtc.org        }
2465470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
2466470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    _sendTelephoneEventPayloadType = type;
2467470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    return 0;
2468470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com}
2469470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
2470470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.comint
2471470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.comChannel::GetSendTelephoneEventPayloadType(unsigned char& type)
2472470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com{
2473470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2474470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                 "Channel::GetSendTelephoneEventPayloadType()");
2475470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    type = _sendTelephoneEventPayloadType;
2476470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
2477470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com               VoEId(_instanceId,_channelId),
2478470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com               "GetSendTelephoneEventPayloadType() => type=%u", type);
2479470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    return 0;
2480470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com}
2481470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
2482470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.comint
2483470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.comChannel::UpdateRxVadDetection(AudioFrame& audioFrame)
2484470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com{
2485470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
2486470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                 "Channel::UpdateRxVadDetection()");
2487470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
2488470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    int vadDecision = 1;
2489470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
249063a509858d3988299726640c664b699d6229a1d4andrew@webrtc.org    vadDecision = (audioFrame.vad_activity_ == AudioFrame::kVadActive)? 1 : 0;
2491470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
2492470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    if ((vadDecision != _oldVadDecision) && _rxVadObserverPtr)
2493470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
2494470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        OnRxVadDetected(vadDecision);
2495470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        _oldVadDecision = vadDecision;
2496470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
2497470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
2498470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
2499470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                 "Channel::UpdateRxVadDetection() => vadDecision=%d",
2500470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                 vadDecision);
2501470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    return 0;
2502470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com}
2503470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
2504470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.comint
2505470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.comChannel::RegisterRxVadObserver(VoERxVadCallback &observer)
2506470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com{
2507470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2508470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                 "Channel::RegisterRxVadObserver()");
25099a065d1eae9ed296e1e2eaaad73d7ca1223bfe79mflodman@webrtc.org    CriticalSectionScoped cs(&_callbackCritSect);
2510470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
2511470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    if (_rxVadObserverPtr)
2512470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
2513470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        _engineStatisticsPtr->SetLastError(
2514470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            VE_INVALID_OPERATION, kTraceError,
2515470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            "RegisterRxVadObserver() observer already enabled");
2516470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        return -1;
2517470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
2518470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    _rxVadObserverPtr = &observer;
2519470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    _RxVadDetection = true;
2520470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    return 0;
2521470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com}
2522470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
2523470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.comint
2524470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.comChannel::DeRegisterRxVadObserver()
2525470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com{
2526470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2527470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                 "Channel::DeRegisterRxVadObserver()");
25289a065d1eae9ed296e1e2eaaad73d7ca1223bfe79mflodman@webrtc.org    CriticalSectionScoped cs(&_callbackCritSect);
2529470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
2530470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    if (!_rxVadObserverPtr)
2531470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
2532470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        _engineStatisticsPtr->SetLastError(
2533470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            VE_INVALID_OPERATION, kTraceWarning,
2534470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            "DeRegisterRxVadObserver() observer already disabled");
2535470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        return 0;
2536470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
2537470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    _rxVadObserverPtr = NULL;
2538470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    _RxVadDetection = false;
2539470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    return 0;
2540470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com}
2541470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
2542470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.comint
2543470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.comChannel::VoiceActivityIndicator(int &activity)
2544470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com{
2545470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    activity = _sendFrameType;
2546470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
2547470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
25486c264cc92eb554716814db200b84752d4dfb6ba3andrew@webrtc.org                 "Channel::VoiceActivityIndicator(indicator=%d)", activity);
2549470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    return 0;
2550470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com}
2551470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
2552470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com#ifdef WEBRTC_VOICE_ENGINE_AGC
2553470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
2554470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.comint
25559213521ea98b0977c7cdabd2853060835af226f3pbos@webrtc.orgChannel::SetRxAgcStatus(bool enable, AgcModes mode)
2556470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com{
2557470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2558470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                 "Channel::SetRxAgcStatus(enable=%d, mode=%d)",
2559470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                 (int)enable, (int)mode);
2560470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
25616c264cc92eb554716814db200b84752d4dfb6ba3andrew@webrtc.org    GainControl::Mode agcMode = kDefaultRxAgcMode;
2562470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    switch (mode)
2563470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
2564470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        case kAgcDefault:
2565470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            break;
2566470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        case kAgcUnchanged:
2567f3930e941c15da48c037c62cdb1eebbcbf89c9c7andrew@webrtc.org            agcMode = rx_audioproc_->gain_control()->mode();
2568470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            break;
2569470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        case kAgcFixedDigital:
2570470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            agcMode = GainControl::kFixedDigital;
2571470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            break;
2572470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        case kAgcAdaptiveDigital:
2573470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            agcMode =GainControl::kAdaptiveDigital;
2574470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            break;
2575470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        default:
2576470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            _engineStatisticsPtr->SetLastError(
2577470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                VE_INVALID_ARGUMENT, kTraceError,
2578470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                "SetRxAgcStatus() invalid Agc mode");
2579470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            return -1;
2580470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
2581470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
2582f3930e941c15da48c037c62cdb1eebbcbf89c9c7andrew@webrtc.org    if (rx_audioproc_->gain_control()->set_mode(agcMode) != 0)
2583470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
2584470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        _engineStatisticsPtr->SetLastError(
2585470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            VE_APM_ERROR, kTraceError,
2586470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            "SetRxAgcStatus() failed to set Agc mode");
2587470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        return -1;
2588470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
2589f3930e941c15da48c037c62cdb1eebbcbf89c9c7andrew@webrtc.org    if (rx_audioproc_->gain_control()->Enable(enable) != 0)
2590470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
2591470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        _engineStatisticsPtr->SetLastError(
2592470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            VE_APM_ERROR, kTraceError,
2593470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            "SetRxAgcStatus() failed to set Agc state");
2594470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        return -1;
2595470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
2596470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
2597470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    _rxAgcIsEnabled = enable;
2598944cbeb2926feb86a687e5fda9e2ac88ea8e3001henrika@webrtc.org    channel_state_.SetRxApmIsEnabled(_rxAgcIsEnabled || _rxNsIsEnabled);
2599470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
2600470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    return 0;
2601470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com}
2602470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
2603470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.comint
2604470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.comChannel::GetRxAgcStatus(bool& enabled, AgcModes& mode)
2605470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com{
2606470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2607470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                     "Channel::GetRxAgcStatus(enable=?, mode=?)");
2608470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
2609f3930e941c15da48c037c62cdb1eebbcbf89c9c7andrew@webrtc.org    bool enable = rx_audioproc_->gain_control()->is_enabled();
2610470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    GainControl::Mode agcMode =
2611f3930e941c15da48c037c62cdb1eebbcbf89c9c7andrew@webrtc.org        rx_audioproc_->gain_control()->mode();
2612470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
2613470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    enabled = enable;
2614470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
2615470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    switch (agcMode)
2616470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
2617470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        case GainControl::kFixedDigital:
2618470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            mode = kAgcFixedDigital;
2619470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            break;
2620470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        case GainControl::kAdaptiveDigital:
2621470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            mode = kAgcAdaptiveDigital;
2622470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            break;
2623470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        default:
2624470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            _engineStatisticsPtr->SetLastError(
2625470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                VE_APM_ERROR, kTraceError,
2626470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                "GetRxAgcStatus() invalid Agc mode");
2627470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            return -1;
2628470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
2629470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
2630470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    return 0;
2631470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com}
2632470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
2633470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.comint
26349213521ea98b0977c7cdabd2853060835af226f3pbos@webrtc.orgChannel::SetRxAgcConfig(AgcConfig config)
2635470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com{
2636470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2637470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                 "Channel::SetRxAgcConfig()");
2638470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
2639f3930e941c15da48c037c62cdb1eebbcbf89c9c7andrew@webrtc.org    if (rx_audioproc_->gain_control()->set_target_level_dbfs(
2640470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        config.targetLeveldBOv) != 0)
2641470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
2642470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        _engineStatisticsPtr->SetLastError(
2643470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            VE_APM_ERROR, kTraceError,
2644470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            "SetRxAgcConfig() failed to set target peak |level|"
2645470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            "(or envelope) of the Agc");
2646470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        return -1;
2647470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
2648f3930e941c15da48c037c62cdb1eebbcbf89c9c7andrew@webrtc.org    if (rx_audioproc_->gain_control()->set_compression_gain_db(
2649470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        config.digitalCompressionGaindB) != 0)
2650470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
2651470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        _engineStatisticsPtr->SetLastError(
2652470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            VE_APM_ERROR, kTraceError,
2653470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            "SetRxAgcConfig() failed to set the range in |gain| the"
2654470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            " digital compression stage may apply");
2655470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        return -1;
2656470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
2657f3930e941c15da48c037c62cdb1eebbcbf89c9c7andrew@webrtc.org    if (rx_audioproc_->gain_control()->enable_limiter(
2658470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        config.limiterEnable) != 0)
2659470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
2660470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        _engineStatisticsPtr->SetLastError(
2661470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            VE_APM_ERROR, kTraceError,
2662470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            "SetRxAgcConfig() failed to set hard limiter to the signal");
2663470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        return -1;
2664470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
2665470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
2666470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    return 0;
2667470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com}
2668470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
2669470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.comint
2670470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.comChannel::GetRxAgcConfig(AgcConfig& config)
2671470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com{
2672470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2673470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                 "Channel::GetRxAgcConfig(config=%?)");
2674470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
2675470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    config.targetLeveldBOv =
2676f3930e941c15da48c037c62cdb1eebbcbf89c9c7andrew@webrtc.org        rx_audioproc_->gain_control()->target_level_dbfs();
2677470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    config.digitalCompressionGaindB =
2678f3930e941c15da48c037c62cdb1eebbcbf89c9c7andrew@webrtc.org        rx_audioproc_->gain_control()->compression_gain_db();
2679470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    config.limiterEnable =
2680f3930e941c15da48c037c62cdb1eebbcbf89c9c7andrew@webrtc.org        rx_audioproc_->gain_control()->is_limiter_enabled();
2681470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
2682470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
2683470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com               VoEId(_instanceId,_channelId), "GetRxAgcConfig() => "
2684470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                   "targetLeveldBOv=%u, digitalCompressionGaindB=%u,"
2685470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                   " limiterEnable=%d",
2686470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                   config.targetLeveldBOv,
2687470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                   config.digitalCompressionGaindB,
2688470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                   config.limiterEnable);
2689470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
2690470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    return 0;
2691470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com}
2692470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
2693470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com#endif // #ifdef WEBRTC_VOICE_ENGINE_AGC
2694470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
2695470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com#ifdef WEBRTC_VOICE_ENGINE_NR
2696470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
2697470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.comint
26989213521ea98b0977c7cdabd2853060835af226f3pbos@webrtc.orgChannel::SetRxNsStatus(bool enable, NsModes mode)
2699470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com{
2700470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2701470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                 "Channel::SetRxNsStatus(enable=%d, mode=%d)",
2702470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                 (int)enable, (int)mode);
2703470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
27046c264cc92eb554716814db200b84752d4dfb6ba3andrew@webrtc.org    NoiseSuppression::Level nsLevel = kDefaultNsMode;
2705470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    switch (mode)
2706470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
2707470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
2708470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        case kNsDefault:
2709470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            break;
2710470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        case kNsUnchanged:
2711f3930e941c15da48c037c62cdb1eebbcbf89c9c7andrew@webrtc.org            nsLevel = rx_audioproc_->noise_suppression()->level();
2712470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            break;
2713470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        case kNsConference:
2714470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            nsLevel = NoiseSuppression::kHigh;
2715470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            break;
2716470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        case kNsLowSuppression:
2717470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            nsLevel = NoiseSuppression::kLow;
2718470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            break;
2719470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        case kNsModerateSuppression:
2720470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            nsLevel = NoiseSuppression::kModerate;
2721470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            break;
2722470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        case kNsHighSuppression:
2723470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            nsLevel = NoiseSuppression::kHigh;
2724470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            break;
2725470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        case kNsVeryHighSuppression:
2726470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            nsLevel = NoiseSuppression::kVeryHigh;
2727470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            break;
2728470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
2729470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
2730f3930e941c15da48c037c62cdb1eebbcbf89c9c7andrew@webrtc.org    if (rx_audioproc_->noise_suppression()->set_level(nsLevel)
2731470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        != 0)
2732470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
2733470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        _engineStatisticsPtr->SetLastError(
2734470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            VE_APM_ERROR, kTraceError,
27356c264cc92eb554716814db200b84752d4dfb6ba3andrew@webrtc.org            "SetRxNsStatus() failed to set NS level");
2736470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        return -1;
2737470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
2738f3930e941c15da48c037c62cdb1eebbcbf89c9c7andrew@webrtc.org    if (rx_audioproc_->noise_suppression()->Enable(enable) != 0)
2739470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
2740470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        _engineStatisticsPtr->SetLastError(
2741470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            VE_APM_ERROR, kTraceError,
27426c264cc92eb554716814db200b84752d4dfb6ba3andrew@webrtc.org            "SetRxNsStatus() failed to set NS state");
2743470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        return -1;
2744470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
2745470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
2746470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    _rxNsIsEnabled = enable;
2747944cbeb2926feb86a687e5fda9e2ac88ea8e3001henrika@webrtc.org    channel_state_.SetRxApmIsEnabled(_rxAgcIsEnabled || _rxNsIsEnabled);
2748470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
2749470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    return 0;
2750470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com}
2751470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
2752470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.comint
2753470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.comChannel::GetRxNsStatus(bool& enabled, NsModes& mode)
2754470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com{
2755470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2756470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                 "Channel::GetRxNsStatus(enable=?, mode=?)");
2757470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
2758470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    bool enable =
2759f3930e941c15da48c037c62cdb1eebbcbf89c9c7andrew@webrtc.org        rx_audioproc_->noise_suppression()->is_enabled();
2760470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    NoiseSuppression::Level ncLevel =
2761f3930e941c15da48c037c62cdb1eebbcbf89c9c7andrew@webrtc.org        rx_audioproc_->noise_suppression()->level();
2762470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
2763470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    enabled = enable;
2764470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
2765470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    switch (ncLevel)
2766470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
2767470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        case NoiseSuppression::kLow:
2768470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            mode = kNsLowSuppression;
2769470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            break;
2770470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        case NoiseSuppression::kModerate:
2771470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            mode = kNsModerateSuppression;
2772470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            break;
2773470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        case NoiseSuppression::kHigh:
2774470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            mode = kNsHighSuppression;
2775470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            break;
2776470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        case NoiseSuppression::kVeryHigh:
2777470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            mode = kNsVeryHighSuppression;
2778470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            break;
2779470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
2780470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
2781470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
2782470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com               VoEId(_instanceId,_channelId),
2783470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com               "GetRxNsStatus() => enabled=%d, mode=%d", enabled, mode);
2784470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    return 0;
2785470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com}
2786470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
2787470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com#endif // #ifdef WEBRTC_VOICE_ENGINE_NR
2788470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
2789470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.comint
2790470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.comChannel::SetLocalSSRC(unsigned int ssrc)
2791470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com{
2792470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
2793470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                 "Channel::SetLocalSSRC()");
2794944cbeb2926feb86a687e5fda9e2ac88ea8e3001henrika@webrtc.org    if (channel_state_.Get().sending)
2795470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
2796470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        _engineStatisticsPtr->SetLastError(
2797470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            VE_ALREADY_SENDING, kTraceError,
2798470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            "SetLocalSSRC() already sending");
2799470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        return -1;
2800470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
2801ef92755780253c6a7940c89598a206e58e05b810stefan@webrtc.org    _rtpRtcpModule->SetSSRC(ssrc);
2802470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    return 0;
2803470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com}
2804470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
2805470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.comint
2806470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.comChannel::GetLocalSSRC(unsigned int& ssrc)
2807470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com{
28082853dde5201d9ddc284ce5efb9688f6340487acepwestin@webrtc.org    ssrc = _rtpRtcpModule->SSRC();
2809470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
2810470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                 VoEId(_instanceId,_channelId),
2811470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                 "GetLocalSSRC() => ssrc=%lu", ssrc);
2812470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    return 0;
2813470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com}
2814470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
2815470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.comint
2816470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.comChannel::GetRemoteSSRC(unsigned int& ssrc)
2817470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com{
2818822fbd8b68ffdb481b9557e2950ae8d6657c8ce6wu@webrtc.org    ssrc = rtp_receiver_->SSRC();
2819470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
2820470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                 VoEId(_instanceId,_channelId),
2821470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                 "GetRemoteSSRC() => ssrc=%lu", ssrc);
2822470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    return 0;
2823470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com}
2824470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
2825ebdb0e3ad0a787bee066d12cdcd115a38b0a10d1wu@webrtc.orgint Channel::SetSendAudioLevelIndicationStatus(bool enable, unsigned char id) {
2826f3930e941c15da48c037c62cdb1eebbcbf89c9c7andrew@webrtc.org  _includeAudioLevelIndication = enable;
2827ebdb0e3ad0a787bee066d12cdcd115a38b0a10d1wu@webrtc.org  return SetSendRtpHeaderExtension(enable, kRtpExtensionAudioLevel, id);
2828470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com}
2829f3930e941c15da48c037c62cdb1eebbcbf89c9c7andrew@webrtc.org
283093fd25c20c688961569d3631b875c8ee0dfc2a80wu@webrtc.orgint Channel::SetReceiveAudioLevelIndicationStatus(bool enable,
283193fd25c20c688961569d3631b875c8ee0dfc2a80wu@webrtc.org                                                  unsigned char id) {
283293fd25c20c688961569d3631b875c8ee0dfc2a80wu@webrtc.org  rtp_header_parser_->DeregisterRtpHeaderExtension(
283393fd25c20c688961569d3631b875c8ee0dfc2a80wu@webrtc.org      kRtpExtensionAudioLevel);
283493fd25c20c688961569d3631b875c8ee0dfc2a80wu@webrtc.org  if (enable && !rtp_header_parser_->RegisterRtpHeaderExtension(
283593fd25c20c688961569d3631b875c8ee0dfc2a80wu@webrtc.org          kRtpExtensionAudioLevel, id)) {
283693fd25c20c688961569d3631b875c8ee0dfc2a80wu@webrtc.org    return -1;
283793fd25c20c688961569d3631b875c8ee0dfc2a80wu@webrtc.org  }
283893fd25c20c688961569d3631b875c8ee0dfc2a80wu@webrtc.org  return 0;
283993fd25c20c688961569d3631b875c8ee0dfc2a80wu@webrtc.org}
284093fd25c20c688961569d3631b875c8ee0dfc2a80wu@webrtc.org
2841ebdb0e3ad0a787bee066d12cdcd115a38b0a10d1wu@webrtc.orgint Channel::SetSendAbsoluteSenderTimeStatus(bool enable, unsigned char id) {
2842ebdb0e3ad0a787bee066d12cdcd115a38b0a10d1wu@webrtc.org  return SetSendRtpHeaderExtension(enable, kRtpExtensionAbsoluteSendTime, id);
2843ebdb0e3ad0a787bee066d12cdcd115a38b0a10d1wu@webrtc.org}
2844ebdb0e3ad0a787bee066d12cdcd115a38b0a10d1wu@webrtc.org
2845ebdb0e3ad0a787bee066d12cdcd115a38b0a10d1wu@webrtc.orgint Channel::SetReceiveAbsoluteSenderTimeStatus(bool enable, unsigned char id) {
2846ebdb0e3ad0a787bee066d12cdcd115a38b0a10d1wu@webrtc.org  rtp_header_parser_->DeregisterRtpHeaderExtension(
2847ebdb0e3ad0a787bee066d12cdcd115a38b0a10d1wu@webrtc.org      kRtpExtensionAbsoluteSendTime);
2848b1f50100757036cf475072c26f5f374eee9588casolenberg@webrtc.org  if (enable && !rtp_header_parser_->RegisterRtpHeaderExtension(
2849b1f50100757036cf475072c26f5f374eee9588casolenberg@webrtc.org      kRtpExtensionAbsoluteSendTime, id)) {
2850b1f50100757036cf475072c26f5f374eee9588casolenberg@webrtc.org    return -1;
2851ebdb0e3ad0a787bee066d12cdcd115a38b0a10d1wu@webrtc.org  }
2852ebdb0e3ad0a787bee066d12cdcd115a38b0a10d1wu@webrtc.org  return 0;
2853470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com}
2854470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
2855d16e839c6d29831e79312180085b6a19149df43fpbos@webrtc.orgvoid Channel::SetRTCPStatus(bool enable) {
2856d16e839c6d29831e79312180085b6a19149df43fpbos@webrtc.org  WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
2857d16e839c6d29831e79312180085b6a19149df43fpbos@webrtc.org               "Channel::SetRTCPStatus()");
2858d16e839c6d29831e79312180085b6a19149df43fpbos@webrtc.org  _rtpRtcpModule->SetRTCPStatus(enable ? kRtcpCompound : kRtcpOff);
2859470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com}
2860470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
2861470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.comint
2862470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.comChannel::GetRTCPStatus(bool& enabled)
2863470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com{
28642853dde5201d9ddc284ce5efb9688f6340487acepwestin@webrtc.org    RTCPMethod method = _rtpRtcpModule->RTCP();
2865470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    enabled = (method != kRtcpOff);
2866470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
2867470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                 VoEId(_instanceId,_channelId),
2868470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                 "GetRTCPStatus() => enabled=%d", enabled);
2869470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    return 0;
2870470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com}
2871470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
2872470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.comint
2873470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.comChannel::SetRTCP_CNAME(const char cName[256])
2874470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com{
2875470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
2876470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                 "Channel::SetRTCP_CNAME()");
28772853dde5201d9ddc284ce5efb9688f6340487acepwestin@webrtc.org    if (_rtpRtcpModule->SetCNAME(cName) != 0)
2878470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
2879470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        _engineStatisticsPtr->SetLastError(
2880470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            VE_RTP_RTCP_MODULE_ERROR, kTraceError,
2881470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            "SetRTCP_CNAME() failed to set RTCP CNAME");
2882470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        return -1;
2883470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
2884470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    return 0;
2885470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com}
2886470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
2887470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.comint
2888470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.comChannel::GetRemoteRTCP_CNAME(char cName[256])
2889470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com{
2890470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    if (cName == NULL)
2891470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
2892470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        _engineStatisticsPtr->SetLastError(
2893470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            VE_INVALID_ARGUMENT, kTraceError,
2894470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            "GetRemoteRTCP_CNAME() invalid CNAME input buffer");
2895470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        return -1;
2896470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
2897813e4b0af06272dada388c2d8383b2e36a1da6a6leozwang@webrtc.org    char cname[RTCP_CNAME_SIZE];
2898822fbd8b68ffdb481b9557e2950ae8d6657c8ce6wu@webrtc.org    const uint32_t remoteSSRC = rtp_receiver_->SSRC();
28992853dde5201d9ddc284ce5efb9688f6340487acepwestin@webrtc.org    if (_rtpRtcpModule->RemoteCNAME(remoteSSRC, cname) != 0)
2900470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
2901470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        _engineStatisticsPtr->SetLastError(
2902470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            VE_CANNOT_RETRIEVE_CNAME, kTraceError,
2903470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            "GetRemoteRTCP_CNAME() failed to retrieve remote RTCP CNAME");
2904470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        return -1;
2905470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
2906470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    strcpy(cName, cname);
2907470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
2908470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                 VoEId(_instanceId, _channelId),
2909470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                 "GetRemoteRTCP_CNAME() => cName=%s", cName);
2910470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    return 0;
2911470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com}
2912470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
2913470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.comint
2914470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.comChannel::GetRemoteRTCPData(
2915470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    unsigned int& NTPHigh,
2916470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    unsigned int& NTPLow,
2917470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    unsigned int& timestamp,
2918470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    unsigned int& playoutTimestamp,
2919470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    unsigned int* jitter,
2920470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    unsigned short* fractionLost)
2921470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com{
2922470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    // --- Information from sender info in received Sender Reports
2923470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
2924470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    RTCPSenderInfo senderInfo;
29252853dde5201d9ddc284ce5efb9688f6340487acepwestin@webrtc.org    if (_rtpRtcpModule->RemoteRTCPStat(&senderInfo) != 0)
2926470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
2927470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        _engineStatisticsPtr->SetLastError(
2928470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            VE_RTP_RTCP_MODULE_ERROR, kTraceError,
2929fcd12b3b7d7e92d6f8cdfdf8277808ae52a07c36wu@webrtc.org            "GetRemoteRTCPData() failed to retrieve sender info for remote "
2930470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            "side");
2931470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        return -1;
2932470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
2933470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
2934470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    // We only utilize 12 out of 20 bytes in the sender info (ignores packet
2935470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    // and octet count)
2936470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    NTPHigh = senderInfo.NTPseconds;
2937470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    NTPLow = senderInfo.NTPfraction;
2938470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    timestamp = senderInfo.RTPtimeStamp;
2939470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
2940470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
2941470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                 VoEId(_instanceId, _channelId),
2942470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                 "GetRemoteRTCPData() => NTPHigh=%lu, NTPLow=%lu, "
2943470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                 "timestamp=%lu",
2944470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                 NTPHigh, NTPLow, timestamp);
2945470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
2946470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    // --- Locally derived information
2947470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
2948470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    // This value is updated on each incoming RTCP packet (0 when no packet
2949470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    // has been received)
29501de01354e68da71bc62c81af17afeac8ed374a18pwestin@webrtc.org    playoutTimestamp = playout_timestamp_rtcp_;
2951470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
2952470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
2953470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                 VoEId(_instanceId, _channelId),
2954470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                 "GetRemoteRTCPData() => playoutTimestamp=%lu",
29551de01354e68da71bc62c81af17afeac8ed374a18pwestin@webrtc.org                 playout_timestamp_rtcp_);
2956470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
2957470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    if (NULL != jitter || NULL != fractionLost)
2958470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
2959ce5990cb0bbfbf5ee5306cf990e975a2faa090b7perkj@webrtc.org        // Get all RTCP receiver report blocks that have been received on this
2960ce5990cb0bbfbf5ee5306cf990e975a2faa090b7perkj@webrtc.org        // channel. If we receive RTP packets from a remote source we know the
2961ce5990cb0bbfbf5ee5306cf990e975a2faa090b7perkj@webrtc.org        // remote SSRC and use the report block from him.
2962ce5990cb0bbfbf5ee5306cf990e975a2faa090b7perkj@webrtc.org        // Otherwise use the first report block.
2963ce5990cb0bbfbf5ee5306cf990e975a2faa090b7perkj@webrtc.org        std::vector<RTCPReportBlock> remote_stats;
29642853dde5201d9ddc284ce5efb9688f6340487acepwestin@webrtc.org        if (_rtpRtcpModule->RemoteRTCPStat(&remote_stats) != 0 ||
2965ce5990cb0bbfbf5ee5306cf990e975a2faa090b7perkj@webrtc.org            remote_stats.empty()) {
2966ce5990cb0bbfbf5ee5306cf990e975a2faa090b7perkj@webrtc.org          WEBRTC_TRACE(kTraceWarning, kTraceVoice,
2967ce5990cb0bbfbf5ee5306cf990e975a2faa090b7perkj@webrtc.org                       VoEId(_instanceId, _channelId),
2968ce5990cb0bbfbf5ee5306cf990e975a2faa090b7perkj@webrtc.org                       "GetRemoteRTCPData() failed to measure statistics due"
2969ce5990cb0bbfbf5ee5306cf990e975a2faa090b7perkj@webrtc.org                       " to lack of received RTP and/or RTCP packets");
2970ce5990cb0bbfbf5ee5306cf990e975a2faa090b7perkj@webrtc.org          return -1;
2971470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        }
2972ce5990cb0bbfbf5ee5306cf990e975a2faa090b7perkj@webrtc.org
2973822fbd8b68ffdb481b9557e2950ae8d6657c8ce6wu@webrtc.org        uint32_t remoteSSRC = rtp_receiver_->SSRC();
2974ce5990cb0bbfbf5ee5306cf990e975a2faa090b7perkj@webrtc.org        std::vector<RTCPReportBlock>::const_iterator it = remote_stats.begin();
2975ce5990cb0bbfbf5ee5306cf990e975a2faa090b7perkj@webrtc.org        for (; it != remote_stats.end(); ++it) {
2976ce5990cb0bbfbf5ee5306cf990e975a2faa090b7perkj@webrtc.org          if (it->remoteSSRC == remoteSSRC)
2977ce5990cb0bbfbf5ee5306cf990e975a2faa090b7perkj@webrtc.org            break;
2978470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        }
2979ce5990cb0bbfbf5ee5306cf990e975a2faa090b7perkj@webrtc.org
2980ce5990cb0bbfbf5ee5306cf990e975a2faa090b7perkj@webrtc.org        if (it == remote_stats.end()) {
2981ce5990cb0bbfbf5ee5306cf990e975a2faa090b7perkj@webrtc.org          // If we have not received any RTCP packets from this SSRC it probably
2982ce5990cb0bbfbf5ee5306cf990e975a2faa090b7perkj@webrtc.org          // means that we have not received any RTP packets.
2983ce5990cb0bbfbf5ee5306cf990e975a2faa090b7perkj@webrtc.org          // Use the first received report block instead.
2984ce5990cb0bbfbf5ee5306cf990e975a2faa090b7perkj@webrtc.org          it = remote_stats.begin();
2985ce5990cb0bbfbf5ee5306cf990e975a2faa090b7perkj@webrtc.org          remoteSSRC = it->remoteSSRC;
2986470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        }
2987ce5990cb0bbfbf5ee5306cf990e975a2faa090b7perkj@webrtc.org
298879af734807109d119573ce23daa1a2bff0f0eecaxians@webrtc.org        if (jitter) {
298979af734807109d119573ce23daa1a2bff0f0eecaxians@webrtc.org          *jitter = it->jitter;
299079af734807109d119573ce23daa1a2bff0f0eecaxians@webrtc.org          WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
299179af734807109d119573ce23daa1a2bff0f0eecaxians@webrtc.org                       VoEId(_instanceId, _channelId),
299279af734807109d119573ce23daa1a2bff0f0eecaxians@webrtc.org                       "GetRemoteRTCPData() => jitter = %lu", *jitter);
299379af734807109d119573ce23daa1a2bff0f0eecaxians@webrtc.org        }
2994ce5990cb0bbfbf5ee5306cf990e975a2faa090b7perkj@webrtc.org
299579af734807109d119573ce23daa1a2bff0f0eecaxians@webrtc.org        if (fractionLost) {
299679af734807109d119573ce23daa1a2bff0f0eecaxians@webrtc.org          *fractionLost = it->fractionLost;
299779af734807109d119573ce23daa1a2bff0f0eecaxians@webrtc.org          WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
299879af734807109d119573ce23daa1a2bff0f0eecaxians@webrtc.org                       VoEId(_instanceId, _channelId),
299979af734807109d119573ce23daa1a2bff0f0eecaxians@webrtc.org                       "GetRemoteRTCPData() => fractionLost = %lu",
300079af734807109d119573ce23daa1a2bff0f0eecaxians@webrtc.org                       *fractionLost);
300179af734807109d119573ce23daa1a2bff0f0eecaxians@webrtc.org        }
3002470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
3003470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    return 0;
3004470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com}
3005470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
3006470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.comint
30079213521ea98b0977c7cdabd2853060835af226f3pbos@webrtc.orgChannel::SendApplicationDefinedRTCPPacket(unsigned char subType,
3008470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                                             unsigned int name,
3009470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                                             const char* data,
3010470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                                             unsigned short dataLengthInBytes)
3011470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com{
3012470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
3013470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                 "Channel::SendApplicationDefinedRTCPPacket()");
3014944cbeb2926feb86a687e5fda9e2ac88ea8e3001henrika@webrtc.org    if (!channel_state_.Get().sending)
3015470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
3016470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        _engineStatisticsPtr->SetLastError(
3017470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            VE_NOT_SENDING, kTraceError,
3018470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            "SendApplicationDefinedRTCPPacket() not sending");
3019470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        return -1;
3020470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
3021470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    if (NULL == data)
3022470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
3023470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        _engineStatisticsPtr->SetLastError(
3024470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            VE_INVALID_ARGUMENT, kTraceError,
3025470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            "SendApplicationDefinedRTCPPacket() invalid data value");
3026470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        return -1;
3027470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
3028470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    if (dataLengthInBytes % 4 != 0)
3029470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
3030470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        _engineStatisticsPtr->SetLastError(
3031470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            VE_INVALID_ARGUMENT, kTraceError,
3032470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            "SendApplicationDefinedRTCPPacket() invalid length value");
3033470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        return -1;
3034470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
30352853dde5201d9ddc284ce5efb9688f6340487acepwestin@webrtc.org    RTCPMethod status = _rtpRtcpModule->RTCP();
3036470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    if (status == kRtcpOff)
3037470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
3038470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        _engineStatisticsPtr->SetLastError(
3039470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            VE_RTCP_ERROR, kTraceError,
3040470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            "SendApplicationDefinedRTCPPacket() RTCP is disabled");
3041470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        return -1;
3042470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
3043470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
3044470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    // Create and schedule the RTCP APP packet for transmission
30452853dde5201d9ddc284ce5efb9688f6340487acepwestin@webrtc.org    if (_rtpRtcpModule->SetRTCPApplicationSpecificData(
3046470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        subType,
3047470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        name,
3048470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        (const unsigned char*) data,
3049470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        dataLengthInBytes) != 0)
3050470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
3051470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        _engineStatisticsPtr->SetLastError(
3052470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            VE_SEND_ERROR, kTraceError,
3053470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            "SendApplicationDefinedRTCPPacket() failed to send RTCP packet");
3054470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        return -1;
3055470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
3056470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    return 0;
3057470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com}
3058470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
3059470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.comint
3060470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.comChannel::GetRTPStatistics(
3061470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        unsigned int& averageJitterMs,
3062470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        unsigned int& maxJitterMs,
3063470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        unsigned int& discardedPackets)
3064470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com{
3065470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    // The jitter statistics is updated for each received RTP packet and is
3066470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    // based on received packets.
306754ae4ffb9e235a9742e2b11298327e02d870571csprang@webrtc.org    if (_rtpRtcpModule->RTCP() == kRtcpOff) {
306854ae4ffb9e235a9742e2b11298327e02d870571csprang@webrtc.org      // If RTCP is off, there is no timed thread in the RTCP module regularly
306954ae4ffb9e235a9742e2b11298327e02d870571csprang@webrtc.org      // generating new stats, trigger the update manually here instead.
307054ae4ffb9e235a9742e2b11298327e02d870571csprang@webrtc.org      StreamStatistician* statistician =
307154ae4ffb9e235a9742e2b11298327e02d870571csprang@webrtc.org          rtp_receive_statistics_->GetStatistician(rtp_receiver_->SSRC());
307254ae4ffb9e235a9742e2b11298327e02d870571csprang@webrtc.org      if (statistician) {
307354ae4ffb9e235a9742e2b11298327e02d870571csprang@webrtc.org        // Don't use returned statistics, use data from proxy instead so that
307454ae4ffb9e235a9742e2b11298327e02d870571csprang@webrtc.org        // max jitter can be fetched atomically.
307554ae4ffb9e235a9742e2b11298327e02d870571csprang@webrtc.org        RtcpStatistics s;
307654ae4ffb9e235a9742e2b11298327e02d870571csprang@webrtc.org        statistician->GetStatistics(&s, true);
307754ae4ffb9e235a9742e2b11298327e02d870571csprang@webrtc.org      }
3078470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
3079470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
308054ae4ffb9e235a9742e2b11298327e02d870571csprang@webrtc.org    ChannelStatistics stats = statistics_proxy_->GetStats();
3081eb524d997b877ba9b0bcaf8c85eae52bd40c37e3andrew@webrtc.org    const int32_t playoutFrequency = audio_coding_->PlayoutFrequency();
308254ae4ffb9e235a9742e2b11298327e02d870571csprang@webrtc.org    if (playoutFrequency > 0) {
308354ae4ffb9e235a9742e2b11298327e02d870571csprang@webrtc.org      // Scale RTP statistics given the current playout frequency
308454ae4ffb9e235a9742e2b11298327e02d870571csprang@webrtc.org      maxJitterMs = stats.max_jitter / (playoutFrequency / 1000);
308554ae4ffb9e235a9742e2b11298327e02d870571csprang@webrtc.org      averageJitterMs = stats.rtcp.jitter / (playoutFrequency / 1000);
3086470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
3087470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
3088470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    discardedPackets = _numberOfDiscardedPackets;
3089470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
3090470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3091470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com               VoEId(_instanceId, _channelId),
3092470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com               "GetRTPStatistics() => averageJitterMs = %lu, maxJitterMs = %lu,"
3093fcd12b3b7d7e92d6f8cdfdf8277808ae52a07c36wu@webrtc.org               " discardedPackets = %lu)",
3094470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com               averageJitterMs, maxJitterMs, discardedPackets);
3095470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    return 0;
3096470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com}
3097470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
30988a2fc88459dc507a67594e3127143e16af612fc9henrika@webrtc.orgint Channel::GetRemoteRTCPReportBlocks(
30998a2fc88459dc507a67594e3127143e16af612fc9henrika@webrtc.org    std::vector<ReportBlock>* report_blocks) {
31008a2fc88459dc507a67594e3127143e16af612fc9henrika@webrtc.org  if (report_blocks == NULL) {
31018a2fc88459dc507a67594e3127143e16af612fc9henrika@webrtc.org    _engineStatisticsPtr->SetLastError(VE_INVALID_ARGUMENT, kTraceError,
31028a2fc88459dc507a67594e3127143e16af612fc9henrika@webrtc.org      "GetRemoteRTCPReportBlock()s invalid report_blocks.");
31038a2fc88459dc507a67594e3127143e16af612fc9henrika@webrtc.org    return -1;
31048a2fc88459dc507a67594e3127143e16af612fc9henrika@webrtc.org  }
31058a2fc88459dc507a67594e3127143e16af612fc9henrika@webrtc.org
31068a2fc88459dc507a67594e3127143e16af612fc9henrika@webrtc.org  // Get the report blocks from the latest received RTCP Sender or Receiver
31078a2fc88459dc507a67594e3127143e16af612fc9henrika@webrtc.org  // Report. Each element in the vector contains the sender's SSRC and a
31088a2fc88459dc507a67594e3127143e16af612fc9henrika@webrtc.org  // report block according to RFC 3550.
31098a2fc88459dc507a67594e3127143e16af612fc9henrika@webrtc.org  std::vector<RTCPReportBlock> rtcp_report_blocks;
31108a2fc88459dc507a67594e3127143e16af612fc9henrika@webrtc.org  if (_rtpRtcpModule->RemoteRTCPStat(&rtcp_report_blocks) != 0) {
31118a2fc88459dc507a67594e3127143e16af612fc9henrika@webrtc.org    _engineStatisticsPtr->SetLastError(VE_RTP_RTCP_MODULE_ERROR, kTraceError,
31128a2fc88459dc507a67594e3127143e16af612fc9henrika@webrtc.org        "GetRemoteRTCPReportBlocks() failed to read RTCP SR/RR report block.");
31138a2fc88459dc507a67594e3127143e16af612fc9henrika@webrtc.org    return -1;
31148a2fc88459dc507a67594e3127143e16af612fc9henrika@webrtc.org  }
31158a2fc88459dc507a67594e3127143e16af612fc9henrika@webrtc.org
31168a2fc88459dc507a67594e3127143e16af612fc9henrika@webrtc.org  if (rtcp_report_blocks.empty())
31178a2fc88459dc507a67594e3127143e16af612fc9henrika@webrtc.org    return 0;
31188a2fc88459dc507a67594e3127143e16af612fc9henrika@webrtc.org
31198a2fc88459dc507a67594e3127143e16af612fc9henrika@webrtc.org  std::vector<RTCPReportBlock>::const_iterator it = rtcp_report_blocks.begin();
31208a2fc88459dc507a67594e3127143e16af612fc9henrika@webrtc.org  for (; it != rtcp_report_blocks.end(); ++it) {
31218a2fc88459dc507a67594e3127143e16af612fc9henrika@webrtc.org    ReportBlock report_block;
31228a2fc88459dc507a67594e3127143e16af612fc9henrika@webrtc.org    report_block.sender_SSRC = it->remoteSSRC;
31238a2fc88459dc507a67594e3127143e16af612fc9henrika@webrtc.org    report_block.source_SSRC = it->sourceSSRC;
31248a2fc88459dc507a67594e3127143e16af612fc9henrika@webrtc.org    report_block.fraction_lost = it->fractionLost;
31258a2fc88459dc507a67594e3127143e16af612fc9henrika@webrtc.org    report_block.cumulative_num_packets_lost = it->cumulativeLost;
31268a2fc88459dc507a67594e3127143e16af612fc9henrika@webrtc.org    report_block.extended_highest_sequence_number = it->extendedHighSeqNum;
31278a2fc88459dc507a67594e3127143e16af612fc9henrika@webrtc.org    report_block.interarrival_jitter = it->jitter;
31288a2fc88459dc507a67594e3127143e16af612fc9henrika@webrtc.org    report_block.last_SR_timestamp = it->lastSR;
31298a2fc88459dc507a67594e3127143e16af612fc9henrika@webrtc.org    report_block.delay_since_last_SR = it->delaySinceLastSR;
31308a2fc88459dc507a67594e3127143e16af612fc9henrika@webrtc.org    report_blocks->push_back(report_block);
31318a2fc88459dc507a67594e3127143e16af612fc9henrika@webrtc.org  }
31328a2fc88459dc507a67594e3127143e16af612fc9henrika@webrtc.org  return 0;
31338a2fc88459dc507a67594e3127143e16af612fc9henrika@webrtc.org}
31348a2fc88459dc507a67594e3127143e16af612fc9henrika@webrtc.org
3135470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.comint
3136470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.comChannel::GetRTPStatistics(CallStatistics& stats)
3137470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com{
3138cb711f77d2ff9ebd42678869a73353809b3af66ewu@webrtc.org    // --- RtcpStatistics
3139470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
3140470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    // The jitter statistics is updated for each received RTP packet and is
3141470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    // based on received packets.
314254ae4ffb9e235a9742e2b11298327e02d870571csprang@webrtc.org    RtcpStatistics statistics;
3143286fe0b04d97205ac84688bbe613d5749192b2d1stefan@webrtc.org    StreamStatistician* statistician =
3144286fe0b04d97205ac84688bbe613d5749192b2d1stefan@webrtc.org        rtp_receive_statistics_->GetStatistician(rtp_receiver_->SSRC());
3145286fe0b04d97205ac84688bbe613d5749192b2d1stefan@webrtc.org    if (!statistician || !statistician->GetStatistics(
3146822fbd8b68ffdb481b9557e2950ae8d6657c8ce6wu@webrtc.org        &statistics, _rtpRtcpModule->RTCP() == kRtcpOff)) {
3147822fbd8b68ffdb481b9557e2950ae8d6657c8ce6wu@webrtc.org      _engineStatisticsPtr->SetLastError(
3148822fbd8b68ffdb481b9557e2950ae8d6657c8ce6wu@webrtc.org          VE_CANNOT_RETRIEVE_RTP_STAT, kTraceWarning,
3149822fbd8b68ffdb481b9557e2950ae8d6657c8ce6wu@webrtc.org          "GetRTPStatistics() failed to read RTP statistics from the "
3150822fbd8b68ffdb481b9557e2950ae8d6657c8ce6wu@webrtc.org          "RTP/RTCP module");
3151470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
3152470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
3153822fbd8b68ffdb481b9557e2950ae8d6657c8ce6wu@webrtc.org    stats.fractionLost = statistics.fraction_lost;
3154822fbd8b68ffdb481b9557e2950ae8d6657c8ce6wu@webrtc.org    stats.cumulativeLost = statistics.cumulative_lost;
3155822fbd8b68ffdb481b9557e2950ae8d6657c8ce6wu@webrtc.org    stats.extendedMax = statistics.extended_max_sequence_number;
3156822fbd8b68ffdb481b9557e2950ae8d6657c8ce6wu@webrtc.org    stats.jitterSamples = statistics.jitter;
3157470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
3158470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3159470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                 VoEId(_instanceId, _channelId),
3160470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                 "GetRTPStatistics() => fractionLost=%lu, cumulativeLost=%lu,"
3161fcd12b3b7d7e92d6f8cdfdf8277808ae52a07c36wu@webrtc.org                 " extendedMax=%lu, jitterSamples=%li)",
3162470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                 stats.fractionLost, stats.cumulativeLost, stats.extendedMax,
3163470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                 stats.jitterSamples);
3164470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
3165cb711f77d2ff9ebd42678869a73353809b3af66ewu@webrtc.org    // --- RTT
31662013aeced2b7821a407f302802c4a16fd02728b1Minyue    stats.rttMs = GetRTT(true);
31676fd930842055525b5c7cff412735515dd463571aminyue@webrtc.org    if (stats.rttMs == 0) {
31686fd930842055525b5c7cff412735515dd463571aminyue@webrtc.org      WEBRTC_TRACE(kTraceWarning, kTraceVoice, VoEId(_instanceId, _channelId),
31696fd930842055525b5c7cff412735515dd463571aminyue@webrtc.org                   "GetRTPStatistics() failed to get RTT");
31706fd930842055525b5c7cff412735515dd463571aminyue@webrtc.org    } else {
31716fd930842055525b5c7cff412735515dd463571aminyue@webrtc.org      WEBRTC_TRACE(kTraceStateInfo, kTraceVoice, VoEId(_instanceId, _channelId),
317216825b1a828bb4ff40f7682040e43a239b7b8ca3pkasting@chromium.org                   "GetRTPStatistics() => rttMs=%" PRId64, stats.rttMs);
31736fd930842055525b5c7cff412735515dd463571aminyue@webrtc.org    }
3174470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
3175cb711f77d2ff9ebd42678869a73353809b3af66ewu@webrtc.org    // --- Data counters
3176470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
31774591fbd09f9cb6e83433c49a12dd8524c2806502pkasting@chromium.org    size_t bytesSent(0);
31786141e13873d0fdea626de08dfec2efa2c9171c76pbos@webrtc.org    uint32_t packetsSent(0);
31794591fbd09f9cb6e83433c49a12dd8524c2806502pkasting@chromium.org    size_t bytesReceived(0);
31806141e13873d0fdea626de08dfec2efa2c9171c76pbos@webrtc.org    uint32_t packetsReceived(0);
3181470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
3182286fe0b04d97205ac84688bbe613d5749192b2d1stefan@webrtc.org    if (statistician) {
3183286fe0b04d97205ac84688bbe613d5749192b2d1stefan@webrtc.org      statistician->GetDataCounters(&bytesReceived, &packetsReceived);
3184286fe0b04d97205ac84688bbe613d5749192b2d1stefan@webrtc.org    }
3185822fbd8b68ffdb481b9557e2950ae8d6657c8ce6wu@webrtc.org
31862853dde5201d9ddc284ce5efb9688f6340487acepwestin@webrtc.org    if (_rtpRtcpModule->DataCountersRTP(&bytesSent,
3187822fbd8b68ffdb481b9557e2950ae8d6657c8ce6wu@webrtc.org                                        &packetsSent) != 0)
3188470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
3189470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        WEBRTC_TRACE(kTraceWarning, kTraceVoice,
3190470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                     VoEId(_instanceId, _channelId),
3191470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                     "GetRTPStatistics() failed to retrieve RTP datacounters =>"
3192fcd12b3b7d7e92d6f8cdfdf8277808ae52a07c36wu@webrtc.org                     " output will not be complete");
3193470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
3194470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
3195470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    stats.bytesSent = bytesSent;
3196470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    stats.packetsSent = packetsSent;
3197470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    stats.bytesReceived = bytesReceived;
3198470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    stats.packetsReceived = packetsReceived;
3199470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
3200470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3201470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                 VoEId(_instanceId, _channelId),
32024591fbd09f9cb6e83433c49a12dd8524c2806502pkasting@chromium.org                 "GetRTPStatistics() => bytesSent=%" PRIuS ", packetsSent=%d,"
32034591fbd09f9cb6e83433c49a12dd8524c2806502pkasting@chromium.org                 " bytesReceived=%" PRIuS ", packetsReceived=%d)",
3204470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                 stats.bytesSent, stats.packetsSent, stats.bytesReceived,
3205470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                 stats.packetsReceived);
3206470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
3207cb711f77d2ff9ebd42678869a73353809b3af66ewu@webrtc.org    // --- Timestamps
3208cb711f77d2ff9ebd42678869a73353809b3af66ewu@webrtc.org    {
3209cb711f77d2ff9ebd42678869a73353809b3af66ewu@webrtc.org      CriticalSectionScoped lock(ts_stats_lock_.get());
3210cb711f77d2ff9ebd42678869a73353809b3af66ewu@webrtc.org      stats.capture_start_ntp_time_ms_ = capture_start_ntp_time_ms_;
3211cb711f77d2ff9ebd42678869a73353809b3af66ewu@webrtc.org    }
3212470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    return 0;
3213470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com}
3214470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
3215c1a40a7b68a8d253b0ba32b89f3126931eeaeab3minyue@webrtc.orgint Channel::SetREDStatus(bool enable, int redPayloadtype) {
321642259e7ebc7126f5a7036940fcab65b3f8d2af38turaj@webrtc.org  WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
3217c1a40a7b68a8d253b0ba32b89f3126931eeaeab3minyue@webrtc.org               "Channel::SetREDStatus()");
321842259e7ebc7126f5a7036940fcab65b3f8d2af38turaj@webrtc.org
32198c8ad85c5d70c38cea82f5b17794a4e7ab4cf531turaj@webrtc.org  if (enable) {
32208c8ad85c5d70c38cea82f5b17794a4e7ab4cf531turaj@webrtc.org    if (redPayloadtype < 0 || redPayloadtype > 127) {
32218c8ad85c5d70c38cea82f5b17794a4e7ab4cf531turaj@webrtc.org      _engineStatisticsPtr->SetLastError(
32228c8ad85c5d70c38cea82f5b17794a4e7ab4cf531turaj@webrtc.org          VE_PLTYPE_ERROR, kTraceError,
3223c1a40a7b68a8d253b0ba32b89f3126931eeaeab3minyue@webrtc.org          "SetREDStatus() invalid RED payload type");
32248c8ad85c5d70c38cea82f5b17794a4e7ab4cf531turaj@webrtc.org      return -1;
32258c8ad85c5d70c38cea82f5b17794a4e7ab4cf531turaj@webrtc.org    }
32268c8ad85c5d70c38cea82f5b17794a4e7ab4cf531turaj@webrtc.org
32278c8ad85c5d70c38cea82f5b17794a4e7ab4cf531turaj@webrtc.org    if (SetRedPayloadType(redPayloadtype) < 0) {
32288c8ad85c5d70c38cea82f5b17794a4e7ab4cf531turaj@webrtc.org      _engineStatisticsPtr->SetLastError(
32298c8ad85c5d70c38cea82f5b17794a4e7ab4cf531turaj@webrtc.org          VE_CODEC_ERROR, kTraceError,
32308c8ad85c5d70c38cea82f5b17794a4e7ab4cf531turaj@webrtc.org          "SetSecondarySendCodec() Failed to register RED ACM");
32318c8ad85c5d70c38cea82f5b17794a4e7ab4cf531turaj@webrtc.org      return -1;
32328c8ad85c5d70c38cea82f5b17794a4e7ab4cf531turaj@webrtc.org    }
323342259e7ebc7126f5a7036940fcab65b3f8d2af38turaj@webrtc.org  }
32342cf22a6abce2d38e673505a4cfd5624a3710b5cdperkj@webrtc.org
3235aa5ea1c0f9d0df583ae0f791f6715a0764aff3cfminyue@webrtc.org  if (audio_coding_->SetREDStatus(enable) != 0) {
323642259e7ebc7126f5a7036940fcab65b3f8d2af38turaj@webrtc.org    _engineStatisticsPtr->SetLastError(
323742259e7ebc7126f5a7036940fcab65b3f8d2af38turaj@webrtc.org        VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
3238aa5ea1c0f9d0df583ae0f791f6715a0764aff3cfminyue@webrtc.org        "SetREDStatus() failed to set RED state in the ACM");
323942259e7ebc7126f5a7036940fcab65b3f8d2af38turaj@webrtc.org    return -1;
324042259e7ebc7126f5a7036940fcab65b3f8d2af38turaj@webrtc.org  }
324142259e7ebc7126f5a7036940fcab65b3f8d2af38turaj@webrtc.org  return 0;
3242470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com}
3243470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
3244470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.comint
3245c1a40a7b68a8d253b0ba32b89f3126931eeaeab3minyue@webrtc.orgChannel::GetREDStatus(bool& enabled, int& redPayloadtype)
3246470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com{
3247aa5ea1c0f9d0df583ae0f791f6715a0764aff3cfminyue@webrtc.org    enabled = audio_coding_->REDStatus();
3248470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    if (enabled)
3249470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
32506141e13873d0fdea626de08dfec2efa2c9171c76pbos@webrtc.org        int8_t payloadType(0);
32512853dde5201d9ddc284ce5efb9688f6340487acepwestin@webrtc.org        if (_rtpRtcpModule->SendREDPayloadType(payloadType) != 0)
3252470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        {
3253470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            _engineStatisticsPtr->SetLastError(
3254470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                VE_RTP_RTCP_MODULE_ERROR, kTraceError,
3255c1a40a7b68a8d253b0ba32b89f3126931eeaeab3minyue@webrtc.org                "GetREDStatus() failed to retrieve RED PT from RTP/RTCP "
3256470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                "module");
3257470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            return -1;
3258470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        }
3259df9a41d2701d321dbc987201ec7cffe2a16bd2c4pkasting@chromium.org        redPayloadtype = payloadType;
3260470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3261470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                   VoEId(_instanceId, _channelId),
3262c1a40a7b68a8d253b0ba32b89f3126931eeaeab3minyue@webrtc.org                   "GetREDStatus() => enabled=%d, redPayloadtype=%d",
3263470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                   enabled, redPayloadtype);
3264470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        return 0;
3265470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
3266470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3267470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                 VoEId(_instanceId, _channelId),
3268c1a40a7b68a8d253b0ba32b89f3126931eeaeab3minyue@webrtc.org                 "GetREDStatus() => enabled=%d", enabled);
3269470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    return 0;
3270470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com}
3271470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
3272c1a40a7b68a8d253b0ba32b89f3126931eeaeab3minyue@webrtc.orgint Channel::SetCodecFECStatus(bool enable) {
3273c1a40a7b68a8d253b0ba32b89f3126931eeaeab3minyue@webrtc.org  WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
3274c1a40a7b68a8d253b0ba32b89f3126931eeaeab3minyue@webrtc.org               "Channel::SetCodecFECStatus()");
3275c1a40a7b68a8d253b0ba32b89f3126931eeaeab3minyue@webrtc.org
3276c1a40a7b68a8d253b0ba32b89f3126931eeaeab3minyue@webrtc.org  if (audio_coding_->SetCodecFEC(enable) != 0) {
3277c1a40a7b68a8d253b0ba32b89f3126931eeaeab3minyue@webrtc.org    _engineStatisticsPtr->SetLastError(
3278c1a40a7b68a8d253b0ba32b89f3126931eeaeab3minyue@webrtc.org        VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
3279c1a40a7b68a8d253b0ba32b89f3126931eeaeab3minyue@webrtc.org        "SetCodecFECStatus() failed to set FEC state");
3280c1a40a7b68a8d253b0ba32b89f3126931eeaeab3minyue@webrtc.org    return -1;
3281c1a40a7b68a8d253b0ba32b89f3126931eeaeab3minyue@webrtc.org  }
3282c1a40a7b68a8d253b0ba32b89f3126931eeaeab3minyue@webrtc.org  return 0;
3283c1a40a7b68a8d253b0ba32b89f3126931eeaeab3minyue@webrtc.org}
3284c1a40a7b68a8d253b0ba32b89f3126931eeaeab3minyue@webrtc.org
3285c1a40a7b68a8d253b0ba32b89f3126931eeaeab3minyue@webrtc.orgbool Channel::GetCodecFECStatus() {
3286c1a40a7b68a8d253b0ba32b89f3126931eeaeab3minyue@webrtc.org  bool enabled = audio_coding_->CodecFEC();
3287c1a40a7b68a8d253b0ba32b89f3126931eeaeab3minyue@webrtc.org  WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3288c1a40a7b68a8d253b0ba32b89f3126931eeaeab3minyue@webrtc.org               VoEId(_instanceId, _channelId),
3289c1a40a7b68a8d253b0ba32b89f3126931eeaeab3minyue@webrtc.org               "GetCodecFECStatus() => enabled=%d", enabled);
3290c1a40a7b68a8d253b0ba32b89f3126931eeaeab3minyue@webrtc.org  return enabled;
3291c1a40a7b68a8d253b0ba32b89f3126931eeaeab3minyue@webrtc.org}
3292c1a40a7b68a8d253b0ba32b89f3126931eeaeab3minyue@webrtc.org
3293db249956807d916729aacfaf3382923e8239d533pwestin@webrtc.orgvoid Channel::SetNACKStatus(bool enable, int maxNumberOfPackets) {
3294db249956807d916729aacfaf3382923e8239d533pwestin@webrtc.org  // None of these functions can fail.
3295db249956807d916729aacfaf3382923e8239d533pwestin@webrtc.org  _rtpRtcpModule->SetStorePacketsStatus(enable, maxNumberOfPackets);
32967bb8f02274ecbfa1f7ef134d708369a369a78c83stefan@webrtc.org  rtp_receive_statistics_->SetMaxReorderingThreshold(maxNumberOfPackets);
32977bb8f02274ecbfa1f7ef134d708369a369a78c83stefan@webrtc.org  rtp_receiver_->SetNACKStatus(enable ? kNackRtcp : kNackOff);
3298d30859e58e2c0b0676ab2b52b8a2723e10d49e28pwestin@webrtc.org  if (enable)
3299eb524d997b877ba9b0bcaf8c85eae52bd40c37e3andrew@webrtc.org    audio_coding_->EnableNack(maxNumberOfPackets);
3300d30859e58e2c0b0676ab2b52b8a2723e10d49e28pwestin@webrtc.org  else
3301eb524d997b877ba9b0bcaf8c85eae52bd40c37e3andrew@webrtc.org    audio_coding_->DisableNack();
3302db249956807d916729aacfaf3382923e8239d533pwestin@webrtc.org}
3303db249956807d916729aacfaf3382923e8239d533pwestin@webrtc.org
3304d30859e58e2c0b0676ab2b52b8a2723e10d49e28pwestin@webrtc.org// Called when we are missing one or more packets.
3305d30859e58e2c0b0676ab2b52b8a2723e10d49e28pwestin@webrtc.orgint Channel::ResendPackets(const uint16_t* sequence_numbers, int length) {
3306db249956807d916729aacfaf3382923e8239d533pwestin@webrtc.org  return _rtpRtcpModule->SendNACK(sequence_numbers, length);
3307db249956807d916729aacfaf3382923e8239d533pwestin@webrtc.org}
3308db249956807d916729aacfaf3382923e8239d533pwestin@webrtc.org
33096141e13873d0fdea626de08dfec2efa2c9171c76pbos@webrtc.orguint32_t
3310755b04a06ec4ae91ae7fb601c641e683f4e9e87dandrew@webrtc.orgChannel::Demultiplex(const AudioFrame& audioFrame)
3311470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com{
3312470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
3313755b04a06ec4ae91ae7fb601c641e683f4e9e87dandrew@webrtc.org                 "Channel::Demultiplex()");
3314ae1a58bba4f926d149a5f39243269c3f6625f494andrew@webrtc.org    _audioFrame.CopyFrom(audioFrame);
331563a509858d3988299726640c664b699d6229a1d4andrew@webrtc.org    _audioFrame.id_ = _channelId;
3316470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    return 0;
3317470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com}
3318470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
33192f84afad30b088ddebb4063bc47ac9a79d735a2bxians@webrtc.orgvoid Channel::Demultiplex(const int16_t* audio_data,
33208fff1f065ea9d25970c3839294acdd606a5ddf22xians@webrtc.org                          int sample_rate,
3321dce40cf804019a9898b6ab8d8262466b697c56e0Peter Kasting                          size_t number_of_frames,
33228fff1f065ea9d25970c3839294acdd606a5ddf22xians@webrtc.org                          int number_of_channels) {
33232f84afad30b088ddebb4063bc47ac9a79d735a2bxians@webrtc.org  CodecInst codec;
33242f84afad30b088ddebb4063bc47ac9a79d735a2bxians@webrtc.org  GetSendCodec(codec);
33252f84afad30b088ddebb4063bc47ac9a79d735a2bxians@webrtc.org
332640ee3d07eda24b8e8214429d9885d9ad9a2c04f7andrew@webrtc.org  if (!mono_recording_audio_.get()) {
332740ee3d07eda24b8e8214429d9885d9ad9a2c04f7andrew@webrtc.org    // Temporary space for DownConvertToCodecFormat.
332840ee3d07eda24b8e8214429d9885d9ad9a2c04f7andrew@webrtc.org    mono_recording_audio_.reset(new int16_t[kMaxMonoDataSizeSamples]);
33292f84afad30b088ddebb4063bc47ac9a79d735a2bxians@webrtc.org  }
333040ee3d07eda24b8e8214429d9885d9ad9a2c04f7andrew@webrtc.org  DownConvertToCodecFormat(audio_data,
333140ee3d07eda24b8e8214429d9885d9ad9a2c04f7andrew@webrtc.org                           number_of_frames,
333240ee3d07eda24b8e8214429d9885d9ad9a2c04f7andrew@webrtc.org                           number_of_channels,
333340ee3d07eda24b8e8214429d9885d9ad9a2c04f7andrew@webrtc.org                           sample_rate,
333440ee3d07eda24b8e8214429d9885d9ad9a2c04f7andrew@webrtc.org                           codec.channels,
333540ee3d07eda24b8e8214429d9885d9ad9a2c04f7andrew@webrtc.org                           codec.plfreq,
333640ee3d07eda24b8e8214429d9885d9ad9a2c04f7andrew@webrtc.org                           mono_recording_audio_.get(),
333740ee3d07eda24b8e8214429d9885d9ad9a2c04f7andrew@webrtc.org                           &input_resampler_,
333840ee3d07eda24b8e8214429d9885d9ad9a2c04f7andrew@webrtc.org                           &_audioFrame);
33392f84afad30b088ddebb4063bc47ac9a79d735a2bxians@webrtc.org}
33402f84afad30b088ddebb4063bc47ac9a79d735a2bxians@webrtc.org
33416141e13873d0fdea626de08dfec2efa2c9171c76pbos@webrtc.orguint32_t
33420b0665acc1464d68e878f203bbc8772a0e32402dxians@google.comChannel::PrepareEncodeAndSend(int mixingFrequency)
3343470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com{
3344470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
3345470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                 "Channel::PrepareEncodeAndSend()");
3346470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
334763a509858d3988299726640c664b699d6229a1d4andrew@webrtc.org    if (_audioFrame.samples_per_channel_ == 0)
3348470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
3349470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        WEBRTC_TRACE(kTraceWarning, kTraceVoice, VoEId(_instanceId,_channelId),
3350470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                     "Channel::PrepareEncodeAndSend() invalid audio frame");
3351eec6ecdb1e249871dd25d04b62fc9ddc03dc8a34tommi@webrtc.org        return 0xFFFFFFFF;
3352470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
3353470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
3354944cbeb2926feb86a687e5fda9e2ac88ea8e3001henrika@webrtc.org    if (channel_state_.Get().input_file_playing)
3355470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
3356470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        MixOrReplaceAudioWithFile(mixingFrequency);
3357470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
3358470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
335921299d4e00781e199a53ba33ec192cdce920acecandrew@webrtc.org    bool is_muted = Mute();  // Cache locally as Mute() takes a lock.
336021299d4e00781e199a53ba33ec192cdce920acecandrew@webrtc.org    if (is_muted) {
336121299d4e00781e199a53ba33ec192cdce920acecandrew@webrtc.org      AudioFrameOperations::Mute(_audioFrame);
3362470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
3363470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
3364944cbeb2926feb86a687e5fda9e2ac88ea8e3001henrika@webrtc.org    if (channel_state_.Get().input_external_media)
3365470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
33669a065d1eae9ed296e1e2eaaad73d7ca1223bfe79mflodman@webrtc.org        CriticalSectionScoped cs(&_callbackCritSect);
336763a509858d3988299726640c664b699d6229a1d4andrew@webrtc.org        const bool isStereo = (_audioFrame.num_channels_ == 2);
3368470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        if (_inputExternalMediaCallbackPtr)
3369470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        {
3370470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            _inputExternalMediaCallbackPtr->Process(
3371470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                _channelId,
3372470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                kRecordingPerChannel,
33736141e13873d0fdea626de08dfec2efa2c9171c76pbos@webrtc.org               (int16_t*)_audioFrame.data_,
337463a509858d3988299726640c664b699d6229a1d4andrew@webrtc.org                _audioFrame.samples_per_channel_,
337563a509858d3988299726640c664b699d6229a1d4andrew@webrtc.org                _audioFrame.sample_rate_hz_,
3376470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                isStereo);
3377470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        }
3378470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
3379470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
3380470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    InsertInbandDtmfTone();
3381470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
338260730cfe3ce80e4023cd678373456cb703f000a4andrew@webrtc.org    if (_includeAudioLevelIndication) {
3383dce40cf804019a9898b6ab8d8262466b697c56e0Peter Kasting      size_t length =
3384dce40cf804019a9898b6ab8d8262466b697c56e0Peter Kasting          _audioFrame.samples_per_channel_ * _audioFrame.num_channels_;
338521299d4e00781e199a53ba33ec192cdce920acecandrew@webrtc.org      if (is_muted) {
338621299d4e00781e199a53ba33ec192cdce920acecandrew@webrtc.org        rms_level_.ProcessMuted(length);
338721299d4e00781e199a53ba33ec192cdce920acecandrew@webrtc.org      } else {
338821299d4e00781e199a53ba33ec192cdce920acecandrew@webrtc.org        rms_level_.Process(_audioFrame.data_, length);
338921299d4e00781e199a53ba33ec192cdce920acecandrew@webrtc.org      }
3390755b04a06ec4ae91ae7fb601c641e683f4e9e87dandrew@webrtc.org    }
3391755b04a06ec4ae91ae7fb601c641e683f4e9e87dandrew@webrtc.org
3392470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    return 0;
3393470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com}
3394470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
33956141e13873d0fdea626de08dfec2efa2c9171c76pbos@webrtc.orguint32_t
3396470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.comChannel::EncodeAndSend()
3397470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com{
3398470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
3399470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                 "Channel::EncodeAndSend()");
3400470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
340163a509858d3988299726640c664b699d6229a1d4andrew@webrtc.org    assert(_audioFrame.num_channels_ <= 2);
340263a509858d3988299726640c664b699d6229a1d4andrew@webrtc.org    if (_audioFrame.samples_per_channel_ == 0)
3403470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
3404470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        WEBRTC_TRACE(kTraceWarning, kTraceVoice, VoEId(_instanceId,_channelId),
3405470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                     "Channel::EncodeAndSend() invalid audio frame");
3406eec6ecdb1e249871dd25d04b62fc9ddc03dc8a34tommi@webrtc.org        return 0xFFFFFFFF;
3407470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
3408470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
340963a509858d3988299726640c664b699d6229a1d4andrew@webrtc.org    _audioFrame.id_ = _channelId;
3410470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
3411470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    // --- Add 10ms of raw (PCM) audio data to the encoder @ 32kHz.
3412470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
3413470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    // The ACM resamples internally.
341463a509858d3988299726640c664b699d6229a1d4andrew@webrtc.org    _audioFrame.timestamp_ = _timeStamp;
3415f56c1623103e3f72198d6b0f50de9f0585b6f52fhenrik.lundin@webrtc.org    // This call will trigger AudioPacketizationCallback::SendData if encoding
3416f56c1623103e3f72198d6b0f50de9f0585b6f52fhenrik.lundin@webrtc.org    // is done and payload is ready for packetization and transmission.
3417f56c1623103e3f72198d6b0f50de9f0585b6f52fhenrik.lundin@webrtc.org    // Otherwise, it will return without invoking the callback.
3418f56c1623103e3f72198d6b0f50de9f0585b6f52fhenrik.lundin@webrtc.org    if (audio_coding_->Add10MsData((AudioFrame&)_audioFrame) < 0)
3419470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
3420470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        WEBRTC_TRACE(kTraceError, kTraceVoice, VoEId(_instanceId,_channelId),
3421470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                     "Channel::EncodeAndSend() ACM encoding failed");
3422eec6ecdb1e249871dd25d04b62fc9ddc03dc8a34tommi@webrtc.org        return 0xFFFFFFFF;
3423470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
3424470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
3425b7e5054414ff524f9db81dab7917729b8c4c8bcbPeter Kasting    _timeStamp += static_cast<uint32_t>(_audioFrame.samples_per_channel_);
3426f56c1623103e3f72198d6b0f50de9f0585b6f52fhenrik.lundin@webrtc.org    return 0;
3427470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com}
3428470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
34292013aeced2b7821a407f302802c4a16fd02728b1Minyuevoid Channel::DisassociateSendChannel(int channel_id) {
34302013aeced2b7821a407f302802c4a16fd02728b1Minyue  CriticalSectionScoped lock(assoc_send_channel_lock_.get());
34312013aeced2b7821a407f302802c4a16fd02728b1Minyue  Channel* channel = associate_send_channel_.channel();
34322013aeced2b7821a407f302802c4a16fd02728b1Minyue  if (channel && channel->ChannelId() == channel_id) {
34332013aeced2b7821a407f302802c4a16fd02728b1Minyue    // If this channel is associated with a send channel of the specified
34342013aeced2b7821a407f302802c4a16fd02728b1Minyue    // Channel ID, disassociate with it.
34352013aeced2b7821a407f302802c4a16fd02728b1Minyue    ChannelOwner ref(NULL);
34362013aeced2b7821a407f302802c4a16fd02728b1Minyue    associate_send_channel_ = ref;
34372013aeced2b7821a407f302802c4a16fd02728b1Minyue  }
34382013aeced2b7821a407f302802c4a16fd02728b1Minyue}
34392013aeced2b7821a407f302802c4a16fd02728b1Minyue
3440470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.comint Channel::RegisterExternalMediaProcessing(
3441470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    ProcessingTypes type,
3442470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    VoEMediaProcess& processObject)
3443470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com{
3444470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3445470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                 "Channel::RegisterExternalMediaProcessing()");
3446470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
34479a065d1eae9ed296e1e2eaaad73d7ca1223bfe79mflodman@webrtc.org    CriticalSectionScoped cs(&_callbackCritSect);
3448470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
3449470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    if (kPlaybackPerChannel == type)
3450470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
3451470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        if (_outputExternalMediaCallbackPtr)
3452470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        {
3453470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            _engineStatisticsPtr->SetLastError(
3454470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                VE_INVALID_OPERATION, kTraceError,
3455470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                "Channel::RegisterExternalMediaProcessing() "
3456470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                "output external media already enabled");
3457470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            return -1;
3458470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        }
3459470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        _outputExternalMediaCallbackPtr = &processObject;
3460470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        _outputExternalMedia = true;
3461470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
3462470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    else if (kRecordingPerChannel == type)
3463470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
3464470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        if (_inputExternalMediaCallbackPtr)
3465470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        {
3466470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            _engineStatisticsPtr->SetLastError(
3467470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                VE_INVALID_OPERATION, kTraceError,
3468470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                "Channel::RegisterExternalMediaProcessing() "
3469470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                "output external media already enabled");
3470470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            return -1;
3471470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        }
3472470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        _inputExternalMediaCallbackPtr = &processObject;
3473944cbeb2926feb86a687e5fda9e2ac88ea8e3001henrika@webrtc.org        channel_state_.SetInputExternalMedia(true);
3474470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
3475470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    return 0;
3476470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com}
3477470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
3478470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.comint Channel::DeRegisterExternalMediaProcessing(ProcessingTypes type)
3479470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com{
3480470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3481470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                 "Channel::DeRegisterExternalMediaProcessing()");
3482470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
34839a065d1eae9ed296e1e2eaaad73d7ca1223bfe79mflodman@webrtc.org    CriticalSectionScoped cs(&_callbackCritSect);
3484470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
3485470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    if (kPlaybackPerChannel == type)
3486470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
3487470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        if (!_outputExternalMediaCallbackPtr)
3488470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        {
3489470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            _engineStatisticsPtr->SetLastError(
3490470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                VE_INVALID_OPERATION, kTraceWarning,
3491470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                "Channel::DeRegisterExternalMediaProcessing() "
3492470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                "output external media already disabled");
3493470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            return 0;
3494470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        }
3495470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        _outputExternalMedia = false;
3496470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        _outputExternalMediaCallbackPtr = NULL;
3497470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
3498470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    else if (kRecordingPerChannel == type)
3499470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
3500470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        if (!_inputExternalMediaCallbackPtr)
3501470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        {
3502470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            _engineStatisticsPtr->SetLastError(
3503470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                VE_INVALID_OPERATION, kTraceWarning,
3504470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                "Channel::DeRegisterExternalMediaProcessing() "
3505470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                "input external media already disabled");
3506470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            return 0;
3507470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        }
3508944cbeb2926feb86a687e5fda9e2ac88ea8e3001henrika@webrtc.org        channel_state_.SetInputExternalMedia(false);
3509470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        _inputExternalMediaCallbackPtr = NULL;
3510470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
3511470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
3512470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    return 0;
3513470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com}
3514470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
35151b60ceb499ee35460886f2bfaecee1f47319f925roosa@google.comint Channel::SetExternalMixing(bool enabled) {
35161b60ceb499ee35460886f2bfaecee1f47319f925roosa@google.com    WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
35171b60ceb499ee35460886f2bfaecee1f47319f925roosa@google.com                 "Channel::SetExternalMixing(enabled=%d)", enabled);
35181b60ceb499ee35460886f2bfaecee1f47319f925roosa@google.com
3519944cbeb2926feb86a687e5fda9e2ac88ea8e3001henrika@webrtc.org    if (channel_state_.Get().playing)
35201b60ceb499ee35460886f2bfaecee1f47319f925roosa@google.com    {
35211b60ceb499ee35460886f2bfaecee1f47319f925roosa@google.com        _engineStatisticsPtr->SetLastError(
35221b60ceb499ee35460886f2bfaecee1f47319f925roosa@google.com            VE_INVALID_OPERATION, kTraceError,
35231b60ceb499ee35460886f2bfaecee1f47319f925roosa@google.com            "Channel::SetExternalMixing() "
35241b60ceb499ee35460886f2bfaecee1f47319f925roosa@google.com            "external mixing cannot be changed while playing.");
35251b60ceb499ee35460886f2bfaecee1f47319f925roosa@google.com        return -1;
35261b60ceb499ee35460886f2bfaecee1f47319f925roosa@google.com    }
35271b60ceb499ee35460886f2bfaecee1f47319f925roosa@google.com
35281b60ceb499ee35460886f2bfaecee1f47319f925roosa@google.com    _externalMixing = enabled;
35291b60ceb499ee35460886f2bfaecee1f47319f925roosa@google.com
35301b60ceb499ee35460886f2bfaecee1f47319f925roosa@google.com    return 0;
35311b60ceb499ee35460886f2bfaecee1f47319f925roosa@google.com}
35321b60ceb499ee35460886f2bfaecee1f47319f925roosa@google.com
3533470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.comint
3534470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.comChannel::GetNetworkStatistics(NetworkStatistics& stats)
3535470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com{
3536470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3537470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                 "Channel::GetNetworkStatistics()");
3538c0bd7be0df67735d63f5cdd302a3b85f88239874minyue@webrtc.org    return audio_coding_->GetNetworkStatistics(&stats);
3539470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com}
3540470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
354124301a67c66e6091418e83da49cfb367ef2c6645wu@webrtc.orgvoid Channel::GetDecodingCallStatistics(AudioDecodingCallStats* stats) const {
354224301a67c66e6091418e83da49cfb367ef2c6645wu@webrtc.org  audio_coding_->GetDecodingCallStatistics(stats);
354324301a67c66e6091418e83da49cfb367ef2c6645wu@webrtc.org}
354424301a67c66e6091418e83da49cfb367ef2c6645wu@webrtc.org
35451de01354e68da71bc62c81af17afeac8ed374a18pwestin@webrtc.orgbool Channel::GetDelayEstimate(int* jitter_buffer_delay_ms,
35461de01354e68da71bc62c81af17afeac8ed374a18pwestin@webrtc.org                               int* playout_buffer_delay_ms) const {
3547743758816853df2040a21c5652b0d0e238b1512fdeadbeef  CriticalSectionScoped cs(video_sync_lock_.get());
35481de01354e68da71bc62c81af17afeac8ed374a18pwestin@webrtc.org  if (_average_jitter_buffer_delay_us == 0) {
3549470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
35501de01354e68da71bc62c81af17afeac8ed374a18pwestin@webrtc.org                 "Channel::GetDelayEstimate() no valid estimate.");
35511de01354e68da71bc62c81af17afeac8ed374a18pwestin@webrtc.org    return false;
35521de01354e68da71bc62c81af17afeac8ed374a18pwestin@webrtc.org  }
35531de01354e68da71bc62c81af17afeac8ed374a18pwestin@webrtc.org  *jitter_buffer_delay_ms = (_average_jitter_buffer_delay_us + 500) / 1000 +
35541de01354e68da71bc62c81af17afeac8ed374a18pwestin@webrtc.org      _recPacketDelayMs;
35551de01354e68da71bc62c81af17afeac8ed374a18pwestin@webrtc.org  *playout_buffer_delay_ms = playout_delay_ms_;
35561de01354e68da71bc62c81af17afeac8ed374a18pwestin@webrtc.org  WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
35571de01354e68da71bc62c81af17afeac8ed374a18pwestin@webrtc.org               "Channel::GetDelayEstimate()");
35581de01354e68da71bc62c81af17afeac8ed374a18pwestin@webrtc.org  return true;
3559470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com}
3560470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
3561743758816853df2040a21c5652b0d0e238b1512fdeadbeefint Channel::LeastRequiredDelayMs() const {
3562743758816853df2040a21c5652b0d0e238b1512fdeadbeef  return audio_coding_->LeastRequiredDelayMs();
3563743758816853df2040a21c5652b0d0e238b1512fdeadbeef}
3564743758816853df2040a21c5652b0d0e238b1512fdeadbeef
35656388c3e2fdfc91b3648fb7d408a14ddb25e41cd1turaj@webrtc.orgint Channel::SetInitialPlayoutDelay(int delay_ms)
35666388c3e2fdfc91b3648fb7d408a14ddb25e41cd1turaj@webrtc.org{
35676388c3e2fdfc91b3648fb7d408a14ddb25e41cd1turaj@webrtc.org  WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
35686388c3e2fdfc91b3648fb7d408a14ddb25e41cd1turaj@webrtc.org               "Channel::SetInitialPlayoutDelay()");
35696388c3e2fdfc91b3648fb7d408a14ddb25e41cd1turaj@webrtc.org  if ((delay_ms < kVoiceEngineMinMinPlayoutDelayMs) ||
35706388c3e2fdfc91b3648fb7d408a14ddb25e41cd1turaj@webrtc.org      (delay_ms > kVoiceEngineMaxMinPlayoutDelayMs))
35716388c3e2fdfc91b3648fb7d408a14ddb25e41cd1turaj@webrtc.org  {
35726388c3e2fdfc91b3648fb7d408a14ddb25e41cd1turaj@webrtc.org    _engineStatisticsPtr->SetLastError(
35736388c3e2fdfc91b3648fb7d408a14ddb25e41cd1turaj@webrtc.org        VE_INVALID_ARGUMENT, kTraceError,
35746388c3e2fdfc91b3648fb7d408a14ddb25e41cd1turaj@webrtc.org        "SetInitialPlayoutDelay() invalid min delay");
35756388c3e2fdfc91b3648fb7d408a14ddb25e41cd1turaj@webrtc.org    return -1;
35766388c3e2fdfc91b3648fb7d408a14ddb25e41cd1turaj@webrtc.org  }
3577eb524d997b877ba9b0bcaf8c85eae52bd40c37e3andrew@webrtc.org  if (audio_coding_->SetInitialPlayoutDelay(delay_ms) != 0)
35786388c3e2fdfc91b3648fb7d408a14ddb25e41cd1turaj@webrtc.org  {
35796388c3e2fdfc91b3648fb7d408a14ddb25e41cd1turaj@webrtc.org    _engineStatisticsPtr->SetLastError(
35806388c3e2fdfc91b3648fb7d408a14ddb25e41cd1turaj@webrtc.org        VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
35816388c3e2fdfc91b3648fb7d408a14ddb25e41cd1turaj@webrtc.org        "SetInitialPlayoutDelay() failed to set min playout delay");
35826388c3e2fdfc91b3648fb7d408a14ddb25e41cd1turaj@webrtc.org    return -1;
35836388c3e2fdfc91b3648fb7d408a14ddb25e41cd1turaj@webrtc.org  }
35846388c3e2fdfc91b3648fb7d408a14ddb25e41cd1turaj@webrtc.org  return 0;
35856388c3e2fdfc91b3648fb7d408a14ddb25e41cd1turaj@webrtc.org}
35866388c3e2fdfc91b3648fb7d408a14ddb25e41cd1turaj@webrtc.org
35876388c3e2fdfc91b3648fb7d408a14ddb25e41cd1turaj@webrtc.org
3588470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.comint
3589470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.comChannel::SetMinimumPlayoutDelay(int delayMs)
3590470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com{
3591470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3592470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                 "Channel::SetMinimumPlayoutDelay()");
3593470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    if ((delayMs < kVoiceEngineMinMinPlayoutDelayMs) ||
3594470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        (delayMs > kVoiceEngineMaxMinPlayoutDelayMs))
3595470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
3596470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        _engineStatisticsPtr->SetLastError(
3597470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            VE_INVALID_ARGUMENT, kTraceError,
3598470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            "SetMinimumPlayoutDelay() invalid min delay");
3599470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        return -1;
3600470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
3601eb524d997b877ba9b0bcaf8c85eae52bd40c37e3andrew@webrtc.org    if (audio_coding_->SetMinimumPlayoutDelay(delayMs) != 0)
3602470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
3603470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        _engineStatisticsPtr->SetLastError(
3604470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
3605470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            "SetMinimumPlayoutDelay() failed to set min playout delay");
3606470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        return -1;
3607470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
3608470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    return 0;
3609470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com}
3610470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
36111de01354e68da71bc62c81af17afeac8ed374a18pwestin@webrtc.orgint Channel::GetPlayoutTimestamp(unsigned int& timestamp) {
36121de01354e68da71bc62c81af17afeac8ed374a18pwestin@webrtc.org  WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
36131de01354e68da71bc62c81af17afeac8ed374a18pwestin@webrtc.org               "Channel::GetPlayoutTimestamp()");
3614743758816853df2040a21c5652b0d0e238b1512fdeadbeef  uint32_t playout_timestamp_rtp = 0;
3615743758816853df2040a21c5652b0d0e238b1512fdeadbeef  {
3616743758816853df2040a21c5652b0d0e238b1512fdeadbeef    CriticalSectionScoped cs(video_sync_lock_.get());
3617743758816853df2040a21c5652b0d0e238b1512fdeadbeef    playout_timestamp_rtp = playout_timestamp_rtp_;
3618743758816853df2040a21c5652b0d0e238b1512fdeadbeef  }
3619743758816853df2040a21c5652b0d0e238b1512fdeadbeef  if (playout_timestamp_rtp == 0)  {
36201de01354e68da71bc62c81af17afeac8ed374a18pwestin@webrtc.org    _engineStatisticsPtr->SetLastError(
36211de01354e68da71bc62c81af17afeac8ed374a18pwestin@webrtc.org        VE_CANNOT_RETRIEVE_VALUE, kTraceError,
36221de01354e68da71bc62c81af17afeac8ed374a18pwestin@webrtc.org        "GetPlayoutTimestamp() failed to retrieve timestamp");
36231de01354e68da71bc62c81af17afeac8ed374a18pwestin@webrtc.org    return -1;
36241de01354e68da71bc62c81af17afeac8ed374a18pwestin@webrtc.org  }
3625743758816853df2040a21c5652b0d0e238b1512fdeadbeef  timestamp = playout_timestamp_rtp;
36261de01354e68da71bc62c81af17afeac8ed374a18pwestin@webrtc.org  WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
36271de01354e68da71bc62c81af17afeac8ed374a18pwestin@webrtc.org               VoEId(_instanceId,_channelId),
36281de01354e68da71bc62c81af17afeac8ed374a18pwestin@webrtc.org               "GetPlayoutTimestamp() => timestamp=%u", timestamp);
36291de01354e68da71bc62c81af17afeac8ed374a18pwestin@webrtc.org  return 0;
3630470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com}
3631470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
3632d16e839c6d29831e79312180085b6a19149df43fpbos@webrtc.orgint Channel::SetInitTimestamp(unsigned int timestamp) {
3633d16e839c6d29831e79312180085b6a19149df43fpbos@webrtc.org  WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
3634470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com               "Channel::SetInitTimestamp()");
3635d16e839c6d29831e79312180085b6a19149df43fpbos@webrtc.org  if (channel_state_.Get().sending) {
3636d16e839c6d29831e79312180085b6a19149df43fpbos@webrtc.org    _engineStatisticsPtr->SetLastError(VE_SENDING, kTraceError,
3637d16e839c6d29831e79312180085b6a19149df43fpbos@webrtc.org                                       "SetInitTimestamp() already sending");
3638d16e839c6d29831e79312180085b6a19149df43fpbos@webrtc.org    return -1;
3639d16e839c6d29831e79312180085b6a19149df43fpbos@webrtc.org  }
3640d16e839c6d29831e79312180085b6a19149df43fpbos@webrtc.org  _rtpRtcpModule->SetStartTimestamp(timestamp);
3641d16e839c6d29831e79312180085b6a19149df43fpbos@webrtc.org  return 0;
3642470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com}
3643470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
3644d16e839c6d29831e79312180085b6a19149df43fpbos@webrtc.orgint Channel::SetInitSequenceNumber(short sequenceNumber) {
3645d16e839c6d29831e79312180085b6a19149df43fpbos@webrtc.org  WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
3646d16e839c6d29831e79312180085b6a19149df43fpbos@webrtc.org               "Channel::SetInitSequenceNumber()");
3647d16e839c6d29831e79312180085b6a19149df43fpbos@webrtc.org  if (channel_state_.Get().sending) {
3648d16e839c6d29831e79312180085b6a19149df43fpbos@webrtc.org    _engineStatisticsPtr->SetLastError(
3649d16e839c6d29831e79312180085b6a19149df43fpbos@webrtc.org        VE_SENDING, kTraceError, "SetInitSequenceNumber() already sending");
3650d16e839c6d29831e79312180085b6a19149df43fpbos@webrtc.org    return -1;
3651d16e839c6d29831e79312180085b6a19149df43fpbos@webrtc.org  }
3652d16e839c6d29831e79312180085b6a19149df43fpbos@webrtc.org  _rtpRtcpModule->SetSequenceNumber(sequenceNumber);
3653d16e839c6d29831e79312180085b6a19149df43fpbos@webrtc.org  return 0;
3654470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com}
3655470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
3656470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.comint
3657822fbd8b68ffdb481b9557e2950ae8d6657c8ce6wu@webrtc.orgChannel::GetRtpRtcp(RtpRtcp** rtpRtcpModule, RtpReceiver** rtp_receiver) const
3658470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com{
3659470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3660470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                 "Channel::GetRtpRtcp()");
3661822fbd8b68ffdb481b9557e2950ae8d6657c8ce6wu@webrtc.org    *rtpRtcpModule = _rtpRtcpModule.get();
3662822fbd8b68ffdb481b9557e2950ae8d6657c8ce6wu@webrtc.org    *rtp_receiver = rtp_receiver_.get();
3663470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    return 0;
3664470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com}
3665470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
3666e59a0aca6a0762592644ebc0282dbe244162eb8dandrew@webrtc.org// TODO(andrew): refactor Mix functions here and in transmit_mixer.cc to use
3667e59a0aca6a0762592644ebc0282dbe244162eb8dandrew@webrtc.org// a shared helper.
36686141e13873d0fdea626de08dfec2efa2c9171c76pbos@webrtc.orgint32_t
36699213521ea98b0977c7cdabd2853060835af226f3pbos@webrtc.orgChannel::MixOrReplaceAudioWithFile(int mixingFrequency)
3670470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com{
367100b8f6b3643332cce1ee711715f7fbb824d793cakwiberg@webrtc.org  rtc::scoped_ptr<int16_t[]> fileBuffer(new int16_t[640]);
3672dce40cf804019a9898b6ab8d8262466b697c56e0Peter Kasting    size_t fileSamples(0);
3673470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
3674470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
36759a065d1eae9ed296e1e2eaaad73d7ca1223bfe79mflodman@webrtc.org        CriticalSectionScoped cs(&_fileCritSect);
3676470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
3677470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        if (_inputFilePlayerPtr == NULL)
3678470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        {
3679470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            WEBRTC_TRACE(kTraceWarning, kTraceVoice,
3680470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                         VoEId(_instanceId, _channelId),
3681470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                         "Channel::MixOrReplaceAudioWithFile() fileplayer"
3682470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                             " doesnt exist");
3683470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            return -1;
3684470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        }
3685470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
3686d713143d99b205aaaa589b96443d82b36c3843e4braveyao@webrtc.org        if (_inputFilePlayerPtr->Get10msAudioFromFile(fileBuffer.get(),
3687470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                                                      fileSamples,
3688470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                                                      mixingFrequency) == -1)
3689470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        {
3690470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            WEBRTC_TRACE(kTraceWarning, kTraceVoice,
3691470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                         VoEId(_instanceId, _channelId),
3692470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                         "Channel::MixOrReplaceAudioWithFile() file mixing "
3693470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                         "failed");
3694470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            return -1;
3695470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        }
3696470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        if (fileSamples == 0)
3697470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        {
3698470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            WEBRTC_TRACE(kTraceWarning, kTraceVoice,
3699470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                         VoEId(_instanceId, _channelId),
3700470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                         "Channel::MixOrReplaceAudioWithFile() file is ended");
3701470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            return 0;
3702470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        }
3703470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
3704470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
370563a509858d3988299726640c664b699d6229a1d4andrew@webrtc.org    assert(_audioFrame.samples_per_channel_ == fileSamples);
3706470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
3707470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    if (_mixFileWithMicrophone)
3708470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
3709d713143d99b205aaaa589b96443d82b36c3843e4braveyao@webrtc.org        // Currently file stream is always mono.
3710d713143d99b205aaaa589b96443d82b36c3843e4braveyao@webrtc.org        // TODO(xians): Change the code when FilePlayer supports real stereo.
371140ee3d07eda24b8e8214429d9885d9ad9a2c04f7andrew@webrtc.org        MixWithSat(_audioFrame.data_,
371240ee3d07eda24b8e8214429d9885d9ad9a2c04f7andrew@webrtc.org                   _audioFrame.num_channels_,
371340ee3d07eda24b8e8214429d9885d9ad9a2c04f7andrew@webrtc.org                   fileBuffer.get(),
371440ee3d07eda24b8e8214429d9885d9ad9a2c04f7andrew@webrtc.org                   1,
371540ee3d07eda24b8e8214429d9885d9ad9a2c04f7andrew@webrtc.org                   fileSamples);
3716470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
3717470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    else
3718470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
3719d713143d99b205aaaa589b96443d82b36c3843e4braveyao@webrtc.org        // Replace ACM audio with file.
3720d713143d99b205aaaa589b96443d82b36c3843e4braveyao@webrtc.org        // Currently file stream is always mono.
3721d713143d99b205aaaa589b96443d82b36c3843e4braveyao@webrtc.org        // TODO(xians): Change the code when FilePlayer supports real stereo.
3722470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        _audioFrame.UpdateFrame(_channelId,
3723eec6ecdb1e249871dd25d04b62fc9ddc03dc8a34tommi@webrtc.org                                0xFFFFFFFF,
3724d713143d99b205aaaa589b96443d82b36c3843e4braveyao@webrtc.org                                fileBuffer.get(),
3725e59a0aca6a0762592644ebc0282dbe244162eb8dandrew@webrtc.org                                fileSamples,
3726470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                                mixingFrequency,
3727470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                                AudioFrame::kNormalSpeech,
3728470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                                AudioFrame::kVadUnknown,
3729470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                                1);
3730470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
3731470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
3732470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    return 0;
3733470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com}
3734470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
37356141e13873d0fdea626de08dfec2efa2c9171c76pbos@webrtc.orgint32_t
3736470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.comChannel::MixAudioWithFile(AudioFrame& audioFrame,
37379213521ea98b0977c7cdabd2853060835af226f3pbos@webrtc.org                          int mixingFrequency)
3738470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com{
37392a8df7c375c73a3f477ee5cd9d85336a98f57ee2minyue@webrtc.org    assert(mixingFrequency <= 48000);
3740470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
374100b8f6b3643332cce1ee711715f7fbb824d793cakwiberg@webrtc.org    rtc::scoped_ptr<int16_t[]> fileBuffer(new int16_t[960]);
3742dce40cf804019a9898b6ab8d8262466b697c56e0Peter Kasting    size_t fileSamples(0);
3743470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
3744470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
37459a065d1eae9ed296e1e2eaaad73d7ca1223bfe79mflodman@webrtc.org        CriticalSectionScoped cs(&_fileCritSect);
3746470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
3747470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        if (_outputFilePlayerPtr == NULL)
3748470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        {
3749470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            WEBRTC_TRACE(kTraceWarning, kTraceVoice,
3750470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                         VoEId(_instanceId, _channelId),
3751470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                         "Channel::MixAudioWithFile() file mixing failed");
3752470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            return -1;
3753470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        }
3754470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
3755470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        // We should get the frequency we ask for.
3756d713143d99b205aaaa589b96443d82b36c3843e4braveyao@webrtc.org        if (_outputFilePlayerPtr->Get10msAudioFromFile(fileBuffer.get(),
3757470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                                                       fileSamples,
3758470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                                                       mixingFrequency) == -1)
3759470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        {
3760470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            WEBRTC_TRACE(kTraceWarning, kTraceVoice,
3761470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                         VoEId(_instanceId, _channelId),
3762470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                         "Channel::MixAudioWithFile() file mixing failed");
3763470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            return -1;
3764470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        }
3765470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
3766470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
376763a509858d3988299726640c664b699d6229a1d4andrew@webrtc.org    if (audioFrame.samples_per_channel_ == fileSamples)
3768470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
3769d713143d99b205aaaa589b96443d82b36c3843e4braveyao@webrtc.org        // Currently file stream is always mono.
3770d713143d99b205aaaa589b96443d82b36c3843e4braveyao@webrtc.org        // TODO(xians): Change the code when FilePlayer supports real stereo.
377140ee3d07eda24b8e8214429d9885d9ad9a2c04f7andrew@webrtc.org        MixWithSat(audioFrame.data_,
377240ee3d07eda24b8e8214429d9885d9ad9a2c04f7andrew@webrtc.org                   audioFrame.num_channels_,
377340ee3d07eda24b8e8214429d9885d9ad9a2c04f7andrew@webrtc.org                   fileBuffer.get(),
377440ee3d07eda24b8e8214429d9885d9ad9a2c04f7andrew@webrtc.org                   1,
377540ee3d07eda24b8e8214429d9885d9ad9a2c04f7andrew@webrtc.org                   fileSamples);
3776470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
3777470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    else
3778470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
3779470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        WEBRTC_TRACE(kTraceWarning, kTraceVoice, VoEId(_instanceId,_channelId),
3780dce40cf804019a9898b6ab8d8262466b697c56e0Peter Kasting            "Channel::MixAudioWithFile() samples_per_channel_(%" PRIuS ") != "
3781dce40cf804019a9898b6ab8d8262466b697c56e0Peter Kasting            "fileSamples(%" PRIuS ")",
378263a509858d3988299726640c664b699d6229a1d4andrew@webrtc.org            audioFrame.samples_per_channel_, fileSamples);
3783470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        return -1;
3784470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
3785470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
3786470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    return 0;
3787470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com}
3788470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
3789470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.comint
3790470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.comChannel::InsertInbandDtmfTone()
3791470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com{
3792af26f646165e7e2a8747fd54e92e73f48118a807niklas.enbom@webrtc.org    // Check if we should start a new tone.
3793470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    if (_inbandDtmfQueue.PendingDtmf() &&
3794470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        !_inbandDtmfGenerator.IsAddingTone() &&
3795470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        _inbandDtmfGenerator.DelaySinceLastTone() >
3796470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        kMinTelephoneEventSeparationMs)
3797470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
37986141e13873d0fdea626de08dfec2efa2c9171c76pbos@webrtc.org        int8_t eventCode(0);
37996141e13873d0fdea626de08dfec2efa2c9171c76pbos@webrtc.org        uint16_t lengthMs(0);
38006141e13873d0fdea626de08dfec2efa2c9171c76pbos@webrtc.org        uint8_t attenuationDb(0);
3801470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
3802470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        eventCode = _inbandDtmfQueue.NextDtmf(&lengthMs, &attenuationDb);
3803470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        _inbandDtmfGenerator.AddTone(eventCode, lengthMs, attenuationDb);
3804470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        if (_playInbandDtmfEvent)
3805470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        {
3806470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            // Add tone to output mixer using a reduced length to minimize
3807470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            // risk of echo.
3808470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            _outputMixerPtr->PlayDtmfTone(eventCode, lengthMs - 80,
3809470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                                          attenuationDb);
3810470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        }
3811470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
3812470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
3813470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    if (_inbandDtmfGenerator.IsAddingTone())
3814470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
38156141e13873d0fdea626de08dfec2efa2c9171c76pbos@webrtc.org        uint16_t frequency(0);
3816470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        _inbandDtmfGenerator.GetSampleRate(frequency);
3817470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
381863a509858d3988299726640c664b699d6229a1d4andrew@webrtc.org        if (frequency != _audioFrame.sample_rate_hz_)
3819470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        {
3820470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            // Update sample rate of Dtmf tone since the mixing frequency
3821470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            // has changed.
3822470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            _inbandDtmfGenerator.SetSampleRate(
38236141e13873d0fdea626de08dfec2efa2c9171c76pbos@webrtc.org                (uint16_t) (_audioFrame.sample_rate_hz_));
3824470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            // Reset the tone to be added taking the new sample rate into
3825470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            // account.
3826470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            _inbandDtmfGenerator.ResetTone();
3827470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        }
3828ae1a58bba4f926d149a5f39243269c3f6625f494andrew@webrtc.org
38296141e13873d0fdea626de08dfec2efa2c9171c76pbos@webrtc.org        int16_t toneBuffer[320];
38306141e13873d0fdea626de08dfec2efa2c9171c76pbos@webrtc.org        uint16_t toneSamples(0);
3831470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        // Get 10ms tone segment and set time since last tone to zero
3832470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        if (_inbandDtmfGenerator.Get10msTone(toneBuffer, toneSamples) == -1)
3833470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        {
3834470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            WEBRTC_TRACE(kTraceWarning, kTraceVoice,
3835470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                       VoEId(_instanceId, _channelId),
3836470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                       "Channel::EncodeAndSend() inserting Dtmf failed");
3837470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            return -1;
3838470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        }
3839470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
3840af26f646165e7e2a8747fd54e92e73f48118a807niklas.enbom@webrtc.org        // Replace mixed audio with DTMF tone.
3841dce40cf804019a9898b6ab8d8262466b697c56e0Peter Kasting        for (size_t sample = 0;
384263a509858d3988299726640c664b699d6229a1d4andrew@webrtc.org            sample < _audioFrame.samples_per_channel_;
3843af26f646165e7e2a8747fd54e92e73f48118a807niklas.enbom@webrtc.org            sample++)
3844af26f646165e7e2a8747fd54e92e73f48118a807niklas.enbom@webrtc.org        {
3845ae1a58bba4f926d149a5f39243269c3f6625f494andrew@webrtc.org            for (int channel = 0;
3846ae1a58bba4f926d149a5f39243269c3f6625f494andrew@webrtc.org                channel < _audioFrame.num_channels_;
3847af26f646165e7e2a8747fd54e92e73f48118a807niklas.enbom@webrtc.org                channel++)
3848af26f646165e7e2a8747fd54e92e73f48118a807niklas.enbom@webrtc.org            {
3849dce40cf804019a9898b6ab8d8262466b697c56e0Peter Kasting                const size_t index =
3850dce40cf804019a9898b6ab8d8262466b697c56e0Peter Kasting                    sample * _audioFrame.num_channels_ + channel;
3851ae1a58bba4f926d149a5f39243269c3f6625f494andrew@webrtc.org                _audioFrame.data_[index] = toneBuffer[sample];
3852af26f646165e7e2a8747fd54e92e73f48118a807niklas.enbom@webrtc.org            }
3853af26f646165e7e2a8747fd54e92e73f48118a807niklas.enbom@webrtc.org        }
3854ae1a58bba4f926d149a5f39243269c3f6625f494andrew@webrtc.org
385563a509858d3988299726640c664b699d6229a1d4andrew@webrtc.org        assert(_audioFrame.samples_per_channel_ == toneSamples);
3856470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    } else
3857470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
3858470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        // Add 10ms to "delay-since-last-tone" counter
3859470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        _inbandDtmfGenerator.UpdateDelaySinceLastTone();
3860470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
3861470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    return 0;
3862470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com}
3863470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
38646141e13873d0fdea626de08dfec2efa2c9171c76pbos@webrtc.orgint32_t
38654591fbd09f9cb6e83433c49a12dd8524c2806502pkasting@chromium.orgChannel::SendPacketRaw(const void *data, size_t len, bool RTCP)
3866470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com{
3867fb648da2b9d33e8641c88a7f0559508539104b6dwu@webrtc.org    CriticalSectionScoped cs(&_callbackCritSect);
3868470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    if (_transportPtr == NULL)
3869470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
3870470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        return -1;
3871470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
3872470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    if (!RTCP)
3873470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
3874ac547a653862744d0aae560713f8418ad2852085Peter Boström        return _transportPtr->SendPacket(data, len);
3875470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
3876470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    else
3877470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
3878ac547a653862744d0aae560713f8418ad2852085Peter Boström        return _transportPtr->SendRTCPPacket(data, len);
3879470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
3880470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com}
3881470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
3882743758816853df2040a21c5652b0d0e238b1512fdeadbeefvoid Channel::UpdatePlayoutTimestamp(bool rtcp) {
3883743758816853df2040a21c5652b0d0e238b1512fdeadbeef  uint32_t playout_timestamp = 0;
3884743758816853df2040a21c5652b0d0e238b1512fdeadbeef
3885743758816853df2040a21c5652b0d0e238b1512fdeadbeef  if (audio_coding_->PlayoutTimestamp(&playout_timestamp) == -1)  {
3886743758816853df2040a21c5652b0d0e238b1512fdeadbeef    // This can happen if this channel has not been received any RTP packet. In
3887743758816853df2040a21c5652b0d0e238b1512fdeadbeef    // this case, NetEq is not capable of computing playout timestamp.
3888743758816853df2040a21c5652b0d0e238b1512fdeadbeef    return;
3889743758816853df2040a21c5652b0d0e238b1512fdeadbeef  }
3890743758816853df2040a21c5652b0d0e238b1512fdeadbeef
3891743758816853df2040a21c5652b0d0e238b1512fdeadbeef  uint16_t delay_ms = 0;
3892743758816853df2040a21c5652b0d0e238b1512fdeadbeef  if (_audioDeviceModulePtr->PlayoutDelay(&delay_ms) == -1) {
3893743758816853df2040a21c5652b0d0e238b1512fdeadbeef    WEBRTC_TRACE(kTraceWarning, kTraceVoice, VoEId(_instanceId,_channelId),
3894743758816853df2040a21c5652b0d0e238b1512fdeadbeef                 "Channel::UpdatePlayoutTimestamp() failed to read playout"
3895743758816853df2040a21c5652b0d0e238b1512fdeadbeef                 " delay from the ADM");
3896743758816853df2040a21c5652b0d0e238b1512fdeadbeef    _engineStatisticsPtr->SetLastError(
3897743758816853df2040a21c5652b0d0e238b1512fdeadbeef        VE_CANNOT_RETRIEVE_VALUE, kTraceError,
3898743758816853df2040a21c5652b0d0e238b1512fdeadbeef        "UpdatePlayoutTimestamp() failed to retrieve playout delay");
3899743758816853df2040a21c5652b0d0e238b1512fdeadbeef    return;
3900743758816853df2040a21c5652b0d0e238b1512fdeadbeef  }
3901743758816853df2040a21c5652b0d0e238b1512fdeadbeef
3902743758816853df2040a21c5652b0d0e238b1512fdeadbeef  jitter_buffer_playout_timestamp_ = playout_timestamp;
3903743758816853df2040a21c5652b0d0e238b1512fdeadbeef
3904743758816853df2040a21c5652b0d0e238b1512fdeadbeef  // Remove the playout delay.
3905743758816853df2040a21c5652b0d0e238b1512fdeadbeef  playout_timestamp -= (delay_ms * (GetPlayoutFrequency() / 1000));
3906743758816853df2040a21c5652b0d0e238b1512fdeadbeef
3907743758816853df2040a21c5652b0d0e238b1512fdeadbeef  WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
3908743758816853df2040a21c5652b0d0e238b1512fdeadbeef               "Channel::UpdatePlayoutTimestamp() => playoutTimestamp = %lu",
3909743758816853df2040a21c5652b0d0e238b1512fdeadbeef               playout_timestamp);
3910743758816853df2040a21c5652b0d0e238b1512fdeadbeef
3911743758816853df2040a21c5652b0d0e238b1512fdeadbeef  {
3912743758816853df2040a21c5652b0d0e238b1512fdeadbeef    CriticalSectionScoped cs(video_sync_lock_.get());
3913743758816853df2040a21c5652b0d0e238b1512fdeadbeef    if (rtcp) {
3914743758816853df2040a21c5652b0d0e238b1512fdeadbeef      playout_timestamp_rtcp_ = playout_timestamp;
3915743758816853df2040a21c5652b0d0e238b1512fdeadbeef    } else {
3916743758816853df2040a21c5652b0d0e238b1512fdeadbeef      playout_timestamp_rtp_ = playout_timestamp;
3917743758816853df2040a21c5652b0d0e238b1512fdeadbeef    }
3918743758816853df2040a21c5652b0d0e238b1512fdeadbeef    playout_delay_ms_ = delay_ms;
3919743758816853df2040a21c5652b0d0e238b1512fdeadbeef  }
3920743758816853df2040a21c5652b0d0e238b1512fdeadbeef}
3921743758816853df2040a21c5652b0d0e238b1512fdeadbeef
39221de01354e68da71bc62c81af17afeac8ed374a18pwestin@webrtc.org// Called for incoming RTP packets after successful RTP header parsing.
39231de01354e68da71bc62c81af17afeac8ed374a18pwestin@webrtc.orgvoid Channel::UpdatePacketDelay(uint32_t rtp_timestamp,
39241de01354e68da71bc62c81af17afeac8ed374a18pwestin@webrtc.org                                uint16_t sequence_number) {
39251de01354e68da71bc62c81af17afeac8ed374a18pwestin@webrtc.org  WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
39261de01354e68da71bc62c81af17afeac8ed374a18pwestin@webrtc.org               "Channel::UpdatePacketDelay(timestamp=%lu, sequenceNumber=%u)",
39271de01354e68da71bc62c81af17afeac8ed374a18pwestin@webrtc.org               rtp_timestamp, sequence_number);
3928470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
39291de01354e68da71bc62c81af17afeac8ed374a18pwestin@webrtc.org  // Get frequency of last received payload
393094454b71adc37e15fd3f5a5fc432063f05caabcbwu@webrtc.org  int rtp_receive_frequency = GetPlayoutFrequency();
3931470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
3932167b6dfc73fc2f4c47713bcbd89b58c52612983bturaj@webrtc.org  // |jitter_buffer_playout_timestamp_| updated in UpdatePlayoutTimestamp for
3933167b6dfc73fc2f4c47713bcbd89b58c52612983bturaj@webrtc.org  // every incoming packet.
3934167b6dfc73fc2f4c47713bcbd89b58c52612983bturaj@webrtc.org  uint32_t timestamp_diff_ms = (rtp_timestamp -
3935167b6dfc73fc2f4c47713bcbd89b58c52612983bturaj@webrtc.org      jitter_buffer_playout_timestamp_) / (rtp_receive_frequency / 1000);
3936d66929995ff62e92c6cb5177d059e85b902fd388henrik.lundin@webrtc.org  if (!IsNewerTimestamp(rtp_timestamp, jitter_buffer_playout_timestamp_) ||
3937d66929995ff62e92c6cb5177d059e85b902fd388henrik.lundin@webrtc.org      timestamp_diff_ms > (2 * kVoiceEngineMaxMinPlayoutDelayMs)) {
3938d66929995ff62e92c6cb5177d059e85b902fd388henrik.lundin@webrtc.org    // If |jitter_buffer_playout_timestamp_| is newer than the incoming RTP
3939d66929995ff62e92c6cb5177d059e85b902fd388henrik.lundin@webrtc.org    // timestamp, the resulting difference is negative, but is set to zero.
3940d66929995ff62e92c6cb5177d059e85b902fd388henrik.lundin@webrtc.org    // This can happen when a network glitch causes a packet to arrive late,
3941d66929995ff62e92c6cb5177d059e85b902fd388henrik.lundin@webrtc.org    // and during long comfort noise periods with clock drift.
3942d66929995ff62e92c6cb5177d059e85b902fd388henrik.lundin@webrtc.org    timestamp_diff_ms = 0;
3943d66929995ff62e92c6cb5177d059e85b902fd388henrik.lundin@webrtc.org  }
3944470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
39451de01354e68da71bc62c81af17afeac8ed374a18pwestin@webrtc.org  uint16_t packet_delay_ms = (rtp_timestamp - _previousTimestamp) /
39461de01354e68da71bc62c81af17afeac8ed374a18pwestin@webrtc.org      (rtp_receive_frequency / 1000);
3947470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
39481de01354e68da71bc62c81af17afeac8ed374a18pwestin@webrtc.org  _previousTimestamp = rtp_timestamp;
3949470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
39501de01354e68da71bc62c81af17afeac8ed374a18pwestin@webrtc.org  if (timestamp_diff_ms == 0) return;
39511de01354e68da71bc62c81af17afeac8ed374a18pwestin@webrtc.org
3952743758816853df2040a21c5652b0d0e238b1512fdeadbeef  {
3953743758816853df2040a21c5652b0d0e238b1512fdeadbeef    CriticalSectionScoped cs(video_sync_lock_.get());
39541de01354e68da71bc62c81af17afeac8ed374a18pwestin@webrtc.org
3955743758816853df2040a21c5652b0d0e238b1512fdeadbeef    if (packet_delay_ms >= 10 && packet_delay_ms <= 60) {
3956743758816853df2040a21c5652b0d0e238b1512fdeadbeef      _recPacketDelayMs = packet_delay_ms;
3957743758816853df2040a21c5652b0d0e238b1512fdeadbeef    }
39581de01354e68da71bc62c81af17afeac8ed374a18pwestin@webrtc.org
3959743758816853df2040a21c5652b0d0e238b1512fdeadbeef    if (_average_jitter_buffer_delay_us == 0) {
3960743758816853df2040a21c5652b0d0e238b1512fdeadbeef      _average_jitter_buffer_delay_us = timestamp_diff_ms * 1000;
3961743758816853df2040a21c5652b0d0e238b1512fdeadbeef      return;
3962743758816853df2040a21c5652b0d0e238b1512fdeadbeef    }
3963743758816853df2040a21c5652b0d0e238b1512fdeadbeef
3964743758816853df2040a21c5652b0d0e238b1512fdeadbeef    // Filter average delay value using exponential filter (alpha is
3965743758816853df2040a21c5652b0d0e238b1512fdeadbeef    // 7/8). We derive 1000 *_average_jitter_buffer_delay_us here (reduces
3966743758816853df2040a21c5652b0d0e238b1512fdeadbeef    // risk of rounding error) and compensate for it in GetDelayEstimate()
3967743758816853df2040a21c5652b0d0e238b1512fdeadbeef    // later.
3968743758816853df2040a21c5652b0d0e238b1512fdeadbeef    _average_jitter_buffer_delay_us = (_average_jitter_buffer_delay_us * 7 +
3969743758816853df2040a21c5652b0d0e238b1512fdeadbeef        1000 * timestamp_diff_ms + 500) / 8;
3970743758816853df2040a21c5652b0d0e238b1512fdeadbeef  }
3971470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com}
3972470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
3973470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.comvoid
3974470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.comChannel::RegisterReceiveCodecsToRTPModule()
3975470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com{
3976470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3977470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                 "Channel::RegisterReceiveCodecsToRTPModule()");
3978470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
3979470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
3980470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    CodecInst codec;
39816141e13873d0fdea626de08dfec2efa2c9171c76pbos@webrtc.org    const uint8_t nSupportedCodecs = AudioCodingModule::NumberOfCodecs();
3982470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
3983470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    for (int idx = 0; idx < nSupportedCodecs; idx++)
3984470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
3985470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        // Open up the RTP/RTCP receiver for all supported codecs
3986eb524d997b877ba9b0bcaf8c85eae52bd40c37e3andrew@webrtc.org        if ((audio_coding_->Codec(idx, &codec) == -1) ||
3987822fbd8b68ffdb481b9557e2950ae8d6657c8ce6wu@webrtc.org            (rtp_receiver_->RegisterReceivePayload(
3988822fbd8b68ffdb481b9557e2950ae8d6657c8ce6wu@webrtc.org                codec.plname,
3989822fbd8b68ffdb481b9557e2950ae8d6657c8ce6wu@webrtc.org                codec.pltype,
3990822fbd8b68ffdb481b9557e2950ae8d6657c8ce6wu@webrtc.org                codec.plfreq,
3991822fbd8b68ffdb481b9557e2950ae8d6657c8ce6wu@webrtc.org                codec.channels,
3992822fbd8b68ffdb481b9557e2950ae8d6657c8ce6wu@webrtc.org                (codec.rate < 0) ? 0 : codec.rate) == -1))
3993470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        {
3994470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            WEBRTC_TRACE(
3995470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                         kTraceWarning,
3996470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                         kTraceVoice,
3997470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                         VoEId(_instanceId, _channelId),
3998470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                         "Channel::RegisterReceiveCodecsToRTPModule() unable"
3999470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                         " to register %s (%d/%d/%d/%d) to RTP/RTCP receiver",
4000470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                         codec.plname, codec.pltype, codec.plfreq,
4001470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                         codec.channels, codec.rate);
4002470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        }
4003470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        else
4004470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        {
4005470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            WEBRTC_TRACE(
4006470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                         kTraceInfo,
4007470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                         kTraceVoice,
4008470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                         VoEId(_instanceId, _channelId),
4009470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                         "Channel::RegisterReceiveCodecsToRTPModule() %s "
4010fcd12b3b7d7e92d6f8cdfdf8277808ae52a07c36wu@webrtc.org                         "(%d/%d/%d/%d) has been added to the RTP/RTCP "
4011470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                         "receiver",
4012470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                         codec.plname, codec.pltype, codec.plfreq,
4013470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                         codec.channels, codec.rate);
4014470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        }
4015470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
4016470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com}
4017470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
40188c8ad85c5d70c38cea82f5b17794a4e7ab4cf531turaj@webrtc.org// Assuming this method is called with valid payload type.
401942259e7ebc7126f5a7036940fcab65b3f8d2af38turaj@webrtc.orgint Channel::SetRedPayloadType(int red_payload_type) {
402042259e7ebc7126f5a7036940fcab65b3f8d2af38turaj@webrtc.org  CodecInst codec;
402142259e7ebc7126f5a7036940fcab65b3f8d2af38turaj@webrtc.org  bool found_red = false;
402242259e7ebc7126f5a7036940fcab65b3f8d2af38turaj@webrtc.org
402342259e7ebc7126f5a7036940fcab65b3f8d2af38turaj@webrtc.org  // Get default RED settings from the ACM database
402442259e7ebc7126f5a7036940fcab65b3f8d2af38turaj@webrtc.org  const int num_codecs = AudioCodingModule::NumberOfCodecs();
402542259e7ebc7126f5a7036940fcab65b3f8d2af38turaj@webrtc.org  for (int idx = 0; idx < num_codecs; idx++) {
4026eb524d997b877ba9b0bcaf8c85eae52bd40c37e3andrew@webrtc.org    audio_coding_->Codec(idx, &codec);
402742259e7ebc7126f5a7036940fcab65b3f8d2af38turaj@webrtc.org    if (!STR_CASE_CMP(codec.plname, "RED")) {
402842259e7ebc7126f5a7036940fcab65b3f8d2af38turaj@webrtc.org      found_red = true;
402942259e7ebc7126f5a7036940fcab65b3f8d2af38turaj@webrtc.org      break;
403042259e7ebc7126f5a7036940fcab65b3f8d2af38turaj@webrtc.org    }
403142259e7ebc7126f5a7036940fcab65b3f8d2af38turaj@webrtc.org  }
403242259e7ebc7126f5a7036940fcab65b3f8d2af38turaj@webrtc.org
403342259e7ebc7126f5a7036940fcab65b3f8d2af38turaj@webrtc.org  if (!found_red) {
403442259e7ebc7126f5a7036940fcab65b3f8d2af38turaj@webrtc.org    _engineStatisticsPtr->SetLastError(
403542259e7ebc7126f5a7036940fcab65b3f8d2af38turaj@webrtc.org        VE_CODEC_ERROR, kTraceError,
403642259e7ebc7126f5a7036940fcab65b3f8d2af38turaj@webrtc.org        "SetRedPayloadType() RED is not supported");
403742259e7ebc7126f5a7036940fcab65b3f8d2af38turaj@webrtc.org    return -1;
403842259e7ebc7126f5a7036940fcab65b3f8d2af38turaj@webrtc.org  }
403942259e7ebc7126f5a7036940fcab65b3f8d2af38turaj@webrtc.org
40409d532fd2752290e85aa804f29ab9aa6c017c9208turaj@webrtc.org  codec.pltype = red_payload_type;
4041eb524d997b877ba9b0bcaf8c85eae52bd40c37e3andrew@webrtc.org  if (audio_coding_->RegisterSendCodec(codec) < 0) {
404242259e7ebc7126f5a7036940fcab65b3f8d2af38turaj@webrtc.org    _engineStatisticsPtr->SetLastError(
404342259e7ebc7126f5a7036940fcab65b3f8d2af38turaj@webrtc.org        VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
404442259e7ebc7126f5a7036940fcab65b3f8d2af38turaj@webrtc.org        "SetRedPayloadType() RED registration in ACM module failed");
404542259e7ebc7126f5a7036940fcab65b3f8d2af38turaj@webrtc.org    return -1;
404642259e7ebc7126f5a7036940fcab65b3f8d2af38turaj@webrtc.org  }
404742259e7ebc7126f5a7036940fcab65b3f8d2af38turaj@webrtc.org
404842259e7ebc7126f5a7036940fcab65b3f8d2af38turaj@webrtc.org  if (_rtpRtcpModule->SetSendREDPayloadType(red_payload_type) != 0) {
404942259e7ebc7126f5a7036940fcab65b3f8d2af38turaj@webrtc.org    _engineStatisticsPtr->SetLastError(
405042259e7ebc7126f5a7036940fcab65b3f8d2af38turaj@webrtc.org        VE_RTP_RTCP_MODULE_ERROR, kTraceError,
405142259e7ebc7126f5a7036940fcab65b3f8d2af38turaj@webrtc.org        "SetRedPayloadType() RED registration in RTP/RTCP module failed");
405242259e7ebc7126f5a7036940fcab65b3f8d2af38turaj@webrtc.org    return -1;
405342259e7ebc7126f5a7036940fcab65b3f8d2af38turaj@webrtc.org  }
405442259e7ebc7126f5a7036940fcab65b3f8d2af38turaj@webrtc.org  return 0;
405542259e7ebc7126f5a7036940fcab65b3f8d2af38turaj@webrtc.org}
405642259e7ebc7126f5a7036940fcab65b3f8d2af38turaj@webrtc.org
4057ebdb0e3ad0a787bee066d12cdcd115a38b0a10d1wu@webrtc.orgint Channel::SetSendRtpHeaderExtension(bool enable, RTPExtensionType type,
4058ebdb0e3ad0a787bee066d12cdcd115a38b0a10d1wu@webrtc.org                                       unsigned char id) {
4059ebdb0e3ad0a787bee066d12cdcd115a38b0a10d1wu@webrtc.org  int error = 0;
4060ebdb0e3ad0a787bee066d12cdcd115a38b0a10d1wu@webrtc.org  _rtpRtcpModule->DeregisterSendRtpHeaderExtension(type);
4061ebdb0e3ad0a787bee066d12cdcd115a38b0a10d1wu@webrtc.org  if (enable) {
4062ebdb0e3ad0a787bee066d12cdcd115a38b0a10d1wu@webrtc.org    error = _rtpRtcpModule->RegisterSendRtpHeaderExtension(type, id);
4063ebdb0e3ad0a787bee066d12cdcd115a38b0a10d1wu@webrtc.org  }
4064ebdb0e3ad0a787bee066d12cdcd115a38b0a10d1wu@webrtc.org  return error;
4065ebdb0e3ad0a787bee066d12cdcd115a38b0a10d1wu@webrtc.org}
4066c1a40a7b68a8d253b0ba32b89f3126931eeaeab3minyue@webrtc.org
406794454b71adc37e15fd3f5a5fc432063f05caabcbwu@webrtc.orgint32_t Channel::GetPlayoutFrequency() {
406894454b71adc37e15fd3f5a5fc432063f05caabcbwu@webrtc.org  int32_t playout_frequency = audio_coding_->PlayoutFrequency();
406994454b71adc37e15fd3f5a5fc432063f05caabcbwu@webrtc.org  CodecInst current_recive_codec;
407094454b71adc37e15fd3f5a5fc432063f05caabcbwu@webrtc.org  if (audio_coding_->ReceiveCodec(&current_recive_codec) == 0) {
407194454b71adc37e15fd3f5a5fc432063f05caabcbwu@webrtc.org    if (STR_CASE_CMP("G722", current_recive_codec.plname) == 0) {
407294454b71adc37e15fd3f5a5fc432063f05caabcbwu@webrtc.org      // Even though the actual sampling rate for G.722 audio is
407394454b71adc37e15fd3f5a5fc432063f05caabcbwu@webrtc.org      // 16,000 Hz, the RTP clock rate for the G722 payload format is
407494454b71adc37e15fd3f5a5fc432063f05caabcbwu@webrtc.org      // 8,000 Hz because that value was erroneously assigned in
407594454b71adc37e15fd3f5a5fc432063f05caabcbwu@webrtc.org      // RFC 1890 and must remain unchanged for backward compatibility.
407694454b71adc37e15fd3f5a5fc432063f05caabcbwu@webrtc.org      playout_frequency = 8000;
407794454b71adc37e15fd3f5a5fc432063f05caabcbwu@webrtc.org    } else if (STR_CASE_CMP("opus", current_recive_codec.plname) == 0) {
407894454b71adc37e15fd3f5a5fc432063f05caabcbwu@webrtc.org      // We are resampling Opus internally to 32,000 Hz until all our
407994454b71adc37e15fd3f5a5fc432063f05caabcbwu@webrtc.org      // DSP routines can operate at 48,000 Hz, but the RTP clock
408094454b71adc37e15fd3f5a5fc432063f05caabcbwu@webrtc.org      // rate for the Opus payload format is standardized to 48,000 Hz,
408194454b71adc37e15fd3f5a5fc432063f05caabcbwu@webrtc.org      // because that is the maximum supported decoding sampling rate.
408294454b71adc37e15fd3f5a5fc432063f05caabcbwu@webrtc.org      playout_frequency = 48000;
408394454b71adc37e15fd3f5a5fc432063f05caabcbwu@webrtc.org    }
408494454b71adc37e15fd3f5a5fc432063f05caabcbwu@webrtc.org  }
408594454b71adc37e15fd3f5a5fc432063f05caabcbwu@webrtc.org  return playout_frequency;
408694454b71adc37e15fd3f5a5fc432063f05caabcbwu@webrtc.org}
408794454b71adc37e15fd3f5a5fc432063f05caabcbwu@webrtc.org
40882013aeced2b7821a407f302802c4a16fd02728b1Minyueint64_t Channel::GetRTT(bool allow_associate_channel) const {
40892b58a4433f16c510d56b1d16d2e3bb882b184861minyue@webrtc.org  RTCPMethod method = _rtpRtcpModule->RTCP();
40902b58a4433f16c510d56b1d16d2e3bb882b184861minyue@webrtc.org  if (method == kRtcpOff) {
40912b58a4433f16c510d56b1d16d2e3bb882b184861minyue@webrtc.org    return 0;
40922b58a4433f16c510d56b1d16d2e3bb882b184861minyue@webrtc.org  }
40932b58a4433f16c510d56b1d16d2e3bb882b184861minyue@webrtc.org  std::vector<RTCPReportBlock> report_blocks;
40942b58a4433f16c510d56b1d16d2e3bb882b184861minyue@webrtc.org  _rtpRtcpModule->RemoteRTCPStat(&report_blocks);
40952013aeced2b7821a407f302802c4a16fd02728b1Minyue
40962013aeced2b7821a407f302802c4a16fd02728b1Minyue  int64_t rtt = 0;
40972b58a4433f16c510d56b1d16d2e3bb882b184861minyue@webrtc.org  if (report_blocks.empty()) {
40982013aeced2b7821a407f302802c4a16fd02728b1Minyue    if (allow_associate_channel) {
40992013aeced2b7821a407f302802c4a16fd02728b1Minyue      CriticalSectionScoped lock(assoc_send_channel_lock_.get());
41002013aeced2b7821a407f302802c4a16fd02728b1Minyue      Channel* channel = associate_send_channel_.channel();
41012013aeced2b7821a407f302802c4a16fd02728b1Minyue      // Tries to get RTT from an associated channel. This is important for
41022013aeced2b7821a407f302802c4a16fd02728b1Minyue      // receive-only channels.
41032013aeced2b7821a407f302802c4a16fd02728b1Minyue      if (channel) {
41042013aeced2b7821a407f302802c4a16fd02728b1Minyue        // To prevent infinite recursion and deadlock, calling GetRTT of
41052013aeced2b7821a407f302802c4a16fd02728b1Minyue        // associate channel should always use "false" for argument:
41062013aeced2b7821a407f302802c4a16fd02728b1Minyue        // |allow_associate_channel|.
41072013aeced2b7821a407f302802c4a16fd02728b1Minyue        rtt = channel->GetRTT(false);
41082013aeced2b7821a407f302802c4a16fd02728b1Minyue      }
41092013aeced2b7821a407f302802c4a16fd02728b1Minyue    }
41102013aeced2b7821a407f302802c4a16fd02728b1Minyue    return rtt;
41112b58a4433f16c510d56b1d16d2e3bb882b184861minyue@webrtc.org  }
41122b58a4433f16c510d56b1d16d2e3bb882b184861minyue@webrtc.org
41132b58a4433f16c510d56b1d16d2e3bb882b184861minyue@webrtc.org  uint32_t remoteSSRC = rtp_receiver_->SSRC();
41142b58a4433f16c510d56b1d16d2e3bb882b184861minyue@webrtc.org  std::vector<RTCPReportBlock>::const_iterator it = report_blocks.begin();
41152b58a4433f16c510d56b1d16d2e3bb882b184861minyue@webrtc.org  for (; it != report_blocks.end(); ++it) {
41162b58a4433f16c510d56b1d16d2e3bb882b184861minyue@webrtc.org    if (it->remoteSSRC == remoteSSRC)
41172b58a4433f16c510d56b1d16d2e3bb882b184861minyue@webrtc.org      break;
41182b58a4433f16c510d56b1d16d2e3bb882b184861minyue@webrtc.org  }
41192b58a4433f16c510d56b1d16d2e3bb882b184861minyue@webrtc.org  if (it == report_blocks.end()) {
41202b58a4433f16c510d56b1d16d2e3bb882b184861minyue@webrtc.org    // We have not received packets with SSRC matching the report blocks.
41212b58a4433f16c510d56b1d16d2e3bb882b184861minyue@webrtc.org    // To calculate RTT we try with the SSRC of the first report block.
41222b58a4433f16c510d56b1d16d2e3bb882b184861minyue@webrtc.org    // This is very important for send-only channels where we don't know
41232b58a4433f16c510d56b1d16d2e3bb882b184861minyue@webrtc.org    // the SSRC of the other end.
41242b58a4433f16c510d56b1d16d2e3bb882b184861minyue@webrtc.org    remoteSSRC = report_blocks[0].remoteSSRC;
41252b58a4433f16c510d56b1d16d2e3bb882b184861minyue@webrtc.org  }
41262013aeced2b7821a407f302802c4a16fd02728b1Minyue
412716825b1a828bb4ff40f7682040e43a239b7b8ca3pkasting@chromium.org  int64_t avg_rtt = 0;
412816825b1a828bb4ff40f7682040e43a239b7b8ca3pkasting@chromium.org  int64_t max_rtt= 0;
412916825b1a828bb4ff40f7682040e43a239b7b8ca3pkasting@chromium.org  int64_t min_rtt = 0;
41302b58a4433f16c510d56b1d16d2e3bb882b184861minyue@webrtc.org  if (_rtpRtcpModule->RTT(remoteSSRC, &rtt, &avg_rtt, &min_rtt, &max_rtt)
41312b58a4433f16c510d56b1d16d2e3bb882b184861minyue@webrtc.org      != 0) {
41322b58a4433f16c510d56b1d16d2e3bb882b184861minyue@webrtc.org    return 0;
41332b58a4433f16c510d56b1d16d2e3bb882b184861minyue@webrtc.org  }
413416825b1a828bb4ff40f7682040e43a239b7b8ca3pkasting@chromium.org  return rtt;
41352b58a4433f16c510d56b1d16d2e3bb882b184861minyue@webrtc.org}
41362b58a4433f16c510d56b1d16d2e3bb882b184861minyue@webrtc.org
4137d900e8bea84c474696bf0219aed1353ce65ffd8epbos@webrtc.org}  // namespace voe
4138d900e8bea84c474696bf0219aed1353ce65ffd8epbos@webrtc.org}  // namespace webrtc
4139