blob: 7d473ae6317d67dec42e3f509cd0d9ed78c73567 [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
Karl Wiberg918f50c2018-07-05 11:40:33 +020017#include "absl/memory/memory.h"
Fredrik Solenbergd5247512017-12-18 22:41:03 +010018#include "audio/audio_receive_stream.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020019#include "modules/audio_device/include/audio_device.h"
20#include "rtc_base/atomicops.h"
21#include "rtc_base/checks.h"
22#include "rtc_base/logging.h"
henrika5f6bf242017-11-01 11:06:56 +010023#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),
Yves Gerey665174f2018-06-19 15:03:05 +020030 audio_transport_(config_.audio_mixer, config_.audio_processing.get()) {
solenberg566ef242015-11-06 15:34:49 -080031 process_thread_checker_.DetachFromThread();
aleloi10111bc2016-11-17 06:48:48 -080032 RTC_DCHECK(config_.audio_mixer);
Fredrik Solenbergaaedf752017-12-18 13:09:12 +010033 RTC_DCHECK(config_.audio_device_module);
solenberg566ef242015-11-06 15:34:49 -080034}
35
36AudioState::~AudioState() {
37 RTC_DCHECK(thread_checker_.CalledOnValidThread());
Fredrik Solenbergd5247512017-12-18 22:41:03 +010038 RTC_DCHECK(receiving_streams_.empty());
Fredrik Solenberg2a877972017-12-15 16:42:15 +010039 RTC_DCHECK(sending_streams_.empty());
solenberg566ef242015-11-06 15:34:49 -080040}
41
Mirko Bonadei8fdcac32018-08-28 16:30:18 +020042AudioProcessing* AudioState::audio_processing() {
43 RTC_DCHECK(config_.audio_processing);
44 return config_.audio_processing.get();
45}
46
47AudioTransport* AudioState::audio_transport() {
48 return &audio_transport_;
49}
50
solenberg566ef242015-11-06 15:34:49 -080051bool AudioState::typing_noise_detected() const {
52 RTC_DCHECK(thread_checker_.CalledOnValidThread());
Fredrik Solenberg2a877972017-12-15 16:42:15 +010053 return audio_transport_.typing_noise_detected();
54}
55
Fredrik Solenbergd5247512017-12-18 22:41:03 +010056void AudioState::AddReceivingStream(webrtc::AudioReceiveStream* stream) {
57 RTC_DCHECK(thread_checker_.CalledOnValidThread());
58 RTC_DCHECK_EQ(0, receiving_streams_.count(stream));
59 receiving_streams_.insert(stream);
60 if (!config_.audio_mixer->AddSource(
Yves Gerey665174f2018-06-19 15:03:05 +020061 static_cast<internal::AudioReceiveStream*>(stream))) {
Jonas Olsson24ea8222018-01-25 10:14:29 +010062 RTC_DLOG(LS_ERROR) << "Failed to add source to mixer.";
Fredrik Solenbergd5247512017-12-18 22:41:03 +010063 }
64
65 // Make sure playback is initialized; start playing if enabled.
66 auto* adm = config_.audio_device_module.get();
67 if (!adm->Playing()) {
68 if (adm->InitPlayout() == 0) {
69 if (playout_enabled_) {
70 adm->StartPlayout();
71 }
72 } else {
73 RTC_DLOG_F(LS_ERROR) << "Failed to initialize playout.";
74 }
75 }
76}
77
78void AudioState::RemoveReceivingStream(webrtc::AudioReceiveStream* stream) {
79 RTC_DCHECK(thread_checker_.CalledOnValidThread());
80 auto count = receiving_streams_.erase(stream);
81 RTC_DCHECK_EQ(1, count);
82 config_.audio_mixer->RemoveSource(
83 static_cast<internal::AudioReceiveStream*>(stream));
84 if (receiving_streams_.empty()) {
85 config_.audio_device_module->StopPlayout();
86 }
87}
88
Fredrik Solenberg2a877972017-12-15 16:42:15 +010089void AudioState::AddSendingStream(webrtc::AudioSendStream* stream,
Yves Gerey665174f2018-06-19 15:03:05 +020090 int sample_rate_hz,
91 size_t num_channels) {
Fredrik Solenberg2a877972017-12-15 16:42:15 +010092 RTC_DCHECK(thread_checker_.CalledOnValidThread());
93 auto& properties = sending_streams_[stream];
94 properties.sample_rate_hz = sample_rate_hz;
95 properties.num_channels = num_channels;
96 UpdateAudioTransportWithSendingStreams();
Fredrik Solenbergaaedf752017-12-18 13:09:12 +010097
98 // Make sure recording is initialized; start recording if enabled.
99 auto* adm = config_.audio_device_module.get();
100 if (!adm->Recording()) {
101 if (adm->InitRecording() == 0) {
102 if (recording_enabled_) {
103 adm->StartRecording();
104 }
105 } else {
106 RTC_DLOG_F(LS_ERROR) << "Failed to initialize recording.";
107 }
108 }
Fredrik Solenberg2a877972017-12-15 16:42:15 +0100109}
110
111void AudioState::RemoveSendingStream(webrtc::AudioSendStream* stream) {
112 RTC_DCHECK(thread_checker_.CalledOnValidThread());
113 auto count = sending_streams_.erase(stream);
114 RTC_DCHECK_EQ(1, count);
115 UpdateAudioTransportWithSendingStreams();
Fredrik Solenbergaaedf752017-12-18 13:09:12 +0100116 if (sending_streams_.empty()) {
117 config_.audio_device_module->StopRecording();
118 }
solenberg566ef242015-11-06 15:34:49 -0800119}
120
henrika5f6bf242017-11-01 11:06:56 +0100121void AudioState::SetPlayout(bool enabled) {
Mirko Bonadei675513b2017-11-09 11:09:25 +0100122 RTC_LOG(INFO) << "SetPlayout(" << enabled << ")";
henrika5f6bf242017-11-01 11:06:56 +0100123 RTC_DCHECK(thread_checker_.CalledOnValidThread());
Fredrik Solenbergd5247512017-12-18 22:41:03 +0100124 if (playout_enabled_ != enabled) {
125 playout_enabled_ = enabled;
126 if (enabled) {
127 null_audio_poller_.reset();
128 if (!receiving_streams_.empty()) {
129 config_.audio_device_module->StartPlayout();
130 }
131 } else {
132 config_.audio_device_module->StopPlayout();
Karl Wiberg918f50c2018-07-05 11:40:33 +0200133 null_audio_poller_ =
134 absl::make_unique<NullAudioPoller>(&audio_transport_);
Fredrik Solenbergd5247512017-12-18 22:41:03 +0100135 }
henrika5f6bf242017-11-01 11:06:56 +0100136 }
137}
138
139void AudioState::SetRecording(bool enabled) {
Mirko Bonadei675513b2017-11-09 11:09:25 +0100140 RTC_LOG(INFO) << "SetRecording(" << enabled << ")";
henrika5f6bf242017-11-01 11:06:56 +0100141 RTC_DCHECK(thread_checker_.CalledOnValidThread());
Fredrik Solenbergaaedf752017-12-18 13:09:12 +0100142 if (recording_enabled_ != enabled) {
143 recording_enabled_ = enabled;
144 if (enabled) {
145 if (!sending_streams_.empty()) {
146 config_.audio_device_module->StartRecording();
147 }
148 } else {
149 config_.audio_device_module->StopRecording();
150 }
151 }
Fredrik Solenberg2a877972017-12-15 16:42:15 +0100152}
153
154AudioState::Stats AudioState::GetAudioInputStats() const {
155 RTC_DCHECK(thread_checker_.CalledOnValidThread());
156 const voe::AudioLevel& audio_level = audio_transport_.audio_level();
157 Stats result;
158 result.audio_level = audio_level.LevelFullRange();
159 RTC_DCHECK_LE(0, result.audio_level);
160 RTC_DCHECK_GE(32767, result.audio_level);
Fredrik Solenberg2a877972017-12-15 16:42:15 +0100161 result.total_energy = audio_level.TotalEnergy();
162 result.total_duration = audio_level.TotalDuration();
163 return result;
164}
165
166void AudioState::SetStereoChannelSwapping(bool enable) {
167 RTC_DCHECK(thread_checker_.CalledOnValidThread());
168 audio_transport_.SetStereoChannelSwapping(enable);
henrika5f6bf242017-11-01 11:06:56 +0100169}
170
solenberg566ef242015-11-06 15:34:49 -0800171// Reference count; implementation copied from rtc::RefCountedObject.
Niels Möller6f72f562017-10-19 13:15:17 +0200172void AudioState::AddRef() const {
173 rtc::AtomicOps::Increment(&ref_count_);
solenberg566ef242015-11-06 15:34:49 -0800174}
175
176// Reference count; implementation copied from rtc::RefCountedObject.
Niels Möller6f72f562017-10-19 13:15:17 +0200177rtc::RefCountReleaseStatus AudioState::Release() const {
178 if (rtc::AtomicOps::Decrement(&ref_count_) == 0) {
solenberg566ef242015-11-06 15:34:49 -0800179 delete this;
Niels Möller6f72f562017-10-19 13:15:17 +0200180 return rtc::RefCountReleaseStatus::kDroppedLastRef;
solenberg566ef242015-11-06 15:34:49 -0800181 }
Niels Möller6f72f562017-10-19 13:15:17 +0200182 return rtc::RefCountReleaseStatus::kOtherRefsRemained;
solenberg566ef242015-11-06 15:34:49 -0800183}
Fredrik Solenberg2a877972017-12-15 16:42:15 +0100184
185void AudioState::UpdateAudioTransportWithSendingStreams() {
186 RTC_DCHECK(thread_checker_.CalledOnValidThread());
Fredrik Solenbergd5247512017-12-18 22:41:03 +0100187 std::vector<webrtc::AudioSendStream*> sending_streams;
Fredrik Solenberg2a877972017-12-15 16:42:15 +0100188 int max_sample_rate_hz = 8000;
189 size_t max_num_channels = 1;
190 for (const auto& kv : sending_streams_) {
191 sending_streams.push_back(kv.first);
192 max_sample_rate_hz = std::max(max_sample_rate_hz, kv.second.sample_rate_hz);
193 max_num_channels = std::max(max_num_channels, kv.second.num_channels);
194 }
195 audio_transport_.UpdateSendingStreams(std::move(sending_streams),
196 max_sample_rate_hz, max_num_channels);
197}
solenberg566ef242015-11-06 15:34:49 -0800198} // namespace internal
199
200rtc::scoped_refptr<AudioState> AudioState::Create(
201 const AudioState::Config& config) {
202 return rtc::scoped_refptr<AudioState>(new internal::AudioState(config));
203}
204} // namespace webrtc