blob: 24a7ce801edb16bb17d713d270379c9c26efb70a [file] [log] [blame]
solenberg566ef242015-11-06 15:34:49 -08001/*
2 * Copyright (c) 2015 The WebRTC project authors. All Rights Reserved.
3 *
4 * Use of this source code is governed by a BSD-style license
5 * that can be found in the LICENSE file in the root of the source
6 * tree. An additional intellectual property rights grant can be found
7 * in the file PATENTS. All contributing project authors may
8 * be found in the AUTHORS file in the root of the source tree.
9 */
10
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020011#include "audio/audio_state.h"
solenberg566ef242015-11-06 15:34:49 -080012
Fredrik Solenberg2a877972017-12-15 16:42:15 +010013#include <algorithm>
14#include <utility>
15#include <vector>
16
Fredrik Solenbergd5247512017-12-18 22:41:03 +010017#include "audio/audio_receive_stream.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020018#include "modules/audio_device/include/audio_device.h"
19#include "rtc_base/atomicops.h"
20#include "rtc_base/checks.h"
21#include "rtc_base/logging.h"
henrika5f6bf242017-11-01 11:06:56 +010022#include "rtc_base/ptr_util.h"
23#include "rtc_base/thread.h"
solenberg566ef242015-11-06 15:34:49 -080024
25namespace webrtc {
26namespace internal {
27
28AudioState::AudioState(const AudioState::Config& config)
aleloidd310712016-11-17 06:28:59 -080029 : config_(config),
Fredrik Solenberg2a877972017-12-15 16:42:15 +010030 audio_transport_(config_.audio_mixer,
31 config_.audio_processing.get(),
32 config_.audio_device_module.get()) {
solenberg566ef242015-11-06 15:34:49 -080033 process_thread_checker_.DetachFromThread();
aleloi10111bc2016-11-17 06:48:48 -080034 RTC_DCHECK(config_.audio_mixer);
Fredrik Solenbergaaedf752017-12-18 13:09:12 +010035 RTC_DCHECK(config_.audio_device_module);
solenberg566ef242015-11-06 15:34:49 -080036}
37
38AudioState::~AudioState() {
39 RTC_DCHECK(thread_checker_.CalledOnValidThread());
Fredrik Solenbergd5247512017-12-18 22:41:03 +010040 RTC_DCHECK(receiving_streams_.empty());
Fredrik Solenberg2a877972017-12-15 16:42:15 +010041 RTC_DCHECK(sending_streams_.empty());
solenberg566ef242015-11-06 15:34:49 -080042}
43
solenberg566ef242015-11-06 15:34:49 -080044bool AudioState::typing_noise_detected() const {
45 RTC_DCHECK(thread_checker_.CalledOnValidThread());
Fredrik Solenberg2a877972017-12-15 16:42:15 +010046 return audio_transport_.typing_noise_detected();
47}
48
Fredrik Solenbergd5247512017-12-18 22:41:03 +010049void AudioState::AddReceivingStream(webrtc::AudioReceiveStream* stream) {
50 RTC_DCHECK(thread_checker_.CalledOnValidThread());
51 RTC_DCHECK_EQ(0, receiving_streams_.count(stream));
52 receiving_streams_.insert(stream);
53 if (!config_.audio_mixer->AddSource(
54 static_cast<internal::AudioReceiveStream*>(stream))) {
55 RTC_LOG(LS_ERROR) << "Failed to add source to mixer.";
56 }
57
58 // Make sure playback is initialized; start playing if enabled.
59 auto* adm = config_.audio_device_module.get();
60 if (!adm->Playing()) {
61 if (adm->InitPlayout() == 0) {
62 if (playout_enabled_) {
63 adm->StartPlayout();
64 }
65 } else {
66 RTC_DLOG_F(LS_ERROR) << "Failed to initialize playout.";
67 }
68 }
69}
70
71void AudioState::RemoveReceivingStream(webrtc::AudioReceiveStream* stream) {
72 RTC_DCHECK(thread_checker_.CalledOnValidThread());
73 auto count = receiving_streams_.erase(stream);
74 RTC_DCHECK_EQ(1, count);
75 config_.audio_mixer->RemoveSource(
76 static_cast<internal::AudioReceiveStream*>(stream));
77 if (receiving_streams_.empty()) {
78 config_.audio_device_module->StopPlayout();
79 }
80}
81
Fredrik Solenberg2a877972017-12-15 16:42:15 +010082void AudioState::AddSendingStream(webrtc::AudioSendStream* stream,
83 int sample_rate_hz, size_t num_channels) {
84 RTC_DCHECK(thread_checker_.CalledOnValidThread());
85 auto& properties = sending_streams_[stream];
86 properties.sample_rate_hz = sample_rate_hz;
87 properties.num_channels = num_channels;
88 UpdateAudioTransportWithSendingStreams();
Fredrik Solenbergaaedf752017-12-18 13:09:12 +010089
90 // Make sure recording is initialized; start recording if enabled.
91 auto* adm = config_.audio_device_module.get();
92 if (!adm->Recording()) {
93 if (adm->InitRecording() == 0) {
94 if (recording_enabled_) {
95 adm->StartRecording();
96 }
97 } else {
98 RTC_DLOG_F(LS_ERROR) << "Failed to initialize recording.";
99 }
100 }
Fredrik Solenberg2a877972017-12-15 16:42:15 +0100101}
102
103void AudioState::RemoveSendingStream(webrtc::AudioSendStream* stream) {
104 RTC_DCHECK(thread_checker_.CalledOnValidThread());
105 auto count = sending_streams_.erase(stream);
106 RTC_DCHECK_EQ(1, count);
107 UpdateAudioTransportWithSendingStreams();
Fredrik Solenbergaaedf752017-12-18 13:09:12 +0100108 if (sending_streams_.empty()) {
109 config_.audio_device_module->StopRecording();
110 }
solenberg566ef242015-11-06 15:34:49 -0800111}
112
henrika5f6bf242017-11-01 11:06:56 +0100113void AudioState::SetPlayout(bool enabled) {
Mirko Bonadei675513b2017-11-09 11:09:25 +0100114 RTC_LOG(INFO) << "SetPlayout(" << enabled << ")";
henrika5f6bf242017-11-01 11:06:56 +0100115 RTC_DCHECK(thread_checker_.CalledOnValidThread());
Fredrik Solenbergd5247512017-12-18 22:41:03 +0100116 if (playout_enabled_ != enabled) {
117 playout_enabled_ = enabled;
118 if (enabled) {
119 null_audio_poller_.reset();
120 if (!receiving_streams_.empty()) {
121 config_.audio_device_module->StartPlayout();
122 }
123 } else {
124 config_.audio_device_module->StopPlayout();
125 null_audio_poller_ =
126 rtc::MakeUnique<NullAudioPoller>(&audio_transport_);
127 }
henrika5f6bf242017-11-01 11:06:56 +0100128 }
129}
130
131void AudioState::SetRecording(bool enabled) {
Mirko Bonadei675513b2017-11-09 11:09:25 +0100132 RTC_LOG(INFO) << "SetRecording(" << enabled << ")";
henrika5f6bf242017-11-01 11:06:56 +0100133 RTC_DCHECK(thread_checker_.CalledOnValidThread());
Fredrik Solenbergaaedf752017-12-18 13:09:12 +0100134 if (recording_enabled_ != enabled) {
135 recording_enabled_ = enabled;
136 if (enabled) {
137 if (!sending_streams_.empty()) {
138 config_.audio_device_module->StartRecording();
139 }
140 } else {
141 config_.audio_device_module->StopRecording();
142 }
143 }
Fredrik Solenberg2a877972017-12-15 16:42:15 +0100144}
145
146AudioState::Stats AudioState::GetAudioInputStats() const {
147 RTC_DCHECK(thread_checker_.CalledOnValidThread());
148 const voe::AudioLevel& audio_level = audio_transport_.audio_level();
149 Stats result;
150 result.audio_level = audio_level.LevelFullRange();
151 RTC_DCHECK_LE(0, result.audio_level);
152 RTC_DCHECK_GE(32767, result.audio_level);
153 result.quantized_audio_level = audio_level.Level();
154 RTC_DCHECK_LE(0, result.quantized_audio_level);
155 RTC_DCHECK_GE(9, result.quantized_audio_level);
156 result.total_energy = audio_level.TotalEnergy();
157 result.total_duration = audio_level.TotalDuration();
158 return result;
159}
160
161void AudioState::SetStereoChannelSwapping(bool enable) {
162 RTC_DCHECK(thread_checker_.CalledOnValidThread());
163 audio_transport_.SetStereoChannelSwapping(enable);
henrika5f6bf242017-11-01 11:06:56 +0100164}
165
solenberg566ef242015-11-06 15:34:49 -0800166// Reference count; implementation copied from rtc::RefCountedObject.
Niels Möller6f72f562017-10-19 13:15:17 +0200167void AudioState::AddRef() const {
168 rtc::AtomicOps::Increment(&ref_count_);
solenberg566ef242015-11-06 15:34:49 -0800169}
170
171// Reference count; implementation copied from rtc::RefCountedObject.
Niels Möller6f72f562017-10-19 13:15:17 +0200172rtc::RefCountReleaseStatus AudioState::Release() const {
173 if (rtc::AtomicOps::Decrement(&ref_count_) == 0) {
solenberg566ef242015-11-06 15:34:49 -0800174 delete this;
Niels Möller6f72f562017-10-19 13:15:17 +0200175 return rtc::RefCountReleaseStatus::kDroppedLastRef;
solenberg566ef242015-11-06 15:34:49 -0800176 }
Niels Möller6f72f562017-10-19 13:15:17 +0200177 return rtc::RefCountReleaseStatus::kOtherRefsRemained;
solenberg566ef242015-11-06 15:34:49 -0800178}
Fredrik Solenberg2a877972017-12-15 16:42:15 +0100179
180void AudioState::UpdateAudioTransportWithSendingStreams() {
181 RTC_DCHECK(thread_checker_.CalledOnValidThread());
Fredrik Solenbergd5247512017-12-18 22:41:03 +0100182 std::vector<webrtc::AudioSendStream*> sending_streams;
Fredrik Solenberg2a877972017-12-15 16:42:15 +0100183 int max_sample_rate_hz = 8000;
184 size_t max_num_channels = 1;
185 for (const auto& kv : sending_streams_) {
186 sending_streams.push_back(kv.first);
187 max_sample_rate_hz = std::max(max_sample_rate_hz, kv.second.sample_rate_hz);
188 max_num_channels = std::max(max_num_channels, kv.second.num_channels);
189 }
190 audio_transport_.UpdateSendingStreams(std::move(sending_streams),
191 max_sample_rate_hz, max_num_channels);
192}
solenberg566ef242015-11-06 15:34:49 -0800193} // namespace internal
194
195rtc::scoped_refptr<AudioState> AudioState::Create(
196 const AudioState::Config& config) {
197 return rtc::scoped_refptr<AudioState>(new internal::AudioState(config));
198}
199} // namespace webrtc