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>
14f888bb58da04c5095759b5ec7ce2e1fa2cd414fdTommi#include <utility>
1564dad838e61e92e4a72437b153c5eba7a200fb4aHenrik Lundin
16ae856f2c9fc358e5cd68d8a595136dcef017ed96Ivo Creusen#include "webrtc/base/checks.h"
174591fbd09f9cb6e83433c49a12dd8524c2806502pkasting@chromium.org#include "webrtc/base/format_macros.h"
18ad856229a796a8efa1126ef8aa8d238f2b0a2b21pbos#include "webrtc/base/logging.h"
19b86d4e4a8dec1eb1b801244a2a97cda66f561d8eStefan Holmer#include "webrtc/base/thread_checker.h"
2094454b71adc37e15fd3f5a5fc432063f05caabcbwu@webrtc.org#include "webrtc/base/timeutils.h"
21e509f943eded156f7a8365b0b001abe73646acfaminyue@webrtc.org#include "webrtc/common.h"
2264dad838e61e92e4a72437b153c5eba7a200fb4aHenrik Lundin#include "webrtc/config.h"
236388c3e2fdfc91b3648fb7d408a14ddb25e41cd1turaj@webrtc.org#include "webrtc/modules/audio_device/include/audio_device.h"
246388c3e2fdfc91b3648fb7d408a14ddb25e41cd1turaj@webrtc.org#include "webrtc/modules/audio_processing/include/audio_processing.h"
25ff761fba8274d93bd73e76c8b8a1f2d0776dd840Henrik Kjellander#include "webrtc/modules/include/module_common_types.h"
26b86d4e4a8dec1eb1b801244a2a97cda66f561d8eStefan Holmer#include "webrtc/modules/pacing/packet_router.h"
27ff761fba8274d93bd73e76c8b8a1f2d0776dd840Henrik Kjellander#include "webrtc/modules/rtp_rtcp/include/receive_statistics.h"
28ff761fba8274d93bd73e76c8b8a1f2d0776dd840Henrik Kjellander#include "webrtc/modules/rtp_rtcp/include/rtp_payload_registry.h"
29ff761fba8274d93bd73e76c8b8a1f2d0776dd840Henrik Kjellander#include "webrtc/modules/rtp_rtcp/include/rtp_receiver.h"
30822fbd8b68ffdb481b9557e2950ae8d6657c8ce6wu@webrtc.org#include "webrtc/modules/rtp_rtcp/source/rtp_receiver_strategy.h"
31ff761fba8274d93bd73e76c8b8a1f2d0776dd840Henrik Kjellander#include "webrtc/modules/utility/include/audio_frame_operations.h"
32ff761fba8274d93bd73e76c8b8a1f2d0776dd840Henrik Kjellander#include "webrtc/modules/utility/include/process_thread.h"
3398f53510b222f71fdd8b799b2f33737ceeb28c61Henrik Kjellander#include "webrtc/system_wrappers/include/critical_section_wrapper.h"
3498f53510b222f71fdd8b799b2f33737ceeb28c61Henrik Kjellander#include "webrtc/system_wrappers/include/trace.h"
356388c3e2fdfc91b3648fb7d408a14ddb25e41cd1turaj@webrtc.org#include "webrtc/voice_engine/include/voe_base.h"
366388c3e2fdfc91b3648fb7d408a14ddb25e41cd1turaj@webrtc.org#include "webrtc/voice_engine/include/voe_external_media.h"
376388c3e2fdfc91b3648fb7d408a14ddb25e41cd1turaj@webrtc.org#include "webrtc/voice_engine/include/voe_rtp_rtcp.h"
386388c3e2fdfc91b3648fb7d408a14ddb25e41cd1turaj@webrtc.org#include "webrtc/voice_engine/output_mixer.h"
396388c3e2fdfc91b3648fb7d408a14ddb25e41cd1turaj@webrtc.org#include "webrtc/voice_engine/statistics.h"
406388c3e2fdfc91b3648fb7d408a14ddb25e41cd1turaj@webrtc.org#include "webrtc/voice_engine/transmit_mixer.h"
416388c3e2fdfc91b3648fb7d408a14ddb25e41cd1turaj@webrtc.org#include "webrtc/voice_engine/utility.h"
42470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
43470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com#if defined(_WIN32)
44470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com#include <Qos.h>
45470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com#endif
46470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
4750419b07772de974964072478886c4c35ab9c8ccandrew@webrtc.orgnamespace webrtc {
4850419b07772de974964072478886c4c35ab9c8ccandrew@webrtc.orgnamespace voe {
49470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
50b86d4e4a8dec1eb1b801244a2a97cda66f561d8eStefan Holmerclass TransportFeedbackProxy : public TransportFeedbackObserver {
51b86d4e4a8dec1eb1b801244a2a97cda66f561d8eStefan Holmer public:
52b86d4e4a8dec1eb1b801244a2a97cda66f561d8eStefan Holmer  TransportFeedbackProxy() : feedback_observer_(nullptr) {
53b86d4e4a8dec1eb1b801244a2a97cda66f561d8eStefan Holmer    pacer_thread_.DetachFromThread();
54b86d4e4a8dec1eb1b801244a2a97cda66f561d8eStefan Holmer    network_thread_.DetachFromThread();
55b86d4e4a8dec1eb1b801244a2a97cda66f561d8eStefan Holmer  }
56b86d4e4a8dec1eb1b801244a2a97cda66f561d8eStefan Holmer
57b86d4e4a8dec1eb1b801244a2a97cda66f561d8eStefan Holmer  void SetTransportFeedbackObserver(
58b86d4e4a8dec1eb1b801244a2a97cda66f561d8eStefan Holmer      TransportFeedbackObserver* feedback_observer) {
59b86d4e4a8dec1eb1b801244a2a97cda66f561d8eStefan Holmer    RTC_DCHECK(thread_checker_.CalledOnValidThread());
60b86d4e4a8dec1eb1b801244a2a97cda66f561d8eStefan Holmer    rtc::CritScope lock(&crit_);
61b86d4e4a8dec1eb1b801244a2a97cda66f561d8eStefan Holmer    feedback_observer_ = feedback_observer;
62b86d4e4a8dec1eb1b801244a2a97cda66f561d8eStefan Holmer  }
63b86d4e4a8dec1eb1b801244a2a97cda66f561d8eStefan Holmer
64b86d4e4a8dec1eb1b801244a2a97cda66f561d8eStefan Holmer  // Implements TransportFeedbackObserver.
65b86d4e4a8dec1eb1b801244a2a97cda66f561d8eStefan Holmer  void AddPacket(uint16_t sequence_number,
66b86d4e4a8dec1eb1b801244a2a97cda66f561d8eStefan Holmer                 size_t length,
67b86d4e4a8dec1eb1b801244a2a97cda66f561d8eStefan Holmer                 bool was_paced) override {
68b86d4e4a8dec1eb1b801244a2a97cda66f561d8eStefan Holmer    RTC_DCHECK(pacer_thread_.CalledOnValidThread());
69b86d4e4a8dec1eb1b801244a2a97cda66f561d8eStefan Holmer    rtc::CritScope lock(&crit_);
70b86d4e4a8dec1eb1b801244a2a97cda66f561d8eStefan Holmer    if (feedback_observer_)
71b86d4e4a8dec1eb1b801244a2a97cda66f561d8eStefan Holmer      feedback_observer_->AddPacket(sequence_number, length, was_paced);
72b86d4e4a8dec1eb1b801244a2a97cda66f561d8eStefan Holmer  }
73b86d4e4a8dec1eb1b801244a2a97cda66f561d8eStefan Holmer  void OnTransportFeedback(const rtcp::TransportFeedback& feedback) override {
74b86d4e4a8dec1eb1b801244a2a97cda66f561d8eStefan Holmer    RTC_DCHECK(network_thread_.CalledOnValidThread());
75b86d4e4a8dec1eb1b801244a2a97cda66f561d8eStefan Holmer    rtc::CritScope lock(&crit_);
76b86d4e4a8dec1eb1b801244a2a97cda66f561d8eStefan Holmer    if (feedback_observer_)
77b86d4e4a8dec1eb1b801244a2a97cda66f561d8eStefan Holmer      feedback_observer_->OnTransportFeedback(feedback);
78b86d4e4a8dec1eb1b801244a2a97cda66f561d8eStefan Holmer  }
79b86d4e4a8dec1eb1b801244a2a97cda66f561d8eStefan Holmer
80b86d4e4a8dec1eb1b801244a2a97cda66f561d8eStefan Holmer private:
81b86d4e4a8dec1eb1b801244a2a97cda66f561d8eStefan Holmer  rtc::CriticalSection crit_;
82b86d4e4a8dec1eb1b801244a2a97cda66f561d8eStefan Holmer  rtc::ThreadChecker thread_checker_;
83b86d4e4a8dec1eb1b801244a2a97cda66f561d8eStefan Holmer  rtc::ThreadChecker pacer_thread_;
84b86d4e4a8dec1eb1b801244a2a97cda66f561d8eStefan Holmer  rtc::ThreadChecker network_thread_;
85b86d4e4a8dec1eb1b801244a2a97cda66f561d8eStefan Holmer  TransportFeedbackObserver* feedback_observer_ GUARDED_BY(&crit_);
86b86d4e4a8dec1eb1b801244a2a97cda66f561d8eStefan Holmer};
87b86d4e4a8dec1eb1b801244a2a97cda66f561d8eStefan Holmer
88b86d4e4a8dec1eb1b801244a2a97cda66f561d8eStefan Holmerclass TransportSequenceNumberProxy : public TransportSequenceNumberAllocator {
89b86d4e4a8dec1eb1b801244a2a97cda66f561d8eStefan Holmer public:
90b86d4e4a8dec1eb1b801244a2a97cda66f561d8eStefan Holmer  TransportSequenceNumberProxy() : seq_num_allocator_(nullptr) {
91b86d4e4a8dec1eb1b801244a2a97cda66f561d8eStefan Holmer    pacer_thread_.DetachFromThread();
92b86d4e4a8dec1eb1b801244a2a97cda66f561d8eStefan Holmer  }
93b86d4e4a8dec1eb1b801244a2a97cda66f561d8eStefan Holmer
94b86d4e4a8dec1eb1b801244a2a97cda66f561d8eStefan Holmer  void SetSequenceNumberAllocator(
95b86d4e4a8dec1eb1b801244a2a97cda66f561d8eStefan Holmer      TransportSequenceNumberAllocator* seq_num_allocator) {
96b86d4e4a8dec1eb1b801244a2a97cda66f561d8eStefan Holmer    RTC_DCHECK(thread_checker_.CalledOnValidThread());
97b86d4e4a8dec1eb1b801244a2a97cda66f561d8eStefan Holmer    rtc::CritScope lock(&crit_);
98b86d4e4a8dec1eb1b801244a2a97cda66f561d8eStefan Holmer    seq_num_allocator_ = seq_num_allocator;
99b86d4e4a8dec1eb1b801244a2a97cda66f561d8eStefan Holmer  }
100b86d4e4a8dec1eb1b801244a2a97cda66f561d8eStefan Holmer
101b86d4e4a8dec1eb1b801244a2a97cda66f561d8eStefan Holmer  // Implements TransportSequenceNumberAllocator.
102b86d4e4a8dec1eb1b801244a2a97cda66f561d8eStefan Holmer  uint16_t AllocateSequenceNumber() override {
103b86d4e4a8dec1eb1b801244a2a97cda66f561d8eStefan Holmer    RTC_DCHECK(pacer_thread_.CalledOnValidThread());
104b86d4e4a8dec1eb1b801244a2a97cda66f561d8eStefan Holmer    rtc::CritScope lock(&crit_);
105b86d4e4a8dec1eb1b801244a2a97cda66f561d8eStefan Holmer    if (!seq_num_allocator_)
106b86d4e4a8dec1eb1b801244a2a97cda66f561d8eStefan Holmer      return 0;
107b86d4e4a8dec1eb1b801244a2a97cda66f561d8eStefan Holmer    return seq_num_allocator_->AllocateSequenceNumber();
108b86d4e4a8dec1eb1b801244a2a97cda66f561d8eStefan Holmer  }
109b86d4e4a8dec1eb1b801244a2a97cda66f561d8eStefan Holmer
110b86d4e4a8dec1eb1b801244a2a97cda66f561d8eStefan Holmer private:
111b86d4e4a8dec1eb1b801244a2a97cda66f561d8eStefan Holmer  rtc::CriticalSection crit_;
112b86d4e4a8dec1eb1b801244a2a97cda66f561d8eStefan Holmer  rtc::ThreadChecker thread_checker_;
113b86d4e4a8dec1eb1b801244a2a97cda66f561d8eStefan Holmer  rtc::ThreadChecker pacer_thread_;
114b86d4e4a8dec1eb1b801244a2a97cda66f561d8eStefan Holmer  TransportSequenceNumberAllocator* seq_num_allocator_ GUARDED_BY(&crit_);
115b86d4e4a8dec1eb1b801244a2a97cda66f561d8eStefan Holmer};
116b86d4e4a8dec1eb1b801244a2a97cda66f561d8eStefan Holmer
117b86d4e4a8dec1eb1b801244a2a97cda66f561d8eStefan Holmerclass RtpPacketSenderProxy : public RtpPacketSender {
118b86d4e4a8dec1eb1b801244a2a97cda66f561d8eStefan Holmer public:
119b86d4e4a8dec1eb1b801244a2a97cda66f561d8eStefan Holmer  RtpPacketSenderProxy() : rtp_packet_sender_(nullptr) {
120b86d4e4a8dec1eb1b801244a2a97cda66f561d8eStefan Holmer  }
121b86d4e4a8dec1eb1b801244a2a97cda66f561d8eStefan Holmer
122b86d4e4a8dec1eb1b801244a2a97cda66f561d8eStefan Holmer  void SetPacketSender(RtpPacketSender* rtp_packet_sender) {
123b86d4e4a8dec1eb1b801244a2a97cda66f561d8eStefan Holmer    RTC_DCHECK(thread_checker_.CalledOnValidThread());
124b86d4e4a8dec1eb1b801244a2a97cda66f561d8eStefan Holmer    rtc::CritScope lock(&crit_);
125b86d4e4a8dec1eb1b801244a2a97cda66f561d8eStefan Holmer    rtp_packet_sender_ = rtp_packet_sender;
126b86d4e4a8dec1eb1b801244a2a97cda66f561d8eStefan Holmer  }
127b86d4e4a8dec1eb1b801244a2a97cda66f561d8eStefan Holmer
128b86d4e4a8dec1eb1b801244a2a97cda66f561d8eStefan Holmer  // Implements RtpPacketSender.
129b86d4e4a8dec1eb1b801244a2a97cda66f561d8eStefan Holmer  void InsertPacket(Priority priority,
130b86d4e4a8dec1eb1b801244a2a97cda66f561d8eStefan Holmer                    uint32_t ssrc,
131b86d4e4a8dec1eb1b801244a2a97cda66f561d8eStefan Holmer                    uint16_t sequence_number,
132b86d4e4a8dec1eb1b801244a2a97cda66f561d8eStefan Holmer                    int64_t capture_time_ms,
133b86d4e4a8dec1eb1b801244a2a97cda66f561d8eStefan Holmer                    size_t bytes,
134b86d4e4a8dec1eb1b801244a2a97cda66f561d8eStefan Holmer                    bool retransmission) override {
135b86d4e4a8dec1eb1b801244a2a97cda66f561d8eStefan Holmer    rtc::CritScope lock(&crit_);
136b86d4e4a8dec1eb1b801244a2a97cda66f561d8eStefan Holmer    if (rtp_packet_sender_) {
137b86d4e4a8dec1eb1b801244a2a97cda66f561d8eStefan Holmer      rtp_packet_sender_->InsertPacket(priority, ssrc, sequence_number,
138b86d4e4a8dec1eb1b801244a2a97cda66f561d8eStefan Holmer                                       capture_time_ms, bytes, retransmission);
139b86d4e4a8dec1eb1b801244a2a97cda66f561d8eStefan Holmer    }
140b86d4e4a8dec1eb1b801244a2a97cda66f561d8eStefan Holmer  }
141b86d4e4a8dec1eb1b801244a2a97cda66f561d8eStefan Holmer
142b86d4e4a8dec1eb1b801244a2a97cda66f561d8eStefan Holmer private:
143b86d4e4a8dec1eb1b801244a2a97cda66f561d8eStefan Holmer  rtc::ThreadChecker thread_checker_;
144b86d4e4a8dec1eb1b801244a2a97cda66f561d8eStefan Holmer  rtc::CriticalSection crit_;
145b86d4e4a8dec1eb1b801244a2a97cda66f561d8eStefan Holmer  RtpPacketSender* rtp_packet_sender_ GUARDED_BY(&crit_);
146b86d4e4a8dec1eb1b801244a2a97cda66f561d8eStefan Holmer};
147b86d4e4a8dec1eb1b801244a2a97cda66f561d8eStefan Holmer
14854ae4ffb9e235a9742e2b11298327e02d870571csprang@webrtc.org// Extend the default RTCP statistics struct with max_jitter, defined as the
14954ae4ffb9e235a9742e2b11298327e02d870571csprang@webrtc.org// maximum jitter value seen in an RTCP report block.
15054ae4ffb9e235a9742e2b11298327e02d870571csprang@webrtc.orgstruct ChannelStatistics : public RtcpStatistics {
15154ae4ffb9e235a9742e2b11298327e02d870571csprang@webrtc.org  ChannelStatistics() : rtcp(), max_jitter(0) {}
15254ae4ffb9e235a9742e2b11298327e02d870571csprang@webrtc.org
15354ae4ffb9e235a9742e2b11298327e02d870571csprang@webrtc.org  RtcpStatistics rtcp;
15454ae4ffb9e235a9742e2b11298327e02d870571csprang@webrtc.org  uint32_t max_jitter;
15554ae4ffb9e235a9742e2b11298327e02d870571csprang@webrtc.org};
15654ae4ffb9e235a9742e2b11298327e02d870571csprang@webrtc.org
15754ae4ffb9e235a9742e2b11298327e02d870571csprang@webrtc.org// Statistics callback, called at each generation of a new RTCP report block.
15854ae4ffb9e235a9742e2b11298327e02d870571csprang@webrtc.orgclass StatisticsProxy : public RtcpStatisticsCallback {
15954ae4ffb9e235a9742e2b11298327e02d870571csprang@webrtc.org public:
16054ae4ffb9e235a9742e2b11298327e02d870571csprang@webrtc.org  StatisticsProxy(uint32_t ssrc)
16154ae4ffb9e235a9742e2b11298327e02d870571csprang@webrtc.org   : stats_lock_(CriticalSectionWrapper::CreateCriticalSection()),
16254ae4ffb9e235a9742e2b11298327e02d870571csprang@webrtc.org     ssrc_(ssrc) {}
16354ae4ffb9e235a9742e2b11298327e02d870571csprang@webrtc.org  virtual ~StatisticsProxy() {}
16454ae4ffb9e235a9742e2b11298327e02d870571csprang@webrtc.org
16514665ff7d4024d07e58622f498b23fd980001871kjellander@webrtc.org  void StatisticsUpdated(const RtcpStatistics& statistics,
16614665ff7d4024d07e58622f498b23fd980001871kjellander@webrtc.org                         uint32_t ssrc) override {
16754ae4ffb9e235a9742e2b11298327e02d870571csprang@webrtc.org    if (ssrc != ssrc_)
16854ae4ffb9e235a9742e2b11298327e02d870571csprang@webrtc.org      return;
16954ae4ffb9e235a9742e2b11298327e02d870571csprang@webrtc.org
17054ae4ffb9e235a9742e2b11298327e02d870571csprang@webrtc.org    CriticalSectionScoped cs(stats_lock_.get());
17154ae4ffb9e235a9742e2b11298327e02d870571csprang@webrtc.org    stats_.rtcp = statistics;
17254ae4ffb9e235a9742e2b11298327e02d870571csprang@webrtc.org    if (statistics.jitter > stats_.max_jitter) {
17354ae4ffb9e235a9742e2b11298327e02d870571csprang@webrtc.org      stats_.max_jitter = statistics.jitter;
17454ae4ffb9e235a9742e2b11298327e02d870571csprang@webrtc.org    }
17554ae4ffb9e235a9742e2b11298327e02d870571csprang@webrtc.org  }
17654ae4ffb9e235a9742e2b11298327e02d870571csprang@webrtc.org
17714665ff7d4024d07e58622f498b23fd980001871kjellander@webrtc.org  void CNameChanged(const char* cname, uint32_t ssrc) override {}
178ce4e9a356200170abcdd44ff2af95f87a6781b8epbos@webrtc.org
17954ae4ffb9e235a9742e2b11298327e02d870571csprang@webrtc.org  ChannelStatistics GetStats() {
18054ae4ffb9e235a9742e2b11298327e02d870571csprang@webrtc.org    CriticalSectionScoped cs(stats_lock_.get());
18154ae4ffb9e235a9742e2b11298327e02d870571csprang@webrtc.org    return stats_;
18254ae4ffb9e235a9742e2b11298327e02d870571csprang@webrtc.org  }
18354ae4ffb9e235a9742e2b11298327e02d870571csprang@webrtc.org
18454ae4ffb9e235a9742e2b11298327e02d870571csprang@webrtc.org private:
18554ae4ffb9e235a9742e2b11298327e02d870571csprang@webrtc.org  // StatisticsUpdated calls are triggered from threads in the RTP module,
18654ae4ffb9e235a9742e2b11298327e02d870571csprang@webrtc.org  // while GetStats calls can be triggered from the public voice engine API,
18754ae4ffb9e235a9742e2b11298327e02d870571csprang@webrtc.org  // hence synchronization is needed.
18800b8f6b3643332cce1ee711715f7fbb824d793cakwiberg@webrtc.org  rtc::scoped_ptr<CriticalSectionWrapper> stats_lock_;
18954ae4ffb9e235a9742e2b11298327e02d870571csprang@webrtc.org  const uint32_t ssrc_;
19054ae4ffb9e235a9742e2b11298327e02d870571csprang@webrtc.org  ChannelStatistics stats_;
19154ae4ffb9e235a9742e2b11298327e02d870571csprang@webrtc.org};
19254ae4ffb9e235a9742e2b11298327e02d870571csprang@webrtc.org
1930a7d4eed98ccec0c2b3e7522e7b2dde1919a4ae3mflodman@webrtc.orgclass VoERtcpObserver : public RtcpBandwidthObserver {
194c1a40a7b68a8d253b0ba32b89f3126931eeaeab3minyue@webrtc.org public:
1950a7d4eed98ccec0c2b3e7522e7b2dde1919a4ae3mflodman@webrtc.org  explicit VoERtcpObserver(Channel* owner) : owner_(owner) {}
1960a7d4eed98ccec0c2b3e7522e7b2dde1919a4ae3mflodman@webrtc.org  virtual ~VoERtcpObserver() {}
1970a7d4eed98ccec0c2b3e7522e7b2dde1919a4ae3mflodman@webrtc.org
1980a7d4eed98ccec0c2b3e7522e7b2dde1919a4ae3mflodman@webrtc.org  void OnReceivedEstimatedBitrate(uint32_t bitrate) override {
1990a7d4eed98ccec0c2b3e7522e7b2dde1919a4ae3mflodman@webrtc.org    // Not used for Voice Engine.
2000a7d4eed98ccec0c2b3e7522e7b2dde1919a4ae3mflodman@webrtc.org  }
2010a7d4eed98ccec0c2b3e7522e7b2dde1919a4ae3mflodman@webrtc.org
20214665ff7d4024d07e58622f498b23fd980001871kjellander@webrtc.org  void OnReceivedRtcpReceiverReport(const ReportBlockList& report_blocks,
20314665ff7d4024d07e58622f498b23fd980001871kjellander@webrtc.org                                    int64_t rtt,
20414665ff7d4024d07e58622f498b23fd980001871kjellander@webrtc.org                                    int64_t now_ms) override {
2050a7d4eed98ccec0c2b3e7522e7b2dde1919a4ae3mflodman@webrtc.org    // TODO(mflodman): Do we need to aggregate reports here or can we jut send
2060a7d4eed98ccec0c2b3e7522e7b2dde1919a4ae3mflodman@webrtc.org    // what we get? I.e. do we ever get multiple reports bundled into one RTCP
2070a7d4eed98ccec0c2b3e7522e7b2dde1919a4ae3mflodman@webrtc.org    // report for VoiceEngine?
2080a7d4eed98ccec0c2b3e7522e7b2dde1919a4ae3mflodman@webrtc.org    if (report_blocks.empty())
2090a7d4eed98ccec0c2b3e7522e7b2dde1919a4ae3mflodman@webrtc.org      return;
2100a7d4eed98ccec0c2b3e7522e7b2dde1919a4ae3mflodman@webrtc.org
2110a7d4eed98ccec0c2b3e7522e7b2dde1919a4ae3mflodman@webrtc.org    int fraction_lost_aggregate = 0;
2120a7d4eed98ccec0c2b3e7522e7b2dde1919a4ae3mflodman@webrtc.org    int total_number_of_packets = 0;
2130a7d4eed98ccec0c2b3e7522e7b2dde1919a4ae3mflodman@webrtc.org
2140a7d4eed98ccec0c2b3e7522e7b2dde1919a4ae3mflodman@webrtc.org    // If receiving multiple report blocks, calculate the weighted average based
2150a7d4eed98ccec0c2b3e7522e7b2dde1919a4ae3mflodman@webrtc.org    // on the number of packets a report refers to.
2160a7d4eed98ccec0c2b3e7522e7b2dde1919a4ae3mflodman@webrtc.org    for (ReportBlockList::const_iterator block_it = report_blocks.begin();
2170a7d4eed98ccec0c2b3e7522e7b2dde1919a4ae3mflodman@webrtc.org         block_it != report_blocks.end(); ++block_it) {
2180a7d4eed98ccec0c2b3e7522e7b2dde1919a4ae3mflodman@webrtc.org      // Find the previous extended high sequence number for this remote SSRC,
2190a7d4eed98ccec0c2b3e7522e7b2dde1919a4ae3mflodman@webrtc.org      // to calculate the number of RTP packets this report refers to. Ignore if
2200a7d4eed98ccec0c2b3e7522e7b2dde1919a4ae3mflodman@webrtc.org      // we haven't seen this SSRC before.
2210a7d4eed98ccec0c2b3e7522e7b2dde1919a4ae3mflodman@webrtc.org      std::map<uint32_t, uint32_t>::iterator seq_num_it =
2220a7d4eed98ccec0c2b3e7522e7b2dde1919a4ae3mflodman@webrtc.org          extended_max_sequence_number_.find(block_it->sourceSSRC);
2230a7d4eed98ccec0c2b3e7522e7b2dde1919a4ae3mflodman@webrtc.org      int number_of_packets = 0;
2240a7d4eed98ccec0c2b3e7522e7b2dde1919a4ae3mflodman@webrtc.org      if (seq_num_it != extended_max_sequence_number_.end()) {
2250a7d4eed98ccec0c2b3e7522e7b2dde1919a4ae3mflodman@webrtc.org        number_of_packets = block_it->extendedHighSeqNum - seq_num_it->second;
2260a7d4eed98ccec0c2b3e7522e7b2dde1919a4ae3mflodman@webrtc.org      }
2270a7d4eed98ccec0c2b3e7522e7b2dde1919a4ae3mflodman@webrtc.org      fraction_lost_aggregate += number_of_packets * block_it->fractionLost;
2280a7d4eed98ccec0c2b3e7522e7b2dde1919a4ae3mflodman@webrtc.org      total_number_of_packets += number_of_packets;
2290a7d4eed98ccec0c2b3e7522e7b2dde1919a4ae3mflodman@webrtc.org
2300a7d4eed98ccec0c2b3e7522e7b2dde1919a4ae3mflodman@webrtc.org      extended_max_sequence_number_[block_it->sourceSSRC] =
2310a7d4eed98ccec0c2b3e7522e7b2dde1919a4ae3mflodman@webrtc.org          block_it->extendedHighSeqNum;
2320a7d4eed98ccec0c2b3e7522e7b2dde1919a4ae3mflodman@webrtc.org    }
2330a7d4eed98ccec0c2b3e7522e7b2dde1919a4ae3mflodman@webrtc.org    int weighted_fraction_lost = 0;
2340a7d4eed98ccec0c2b3e7522e7b2dde1919a4ae3mflodman@webrtc.org    if (total_number_of_packets > 0) {
2350a7d4eed98ccec0c2b3e7522e7b2dde1919a4ae3mflodman@webrtc.org      weighted_fraction_lost = (fraction_lost_aggregate +
2360a7d4eed98ccec0c2b3e7522e7b2dde1919a4ae3mflodman@webrtc.org          total_number_of_packets / 2) / total_number_of_packets;
2370a7d4eed98ccec0c2b3e7522e7b2dde1919a4ae3mflodman@webrtc.org    }
2380a7d4eed98ccec0c2b3e7522e7b2dde1919a4ae3mflodman@webrtc.org    owner_->OnIncomingFractionLoss(weighted_fraction_lost);
239c1a40a7b68a8d253b0ba32b89f3126931eeaeab3minyue@webrtc.org  }
240c1a40a7b68a8d253b0ba32b89f3126931eeaeab3minyue@webrtc.org
241c1a40a7b68a8d253b0ba32b89f3126931eeaeab3minyue@webrtc.org private:
242c1a40a7b68a8d253b0ba32b89f3126931eeaeab3minyue@webrtc.org  Channel* owner_;
2430a7d4eed98ccec0c2b3e7522e7b2dde1919a4ae3mflodman@webrtc.org  // Maps remote side ssrc to extended highest sequence number received.
2440a7d4eed98ccec0c2b3e7522e7b2dde1919a4ae3mflodman@webrtc.org  std::map<uint32_t, uint32_t> extended_max_sequence_number_;
245c1a40a7b68a8d253b0ba32b89f3126931eeaeab3minyue@webrtc.org};
246c1a40a7b68a8d253b0ba32b89f3126931eeaeab3minyue@webrtc.org
2476141e13873d0fdea626de08dfec2efa2c9171c76pbos@webrtc.orgint32_t
248470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.comChannel::SendData(FrameType frameType,
2496141e13873d0fdea626de08dfec2efa2c9171c76pbos@webrtc.org                  uint8_t   payloadType,
2506141e13873d0fdea626de08dfec2efa2c9171c76pbos@webrtc.org                  uint32_t  timeStamp,
2516141e13873d0fdea626de08dfec2efa2c9171c76pbos@webrtc.org                  const uint8_t*  payloadData,
2524591fbd09f9cb6e83433c49a12dd8524c2806502pkasting@chromium.org                  size_t    payloadSize,
253470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                  const RTPFragmentationHeader* fragmentation)
254470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com{
255470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
256470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                 "Channel::SendData(frameType=%u, payloadType=%u, timeStamp=%u,"
2574591fbd09f9cb6e83433c49a12dd8524c2806502pkasting@chromium.org                 " payloadSize=%" PRIuS ", fragmentation=0x%x)",
2584591fbd09f9cb6e83433c49a12dd8524c2806502pkasting@chromium.org                 frameType, payloadType, timeStamp,
2594591fbd09f9cb6e83433c49a12dd8524c2806502pkasting@chromium.org                 payloadSize, fragmentation);
260470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
261470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    if (_includeAudioLevelIndication)
262470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
263470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        // Store current audio level in the RTP/RTCP module.
264470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        // The level will be used in combination with voice-activity state
265470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        // (frameType) to add an RTP header extension
266382c0c209d323c1e6972d988a7b26f08fc2e8a6bandrew@webrtc.org        _rtpRtcpModule->SetAudioLevel(rms_level_.RMS());
267470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
268470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
269470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    // Push data from ACM to RTP/RTCP-module to deliver audio frame for
270470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    // packetization.
271470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    // This call will trigger Transport::SendPacket() from the RTP/RTCP module.
2722853dde5201d9ddc284ce5efb9688f6340487acepwestin@webrtc.org    if (_rtpRtcpModule->SendOutgoingData((FrameType&)frameType,
273470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                                        payloadType,
274470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                                        timeStamp,
275ddfdfed3b55de3da5fda9a55d34e46d6e422baafstefan@webrtc.org                                        // Leaving the time when this frame was
276ddfdfed3b55de3da5fda9a55d34e46d6e422baafstefan@webrtc.org                                        // received from the capture device as
277ddfdfed3b55de3da5fda9a55d34e46d6e422baafstefan@webrtc.org                                        // undefined for voice for now.
278ddfdfed3b55de3da5fda9a55d34e46d6e422baafstefan@webrtc.org                                        -1,
279470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                                        payloadData,
280470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                                        payloadSize,
281470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                                        fragmentation) == -1)
282470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
283470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        _engineStatisticsPtr->SetLastError(
284470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            VE_RTP_RTCP_MODULE_ERROR, kTraceWarning,
285470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            "Channel::SendData() failed to send data to RTP/RTCP module");
286470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        return -1;
287470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
288470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
289470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    _lastLocalTimeStamp = timeStamp;
290470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    _lastPayloadType = payloadType;
291470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
292470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    return 0;
293470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com}
294470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
2956141e13873d0fdea626de08dfec2efa2c9171c76pbos@webrtc.orgint32_t
296e9217b4bdbf9a8fd8b4882b2f995665927f28ad2henrik.lundin@webrtc.orgChannel::InFrameType(FrameType frame_type)
297470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com{
298470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
299e9217b4bdbf9a8fd8b4882b2f995665927f28ad2henrik.lundin@webrtc.org                 "Channel::InFrameType(frame_type=%d)", frame_type);
300470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
3019a065d1eae9ed296e1e2eaaad73d7ca1223bfe79mflodman@webrtc.org    CriticalSectionScoped cs(&_callbackCritSect);
302e9217b4bdbf9a8fd8b4882b2f995665927f28ad2henrik.lundin@webrtc.org    _sendFrameType = (frame_type == kAudioFrameSpeech);
303470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    return 0;
304470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com}
305470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
3066141e13873d0fdea626de08dfec2efa2c9171c76pbos@webrtc.orgint32_t
3079213521ea98b0977c7cdabd2853060835af226f3pbos@webrtc.orgChannel::OnRxVadDetected(int vadDecision)
308470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com{
3099a065d1eae9ed296e1e2eaaad73d7ca1223bfe79mflodman@webrtc.org    CriticalSectionScoped cs(&_callbackCritSect);
310470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    if (_rxVadObserverPtr)
311470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
312470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        _rxVadObserverPtr->OnRxVad(_channelId, vadDecision);
313470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
314470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
315470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    return 0;
316470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com}
317470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
3181d8a506405734d0cef9653704b036ca4f1388960stefanbool Channel::SendRtp(const uint8_t* data,
3191d8a506405734d0cef9653704b036ca4f1388960stefan                      size_t len,
3201d8a506405734d0cef9653704b036ca4f1388960stefan                      const PacketOptions& options) {
321470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
322ac547a653862744d0aae560713f8418ad2852085Peter Boström                 "Channel::SendPacket(channel=%d, len=%" PRIuS ")", len);
323470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
324fb648da2b9d33e8641c88a7f0559508539104b6dwu@webrtc.org    CriticalSectionScoped cs(&_callbackCritSect);
325fb648da2b9d33e8641c88a7f0559508539104b6dwu@webrtc.org
326470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    if (_transportPtr == NULL)
327470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
328470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        WEBRTC_TRACE(kTraceError, kTraceVoice, VoEId(_instanceId,_channelId),
329470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                     "Channel::SendPacket() failed to send RTP packet due to"
330470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                     " invalid transport object");
3312d566686a23fe93ada58f1c38a0d4b9a0d68556epbos        return false;
332470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
333470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
3346141e13873d0fdea626de08dfec2efa2c9171c76pbos@webrtc.org    uint8_t* bufferToSendPtr = (uint8_t*)data;
3354591fbd09f9cb6e83433c49a12dd8524c2806502pkasting@chromium.org    size_t bufferLength = len;
336470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
3371d8a506405734d0cef9653704b036ca4f1388960stefan    if (!_transportPtr->SendRtp(bufferToSendPtr, bufferLength, options)) {
338fb648da2b9d33e8641c88a7f0559508539104b6dwu@webrtc.org      std::string transport_name =
339fb648da2b9d33e8641c88a7f0559508539104b6dwu@webrtc.org          _externalTransport ? "external transport" : "WebRtc sockets";
340fb648da2b9d33e8641c88a7f0559508539104b6dwu@webrtc.org      WEBRTC_TRACE(kTraceError, kTraceVoice,
341fb648da2b9d33e8641c88a7f0559508539104b6dwu@webrtc.org                   VoEId(_instanceId,_channelId),
342fb648da2b9d33e8641c88a7f0559508539104b6dwu@webrtc.org                   "Channel::SendPacket() RTP transmission using %s failed",
343fb648da2b9d33e8641c88a7f0559508539104b6dwu@webrtc.org                   transport_name.c_str());
3442d566686a23fe93ada58f1c38a0d4b9a0d68556epbos      return false;
345470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
3462d566686a23fe93ada58f1c38a0d4b9a0d68556epbos    return true;
347470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com}
348470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
3492d566686a23fe93ada58f1c38a0d4b9a0d68556epbosbool
3502d566686a23fe93ada58f1c38a0d4b9a0d68556epbosChannel::SendRtcp(const uint8_t *data, size_t len)
351470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com{
352470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
3532d566686a23fe93ada58f1c38a0d4b9a0d68556epbos                 "Channel::SendRtcp(len=%" PRIuS ")", len);
354470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
355fb648da2b9d33e8641c88a7f0559508539104b6dwu@webrtc.org    CriticalSectionScoped cs(&_callbackCritSect);
356fb648da2b9d33e8641c88a7f0559508539104b6dwu@webrtc.org    if (_transportPtr == NULL)
357470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
358fb648da2b9d33e8641c88a7f0559508539104b6dwu@webrtc.org        WEBRTC_TRACE(kTraceError, kTraceVoice,
359fb648da2b9d33e8641c88a7f0559508539104b6dwu@webrtc.org                     VoEId(_instanceId,_channelId),
3602d566686a23fe93ada58f1c38a0d4b9a0d68556epbos                     "Channel::SendRtcp() failed to send RTCP packet"
361fb648da2b9d33e8641c88a7f0559508539104b6dwu@webrtc.org                     " due to invalid transport object");
3622d566686a23fe93ada58f1c38a0d4b9a0d68556epbos        return false;
363470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
364470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
3656141e13873d0fdea626de08dfec2efa2c9171c76pbos@webrtc.org    uint8_t* bufferToSendPtr = (uint8_t*)data;
3664591fbd09f9cb6e83433c49a12dd8524c2806502pkasting@chromium.org    size_t bufferLength = len;
367470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
3682d566686a23fe93ada58f1c38a0d4b9a0d68556epbos    int n = _transportPtr->SendRtcp(bufferToSendPtr, bufferLength);
369fb648da2b9d33e8641c88a7f0559508539104b6dwu@webrtc.org    if (n < 0) {
370fb648da2b9d33e8641c88a7f0559508539104b6dwu@webrtc.org      std::string transport_name =
371fb648da2b9d33e8641c88a7f0559508539104b6dwu@webrtc.org          _externalTransport ? "external transport" : "WebRtc sockets";
372fb648da2b9d33e8641c88a7f0559508539104b6dwu@webrtc.org      WEBRTC_TRACE(kTraceInfo, kTraceVoice,
373fb648da2b9d33e8641c88a7f0559508539104b6dwu@webrtc.org                   VoEId(_instanceId,_channelId),
3742d566686a23fe93ada58f1c38a0d4b9a0d68556epbos                   "Channel::SendRtcp() transmission using %s failed",
375fb648da2b9d33e8641c88a7f0559508539104b6dwu@webrtc.org                   transport_name.c_str());
3762d566686a23fe93ada58f1c38a0d4b9a0d68556epbos      return false;
377470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
3782d566686a23fe93ada58f1c38a0d4b9a0d68556epbos    return true;
379470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com}
380470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
381ac547a653862744d0aae560713f8418ad2852085Peter Boströmvoid Channel::OnPlayTelephoneEvent(uint8_t event,
382ac547a653862744d0aae560713f8418ad2852085Peter Boström                                   uint16_t lengthMs,
383ac547a653862744d0aae560713f8418ad2852085Peter Boström                                   uint8_t volume) {
384470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
385ac547a653862744d0aae560713f8418ad2852085Peter Boström                 "Channel::OnPlayTelephoneEvent(event=%u, lengthMs=%u,"
386ac547a653862744d0aae560713f8418ad2852085Peter Boström                 " volume=%u)", event, lengthMs, volume);
387470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
388470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    if (!_playOutbandDtmfEvent || (event > 15))
389470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
390470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        // Ignore callback since feedback is disabled or event is not a
391470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        // Dtmf tone event.
392470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        return;
393470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
394470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
395470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    assert(_outputMixerPtr != NULL);
396470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
397470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    // Start playing out the Dtmf tone (if playout is enabled).
398470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    // Reduce length of tone with 80ms to the reduce risk of echo.
399470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    _outputMixerPtr->PlayDtmfTone(event, lengthMs - 80, volume);
400470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com}
401470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
402470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.comvoid
403ac547a653862744d0aae560713f8418ad2852085Peter BoströmChannel::OnIncomingSSRCChanged(uint32_t ssrc)
404470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com{
405470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
406ac547a653862744d0aae560713f8418ad2852085Peter Boström                 "Channel::OnIncomingSSRCChanged(SSRC=%d)", ssrc);
407470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
408b295a3f5920e2706d42c960c5180c7cc6e1f435edwkang@webrtc.org    // Update ssrc so that NTP for AV sync can be updated.
409b295a3f5920e2706d42c960c5180c7cc6e1f435edwkang@webrtc.org    _rtpRtcpModule->SetRemoteSSRC(ssrc);
410470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com}
411470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
412ac547a653862744d0aae560713f8418ad2852085Peter Boströmvoid Channel::OnIncomingCSRCChanged(uint32_t CSRC, bool added) {
413ac547a653862744d0aae560713f8418ad2852085Peter Boström  WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
414ac547a653862744d0aae560713f8418ad2852085Peter Boström               "Channel::OnIncomingCSRCChanged(CSRC=%d, added=%d)", CSRC,
415ac547a653862744d0aae560713f8418ad2852085Peter Boström               added);
416470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com}
417470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
418ac547a653862744d0aae560713f8418ad2852085Peter Boströmint32_t Channel::OnInitializeDecoder(
4199213521ea98b0977c7cdabd2853060835af226f3pbos@webrtc.org    int8_t payloadType,
420813e4b0af06272dada388c2d8383b2e36a1da6a6leozwang@webrtc.org    const char payloadName[RTP_PAYLOAD_NAME_SIZE],
4219213521ea98b0977c7cdabd2853060835af226f3pbos@webrtc.org    int frequency,
4226955870806624479723addfae6dcf5d13968796cPeter Kasting    size_t channels,
423ac547a653862744d0aae560713f8418ad2852085Peter Boström    uint32_t rate) {
424470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
425ac547a653862744d0aae560713f8418ad2852085Peter Boström                 "Channel::OnInitializeDecoder(payloadType=%d, "
4266955870806624479723addfae6dcf5d13968796cPeter Kasting                 "payloadName=%s, frequency=%u, channels=%" PRIuS ", rate=%u)",
427ac547a653862744d0aae560713f8418ad2852085Peter Boström                 payloadType, payloadName, frequency, channels, rate);
428470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
429f75901fa4c5f9a1bcefc265b98a480c72119650chenrika@webrtc.org    CodecInst receiveCodec = {0};
430f75901fa4c5f9a1bcefc265b98a480c72119650chenrika@webrtc.org    CodecInst dummyCodec = {0};
431470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
432470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    receiveCodec.pltype = payloadType;
433470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    receiveCodec.plfreq = frequency;
434470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    receiveCodec.channels = channels;
435470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    receiveCodec.rate = rate;
436f75901fa4c5f9a1bcefc265b98a480c72119650chenrika@webrtc.org    strncpy(receiveCodec.plname, payloadName, RTP_PAYLOAD_NAME_SIZE - 1);
437ae1a58bba4f926d149a5f39243269c3f6625f494andrew@webrtc.org
438eb524d997b877ba9b0bcaf8c85eae52bd40c37e3andrew@webrtc.org    audio_coding_->Codec(payloadName, &dummyCodec, frequency, channels);
439470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    receiveCodec.pacsize = dummyCodec.pacsize;
440470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
441470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    // Register the new codec to the ACM
442eb524d997b877ba9b0bcaf8c85eae52bd40c37e3andrew@webrtc.org    if (audio_coding_->RegisterReceiveCodec(receiveCodec) == -1)
443470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
444470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        WEBRTC_TRACE(kTraceWarning, kTraceVoice,
445ceb148ce593627ed0d30a1a8c01752bdebf9172dandrew@webrtc.org                     VoEId(_instanceId, _channelId),
446470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                     "Channel::OnInitializeDecoder() invalid codec ("
447470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                     "pt=%d, name=%s) received - 1", payloadType, payloadName);
448470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        _engineStatisticsPtr->SetLastError(VE_AUDIO_CODING_MODULE_ERROR);
449470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        return -1;
450470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
451470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
452470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    return 0;
453470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com}
454470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
4556141e13873d0fdea626de08dfec2efa2c9171c76pbos@webrtc.orgint32_t
4566141e13873d0fdea626de08dfec2efa2c9171c76pbos@webrtc.orgChannel::OnReceivedPayloadData(const uint8_t* payloadData,
4574591fbd09f9cb6e83433c49a12dd8524c2806502pkasting@chromium.org                               size_t payloadSize,
458470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                               const WebRtcRTPHeader* rtpHeader)
459470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com{
460470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
4614591fbd09f9cb6e83433c49a12dd8524c2806502pkasting@chromium.org                 "Channel::OnReceivedPayloadData(payloadSize=%" PRIuS ","
4626955870806624479723addfae6dcf5d13968796cPeter Kasting                 " payloadType=%u, audioChannel=%" PRIuS ")",
463470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                 payloadSize,
464470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                 rtpHeader->header.payloadType,
465470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                 rtpHeader->type.Audio.channel);
466470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
467944cbeb2926feb86a687e5fda9e2ac88ea8e3001henrika@webrtc.org    if (!channel_state_.Get().playing)
468470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
469470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        // Avoid inserting into NetEQ when we are not playing. Count the
470470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        // packet as discarded.
471470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        WEBRTC_TRACE(kTraceStream, kTraceVoice,
472470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                     VoEId(_instanceId, _channelId),
473470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                     "received packet is discarded since playing is not"
474470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                     " activated");
475470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        _numberOfDiscardedPackets++;
476470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        return 0;
477470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
478470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
479470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    // Push the incoming payload (parsed and ready for decoding) into the ACM
480eb524d997b877ba9b0bcaf8c85eae52bd40c37e3andrew@webrtc.org    if (audio_coding_->IncomingPacket(payloadData,
481eb524d997b877ba9b0bcaf8c85eae52bd40c37e3andrew@webrtc.org                                      payloadSize,
482eb524d997b877ba9b0bcaf8c85eae52bd40c37e3andrew@webrtc.org                                      *rtpHeader) != 0)
483470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
484470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        _engineStatisticsPtr->SetLastError(
485470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            VE_AUDIO_CODING_MODULE_ERROR, kTraceWarning,
486470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            "Channel::OnReceivedPayloadData() unable to push data to the ACM");
487470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        return -1;
488470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
489470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
490d30859e58e2c0b0676ab2b52b8a2723e10d49e28pwestin@webrtc.org    // Update the packet delay.
491470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    UpdatePacketDelay(rtpHeader->header.timestamp,
492470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                      rtpHeader->header.sequenceNumber);
493d30859e58e2c0b0676ab2b52b8a2723e10d49e28pwestin@webrtc.org
49416825b1a828bb4ff40f7682040e43a239b7b8ca3pkasting@chromium.org    int64_t round_trip_time = 0;
495822fbd8b68ffdb481b9557e2950ae8d6657c8ce6wu@webrtc.org    _rtpRtcpModule->RTT(rtp_receiver_->SSRC(), &round_trip_time,
496822fbd8b68ffdb481b9557e2950ae8d6657c8ce6wu@webrtc.org                        NULL, NULL, NULL);
497822fbd8b68ffdb481b9557e2950ae8d6657c8ce6wu@webrtc.org
498eb524d997b877ba9b0bcaf8c85eae52bd40c37e3andrew@webrtc.org    std::vector<uint16_t> nack_list = audio_coding_->GetNackList(
499822fbd8b68ffdb481b9557e2950ae8d6657c8ce6wu@webrtc.org        round_trip_time);
500822fbd8b68ffdb481b9557e2950ae8d6657c8ce6wu@webrtc.org    if (!nack_list.empty()) {
501822fbd8b68ffdb481b9557e2950ae8d6657c8ce6wu@webrtc.org      // Can't use nack_list.data() since it's not supported by all
502822fbd8b68ffdb481b9557e2950ae8d6657c8ce6wu@webrtc.org      // compilers.
503822fbd8b68ffdb481b9557e2950ae8d6657c8ce6wu@webrtc.org      ResendPackets(&(nack_list[0]), static_cast<int>(nack_list.size()));
504d30859e58e2c0b0676ab2b52b8a2723e10d49e28pwestin@webrtc.org    }
505470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    return 0;
506470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com}
507470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
5087bb8f02274ecbfa1f7ef134d708369a369a78c83stefan@webrtc.orgbool Channel::OnRecoveredPacket(const uint8_t* rtp_packet,
5094591fbd09f9cb6e83433c49a12dd8524c2806502pkasting@chromium.org                                size_t rtp_packet_length) {
5107bb8f02274ecbfa1f7ef134d708369a369a78c83stefan@webrtc.org  RTPHeader header;
5117bb8f02274ecbfa1f7ef134d708369a369a78c83stefan@webrtc.org  if (!rtp_header_parser_->Parse(rtp_packet, rtp_packet_length, &header)) {
5127bb8f02274ecbfa1f7ef134d708369a369a78c83stefan@webrtc.org    WEBRTC_TRACE(kTraceDebug, webrtc::kTraceVoice, _channelId,
5137bb8f02274ecbfa1f7ef134d708369a369a78c83stefan@webrtc.org                 "IncomingPacket invalid RTP header");
5147bb8f02274ecbfa1f7ef134d708369a369a78c83stefan@webrtc.org    return false;
5157bb8f02274ecbfa1f7ef134d708369a369a78c83stefan@webrtc.org  }
5167bb8f02274ecbfa1f7ef134d708369a369a78c83stefan@webrtc.org  header.payload_type_frequency =
5177bb8f02274ecbfa1f7ef134d708369a369a78c83stefan@webrtc.org      rtp_payload_registry_->GetPayloadTypeFrequency(header.payloadType);
5187bb8f02274ecbfa1f7ef134d708369a369a78c83stefan@webrtc.org  if (header.payload_type_frequency < 0)
5197bb8f02274ecbfa1f7ef134d708369a369a78c83stefan@webrtc.org    return false;
5207bb8f02274ecbfa1f7ef134d708369a369a78c83stefan@webrtc.org  return ReceivePacket(rtp_packet, rtp_packet_length, header, false);
5217bb8f02274ecbfa1f7ef134d708369a369a78c83stefan@webrtc.org}
5227bb8f02274ecbfa1f7ef134d708369a369a78c83stefan@webrtc.org
5230f4b3731c34e796da92572380855dbc7321c8cfeminyuelint32_t Channel::GetAudioFrame(int32_t id, AudioFrame* audioFrame)
524470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com{
525ae856f2c9fc358e5cd68d8a595136dcef017ed96Ivo Creusen    if (event_log_) {
526ae856f2c9fc358e5cd68d8a595136dcef017ed96Ivo Creusen      unsigned int ssrc;
527ae856f2c9fc358e5cd68d8a595136dcef017ed96Ivo Creusen      RTC_CHECK_EQ(GetLocalSSRC(ssrc), 0);
528ae856f2c9fc358e5cd68d8a595136dcef017ed96Ivo Creusen      event_log_->LogAudioPlayout(ssrc);
529ae856f2c9fc358e5cd68d8a595136dcef017ed96Ivo Creusen    }
530470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    // Get 10ms raw PCM data from the ACM (mixer limits output frequency)
5310f4b3731c34e796da92572380855dbc7321c8cfeminyuel    if (audio_coding_->PlayoutData10Ms(audioFrame->sample_rate_hz_,
5320f4b3731c34e796da92572380855dbc7321c8cfeminyuel                                       audioFrame) == -1)
533470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
534470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        WEBRTC_TRACE(kTraceError, kTraceVoice,
535470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                     VoEId(_instanceId,_channelId),
536470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                     "Channel::GetAudioFrame() PlayoutData10Ms() failed!");
5377859e109855b9536593892734aa65af974e6baa4andrew@webrtc.org        // In all likelihood, the audio in this frame is garbage. We return an
5387859e109855b9536593892734aa65af974e6baa4andrew@webrtc.org        // error so that the audio mixer module doesn't add it to the mix. As
5397859e109855b9536593892734aa65af974e6baa4andrew@webrtc.org        // a result, it won't be played out and the actions skipped here are
5407859e109855b9536593892734aa65af974e6baa4andrew@webrtc.org        // irrelevant.
5417859e109855b9536593892734aa65af974e6baa4andrew@webrtc.org        return -1;
542470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
543470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
544470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    if (_RxVadDetection)
545470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
5460f4b3731c34e796da92572380855dbc7321c8cfeminyuel        UpdateRxVadDetection(*audioFrame);
547470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
548470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
549470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    // Convert module ID to internal VoE channel ID
5500f4b3731c34e796da92572380855dbc7321c8cfeminyuel    audioFrame->id_ = VoEChannelId(audioFrame->id_);
551470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    // Store speech type for dead-or-alive detection
5520f4b3731c34e796da92572380855dbc7321c8cfeminyuel    _outputSpeechType = audioFrame->speech_type_;
553470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
554944cbeb2926feb86a687e5fda9e2ac88ea8e3001henrika@webrtc.org    ChannelState::State state = channel_state_.Get();
555944cbeb2926feb86a687e5fda9e2ac88ea8e3001henrika@webrtc.org
556944cbeb2926feb86a687e5fda9e2ac88ea8e3001henrika@webrtc.org    if (state.rx_apm_is_enabled) {
5570f4b3731c34e796da92572380855dbc7321c8cfeminyuel      int err = rx_audioproc_->ProcessStream(audioFrame);
55860730cfe3ce80e4023cd678373456cb703f000a4andrew@webrtc.org      if (err) {
55960730cfe3ce80e4023cd678373456cb703f000a4andrew@webrtc.org        LOG(LS_ERROR) << "ProcessStream() error: " << err;
56060730cfe3ce80e4023cd678373456cb703f000a4andrew@webrtc.org        assert(false);
56160730cfe3ce80e4023cd678373456cb703f000a4andrew@webrtc.org      }
562470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
563470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
564f888bb58da04c5095759b5ec7ce2e1fa2cd414fdTommi    {
565f888bb58da04c5095759b5ec7ce2e1fa2cd414fdTommi      // Pass the audio buffers to an optional sink callback, before applying
566f888bb58da04c5095759b5ec7ce2e1fa2cd414fdTommi      // scaling/panning, as that applies to the mix operation.
567f888bb58da04c5095759b5ec7ce2e1fa2cd414fdTommi      // External recipients of the audio (e.g. via AudioTrack), will do their
568f888bb58da04c5095759b5ec7ce2e1fa2cd414fdTommi      // own mixing/dynamic processing.
569f888bb58da04c5095759b5ec7ce2e1fa2cd414fdTommi      CriticalSectionScoped cs(&_callbackCritSect);
570f888bb58da04c5095759b5ec7ce2e1fa2cd414fdTommi      if (audio_sink_) {
571f888bb58da04c5095759b5ec7ce2e1fa2cd414fdTommi        AudioSinkInterface::Data data(
572f888bb58da04c5095759b5ec7ce2e1fa2cd414fdTommi            &audioFrame->data_[0],
573f888bb58da04c5095759b5ec7ce2e1fa2cd414fdTommi            audioFrame->samples_per_channel_, audioFrame->sample_rate_hz_,
574f888bb58da04c5095759b5ec7ce2e1fa2cd414fdTommi            audioFrame->num_channels_, audioFrame->timestamp_);
575f888bb58da04c5095759b5ec7ce2e1fa2cd414fdTommi        audio_sink_->OnData(data);
576f888bb58da04c5095759b5ec7ce2e1fa2cd414fdTommi      }
577f888bb58da04c5095759b5ec7ce2e1fa2cd414fdTommi    }
578f888bb58da04c5095759b5ec7ce2e1fa2cd414fdTommi
57963420669746cfca6ed1d902c68c656b79ffa5a1bwu@webrtc.org    float output_gain = 1.0f;
58063420669746cfca6ed1d902c68c656b79ffa5a1bwu@webrtc.org    float left_pan =  1.0f;
58163420669746cfca6ed1d902c68c656b79ffa5a1bwu@webrtc.org    float right_pan =  1.0f;
58263420669746cfca6ed1d902c68c656b79ffa5a1bwu@webrtc.org    {
58363420669746cfca6ed1d902c68c656b79ffa5a1bwu@webrtc.org      CriticalSectionScoped cs(&volume_settings_critsect_);
58463420669746cfca6ed1d902c68c656b79ffa5a1bwu@webrtc.org      output_gain = _outputGain;
58563420669746cfca6ed1d902c68c656b79ffa5a1bwu@webrtc.org      left_pan = _panLeft;
58663420669746cfca6ed1d902c68c656b79ffa5a1bwu@webrtc.org      right_pan= _panRight;
58763420669746cfca6ed1d902c68c656b79ffa5a1bwu@webrtc.org    }
58863420669746cfca6ed1d902c68c656b79ffa5a1bwu@webrtc.org
589470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    // Output volume scaling
59063420669746cfca6ed1d902c68c656b79ffa5a1bwu@webrtc.org    if (output_gain < 0.99f || output_gain > 1.01f)
591470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
5920f4b3731c34e796da92572380855dbc7321c8cfeminyuel        AudioFrameOperations::ScaleWithSat(output_gain, *audioFrame);
593470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
594470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
595470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    // Scale left and/or right channel(s) if stereo and master balance is
596470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    // active
597470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
59863420669746cfca6ed1d902c68c656b79ffa5a1bwu@webrtc.org    if (left_pan != 1.0f || right_pan != 1.0f)
599470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
6000f4b3731c34e796da92572380855dbc7321c8cfeminyuel        if (audioFrame->num_channels_ == 1)
601470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        {
602470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            // Emulate stereo mode since panning is active.
603470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            // The mono signal is copied to both left and right channels here.
6040f4b3731c34e796da92572380855dbc7321c8cfeminyuel            AudioFrameOperations::MonoToStereo(audioFrame);
605470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        }
606470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        // For true stereo mode (when we are receiving a stereo signal), no
607470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        // action is needed.
608470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
609470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        // Do the panning operation (the audio frame contains stereo at this
610470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        // stage)
6110f4b3731c34e796da92572380855dbc7321c8cfeminyuel        AudioFrameOperations::Scale(left_pan, right_pan, *audioFrame);
612470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
613470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
614470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    // Mix decoded PCM output with file if file mixing is enabled
615944cbeb2926feb86a687e5fda9e2ac88ea8e3001henrika@webrtc.org    if (state.output_file_playing)
616470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
6170f4b3731c34e796da92572380855dbc7321c8cfeminyuel        MixAudioWithFile(*audioFrame, audioFrame->sample_rate_hz_);
618470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
619470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
620470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    // External media
621470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    if (_outputExternalMedia)
622470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
6239a065d1eae9ed296e1e2eaaad73d7ca1223bfe79mflodman@webrtc.org        CriticalSectionScoped cs(&_callbackCritSect);
6240f4b3731c34e796da92572380855dbc7321c8cfeminyuel        const bool isStereo = (audioFrame->num_channels_ == 2);
625470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        if (_outputExternalMediaCallbackPtr)
626470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        {
627f888bb58da04c5095759b5ec7ce2e1fa2cd414fdTommi          _outputExternalMediaCallbackPtr->Process(
628f888bb58da04c5095759b5ec7ce2e1fa2cd414fdTommi              _channelId, kPlaybackPerChannel, (int16_t*)audioFrame->data_,
629f888bb58da04c5095759b5ec7ce2e1fa2cd414fdTommi              audioFrame->samples_per_channel_, audioFrame->sample_rate_hz_,
630f888bb58da04c5095759b5ec7ce2e1fa2cd414fdTommi              isStereo);
631470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        }
632470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
633470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
634470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    // Record playout if enabled
635470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
6369a065d1eae9ed296e1e2eaaad73d7ca1223bfe79mflodman@webrtc.org        CriticalSectionScoped cs(&_fileCritSect);
637470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
638470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        if (_outputFileRecording && _outputFileRecorderPtr)
639470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        {
6400f4b3731c34e796da92572380855dbc7321c8cfeminyuel            _outputFileRecorderPtr->RecordAudioToFile(*audioFrame);
641470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        }
642470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
643470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
644470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    // Measure audio level (0-9)
6450f4b3731c34e796da92572380855dbc7321c8cfeminyuel    _outputAudioLevel.ComputeLevel(*audioFrame);
646470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
6470f4b3731c34e796da92572380855dbc7321c8cfeminyuel    if (capture_start_rtp_time_stamp_ < 0 && audioFrame->timestamp_ != 0) {
64894454b71adc37e15fd3f5a5fc432063f05caabcbwu@webrtc.org      // The first frame with a valid rtp timestamp.
6490f4b3731c34e796da92572380855dbc7321c8cfeminyuel      capture_start_rtp_time_stamp_ = audioFrame->timestamp_;
65094454b71adc37e15fd3f5a5fc432063f05caabcbwu@webrtc.org    }
65194454b71adc37e15fd3f5a5fc432063f05caabcbwu@webrtc.org
65294454b71adc37e15fd3f5a5fc432063f05caabcbwu@webrtc.org    if (capture_start_rtp_time_stamp_ >= 0) {
65394454b71adc37e15fd3f5a5fc432063f05caabcbwu@webrtc.org      // audioFrame.timestamp_ should be valid from now on.
65494454b71adc37e15fd3f5a5fc432063f05caabcbwu@webrtc.org
65594454b71adc37e15fd3f5a5fc432063f05caabcbwu@webrtc.org      // Compute elapsed time.
65694454b71adc37e15fd3f5a5fc432063f05caabcbwu@webrtc.org      int64_t unwrap_timestamp =
6570f4b3731c34e796da92572380855dbc7321c8cfeminyuel          rtp_ts_wraparound_handler_->Unwrap(audioFrame->timestamp_);
6580f4b3731c34e796da92572380855dbc7321c8cfeminyuel      audioFrame->elapsed_time_ms_ =
65994454b71adc37e15fd3f5a5fc432063f05caabcbwu@webrtc.org          (unwrap_timestamp - capture_start_rtp_time_stamp_) /
66094454b71adc37e15fd3f5a5fc432063f05caabcbwu@webrtc.org          (GetPlayoutFrequency() / 1000);
66194454b71adc37e15fd3f5a5fc432063f05caabcbwu@webrtc.org
6628e24d8777849951ed86fb01e0bf556d4eda65161stefan@webrtc.org      {
663cb711f77d2ff9ebd42678869a73353809b3af66ewu@webrtc.org        CriticalSectionScoped lock(ts_stats_lock_.get());
6648e24d8777849951ed86fb01e0bf556d4eda65161stefan@webrtc.org        // Compute ntp time.
6650f4b3731c34e796da92572380855dbc7321c8cfeminyuel        audioFrame->ntp_time_ms_ = ntp_estimator_.Estimate(
6660f4b3731c34e796da92572380855dbc7321c8cfeminyuel            audioFrame->timestamp_);
6678e24d8777849951ed86fb01e0bf556d4eda65161stefan@webrtc.org        // |ntp_time_ms_| won't be valid until at least 2 RTCP SRs are received.
6680f4b3731c34e796da92572380855dbc7321c8cfeminyuel        if (audioFrame->ntp_time_ms_ > 0) {
6698e24d8777849951ed86fb01e0bf556d4eda65161stefan@webrtc.org          // Compute |capture_start_ntp_time_ms_| so that
6708e24d8777849951ed86fb01e0bf556d4eda65161stefan@webrtc.org          // |capture_start_ntp_time_ms_| + |elapsed_time_ms_| == |ntp_time_ms_|
6718e24d8777849951ed86fb01e0bf556d4eda65161stefan@webrtc.org          capture_start_ntp_time_ms_ =
6720f4b3731c34e796da92572380855dbc7321c8cfeminyuel              audioFrame->ntp_time_ms_ - audioFrame->elapsed_time_ms_;
6738e24d8777849951ed86fb01e0bf556d4eda65161stefan@webrtc.org        }
674cb711f77d2ff9ebd42678869a73353809b3af66ewu@webrtc.org      }
675cb711f77d2ff9ebd42678869a73353809b3af66ewu@webrtc.org    }
676cb711f77d2ff9ebd42678869a73353809b3af66ewu@webrtc.org
677470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    return 0;
678470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com}
679470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
6806141e13873d0fdea626de08dfec2efa2c9171c76pbos@webrtc.orgint32_t
6810f4b3731c34e796da92572380855dbc7321c8cfeminyuelChannel::NeededFrequency(int32_t id) const
682470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com{
683470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
684470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                 "Channel::NeededFrequency(id=%d)", id);
685470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
686470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    int highestNeeded = 0;
687470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
688470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    // Determine highest needed receive frequency
689eb524d997b877ba9b0bcaf8c85eae52bd40c37e3andrew@webrtc.org    int32_t receiveFrequency = audio_coding_->ReceiveFrequency();
690470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
691470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    // Return the bigger of playout and receive frequency in the ACM.
692eb524d997b877ba9b0bcaf8c85eae52bd40c37e3andrew@webrtc.org    if (audio_coding_->PlayoutFrequency() > receiveFrequency)
693470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
694eb524d997b877ba9b0bcaf8c85eae52bd40c37e3andrew@webrtc.org        highestNeeded = audio_coding_->PlayoutFrequency();
695470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
696470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    else
697470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
698470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        highestNeeded = receiveFrequency;
699470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
700470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
701470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    // Special case, if we're playing a file on the playout side
702470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    // we take that frequency into consideration as well
703470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    // This is not needed on sending side, since the codec will
704470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    // limit the spectrum anyway.
705944cbeb2926feb86a687e5fda9e2ac88ea8e3001henrika@webrtc.org    if (channel_state_.Get().output_file_playing)
706470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
7079a065d1eae9ed296e1e2eaaad73d7ca1223bfe79mflodman@webrtc.org        CriticalSectionScoped cs(&_fileCritSect);
708944cbeb2926feb86a687e5fda9e2ac88ea8e3001henrika@webrtc.org        if (_outputFilePlayerPtr)
709470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        {
710470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            if(_outputFilePlayerPtr->Frequency()>highestNeeded)
711470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            {
712470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                highestNeeded=_outputFilePlayerPtr->Frequency();
713470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            }
714470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        }
715470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
716470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
717470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    return(highestNeeded);
718470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com}
719470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
720b04965ccf83c2bc6e2758abab9bea0c18551a54civocint32_t Channel::CreateChannel(Channel*& channel,
721b04965ccf83c2bc6e2758abab9bea0c18551a54civoc                               int32_t channelId,
722b04965ccf83c2bc6e2758abab9bea0c18551a54civoc                               uint32_t instanceId,
723b04965ccf83c2bc6e2758abab9bea0c18551a54civoc                               RtcEventLog* const event_log,
724b04965ccf83c2bc6e2758abab9bea0c18551a54civoc                               const Config& config) {
725470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    WEBRTC_TRACE(kTraceMemory, kTraceVoice, VoEId(instanceId,channelId),
726470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                 "Channel::CreateChannel(channelId=%d, instanceId=%d)",
727470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        channelId, instanceId);
728470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
729b04965ccf83c2bc6e2758abab9bea0c18551a54civoc    channel = new Channel(channelId, instanceId, event_log, config);
730470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    if (channel == NULL)
731470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
732470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        WEBRTC_TRACE(kTraceMemory, kTraceVoice,
733470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                     VoEId(instanceId,channelId),
734470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                     "Channel::CreateChannel() unable to allocate memory for"
735470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                     " channel");
736470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        return -1;
737470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
738470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    return 0;
739470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com}
740470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
741470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.comvoid
7429213521ea98b0977c7cdabd2853060835af226f3pbos@webrtc.orgChannel::PlayNotification(int32_t id, uint32_t durationMs)
743470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com{
744470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
745470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                 "Channel::PlayNotification(id=%d, durationMs=%d)",
746470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                 id, durationMs);
747470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
748470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    // Not implement yet
749470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com}
750470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
751470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.comvoid
7529213521ea98b0977c7cdabd2853060835af226f3pbos@webrtc.orgChannel::RecordNotification(int32_t id, uint32_t durationMs)
753470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com{
754470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
755470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                 "Channel::RecordNotification(id=%d, durationMs=%d)",
756470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                 id, durationMs);
757470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
758470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    // Not implement yet
759470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com}
760470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
761470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.comvoid
7629213521ea98b0977c7cdabd2853060835af226f3pbos@webrtc.orgChannel::PlayFileEnded(int32_t id)
763470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com{
764470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
765470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                 "Channel::PlayFileEnded(id=%d)", id);
766470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
767470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    if (id == _inputFilePlayerId)
768470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
769944cbeb2926feb86a687e5fda9e2ac88ea8e3001henrika@webrtc.org        channel_state_.SetInputFilePlaying(false);
770470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
771470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                     VoEId(_instanceId,_channelId),
772470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                     "Channel::PlayFileEnded() => input file player module is"
773470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                     " shutdown");
774470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
775470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    else if (id == _outputFilePlayerId)
776470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
777944cbeb2926feb86a687e5fda9e2ac88ea8e3001henrika@webrtc.org        channel_state_.SetOutputFilePlaying(false);
778470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
779470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                     VoEId(_instanceId,_channelId),
780470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                     "Channel::PlayFileEnded() => output file player module is"
781470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                     " shutdown");
782470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
783470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com}
784470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
785470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.comvoid
7869213521ea98b0977c7cdabd2853060835af226f3pbos@webrtc.orgChannel::RecordFileEnded(int32_t id)
787470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com{
788470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
789470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                 "Channel::RecordFileEnded(id=%d)", id);
790470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
791470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    assert(id == _outputFileRecorderId);
792470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
7939a065d1eae9ed296e1e2eaaad73d7ca1223bfe79mflodman@webrtc.org    CriticalSectionScoped cs(&_fileCritSect);
794470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
795470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    _outputFileRecording = false;
796470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
797470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                 VoEId(_instanceId,_channelId),
798470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                 "Channel::RecordFileEnded() => output file recorder module is"
799470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                 " shutdown");
800470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com}
801470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
8029213521ea98b0977c7cdabd2853060835af226f3pbos@webrtc.orgChannel::Channel(int32_t channelId,
803e509f943eded156f7a8365b0b001abe73646acfaminyue@webrtc.org                 uint32_t instanceId,
804b04965ccf83c2bc6e2758abab9bea0c18551a54civoc                 RtcEventLog* const event_log,
805b04965ccf83c2bc6e2758abab9bea0c18551a54civoc                 const Config& config)
806b86d4e4a8dec1eb1b801244a2a97cda66f561d8eStefan Holmer    : _fileCritSect(*CriticalSectionWrapper::CreateCriticalSection()),
807b86d4e4a8dec1eb1b801244a2a97cda66f561d8eStefan Holmer      _callbackCritSect(*CriticalSectionWrapper::CreateCriticalSection()),
808b86d4e4a8dec1eb1b801244a2a97cda66f561d8eStefan Holmer      volume_settings_critsect_(
809b86d4e4a8dec1eb1b801244a2a97cda66f561d8eStefan Holmer          *CriticalSectionWrapper::CreateCriticalSection()),
810b86d4e4a8dec1eb1b801244a2a97cda66f561d8eStefan Holmer      _instanceId(instanceId),
811b86d4e4a8dec1eb1b801244a2a97cda66f561d8eStefan Holmer      _channelId(channelId),
812b86d4e4a8dec1eb1b801244a2a97cda66f561d8eStefan Holmer      event_log_(event_log),
813b86d4e4a8dec1eb1b801244a2a97cda66f561d8eStefan Holmer      rtp_header_parser_(RtpHeaderParser::Create()),
814b86d4e4a8dec1eb1b801244a2a97cda66f561d8eStefan Holmer      rtp_payload_registry_(
815b86d4e4a8dec1eb1b801244a2a97cda66f561d8eStefan Holmer          new RTPPayloadRegistry(RTPPayloadStrategy::CreateStrategy(true))),
816b86d4e4a8dec1eb1b801244a2a97cda66f561d8eStefan Holmer      rtp_receive_statistics_(
817b86d4e4a8dec1eb1b801244a2a97cda66f561d8eStefan Holmer          ReceiveStatistics::Create(Clock::GetRealTimeClock())),
818b86d4e4a8dec1eb1b801244a2a97cda66f561d8eStefan Holmer      rtp_receiver_(
819b86d4e4a8dec1eb1b801244a2a97cda66f561d8eStefan Holmer          RtpReceiver::CreateAudioReceiver(Clock::GetRealTimeClock(),
820b86d4e4a8dec1eb1b801244a2a97cda66f561d8eStefan Holmer                                           this,
821b86d4e4a8dec1eb1b801244a2a97cda66f561d8eStefan Holmer                                           this,
822b86d4e4a8dec1eb1b801244a2a97cda66f561d8eStefan Holmer                                           this,
823b86d4e4a8dec1eb1b801244a2a97cda66f561d8eStefan Holmer                                           rtp_payload_registry_.get())),
824b86d4e4a8dec1eb1b801244a2a97cda66f561d8eStefan Holmer      telephone_event_handler_(rtp_receiver_->GetTelephoneEventHandler()),
825b86d4e4a8dec1eb1b801244a2a97cda66f561d8eStefan Holmer      _outputAudioLevel(),
826b86d4e4a8dec1eb1b801244a2a97cda66f561d8eStefan Holmer      _externalTransport(false),
827b86d4e4a8dec1eb1b801244a2a97cda66f561d8eStefan Holmer      _inputFilePlayerPtr(NULL),
828b86d4e4a8dec1eb1b801244a2a97cda66f561d8eStefan Holmer      _outputFilePlayerPtr(NULL),
829b86d4e4a8dec1eb1b801244a2a97cda66f561d8eStefan Holmer      _outputFileRecorderPtr(NULL),
830b86d4e4a8dec1eb1b801244a2a97cda66f561d8eStefan Holmer      // Avoid conflict with other channels by adding 1024 - 1026,
831b86d4e4a8dec1eb1b801244a2a97cda66f561d8eStefan Holmer      // won't use as much as 1024 channels.
832b86d4e4a8dec1eb1b801244a2a97cda66f561d8eStefan Holmer      _inputFilePlayerId(VoEModuleId(instanceId, channelId) + 1024),
833b86d4e4a8dec1eb1b801244a2a97cda66f561d8eStefan Holmer      _outputFilePlayerId(VoEModuleId(instanceId, channelId) + 1025),
834b86d4e4a8dec1eb1b801244a2a97cda66f561d8eStefan Holmer      _outputFileRecorderId(VoEModuleId(instanceId, channelId) + 1026),
835b86d4e4a8dec1eb1b801244a2a97cda66f561d8eStefan Holmer      _outputFileRecording(false),
836b86d4e4a8dec1eb1b801244a2a97cda66f561d8eStefan Holmer      _inbandDtmfQueue(VoEModuleId(instanceId, channelId)),
837b86d4e4a8dec1eb1b801244a2a97cda66f561d8eStefan Holmer      _inbandDtmfGenerator(VoEModuleId(instanceId, channelId)),
838b86d4e4a8dec1eb1b801244a2a97cda66f561d8eStefan Holmer      _outputExternalMedia(false),
839b86d4e4a8dec1eb1b801244a2a97cda66f561d8eStefan Holmer      _inputExternalMediaCallbackPtr(NULL),
840b86d4e4a8dec1eb1b801244a2a97cda66f561d8eStefan Holmer      _outputExternalMediaCallbackPtr(NULL),
841b86d4e4a8dec1eb1b801244a2a97cda66f561d8eStefan Holmer      _timeStamp(0),  // This is just an offset, RTP module will add it's own
842b86d4e4a8dec1eb1b801244a2a97cda66f561d8eStefan Holmer                      // random offset
843b86d4e4a8dec1eb1b801244a2a97cda66f561d8eStefan Holmer      _sendTelephoneEventPayloadType(106),
844b86d4e4a8dec1eb1b801244a2a97cda66f561d8eStefan Holmer      ntp_estimator_(Clock::GetRealTimeClock()),
845b86d4e4a8dec1eb1b801244a2a97cda66f561d8eStefan Holmer      jitter_buffer_playout_timestamp_(0),
846b86d4e4a8dec1eb1b801244a2a97cda66f561d8eStefan Holmer      playout_timestamp_rtp_(0),
847b86d4e4a8dec1eb1b801244a2a97cda66f561d8eStefan Holmer      playout_timestamp_rtcp_(0),
848b86d4e4a8dec1eb1b801244a2a97cda66f561d8eStefan Holmer      playout_delay_ms_(0),
849b86d4e4a8dec1eb1b801244a2a97cda66f561d8eStefan Holmer      _numberOfDiscardedPackets(0),
850b86d4e4a8dec1eb1b801244a2a97cda66f561d8eStefan Holmer      send_sequence_number_(0),
851b86d4e4a8dec1eb1b801244a2a97cda66f561d8eStefan Holmer      ts_stats_lock_(CriticalSectionWrapper::CreateCriticalSection()),
852b86d4e4a8dec1eb1b801244a2a97cda66f561d8eStefan Holmer      rtp_ts_wraparound_handler_(new rtc::TimestampWrapAroundHandler()),
853b86d4e4a8dec1eb1b801244a2a97cda66f561d8eStefan Holmer      capture_start_rtp_time_stamp_(-1),
854b86d4e4a8dec1eb1b801244a2a97cda66f561d8eStefan Holmer      capture_start_ntp_time_ms_(-1),
855b86d4e4a8dec1eb1b801244a2a97cda66f561d8eStefan Holmer      _engineStatisticsPtr(NULL),
856b86d4e4a8dec1eb1b801244a2a97cda66f561d8eStefan Holmer      _outputMixerPtr(NULL),
857b86d4e4a8dec1eb1b801244a2a97cda66f561d8eStefan Holmer      _transmitMixerPtr(NULL),
858b86d4e4a8dec1eb1b801244a2a97cda66f561d8eStefan Holmer      _moduleProcessThreadPtr(NULL),
859b86d4e4a8dec1eb1b801244a2a97cda66f561d8eStefan Holmer      _audioDeviceModulePtr(NULL),
860b86d4e4a8dec1eb1b801244a2a97cda66f561d8eStefan Holmer      _voiceEngineObserverPtr(NULL),
861b86d4e4a8dec1eb1b801244a2a97cda66f561d8eStefan Holmer      _callbackCritSectPtr(NULL),
862b86d4e4a8dec1eb1b801244a2a97cda66f561d8eStefan Holmer      _transportPtr(NULL),
863b86d4e4a8dec1eb1b801244a2a97cda66f561d8eStefan Holmer      _rxVadObserverPtr(NULL),
864b86d4e4a8dec1eb1b801244a2a97cda66f561d8eStefan Holmer      _oldVadDecision(-1),
865b86d4e4a8dec1eb1b801244a2a97cda66f561d8eStefan Holmer      _sendFrameType(0),
866b86d4e4a8dec1eb1b801244a2a97cda66f561d8eStefan Holmer      _externalMixing(false),
867b86d4e4a8dec1eb1b801244a2a97cda66f561d8eStefan Holmer      _mixFileWithMicrophone(false),
868b86d4e4a8dec1eb1b801244a2a97cda66f561d8eStefan Holmer      _mute(false),
869b86d4e4a8dec1eb1b801244a2a97cda66f561d8eStefan Holmer      _panLeft(1.0f),
870b86d4e4a8dec1eb1b801244a2a97cda66f561d8eStefan Holmer      _panRight(1.0f),
871b86d4e4a8dec1eb1b801244a2a97cda66f561d8eStefan Holmer      _outputGain(1.0f),
872b86d4e4a8dec1eb1b801244a2a97cda66f561d8eStefan Holmer      _playOutbandDtmfEvent(false),
873b86d4e4a8dec1eb1b801244a2a97cda66f561d8eStefan Holmer      _playInbandDtmfEvent(false),
874b86d4e4a8dec1eb1b801244a2a97cda66f561d8eStefan Holmer      _lastLocalTimeStamp(0),
875b86d4e4a8dec1eb1b801244a2a97cda66f561d8eStefan Holmer      _lastPayloadType(0),
876b86d4e4a8dec1eb1b801244a2a97cda66f561d8eStefan Holmer      _includeAudioLevelIndication(false),
877b86d4e4a8dec1eb1b801244a2a97cda66f561d8eStefan Holmer      _outputSpeechType(AudioFrame::kNormalSpeech),
878b86d4e4a8dec1eb1b801244a2a97cda66f561d8eStefan Holmer      video_sync_lock_(CriticalSectionWrapper::CreateCriticalSection()),
879b86d4e4a8dec1eb1b801244a2a97cda66f561d8eStefan Holmer      _average_jitter_buffer_delay_us(0),
880b86d4e4a8dec1eb1b801244a2a97cda66f561d8eStefan Holmer      _previousTimestamp(0),
881b86d4e4a8dec1eb1b801244a2a97cda66f561d8eStefan Holmer      _recPacketDelayMs(20),
882b86d4e4a8dec1eb1b801244a2a97cda66f561d8eStefan Holmer      _RxVadDetection(false),
883b86d4e4a8dec1eb1b801244a2a97cda66f561d8eStefan Holmer      _rxAgcIsEnabled(false),
884b86d4e4a8dec1eb1b801244a2a97cda66f561d8eStefan Holmer      _rxNsIsEnabled(false),
885b86d4e4a8dec1eb1b801244a2a97cda66f561d8eStefan Holmer      restored_packet_in_use_(false),
886b86d4e4a8dec1eb1b801244a2a97cda66f561d8eStefan Holmer      rtcp_observer_(new VoERtcpObserver(this)),
887b86d4e4a8dec1eb1b801244a2a97cda66f561d8eStefan Holmer      network_predictor_(new NetworkPredictor(Clock::GetRealTimeClock())),
888b86d4e4a8dec1eb1b801244a2a97cda66f561d8eStefan Holmer      assoc_send_channel_lock_(CriticalSectionWrapper::CreateCriticalSection()),
889b86d4e4a8dec1eb1b801244a2a97cda66f561d8eStefan Holmer      associate_send_channel_(ChannelOwner(nullptr)),
890b86d4e4a8dec1eb1b801244a2a97cda66f561d8eStefan Holmer      pacing_enabled_(config.Get<VoicePacing>().enabled),
891b86d4e4a8dec1eb1b801244a2a97cda66f561d8eStefan Holmer      feedback_observer_proxy_(pacing_enabled_ ? new TransportFeedbackProxy()
892b86d4e4a8dec1eb1b801244a2a97cda66f561d8eStefan Holmer                                               : nullptr),
893b86d4e4a8dec1eb1b801244a2a97cda66f561d8eStefan Holmer      seq_num_allocator_proxy_(
894b86d4e4a8dec1eb1b801244a2a97cda66f561d8eStefan Holmer          pacing_enabled_ ? new TransportSequenceNumberProxy() : nullptr),
895b86d4e4a8dec1eb1b801244a2a97cda66f561d8eStefan Holmer      rtp_packet_sender_proxy_(pacing_enabled_ ? new RtpPacketSenderProxy()
896b86d4e4a8dec1eb1b801244a2a97cda66f561d8eStefan Holmer                                               : nullptr) {
897470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    WEBRTC_TRACE(kTraceMemory, kTraceVoice, VoEId(_instanceId,_channelId),
898470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                 "Channel::Channel() - ctor");
89964dad838e61e92e4a72437b153c5eba7a200fb4aHenrik Lundin    AudioCodingModule::Config acm_config;
90064dad838e61e92e4a72437b153c5eba7a200fb4aHenrik Lundin    acm_config.id = VoEModuleId(instanceId, channelId);
90164dad838e61e92e4a72437b153c5eba7a200fb4aHenrik Lundin    if (config.Get<NetEqCapacityConfig>().enabled) {
90264dad838e61e92e4a72437b153c5eba7a200fb4aHenrik Lundin      // Clamping the buffer capacity at 20 packets. While going lower will
90364dad838e61e92e4a72437b153c5eba7a200fb4aHenrik Lundin      // probably work, it makes little sense.
90464dad838e61e92e4a72437b153c5eba7a200fb4aHenrik Lundin      acm_config.neteq_config.max_packets_in_buffer =
90564dad838e61e92e4a72437b153c5eba7a200fb4aHenrik Lundin          std::max(20, config.Get<NetEqCapacityConfig>().capacity);
90664dad838e61e92e4a72437b153c5eba7a200fb4aHenrik Lundin    }
9075263b3c1ddb10ecca58d9f08364aad2d6ba1d95dHenrik Lundin    acm_config.neteq_config.enable_fast_accelerate =
9085263b3c1ddb10ecca58d9f08364aad2d6ba1d95dHenrik Lundin        config.Get<NetEqFastAccelerate>().enabled;
90964dad838e61e92e4a72437b153c5eba7a200fb4aHenrik Lundin    audio_coding_.reset(AudioCodingModule::Create(acm_config));
91064dad838e61e92e4a72437b153c5eba7a200fb4aHenrik Lundin
911470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    _inbandDtmfQueue.ResetDtmf();
912470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    _inbandDtmfGenerator.Init();
913470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    _outputAudioLevel.Clear();
914470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
9152853dde5201d9ddc284ce5efb9688f6340487acepwestin@webrtc.org    RtpRtcp::Configuration configuration;
9162853dde5201d9ddc284ce5efb9688f6340487acepwestin@webrtc.org    configuration.audio = true;
9172853dde5201d9ddc284ce5efb9688f6340487acepwestin@webrtc.org    configuration.outgoing_transport = this;
9182853dde5201d9ddc284ce5efb9688f6340487acepwestin@webrtc.org    configuration.audio_messages = this;
919822fbd8b68ffdb481b9557e2950ae8d6657c8ce6wu@webrtc.org    configuration.receive_statistics = rtp_receive_statistics_.get();
9200a7d4eed98ccec0c2b3e7522e7b2dde1919a4ae3mflodman@webrtc.org    configuration.bandwidth_callback = rtcp_observer_.get();
921b86d4e4a8dec1eb1b801244a2a97cda66f561d8eStefan Holmer    configuration.paced_sender = rtp_packet_sender_proxy_.get();
922b86d4e4a8dec1eb1b801244a2a97cda66f561d8eStefan Holmer    configuration.transport_sequence_number_allocator =
923b86d4e4a8dec1eb1b801244a2a97cda66f561d8eStefan Holmer        seq_num_allocator_proxy_.get();
924b86d4e4a8dec1eb1b801244a2a97cda66f561d8eStefan Holmer    configuration.transport_feedback_callback = feedback_observer_proxy_.get();
9252853dde5201d9ddc284ce5efb9688f6340487acepwestin@webrtc.org
9262853dde5201d9ddc284ce5efb9688f6340487acepwestin@webrtc.org    _rtpRtcpModule.reset(RtpRtcp::CreateRtpRtcp(configuration));
92754ae4ffb9e235a9742e2b11298327e02d870571csprang@webrtc.org
92854ae4ffb9e235a9742e2b11298327e02d870571csprang@webrtc.org    statistics_proxy_.reset(new StatisticsProxy(_rtpRtcpModule->SSRC()));
92954ae4ffb9e235a9742e2b11298327e02d870571csprang@webrtc.org    rtp_receive_statistics_->RegisterRtcpStatisticsCallback(
93054ae4ffb9e235a9742e2b11298327e02d870571csprang@webrtc.org        statistics_proxy_.get());
931f927fd64812b4a42a0f4e2686683a43d74b4bf08aluebs@webrtc.org
932f927fd64812b4a42a0f4e2686683a43d74b4bf08aluebs@webrtc.org    Config audioproc_config;
933f927fd64812b4a42a0f4e2686683a43d74b4bf08aluebs@webrtc.org    audioproc_config.Set<ExperimentalAgc>(new ExperimentalAgc(false));
934f927fd64812b4a42a0f4e2686683a43d74b4bf08aluebs@webrtc.org    rx_audioproc_.reset(AudioProcessing::Create(audioproc_config));
935470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com}
936470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
937470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.comChannel::~Channel()
938470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com{
93954ae4ffb9e235a9742e2b11298327e02d870571csprang@webrtc.org    rtp_receive_statistics_->RegisterRtcpStatisticsCallback(NULL);
940470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    WEBRTC_TRACE(kTraceMemory, kTraceVoice, VoEId(_instanceId,_channelId),
941470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                 "Channel::~Channel() - dtor");
942470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
943470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    if (_outputExternalMedia)
944470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
945470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        DeRegisterExternalMediaProcessing(kPlaybackPerChannel);
946470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
947944cbeb2926feb86a687e5fda9e2ac88ea8e3001henrika@webrtc.org    if (channel_state_.Get().input_external_media)
948470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
949470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        DeRegisterExternalMediaProcessing(kRecordingPerChannel);
950470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
951470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    StopSend();
952470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    StopPlayout();
953470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
954470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
9559a065d1eae9ed296e1e2eaaad73d7ca1223bfe79mflodman@webrtc.org        CriticalSectionScoped cs(&_fileCritSect);
956470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        if (_inputFilePlayerPtr)
957470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        {
958470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            _inputFilePlayerPtr->RegisterModuleFileCallback(NULL);
959470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            _inputFilePlayerPtr->StopPlayingFile();
960470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            FilePlayer::DestroyFilePlayer(_inputFilePlayerPtr);
961470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            _inputFilePlayerPtr = NULL;
962470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        }
963470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        if (_outputFilePlayerPtr)
964470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        {
965470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            _outputFilePlayerPtr->RegisterModuleFileCallback(NULL);
966470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            _outputFilePlayerPtr->StopPlayingFile();
967470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            FilePlayer::DestroyFilePlayer(_outputFilePlayerPtr);
968470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            _outputFilePlayerPtr = NULL;
969470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        }
970470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        if (_outputFileRecorderPtr)
971470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        {
972470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            _outputFileRecorderPtr->RegisterModuleFileCallback(NULL);
973470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            _outputFileRecorderPtr->StopRecording();
974470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            FileRecorder::DestroyFileRecorder(_outputFileRecorderPtr);
975470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            _outputFileRecorderPtr = NULL;
976470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        }
977470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
978470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
979470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    // The order to safely shutdown modules in a channel is:
980470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    // 1. De-register callbacks in modules
981470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    // 2. De-register modules in process thread
982470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    // 3. Destroy modules
983eb524d997b877ba9b0bcaf8c85eae52bd40c37e3andrew@webrtc.org    if (audio_coding_->RegisterTransportCallback(NULL) == -1)
984470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
985470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        WEBRTC_TRACE(kTraceWarning, kTraceVoice,
986470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                     VoEId(_instanceId,_channelId),
987470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                     "~Channel() failed to de-register transport callback"
988470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                     " (Audio coding module)");
989470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
990eb524d997b877ba9b0bcaf8c85eae52bd40c37e3andrew@webrtc.org    if (audio_coding_->RegisterVADCallback(NULL) == -1)
991470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
992470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        WEBRTC_TRACE(kTraceWarning, kTraceVoice,
993470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                     VoEId(_instanceId,_channelId),
994470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                     "~Channel() failed to de-register VAD callback"
995470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                     " (Audio coding module)");
996470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
997470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    // De-register modules in process thread
9983985f0151aff9b91418733795a98140079c19a73tommi@webrtc.org    _moduleProcessThreadPtr->DeRegisterModule(_rtpRtcpModule.get());
9993985f0151aff9b91418733795a98140079c19a73tommi@webrtc.org
1000470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    // End of modules shutdown
1001470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
1002470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    // Delete other objects
1003470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    delete &_callbackCritSect;
1004470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    delete &_fileCritSect;
100563420669746cfca6ed1d902c68c656b79ffa5a1bwu@webrtc.org    delete &volume_settings_critsect_;
1006470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com}
1007470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
10086141e13873d0fdea626de08dfec2efa2c9171c76pbos@webrtc.orgint32_t
1009470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.comChannel::Init()
1010470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com{
1011470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1012470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                 "Channel::Init()");
1013470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
1014944cbeb2926feb86a687e5fda9e2ac88ea8e3001henrika@webrtc.org    channel_state_.Reset();
1015944cbeb2926feb86a687e5fda9e2ac88ea8e3001henrika@webrtc.org
1016470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    // --- Initial sanity
1017470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
1018470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    if ((_engineStatisticsPtr == NULL) ||
1019470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        (_moduleProcessThreadPtr == NULL))
1020470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
1021470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        WEBRTC_TRACE(kTraceError, kTraceVoice,
1022470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                     VoEId(_instanceId,_channelId),
1023470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                     "Channel::Init() must call SetEngineInformation() first");
1024470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        return -1;
1025470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
1026470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
1027470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    // --- Add modules to process thread (for periodic schedulation)
1028470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
10293985f0151aff9b91418733795a98140079c19a73tommi@webrtc.org    _moduleProcessThreadPtr->RegisterModule(_rtpRtcpModule.get());
10303985f0151aff9b91418733795a98140079c19a73tommi@webrtc.org
1031c450a1966965fbb3c16ec6d02c3d5cbec67df500pwestin@webrtc.org    // --- ACM initialization
1032470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
1033061b79af6023b6caf9975be39fe53dd0ec3b7464henrik.lundin    if (audio_coding_->InitializeReceiver() == -1) {
1034470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        _engineStatisticsPtr->SetLastError(
1035470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
1036470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            "Channel::Init() unable to initialize the ACM - 1");
1037470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        return -1;
1038470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
1039470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
1040470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    // --- RTP/RTCP module initialization
1041470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
1042470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    // Ensure that RTCP is enabled by default for the created channel.
1043470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    // Note that, the module will keep generating RTCP until it is explicitly
1044470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    // disabled by the user.
1045470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    // After StopListen (when no sockets exists), RTCP packets will no longer
1046470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    // be transmitted since the Transport object will then be invalid.
1047822fbd8b68ffdb481b9557e2950ae8d6657c8ce6wu@webrtc.org    telephone_event_handler_->SetTelephoneEventForwardToDecoder(true);
1048822fbd8b68ffdb481b9557e2950ae8d6657c8ce6wu@webrtc.org    // RTCP is enabled by default.
1049da903eaabbb6c6830efcafc3c2ade1d36f511e43pbos    _rtpRtcpModule->SetRTCPStatus(RtcpMode::kCompound);
1050d16e839c6d29831e79312180085b6a19149df43fpbos@webrtc.org    // --- Register all permanent callbacks
1051470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    const bool fail =
1052eb524d997b877ba9b0bcaf8c85eae52bd40c37e3andrew@webrtc.org        (audio_coding_->RegisterTransportCallback(this) == -1) ||
1053eb524d997b877ba9b0bcaf8c85eae52bd40c37e3andrew@webrtc.org        (audio_coding_->RegisterVADCallback(this) == -1);
1054470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
1055470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    if (fail)
1056470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
1057470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        _engineStatisticsPtr->SetLastError(
1058470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            VE_CANNOT_INIT_CHANNEL, kTraceError,
1059470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            "Channel::Init() callbacks not registered");
1060470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        return -1;
1061470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
1062470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
1063470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    // --- Register all supported codecs to the receiving side of the
1064470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    // RTP/RTCP module
1065470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
1066470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    CodecInst codec;
10676141e13873d0fdea626de08dfec2efa2c9171c76pbos@webrtc.org    const uint8_t nSupportedCodecs = AudioCodingModule::NumberOfCodecs();
1068470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
1069470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    for (int idx = 0; idx < nSupportedCodecs; idx++)
1070470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
1071470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        // Open up the RTP/RTCP receiver for all supported codecs
1072eb524d997b877ba9b0bcaf8c85eae52bd40c37e3andrew@webrtc.org        if ((audio_coding_->Codec(idx, &codec) == -1) ||
1073822fbd8b68ffdb481b9557e2950ae8d6657c8ce6wu@webrtc.org            (rtp_receiver_->RegisterReceivePayload(
1074822fbd8b68ffdb481b9557e2950ae8d6657c8ce6wu@webrtc.org                codec.plname,
1075822fbd8b68ffdb481b9557e2950ae8d6657c8ce6wu@webrtc.org                codec.pltype,
1076822fbd8b68ffdb481b9557e2950ae8d6657c8ce6wu@webrtc.org                codec.plfreq,
1077822fbd8b68ffdb481b9557e2950ae8d6657c8ce6wu@webrtc.org                codec.channels,
1078822fbd8b68ffdb481b9557e2950ae8d6657c8ce6wu@webrtc.org                (codec.rate < 0) ? 0 : codec.rate) == -1))
1079470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        {
1080470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            WEBRTC_TRACE(kTraceWarning, kTraceVoice,
1081470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                         VoEId(_instanceId,_channelId),
10826955870806624479723addfae6dcf5d13968796cPeter Kasting                         "Channel::Init() unable to register %s "
10836955870806624479723addfae6dcf5d13968796cPeter Kasting                         "(%d/%d/%" PRIuS "/%d) to RTP/RTCP receiver",
1084470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                         codec.plname, codec.pltype, codec.plfreq,
1085470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                         codec.channels, codec.rate);
1086470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        }
1087470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        else
1088470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        {
1089470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            WEBRTC_TRACE(kTraceInfo, kTraceVoice,
1090470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                         VoEId(_instanceId,_channelId),
10916955870806624479723addfae6dcf5d13968796cPeter Kasting                         "Channel::Init() %s (%d/%d/%" PRIuS "/%d) has been "
10926955870806624479723addfae6dcf5d13968796cPeter Kasting                         "added to the RTP/RTCP receiver",
1093470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                         codec.plname, codec.pltype, codec.plfreq,
1094470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                         codec.channels, codec.rate);
1095470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        }
1096470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
1097470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        // Ensure that PCMU is used as default codec on the sending side
10984517585db5f2f2a14fdd56a96f4b44f745967c8ctina.legrand@webrtc.org        if (!STR_CASE_CMP(codec.plname, "PCMU") && (codec.channels == 1))
1099470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        {
1100470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            SetSendCodec(codec);
1101470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        }
1102470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
1103470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        // Register default PT for outband 'telephone-event'
1104470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        if (!STR_CASE_CMP(codec.plname, "telephone-event"))
1105470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        {
11062853dde5201d9ddc284ce5efb9688f6340487acepwestin@webrtc.org            if ((_rtpRtcpModule->RegisterSendPayload(codec) == -1) ||
1107eb524d997b877ba9b0bcaf8c85eae52bd40c37e3andrew@webrtc.org                (audio_coding_->RegisterReceiveCodec(codec) == -1))
1108470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            {
1109470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                WEBRTC_TRACE(kTraceWarning, kTraceVoice,
1110470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                             VoEId(_instanceId,_channelId),
1111470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                             "Channel::Init() failed to register outband "
1112470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                             "'telephone-event' (%d/%d) correctly",
1113470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                             codec.pltype, codec.plfreq);
1114470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            }
1115470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        }
1116470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
1117470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        if (!STR_CASE_CMP(codec.plname, "CN"))
1118470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        {
1119eb524d997b877ba9b0bcaf8c85eae52bd40c37e3andrew@webrtc.org            if ((audio_coding_->RegisterSendCodec(codec) == -1) ||
1120eb524d997b877ba9b0bcaf8c85eae52bd40c37e3andrew@webrtc.org                (audio_coding_->RegisterReceiveCodec(codec) == -1) ||
11212853dde5201d9ddc284ce5efb9688f6340487acepwestin@webrtc.org                (_rtpRtcpModule->RegisterSendPayload(codec) == -1))
1122470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            {
1123470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                WEBRTC_TRACE(kTraceWarning, kTraceVoice,
1124470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                             VoEId(_instanceId,_channelId),
1125470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                             "Channel::Init() failed to register CN (%d/%d) "
1126470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                             "correctly - 1",
1127470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                             codec.pltype, codec.plfreq);
1128470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            }
1129470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        }
1130470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com#ifdef WEBRTC_CODEC_RED
1131470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        // Register RED to the receiving side of the ACM.
1132470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        // We will not receive an OnInitializeDecoder() callback for RED.
1133470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        if (!STR_CASE_CMP(codec.plname, "RED"))
1134470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        {
1135eb524d997b877ba9b0bcaf8c85eae52bd40c37e3andrew@webrtc.org            if (audio_coding_->RegisterReceiveCodec(codec) == -1)
1136470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            {
1137470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                WEBRTC_TRACE(kTraceWarning, kTraceVoice,
1138470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                             VoEId(_instanceId,_channelId),
1139470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                             "Channel::Init() failed to register RED (%d/%d) "
1140470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                             "correctly",
1141470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                             codec.pltype, codec.plfreq);
1142470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            }
1143470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        }
1144470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com#endif
1145470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
1146684f0577fbe4ea393fef1dddf2ca7d02e3205b49pwestin@webrtc.org
11476c264cc92eb554716814db200b84752d4dfb6ba3andrew@webrtc.org    if (rx_audioproc_->noise_suppression()->set_level(kDefaultNsMode) != 0) {
1148ad856229a796a8efa1126ef8aa8d238f2b0a2b21pbos      LOG(LS_ERROR) << "noise_suppression()->set_level(kDefaultNsMode) failed.";
11496c264cc92eb554716814db200b84752d4dfb6ba3andrew@webrtc.org      return -1;
1150470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
11516c264cc92eb554716814db200b84752d4dfb6ba3andrew@webrtc.org    if (rx_audioproc_->gain_control()->set_mode(kDefaultRxAgcMode) != 0) {
1152ad856229a796a8efa1126ef8aa8d238f2b0a2b21pbos      LOG(LS_ERROR) << "gain_control()->set_mode(kDefaultRxAgcMode) failed.";
11536c264cc92eb554716814db200b84752d4dfb6ba3andrew@webrtc.org      return -1;
1154470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
1155470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
1156470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    return 0;
1157470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com}
1158470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
11596141e13873d0fdea626de08dfec2efa2c9171c76pbos@webrtc.orgint32_t
1160470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.comChannel::SetEngineInformation(Statistics& engineStatistics,
1161470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                              OutputMixer& outputMixer,
1162470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                              voe::TransmitMixer& transmitMixer,
1163470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                              ProcessThread& moduleProcessThread,
1164470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                              AudioDeviceModule& audioDeviceModule,
1165470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                              VoiceEngineObserver* voiceEngineObserver,
1166470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                              CriticalSectionWrapper* callbackCritSect)
1167470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com{
1168470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1169470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                 "Channel::SetEngineInformation()");
1170470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    _engineStatisticsPtr = &engineStatistics;
1171470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    _outputMixerPtr = &outputMixer;
1172470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    _transmitMixerPtr = &transmitMixer,
1173470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    _moduleProcessThreadPtr = &moduleProcessThread;
1174470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    _audioDeviceModulePtr = &audioDeviceModule;
1175470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    _voiceEngineObserverPtr = voiceEngineObserver;
1176470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    _callbackCritSectPtr = callbackCritSect;
1177470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    return 0;
1178470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com}
1179470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
11806141e13873d0fdea626de08dfec2efa2c9171c76pbos@webrtc.orgint32_t
1181470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.comChannel::UpdateLocalTimeStamp()
1182470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com{
1183470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
1184b7e5054414ff524f9db81dab7917729b8c4c8bcbPeter Kasting    _timeStamp += static_cast<uint32_t>(_audioFrame.samples_per_channel_);
1185470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    return 0;
1186470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com}
1187470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
11882d110be77f14cab0bb51efe8b61d9c7a967d04cbdeadbeefvoid Channel::SetSink(rtc::scoped_ptr<AudioSinkInterface> sink) {
1189f888bb58da04c5095759b5ec7ce2e1fa2cd414fdTommi  CriticalSectionScoped cs(&_callbackCritSect);
11902d110be77f14cab0bb51efe8b61d9c7a967d04cbdeadbeef  audio_sink_ = std::move(sink);
1191f888bb58da04c5095759b5ec7ce2e1fa2cd414fdTommi}
1192f888bb58da04c5095759b5ec7ce2e1fa2cd414fdTommi
11936141e13873d0fdea626de08dfec2efa2c9171c76pbos@webrtc.orgint32_t
1194470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.comChannel::StartPlayout()
1195470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com{
1196470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1197470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                 "Channel::StartPlayout()");
1198944cbeb2926feb86a687e5fda9e2ac88ea8e3001henrika@webrtc.org    if (channel_state_.Get().playing)
1199470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
1200470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        return 0;
1201470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
12021b60ceb499ee35460886f2bfaecee1f47319f925roosa@google.com
12031b60ceb499ee35460886f2bfaecee1f47319f925roosa@google.com    if (!_externalMixing) {
12041b60ceb499ee35460886f2bfaecee1f47319f925roosa@google.com        // Add participant as candidates for mixing.
12051b60ceb499ee35460886f2bfaecee1f47319f925roosa@google.com        if (_outputMixerPtr->SetMixabilityStatus(*this, true) != 0)
12061b60ceb499ee35460886f2bfaecee1f47319f925roosa@google.com        {
12071b60ceb499ee35460886f2bfaecee1f47319f925roosa@google.com            _engineStatisticsPtr->SetLastError(
12081b60ceb499ee35460886f2bfaecee1f47319f925roosa@google.com                VE_AUDIO_CONF_MIX_MODULE_ERROR, kTraceError,
12091b60ceb499ee35460886f2bfaecee1f47319f925roosa@google.com                "StartPlayout() failed to add participant to mixer");
12101b60ceb499ee35460886f2bfaecee1f47319f925roosa@google.com            return -1;
12111b60ceb499ee35460886f2bfaecee1f47319f925roosa@google.com        }
1212470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
1213470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
1214944cbeb2926feb86a687e5fda9e2ac88ea8e3001henrika@webrtc.org    channel_state_.SetPlaying(true);
1215ab12990b1b8c2410b34c055e73ed04e8a7ee1d85braveyao@webrtc.org    if (RegisterFilePlayingToMixer() != 0)
1216ab12990b1b8c2410b34c055e73ed04e8a7ee1d85braveyao@webrtc.org        return -1;
1217ab12990b1b8c2410b34c055e73ed04e8a7ee1d85braveyao@webrtc.org
1218470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    return 0;
1219470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com}
1220470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
12216141e13873d0fdea626de08dfec2efa2c9171c76pbos@webrtc.orgint32_t
1222470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.comChannel::StopPlayout()
1223470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com{
1224470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1225470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                 "Channel::StopPlayout()");
1226944cbeb2926feb86a687e5fda9e2ac88ea8e3001henrika@webrtc.org    if (!channel_state_.Get().playing)
1227470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
1228470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        return 0;
1229470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
12301b60ceb499ee35460886f2bfaecee1f47319f925roosa@google.com
12311b60ceb499ee35460886f2bfaecee1f47319f925roosa@google.com    if (!_externalMixing) {
12321b60ceb499ee35460886f2bfaecee1f47319f925roosa@google.com        // Remove participant as candidates for mixing
12331b60ceb499ee35460886f2bfaecee1f47319f925roosa@google.com        if (_outputMixerPtr->SetMixabilityStatus(*this, false) != 0)
12341b60ceb499ee35460886f2bfaecee1f47319f925roosa@google.com        {
12351b60ceb499ee35460886f2bfaecee1f47319f925roosa@google.com            _engineStatisticsPtr->SetLastError(
12361b60ceb499ee35460886f2bfaecee1f47319f925roosa@google.com                VE_AUDIO_CONF_MIX_MODULE_ERROR, kTraceError,
12371b60ceb499ee35460886f2bfaecee1f47319f925roosa@google.com                "StopPlayout() failed to remove participant from mixer");
12381b60ceb499ee35460886f2bfaecee1f47319f925roosa@google.com            return -1;
12391b60ceb499ee35460886f2bfaecee1f47319f925roosa@google.com        }
1240470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
1241470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
1242944cbeb2926feb86a687e5fda9e2ac88ea8e3001henrika@webrtc.org    channel_state_.SetPlaying(false);
1243470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    _outputAudioLevel.Clear();
1244470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
1245470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    return 0;
1246470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com}
1247470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
12486141e13873d0fdea626de08dfec2efa2c9171c76pbos@webrtc.orgint32_t
1249470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.comChannel::StartSend()
1250470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com{
1251470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1252470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                 "Channel::StartSend()");
125309e8c47ee5c58e5e86b09dc1950f8d3f9f24cd9fxians@webrtc.org    // Resume the previous sequence number which was reset by StopSend().
1254944cbeb2926feb86a687e5fda9e2ac88ea8e3001henrika@webrtc.org    // This needs to be done before |sending| is set to true.
125509e8c47ee5c58e5e86b09dc1950f8d3f9f24cd9fxians@webrtc.org    if (send_sequence_number_)
125609e8c47ee5c58e5e86b09dc1950f8d3f9f24cd9fxians@webrtc.org      SetInitSequenceNumber(send_sequence_number_);
125709e8c47ee5c58e5e86b09dc1950f8d3f9f24cd9fxians@webrtc.org
1258944cbeb2926feb86a687e5fda9e2ac88ea8e3001henrika@webrtc.org    if (channel_state_.Get().sending)
1259470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
1260944cbeb2926feb86a687e5fda9e2ac88ea8e3001henrika@webrtc.org      return 0;
1261470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
1262944cbeb2926feb86a687e5fda9e2ac88ea8e3001henrika@webrtc.org    channel_state_.SetSending(true);
1263e07247af8d0888529e14156a9929cbd2376f8442xians@webrtc.org
12642853dde5201d9ddc284ce5efb9688f6340487acepwestin@webrtc.org    if (_rtpRtcpModule->SetSendingStatus(true) != 0)
1265470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
1266470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        _engineStatisticsPtr->SetLastError(
1267470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            VE_RTP_RTCP_MODULE_ERROR, kTraceError,
1268470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            "StartSend() RTP/RTCP failed to start sending");
12699a065d1eae9ed296e1e2eaaad73d7ca1223bfe79mflodman@webrtc.org        CriticalSectionScoped cs(&_callbackCritSect);
1270944cbeb2926feb86a687e5fda9e2ac88ea8e3001henrika@webrtc.org        channel_state_.SetSending(false);
1271470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        return -1;
1272470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
1273e07247af8d0888529e14156a9929cbd2376f8442xians@webrtc.org
1274470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    return 0;
1275470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com}
1276470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
12776141e13873d0fdea626de08dfec2efa2c9171c76pbos@webrtc.orgint32_t
1278470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.comChannel::StopSend()
1279470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com{
1280470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1281470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                 "Channel::StopSend()");
1282944cbeb2926feb86a687e5fda9e2ac88ea8e3001henrika@webrtc.org    if (!channel_state_.Get().sending)
1283470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
1284944cbeb2926feb86a687e5fda9e2ac88ea8e3001henrika@webrtc.org      return 0;
1285470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
1286944cbeb2926feb86a687e5fda9e2ac88ea8e3001henrika@webrtc.org    channel_state_.SetSending(false);
1287e07247af8d0888529e14156a9929cbd2376f8442xians@webrtc.org
128809e8c47ee5c58e5e86b09dc1950f8d3f9f24cd9fxians@webrtc.org    // Store the sequence number to be able to pick up the same sequence for
128909e8c47ee5c58e5e86b09dc1950f8d3f9f24cd9fxians@webrtc.org    // the next StartSend(). This is needed for restarting device, otherwise
129009e8c47ee5c58e5e86b09dc1950f8d3f9f24cd9fxians@webrtc.org    // it might cause libSRTP to complain about packets being replayed.
129109e8c47ee5c58e5e86b09dc1950f8d3f9f24cd9fxians@webrtc.org    // TODO(xians): Remove this workaround after RtpRtcpModule's refactoring
129209e8c47ee5c58e5e86b09dc1950f8d3f9f24cd9fxians@webrtc.org    // CL is landed. See issue
129309e8c47ee5c58e5e86b09dc1950f8d3f9f24cd9fxians@webrtc.org    // https://code.google.com/p/webrtc/issues/detail?id=2111 .
129409e8c47ee5c58e5e86b09dc1950f8d3f9f24cd9fxians@webrtc.org    send_sequence_number_ = _rtpRtcpModule->SequenceNumber();
129509e8c47ee5c58e5e86b09dc1950f8d3f9f24cd9fxians@webrtc.org
1296470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    // Reset sending SSRC and sequence number and triggers direct transmission
1297470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    // of RTCP BYE
1298d436298332c7a7ecb51241f3a66588539c2ece83pbos    if (_rtpRtcpModule->SetSendingStatus(false) == -1)
1299470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
1300470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        _engineStatisticsPtr->SetLastError(
1301470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            VE_RTP_RTCP_MODULE_ERROR, kTraceWarning,
1302470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            "StartSend() RTP/RTCP failed to stop sending");
1303470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
1304470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
1305470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    return 0;
1306470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com}
1307470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
13086141e13873d0fdea626de08dfec2efa2c9171c76pbos@webrtc.orgint32_t
1309470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.comChannel::StartReceiving()
1310470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com{
1311470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1312470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                 "Channel::StartReceiving()");
1313944cbeb2926feb86a687e5fda9e2ac88ea8e3001henrika@webrtc.org    if (channel_state_.Get().receiving)
1314470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
1315470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        return 0;
1316470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
1317944cbeb2926feb86a687e5fda9e2ac88ea8e3001henrika@webrtc.org    channel_state_.SetReceiving(true);
1318470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    _numberOfDiscardedPackets = 0;
1319470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    return 0;
1320470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com}
1321470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
13226141e13873d0fdea626de08dfec2efa2c9171c76pbos@webrtc.orgint32_t
1323470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.comChannel::StopReceiving()
1324470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com{
1325470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1326470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                 "Channel::StopReceiving()");
1327944cbeb2926feb86a687e5fda9e2ac88ea8e3001henrika@webrtc.org    if (!channel_state_.Get().receiving)
1328470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
1329470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        return 0;
1330470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
1331684f0577fbe4ea393fef1dddf2ca7d02e3205b49pwestin@webrtc.org
1332944cbeb2926feb86a687e5fda9e2ac88ea8e3001henrika@webrtc.org    channel_state_.SetReceiving(false);
1333470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    return 0;
1334470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com}
1335470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
13366141e13873d0fdea626de08dfec2efa2c9171c76pbos@webrtc.orgint32_t
1337470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.comChannel::RegisterVoiceEngineObserver(VoiceEngineObserver& observer)
1338470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com{
1339470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1340470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                 "Channel::RegisterVoiceEngineObserver()");
13419a065d1eae9ed296e1e2eaaad73d7ca1223bfe79mflodman@webrtc.org    CriticalSectionScoped cs(&_callbackCritSect);
1342470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
1343470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    if (_voiceEngineObserverPtr)
1344470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
1345470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        _engineStatisticsPtr->SetLastError(
1346470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            VE_INVALID_OPERATION, kTraceError,
1347470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            "RegisterVoiceEngineObserver() observer already enabled");
1348470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        return -1;
1349470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
1350470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    _voiceEngineObserverPtr = &observer;
1351470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    return 0;
1352470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com}
1353470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
13546141e13873d0fdea626de08dfec2efa2c9171c76pbos@webrtc.orgint32_t
1355470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.comChannel::DeRegisterVoiceEngineObserver()
1356470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com{
1357470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1358470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                 "Channel::DeRegisterVoiceEngineObserver()");
13599a065d1eae9ed296e1e2eaaad73d7ca1223bfe79mflodman@webrtc.org    CriticalSectionScoped cs(&_callbackCritSect);
1360470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
1361470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    if (!_voiceEngineObserverPtr)
1362470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
1363470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        _engineStatisticsPtr->SetLastError(
1364470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            VE_INVALID_OPERATION, kTraceWarning,
1365470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            "DeRegisterVoiceEngineObserver() observer already disabled");
1366470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        return 0;
1367470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
1368470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    _voiceEngineObserverPtr = NULL;
1369470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    return 0;
1370470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com}
1371470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
13726141e13873d0fdea626de08dfec2efa2c9171c76pbos@webrtc.orgint32_t
1373470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.comChannel::GetSendCodec(CodecInst& codec)
1374470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com{
13751fd4a4ab35f1fcb08b551befca180de9a1f55dfckwiberg  auto send_codec = audio_coding_->SendCodec();
13761fd4a4ab35f1fcb08b551befca180de9a1f55dfckwiberg  if (send_codec) {
13771fd4a4ab35f1fcb08b551befca180de9a1f55dfckwiberg    codec = *send_codec;
13781fd4a4ab35f1fcb08b551befca180de9a1f55dfckwiberg    return 0;
13791fd4a4ab35f1fcb08b551befca180de9a1f55dfckwiberg  }
13801fd4a4ab35f1fcb08b551befca180de9a1f55dfckwiberg  return -1;
1381470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com}
1382470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
13836141e13873d0fdea626de08dfec2efa2c9171c76pbos@webrtc.orgint32_t
1384470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.comChannel::GetRecCodec(CodecInst& codec)
1385470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com{
1386eb524d997b877ba9b0bcaf8c85eae52bd40c37e3andrew@webrtc.org    return (audio_coding_->ReceiveCodec(&codec));
1387470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com}
1388470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
13896141e13873d0fdea626de08dfec2efa2c9171c76pbos@webrtc.orgint32_t
1390470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.comChannel::SetSendCodec(const CodecInst& codec)
1391470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com{
1392470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1393470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                 "Channel::SetSendCodec()");
1394470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
1395eb524d997b877ba9b0bcaf8c85eae52bd40c37e3andrew@webrtc.org    if (audio_coding_->RegisterSendCodec(codec) != 0)
1396470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
1397470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        WEBRTC_TRACE(kTraceError, kTraceVoice, VoEId(_instanceId,_channelId),
1398470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                     "SetSendCodec() failed to register codec to ACM");
1399470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        return -1;
1400470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
1401470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
14022853dde5201d9ddc284ce5efb9688f6340487acepwestin@webrtc.org    if (_rtpRtcpModule->RegisterSendPayload(codec) != 0)
1403470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
14042853dde5201d9ddc284ce5efb9688f6340487acepwestin@webrtc.org        _rtpRtcpModule->DeRegisterSendPayload(codec.pltype);
14052853dde5201d9ddc284ce5efb9688f6340487acepwestin@webrtc.org        if (_rtpRtcpModule->RegisterSendPayload(codec) != 0)
1406470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        {
1407470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            WEBRTC_TRACE(
1408470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                    kTraceError, kTraceVoice, VoEId(_instanceId,_channelId),
1409470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                    "SetSendCodec() failed to register codec to"
1410470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                    " RTP/RTCP module");
1411470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            return -1;
1412470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        }
1413470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
1414470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
14152853dde5201d9ddc284ce5efb9688f6340487acepwestin@webrtc.org    if (_rtpRtcpModule->SetAudioPacketSize(codec.pacsize) != 0)
1416470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
1417470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        WEBRTC_TRACE(kTraceError, kTraceVoice, VoEId(_instanceId,_channelId),
1418470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                     "SetSendCodec() failed to set audio packet size");
1419470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        return -1;
1420470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
1421470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
1422470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    return 0;
1423470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com}
1424470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
1425adf89b7e33cc54dab9365dddead687a46a074cf0Ivo Creusenvoid Channel::SetBitRate(int bitrate_bps) {
1426adf89b7e33cc54dab9365dddead687a46a074cf0Ivo Creusen  WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
1427adf89b7e33cc54dab9365dddead687a46a074cf0Ivo Creusen               "Channel::SetBitRate(bitrate_bps=%d)", bitrate_bps);
1428adf89b7e33cc54dab9365dddead687a46a074cf0Ivo Creusen  audio_coding_->SetBitRate(bitrate_bps);
1429adf89b7e33cc54dab9365dddead687a46a074cf0Ivo Creusen}
1430adf89b7e33cc54dab9365dddead687a46a074cf0Ivo Creusen
14310a7d4eed98ccec0c2b3e7522e7b2dde1919a4ae3mflodman@webrtc.orgvoid Channel::OnIncomingFractionLoss(int fraction_lost) {
143274aaf29a0ff1b211dbfdbb6309791111a7871779minyue@webrtc.org  network_predictor_->UpdatePacketLossRate(fraction_lost);
14330a7d4eed98ccec0c2b3e7522e7b2dde1919a4ae3mflodman@webrtc.org  uint8_t average_fraction_loss = network_predictor_->GetLossRate();
14340a7d4eed98ccec0c2b3e7522e7b2dde1919a4ae3mflodman@webrtc.org
1435c1a40a7b68a8d253b0ba32b89f3126931eeaeab3minyue@webrtc.org  // Normalizes rate to 0 - 100.
14360a7d4eed98ccec0c2b3e7522e7b2dde1919a4ae3mflodman@webrtc.org  if (audio_coding_->SetPacketLossRate(
14370a7d4eed98ccec0c2b3e7522e7b2dde1919a4ae3mflodman@webrtc.org      100 * average_fraction_loss / 255) != 0) {
1438c1a40a7b68a8d253b0ba32b89f3126931eeaeab3minyue@webrtc.org    assert(false);  // This should not happen.
1439c1a40a7b68a8d253b0ba32b89f3126931eeaeab3minyue@webrtc.org  }
1440c1a40a7b68a8d253b0ba32b89f3126931eeaeab3minyue@webrtc.org}
1441c1a40a7b68a8d253b0ba32b89f3126931eeaeab3minyue@webrtc.org
14426141e13873d0fdea626de08dfec2efa2c9171c76pbos@webrtc.orgint32_t
1443470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.comChannel::SetVADStatus(bool enableVAD, ACMVADMode mode, bool disableDTX)
1444470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com{
1445470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1446470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                 "Channel::SetVADStatus(mode=%d)", mode);
1447664ccb7d8da3adfffdb7c56f885b633224555e6ehenrik.lundin@webrtc.org    assert(!(disableDTX && enableVAD));  // disableDTX mode is deprecated.
1448470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    // To disable VAD, DTX must be disabled too
1449470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    disableDTX = ((enableVAD == false) ? true : disableDTX);
1450eb524d997b877ba9b0bcaf8c85eae52bd40c37e3andrew@webrtc.org    if (audio_coding_->SetVAD(!disableDTX, enableVAD, mode) != 0)
1451470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
1452470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        _engineStatisticsPtr->SetLastError(
1453470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
1454470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            "SetVADStatus() failed to set VAD");
1455470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        return -1;
1456470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
1457470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    return 0;
1458470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com}
1459470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
14606141e13873d0fdea626de08dfec2efa2c9171c76pbos@webrtc.orgint32_t
1461470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.comChannel::GetVADStatus(bool& enabledVAD, ACMVADMode& mode, bool& disabledDTX)
1462470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com{
1463eb524d997b877ba9b0bcaf8c85eae52bd40c37e3andrew@webrtc.org    if (audio_coding_->VAD(&disabledDTX, &enabledVAD, &mode) != 0)
1464470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
1465470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        _engineStatisticsPtr->SetLastError(
1466470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
1467470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            "GetVADStatus() failed to get VAD status");
1468470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        return -1;
1469470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
1470470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    disabledDTX = !disabledDTX;
1471470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    return 0;
1472470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com}
1473470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
14746141e13873d0fdea626de08dfec2efa2c9171c76pbos@webrtc.orgint32_t
1475470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.comChannel::SetRecPayloadType(const CodecInst& codec)
1476470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com{
1477470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1478470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                 "Channel::SetRecPayloadType()");
1479470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
1480944cbeb2926feb86a687e5fda9e2ac88ea8e3001henrika@webrtc.org    if (channel_state_.Get().playing)
1481470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
1482470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        _engineStatisticsPtr->SetLastError(
1483470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            VE_ALREADY_PLAYING, kTraceError,
1484470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            "SetRecPayloadType() unable to set PT while playing");
1485470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        return -1;
1486470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
1487944cbeb2926feb86a687e5fda9e2ac88ea8e3001henrika@webrtc.org    if (channel_state_.Get().receiving)
1488470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
1489470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        _engineStatisticsPtr->SetLastError(
1490470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            VE_ALREADY_LISTENING, kTraceError,
1491470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            "SetRecPayloadType() unable to set PT while listening");
1492470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        return -1;
1493470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
1494470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
1495470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    if (codec.pltype == -1)
1496470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
1497470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        // De-register the selected codec (RTP/RTCP module and ACM)
1498470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
14996141e13873d0fdea626de08dfec2efa2c9171c76pbos@webrtc.org        int8_t pltype(-1);
1500470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        CodecInst rxCodec = codec;
1501470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
1502470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        // Get payload type for the given codec
1503822fbd8b68ffdb481b9557e2950ae8d6657c8ce6wu@webrtc.org        rtp_payload_registry_->ReceivePayloadType(
1504822fbd8b68ffdb481b9557e2950ae8d6657c8ce6wu@webrtc.org            rxCodec.plname,
1505822fbd8b68ffdb481b9557e2950ae8d6657c8ce6wu@webrtc.org            rxCodec.plfreq,
1506822fbd8b68ffdb481b9557e2950ae8d6657c8ce6wu@webrtc.org            rxCodec.channels,
1507822fbd8b68ffdb481b9557e2950ae8d6657c8ce6wu@webrtc.org            (rxCodec.rate < 0) ? 0 : rxCodec.rate,
1508822fbd8b68ffdb481b9557e2950ae8d6657c8ce6wu@webrtc.org            &pltype);
1509470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        rxCodec.pltype = pltype;
1510470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
1511822fbd8b68ffdb481b9557e2950ae8d6657c8ce6wu@webrtc.org        if (rtp_receiver_->DeRegisterReceivePayload(pltype) != 0)
1512470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        {
1513470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            _engineStatisticsPtr->SetLastError(
1514470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                    VE_RTP_RTCP_MODULE_ERROR,
1515470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                    kTraceError,
1516470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                    "SetRecPayloadType() RTP/RTCP-module deregistration "
1517470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                    "failed");
1518470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            return -1;
1519470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        }
1520eb524d997b877ba9b0bcaf8c85eae52bd40c37e3andrew@webrtc.org        if (audio_coding_->UnregisterReceiveCodec(rxCodec.pltype) != 0)
1521470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        {
1522470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            _engineStatisticsPtr->SetLastError(
1523470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
1524470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                "SetRecPayloadType() ACM deregistration failed - 1");
1525470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            return -1;
1526470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        }
1527470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        return 0;
1528470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
1529470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
1530822fbd8b68ffdb481b9557e2950ae8d6657c8ce6wu@webrtc.org    if (rtp_receiver_->RegisterReceivePayload(
1531822fbd8b68ffdb481b9557e2950ae8d6657c8ce6wu@webrtc.org        codec.plname,
1532822fbd8b68ffdb481b9557e2950ae8d6657c8ce6wu@webrtc.org        codec.pltype,
1533822fbd8b68ffdb481b9557e2950ae8d6657c8ce6wu@webrtc.org        codec.plfreq,
1534822fbd8b68ffdb481b9557e2950ae8d6657c8ce6wu@webrtc.org        codec.channels,
1535822fbd8b68ffdb481b9557e2950ae8d6657c8ce6wu@webrtc.org        (codec.rate < 0) ? 0 : codec.rate) != 0)
1536470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
1537470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        // First attempt to register failed => de-register and try again
1538822fbd8b68ffdb481b9557e2950ae8d6657c8ce6wu@webrtc.org        rtp_receiver_->DeRegisterReceivePayload(codec.pltype);
1539822fbd8b68ffdb481b9557e2950ae8d6657c8ce6wu@webrtc.org        if (rtp_receiver_->RegisterReceivePayload(
1540822fbd8b68ffdb481b9557e2950ae8d6657c8ce6wu@webrtc.org            codec.plname,
1541822fbd8b68ffdb481b9557e2950ae8d6657c8ce6wu@webrtc.org            codec.pltype,
1542822fbd8b68ffdb481b9557e2950ae8d6657c8ce6wu@webrtc.org            codec.plfreq,
1543822fbd8b68ffdb481b9557e2950ae8d6657c8ce6wu@webrtc.org            codec.channels,
1544822fbd8b68ffdb481b9557e2950ae8d6657c8ce6wu@webrtc.org            (codec.rate < 0) ? 0 : codec.rate) != 0)
1545470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        {
1546470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            _engineStatisticsPtr->SetLastError(
1547470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                VE_RTP_RTCP_MODULE_ERROR, kTraceError,
1548470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                "SetRecPayloadType() RTP/RTCP-module registration failed");
1549470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            return -1;
1550470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        }
1551470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
1552eb524d997b877ba9b0bcaf8c85eae52bd40c37e3andrew@webrtc.org    if (audio_coding_->RegisterReceiveCodec(codec) != 0)
1553470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
1554eb524d997b877ba9b0bcaf8c85eae52bd40c37e3andrew@webrtc.org        audio_coding_->UnregisterReceiveCodec(codec.pltype);
1555eb524d997b877ba9b0bcaf8c85eae52bd40c37e3andrew@webrtc.org        if (audio_coding_->RegisterReceiveCodec(codec) != 0)
1556470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        {
1557470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            _engineStatisticsPtr->SetLastError(
1558470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
1559470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                "SetRecPayloadType() ACM registration failed - 1");
1560470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            return -1;
1561470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        }
1562470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
1563470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    return 0;
1564470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com}
1565470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
15666141e13873d0fdea626de08dfec2efa2c9171c76pbos@webrtc.orgint32_t
1567470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.comChannel::GetRecPayloadType(CodecInst& codec)
1568470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com{
15696141e13873d0fdea626de08dfec2efa2c9171c76pbos@webrtc.org    int8_t payloadType(-1);
1570822fbd8b68ffdb481b9557e2950ae8d6657c8ce6wu@webrtc.org    if (rtp_payload_registry_->ReceivePayloadType(
1571822fbd8b68ffdb481b9557e2950ae8d6657c8ce6wu@webrtc.org        codec.plname,
1572822fbd8b68ffdb481b9557e2950ae8d6657c8ce6wu@webrtc.org        codec.plfreq,
1573822fbd8b68ffdb481b9557e2950ae8d6657c8ce6wu@webrtc.org        codec.channels,
1574822fbd8b68ffdb481b9557e2950ae8d6657c8ce6wu@webrtc.org        (codec.rate < 0) ? 0 : codec.rate,
1575822fbd8b68ffdb481b9557e2950ae8d6657c8ce6wu@webrtc.org        &payloadType) != 0)
1576470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
1577470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        _engineStatisticsPtr->SetLastError(
157837198007eab6731fa0f77866155dd4f2b332a262henrika@webrtc.org            VE_RTP_RTCP_MODULE_ERROR, kTraceWarning,
1579470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            "GetRecPayloadType() failed to retrieve RX payload type");
1580470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        return -1;
1581470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
1582470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    codec.pltype = payloadType;
1583470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    return 0;
1584470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com}
1585470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
15866141e13873d0fdea626de08dfec2efa2c9171c76pbos@webrtc.orgint32_t
1587470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.comChannel::SetSendCNPayloadType(int type, PayloadFrequencies frequency)
1588470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com{
1589470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1590470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                 "Channel::SetSendCNPayloadType()");
1591470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
1592470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    CodecInst codec;
15936141e13873d0fdea626de08dfec2efa2c9171c76pbos@webrtc.org    int32_t samplingFreqHz(-1);
15946955870806624479723addfae6dcf5d13968796cPeter Kasting    const size_t kMono = 1;
1595470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    if (frequency == kFreq32000Hz)
1596470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        samplingFreqHz = 32000;
1597470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    else if (frequency == kFreq16000Hz)
1598470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        samplingFreqHz = 16000;
1599470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
1600eb524d997b877ba9b0bcaf8c85eae52bd40c37e3andrew@webrtc.org    if (audio_coding_->Codec("CN", &codec, samplingFreqHz, kMono) == -1)
1601470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
1602470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        _engineStatisticsPtr->SetLastError(
1603470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
1604470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            "SetSendCNPayloadType() failed to retrieve default CN codec "
1605470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            "settings");
1606470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        return -1;
1607470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
1608470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
1609470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    // Modify the payload type (must be set to dynamic range)
1610470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    codec.pltype = type;
1611470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
1612eb524d997b877ba9b0bcaf8c85eae52bd40c37e3andrew@webrtc.org    if (audio_coding_->RegisterSendCodec(codec) != 0)
1613470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
1614470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        _engineStatisticsPtr->SetLastError(
1615470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
1616470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            "SetSendCNPayloadType() failed to register CN to ACM");
1617470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        return -1;
1618470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
1619470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
16202853dde5201d9ddc284ce5efb9688f6340487acepwestin@webrtc.org    if (_rtpRtcpModule->RegisterSendPayload(codec) != 0)
1621470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
16222853dde5201d9ddc284ce5efb9688f6340487acepwestin@webrtc.org        _rtpRtcpModule->DeRegisterSendPayload(codec.pltype);
16232853dde5201d9ddc284ce5efb9688f6340487acepwestin@webrtc.org        if (_rtpRtcpModule->RegisterSendPayload(codec) != 0)
1624470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        {
1625470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            _engineStatisticsPtr->SetLastError(
1626470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                VE_RTP_RTCP_MODULE_ERROR, kTraceError,
1627470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                "SetSendCNPayloadType() failed to register CN to RTP/RTCP "
1628470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                "module");
1629470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            return -1;
1630470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        }
1631470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
1632470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    return 0;
1633470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com}
1634470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
1635adee8f924224e116f041564ddde83c979880e35fminyue@webrtc.orgint Channel::SetOpusMaxPlaybackRate(int frequency_hz) {
16366aac93bd9c3da92e92b016d83c8f84c65aae65b6minyue@webrtc.org  WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
1637adee8f924224e116f041564ddde83c979880e35fminyue@webrtc.org               "Channel::SetOpusMaxPlaybackRate()");
16386aac93bd9c3da92e92b016d83c8f84c65aae65b6minyue@webrtc.org
1639adee8f924224e116f041564ddde83c979880e35fminyue@webrtc.org  if (audio_coding_->SetOpusMaxPlaybackRate(frequency_hz) != 0) {
16406aac93bd9c3da92e92b016d83c8f84c65aae65b6minyue@webrtc.org    _engineStatisticsPtr->SetLastError(
16416aac93bd9c3da92e92b016d83c8f84c65aae65b6minyue@webrtc.org        VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
1642adee8f924224e116f041564ddde83c979880e35fminyue@webrtc.org        "SetOpusMaxPlaybackRate() failed to set maximum playback rate");
16436aac93bd9c3da92e92b016d83c8f84c65aae65b6minyue@webrtc.org    return -1;
16446aac93bd9c3da92e92b016d83c8f84c65aae65b6minyue@webrtc.org  }
16456aac93bd9c3da92e92b016d83c8f84c65aae65b6minyue@webrtc.org  return 0;
16466aac93bd9c3da92e92b016d83c8f84c65aae65b6minyue@webrtc.org}
16476aac93bd9c3da92e92b016d83c8f84c65aae65b6minyue@webrtc.org
16489b2e1144df6e3622354caca00baf4a7462a0809cminyue@webrtc.orgint Channel::SetOpusDtx(bool enable_dtx) {
16499b2e1144df6e3622354caca00baf4a7462a0809cminyue@webrtc.org  WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
16509b2e1144df6e3622354caca00baf4a7462a0809cminyue@webrtc.org               "Channel::SetOpusDtx(%d)", enable_dtx);
1651092041c1cdadeb82463ee79dfc291d60b41d35efMinyue Li  int ret = enable_dtx ? audio_coding_->EnableOpusDtx()
16529b2e1144df6e3622354caca00baf4a7462a0809cminyue@webrtc.org                       : audio_coding_->DisableOpusDtx();
16539b2e1144df6e3622354caca00baf4a7462a0809cminyue@webrtc.org  if (ret != 0) {
16549b2e1144df6e3622354caca00baf4a7462a0809cminyue@webrtc.org    _engineStatisticsPtr->SetLastError(
16559b2e1144df6e3622354caca00baf4a7462a0809cminyue@webrtc.org        VE_AUDIO_CODING_MODULE_ERROR, kTraceError, "SetOpusDtx() failed");
16569b2e1144df6e3622354caca00baf4a7462a0809cminyue@webrtc.org    return -1;
16579b2e1144df6e3622354caca00baf4a7462a0809cminyue@webrtc.org  }
16589b2e1144df6e3622354caca00baf4a7462a0809cminyue@webrtc.org  return 0;
16599b2e1144df6e3622354caca00baf4a7462a0809cminyue@webrtc.org}
16609b2e1144df6e3622354caca00baf4a7462a0809cminyue@webrtc.org
16616141e13873d0fdea626de08dfec2efa2c9171c76pbos@webrtc.orgint32_t Channel::RegisterExternalTransport(Transport& transport)
1662470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com{
1663470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
1664470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com               "Channel::RegisterExternalTransport()");
1665470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
16669a065d1eae9ed296e1e2eaaad73d7ca1223bfe79mflodman@webrtc.org    CriticalSectionScoped cs(&_callbackCritSect);
1667470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
1668470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    if (_externalTransport)
1669470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
1670470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        _engineStatisticsPtr->SetLastError(VE_INVALID_OPERATION,
1671470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                                           kTraceError,
1672470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com              "RegisterExternalTransport() external transport already enabled");
1673470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com       return -1;
1674470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
1675470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    _externalTransport = true;
1676470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    _transportPtr = &transport;
1677470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    return 0;
1678470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com}
1679470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
16806141e13873d0fdea626de08dfec2efa2c9171c76pbos@webrtc.orgint32_t
1681470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.comChannel::DeRegisterExternalTransport()
1682470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com{
1683470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1684470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                 "Channel::DeRegisterExternalTransport()");
1685470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
16869a065d1eae9ed296e1e2eaaad73d7ca1223bfe79mflodman@webrtc.org    CriticalSectionScoped cs(&_callbackCritSect);
168783661f534e56dfaf3542963b54b1e208f223a377xians@webrtc.org
1688470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    if (!_transportPtr)
1689470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
1690470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        _engineStatisticsPtr->SetLastError(
1691470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            VE_INVALID_OPERATION, kTraceWarning,
1692470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            "DeRegisterExternalTransport() external transport already "
1693470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            "disabled");
1694470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        return 0;
1695470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
1696470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    _externalTransport = false;
1697470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    _transportPtr = NULL;
1698470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1699470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                 "DeRegisterExternalTransport() all transport is disabled");
1700684f0577fbe4ea393fef1dddf2ca7d02e3205b49pwestin@webrtc.org    return 0;
1701684f0577fbe4ea393fef1dddf2ca7d02e3205b49pwestin@webrtc.org}
1702684f0577fbe4ea393fef1dddf2ca7d02e3205b49pwestin@webrtc.org
17034591fbd09f9cb6e83433c49a12dd8524c2806502pkasting@chromium.orgint32_t Channel::ReceivedRTPPacket(const int8_t* data, size_t length,
1704b1f50100757036cf475072c26f5f374eee9588casolenberg@webrtc.org                                   const PacketTime& packet_time) {
17050c45957e3a6963e1460c0b5b62a6adf43cf44314pwestin@webrtc.org  WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
17060c45957e3a6963e1460c0b5b62a6adf43cf44314pwestin@webrtc.org               "Channel::ReceivedRTPPacket()");
1707684f0577fbe4ea393fef1dddf2ca7d02e3205b49pwestin@webrtc.org
17080c45957e3a6963e1460c0b5b62a6adf43cf44314pwestin@webrtc.org  // Store playout timestamp for the received RTP packet
17091de01354e68da71bc62c81af17afeac8ed374a18pwestin@webrtc.org  UpdatePlayoutTimestamp(false);
1710684f0577fbe4ea393fef1dddf2ca7d02e3205b49pwestin@webrtc.org
17117bb8f02274ecbfa1f7ef134d708369a369a78c83stefan@webrtc.org  const uint8_t* received_packet = reinterpret_cast<const uint8_t*>(data);
1712a5cb98cbbd11e93cb6d0a6232387814aac168c7dstefan@webrtc.org  RTPHeader header;
17137bb8f02274ecbfa1f7ef134d708369a369a78c83stefan@webrtc.org  if (!rtp_header_parser_->Parse(received_packet, length, &header)) {
17147bb8f02274ecbfa1f7ef134d708369a369a78c83stefan@webrtc.org    WEBRTC_TRACE(webrtc::kTraceDebug, webrtc::kTraceVoice, _channelId,
17157bb8f02274ecbfa1f7ef134d708369a369a78c83stefan@webrtc.org                 "Incoming packet: invalid RTP header");
1716a5cb98cbbd11e93cb6d0a6232387814aac168c7dstefan@webrtc.org    return -1;
1717a5cb98cbbd11e93cb6d0a6232387814aac168c7dstefan@webrtc.org  }
1718822fbd8b68ffdb481b9557e2950ae8d6657c8ce6wu@webrtc.org  header.payload_type_frequency =
1719822fbd8b68ffdb481b9557e2950ae8d6657c8ce6wu@webrtc.org      rtp_payload_registry_->GetPayloadTypeFrequency(header.payloadType);
17207bb8f02274ecbfa1f7ef134d708369a369a78c83stefan@webrtc.org  if (header.payload_type_frequency < 0)
1721822fbd8b68ffdb481b9557e2950ae8d6657c8ce6wu@webrtc.org    return -1;
172248df38114d9502f4b4ad700c011190c608a702d5stefan@webrtc.org  bool in_order = IsPacketInOrder(header);
17237bb8f02274ecbfa1f7ef134d708369a369a78c83stefan@webrtc.org  rtp_receive_statistics_->IncomingPacket(header, length,
172448df38114d9502f4b4ad700c011190c608a702d5stefan@webrtc.org      IsPacketRetransmitted(header, in_order));
17257bb8f02274ecbfa1f7ef134d708369a369a78c83stefan@webrtc.org  rtp_payload_registry_->SetIncomingPayloadType(header);
1726b1f50100757036cf475072c26f5f374eee9588casolenberg@webrtc.org
172748df38114d9502f4b4ad700c011190c608a702d5stefan@webrtc.org  return ReceivePacket(received_packet, length, header, in_order) ? 0 : -1;
17287bb8f02274ecbfa1f7ef134d708369a369a78c83stefan@webrtc.org}
17297bb8f02274ecbfa1f7ef134d708369a369a78c83stefan@webrtc.org
17307bb8f02274ecbfa1f7ef134d708369a369a78c83stefan@webrtc.orgbool Channel::ReceivePacket(const uint8_t* packet,
17314591fbd09f9cb6e83433c49a12dd8524c2806502pkasting@chromium.org                            size_t packet_length,
17327bb8f02274ecbfa1f7ef134d708369a369a78c83stefan@webrtc.org                            const RTPHeader& header,
17337bb8f02274ecbfa1f7ef134d708369a369a78c83stefan@webrtc.org                            bool in_order) {
1734456f01441aa4f8c0c8b98aa6d9c2af4a4817e8dbminyue@webrtc.org  if (rtp_payload_registry_->IsRtx(header)) {
1735456f01441aa4f8c0c8b98aa6d9c2af4a4817e8dbminyue@webrtc.org    return HandleRtxPacket(packet, packet_length, header);
1736822fbd8b68ffdb481b9557e2950ae8d6657c8ce6wu@webrtc.org  }
17377bb8f02274ecbfa1f7ef134d708369a369a78c83stefan@webrtc.org  const uint8_t* payload = packet + header.headerLength;
17384591fbd09f9cb6e83433c49a12dd8524c2806502pkasting@chromium.org  assert(packet_length >= header.headerLength);
17394591fbd09f9cb6e83433c49a12dd8524c2806502pkasting@chromium.org  size_t payload_length = packet_length - header.headerLength;
1740822fbd8b68ffdb481b9557e2950ae8d6657c8ce6wu@webrtc.org  PayloadUnion payload_specific;
1741822fbd8b68ffdb481b9557e2950ae8d6657c8ce6wu@webrtc.org  if (!rtp_payload_registry_->GetPayloadSpecifics(header.payloadType,
17427bb8f02274ecbfa1f7ef134d708369a369a78c83stefan@webrtc.org                                                  &payload_specific)) {
17437bb8f02274ecbfa1f7ef134d708369a369a78c83stefan@webrtc.org    return false;
1744822fbd8b68ffdb481b9557e2950ae8d6657c8ce6wu@webrtc.org  }
17457bb8f02274ecbfa1f7ef134d708369a369a78c83stefan@webrtc.org  return rtp_receiver_->IncomingRtpPacket(header, payload, payload_length,
17467bb8f02274ecbfa1f7ef134d708369a369a78c83stefan@webrtc.org                                          payload_specific, in_order);
17477bb8f02274ecbfa1f7ef134d708369a369a78c83stefan@webrtc.org}
17487bb8f02274ecbfa1f7ef134d708369a369a78c83stefan@webrtc.org
1749456f01441aa4f8c0c8b98aa6d9c2af4a4817e8dbminyue@webrtc.orgbool Channel::HandleRtxPacket(const uint8_t* packet,
1750456f01441aa4f8c0c8b98aa6d9c2af4a4817e8dbminyue@webrtc.org                              size_t packet_length,
1751456f01441aa4f8c0c8b98aa6d9c2af4a4817e8dbminyue@webrtc.org                              const RTPHeader& header) {
17527bb8f02274ecbfa1f7ef134d708369a369a78c83stefan@webrtc.org  if (!rtp_payload_registry_->IsRtx(header))
17537bb8f02274ecbfa1f7ef134d708369a369a78c83stefan@webrtc.org    return false;
17547bb8f02274ecbfa1f7ef134d708369a369a78c83stefan@webrtc.org
17557bb8f02274ecbfa1f7ef134d708369a369a78c83stefan@webrtc.org  // Remove the RTX header and parse the original RTP header.
17567bb8f02274ecbfa1f7ef134d708369a369a78c83stefan@webrtc.org  if (packet_length < header.headerLength)
17577bb8f02274ecbfa1f7ef134d708369a369a78c83stefan@webrtc.org    return false;
17587bb8f02274ecbfa1f7ef134d708369a369a78c83stefan@webrtc.org  if (packet_length > kVoiceEngineMaxIpPacketSizeBytes)
17597bb8f02274ecbfa1f7ef134d708369a369a78c83stefan@webrtc.org    return false;
17607bb8f02274ecbfa1f7ef134d708369a369a78c83stefan@webrtc.org  if (restored_packet_in_use_) {
17617bb8f02274ecbfa1f7ef134d708369a369a78c83stefan@webrtc.org    WEBRTC_TRACE(webrtc::kTraceDebug, webrtc::kTraceVoice, _channelId,
17627bb8f02274ecbfa1f7ef134d708369a369a78c83stefan@webrtc.org                 "Multiple RTX headers detected, dropping packet");
17637bb8f02274ecbfa1f7ef134d708369a369a78c83stefan@webrtc.org    return false;
17640c45957e3a6963e1460c0b5b62a6adf43cf44314pwestin@webrtc.org  }
17657bb8f02274ecbfa1f7ef134d708369a369a78c83stefan@webrtc.org  if (!rtp_payload_registry_->RestoreOriginalPacket(
176665220a70a38ffe252b587775c5e9104606ab7c2cnoahric          restored_packet_, packet, &packet_length, rtp_receiver_->SSRC(),
176765220a70a38ffe252b587775c5e9104606ab7c2cnoahric          header)) {
17687bb8f02274ecbfa1f7ef134d708369a369a78c83stefan@webrtc.org    WEBRTC_TRACE(webrtc::kTraceDebug, webrtc::kTraceVoice, _channelId,
17697bb8f02274ecbfa1f7ef134d708369a369a78c83stefan@webrtc.org                 "Incoming RTX packet: invalid RTP header");
17707bb8f02274ecbfa1f7ef134d708369a369a78c83stefan@webrtc.org    return false;
17717bb8f02274ecbfa1f7ef134d708369a369a78c83stefan@webrtc.org  }
17727bb8f02274ecbfa1f7ef134d708369a369a78c83stefan@webrtc.org  restored_packet_in_use_ = true;
177365220a70a38ffe252b587775c5e9104606ab7c2cnoahric  bool ret = OnRecoveredPacket(restored_packet_, packet_length);
17747bb8f02274ecbfa1f7ef134d708369a369a78c83stefan@webrtc.org  restored_packet_in_use_ = false;
17757bb8f02274ecbfa1f7ef134d708369a369a78c83stefan@webrtc.org  return ret;
17767bb8f02274ecbfa1f7ef134d708369a369a78c83stefan@webrtc.org}
17777bb8f02274ecbfa1f7ef134d708369a369a78c83stefan@webrtc.org
17787bb8f02274ecbfa1f7ef134d708369a369a78c83stefan@webrtc.orgbool Channel::IsPacketInOrder(const RTPHeader& header) const {
17797bb8f02274ecbfa1f7ef134d708369a369a78c83stefan@webrtc.org  StreamStatistician* statistician =
17807bb8f02274ecbfa1f7ef134d708369a369a78c83stefan@webrtc.org      rtp_receive_statistics_->GetStatistician(header.ssrc);
17817bb8f02274ecbfa1f7ef134d708369a369a78c83stefan@webrtc.org  if (!statistician)
17827bb8f02274ecbfa1f7ef134d708369a369a78c83stefan@webrtc.org    return false;
17837bb8f02274ecbfa1f7ef134d708369a369a78c83stefan@webrtc.org  return statistician->IsPacketInOrder(header.sequenceNumber);
17840c45957e3a6963e1460c0b5b62a6adf43cf44314pwestin@webrtc.org}
17850c45957e3a6963e1460c0b5b62a6adf43cf44314pwestin@webrtc.org
178648df38114d9502f4b4ad700c011190c608a702d5stefan@webrtc.orgbool Channel::IsPacketRetransmitted(const RTPHeader& header,
178748df38114d9502f4b4ad700c011190c608a702d5stefan@webrtc.org                                    bool in_order) const {
17887bb8f02274ecbfa1f7ef134d708369a369a78c83stefan@webrtc.org  // Retransmissions are handled separately if RTX is enabled.
17897bb8f02274ecbfa1f7ef134d708369a369a78c83stefan@webrtc.org  if (rtp_payload_registry_->RtxEnabled())
17907bb8f02274ecbfa1f7ef134d708369a369a78c83stefan@webrtc.org    return false;
17917bb8f02274ecbfa1f7ef134d708369a369a78c83stefan@webrtc.org  StreamStatistician* statistician =
17927bb8f02274ecbfa1f7ef134d708369a369a78c83stefan@webrtc.org      rtp_receive_statistics_->GetStatistician(header.ssrc);
17937bb8f02274ecbfa1f7ef134d708369a369a78c83stefan@webrtc.org  if (!statistician)
17947bb8f02274ecbfa1f7ef134d708369a369a78c83stefan@webrtc.org    return false;
17957bb8f02274ecbfa1f7ef134d708369a369a78c83stefan@webrtc.org  // Check if this is a retransmission.
179616825b1a828bb4ff40f7682040e43a239b7b8ca3pkasting@chromium.org  int64_t min_rtt = 0;
17977bb8f02274ecbfa1f7ef134d708369a369a78c83stefan@webrtc.org  _rtpRtcpModule->RTT(rtp_receiver_->SSRC(), NULL, NULL, &min_rtt, NULL);
179848df38114d9502f4b4ad700c011190c608a702d5stefan@webrtc.org  return !in_order &&
17997bb8f02274ecbfa1f7ef134d708369a369a78c83stefan@webrtc.org      statistician->IsRetransmitOfOldPacket(header, min_rtt);
1800822fbd8b68ffdb481b9557e2950ae8d6657c8ce6wu@webrtc.org}
1801822fbd8b68ffdb481b9557e2950ae8d6657c8ce6wu@webrtc.org
18024591fbd09f9cb6e83433c49a12dd8524c2806502pkasting@chromium.orgint32_t Channel::ReceivedRTCPPacket(const int8_t* data, size_t length) {
18030c45957e3a6963e1460c0b5b62a6adf43cf44314pwestin@webrtc.org  WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
18040c45957e3a6963e1460c0b5b62a6adf43cf44314pwestin@webrtc.org               "Channel::ReceivedRTCPPacket()");
18050c45957e3a6963e1460c0b5b62a6adf43cf44314pwestin@webrtc.org  // Store playout timestamp for the received RTCP packet
18061de01354e68da71bc62c81af17afeac8ed374a18pwestin@webrtc.org  UpdatePlayoutTimestamp(true);
18070c45957e3a6963e1460c0b5b62a6adf43cf44314pwestin@webrtc.org
18080c45957e3a6963e1460c0b5b62a6adf43cf44314pwestin@webrtc.org  // Deliver RTCP packet to RTP/RTCP module for parsing
18094591fbd09f9cb6e83433c49a12dd8524c2806502pkasting@chromium.org  if (_rtpRtcpModule->IncomingRtcpPacket((const uint8_t*)data, length) == -1) {
18100c45957e3a6963e1460c0b5b62a6adf43cf44314pwestin@webrtc.org    _engineStatisticsPtr->SetLastError(
18110c45957e3a6963e1460c0b5b62a6adf43cf44314pwestin@webrtc.org        VE_SOCKET_TRANSPORT_MODULE_ERROR, kTraceWarning,
18120c45957e3a6963e1460c0b5b62a6adf43cf44314pwestin@webrtc.org        "Channel::IncomingRTPPacket() RTCP packet is invalid");
18130c45957e3a6963e1460c0b5b62a6adf43cf44314pwestin@webrtc.org  }
181482c4b8531c2c4c2aaf82ff57ee1805037a43ed50wu@webrtc.org
18152013aeced2b7821a407f302802c4a16fd02728b1Minyue  int64_t rtt = GetRTT(true);
18162013aeced2b7821a407f302802c4a16fd02728b1Minyue  if (rtt == 0) {
18172013aeced2b7821a407f302802c4a16fd02728b1Minyue    // Waiting for valid RTT.
18182013aeced2b7821a407f302802c4a16fd02728b1Minyue    return 0;
18192013aeced2b7821a407f302802c4a16fd02728b1Minyue  }
18202013aeced2b7821a407f302802c4a16fd02728b1Minyue  uint32_t ntp_secs = 0;
18212013aeced2b7821a407f302802c4a16fd02728b1Minyue  uint32_t ntp_frac = 0;
18222013aeced2b7821a407f302802c4a16fd02728b1Minyue  uint32_t rtp_timestamp = 0;
18232013aeced2b7821a407f302802c4a16fd02728b1Minyue  if (0 != _rtpRtcpModule->RemoteNTP(&ntp_secs, &ntp_frac, NULL, NULL,
18242013aeced2b7821a407f302802c4a16fd02728b1Minyue                                     &rtp_timestamp)) {
18252013aeced2b7821a407f302802c4a16fd02728b1Minyue    // Waiting for RTCP.
18262013aeced2b7821a407f302802c4a16fd02728b1Minyue    return 0;
18272013aeced2b7821a407f302802c4a16fd02728b1Minyue  }
18282013aeced2b7821a407f302802c4a16fd02728b1Minyue
18298e24d8777849951ed86fb01e0bf556d4eda65161stefan@webrtc.org  {
18308e24d8777849951ed86fb01e0bf556d4eda65161stefan@webrtc.org    CriticalSectionScoped lock(ts_stats_lock_.get());
18312c0cdbce226137a8f755ae0fb51c28a335b2ea5dminyue@webrtc.org    ntp_estimator_.UpdateRtcpTimestamp(rtt, ntp_secs, ntp_frac, rtp_timestamp);
18328e24d8777849951ed86fb01e0bf556d4eda65161stefan@webrtc.org  }
18330c45957e3a6963e1460c0b5b62a6adf43cf44314pwestin@webrtc.org  return 0;
1834684f0577fbe4ea393fef1dddf2ca7d02e3205b49pwestin@webrtc.org}
1835684f0577fbe4ea393fef1dddf2ca7d02e3205b49pwestin@webrtc.org
1836470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.comint Channel::StartPlayingFileLocally(const char* fileName,
18379213521ea98b0977c7cdabd2853060835af226f3pbos@webrtc.org                                     bool loop,
18389213521ea98b0977c7cdabd2853060835af226f3pbos@webrtc.org                                     FileFormats format,
18399213521ea98b0977c7cdabd2853060835af226f3pbos@webrtc.org                                     int startPosition,
18409213521ea98b0977c7cdabd2853060835af226f3pbos@webrtc.org                                     float volumeScaling,
18419213521ea98b0977c7cdabd2853060835af226f3pbos@webrtc.org                                     int stopPosition,
1842470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                                     const CodecInst* codecInst)
1843470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com{
1844470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1845470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                 "Channel::StartPlayingFileLocally(fileNameUTF8[]=%s, loop=%d,"
1846470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                 " format=%d, volumeScaling=%5.3f, startPosition=%d, "
1847470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                 "stopPosition=%d)", fileName, loop, format, volumeScaling,
1848470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                 startPosition, stopPosition);
1849470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
1850944cbeb2926feb86a687e5fda9e2ac88ea8e3001henrika@webrtc.org    if (channel_state_.Get().output_file_playing)
1851470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
1852470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        _engineStatisticsPtr->SetLastError(
1853470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            VE_ALREADY_PLAYING, kTraceError,
1854470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            "StartPlayingFileLocally() is already playing");
1855470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        return -1;
1856470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
1857470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
1858470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
18599a065d1eae9ed296e1e2eaaad73d7ca1223bfe79mflodman@webrtc.org        CriticalSectionScoped cs(&_fileCritSect);
1860470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
1861b37c628ae43a9086da607a638785723306bd9aedhenrike@webrtc.org        if (_outputFilePlayerPtr)
1862b37c628ae43a9086da607a638785723306bd9aedhenrike@webrtc.org        {
1863b37c628ae43a9086da607a638785723306bd9aedhenrike@webrtc.org            _outputFilePlayerPtr->RegisterModuleFileCallback(NULL);
1864b37c628ae43a9086da607a638785723306bd9aedhenrike@webrtc.org            FilePlayer::DestroyFilePlayer(_outputFilePlayerPtr);
1865b37c628ae43a9086da607a638785723306bd9aedhenrike@webrtc.org            _outputFilePlayerPtr = NULL;
1866b37c628ae43a9086da607a638785723306bd9aedhenrike@webrtc.org        }
1867470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
1868b37c628ae43a9086da607a638785723306bd9aedhenrike@webrtc.org        _outputFilePlayerPtr = FilePlayer::CreateFilePlayer(
1869b37c628ae43a9086da607a638785723306bd9aedhenrike@webrtc.org            _outputFilePlayerId, (const FileFormats)format);
1870b37c628ae43a9086da607a638785723306bd9aedhenrike@webrtc.org
1871b37c628ae43a9086da607a638785723306bd9aedhenrike@webrtc.org        if (_outputFilePlayerPtr == NULL)
1872b37c628ae43a9086da607a638785723306bd9aedhenrike@webrtc.org        {
1873b37c628ae43a9086da607a638785723306bd9aedhenrike@webrtc.org            _engineStatisticsPtr->SetLastError(
1874b37c628ae43a9086da607a638785723306bd9aedhenrike@webrtc.org                VE_INVALID_ARGUMENT, kTraceError,
187531d30700d638c4cfa47c26cac7cb00c7232874c9henrike@webrtc.org                "StartPlayingFileLocally() filePlayer format is not correct");
1876b37c628ae43a9086da607a638785723306bd9aedhenrike@webrtc.org            return -1;
1877b37c628ae43a9086da607a638785723306bd9aedhenrike@webrtc.org        }
1878470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
18796141e13873d0fdea626de08dfec2efa2c9171c76pbos@webrtc.org        const uint32_t notificationTime(0);
1880470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
1881b37c628ae43a9086da607a638785723306bd9aedhenrike@webrtc.org        if (_outputFilePlayerPtr->StartPlayingFile(
1882b37c628ae43a9086da607a638785723306bd9aedhenrike@webrtc.org                fileName,
1883b37c628ae43a9086da607a638785723306bd9aedhenrike@webrtc.org                loop,
1884b37c628ae43a9086da607a638785723306bd9aedhenrike@webrtc.org                startPosition,
1885b37c628ae43a9086da607a638785723306bd9aedhenrike@webrtc.org                volumeScaling,
1886b37c628ae43a9086da607a638785723306bd9aedhenrike@webrtc.org                notificationTime,
1887b37c628ae43a9086da607a638785723306bd9aedhenrike@webrtc.org                stopPosition,
1888b37c628ae43a9086da607a638785723306bd9aedhenrike@webrtc.org                (const CodecInst*)codecInst) != 0)
1889b37c628ae43a9086da607a638785723306bd9aedhenrike@webrtc.org        {
1890b37c628ae43a9086da607a638785723306bd9aedhenrike@webrtc.org            _engineStatisticsPtr->SetLastError(
1891b37c628ae43a9086da607a638785723306bd9aedhenrike@webrtc.org                VE_BAD_FILE, kTraceError,
1892b37c628ae43a9086da607a638785723306bd9aedhenrike@webrtc.org                "StartPlayingFile() failed to start file playout");
1893b37c628ae43a9086da607a638785723306bd9aedhenrike@webrtc.org            _outputFilePlayerPtr->StopPlayingFile();
1894b37c628ae43a9086da607a638785723306bd9aedhenrike@webrtc.org            FilePlayer::DestroyFilePlayer(_outputFilePlayerPtr);
1895b37c628ae43a9086da607a638785723306bd9aedhenrike@webrtc.org            _outputFilePlayerPtr = NULL;
1896b37c628ae43a9086da607a638785723306bd9aedhenrike@webrtc.org            return -1;
1897b37c628ae43a9086da607a638785723306bd9aedhenrike@webrtc.org        }
1898b37c628ae43a9086da607a638785723306bd9aedhenrike@webrtc.org        _outputFilePlayerPtr->RegisterModuleFileCallback(this);
1899944cbeb2926feb86a687e5fda9e2ac88ea8e3001henrika@webrtc.org        channel_state_.SetOutputFilePlaying(true);
1900470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
1901ab12990b1b8c2410b34c055e73ed04e8a7ee1d85braveyao@webrtc.org
1902ab12990b1b8c2410b34c055e73ed04e8a7ee1d85braveyao@webrtc.org    if (RegisterFilePlayingToMixer() != 0)
1903066f9e5a2fbb8e83ef88ceca0ab5a4ea057cc619henrike@webrtc.org        return -1;
1904470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
1905470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    return 0;
1906470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com}
1907470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
1908470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.comint Channel::StartPlayingFileLocally(InStream* stream,
19099213521ea98b0977c7cdabd2853060835af226f3pbos@webrtc.org                                     FileFormats format,
19109213521ea98b0977c7cdabd2853060835af226f3pbos@webrtc.org                                     int startPosition,
19119213521ea98b0977c7cdabd2853060835af226f3pbos@webrtc.org                                     float volumeScaling,
19129213521ea98b0977c7cdabd2853060835af226f3pbos@webrtc.org                                     int stopPosition,
1913470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                                     const CodecInst* codecInst)
1914470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com{
1915470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1916470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                 "Channel::StartPlayingFileLocally(format=%d,"
1917470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                 " volumeScaling=%5.3f, startPosition=%d, stopPosition=%d)",
1918470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                 format, volumeScaling, startPosition, stopPosition);
1919470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
1920470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    if(stream == NULL)
1921470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
1922470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        _engineStatisticsPtr->SetLastError(
1923470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            VE_BAD_FILE, kTraceError,
1924470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            "StartPlayingFileLocally() NULL as input stream");
1925470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        return -1;
1926470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
1927470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
1928470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
1929944cbeb2926feb86a687e5fda9e2ac88ea8e3001henrika@webrtc.org    if (channel_state_.Get().output_file_playing)
1930470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
1931470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        _engineStatisticsPtr->SetLastError(
1932470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            VE_ALREADY_PLAYING, kTraceError,
1933470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            "StartPlayingFileLocally() is already playing");
1934470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        return -1;
1935470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
1936470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
1937470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
19389a065d1eae9ed296e1e2eaaad73d7ca1223bfe79mflodman@webrtc.org      CriticalSectionScoped cs(&_fileCritSect);
1939b37c628ae43a9086da607a638785723306bd9aedhenrike@webrtc.org
1940b37c628ae43a9086da607a638785723306bd9aedhenrike@webrtc.org      // Destroy the old instance
1941b37c628ae43a9086da607a638785723306bd9aedhenrike@webrtc.org      if (_outputFilePlayerPtr)
1942b37c628ae43a9086da607a638785723306bd9aedhenrike@webrtc.org      {
1943b37c628ae43a9086da607a638785723306bd9aedhenrike@webrtc.org          _outputFilePlayerPtr->RegisterModuleFileCallback(NULL);
1944b37c628ae43a9086da607a638785723306bd9aedhenrike@webrtc.org          FilePlayer::DestroyFilePlayer(_outputFilePlayerPtr);
1945b37c628ae43a9086da607a638785723306bd9aedhenrike@webrtc.org          _outputFilePlayerPtr = NULL;
1946b37c628ae43a9086da607a638785723306bd9aedhenrike@webrtc.org      }
1947b37c628ae43a9086da607a638785723306bd9aedhenrike@webrtc.org
1948b37c628ae43a9086da607a638785723306bd9aedhenrike@webrtc.org      // Create the instance
1949b37c628ae43a9086da607a638785723306bd9aedhenrike@webrtc.org      _outputFilePlayerPtr = FilePlayer::CreateFilePlayer(
1950b37c628ae43a9086da607a638785723306bd9aedhenrike@webrtc.org          _outputFilePlayerId,
1951b37c628ae43a9086da607a638785723306bd9aedhenrike@webrtc.org          (const FileFormats)format);
1952b37c628ae43a9086da607a638785723306bd9aedhenrike@webrtc.org
1953b37c628ae43a9086da607a638785723306bd9aedhenrike@webrtc.org      if (_outputFilePlayerPtr == NULL)
1954b37c628ae43a9086da607a638785723306bd9aedhenrike@webrtc.org      {
1955b37c628ae43a9086da607a638785723306bd9aedhenrike@webrtc.org          _engineStatisticsPtr->SetLastError(
1956b37c628ae43a9086da607a638785723306bd9aedhenrike@webrtc.org              VE_INVALID_ARGUMENT, kTraceError,
1957b37c628ae43a9086da607a638785723306bd9aedhenrike@webrtc.org              "StartPlayingFileLocally() filePlayer format isnot correct");
1958b37c628ae43a9086da607a638785723306bd9aedhenrike@webrtc.org          return -1;
1959b37c628ae43a9086da607a638785723306bd9aedhenrike@webrtc.org      }
1960b37c628ae43a9086da607a638785723306bd9aedhenrike@webrtc.org
19616141e13873d0fdea626de08dfec2efa2c9171c76pbos@webrtc.org      const uint32_t notificationTime(0);
1962b37c628ae43a9086da607a638785723306bd9aedhenrike@webrtc.org
1963b37c628ae43a9086da607a638785723306bd9aedhenrike@webrtc.org      if (_outputFilePlayerPtr->StartPlayingFile(*stream, startPosition,
1964b37c628ae43a9086da607a638785723306bd9aedhenrike@webrtc.org                                                 volumeScaling,
1965b37c628ae43a9086da607a638785723306bd9aedhenrike@webrtc.org                                                 notificationTime,
1966b37c628ae43a9086da607a638785723306bd9aedhenrike@webrtc.org                                                 stopPosition, codecInst) != 0)
1967b37c628ae43a9086da607a638785723306bd9aedhenrike@webrtc.org      {
1968b37c628ae43a9086da607a638785723306bd9aedhenrike@webrtc.org          _engineStatisticsPtr->SetLastError(VE_BAD_FILE, kTraceError,
1969b37c628ae43a9086da607a638785723306bd9aedhenrike@webrtc.org                                             "StartPlayingFile() failed to "
1970b37c628ae43a9086da607a638785723306bd9aedhenrike@webrtc.org                                             "start file playout");
1971b37c628ae43a9086da607a638785723306bd9aedhenrike@webrtc.org          _outputFilePlayerPtr->StopPlayingFile();
1972b37c628ae43a9086da607a638785723306bd9aedhenrike@webrtc.org          FilePlayer::DestroyFilePlayer(_outputFilePlayerPtr);
1973b37c628ae43a9086da607a638785723306bd9aedhenrike@webrtc.org          _outputFilePlayerPtr = NULL;
1974b37c628ae43a9086da607a638785723306bd9aedhenrike@webrtc.org          return -1;
1975b37c628ae43a9086da607a638785723306bd9aedhenrike@webrtc.org      }
1976b37c628ae43a9086da607a638785723306bd9aedhenrike@webrtc.org      _outputFilePlayerPtr->RegisterModuleFileCallback(this);
1977944cbeb2926feb86a687e5fda9e2ac88ea8e3001henrika@webrtc.org      channel_state_.SetOutputFilePlaying(true);
1978b37c628ae43a9086da607a638785723306bd9aedhenrike@webrtc.org    }
1979ab12990b1b8c2410b34c055e73ed04e8a7ee1d85braveyao@webrtc.org
1980ab12990b1b8c2410b34c055e73ed04e8a7ee1d85braveyao@webrtc.org    if (RegisterFilePlayingToMixer() != 0)
1981066f9e5a2fbb8e83ef88ceca0ab5a4ea057cc619henrike@webrtc.org        return -1;
1982470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
1983470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    return 0;
1984470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com}
1985470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
1986470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.comint Channel::StopPlayingFileLocally()
1987470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com{
1988470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1989470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                 "Channel::StopPlayingFileLocally()");
1990470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
1991944cbeb2926feb86a687e5fda9e2ac88ea8e3001henrika@webrtc.org    if (!channel_state_.Get().output_file_playing)
1992470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
1993470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        return 0;
1994470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
1995470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
1996470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
19979a065d1eae9ed296e1e2eaaad73d7ca1223bfe79mflodman@webrtc.org        CriticalSectionScoped cs(&_fileCritSect);
1998b37c628ae43a9086da607a638785723306bd9aedhenrike@webrtc.org
1999b37c628ae43a9086da607a638785723306bd9aedhenrike@webrtc.org        if (_outputFilePlayerPtr->StopPlayingFile() != 0)
2000b37c628ae43a9086da607a638785723306bd9aedhenrike@webrtc.org        {
2001b37c628ae43a9086da607a638785723306bd9aedhenrike@webrtc.org            _engineStatisticsPtr->SetLastError(
2002b37c628ae43a9086da607a638785723306bd9aedhenrike@webrtc.org                VE_STOP_RECORDING_FAILED, kTraceError,
2003b37c628ae43a9086da607a638785723306bd9aedhenrike@webrtc.org                "StopPlayingFile() could not stop playing");
2004b37c628ae43a9086da607a638785723306bd9aedhenrike@webrtc.org            return -1;
2005b37c628ae43a9086da607a638785723306bd9aedhenrike@webrtc.org        }
2006b37c628ae43a9086da607a638785723306bd9aedhenrike@webrtc.org        _outputFilePlayerPtr->RegisterModuleFileCallback(NULL);
2007b37c628ae43a9086da607a638785723306bd9aedhenrike@webrtc.org        FilePlayer::DestroyFilePlayer(_outputFilePlayerPtr);
2008b37c628ae43a9086da607a638785723306bd9aedhenrike@webrtc.org        _outputFilePlayerPtr = NULL;
2009944cbeb2926feb86a687e5fda9e2ac88ea8e3001henrika@webrtc.org        channel_state_.SetOutputFilePlaying(false);
2010470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
2011b37c628ae43a9086da607a638785723306bd9aedhenrike@webrtc.org    // _fileCritSect cannot be taken while calling
2012b37c628ae43a9086da607a638785723306bd9aedhenrike@webrtc.org    // SetAnonymousMixibilityStatus. Refer to comments in
2013b37c628ae43a9086da607a638785723306bd9aedhenrike@webrtc.org    // StartPlayingFileLocally(const char* ...) for more details.
2014066f9e5a2fbb8e83ef88ceca0ab5a4ea057cc619henrike@webrtc.org    if (_outputMixerPtr->SetAnonymousMixabilityStatus(*this, false) != 0)
2015066f9e5a2fbb8e83ef88ceca0ab5a4ea057cc619henrike@webrtc.org    {
2016066f9e5a2fbb8e83ef88ceca0ab5a4ea057cc619henrike@webrtc.org        _engineStatisticsPtr->SetLastError(
2017066f9e5a2fbb8e83ef88ceca0ab5a4ea057cc619henrike@webrtc.org            VE_AUDIO_CONF_MIX_MODULE_ERROR, kTraceError,
2018b37c628ae43a9086da607a638785723306bd9aedhenrike@webrtc.org            "StopPlayingFile() failed to stop participant from playing as"
2019b37c628ae43a9086da607a638785723306bd9aedhenrike@webrtc.org            "file in the mixer");
2020066f9e5a2fbb8e83ef88ceca0ab5a4ea057cc619henrike@webrtc.org        return -1;
2021066f9e5a2fbb8e83ef88ceca0ab5a4ea057cc619henrike@webrtc.org    }
2022470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
2023470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    return 0;
2024470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com}
2025470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
2026470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.comint Channel::IsPlayingFileLocally() const
2027470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com{
2028944cbeb2926feb86a687e5fda9e2ac88ea8e3001henrika@webrtc.org    return channel_state_.Get().output_file_playing;
2029470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com}
2030470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
2031ab12990b1b8c2410b34c055e73ed04e8a7ee1d85braveyao@webrtc.orgint Channel::RegisterFilePlayingToMixer()
2032ab12990b1b8c2410b34c055e73ed04e8a7ee1d85braveyao@webrtc.org{
2033ab12990b1b8c2410b34c055e73ed04e8a7ee1d85braveyao@webrtc.org    // Return success for not registering for file playing to mixer if:
2034ab12990b1b8c2410b34c055e73ed04e8a7ee1d85braveyao@webrtc.org    // 1. playing file before playout is started on that channel.
2035ab12990b1b8c2410b34c055e73ed04e8a7ee1d85braveyao@webrtc.org    // 2. starting playout without file playing on that channel.
2036944cbeb2926feb86a687e5fda9e2ac88ea8e3001henrika@webrtc.org    if (!channel_state_.Get().playing ||
2037944cbeb2926feb86a687e5fda9e2ac88ea8e3001henrika@webrtc.org        !channel_state_.Get().output_file_playing)
2038ab12990b1b8c2410b34c055e73ed04e8a7ee1d85braveyao@webrtc.org    {
2039ab12990b1b8c2410b34c055e73ed04e8a7ee1d85braveyao@webrtc.org        return 0;
2040ab12990b1b8c2410b34c055e73ed04e8a7ee1d85braveyao@webrtc.org    }
2041ab12990b1b8c2410b34c055e73ed04e8a7ee1d85braveyao@webrtc.org
2042ab12990b1b8c2410b34c055e73ed04e8a7ee1d85braveyao@webrtc.org    // |_fileCritSect| cannot be taken while calling
2043ab12990b1b8c2410b34c055e73ed04e8a7ee1d85braveyao@webrtc.org    // SetAnonymousMixabilityStatus() since as soon as the participant is added
2044ab12990b1b8c2410b34c055e73ed04e8a7ee1d85braveyao@webrtc.org    // frames can be pulled by the mixer. Since the frames are generated from
2045ab12990b1b8c2410b34c055e73ed04e8a7ee1d85braveyao@webrtc.org    // the file, _fileCritSect will be taken. This would result in a deadlock.
2046ab12990b1b8c2410b34c055e73ed04e8a7ee1d85braveyao@webrtc.org    if (_outputMixerPtr->SetAnonymousMixabilityStatus(*this, true) != 0)
2047ab12990b1b8c2410b34c055e73ed04e8a7ee1d85braveyao@webrtc.org    {
2048944cbeb2926feb86a687e5fda9e2ac88ea8e3001henrika@webrtc.org        channel_state_.SetOutputFilePlaying(false);
2049ab12990b1b8c2410b34c055e73ed04e8a7ee1d85braveyao@webrtc.org        CriticalSectionScoped cs(&_fileCritSect);
2050ab12990b1b8c2410b34c055e73ed04e8a7ee1d85braveyao@webrtc.org        _engineStatisticsPtr->SetLastError(
2051ab12990b1b8c2410b34c055e73ed04e8a7ee1d85braveyao@webrtc.org            VE_AUDIO_CONF_MIX_MODULE_ERROR, kTraceError,
2052ab12990b1b8c2410b34c055e73ed04e8a7ee1d85braveyao@webrtc.org            "StartPlayingFile() failed to add participant as file to mixer");
2053ab12990b1b8c2410b34c055e73ed04e8a7ee1d85braveyao@webrtc.org        _outputFilePlayerPtr->StopPlayingFile();
2054ab12990b1b8c2410b34c055e73ed04e8a7ee1d85braveyao@webrtc.org        FilePlayer::DestroyFilePlayer(_outputFilePlayerPtr);
2055ab12990b1b8c2410b34c055e73ed04e8a7ee1d85braveyao@webrtc.org        _outputFilePlayerPtr = NULL;
2056ab12990b1b8c2410b34c055e73ed04e8a7ee1d85braveyao@webrtc.org        return -1;
2057ab12990b1b8c2410b34c055e73ed04e8a7ee1d85braveyao@webrtc.org    }
2058ab12990b1b8c2410b34c055e73ed04e8a7ee1d85braveyao@webrtc.org
2059ab12990b1b8c2410b34c055e73ed04e8a7ee1d85braveyao@webrtc.org    return 0;
2060ab12990b1b8c2410b34c055e73ed04e8a7ee1d85braveyao@webrtc.org}
2061ab12990b1b8c2410b34c055e73ed04e8a7ee1d85braveyao@webrtc.org
2062470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.comint Channel::StartPlayingFileAsMicrophone(const char* fileName,
20639213521ea98b0977c7cdabd2853060835af226f3pbos@webrtc.org                                          bool loop,
20649213521ea98b0977c7cdabd2853060835af226f3pbos@webrtc.org                                          FileFormats format,
20659213521ea98b0977c7cdabd2853060835af226f3pbos@webrtc.org                                          int startPosition,
20669213521ea98b0977c7cdabd2853060835af226f3pbos@webrtc.org                                          float volumeScaling,
20679213521ea98b0977c7cdabd2853060835af226f3pbos@webrtc.org                                          int stopPosition,
2068470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                                          const CodecInst* codecInst)
2069470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com{
2070470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2071470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                 "Channel::StartPlayingFileAsMicrophone(fileNameUTF8[]=%s, "
2072470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                 "loop=%d, format=%d, volumeScaling=%5.3f, startPosition=%d, "
2073470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                 "stopPosition=%d)", fileName, loop, format, volumeScaling,
2074470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                 startPosition, stopPosition);
2075470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
2076944cbeb2926feb86a687e5fda9e2ac88ea8e3001henrika@webrtc.org    CriticalSectionScoped cs(&_fileCritSect);
2077944cbeb2926feb86a687e5fda9e2ac88ea8e3001henrika@webrtc.org
2078944cbeb2926feb86a687e5fda9e2ac88ea8e3001henrika@webrtc.org    if (channel_state_.Get().input_file_playing)
2079470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
2080470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        _engineStatisticsPtr->SetLastError(
2081470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            VE_ALREADY_PLAYING, kTraceWarning,
2082470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            "StartPlayingFileAsMicrophone() filePlayer is playing");
2083470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        return 0;
2084470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
2085470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
2086470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    // Destroy the old instance
2087470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    if (_inputFilePlayerPtr)
2088470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
2089470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        _inputFilePlayerPtr->RegisterModuleFileCallback(NULL);
2090470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        FilePlayer::DestroyFilePlayer(_inputFilePlayerPtr);
2091470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        _inputFilePlayerPtr = NULL;
2092470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
2093470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
2094470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    // Create the instance
2095470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    _inputFilePlayerPtr = FilePlayer::CreateFilePlayer(
2096470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        _inputFilePlayerId, (const FileFormats)format);
2097470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
2098470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    if (_inputFilePlayerPtr == NULL)
2099470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
2100470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        _engineStatisticsPtr->SetLastError(
2101470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            VE_INVALID_ARGUMENT, kTraceError,
2102470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            "StartPlayingFileAsMicrophone() filePlayer format isnot correct");
2103470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        return -1;
2104470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
2105470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
21066141e13873d0fdea626de08dfec2efa2c9171c76pbos@webrtc.org    const uint32_t notificationTime(0);
2107470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
2108470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    if (_inputFilePlayerPtr->StartPlayingFile(
2109470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        fileName,
2110470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        loop,
2111470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        startPosition,
2112470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        volumeScaling,
2113470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        notificationTime,
2114470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        stopPosition,
2115470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        (const CodecInst*)codecInst) != 0)
2116470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
2117470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        _engineStatisticsPtr->SetLastError(
2118470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            VE_BAD_FILE, kTraceError,
2119470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            "StartPlayingFile() failed to start file playout");
2120470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        _inputFilePlayerPtr->StopPlayingFile();
2121470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        FilePlayer::DestroyFilePlayer(_inputFilePlayerPtr);
2122470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        _inputFilePlayerPtr = NULL;
2123470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        return -1;
2124470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
2125470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    _inputFilePlayerPtr->RegisterModuleFileCallback(this);
2126944cbeb2926feb86a687e5fda9e2ac88ea8e3001henrika@webrtc.org    channel_state_.SetInputFilePlaying(true);
2127470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
2128470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    return 0;
2129470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com}
2130470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
2131470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.comint Channel::StartPlayingFileAsMicrophone(InStream* stream,
21329213521ea98b0977c7cdabd2853060835af226f3pbos@webrtc.org                                          FileFormats format,
21339213521ea98b0977c7cdabd2853060835af226f3pbos@webrtc.org                                          int startPosition,
21349213521ea98b0977c7cdabd2853060835af226f3pbos@webrtc.org                                          float volumeScaling,
21359213521ea98b0977c7cdabd2853060835af226f3pbos@webrtc.org                                          int stopPosition,
2136470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                                          const CodecInst* codecInst)
2137470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com{
2138470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2139470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                 "Channel::StartPlayingFileAsMicrophone(format=%d, "
2140470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                 "volumeScaling=%5.3f, startPosition=%d, stopPosition=%d)",
2141470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                 format, volumeScaling, startPosition, stopPosition);
2142470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
2143470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    if(stream == NULL)
2144470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
2145470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        _engineStatisticsPtr->SetLastError(
2146470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            VE_BAD_FILE, kTraceError,
2147470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            "StartPlayingFileAsMicrophone NULL as input stream");
2148470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        return -1;
2149470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
2150470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
2151944cbeb2926feb86a687e5fda9e2ac88ea8e3001henrika@webrtc.org    CriticalSectionScoped cs(&_fileCritSect);
2152944cbeb2926feb86a687e5fda9e2ac88ea8e3001henrika@webrtc.org
2153944cbeb2926feb86a687e5fda9e2ac88ea8e3001henrika@webrtc.org    if (channel_state_.Get().input_file_playing)
2154470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
2155470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        _engineStatisticsPtr->SetLastError(
2156470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            VE_ALREADY_PLAYING, kTraceWarning,
2157470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            "StartPlayingFileAsMicrophone() is playing");
2158470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        return 0;
2159470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
2160470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
2161470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    // Destroy the old instance
2162470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    if (_inputFilePlayerPtr)
2163470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
2164470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        _inputFilePlayerPtr->RegisterModuleFileCallback(NULL);
2165470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        FilePlayer::DestroyFilePlayer(_inputFilePlayerPtr);
2166470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        _inputFilePlayerPtr = NULL;
2167470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
2168470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
2169470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    // Create the instance
2170470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    _inputFilePlayerPtr = FilePlayer::CreateFilePlayer(
2171470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        _inputFilePlayerId, (const FileFormats)format);
2172470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
2173470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    if (_inputFilePlayerPtr == NULL)
2174470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
2175470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        _engineStatisticsPtr->SetLastError(
2176470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            VE_INVALID_ARGUMENT, kTraceError,
2177470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            "StartPlayingInputFile() filePlayer format isnot correct");
2178470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        return -1;
2179470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
2180470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
21816141e13873d0fdea626de08dfec2efa2c9171c76pbos@webrtc.org    const uint32_t notificationTime(0);
2182470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
2183470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    if (_inputFilePlayerPtr->StartPlayingFile(*stream, startPosition,
2184470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                                              volumeScaling, notificationTime,
2185470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                                              stopPosition, codecInst) != 0)
2186470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
2187470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        _engineStatisticsPtr->SetLastError(VE_BAD_FILE, kTraceError,
2188470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                                           "StartPlayingFile() failed to start "
2189470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                                           "file playout");
2190470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        _inputFilePlayerPtr->StopPlayingFile();
2191470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        FilePlayer::DestroyFilePlayer(_inputFilePlayerPtr);
2192470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        _inputFilePlayerPtr = NULL;
2193470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        return -1;
2194470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
2195ae1a58bba4f926d149a5f39243269c3f6625f494andrew@webrtc.org
2196470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    _inputFilePlayerPtr->RegisterModuleFileCallback(this);
2197944cbeb2926feb86a687e5fda9e2ac88ea8e3001henrika@webrtc.org    channel_state_.SetInputFilePlaying(true);
2198470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
2199470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    return 0;
2200470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com}
2201470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
2202470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.comint Channel::StopPlayingFileAsMicrophone()
2203470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com{
2204470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2205470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                 "Channel::StopPlayingFileAsMicrophone()");
2206470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
2207944cbeb2926feb86a687e5fda9e2ac88ea8e3001henrika@webrtc.org    CriticalSectionScoped cs(&_fileCritSect);
2208944cbeb2926feb86a687e5fda9e2ac88ea8e3001henrika@webrtc.org
2209944cbeb2926feb86a687e5fda9e2ac88ea8e3001henrika@webrtc.org    if (!channel_state_.Get().input_file_playing)
2210470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
2211470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        return 0;
2212470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
2213470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
2214470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    if (_inputFilePlayerPtr->StopPlayingFile() != 0)
2215470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
2216470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        _engineStatisticsPtr->SetLastError(
2217470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            VE_STOP_RECORDING_FAILED, kTraceError,
2218470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            "StopPlayingFile() could not stop playing");
2219470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        return -1;
2220470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
2221470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    _inputFilePlayerPtr->RegisterModuleFileCallback(NULL);
2222470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    FilePlayer::DestroyFilePlayer(_inputFilePlayerPtr);
2223470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    _inputFilePlayerPtr = NULL;
2224944cbeb2926feb86a687e5fda9e2ac88ea8e3001henrika@webrtc.org    channel_state_.SetInputFilePlaying(false);
2225470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
2226470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    return 0;
2227470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com}
2228470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
2229470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.comint Channel::IsPlayingFileAsMicrophone() const
2230470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com{
2231944cbeb2926feb86a687e5fda9e2ac88ea8e3001henrika@webrtc.org    return channel_state_.Get().input_file_playing;
2232470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com}
2233470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
2234813e4b0af06272dada388c2d8383b2e36a1da6a6leozwang@webrtc.orgint Channel::StartRecordingPlayout(const char* fileName,
2235470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                                   const CodecInst* codecInst)
2236470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com{
2237470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2238470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                 "Channel::StartRecordingPlayout(fileName=%s)", fileName);
2239470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
2240470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    if (_outputFileRecording)
2241470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
2242470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        WEBRTC_TRACE(kTraceWarning, kTraceVoice, VoEId(_instanceId,-1),
2243470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                     "StartRecordingPlayout() is already recording");
2244470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        return 0;
2245470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
2246470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
2247470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    FileFormats format;
22486141e13873d0fdea626de08dfec2efa2c9171c76pbos@webrtc.org    const uint32_t notificationTime(0); // Not supported in VoE
2249470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    CodecInst dummyCodec={100,"L16",16000,320,1,320000};
2250470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
225140197d7b3b347f05b299a930641dad131c853e01niklas.enbom@webrtc.org    if ((codecInst != NULL) &&
225240197d7b3b347f05b299a930641dad131c853e01niklas.enbom@webrtc.org      ((codecInst->channels < 1) || (codecInst->channels > 2)))
2253470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
2254470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        _engineStatisticsPtr->SetLastError(
2255470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            VE_BAD_ARGUMENT, kTraceError,
2256470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            "StartRecordingPlayout() invalid compression");
2257470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        return(-1);
2258470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
2259470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    if(codecInst == NULL)
2260470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
2261470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        format = kFileFormatPcm16kHzFile;
2262470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        codecInst=&dummyCodec;
2263470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
2264470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    else if((STR_CASE_CMP(codecInst->plname,"L16") == 0) ||
2265470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        (STR_CASE_CMP(codecInst->plname,"PCMU") == 0) ||
2266470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        (STR_CASE_CMP(codecInst->plname,"PCMA") == 0))
2267470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
2268470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        format = kFileFormatWavFile;
2269470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
2270470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    else
2271470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
2272470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        format = kFileFormatCompressedFile;
2273470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
2274470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
22759a065d1eae9ed296e1e2eaaad73d7ca1223bfe79mflodman@webrtc.org    CriticalSectionScoped cs(&_fileCritSect);
2276470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
2277470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    // Destroy the old instance
2278470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    if (_outputFileRecorderPtr)
2279470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
2280470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        _outputFileRecorderPtr->RegisterModuleFileCallback(NULL);
2281470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        FileRecorder::DestroyFileRecorder(_outputFileRecorderPtr);
2282470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        _outputFileRecorderPtr = NULL;
2283470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
2284470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
2285470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    _outputFileRecorderPtr = FileRecorder::CreateFileRecorder(
2286470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        _outputFileRecorderId, (const FileFormats)format);
2287470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    if (_outputFileRecorderPtr == NULL)
2288470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
2289470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        _engineStatisticsPtr->SetLastError(
2290470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            VE_INVALID_ARGUMENT, kTraceError,
2291470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            "StartRecordingPlayout() fileRecorder format isnot correct");
2292470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        return -1;
2293470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
2294470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
2295470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    if (_outputFileRecorderPtr->StartRecordingAudioFile(
2296470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        fileName, (const CodecInst&)*codecInst, notificationTime) != 0)
2297470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
2298470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        _engineStatisticsPtr->SetLastError(
2299470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            VE_BAD_FILE, kTraceError,
2300470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            "StartRecordingAudioFile() failed to start file recording");
2301470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        _outputFileRecorderPtr->StopRecording();
2302470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        FileRecorder::DestroyFileRecorder(_outputFileRecorderPtr);
2303470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        _outputFileRecorderPtr = NULL;
2304470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        return -1;
2305470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
2306470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    _outputFileRecorderPtr->RegisterModuleFileCallback(this);
2307470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    _outputFileRecording = true;
2308470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
2309470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    return 0;
2310470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com}
2311470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
2312470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.comint Channel::StartRecordingPlayout(OutStream* stream,
2313470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                                   const CodecInst* codecInst)
2314470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com{
2315470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2316470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                 "Channel::StartRecordingPlayout()");
2317470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
2318470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    if (_outputFileRecording)
2319470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
2320470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        WEBRTC_TRACE(kTraceWarning, kTraceVoice, VoEId(_instanceId,-1),
2321470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                     "StartRecordingPlayout() is already recording");
2322470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        return 0;
2323470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
2324470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
2325470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    FileFormats format;
23266141e13873d0fdea626de08dfec2efa2c9171c76pbos@webrtc.org    const uint32_t notificationTime(0); // Not supported in VoE
2327470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    CodecInst dummyCodec={100,"L16",16000,320,1,320000};
2328470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
2329470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    if (codecInst != NULL && codecInst->channels != 1)
2330470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
2331470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        _engineStatisticsPtr->SetLastError(
2332470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            VE_BAD_ARGUMENT, kTraceError,
2333470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            "StartRecordingPlayout() invalid compression");
2334470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        return(-1);
2335470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
2336470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    if(codecInst == NULL)
2337470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
2338470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        format = kFileFormatPcm16kHzFile;
2339470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        codecInst=&dummyCodec;
2340470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
2341470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    else if((STR_CASE_CMP(codecInst->plname,"L16") == 0) ||
2342470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        (STR_CASE_CMP(codecInst->plname,"PCMU") == 0) ||
2343470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        (STR_CASE_CMP(codecInst->plname,"PCMA") == 0))
2344470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
2345470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        format = kFileFormatWavFile;
2346470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
2347470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    else
2348470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
2349470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        format = kFileFormatCompressedFile;
2350470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
2351470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
23529a065d1eae9ed296e1e2eaaad73d7ca1223bfe79mflodman@webrtc.org    CriticalSectionScoped cs(&_fileCritSect);
2353470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
2354470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    // Destroy the old instance
2355470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    if (_outputFileRecorderPtr)
2356470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
2357470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        _outputFileRecorderPtr->RegisterModuleFileCallback(NULL);
2358470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        FileRecorder::DestroyFileRecorder(_outputFileRecorderPtr);
2359470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        _outputFileRecorderPtr = NULL;
2360470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
2361470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
2362470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    _outputFileRecorderPtr = FileRecorder::CreateFileRecorder(
2363470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        _outputFileRecorderId, (const FileFormats)format);
2364470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    if (_outputFileRecorderPtr == NULL)
2365470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
2366470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        _engineStatisticsPtr->SetLastError(
2367470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            VE_INVALID_ARGUMENT, kTraceError,
2368470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            "StartRecordingPlayout() fileRecorder format isnot correct");
2369470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        return -1;
2370470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
2371470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
2372470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    if (_outputFileRecorderPtr->StartRecordingAudioFile(*stream, *codecInst,
2373470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                                                        notificationTime) != 0)
2374470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
2375470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        _engineStatisticsPtr->SetLastError(VE_BAD_FILE, kTraceError,
2376470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                                           "StartRecordingPlayout() failed to "
2377470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                                           "start file recording");
2378470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        _outputFileRecorderPtr->StopRecording();
2379470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        FileRecorder::DestroyFileRecorder(_outputFileRecorderPtr);
2380470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        _outputFileRecorderPtr = NULL;
2381470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        return -1;
2382470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
2383ae1a58bba4f926d149a5f39243269c3f6625f494andrew@webrtc.org
2384470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    _outputFileRecorderPtr->RegisterModuleFileCallback(this);
2385470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    _outputFileRecording = true;
2386470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
2387470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    return 0;
2388470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com}
2389470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
2390470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.comint Channel::StopRecordingPlayout()
2391470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com{
2392470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,-1),
2393470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                 "Channel::StopRecordingPlayout()");
2394470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
2395470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    if (!_outputFileRecording)
2396470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
2397470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        WEBRTC_TRACE(kTraceError, kTraceVoice, VoEId(_instanceId,-1),
2398470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                     "StopRecordingPlayout() isnot recording");
2399470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        return -1;
2400470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
2401470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
2402470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
24039a065d1eae9ed296e1e2eaaad73d7ca1223bfe79mflodman@webrtc.org    CriticalSectionScoped cs(&_fileCritSect);
2404470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
2405470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    if (_outputFileRecorderPtr->StopRecording() != 0)
2406470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
2407470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        _engineStatisticsPtr->SetLastError(
2408470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            VE_STOP_RECORDING_FAILED, kTraceError,
2409470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            "StopRecording() could not stop recording");
2410470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        return(-1);
2411470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
2412470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    _outputFileRecorderPtr->RegisterModuleFileCallback(NULL);
2413470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    FileRecorder::DestroyFileRecorder(_outputFileRecorderPtr);
2414470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    _outputFileRecorderPtr = NULL;
2415470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    _outputFileRecording = false;
2416470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
2417470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    return 0;
2418470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com}
2419470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
2420470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.comvoid
2421470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.comChannel::SetMixWithMicStatus(bool mix)
2422470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com{
2423944cbeb2926feb86a687e5fda9e2ac88ea8e3001henrika@webrtc.org    CriticalSectionScoped cs(&_fileCritSect);
2424470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    _mixFileWithMicrophone=mix;
2425470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com}
2426470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
2427470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.comint
24286141e13873d0fdea626de08dfec2efa2c9171c76pbos@webrtc.orgChannel::GetSpeechOutputLevel(uint32_t& level) const
2429470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com{
24306141e13873d0fdea626de08dfec2efa2c9171c76pbos@webrtc.org    int8_t currentLevel = _outputAudioLevel.Level();
24316141e13873d0fdea626de08dfec2efa2c9171c76pbos@webrtc.org    level = static_cast<int32_t> (currentLevel);
2432470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    return 0;
2433470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com}
2434470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
2435470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.comint
24366141e13873d0fdea626de08dfec2efa2c9171c76pbos@webrtc.orgChannel::GetSpeechOutputLevelFullRange(uint32_t& level) const
2437470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com{
24386141e13873d0fdea626de08dfec2efa2c9171c76pbos@webrtc.org    int16_t currentLevel = _outputAudioLevel.LevelFullRange();
24396141e13873d0fdea626de08dfec2efa2c9171c76pbos@webrtc.org    level = static_cast<int32_t> (currentLevel);
2440470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    return 0;
2441470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com}
2442470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
2443470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.comint
2444470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.comChannel::SetMute(bool enable)
2445470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com{
244663420669746cfca6ed1d902c68c656b79ffa5a1bwu@webrtc.org    CriticalSectionScoped cs(&volume_settings_critsect_);
2447470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2448470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com               "Channel::SetMute(enable=%d)", enable);
2449470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    _mute = enable;
2450470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    return 0;
2451470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com}
2452470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
2453470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.combool
2454470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.comChannel::Mute() const
2455470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com{
245663420669746cfca6ed1d902c68c656b79ffa5a1bwu@webrtc.org    CriticalSectionScoped cs(&volume_settings_critsect_);
2457470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    return _mute;
2458470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com}
2459470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
2460470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.comint
2461470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.comChannel::SetOutputVolumePan(float left, float right)
2462470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com{
246363420669746cfca6ed1d902c68c656b79ffa5a1bwu@webrtc.org    CriticalSectionScoped cs(&volume_settings_critsect_);
2464470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2465470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com               "Channel::SetOutputVolumePan()");
2466470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    _panLeft = left;
2467470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    _panRight = right;
2468470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    return 0;
2469470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com}
2470470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
2471470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.comint
2472470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.comChannel::GetOutputVolumePan(float& left, float& right) const
2473470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com{
247463420669746cfca6ed1d902c68c656b79ffa5a1bwu@webrtc.org    CriticalSectionScoped cs(&volume_settings_critsect_);
2475470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    left = _panLeft;
2476470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    right = _panRight;
2477470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    return 0;
2478470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com}
2479470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
2480470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.comint
2481470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.comChannel::SetChannelOutputVolumeScaling(float scaling)
2482470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com{
248363420669746cfca6ed1d902c68c656b79ffa5a1bwu@webrtc.org    CriticalSectionScoped cs(&volume_settings_critsect_);
2484470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2485470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com               "Channel::SetChannelOutputVolumeScaling()");
2486470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    _outputGain = scaling;
2487470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    return 0;
2488470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com}
2489470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
2490470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.comint
2491470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.comChannel::GetChannelOutputVolumeScaling(float& scaling) const
2492470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com{
249363420669746cfca6ed1d902c68c656b79ffa5a1bwu@webrtc.org    CriticalSectionScoped cs(&volume_settings_critsect_);
2494470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    scaling = _outputGain;
2495470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    return 0;
2496470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com}
2497470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
2498470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.comint Channel::SendTelephoneEventOutband(unsigned char eventCode,
2499822fbd8b68ffdb481b9557e2950ae8d6657c8ce6wu@webrtc.org                                       int lengthMs, int attenuationDb,
2500822fbd8b68ffdb481b9557e2950ae8d6657c8ce6wu@webrtc.org                                       bool playDtmfEvent)
2501470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com{
2502470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
2503470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com               "Channel::SendTelephoneEventOutband(..., playDtmfEvent=%d)",
2504470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com               playDtmfEvent);
2505b572768efbc1e52b97a5ad98932c667956aba4b8Fredrik Solenberg    if (!Sending()) {
2506b572768efbc1e52b97a5ad98932c667956aba4b8Fredrik Solenberg      return -1;
2507b572768efbc1e52b97a5ad98932c667956aba4b8Fredrik Solenberg    }
2508470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
2509470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    _playOutbandDtmfEvent = playDtmfEvent;
2510470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
25112853dde5201d9ddc284ce5efb9688f6340487acepwestin@webrtc.org    if (_rtpRtcpModule->SendTelephoneEventOutband(eventCode, lengthMs,
2512470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                                                 attenuationDb) != 0)
2513470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
2514470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        _engineStatisticsPtr->SetLastError(
2515470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            VE_SEND_DTMF_FAILED,
2516470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            kTraceWarning,
2517470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            "SendTelephoneEventOutband() failed to send event");
2518470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        return -1;
2519470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
2520470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    return 0;
2521470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com}
2522470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
2523470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.comint Channel::SendTelephoneEventInband(unsigned char eventCode,
2524470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                                         int lengthMs,
2525470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                                         int attenuationDb,
2526470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                                         bool playDtmfEvent)
2527470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com{
2528470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
2529470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com               "Channel::SendTelephoneEventInband(..., playDtmfEvent=%d)",
2530470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com               playDtmfEvent);
2531470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
2532470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    _playInbandDtmfEvent = playDtmfEvent;
2533470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    _inbandDtmfQueue.AddDtmf(eventCode, lengthMs, attenuationDb);
2534470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
2535470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    return 0;
2536470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com}
2537470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
2538470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.comint
2539470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.comChannel::SetSendTelephoneEventPayloadType(unsigned char type)
2540470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com{
2541470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2542470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com               "Channel::SetSendTelephoneEventPayloadType()");
2543f81f9f8c2a18fb20ee60406ece45ff3210367ff9andrew@webrtc.org    if (type > 127)
2544470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
2545470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        _engineStatisticsPtr->SetLastError(
2546470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            VE_INVALID_ARGUMENT, kTraceError,
2547470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            "SetSendTelephoneEventPayloadType() invalid type");
2548470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        return -1;
2549470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
25505b10d8fb184db0192091bf407c8166b5d03b932epbos@webrtc.org    CodecInst codec = {};
25511da1ce0da5fcc029dbc2a134a9760e1b398b02d7pwestin@webrtc.org    codec.plfreq = 8000;
25521da1ce0da5fcc029dbc2a134a9760e1b398b02d7pwestin@webrtc.org    codec.pltype = type;
25531da1ce0da5fcc029dbc2a134a9760e1b398b02d7pwestin@webrtc.org    memcpy(codec.plname, "telephone-event", 16);
25542853dde5201d9ddc284ce5efb9688f6340487acepwestin@webrtc.org    if (_rtpRtcpModule->RegisterSendPayload(codec) != 0)
2555470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
25564392d5f9f859b5d55b8017fafb09a496a110beb3henrika@webrtc.org        _rtpRtcpModule->DeRegisterSendPayload(codec.pltype);
25574392d5f9f859b5d55b8017fafb09a496a110beb3henrika@webrtc.org        if (_rtpRtcpModule->RegisterSendPayload(codec) != 0) {
25584392d5f9f859b5d55b8017fafb09a496a110beb3henrika@webrtc.org            _engineStatisticsPtr->SetLastError(
25594392d5f9f859b5d55b8017fafb09a496a110beb3henrika@webrtc.org                VE_RTP_RTCP_MODULE_ERROR, kTraceError,
25604392d5f9f859b5d55b8017fafb09a496a110beb3henrika@webrtc.org                "SetSendTelephoneEventPayloadType() failed to register send"
25614392d5f9f859b5d55b8017fafb09a496a110beb3henrika@webrtc.org                "payload type");
25624392d5f9f859b5d55b8017fafb09a496a110beb3henrika@webrtc.org            return -1;
25634392d5f9f859b5d55b8017fafb09a496a110beb3henrika@webrtc.org        }
2564470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
2565470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    _sendTelephoneEventPayloadType = type;
2566470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    return 0;
2567470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com}
2568470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
2569470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.comint
2570470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.comChannel::GetSendTelephoneEventPayloadType(unsigned char& type)
2571470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com{
2572470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    type = _sendTelephoneEventPayloadType;
2573470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    return 0;
2574470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com}
2575470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
2576470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.comint
2577470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.comChannel::UpdateRxVadDetection(AudioFrame& audioFrame)
2578470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com{
2579470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
2580470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                 "Channel::UpdateRxVadDetection()");
2581470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
2582470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    int vadDecision = 1;
2583470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
258463a509858d3988299726640c664b699d6229a1d4andrew@webrtc.org    vadDecision = (audioFrame.vad_activity_ == AudioFrame::kVadActive)? 1 : 0;
2585470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
2586470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    if ((vadDecision != _oldVadDecision) && _rxVadObserverPtr)
2587470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
2588470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        OnRxVadDetected(vadDecision);
2589470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        _oldVadDecision = vadDecision;
2590470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
2591470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
2592470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
2593470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                 "Channel::UpdateRxVadDetection() => vadDecision=%d",
2594470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                 vadDecision);
2595470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    return 0;
2596470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com}
2597470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
2598470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.comint
2599470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.comChannel::RegisterRxVadObserver(VoERxVadCallback &observer)
2600470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com{
2601470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2602470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                 "Channel::RegisterRxVadObserver()");
26039a065d1eae9ed296e1e2eaaad73d7ca1223bfe79mflodman@webrtc.org    CriticalSectionScoped cs(&_callbackCritSect);
2604470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
2605470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    if (_rxVadObserverPtr)
2606470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
2607470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        _engineStatisticsPtr->SetLastError(
2608470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            VE_INVALID_OPERATION, kTraceError,
2609470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            "RegisterRxVadObserver() observer already enabled");
2610470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        return -1;
2611470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
2612470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    _rxVadObserverPtr = &observer;
2613470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    _RxVadDetection = true;
2614470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    return 0;
2615470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com}
2616470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
2617470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.comint
2618470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.comChannel::DeRegisterRxVadObserver()
2619470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com{
2620470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2621470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                 "Channel::DeRegisterRxVadObserver()");
26229a065d1eae9ed296e1e2eaaad73d7ca1223bfe79mflodman@webrtc.org    CriticalSectionScoped cs(&_callbackCritSect);
2623470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
2624470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    if (!_rxVadObserverPtr)
2625470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
2626470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        _engineStatisticsPtr->SetLastError(
2627470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            VE_INVALID_OPERATION, kTraceWarning,
2628470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            "DeRegisterRxVadObserver() observer already disabled");
2629470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        return 0;
2630470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
2631470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    _rxVadObserverPtr = NULL;
2632470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    _RxVadDetection = false;
2633470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    return 0;
2634470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com}
2635470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
2636470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.comint
2637470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.comChannel::VoiceActivityIndicator(int &activity)
2638470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com{
2639470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    activity = _sendFrameType;
2640470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    return 0;
2641470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com}
2642470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
2643470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com#ifdef WEBRTC_VOICE_ENGINE_AGC
2644470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
2645470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.comint
26469213521ea98b0977c7cdabd2853060835af226f3pbos@webrtc.orgChannel::SetRxAgcStatus(bool enable, AgcModes mode)
2647470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com{
2648470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2649470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                 "Channel::SetRxAgcStatus(enable=%d, mode=%d)",
2650470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                 (int)enable, (int)mode);
2651470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
26526c264cc92eb554716814db200b84752d4dfb6ba3andrew@webrtc.org    GainControl::Mode agcMode = kDefaultRxAgcMode;
2653470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    switch (mode)
2654470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
2655470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        case kAgcDefault:
2656470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            break;
2657470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        case kAgcUnchanged:
2658f3930e941c15da48c037c62cdb1eebbcbf89c9c7andrew@webrtc.org            agcMode = rx_audioproc_->gain_control()->mode();
2659470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            break;
2660470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        case kAgcFixedDigital:
2661470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            agcMode = GainControl::kFixedDigital;
2662470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            break;
2663470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        case kAgcAdaptiveDigital:
2664470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            agcMode =GainControl::kAdaptiveDigital;
2665470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            break;
2666470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        default:
2667470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            _engineStatisticsPtr->SetLastError(
2668470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                VE_INVALID_ARGUMENT, kTraceError,
2669470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                "SetRxAgcStatus() invalid Agc mode");
2670470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            return -1;
2671470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
2672470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
2673f3930e941c15da48c037c62cdb1eebbcbf89c9c7andrew@webrtc.org    if (rx_audioproc_->gain_control()->set_mode(agcMode) != 0)
2674470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
2675470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        _engineStatisticsPtr->SetLastError(
2676470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            VE_APM_ERROR, kTraceError,
2677470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            "SetRxAgcStatus() failed to set Agc mode");
2678470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        return -1;
2679470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
2680f3930e941c15da48c037c62cdb1eebbcbf89c9c7andrew@webrtc.org    if (rx_audioproc_->gain_control()->Enable(enable) != 0)
2681470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
2682470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        _engineStatisticsPtr->SetLastError(
2683470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            VE_APM_ERROR, kTraceError,
2684470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            "SetRxAgcStatus() failed to set Agc state");
2685470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        return -1;
2686470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
2687470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
2688470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    _rxAgcIsEnabled = enable;
2689944cbeb2926feb86a687e5fda9e2ac88ea8e3001henrika@webrtc.org    channel_state_.SetRxApmIsEnabled(_rxAgcIsEnabled || _rxNsIsEnabled);
2690470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
2691470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    return 0;
2692470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com}
2693470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
2694470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.comint
2695470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.comChannel::GetRxAgcStatus(bool& enabled, AgcModes& mode)
2696470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com{
2697f3930e941c15da48c037c62cdb1eebbcbf89c9c7andrew@webrtc.org    bool enable = rx_audioproc_->gain_control()->is_enabled();
2698470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    GainControl::Mode agcMode =
2699f3930e941c15da48c037c62cdb1eebbcbf89c9c7andrew@webrtc.org        rx_audioproc_->gain_control()->mode();
2700470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
2701470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    enabled = enable;
2702470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
2703470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    switch (agcMode)
2704470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
2705470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        case GainControl::kFixedDigital:
2706470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            mode = kAgcFixedDigital;
2707470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            break;
2708470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        case GainControl::kAdaptiveDigital:
2709470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            mode = kAgcAdaptiveDigital;
2710470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            break;
2711470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        default:
2712470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            _engineStatisticsPtr->SetLastError(
2713470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                VE_APM_ERROR, kTraceError,
2714470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                "GetRxAgcStatus() invalid Agc mode");
2715470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            return -1;
2716470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
2717470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
2718470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    return 0;
2719470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com}
2720470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
2721470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.comint
27229213521ea98b0977c7cdabd2853060835af226f3pbos@webrtc.orgChannel::SetRxAgcConfig(AgcConfig config)
2723470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com{
2724470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2725470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                 "Channel::SetRxAgcConfig()");
2726470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
2727f3930e941c15da48c037c62cdb1eebbcbf89c9c7andrew@webrtc.org    if (rx_audioproc_->gain_control()->set_target_level_dbfs(
2728470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        config.targetLeveldBOv) != 0)
2729470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
2730470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        _engineStatisticsPtr->SetLastError(
2731470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            VE_APM_ERROR, kTraceError,
2732470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            "SetRxAgcConfig() failed to set target peak |level|"
2733470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            "(or envelope) of the Agc");
2734470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        return -1;
2735470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
2736f3930e941c15da48c037c62cdb1eebbcbf89c9c7andrew@webrtc.org    if (rx_audioproc_->gain_control()->set_compression_gain_db(
2737470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        config.digitalCompressionGaindB) != 0)
2738470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
2739470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        _engineStatisticsPtr->SetLastError(
2740470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            VE_APM_ERROR, kTraceError,
2741470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            "SetRxAgcConfig() failed to set the range in |gain| the"
2742470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            " digital compression stage may apply");
2743470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        return -1;
2744470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
2745f3930e941c15da48c037c62cdb1eebbcbf89c9c7andrew@webrtc.org    if (rx_audioproc_->gain_control()->enable_limiter(
2746470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        config.limiterEnable) != 0)
2747470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
2748470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        _engineStatisticsPtr->SetLastError(
2749470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            VE_APM_ERROR, kTraceError,
2750470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            "SetRxAgcConfig() failed to set hard limiter to the signal");
2751470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        return -1;
2752470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
2753470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
2754470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    return 0;
2755470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com}
2756470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
2757470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.comint
2758470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.comChannel::GetRxAgcConfig(AgcConfig& config)
2759470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com{
2760470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    config.targetLeveldBOv =
2761f3930e941c15da48c037c62cdb1eebbcbf89c9c7andrew@webrtc.org        rx_audioproc_->gain_control()->target_level_dbfs();
2762470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    config.digitalCompressionGaindB =
2763f3930e941c15da48c037c62cdb1eebbcbf89c9c7andrew@webrtc.org        rx_audioproc_->gain_control()->compression_gain_db();
2764470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    config.limiterEnable =
2765f3930e941c15da48c037c62cdb1eebbcbf89c9c7andrew@webrtc.org        rx_audioproc_->gain_control()->is_limiter_enabled();
2766470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
2767470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    return 0;
2768470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com}
2769470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
2770470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com#endif // #ifdef WEBRTC_VOICE_ENGINE_AGC
2771470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
2772470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com#ifdef WEBRTC_VOICE_ENGINE_NR
2773470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
2774470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.comint
27759213521ea98b0977c7cdabd2853060835af226f3pbos@webrtc.orgChannel::SetRxNsStatus(bool enable, NsModes mode)
2776470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com{
2777470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2778470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                 "Channel::SetRxNsStatus(enable=%d, mode=%d)",
2779470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                 (int)enable, (int)mode);
2780470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
27816c264cc92eb554716814db200b84752d4dfb6ba3andrew@webrtc.org    NoiseSuppression::Level nsLevel = kDefaultNsMode;
2782470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    switch (mode)
2783470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
2784470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
2785470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        case kNsDefault:
2786470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            break;
2787470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        case kNsUnchanged:
2788f3930e941c15da48c037c62cdb1eebbcbf89c9c7andrew@webrtc.org            nsLevel = rx_audioproc_->noise_suppression()->level();
2789470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            break;
2790470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        case kNsConference:
2791470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            nsLevel = NoiseSuppression::kHigh;
2792470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            break;
2793470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        case kNsLowSuppression:
2794470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            nsLevel = NoiseSuppression::kLow;
2795470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            break;
2796470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        case kNsModerateSuppression:
2797470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            nsLevel = NoiseSuppression::kModerate;
2798470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            break;
2799470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        case kNsHighSuppression:
2800470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            nsLevel = NoiseSuppression::kHigh;
2801470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            break;
2802470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        case kNsVeryHighSuppression:
2803470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            nsLevel = NoiseSuppression::kVeryHigh;
2804470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            break;
2805470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
2806470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
2807f3930e941c15da48c037c62cdb1eebbcbf89c9c7andrew@webrtc.org    if (rx_audioproc_->noise_suppression()->set_level(nsLevel)
2808470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        != 0)
2809470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
2810470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        _engineStatisticsPtr->SetLastError(
2811470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            VE_APM_ERROR, kTraceError,
28126c264cc92eb554716814db200b84752d4dfb6ba3andrew@webrtc.org            "SetRxNsStatus() failed to set NS level");
2813470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        return -1;
2814470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
2815f3930e941c15da48c037c62cdb1eebbcbf89c9c7andrew@webrtc.org    if (rx_audioproc_->noise_suppression()->Enable(enable) != 0)
2816470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
2817470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        _engineStatisticsPtr->SetLastError(
2818470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            VE_APM_ERROR, kTraceError,
28196c264cc92eb554716814db200b84752d4dfb6ba3andrew@webrtc.org            "SetRxNsStatus() failed to set NS state");
2820470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        return -1;
2821470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
2822470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
2823470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    _rxNsIsEnabled = enable;
2824944cbeb2926feb86a687e5fda9e2ac88ea8e3001henrika@webrtc.org    channel_state_.SetRxApmIsEnabled(_rxAgcIsEnabled || _rxNsIsEnabled);
2825470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
2826470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    return 0;
2827470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com}
2828470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
2829470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.comint
2830470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.comChannel::GetRxNsStatus(bool& enabled, NsModes& mode)
2831470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com{
2832470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    bool enable =
2833f3930e941c15da48c037c62cdb1eebbcbf89c9c7andrew@webrtc.org        rx_audioproc_->noise_suppression()->is_enabled();
2834470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    NoiseSuppression::Level ncLevel =
2835f3930e941c15da48c037c62cdb1eebbcbf89c9c7andrew@webrtc.org        rx_audioproc_->noise_suppression()->level();
2836470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
2837470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    enabled = enable;
2838470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
2839470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    switch (ncLevel)
2840470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
2841470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        case NoiseSuppression::kLow:
2842470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            mode = kNsLowSuppression;
2843470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            break;
2844470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        case NoiseSuppression::kModerate:
2845470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            mode = kNsModerateSuppression;
2846470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            break;
2847470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        case NoiseSuppression::kHigh:
2848470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            mode = kNsHighSuppression;
2849470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            break;
2850470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        case NoiseSuppression::kVeryHigh:
2851470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            mode = kNsVeryHighSuppression;
2852470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            break;
2853470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
2854470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
2855470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    return 0;
2856470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com}
2857470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
2858470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com#endif // #ifdef WEBRTC_VOICE_ENGINE_NR
2859470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
2860470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.comint
2861470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.comChannel::SetLocalSSRC(unsigned int ssrc)
2862470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com{
2863470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
2864470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                 "Channel::SetLocalSSRC()");
2865944cbeb2926feb86a687e5fda9e2ac88ea8e3001henrika@webrtc.org    if (channel_state_.Get().sending)
2866470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
2867470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        _engineStatisticsPtr->SetLastError(
2868470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            VE_ALREADY_SENDING, kTraceError,
2869470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            "SetLocalSSRC() already sending");
2870470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        return -1;
2871470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
2872ef92755780253c6a7940c89598a206e58e05b810stefan@webrtc.org    _rtpRtcpModule->SetSSRC(ssrc);
2873470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    return 0;
2874470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com}
2875470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
2876470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.comint
2877470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.comChannel::GetLocalSSRC(unsigned int& ssrc)
2878470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com{
28792853dde5201d9ddc284ce5efb9688f6340487acepwestin@webrtc.org    ssrc = _rtpRtcpModule->SSRC();
2880470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    return 0;
2881470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com}
2882470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
2883470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.comint
2884470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.comChannel::GetRemoteSSRC(unsigned int& ssrc)
2885470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com{
2886822fbd8b68ffdb481b9557e2950ae8d6657c8ce6wu@webrtc.org    ssrc = rtp_receiver_->SSRC();
2887470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    return 0;
2888470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com}
2889470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
2890ebdb0e3ad0a787bee066d12cdcd115a38b0a10d1wu@webrtc.orgint Channel::SetSendAudioLevelIndicationStatus(bool enable, unsigned char id) {
2891f3930e941c15da48c037c62cdb1eebbcbf89c9c7andrew@webrtc.org  _includeAudioLevelIndication = enable;
2892ebdb0e3ad0a787bee066d12cdcd115a38b0a10d1wu@webrtc.org  return SetSendRtpHeaderExtension(enable, kRtpExtensionAudioLevel, id);
2893470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com}
2894f3930e941c15da48c037c62cdb1eebbcbf89c9c7andrew@webrtc.org
289593fd25c20c688961569d3631b875c8ee0dfc2a80wu@webrtc.orgint Channel::SetReceiveAudioLevelIndicationStatus(bool enable,
289693fd25c20c688961569d3631b875c8ee0dfc2a80wu@webrtc.org                                                  unsigned char id) {
289793fd25c20c688961569d3631b875c8ee0dfc2a80wu@webrtc.org  rtp_header_parser_->DeregisterRtpHeaderExtension(
289893fd25c20c688961569d3631b875c8ee0dfc2a80wu@webrtc.org      kRtpExtensionAudioLevel);
289993fd25c20c688961569d3631b875c8ee0dfc2a80wu@webrtc.org  if (enable && !rtp_header_parser_->RegisterRtpHeaderExtension(
290093fd25c20c688961569d3631b875c8ee0dfc2a80wu@webrtc.org          kRtpExtensionAudioLevel, id)) {
290193fd25c20c688961569d3631b875c8ee0dfc2a80wu@webrtc.org    return -1;
290293fd25c20c688961569d3631b875c8ee0dfc2a80wu@webrtc.org  }
290393fd25c20c688961569d3631b875c8ee0dfc2a80wu@webrtc.org  return 0;
290493fd25c20c688961569d3631b875c8ee0dfc2a80wu@webrtc.org}
290593fd25c20c688961569d3631b875c8ee0dfc2a80wu@webrtc.org
2906ebdb0e3ad0a787bee066d12cdcd115a38b0a10d1wu@webrtc.orgint Channel::SetSendAbsoluteSenderTimeStatus(bool enable, unsigned char id) {
2907ebdb0e3ad0a787bee066d12cdcd115a38b0a10d1wu@webrtc.org  return SetSendRtpHeaderExtension(enable, kRtpExtensionAbsoluteSendTime, id);
2908ebdb0e3ad0a787bee066d12cdcd115a38b0a10d1wu@webrtc.org}
2909ebdb0e3ad0a787bee066d12cdcd115a38b0a10d1wu@webrtc.org
2910ebdb0e3ad0a787bee066d12cdcd115a38b0a10d1wu@webrtc.orgint Channel::SetReceiveAbsoluteSenderTimeStatus(bool enable, unsigned char id) {
2911ebdb0e3ad0a787bee066d12cdcd115a38b0a10d1wu@webrtc.org  rtp_header_parser_->DeregisterRtpHeaderExtension(
2912ebdb0e3ad0a787bee066d12cdcd115a38b0a10d1wu@webrtc.org      kRtpExtensionAbsoluteSendTime);
2913b1f50100757036cf475072c26f5f374eee9588casolenberg@webrtc.org  if (enable && !rtp_header_parser_->RegisterRtpHeaderExtension(
2914b1f50100757036cf475072c26f5f374eee9588casolenberg@webrtc.org      kRtpExtensionAbsoluteSendTime, id)) {
2915b1f50100757036cf475072c26f5f374eee9588casolenberg@webrtc.org    return -1;
2916ebdb0e3ad0a787bee066d12cdcd115a38b0a10d1wu@webrtc.org  }
2917ebdb0e3ad0a787bee066d12cdcd115a38b0a10d1wu@webrtc.org  return 0;
2918470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com}
2919470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
2920b86d4e4a8dec1eb1b801244a2a97cda66f561d8eStefan Holmervoid Channel::EnableSendTransportSequenceNumber(int id) {
2921b86d4e4a8dec1eb1b801244a2a97cda66f561d8eStefan Holmer  int ret =
2922b86d4e4a8dec1eb1b801244a2a97cda66f561d8eStefan Holmer      SetSendRtpHeaderExtension(true, kRtpExtensionTransportSequenceNumber, id);
2923b86d4e4a8dec1eb1b801244a2a97cda66f561d8eStefan Holmer  RTC_DCHECK_EQ(0, ret);
2924b86d4e4a8dec1eb1b801244a2a97cda66f561d8eStefan Holmer}
2925b86d4e4a8dec1eb1b801244a2a97cda66f561d8eStefan Holmer
2926b86d4e4a8dec1eb1b801244a2a97cda66f561d8eStefan Holmervoid Channel::SetCongestionControlObjects(
2927b86d4e4a8dec1eb1b801244a2a97cda66f561d8eStefan Holmer    RtpPacketSender* rtp_packet_sender,
2928b86d4e4a8dec1eb1b801244a2a97cda66f561d8eStefan Holmer    TransportFeedbackObserver* transport_feedback_observer,
2929b86d4e4a8dec1eb1b801244a2a97cda66f561d8eStefan Holmer    PacketRouter* packet_router) {
2930b86d4e4a8dec1eb1b801244a2a97cda66f561d8eStefan Holmer  RTC_DCHECK(packet_router != nullptr || packet_router_ != nullptr);
29313842c5c7f73639527e653f41c65334245d2317a1Stefan Holmer  if (transport_feedback_observer) {
29323842c5c7f73639527e653f41c65334245d2317a1Stefan Holmer    RTC_DCHECK(feedback_observer_proxy_.get());
29333842c5c7f73639527e653f41c65334245d2317a1Stefan Holmer    feedback_observer_proxy_->SetTransportFeedbackObserver(
29343842c5c7f73639527e653f41c65334245d2317a1Stefan Holmer        transport_feedback_observer);
29353842c5c7f73639527e653f41c65334245d2317a1Stefan Holmer  }
29363842c5c7f73639527e653f41c65334245d2317a1Stefan Holmer  if (rtp_packet_sender) {
29373842c5c7f73639527e653f41c65334245d2317a1Stefan Holmer    RTC_DCHECK(rtp_packet_sender_proxy_.get());
29383842c5c7f73639527e653f41c65334245d2317a1Stefan Holmer    rtp_packet_sender_proxy_->SetPacketSender(rtp_packet_sender);
29393842c5c7f73639527e653f41c65334245d2317a1Stefan Holmer  }
29403842c5c7f73639527e653f41c65334245d2317a1Stefan Holmer  if (seq_num_allocator_proxy_.get()) {
29413842c5c7f73639527e653f41c65334245d2317a1Stefan Holmer    seq_num_allocator_proxy_->SetSequenceNumberAllocator(packet_router);
29423842c5c7f73639527e653f41c65334245d2317a1Stefan Holmer  }
2943b86d4e4a8dec1eb1b801244a2a97cda66f561d8eStefan Holmer  _rtpRtcpModule->SetStorePacketsStatus(rtp_packet_sender != nullptr, 600);
2944b86d4e4a8dec1eb1b801244a2a97cda66f561d8eStefan Holmer  if (packet_router != nullptr) {
2945b86d4e4a8dec1eb1b801244a2a97cda66f561d8eStefan Holmer    packet_router->AddRtpModule(_rtpRtcpModule.get());
2946b86d4e4a8dec1eb1b801244a2a97cda66f561d8eStefan Holmer  } else {
2947b86d4e4a8dec1eb1b801244a2a97cda66f561d8eStefan Holmer    packet_router_->RemoveRtpModule(_rtpRtcpModule.get());
2948b86d4e4a8dec1eb1b801244a2a97cda66f561d8eStefan Holmer  }
2949b86d4e4a8dec1eb1b801244a2a97cda66f561d8eStefan Holmer  packet_router_ = packet_router;
2950b86d4e4a8dec1eb1b801244a2a97cda66f561d8eStefan Holmer}
2951b86d4e4a8dec1eb1b801244a2a97cda66f561d8eStefan Holmer
2952d16e839c6d29831e79312180085b6a19149df43fpbos@webrtc.orgvoid Channel::SetRTCPStatus(bool enable) {
2953d16e839c6d29831e79312180085b6a19149df43fpbos@webrtc.org  WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
2954d16e839c6d29831e79312180085b6a19149df43fpbos@webrtc.org               "Channel::SetRTCPStatus()");
2955da903eaabbb6c6830efcafc3c2ade1d36f511e43pbos  _rtpRtcpModule->SetRTCPStatus(enable ? RtcpMode::kCompound : RtcpMode::kOff);
2956470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com}
2957470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
2958470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.comint
2959470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.comChannel::GetRTCPStatus(bool& enabled)
2960470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com{
2961da903eaabbb6c6830efcafc3c2ade1d36f511e43pbos  RtcpMode method = _rtpRtcpModule->RTCP();
2962da903eaabbb6c6830efcafc3c2ade1d36f511e43pbos  enabled = (method != RtcpMode::kOff);
2963470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    return 0;
2964470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com}
2965470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
2966470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.comint
2967470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.comChannel::SetRTCP_CNAME(const char cName[256])
2968470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com{
2969470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
2970470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                 "Channel::SetRTCP_CNAME()");
29712853dde5201d9ddc284ce5efb9688f6340487acepwestin@webrtc.org    if (_rtpRtcpModule->SetCNAME(cName) != 0)
2972470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
2973470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        _engineStatisticsPtr->SetLastError(
2974470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            VE_RTP_RTCP_MODULE_ERROR, kTraceError,
2975470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            "SetRTCP_CNAME() failed to set RTCP CNAME");
2976470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        return -1;
2977470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
2978470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    return 0;
2979470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com}
2980470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
2981470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.comint
2982470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.comChannel::GetRemoteRTCP_CNAME(char cName[256])
2983470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com{
2984470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    if (cName == NULL)
2985470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
2986470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        _engineStatisticsPtr->SetLastError(
2987470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            VE_INVALID_ARGUMENT, kTraceError,
2988470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            "GetRemoteRTCP_CNAME() invalid CNAME input buffer");
2989470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        return -1;
2990470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
2991813e4b0af06272dada388c2d8383b2e36a1da6a6leozwang@webrtc.org    char cname[RTCP_CNAME_SIZE];
2992822fbd8b68ffdb481b9557e2950ae8d6657c8ce6wu@webrtc.org    const uint32_t remoteSSRC = rtp_receiver_->SSRC();
29932853dde5201d9ddc284ce5efb9688f6340487acepwestin@webrtc.org    if (_rtpRtcpModule->RemoteCNAME(remoteSSRC, cname) != 0)
2994470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
2995470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        _engineStatisticsPtr->SetLastError(
2996470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            VE_CANNOT_RETRIEVE_CNAME, kTraceError,
2997470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            "GetRemoteRTCP_CNAME() failed to retrieve remote RTCP CNAME");
2998470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        return -1;
2999470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
3000470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    strcpy(cName, cname);
3001470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    return 0;
3002470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com}
3003470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
3004470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.comint
3005470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.comChannel::GetRemoteRTCPData(
3006470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    unsigned int& NTPHigh,
3007470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    unsigned int& NTPLow,
3008470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    unsigned int& timestamp,
3009470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    unsigned int& playoutTimestamp,
3010470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    unsigned int* jitter,
3011470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    unsigned short* fractionLost)
3012470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com{
3013470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    // --- Information from sender info in received Sender Reports
3014470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
3015470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    RTCPSenderInfo senderInfo;
30162853dde5201d9ddc284ce5efb9688f6340487acepwestin@webrtc.org    if (_rtpRtcpModule->RemoteRTCPStat(&senderInfo) != 0)
3017470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
3018470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        _engineStatisticsPtr->SetLastError(
3019470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            VE_RTP_RTCP_MODULE_ERROR, kTraceError,
3020fcd12b3b7d7e92d6f8cdfdf8277808ae52a07c36wu@webrtc.org            "GetRemoteRTCPData() failed to retrieve sender info for remote "
3021470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            "side");
3022470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        return -1;
3023470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
3024470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
3025470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    // We only utilize 12 out of 20 bytes in the sender info (ignores packet
3026470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    // and octet count)
3027470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    NTPHigh = senderInfo.NTPseconds;
3028470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    NTPLow = senderInfo.NTPfraction;
3029470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    timestamp = senderInfo.RTPtimeStamp;
3030470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
3031470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    // --- Locally derived information
3032470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
3033470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    // This value is updated on each incoming RTCP packet (0 when no packet
3034470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    // has been received)
30351de01354e68da71bc62c81af17afeac8ed374a18pwestin@webrtc.org    playoutTimestamp = playout_timestamp_rtcp_;
3036470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
3037470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    if (NULL != jitter || NULL != fractionLost)
3038470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
3039ce5990cb0bbfbf5ee5306cf990e975a2faa090b7perkj@webrtc.org        // Get all RTCP receiver report blocks that have been received on this
3040ce5990cb0bbfbf5ee5306cf990e975a2faa090b7perkj@webrtc.org        // channel. If we receive RTP packets from a remote source we know the
3041ce5990cb0bbfbf5ee5306cf990e975a2faa090b7perkj@webrtc.org        // remote SSRC and use the report block from him.
3042ce5990cb0bbfbf5ee5306cf990e975a2faa090b7perkj@webrtc.org        // Otherwise use the first report block.
3043ce5990cb0bbfbf5ee5306cf990e975a2faa090b7perkj@webrtc.org        std::vector<RTCPReportBlock> remote_stats;
30442853dde5201d9ddc284ce5efb9688f6340487acepwestin@webrtc.org        if (_rtpRtcpModule->RemoteRTCPStat(&remote_stats) != 0 ||
3045ce5990cb0bbfbf5ee5306cf990e975a2faa090b7perkj@webrtc.org            remote_stats.empty()) {
3046ce5990cb0bbfbf5ee5306cf990e975a2faa090b7perkj@webrtc.org          WEBRTC_TRACE(kTraceWarning, kTraceVoice,
3047ce5990cb0bbfbf5ee5306cf990e975a2faa090b7perkj@webrtc.org                       VoEId(_instanceId, _channelId),
3048ce5990cb0bbfbf5ee5306cf990e975a2faa090b7perkj@webrtc.org                       "GetRemoteRTCPData() failed to measure statistics due"
3049ce5990cb0bbfbf5ee5306cf990e975a2faa090b7perkj@webrtc.org                       " to lack of received RTP and/or RTCP packets");
3050ce5990cb0bbfbf5ee5306cf990e975a2faa090b7perkj@webrtc.org          return -1;
3051470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        }
3052ce5990cb0bbfbf5ee5306cf990e975a2faa090b7perkj@webrtc.org
3053822fbd8b68ffdb481b9557e2950ae8d6657c8ce6wu@webrtc.org        uint32_t remoteSSRC = rtp_receiver_->SSRC();
3054ce5990cb0bbfbf5ee5306cf990e975a2faa090b7perkj@webrtc.org        std::vector<RTCPReportBlock>::const_iterator it = remote_stats.begin();
3055ce5990cb0bbfbf5ee5306cf990e975a2faa090b7perkj@webrtc.org        for (; it != remote_stats.end(); ++it) {
3056ce5990cb0bbfbf5ee5306cf990e975a2faa090b7perkj@webrtc.org          if (it->remoteSSRC == remoteSSRC)
3057ce5990cb0bbfbf5ee5306cf990e975a2faa090b7perkj@webrtc.org            break;
3058470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        }
3059ce5990cb0bbfbf5ee5306cf990e975a2faa090b7perkj@webrtc.org
3060ce5990cb0bbfbf5ee5306cf990e975a2faa090b7perkj@webrtc.org        if (it == remote_stats.end()) {
3061ce5990cb0bbfbf5ee5306cf990e975a2faa090b7perkj@webrtc.org          // If we have not received any RTCP packets from this SSRC it probably
3062ce5990cb0bbfbf5ee5306cf990e975a2faa090b7perkj@webrtc.org          // means that we have not received any RTP packets.
3063ce5990cb0bbfbf5ee5306cf990e975a2faa090b7perkj@webrtc.org          // Use the first received report block instead.
3064ce5990cb0bbfbf5ee5306cf990e975a2faa090b7perkj@webrtc.org          it = remote_stats.begin();
3065ce5990cb0bbfbf5ee5306cf990e975a2faa090b7perkj@webrtc.org          remoteSSRC = it->remoteSSRC;
3066470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        }
3067ce5990cb0bbfbf5ee5306cf990e975a2faa090b7perkj@webrtc.org
306879af734807109d119573ce23daa1a2bff0f0eecaxians@webrtc.org        if (jitter) {
306979af734807109d119573ce23daa1a2bff0f0eecaxians@webrtc.org          *jitter = it->jitter;
307079af734807109d119573ce23daa1a2bff0f0eecaxians@webrtc.org        }
3071ce5990cb0bbfbf5ee5306cf990e975a2faa090b7perkj@webrtc.org
307279af734807109d119573ce23daa1a2bff0f0eecaxians@webrtc.org        if (fractionLost) {
307379af734807109d119573ce23daa1a2bff0f0eecaxians@webrtc.org          *fractionLost = it->fractionLost;
307479af734807109d119573ce23daa1a2bff0f0eecaxians@webrtc.org        }
3075470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
3076470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    return 0;
3077470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com}
3078470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
3079470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.comint
30809213521ea98b0977c7cdabd2853060835af226f3pbos@webrtc.orgChannel::SendApplicationDefinedRTCPPacket(unsigned char subType,
3081470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                                             unsigned int name,
3082470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                                             const char* data,
3083470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                                             unsigned short dataLengthInBytes)
3084470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com{
3085470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
3086470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                 "Channel::SendApplicationDefinedRTCPPacket()");
3087944cbeb2926feb86a687e5fda9e2ac88ea8e3001henrika@webrtc.org    if (!channel_state_.Get().sending)
3088470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
3089470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        _engineStatisticsPtr->SetLastError(
3090470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            VE_NOT_SENDING, kTraceError,
3091470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            "SendApplicationDefinedRTCPPacket() not sending");
3092470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        return -1;
3093470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
3094470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    if (NULL == data)
3095470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
3096470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        _engineStatisticsPtr->SetLastError(
3097470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            VE_INVALID_ARGUMENT, kTraceError,
3098470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            "SendApplicationDefinedRTCPPacket() invalid data value");
3099470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        return -1;
3100470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
3101470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    if (dataLengthInBytes % 4 != 0)
3102470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
3103470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        _engineStatisticsPtr->SetLastError(
3104470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            VE_INVALID_ARGUMENT, kTraceError,
3105470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            "SendApplicationDefinedRTCPPacket() invalid length value");
3106470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        return -1;
3107470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
3108da903eaabbb6c6830efcafc3c2ade1d36f511e43pbos    RtcpMode status = _rtpRtcpModule->RTCP();
3109da903eaabbb6c6830efcafc3c2ade1d36f511e43pbos    if (status == RtcpMode::kOff) {
3110470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        _engineStatisticsPtr->SetLastError(
3111470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            VE_RTCP_ERROR, kTraceError,
3112470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            "SendApplicationDefinedRTCPPacket() RTCP is disabled");
3113470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        return -1;
3114470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
3115470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
3116470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    // Create and schedule the RTCP APP packet for transmission
31172853dde5201d9ddc284ce5efb9688f6340487acepwestin@webrtc.org    if (_rtpRtcpModule->SetRTCPApplicationSpecificData(
3118470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        subType,
3119470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        name,
3120470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        (const unsigned char*) data,
3121470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        dataLengthInBytes) != 0)
3122470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
3123470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        _engineStatisticsPtr->SetLastError(
3124470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            VE_SEND_ERROR, kTraceError,
3125470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            "SendApplicationDefinedRTCPPacket() failed to send RTCP packet");
3126470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        return -1;
3127470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
3128470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    return 0;
3129470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com}
3130470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
3131470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.comint
3132470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.comChannel::GetRTPStatistics(
3133470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        unsigned int& averageJitterMs,
3134470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        unsigned int& maxJitterMs,
3135470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        unsigned int& discardedPackets)
3136470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com{
3137470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    // The jitter statistics is updated for each received RTP packet and is
3138470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    // based on received packets.
3139da903eaabbb6c6830efcafc3c2ade1d36f511e43pbos    if (_rtpRtcpModule->RTCP() == RtcpMode::kOff) {
314054ae4ffb9e235a9742e2b11298327e02d870571csprang@webrtc.org      // If RTCP is off, there is no timed thread in the RTCP module regularly
314154ae4ffb9e235a9742e2b11298327e02d870571csprang@webrtc.org      // generating new stats, trigger the update manually here instead.
314254ae4ffb9e235a9742e2b11298327e02d870571csprang@webrtc.org      StreamStatistician* statistician =
314354ae4ffb9e235a9742e2b11298327e02d870571csprang@webrtc.org          rtp_receive_statistics_->GetStatistician(rtp_receiver_->SSRC());
314454ae4ffb9e235a9742e2b11298327e02d870571csprang@webrtc.org      if (statistician) {
314554ae4ffb9e235a9742e2b11298327e02d870571csprang@webrtc.org        // Don't use returned statistics, use data from proxy instead so that
314654ae4ffb9e235a9742e2b11298327e02d870571csprang@webrtc.org        // max jitter can be fetched atomically.
314754ae4ffb9e235a9742e2b11298327e02d870571csprang@webrtc.org        RtcpStatistics s;
314854ae4ffb9e235a9742e2b11298327e02d870571csprang@webrtc.org        statistician->GetStatistics(&s, true);
314954ae4ffb9e235a9742e2b11298327e02d870571csprang@webrtc.org      }
3150470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
3151470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
315254ae4ffb9e235a9742e2b11298327e02d870571csprang@webrtc.org    ChannelStatistics stats = statistics_proxy_->GetStats();
3153eb524d997b877ba9b0bcaf8c85eae52bd40c37e3andrew@webrtc.org    const int32_t playoutFrequency = audio_coding_->PlayoutFrequency();
315454ae4ffb9e235a9742e2b11298327e02d870571csprang@webrtc.org    if (playoutFrequency > 0) {
315554ae4ffb9e235a9742e2b11298327e02d870571csprang@webrtc.org      // Scale RTP statistics given the current playout frequency
315654ae4ffb9e235a9742e2b11298327e02d870571csprang@webrtc.org      maxJitterMs = stats.max_jitter / (playoutFrequency / 1000);
315754ae4ffb9e235a9742e2b11298327e02d870571csprang@webrtc.org      averageJitterMs = stats.rtcp.jitter / (playoutFrequency / 1000);
3158470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
3159470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
3160470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    discardedPackets = _numberOfDiscardedPackets;
3161470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
3162470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    return 0;
3163470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com}
3164470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
31658a2fc88459dc507a67594e3127143e16af612fc9henrika@webrtc.orgint Channel::GetRemoteRTCPReportBlocks(
31668a2fc88459dc507a67594e3127143e16af612fc9henrika@webrtc.org    std::vector<ReportBlock>* report_blocks) {
31678a2fc88459dc507a67594e3127143e16af612fc9henrika@webrtc.org  if (report_blocks == NULL) {
31688a2fc88459dc507a67594e3127143e16af612fc9henrika@webrtc.org    _engineStatisticsPtr->SetLastError(VE_INVALID_ARGUMENT, kTraceError,
31698a2fc88459dc507a67594e3127143e16af612fc9henrika@webrtc.org      "GetRemoteRTCPReportBlock()s invalid report_blocks.");
31708a2fc88459dc507a67594e3127143e16af612fc9henrika@webrtc.org    return -1;
31718a2fc88459dc507a67594e3127143e16af612fc9henrika@webrtc.org  }
31728a2fc88459dc507a67594e3127143e16af612fc9henrika@webrtc.org
31738a2fc88459dc507a67594e3127143e16af612fc9henrika@webrtc.org  // Get the report blocks from the latest received RTCP Sender or Receiver
31748a2fc88459dc507a67594e3127143e16af612fc9henrika@webrtc.org  // Report. Each element in the vector contains the sender's SSRC and a
31758a2fc88459dc507a67594e3127143e16af612fc9henrika@webrtc.org  // report block according to RFC 3550.
31768a2fc88459dc507a67594e3127143e16af612fc9henrika@webrtc.org  std::vector<RTCPReportBlock> rtcp_report_blocks;
31778a2fc88459dc507a67594e3127143e16af612fc9henrika@webrtc.org  if (_rtpRtcpModule->RemoteRTCPStat(&rtcp_report_blocks) != 0) {
31788a2fc88459dc507a67594e3127143e16af612fc9henrika@webrtc.org    return -1;
31798a2fc88459dc507a67594e3127143e16af612fc9henrika@webrtc.org  }
31808a2fc88459dc507a67594e3127143e16af612fc9henrika@webrtc.org
31818a2fc88459dc507a67594e3127143e16af612fc9henrika@webrtc.org  if (rtcp_report_blocks.empty())
31828a2fc88459dc507a67594e3127143e16af612fc9henrika@webrtc.org    return 0;
31838a2fc88459dc507a67594e3127143e16af612fc9henrika@webrtc.org
31848a2fc88459dc507a67594e3127143e16af612fc9henrika@webrtc.org  std::vector<RTCPReportBlock>::const_iterator it = rtcp_report_blocks.begin();
31858a2fc88459dc507a67594e3127143e16af612fc9henrika@webrtc.org  for (; it != rtcp_report_blocks.end(); ++it) {
31868a2fc88459dc507a67594e3127143e16af612fc9henrika@webrtc.org    ReportBlock report_block;
31878a2fc88459dc507a67594e3127143e16af612fc9henrika@webrtc.org    report_block.sender_SSRC = it->remoteSSRC;
31888a2fc88459dc507a67594e3127143e16af612fc9henrika@webrtc.org    report_block.source_SSRC = it->sourceSSRC;
31898a2fc88459dc507a67594e3127143e16af612fc9henrika@webrtc.org    report_block.fraction_lost = it->fractionLost;
31908a2fc88459dc507a67594e3127143e16af612fc9henrika@webrtc.org    report_block.cumulative_num_packets_lost = it->cumulativeLost;
31918a2fc88459dc507a67594e3127143e16af612fc9henrika@webrtc.org    report_block.extended_highest_sequence_number = it->extendedHighSeqNum;
31928a2fc88459dc507a67594e3127143e16af612fc9henrika@webrtc.org    report_block.interarrival_jitter = it->jitter;
31938a2fc88459dc507a67594e3127143e16af612fc9henrika@webrtc.org    report_block.last_SR_timestamp = it->lastSR;
31948a2fc88459dc507a67594e3127143e16af612fc9henrika@webrtc.org    report_block.delay_since_last_SR = it->delaySinceLastSR;
31958a2fc88459dc507a67594e3127143e16af612fc9henrika@webrtc.org    report_blocks->push_back(report_block);
31968a2fc88459dc507a67594e3127143e16af612fc9henrika@webrtc.org  }
31978a2fc88459dc507a67594e3127143e16af612fc9henrika@webrtc.org  return 0;
31988a2fc88459dc507a67594e3127143e16af612fc9henrika@webrtc.org}
31998a2fc88459dc507a67594e3127143e16af612fc9henrika@webrtc.org
3200470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.comint
3201470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.comChannel::GetRTPStatistics(CallStatistics& stats)
3202470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com{
3203cb711f77d2ff9ebd42678869a73353809b3af66ewu@webrtc.org    // --- RtcpStatistics
3204470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
3205470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    // The jitter statistics is updated for each received RTP packet and is
3206470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    // based on received packets.
320754ae4ffb9e235a9742e2b11298327e02d870571csprang@webrtc.org    RtcpStatistics statistics;
3208286fe0b04d97205ac84688bbe613d5749192b2d1stefan@webrtc.org    StreamStatistician* statistician =
3209286fe0b04d97205ac84688bbe613d5749192b2d1stefan@webrtc.org        rtp_receive_statistics_->GetStatistician(rtp_receiver_->SSRC());
3210da903eaabbb6c6830efcafc3c2ade1d36f511e43pbos    if (!statistician ||
3211da903eaabbb6c6830efcafc3c2ade1d36f511e43pbos        !statistician->GetStatistics(
3212da903eaabbb6c6830efcafc3c2ade1d36f511e43pbos            &statistics, _rtpRtcpModule->RTCP() == RtcpMode::kOff)) {
3213822fbd8b68ffdb481b9557e2950ae8d6657c8ce6wu@webrtc.org      _engineStatisticsPtr->SetLastError(
3214822fbd8b68ffdb481b9557e2950ae8d6657c8ce6wu@webrtc.org          VE_CANNOT_RETRIEVE_RTP_STAT, kTraceWarning,
3215822fbd8b68ffdb481b9557e2950ae8d6657c8ce6wu@webrtc.org          "GetRTPStatistics() failed to read RTP statistics from the "
3216822fbd8b68ffdb481b9557e2950ae8d6657c8ce6wu@webrtc.org          "RTP/RTCP module");
3217470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
3218470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
3219822fbd8b68ffdb481b9557e2950ae8d6657c8ce6wu@webrtc.org    stats.fractionLost = statistics.fraction_lost;
3220822fbd8b68ffdb481b9557e2950ae8d6657c8ce6wu@webrtc.org    stats.cumulativeLost = statistics.cumulative_lost;
3221822fbd8b68ffdb481b9557e2950ae8d6657c8ce6wu@webrtc.org    stats.extendedMax = statistics.extended_max_sequence_number;
3222822fbd8b68ffdb481b9557e2950ae8d6657c8ce6wu@webrtc.org    stats.jitterSamples = statistics.jitter;
3223470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
3224cb711f77d2ff9ebd42678869a73353809b3af66ewu@webrtc.org    // --- RTT
32252013aeced2b7821a407f302802c4a16fd02728b1Minyue    stats.rttMs = GetRTT(true);
3226470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
3227cb711f77d2ff9ebd42678869a73353809b3af66ewu@webrtc.org    // --- Data counters
3228470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
32294591fbd09f9cb6e83433c49a12dd8524c2806502pkasting@chromium.org    size_t bytesSent(0);
32306141e13873d0fdea626de08dfec2efa2c9171c76pbos@webrtc.org    uint32_t packetsSent(0);
32314591fbd09f9cb6e83433c49a12dd8524c2806502pkasting@chromium.org    size_t bytesReceived(0);
32326141e13873d0fdea626de08dfec2efa2c9171c76pbos@webrtc.org    uint32_t packetsReceived(0);
3233470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
3234286fe0b04d97205ac84688bbe613d5749192b2d1stefan@webrtc.org    if (statistician) {
3235286fe0b04d97205ac84688bbe613d5749192b2d1stefan@webrtc.org      statistician->GetDataCounters(&bytesReceived, &packetsReceived);
3236286fe0b04d97205ac84688bbe613d5749192b2d1stefan@webrtc.org    }
3237822fbd8b68ffdb481b9557e2950ae8d6657c8ce6wu@webrtc.org
32382853dde5201d9ddc284ce5efb9688f6340487acepwestin@webrtc.org    if (_rtpRtcpModule->DataCountersRTP(&bytesSent,
3239822fbd8b68ffdb481b9557e2950ae8d6657c8ce6wu@webrtc.org                                        &packetsSent) != 0)
3240470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
3241470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        WEBRTC_TRACE(kTraceWarning, kTraceVoice,
3242470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                     VoEId(_instanceId, _channelId),
3243470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                     "GetRTPStatistics() failed to retrieve RTP datacounters =>"
3244fcd12b3b7d7e92d6f8cdfdf8277808ae52a07c36wu@webrtc.org                     " output will not be complete");
3245470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
3246470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
3247470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    stats.bytesSent = bytesSent;
3248470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    stats.packetsSent = packetsSent;
3249470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    stats.bytesReceived = bytesReceived;
3250470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    stats.packetsReceived = packetsReceived;
3251470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
3252cb711f77d2ff9ebd42678869a73353809b3af66ewu@webrtc.org    // --- Timestamps
3253cb711f77d2ff9ebd42678869a73353809b3af66ewu@webrtc.org    {
3254cb711f77d2ff9ebd42678869a73353809b3af66ewu@webrtc.org      CriticalSectionScoped lock(ts_stats_lock_.get());
3255cb711f77d2ff9ebd42678869a73353809b3af66ewu@webrtc.org      stats.capture_start_ntp_time_ms_ = capture_start_ntp_time_ms_;
3256cb711f77d2ff9ebd42678869a73353809b3af66ewu@webrtc.org    }
3257470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    return 0;
3258470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com}
3259470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
3260c1a40a7b68a8d253b0ba32b89f3126931eeaeab3minyue@webrtc.orgint Channel::SetREDStatus(bool enable, int redPayloadtype) {
326142259e7ebc7126f5a7036940fcab65b3f8d2af38turaj@webrtc.org  WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
3262c1a40a7b68a8d253b0ba32b89f3126931eeaeab3minyue@webrtc.org               "Channel::SetREDStatus()");
326342259e7ebc7126f5a7036940fcab65b3f8d2af38turaj@webrtc.org
32648c8ad85c5d70c38cea82f5b17794a4e7ab4cf531turaj@webrtc.org  if (enable) {
32658c8ad85c5d70c38cea82f5b17794a4e7ab4cf531turaj@webrtc.org    if (redPayloadtype < 0 || redPayloadtype > 127) {
32668c8ad85c5d70c38cea82f5b17794a4e7ab4cf531turaj@webrtc.org      _engineStatisticsPtr->SetLastError(
32678c8ad85c5d70c38cea82f5b17794a4e7ab4cf531turaj@webrtc.org          VE_PLTYPE_ERROR, kTraceError,
3268c1a40a7b68a8d253b0ba32b89f3126931eeaeab3minyue@webrtc.org          "SetREDStatus() invalid RED payload type");
32698c8ad85c5d70c38cea82f5b17794a4e7ab4cf531turaj@webrtc.org      return -1;
32708c8ad85c5d70c38cea82f5b17794a4e7ab4cf531turaj@webrtc.org    }
32718c8ad85c5d70c38cea82f5b17794a4e7ab4cf531turaj@webrtc.org
32728c8ad85c5d70c38cea82f5b17794a4e7ab4cf531turaj@webrtc.org    if (SetRedPayloadType(redPayloadtype) < 0) {
32738c8ad85c5d70c38cea82f5b17794a4e7ab4cf531turaj@webrtc.org      _engineStatisticsPtr->SetLastError(
32748c8ad85c5d70c38cea82f5b17794a4e7ab4cf531turaj@webrtc.org          VE_CODEC_ERROR, kTraceError,
32758c8ad85c5d70c38cea82f5b17794a4e7ab4cf531turaj@webrtc.org          "SetSecondarySendCodec() Failed to register RED ACM");
32768c8ad85c5d70c38cea82f5b17794a4e7ab4cf531turaj@webrtc.org      return -1;
32778c8ad85c5d70c38cea82f5b17794a4e7ab4cf531turaj@webrtc.org    }
327842259e7ebc7126f5a7036940fcab65b3f8d2af38turaj@webrtc.org  }
32792cf22a6abce2d38e673505a4cfd5624a3710b5cdperkj@webrtc.org
3280aa5ea1c0f9d0df583ae0f791f6715a0764aff3cfminyue@webrtc.org  if (audio_coding_->SetREDStatus(enable) != 0) {
328142259e7ebc7126f5a7036940fcab65b3f8d2af38turaj@webrtc.org    _engineStatisticsPtr->SetLastError(
328242259e7ebc7126f5a7036940fcab65b3f8d2af38turaj@webrtc.org        VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
3283aa5ea1c0f9d0df583ae0f791f6715a0764aff3cfminyue@webrtc.org        "SetREDStatus() failed to set RED state in the ACM");
328442259e7ebc7126f5a7036940fcab65b3f8d2af38turaj@webrtc.org    return -1;
328542259e7ebc7126f5a7036940fcab65b3f8d2af38turaj@webrtc.org  }
328642259e7ebc7126f5a7036940fcab65b3f8d2af38turaj@webrtc.org  return 0;
3287470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com}
3288470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
3289470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.comint
3290c1a40a7b68a8d253b0ba32b89f3126931eeaeab3minyue@webrtc.orgChannel::GetREDStatus(bool& enabled, int& redPayloadtype)
3291470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com{
3292aa5ea1c0f9d0df583ae0f791f6715a0764aff3cfminyue@webrtc.org    enabled = audio_coding_->REDStatus();
3293470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    if (enabled)
3294470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
32955c1def8892390a336d1eecd9b61adacece858898danilchap      int8_t payloadType = 0;
32965c1def8892390a336d1eecd9b61adacece858898danilchap      if (_rtpRtcpModule->SendREDPayloadType(&payloadType) != 0) {
3297470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            _engineStatisticsPtr->SetLastError(
3298470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                VE_RTP_RTCP_MODULE_ERROR, kTraceError,
3299c1a40a7b68a8d253b0ba32b89f3126931eeaeab3minyue@webrtc.org                "GetREDStatus() failed to retrieve RED PT from RTP/RTCP "
3300470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                "module");
3301470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            return -1;
3302470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        }
3303df9a41d2701d321dbc987201ec7cffe2a16bd2c4pkasting@chromium.org        redPayloadtype = payloadType;
3304470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        return 0;
3305470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
3306470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    return 0;
3307470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com}
3308470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
3309c1a40a7b68a8d253b0ba32b89f3126931eeaeab3minyue@webrtc.orgint Channel::SetCodecFECStatus(bool enable) {
3310c1a40a7b68a8d253b0ba32b89f3126931eeaeab3minyue@webrtc.org  WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
3311c1a40a7b68a8d253b0ba32b89f3126931eeaeab3minyue@webrtc.org               "Channel::SetCodecFECStatus()");
3312c1a40a7b68a8d253b0ba32b89f3126931eeaeab3minyue@webrtc.org
3313c1a40a7b68a8d253b0ba32b89f3126931eeaeab3minyue@webrtc.org  if (audio_coding_->SetCodecFEC(enable) != 0) {
3314c1a40a7b68a8d253b0ba32b89f3126931eeaeab3minyue@webrtc.org    _engineStatisticsPtr->SetLastError(
3315c1a40a7b68a8d253b0ba32b89f3126931eeaeab3minyue@webrtc.org        VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
3316c1a40a7b68a8d253b0ba32b89f3126931eeaeab3minyue@webrtc.org        "SetCodecFECStatus() failed to set FEC state");
3317c1a40a7b68a8d253b0ba32b89f3126931eeaeab3minyue@webrtc.org    return -1;
3318c1a40a7b68a8d253b0ba32b89f3126931eeaeab3minyue@webrtc.org  }
3319c1a40a7b68a8d253b0ba32b89f3126931eeaeab3minyue@webrtc.org  return 0;
3320c1a40a7b68a8d253b0ba32b89f3126931eeaeab3minyue@webrtc.org}
3321c1a40a7b68a8d253b0ba32b89f3126931eeaeab3minyue@webrtc.org
3322c1a40a7b68a8d253b0ba32b89f3126931eeaeab3minyue@webrtc.orgbool Channel::GetCodecFECStatus() {
3323c1a40a7b68a8d253b0ba32b89f3126931eeaeab3minyue@webrtc.org  bool enabled = audio_coding_->CodecFEC();
3324c1a40a7b68a8d253b0ba32b89f3126931eeaeab3minyue@webrtc.org  return enabled;
3325c1a40a7b68a8d253b0ba32b89f3126931eeaeab3minyue@webrtc.org}
3326c1a40a7b68a8d253b0ba32b89f3126931eeaeab3minyue@webrtc.org
3327db249956807d916729aacfaf3382923e8239d533pwestin@webrtc.orgvoid Channel::SetNACKStatus(bool enable, int maxNumberOfPackets) {
3328db249956807d916729aacfaf3382923e8239d533pwestin@webrtc.org  // None of these functions can fail.
3329b86d4e4a8dec1eb1b801244a2a97cda66f561d8eStefan Holmer  // If pacing is enabled we always store packets.
3330b86d4e4a8dec1eb1b801244a2a97cda66f561d8eStefan Holmer  if (!pacing_enabled_)
3331b86d4e4a8dec1eb1b801244a2a97cda66f561d8eStefan Holmer    _rtpRtcpModule->SetStorePacketsStatus(enable, maxNumberOfPackets);
33327bb8f02274ecbfa1f7ef134d708369a369a78c83stefan@webrtc.org  rtp_receive_statistics_->SetMaxReorderingThreshold(maxNumberOfPackets);
33337bb8f02274ecbfa1f7ef134d708369a369a78c83stefan@webrtc.org  rtp_receiver_->SetNACKStatus(enable ? kNackRtcp : kNackOff);
3334d30859e58e2c0b0676ab2b52b8a2723e10d49e28pwestin@webrtc.org  if (enable)
3335eb524d997b877ba9b0bcaf8c85eae52bd40c37e3andrew@webrtc.org    audio_coding_->EnableNack(maxNumberOfPackets);
3336d30859e58e2c0b0676ab2b52b8a2723e10d49e28pwestin@webrtc.org  else
3337eb524d997b877ba9b0bcaf8c85eae52bd40c37e3andrew@webrtc.org    audio_coding_->DisableNack();
3338db249956807d916729aacfaf3382923e8239d533pwestin@webrtc.org}
3339db249956807d916729aacfaf3382923e8239d533pwestin@webrtc.org
3340d30859e58e2c0b0676ab2b52b8a2723e10d49e28pwestin@webrtc.org// Called when we are missing one or more packets.
3341d30859e58e2c0b0676ab2b52b8a2723e10d49e28pwestin@webrtc.orgint Channel::ResendPackets(const uint16_t* sequence_numbers, int length) {
3342db249956807d916729aacfaf3382923e8239d533pwestin@webrtc.org  return _rtpRtcpModule->SendNACK(sequence_numbers, length);
3343db249956807d916729aacfaf3382923e8239d533pwestin@webrtc.org}
3344db249956807d916729aacfaf3382923e8239d533pwestin@webrtc.org
33456141e13873d0fdea626de08dfec2efa2c9171c76pbos@webrtc.orguint32_t
3346755b04a06ec4ae91ae7fb601c641e683f4e9e87dandrew@webrtc.orgChannel::Demultiplex(const AudioFrame& audioFrame)
3347470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com{
3348470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
3349755b04a06ec4ae91ae7fb601c641e683f4e9e87dandrew@webrtc.org                 "Channel::Demultiplex()");
3350ae1a58bba4f926d149a5f39243269c3f6625f494andrew@webrtc.org    _audioFrame.CopyFrom(audioFrame);
335163a509858d3988299726640c664b699d6229a1d4andrew@webrtc.org    _audioFrame.id_ = _channelId;
3352470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    return 0;
3353470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com}
3354470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
33552f84afad30b088ddebb4063bc47ac9a79d735a2bxians@webrtc.orgvoid Channel::Demultiplex(const int16_t* audio_data,
33568fff1f065ea9d25970c3839294acdd606a5ddf22xians@webrtc.org                          int sample_rate,
3357dce40cf804019a9898b6ab8d8262466b697c56e0Peter Kasting                          size_t number_of_frames,
33586955870806624479723addfae6dcf5d13968796cPeter Kasting                          size_t number_of_channels) {
33592f84afad30b088ddebb4063bc47ac9a79d735a2bxians@webrtc.org  CodecInst codec;
33602f84afad30b088ddebb4063bc47ac9a79d735a2bxians@webrtc.org  GetSendCodec(codec);
33612f84afad30b088ddebb4063bc47ac9a79d735a2bxians@webrtc.org
3362cdfe20bfc1146030aa59eb37635fd2fbcecd6cdbAlejandro Luebs  // Never upsample or upmix the capture signal here. This should be done at the
3363cdfe20bfc1146030aa59eb37635fd2fbcecd6cdbAlejandro Luebs  // end of the send chain.
3364cdfe20bfc1146030aa59eb37635fd2fbcecd6cdbAlejandro Luebs  _audioFrame.sample_rate_hz_ = std::min(codec.plfreq, sample_rate);
3365cdfe20bfc1146030aa59eb37635fd2fbcecd6cdbAlejandro Luebs  _audioFrame.num_channels_ = std::min(number_of_channels, codec.channels);
3366cdfe20bfc1146030aa59eb37635fd2fbcecd6cdbAlejandro Luebs  RemixAndResample(audio_data, number_of_frames, number_of_channels,
3367cdfe20bfc1146030aa59eb37635fd2fbcecd6cdbAlejandro Luebs                   sample_rate, &input_resampler_, &_audioFrame);
33682f84afad30b088ddebb4063bc47ac9a79d735a2bxians@webrtc.org}
33692f84afad30b088ddebb4063bc47ac9a79d735a2bxians@webrtc.org
33706141e13873d0fdea626de08dfec2efa2c9171c76pbos@webrtc.orguint32_t
33710b0665acc1464d68e878f203bbc8772a0e32402dxians@google.comChannel::PrepareEncodeAndSend(int mixingFrequency)
3372470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com{
3373470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
3374470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                 "Channel::PrepareEncodeAndSend()");
3375470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
337663a509858d3988299726640c664b699d6229a1d4andrew@webrtc.org    if (_audioFrame.samples_per_channel_ == 0)
3377470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
3378470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        WEBRTC_TRACE(kTraceWarning, kTraceVoice, VoEId(_instanceId,_channelId),
3379470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                     "Channel::PrepareEncodeAndSend() invalid audio frame");
3380eec6ecdb1e249871dd25d04b62fc9ddc03dc8a34tommi@webrtc.org        return 0xFFFFFFFF;
3381470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
3382470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
3383944cbeb2926feb86a687e5fda9e2ac88ea8e3001henrika@webrtc.org    if (channel_state_.Get().input_file_playing)
3384470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
3385470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        MixOrReplaceAudioWithFile(mixingFrequency);
3386470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
3387470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
338821299d4e00781e199a53ba33ec192cdce920acecandrew@webrtc.org    bool is_muted = Mute();  // Cache locally as Mute() takes a lock.
338921299d4e00781e199a53ba33ec192cdce920acecandrew@webrtc.org    if (is_muted) {
339021299d4e00781e199a53ba33ec192cdce920acecandrew@webrtc.org      AudioFrameOperations::Mute(_audioFrame);
3391470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
3392470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
3393944cbeb2926feb86a687e5fda9e2ac88ea8e3001henrika@webrtc.org    if (channel_state_.Get().input_external_media)
3394470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
33959a065d1eae9ed296e1e2eaaad73d7ca1223bfe79mflodman@webrtc.org        CriticalSectionScoped cs(&_callbackCritSect);
339663a509858d3988299726640c664b699d6229a1d4andrew@webrtc.org        const bool isStereo = (_audioFrame.num_channels_ == 2);
3397470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        if (_inputExternalMediaCallbackPtr)
3398470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        {
3399470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            _inputExternalMediaCallbackPtr->Process(
3400470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                _channelId,
3401470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                kRecordingPerChannel,
34026141e13873d0fdea626de08dfec2efa2c9171c76pbos@webrtc.org               (int16_t*)_audioFrame.data_,
340363a509858d3988299726640c664b699d6229a1d4andrew@webrtc.org                _audioFrame.samples_per_channel_,
340463a509858d3988299726640c664b699d6229a1d4andrew@webrtc.org                _audioFrame.sample_rate_hz_,
3405470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                isStereo);
3406470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        }
3407470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
3408470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
3409470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    InsertInbandDtmfTone();
3410470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
341160730cfe3ce80e4023cd678373456cb703f000a4andrew@webrtc.org    if (_includeAudioLevelIndication) {
3412dce40cf804019a9898b6ab8d8262466b697c56e0Peter Kasting      size_t length =
3413dce40cf804019a9898b6ab8d8262466b697c56e0Peter Kasting          _audioFrame.samples_per_channel_ * _audioFrame.num_channels_;
341421299d4e00781e199a53ba33ec192cdce920acecandrew@webrtc.org      if (is_muted) {
341521299d4e00781e199a53ba33ec192cdce920acecandrew@webrtc.org        rms_level_.ProcessMuted(length);
341621299d4e00781e199a53ba33ec192cdce920acecandrew@webrtc.org      } else {
341721299d4e00781e199a53ba33ec192cdce920acecandrew@webrtc.org        rms_level_.Process(_audioFrame.data_, length);
341821299d4e00781e199a53ba33ec192cdce920acecandrew@webrtc.org      }
3419755b04a06ec4ae91ae7fb601c641e683f4e9e87dandrew@webrtc.org    }
3420755b04a06ec4ae91ae7fb601c641e683f4e9e87dandrew@webrtc.org
3421470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    return 0;
3422470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com}
3423470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
34246141e13873d0fdea626de08dfec2efa2c9171c76pbos@webrtc.orguint32_t
3425470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.comChannel::EncodeAndSend()
3426470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com{
3427470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
3428470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                 "Channel::EncodeAndSend()");
3429470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
343063a509858d3988299726640c664b699d6229a1d4andrew@webrtc.org    assert(_audioFrame.num_channels_ <= 2);
343163a509858d3988299726640c664b699d6229a1d4andrew@webrtc.org    if (_audioFrame.samples_per_channel_ == 0)
3432470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
3433470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        WEBRTC_TRACE(kTraceWarning, kTraceVoice, VoEId(_instanceId,_channelId),
3434470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                     "Channel::EncodeAndSend() invalid audio frame");
3435eec6ecdb1e249871dd25d04b62fc9ddc03dc8a34tommi@webrtc.org        return 0xFFFFFFFF;
3436470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
3437470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
343863a509858d3988299726640c664b699d6229a1d4andrew@webrtc.org    _audioFrame.id_ = _channelId;
3439470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
3440470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    // --- Add 10ms of raw (PCM) audio data to the encoder @ 32kHz.
3441470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
3442470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    // The ACM resamples internally.
344363a509858d3988299726640c664b699d6229a1d4andrew@webrtc.org    _audioFrame.timestamp_ = _timeStamp;
3444f56c1623103e3f72198d6b0f50de9f0585b6f52fhenrik.lundin@webrtc.org    // This call will trigger AudioPacketizationCallback::SendData if encoding
3445f56c1623103e3f72198d6b0f50de9f0585b6f52fhenrik.lundin@webrtc.org    // is done and payload is ready for packetization and transmission.
3446f56c1623103e3f72198d6b0f50de9f0585b6f52fhenrik.lundin@webrtc.org    // Otherwise, it will return without invoking the callback.
3447f56c1623103e3f72198d6b0f50de9f0585b6f52fhenrik.lundin@webrtc.org    if (audio_coding_->Add10MsData((AudioFrame&)_audioFrame) < 0)
3448470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
3449470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        WEBRTC_TRACE(kTraceError, kTraceVoice, VoEId(_instanceId,_channelId),
3450470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                     "Channel::EncodeAndSend() ACM encoding failed");
3451eec6ecdb1e249871dd25d04b62fc9ddc03dc8a34tommi@webrtc.org        return 0xFFFFFFFF;
3452470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
3453470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
3454b7e5054414ff524f9db81dab7917729b8c4c8bcbPeter Kasting    _timeStamp += static_cast<uint32_t>(_audioFrame.samples_per_channel_);
3455f56c1623103e3f72198d6b0f50de9f0585b6f52fhenrik.lundin@webrtc.org    return 0;
3456470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com}
3457470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
34582013aeced2b7821a407f302802c4a16fd02728b1Minyuevoid Channel::DisassociateSendChannel(int channel_id) {
34592013aeced2b7821a407f302802c4a16fd02728b1Minyue  CriticalSectionScoped lock(assoc_send_channel_lock_.get());
34602013aeced2b7821a407f302802c4a16fd02728b1Minyue  Channel* channel = associate_send_channel_.channel();
34612013aeced2b7821a407f302802c4a16fd02728b1Minyue  if (channel && channel->ChannelId() == channel_id) {
34622013aeced2b7821a407f302802c4a16fd02728b1Minyue    // If this channel is associated with a send channel of the specified
34632013aeced2b7821a407f302802c4a16fd02728b1Minyue    // Channel ID, disassociate with it.
34642013aeced2b7821a407f302802c4a16fd02728b1Minyue    ChannelOwner ref(NULL);
34652013aeced2b7821a407f302802c4a16fd02728b1Minyue    associate_send_channel_ = ref;
34662013aeced2b7821a407f302802c4a16fd02728b1Minyue  }
34672013aeced2b7821a407f302802c4a16fd02728b1Minyue}
34682013aeced2b7821a407f302802c4a16fd02728b1Minyue
3469470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.comint Channel::RegisterExternalMediaProcessing(
3470470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    ProcessingTypes type,
3471470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    VoEMediaProcess& processObject)
3472470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com{
3473470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3474470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                 "Channel::RegisterExternalMediaProcessing()");
3475470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
34769a065d1eae9ed296e1e2eaaad73d7ca1223bfe79mflodman@webrtc.org    CriticalSectionScoped cs(&_callbackCritSect);
3477470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
3478470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    if (kPlaybackPerChannel == type)
3479470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
3480470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        if (_outputExternalMediaCallbackPtr)
3481470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        {
3482470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            _engineStatisticsPtr->SetLastError(
3483470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                VE_INVALID_OPERATION, kTraceError,
3484470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                "Channel::RegisterExternalMediaProcessing() "
3485470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                "output external media already enabled");
3486470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            return -1;
3487470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        }
3488470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        _outputExternalMediaCallbackPtr = &processObject;
3489470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        _outputExternalMedia = true;
3490470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
3491470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    else if (kRecordingPerChannel == type)
3492470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
3493470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        if (_inputExternalMediaCallbackPtr)
3494470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        {
3495470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            _engineStatisticsPtr->SetLastError(
3496470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                VE_INVALID_OPERATION, kTraceError,
3497470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                "Channel::RegisterExternalMediaProcessing() "
3498470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                "output external media already enabled");
3499470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            return -1;
3500470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        }
3501470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        _inputExternalMediaCallbackPtr = &processObject;
3502944cbeb2926feb86a687e5fda9e2ac88ea8e3001henrika@webrtc.org        channel_state_.SetInputExternalMedia(true);
3503470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
3504470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    return 0;
3505470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com}
3506470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
3507470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.comint Channel::DeRegisterExternalMediaProcessing(ProcessingTypes type)
3508470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com{
3509470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3510470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                 "Channel::DeRegisterExternalMediaProcessing()");
3511470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
35129a065d1eae9ed296e1e2eaaad73d7ca1223bfe79mflodman@webrtc.org    CriticalSectionScoped cs(&_callbackCritSect);
3513470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
3514470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    if (kPlaybackPerChannel == type)
3515470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
3516470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        if (!_outputExternalMediaCallbackPtr)
3517470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        {
3518470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            _engineStatisticsPtr->SetLastError(
3519470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                VE_INVALID_OPERATION, kTraceWarning,
3520470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                "Channel::DeRegisterExternalMediaProcessing() "
3521470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                "output external media already disabled");
3522470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            return 0;
3523470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        }
3524470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        _outputExternalMedia = false;
3525470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        _outputExternalMediaCallbackPtr = NULL;
3526470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
3527470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    else if (kRecordingPerChannel == type)
3528470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
3529470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        if (!_inputExternalMediaCallbackPtr)
3530470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        {
3531470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            _engineStatisticsPtr->SetLastError(
3532470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                VE_INVALID_OPERATION, kTraceWarning,
3533470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                "Channel::DeRegisterExternalMediaProcessing() "
3534470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                "input external media already disabled");
3535470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            return 0;
3536470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        }
3537944cbeb2926feb86a687e5fda9e2ac88ea8e3001henrika@webrtc.org        channel_state_.SetInputExternalMedia(false);
3538470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        _inputExternalMediaCallbackPtr = NULL;
3539470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
3540470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
3541470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    return 0;
3542470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com}
3543470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
35441b60ceb499ee35460886f2bfaecee1f47319f925roosa@google.comint Channel::SetExternalMixing(bool enabled) {
35451b60ceb499ee35460886f2bfaecee1f47319f925roosa@google.com    WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
35461b60ceb499ee35460886f2bfaecee1f47319f925roosa@google.com                 "Channel::SetExternalMixing(enabled=%d)", enabled);
35471b60ceb499ee35460886f2bfaecee1f47319f925roosa@google.com
3548944cbeb2926feb86a687e5fda9e2ac88ea8e3001henrika@webrtc.org    if (channel_state_.Get().playing)
35491b60ceb499ee35460886f2bfaecee1f47319f925roosa@google.com    {
35501b60ceb499ee35460886f2bfaecee1f47319f925roosa@google.com        _engineStatisticsPtr->SetLastError(
35511b60ceb499ee35460886f2bfaecee1f47319f925roosa@google.com            VE_INVALID_OPERATION, kTraceError,
35521b60ceb499ee35460886f2bfaecee1f47319f925roosa@google.com            "Channel::SetExternalMixing() "
35531b60ceb499ee35460886f2bfaecee1f47319f925roosa@google.com            "external mixing cannot be changed while playing.");
35541b60ceb499ee35460886f2bfaecee1f47319f925roosa@google.com        return -1;
35551b60ceb499ee35460886f2bfaecee1f47319f925roosa@google.com    }
35561b60ceb499ee35460886f2bfaecee1f47319f925roosa@google.com
35571b60ceb499ee35460886f2bfaecee1f47319f925roosa@google.com    _externalMixing = enabled;
35581b60ceb499ee35460886f2bfaecee1f47319f925roosa@google.com
35591b60ceb499ee35460886f2bfaecee1f47319f925roosa@google.com    return 0;
35601b60ceb499ee35460886f2bfaecee1f47319f925roosa@google.com}
35611b60ceb499ee35460886f2bfaecee1f47319f925roosa@google.com
3562470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.comint
3563470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.comChannel::GetNetworkStatistics(NetworkStatistics& stats)
3564470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com{
3565c0bd7be0df67735d63f5cdd302a3b85f88239874minyue@webrtc.org    return audio_coding_->GetNetworkStatistics(&stats);
3566470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com}
3567470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
356824301a67c66e6091418e83da49cfb367ef2c6645wu@webrtc.orgvoid Channel::GetDecodingCallStatistics(AudioDecodingCallStats* stats) const {
356924301a67c66e6091418e83da49cfb367ef2c6645wu@webrtc.org  audio_coding_->GetDecodingCallStatistics(stats);
357024301a67c66e6091418e83da49cfb367ef2c6645wu@webrtc.org}
357124301a67c66e6091418e83da49cfb367ef2c6645wu@webrtc.org
35721de01354e68da71bc62c81af17afeac8ed374a18pwestin@webrtc.orgbool Channel::GetDelayEstimate(int* jitter_buffer_delay_ms,
35731de01354e68da71bc62c81af17afeac8ed374a18pwestin@webrtc.org                               int* playout_buffer_delay_ms) const {
3574743758816853df2040a21c5652b0d0e238b1512fdeadbeef  CriticalSectionScoped cs(video_sync_lock_.get());
35751de01354e68da71bc62c81af17afeac8ed374a18pwestin@webrtc.org  if (_average_jitter_buffer_delay_us == 0) {
35761de01354e68da71bc62c81af17afeac8ed374a18pwestin@webrtc.org    return false;
35771de01354e68da71bc62c81af17afeac8ed374a18pwestin@webrtc.org  }
35781de01354e68da71bc62c81af17afeac8ed374a18pwestin@webrtc.org  *jitter_buffer_delay_ms = (_average_jitter_buffer_delay_us + 500) / 1000 +
35791de01354e68da71bc62c81af17afeac8ed374a18pwestin@webrtc.org      _recPacketDelayMs;
35801de01354e68da71bc62c81af17afeac8ed374a18pwestin@webrtc.org  *playout_buffer_delay_ms = playout_delay_ms_;
35811de01354e68da71bc62c81af17afeac8ed374a18pwestin@webrtc.org  return true;
3582470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com}
3583470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
3584358057b945725390bcecc330513160aa823f651esolenberguint32_t Channel::GetDelayEstimate() const {
3585358057b945725390bcecc330513160aa823f651esolenberg  int jitter_buffer_delay_ms = 0;
3586358057b945725390bcecc330513160aa823f651esolenberg  int playout_buffer_delay_ms = 0;
3587358057b945725390bcecc330513160aa823f651esolenberg  GetDelayEstimate(&jitter_buffer_delay_ms, &playout_buffer_delay_ms);
3588358057b945725390bcecc330513160aa823f651esolenberg  return jitter_buffer_delay_ms + playout_buffer_delay_ms;
3589358057b945725390bcecc330513160aa823f651esolenberg}
3590358057b945725390bcecc330513160aa823f651esolenberg
3591743758816853df2040a21c5652b0d0e238b1512fdeadbeefint Channel::LeastRequiredDelayMs() const {
3592743758816853df2040a21c5652b0d0e238b1512fdeadbeef  return audio_coding_->LeastRequiredDelayMs();
3593743758816853df2040a21c5652b0d0e238b1512fdeadbeef}
3594743758816853df2040a21c5652b0d0e238b1512fdeadbeef
3595470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.comint
3596470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.comChannel::SetMinimumPlayoutDelay(int delayMs)
3597470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com{
3598470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3599470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                 "Channel::SetMinimumPlayoutDelay()");
3600470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    if ((delayMs < kVoiceEngineMinMinPlayoutDelayMs) ||
3601470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        (delayMs > kVoiceEngineMaxMinPlayoutDelayMs))
3602470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
3603470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        _engineStatisticsPtr->SetLastError(
3604470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            VE_INVALID_ARGUMENT, kTraceError,
3605470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            "SetMinimumPlayoutDelay() invalid min delay");
3606470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        return -1;
3607470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
3608eb524d997b877ba9b0bcaf8c85eae52bd40c37e3andrew@webrtc.org    if (audio_coding_->SetMinimumPlayoutDelay(delayMs) != 0)
3609470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
3610470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        _engineStatisticsPtr->SetLastError(
3611470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
3612470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            "SetMinimumPlayoutDelay() failed to set min playout delay");
3613470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        return -1;
3614470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
3615470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    return 0;
3616470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com}
3617470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
36181de01354e68da71bc62c81af17afeac8ed374a18pwestin@webrtc.orgint Channel::GetPlayoutTimestamp(unsigned int& timestamp) {
3619743758816853df2040a21c5652b0d0e238b1512fdeadbeef  uint32_t playout_timestamp_rtp = 0;
3620743758816853df2040a21c5652b0d0e238b1512fdeadbeef  {
3621743758816853df2040a21c5652b0d0e238b1512fdeadbeef    CriticalSectionScoped cs(video_sync_lock_.get());
3622743758816853df2040a21c5652b0d0e238b1512fdeadbeef    playout_timestamp_rtp = playout_timestamp_rtp_;
3623743758816853df2040a21c5652b0d0e238b1512fdeadbeef  }
3624743758816853df2040a21c5652b0d0e238b1512fdeadbeef  if (playout_timestamp_rtp == 0)  {
36251de01354e68da71bc62c81af17afeac8ed374a18pwestin@webrtc.org    _engineStatisticsPtr->SetLastError(
36261de01354e68da71bc62c81af17afeac8ed374a18pwestin@webrtc.org        VE_CANNOT_RETRIEVE_VALUE, kTraceError,
36271de01354e68da71bc62c81af17afeac8ed374a18pwestin@webrtc.org        "GetPlayoutTimestamp() failed to retrieve timestamp");
36281de01354e68da71bc62c81af17afeac8ed374a18pwestin@webrtc.org    return -1;
36291de01354e68da71bc62c81af17afeac8ed374a18pwestin@webrtc.org  }
3630743758816853df2040a21c5652b0d0e238b1512fdeadbeef  timestamp = playout_timestamp_rtp;
36311de01354e68da71bc62c81af17afeac8ed374a18pwestin@webrtc.org  return 0;
3632470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com}
3633470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
3634d16e839c6d29831e79312180085b6a19149df43fpbos@webrtc.orgint Channel::SetInitTimestamp(unsigned int timestamp) {
3635d16e839c6d29831e79312180085b6a19149df43fpbos@webrtc.org  WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
3636470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com               "Channel::SetInitTimestamp()");
3637d16e839c6d29831e79312180085b6a19149df43fpbos@webrtc.org  if (channel_state_.Get().sending) {
3638d16e839c6d29831e79312180085b6a19149df43fpbos@webrtc.org    _engineStatisticsPtr->SetLastError(VE_SENDING, kTraceError,
3639d16e839c6d29831e79312180085b6a19149df43fpbos@webrtc.org                                       "SetInitTimestamp() already sending");
3640d16e839c6d29831e79312180085b6a19149df43fpbos@webrtc.org    return -1;
3641d16e839c6d29831e79312180085b6a19149df43fpbos@webrtc.org  }
3642d16e839c6d29831e79312180085b6a19149df43fpbos@webrtc.org  _rtpRtcpModule->SetStartTimestamp(timestamp);
3643d16e839c6d29831e79312180085b6a19149df43fpbos@webrtc.org  return 0;
3644470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com}
3645470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
3646d16e839c6d29831e79312180085b6a19149df43fpbos@webrtc.orgint Channel::SetInitSequenceNumber(short sequenceNumber) {
3647d16e839c6d29831e79312180085b6a19149df43fpbos@webrtc.org  WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
3648d16e839c6d29831e79312180085b6a19149df43fpbos@webrtc.org               "Channel::SetInitSequenceNumber()");
3649d16e839c6d29831e79312180085b6a19149df43fpbos@webrtc.org  if (channel_state_.Get().sending) {
3650d16e839c6d29831e79312180085b6a19149df43fpbos@webrtc.org    _engineStatisticsPtr->SetLastError(
3651d16e839c6d29831e79312180085b6a19149df43fpbos@webrtc.org        VE_SENDING, kTraceError, "SetInitSequenceNumber() already sending");
3652d16e839c6d29831e79312180085b6a19149df43fpbos@webrtc.org    return -1;
3653d16e839c6d29831e79312180085b6a19149df43fpbos@webrtc.org  }
3654d16e839c6d29831e79312180085b6a19149df43fpbos@webrtc.org  _rtpRtcpModule->SetSequenceNumber(sequenceNumber);
3655d16e839c6d29831e79312180085b6a19149df43fpbos@webrtc.org  return 0;
3656470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com}
3657470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
3658470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.comint
3659822fbd8b68ffdb481b9557e2950ae8d6657c8ce6wu@webrtc.orgChannel::GetRtpRtcp(RtpRtcp** rtpRtcpModule, RtpReceiver** rtp_receiver) const
3660470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com{
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        {
38456955870806624479723addfae6dcf5d13968796cPeter Kasting            for (size_t 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
3864743758816853df2040a21c5652b0d0e238b1512fdeadbeefvoid Channel::UpdatePlayoutTimestamp(bool rtcp) {
3865743758816853df2040a21c5652b0d0e238b1512fdeadbeef  uint32_t playout_timestamp = 0;
3866743758816853df2040a21c5652b0d0e238b1512fdeadbeef
3867743758816853df2040a21c5652b0d0e238b1512fdeadbeef  if (audio_coding_->PlayoutTimestamp(&playout_timestamp) == -1)  {
3868743758816853df2040a21c5652b0d0e238b1512fdeadbeef    // This can happen if this channel has not been received any RTP packet. In
3869743758816853df2040a21c5652b0d0e238b1512fdeadbeef    // this case, NetEq is not capable of computing playout timestamp.
3870743758816853df2040a21c5652b0d0e238b1512fdeadbeef    return;
3871743758816853df2040a21c5652b0d0e238b1512fdeadbeef  }
3872743758816853df2040a21c5652b0d0e238b1512fdeadbeef
3873743758816853df2040a21c5652b0d0e238b1512fdeadbeef  uint16_t delay_ms = 0;
3874743758816853df2040a21c5652b0d0e238b1512fdeadbeef  if (_audioDeviceModulePtr->PlayoutDelay(&delay_ms) == -1) {
3875743758816853df2040a21c5652b0d0e238b1512fdeadbeef    WEBRTC_TRACE(kTraceWarning, kTraceVoice, VoEId(_instanceId,_channelId),
3876743758816853df2040a21c5652b0d0e238b1512fdeadbeef                 "Channel::UpdatePlayoutTimestamp() failed to read playout"
3877743758816853df2040a21c5652b0d0e238b1512fdeadbeef                 " delay from the ADM");
3878743758816853df2040a21c5652b0d0e238b1512fdeadbeef    _engineStatisticsPtr->SetLastError(
3879743758816853df2040a21c5652b0d0e238b1512fdeadbeef        VE_CANNOT_RETRIEVE_VALUE, kTraceError,
3880743758816853df2040a21c5652b0d0e238b1512fdeadbeef        "UpdatePlayoutTimestamp() failed to retrieve playout delay");
3881743758816853df2040a21c5652b0d0e238b1512fdeadbeef    return;
3882743758816853df2040a21c5652b0d0e238b1512fdeadbeef  }
3883743758816853df2040a21c5652b0d0e238b1512fdeadbeef
3884743758816853df2040a21c5652b0d0e238b1512fdeadbeef  jitter_buffer_playout_timestamp_ = playout_timestamp;
3885743758816853df2040a21c5652b0d0e238b1512fdeadbeef
3886743758816853df2040a21c5652b0d0e238b1512fdeadbeef  // Remove the playout delay.
3887743758816853df2040a21c5652b0d0e238b1512fdeadbeef  playout_timestamp -= (delay_ms * (GetPlayoutFrequency() / 1000));
3888743758816853df2040a21c5652b0d0e238b1512fdeadbeef
3889743758816853df2040a21c5652b0d0e238b1512fdeadbeef  WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
3890743758816853df2040a21c5652b0d0e238b1512fdeadbeef               "Channel::UpdatePlayoutTimestamp() => playoutTimestamp = %lu",
3891743758816853df2040a21c5652b0d0e238b1512fdeadbeef               playout_timestamp);
3892743758816853df2040a21c5652b0d0e238b1512fdeadbeef
3893743758816853df2040a21c5652b0d0e238b1512fdeadbeef  {
3894743758816853df2040a21c5652b0d0e238b1512fdeadbeef    CriticalSectionScoped cs(video_sync_lock_.get());
3895743758816853df2040a21c5652b0d0e238b1512fdeadbeef    if (rtcp) {
3896743758816853df2040a21c5652b0d0e238b1512fdeadbeef      playout_timestamp_rtcp_ = playout_timestamp;
3897743758816853df2040a21c5652b0d0e238b1512fdeadbeef    } else {
3898743758816853df2040a21c5652b0d0e238b1512fdeadbeef      playout_timestamp_rtp_ = playout_timestamp;
3899743758816853df2040a21c5652b0d0e238b1512fdeadbeef    }
3900743758816853df2040a21c5652b0d0e238b1512fdeadbeef    playout_delay_ms_ = delay_ms;
3901743758816853df2040a21c5652b0d0e238b1512fdeadbeef  }
3902743758816853df2040a21c5652b0d0e238b1512fdeadbeef}
3903743758816853df2040a21c5652b0d0e238b1512fdeadbeef
39041de01354e68da71bc62c81af17afeac8ed374a18pwestin@webrtc.org// Called for incoming RTP packets after successful RTP header parsing.
39051de01354e68da71bc62c81af17afeac8ed374a18pwestin@webrtc.orgvoid Channel::UpdatePacketDelay(uint32_t rtp_timestamp,
39061de01354e68da71bc62c81af17afeac8ed374a18pwestin@webrtc.org                                uint16_t sequence_number) {
39071de01354e68da71bc62c81af17afeac8ed374a18pwestin@webrtc.org  WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
39081de01354e68da71bc62c81af17afeac8ed374a18pwestin@webrtc.org               "Channel::UpdatePacketDelay(timestamp=%lu, sequenceNumber=%u)",
39091de01354e68da71bc62c81af17afeac8ed374a18pwestin@webrtc.org               rtp_timestamp, sequence_number);
3910470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
39111de01354e68da71bc62c81af17afeac8ed374a18pwestin@webrtc.org  // Get frequency of last received payload
391294454b71adc37e15fd3f5a5fc432063f05caabcbwu@webrtc.org  int rtp_receive_frequency = GetPlayoutFrequency();
3913470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
3914167b6dfc73fc2f4c47713bcbd89b58c52612983bturaj@webrtc.org  // |jitter_buffer_playout_timestamp_| updated in UpdatePlayoutTimestamp for
3915167b6dfc73fc2f4c47713bcbd89b58c52612983bturaj@webrtc.org  // every incoming packet.
3916167b6dfc73fc2f4c47713bcbd89b58c52612983bturaj@webrtc.org  uint32_t timestamp_diff_ms = (rtp_timestamp -
3917167b6dfc73fc2f4c47713bcbd89b58c52612983bturaj@webrtc.org      jitter_buffer_playout_timestamp_) / (rtp_receive_frequency / 1000);
3918d66929995ff62e92c6cb5177d059e85b902fd388henrik.lundin@webrtc.org  if (!IsNewerTimestamp(rtp_timestamp, jitter_buffer_playout_timestamp_) ||
3919d66929995ff62e92c6cb5177d059e85b902fd388henrik.lundin@webrtc.org      timestamp_diff_ms > (2 * kVoiceEngineMaxMinPlayoutDelayMs)) {
3920d66929995ff62e92c6cb5177d059e85b902fd388henrik.lundin@webrtc.org    // If |jitter_buffer_playout_timestamp_| is newer than the incoming RTP
3921d66929995ff62e92c6cb5177d059e85b902fd388henrik.lundin@webrtc.org    // timestamp, the resulting difference is negative, but is set to zero.
3922d66929995ff62e92c6cb5177d059e85b902fd388henrik.lundin@webrtc.org    // This can happen when a network glitch causes a packet to arrive late,
3923d66929995ff62e92c6cb5177d059e85b902fd388henrik.lundin@webrtc.org    // and during long comfort noise periods with clock drift.
3924d66929995ff62e92c6cb5177d059e85b902fd388henrik.lundin@webrtc.org    timestamp_diff_ms = 0;
3925d66929995ff62e92c6cb5177d059e85b902fd388henrik.lundin@webrtc.org  }
3926470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
39271de01354e68da71bc62c81af17afeac8ed374a18pwestin@webrtc.org  uint16_t packet_delay_ms = (rtp_timestamp - _previousTimestamp) /
39281de01354e68da71bc62c81af17afeac8ed374a18pwestin@webrtc.org      (rtp_receive_frequency / 1000);
3929470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
39301de01354e68da71bc62c81af17afeac8ed374a18pwestin@webrtc.org  _previousTimestamp = rtp_timestamp;
3931470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
39321de01354e68da71bc62c81af17afeac8ed374a18pwestin@webrtc.org  if (timestamp_diff_ms == 0) return;
39331de01354e68da71bc62c81af17afeac8ed374a18pwestin@webrtc.org
3934743758816853df2040a21c5652b0d0e238b1512fdeadbeef  {
3935743758816853df2040a21c5652b0d0e238b1512fdeadbeef    CriticalSectionScoped cs(video_sync_lock_.get());
39361de01354e68da71bc62c81af17afeac8ed374a18pwestin@webrtc.org
3937743758816853df2040a21c5652b0d0e238b1512fdeadbeef    if (packet_delay_ms >= 10 && packet_delay_ms <= 60) {
3938743758816853df2040a21c5652b0d0e238b1512fdeadbeef      _recPacketDelayMs = packet_delay_ms;
3939743758816853df2040a21c5652b0d0e238b1512fdeadbeef    }
39401de01354e68da71bc62c81af17afeac8ed374a18pwestin@webrtc.org
3941743758816853df2040a21c5652b0d0e238b1512fdeadbeef    if (_average_jitter_buffer_delay_us == 0) {
3942743758816853df2040a21c5652b0d0e238b1512fdeadbeef      _average_jitter_buffer_delay_us = timestamp_diff_ms * 1000;
3943743758816853df2040a21c5652b0d0e238b1512fdeadbeef      return;
3944743758816853df2040a21c5652b0d0e238b1512fdeadbeef    }
3945743758816853df2040a21c5652b0d0e238b1512fdeadbeef
3946743758816853df2040a21c5652b0d0e238b1512fdeadbeef    // Filter average delay value using exponential filter (alpha is
3947743758816853df2040a21c5652b0d0e238b1512fdeadbeef    // 7/8). We derive 1000 *_average_jitter_buffer_delay_us here (reduces
3948743758816853df2040a21c5652b0d0e238b1512fdeadbeef    // risk of rounding error) and compensate for it in GetDelayEstimate()
3949743758816853df2040a21c5652b0d0e238b1512fdeadbeef    // later.
3950743758816853df2040a21c5652b0d0e238b1512fdeadbeef    _average_jitter_buffer_delay_us = (_average_jitter_buffer_delay_us * 7 +
3951743758816853df2040a21c5652b0d0e238b1512fdeadbeef        1000 * timestamp_diff_ms + 500) / 8;
3952743758816853df2040a21c5652b0d0e238b1512fdeadbeef  }
3953470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com}
3954470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
3955470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.comvoid
3956470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.comChannel::RegisterReceiveCodecsToRTPModule()
3957470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com{
3958470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3959470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                 "Channel::RegisterReceiveCodecsToRTPModule()");
3960470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
3961470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    CodecInst codec;
39626141e13873d0fdea626de08dfec2efa2c9171c76pbos@webrtc.org    const uint8_t nSupportedCodecs = AudioCodingModule::NumberOfCodecs();
3963470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
3964470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    for (int idx = 0; idx < nSupportedCodecs; idx++)
3965470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
3966470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        // Open up the RTP/RTCP receiver for all supported codecs
3967eb524d997b877ba9b0bcaf8c85eae52bd40c37e3andrew@webrtc.org        if ((audio_coding_->Codec(idx, &codec) == -1) ||
3968822fbd8b68ffdb481b9557e2950ae8d6657c8ce6wu@webrtc.org            (rtp_receiver_->RegisterReceivePayload(
3969822fbd8b68ffdb481b9557e2950ae8d6657c8ce6wu@webrtc.org                codec.plname,
3970822fbd8b68ffdb481b9557e2950ae8d6657c8ce6wu@webrtc.org                codec.pltype,
3971822fbd8b68ffdb481b9557e2950ae8d6657c8ce6wu@webrtc.org                codec.plfreq,
3972822fbd8b68ffdb481b9557e2950ae8d6657c8ce6wu@webrtc.org                codec.channels,
3973822fbd8b68ffdb481b9557e2950ae8d6657c8ce6wu@webrtc.org                (codec.rate < 0) ? 0 : codec.rate) == -1))
3974470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        {
3975d5c75b1a0ba1548d3561109e3e5e63757509e9aePeter Boström            WEBRTC_TRACE(kTraceWarning,
3976470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                         kTraceVoice,
3977470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                         VoEId(_instanceId, _channelId),
3978470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                         "Channel::RegisterReceiveCodecsToRTPModule() unable"
39796955870806624479723addfae6dcf5d13968796cPeter Kasting                         " to register %s (%d/%d/%" PRIuS "/%d) to RTP/RTCP "
39806955870806624479723addfae6dcf5d13968796cPeter Kasting                         "receiver",
3981470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                         codec.plname, codec.pltype, codec.plfreq,
3982470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                         codec.channels, codec.rate);
3983470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        }
3984470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        else
3985470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        {
3986d5c75b1a0ba1548d3561109e3e5e63757509e9aePeter Boström            WEBRTC_TRACE(kTraceInfo,
3987470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                         kTraceVoice,
3988470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                         VoEId(_instanceId, _channelId),
3989470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                         "Channel::RegisterReceiveCodecsToRTPModule() %s "
39906955870806624479723addfae6dcf5d13968796cPeter Kasting                         "(%d/%d/%" PRIuS "/%d) has been added to the RTP/RTCP "
3991470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                         "receiver",
3992470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                         codec.plname, codec.pltype, codec.plfreq,
3993470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                         codec.channels, codec.rate);
3994470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        }
3995470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
3996470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com}
3997470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
39988c8ad85c5d70c38cea82f5b17794a4e7ab4cf531turaj@webrtc.org// Assuming this method is called with valid payload type.
399942259e7ebc7126f5a7036940fcab65b3f8d2af38turaj@webrtc.orgint Channel::SetRedPayloadType(int red_payload_type) {
400042259e7ebc7126f5a7036940fcab65b3f8d2af38turaj@webrtc.org  CodecInst codec;
400142259e7ebc7126f5a7036940fcab65b3f8d2af38turaj@webrtc.org  bool found_red = false;
400242259e7ebc7126f5a7036940fcab65b3f8d2af38turaj@webrtc.org
400342259e7ebc7126f5a7036940fcab65b3f8d2af38turaj@webrtc.org  // Get default RED settings from the ACM database
400442259e7ebc7126f5a7036940fcab65b3f8d2af38turaj@webrtc.org  const int num_codecs = AudioCodingModule::NumberOfCodecs();
400542259e7ebc7126f5a7036940fcab65b3f8d2af38turaj@webrtc.org  for (int idx = 0; idx < num_codecs; idx++) {
4006eb524d997b877ba9b0bcaf8c85eae52bd40c37e3andrew@webrtc.org    audio_coding_->Codec(idx, &codec);
400742259e7ebc7126f5a7036940fcab65b3f8d2af38turaj@webrtc.org    if (!STR_CASE_CMP(codec.plname, "RED")) {
400842259e7ebc7126f5a7036940fcab65b3f8d2af38turaj@webrtc.org      found_red = true;
400942259e7ebc7126f5a7036940fcab65b3f8d2af38turaj@webrtc.org      break;
401042259e7ebc7126f5a7036940fcab65b3f8d2af38turaj@webrtc.org    }
401142259e7ebc7126f5a7036940fcab65b3f8d2af38turaj@webrtc.org  }
401242259e7ebc7126f5a7036940fcab65b3f8d2af38turaj@webrtc.org
401342259e7ebc7126f5a7036940fcab65b3f8d2af38turaj@webrtc.org  if (!found_red) {
401442259e7ebc7126f5a7036940fcab65b3f8d2af38turaj@webrtc.org    _engineStatisticsPtr->SetLastError(
401542259e7ebc7126f5a7036940fcab65b3f8d2af38turaj@webrtc.org        VE_CODEC_ERROR, kTraceError,
401642259e7ebc7126f5a7036940fcab65b3f8d2af38turaj@webrtc.org        "SetRedPayloadType() RED is not supported");
401742259e7ebc7126f5a7036940fcab65b3f8d2af38turaj@webrtc.org    return -1;
401842259e7ebc7126f5a7036940fcab65b3f8d2af38turaj@webrtc.org  }
401942259e7ebc7126f5a7036940fcab65b3f8d2af38turaj@webrtc.org
40209d532fd2752290e85aa804f29ab9aa6c017c9208turaj@webrtc.org  codec.pltype = red_payload_type;
4021eb524d997b877ba9b0bcaf8c85eae52bd40c37e3andrew@webrtc.org  if (audio_coding_->RegisterSendCodec(codec) < 0) {
402242259e7ebc7126f5a7036940fcab65b3f8d2af38turaj@webrtc.org    _engineStatisticsPtr->SetLastError(
402342259e7ebc7126f5a7036940fcab65b3f8d2af38turaj@webrtc.org        VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
402442259e7ebc7126f5a7036940fcab65b3f8d2af38turaj@webrtc.org        "SetRedPayloadType() RED registration in ACM module failed");
402542259e7ebc7126f5a7036940fcab65b3f8d2af38turaj@webrtc.org    return -1;
402642259e7ebc7126f5a7036940fcab65b3f8d2af38turaj@webrtc.org  }
402742259e7ebc7126f5a7036940fcab65b3f8d2af38turaj@webrtc.org
402842259e7ebc7126f5a7036940fcab65b3f8d2af38turaj@webrtc.org  if (_rtpRtcpModule->SetSendREDPayloadType(red_payload_type) != 0) {
402942259e7ebc7126f5a7036940fcab65b3f8d2af38turaj@webrtc.org    _engineStatisticsPtr->SetLastError(
403042259e7ebc7126f5a7036940fcab65b3f8d2af38turaj@webrtc.org        VE_RTP_RTCP_MODULE_ERROR, kTraceError,
403142259e7ebc7126f5a7036940fcab65b3f8d2af38turaj@webrtc.org        "SetRedPayloadType() RED registration in RTP/RTCP module failed");
403242259e7ebc7126f5a7036940fcab65b3f8d2af38turaj@webrtc.org    return -1;
403342259e7ebc7126f5a7036940fcab65b3f8d2af38turaj@webrtc.org  }
403442259e7ebc7126f5a7036940fcab65b3f8d2af38turaj@webrtc.org  return 0;
403542259e7ebc7126f5a7036940fcab65b3f8d2af38turaj@webrtc.org}
403642259e7ebc7126f5a7036940fcab65b3f8d2af38turaj@webrtc.org
4037ebdb0e3ad0a787bee066d12cdcd115a38b0a10d1wu@webrtc.orgint Channel::SetSendRtpHeaderExtension(bool enable, RTPExtensionType type,
4038ebdb0e3ad0a787bee066d12cdcd115a38b0a10d1wu@webrtc.org                                       unsigned char id) {
4039ebdb0e3ad0a787bee066d12cdcd115a38b0a10d1wu@webrtc.org  int error = 0;
4040ebdb0e3ad0a787bee066d12cdcd115a38b0a10d1wu@webrtc.org  _rtpRtcpModule->DeregisterSendRtpHeaderExtension(type);
4041ebdb0e3ad0a787bee066d12cdcd115a38b0a10d1wu@webrtc.org  if (enable) {
4042ebdb0e3ad0a787bee066d12cdcd115a38b0a10d1wu@webrtc.org    error = _rtpRtcpModule->RegisterSendRtpHeaderExtension(type, id);
4043ebdb0e3ad0a787bee066d12cdcd115a38b0a10d1wu@webrtc.org  }
4044ebdb0e3ad0a787bee066d12cdcd115a38b0a10d1wu@webrtc.org  return error;
4045ebdb0e3ad0a787bee066d12cdcd115a38b0a10d1wu@webrtc.org}
4046c1a40a7b68a8d253b0ba32b89f3126931eeaeab3minyue@webrtc.org
404794454b71adc37e15fd3f5a5fc432063f05caabcbwu@webrtc.orgint32_t Channel::GetPlayoutFrequency() {
404894454b71adc37e15fd3f5a5fc432063f05caabcbwu@webrtc.org  int32_t playout_frequency = audio_coding_->PlayoutFrequency();
404994454b71adc37e15fd3f5a5fc432063f05caabcbwu@webrtc.org  CodecInst current_recive_codec;
405094454b71adc37e15fd3f5a5fc432063f05caabcbwu@webrtc.org  if (audio_coding_->ReceiveCodec(&current_recive_codec) == 0) {
405194454b71adc37e15fd3f5a5fc432063f05caabcbwu@webrtc.org    if (STR_CASE_CMP("G722", current_recive_codec.plname) == 0) {
405294454b71adc37e15fd3f5a5fc432063f05caabcbwu@webrtc.org      // Even though the actual sampling rate for G.722 audio is
405394454b71adc37e15fd3f5a5fc432063f05caabcbwu@webrtc.org      // 16,000 Hz, the RTP clock rate for the G722 payload format is
405494454b71adc37e15fd3f5a5fc432063f05caabcbwu@webrtc.org      // 8,000 Hz because that value was erroneously assigned in
405594454b71adc37e15fd3f5a5fc432063f05caabcbwu@webrtc.org      // RFC 1890 and must remain unchanged for backward compatibility.
405694454b71adc37e15fd3f5a5fc432063f05caabcbwu@webrtc.org      playout_frequency = 8000;
405794454b71adc37e15fd3f5a5fc432063f05caabcbwu@webrtc.org    } else if (STR_CASE_CMP("opus", current_recive_codec.plname) == 0) {
405894454b71adc37e15fd3f5a5fc432063f05caabcbwu@webrtc.org      // We are resampling Opus internally to 32,000 Hz until all our
405994454b71adc37e15fd3f5a5fc432063f05caabcbwu@webrtc.org      // DSP routines can operate at 48,000 Hz, but the RTP clock
406094454b71adc37e15fd3f5a5fc432063f05caabcbwu@webrtc.org      // rate for the Opus payload format is standardized to 48,000 Hz,
406194454b71adc37e15fd3f5a5fc432063f05caabcbwu@webrtc.org      // because that is the maximum supported decoding sampling rate.
406294454b71adc37e15fd3f5a5fc432063f05caabcbwu@webrtc.org      playout_frequency = 48000;
406394454b71adc37e15fd3f5a5fc432063f05caabcbwu@webrtc.org    }
406494454b71adc37e15fd3f5a5fc432063f05caabcbwu@webrtc.org  }
406594454b71adc37e15fd3f5a5fc432063f05caabcbwu@webrtc.org  return playout_frequency;
406694454b71adc37e15fd3f5a5fc432063f05caabcbwu@webrtc.org}
406794454b71adc37e15fd3f5a5fc432063f05caabcbwu@webrtc.org
40682013aeced2b7821a407f302802c4a16fd02728b1Minyueint64_t Channel::GetRTT(bool allow_associate_channel) const {
4069da903eaabbb6c6830efcafc3c2ade1d36f511e43pbos  RtcpMode method = _rtpRtcpModule->RTCP();
4070da903eaabbb6c6830efcafc3c2ade1d36f511e43pbos  if (method == RtcpMode::kOff) {
40712b58a4433f16c510d56b1d16d2e3bb882b184861minyue@webrtc.org    return 0;
40722b58a4433f16c510d56b1d16d2e3bb882b184861minyue@webrtc.org  }
40732b58a4433f16c510d56b1d16d2e3bb882b184861minyue@webrtc.org  std::vector<RTCPReportBlock> report_blocks;
40742b58a4433f16c510d56b1d16d2e3bb882b184861minyue@webrtc.org  _rtpRtcpModule->RemoteRTCPStat(&report_blocks);
40752013aeced2b7821a407f302802c4a16fd02728b1Minyue
40762013aeced2b7821a407f302802c4a16fd02728b1Minyue  int64_t rtt = 0;
40772b58a4433f16c510d56b1d16d2e3bb882b184861minyue@webrtc.org  if (report_blocks.empty()) {
40782013aeced2b7821a407f302802c4a16fd02728b1Minyue    if (allow_associate_channel) {
40792013aeced2b7821a407f302802c4a16fd02728b1Minyue      CriticalSectionScoped lock(assoc_send_channel_lock_.get());
40802013aeced2b7821a407f302802c4a16fd02728b1Minyue      Channel* channel = associate_send_channel_.channel();
40812013aeced2b7821a407f302802c4a16fd02728b1Minyue      // Tries to get RTT from an associated channel. This is important for
40822013aeced2b7821a407f302802c4a16fd02728b1Minyue      // receive-only channels.
40832013aeced2b7821a407f302802c4a16fd02728b1Minyue      if (channel) {
40842013aeced2b7821a407f302802c4a16fd02728b1Minyue        // To prevent infinite recursion and deadlock, calling GetRTT of
40852013aeced2b7821a407f302802c4a16fd02728b1Minyue        // associate channel should always use "false" for argument:
40862013aeced2b7821a407f302802c4a16fd02728b1Minyue        // |allow_associate_channel|.
40872013aeced2b7821a407f302802c4a16fd02728b1Minyue        rtt = channel->GetRTT(false);
40882013aeced2b7821a407f302802c4a16fd02728b1Minyue      }
40892013aeced2b7821a407f302802c4a16fd02728b1Minyue    }
40902013aeced2b7821a407f302802c4a16fd02728b1Minyue    return rtt;
40912b58a4433f16c510d56b1d16d2e3bb882b184861minyue@webrtc.org  }
40922b58a4433f16c510d56b1d16d2e3bb882b184861minyue@webrtc.org
40932b58a4433f16c510d56b1d16d2e3bb882b184861minyue@webrtc.org  uint32_t remoteSSRC = rtp_receiver_->SSRC();
40942b58a4433f16c510d56b1d16d2e3bb882b184861minyue@webrtc.org  std::vector<RTCPReportBlock>::const_iterator it = report_blocks.begin();
40952b58a4433f16c510d56b1d16d2e3bb882b184861minyue@webrtc.org  for (; it != report_blocks.end(); ++it) {
40962b58a4433f16c510d56b1d16d2e3bb882b184861minyue@webrtc.org    if (it->remoteSSRC == remoteSSRC)
40972b58a4433f16c510d56b1d16d2e3bb882b184861minyue@webrtc.org      break;
40982b58a4433f16c510d56b1d16d2e3bb882b184861minyue@webrtc.org  }
40992b58a4433f16c510d56b1d16d2e3bb882b184861minyue@webrtc.org  if (it == report_blocks.end()) {
41002b58a4433f16c510d56b1d16d2e3bb882b184861minyue@webrtc.org    // We have not received packets with SSRC matching the report blocks.
41012b58a4433f16c510d56b1d16d2e3bb882b184861minyue@webrtc.org    // To calculate RTT we try with the SSRC of the first report block.
41022b58a4433f16c510d56b1d16d2e3bb882b184861minyue@webrtc.org    // This is very important for send-only channels where we don't know
41032b58a4433f16c510d56b1d16d2e3bb882b184861minyue@webrtc.org    // the SSRC of the other end.
41042b58a4433f16c510d56b1d16d2e3bb882b184861minyue@webrtc.org    remoteSSRC = report_blocks[0].remoteSSRC;
41052b58a4433f16c510d56b1d16d2e3bb882b184861minyue@webrtc.org  }
41062013aeced2b7821a407f302802c4a16fd02728b1Minyue
410716825b1a828bb4ff40f7682040e43a239b7b8ca3pkasting@chromium.org  int64_t avg_rtt = 0;
410816825b1a828bb4ff40f7682040e43a239b7b8ca3pkasting@chromium.org  int64_t max_rtt= 0;
410916825b1a828bb4ff40f7682040e43a239b7b8ca3pkasting@chromium.org  int64_t min_rtt = 0;
41102b58a4433f16c510d56b1d16d2e3bb882b184861minyue@webrtc.org  if (_rtpRtcpModule->RTT(remoteSSRC, &rtt, &avg_rtt, &min_rtt, &max_rtt)
41112b58a4433f16c510d56b1d16d2e3bb882b184861minyue@webrtc.org      != 0) {
41122b58a4433f16c510d56b1d16d2e3bb882b184861minyue@webrtc.org    return 0;
41132b58a4433f16c510d56b1d16d2e3bb882b184861minyue@webrtc.org  }
411416825b1a828bb4ff40f7682040e43a239b7b8ca3pkasting@chromium.org  return rtt;
41152b58a4433f16c510d56b1d16d2e3bb882b184861minyue@webrtc.org}
41162b58a4433f16c510d56b1d16d2e3bb882b184861minyue@webrtc.org
4117d900e8bea84c474696bf0219aed1353ce65ffd8epbos@webrtc.org}  // namespace voe
4118d900e8bea84c474696bf0219aed1353ce65ffd8epbos@webrtc.org}  // namespace webrtc
4119