blob: ac7eaf7bca32e3b5783e76d2c15084e3b8425734 [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
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020017#include "modules/audio_device/include/audio_device.h"
18#include "rtc_base/atomicops.h"
19#include "rtc_base/checks.h"
20#include "rtc_base/logging.h"
henrika5f6bf242017-11-01 11:06:56 +010021#include "rtc_base/ptr_util.h"
22#include "rtc_base/thread.h"
solenberg566ef242015-11-06 15:34:49 -080023
24namespace webrtc {
25namespace internal {
26
27AudioState::AudioState(const AudioState::Config& config)
aleloidd310712016-11-17 06:28:59 -080028 : config_(config),
29 voe_base_(config.voice_engine),
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 Solenberg2a877972017-12-15 16:42:15 +010040 RTC_DCHECK(sending_streams_.empty());
solenberg566ef242015-11-06 15:34:49 -080041}
42
43VoiceEngine* AudioState::voice_engine() {
44 RTC_DCHECK(thread_checker_.CalledOnValidThread());
45 return config_.voice_engine;
46}
47
aleloidd310712016-11-17 06:28:59 -080048rtc::scoped_refptr<AudioMixer> AudioState::mixer() {
aleloi10111bc2016-11-17 06:48:48 -080049 RTC_DCHECK(thread_checker_.CalledOnValidThread());
aleloidd310712016-11-17 06:28:59 -080050 return config_.audio_mixer;
51}
52
solenberg566ef242015-11-06 15:34:49 -080053bool AudioState::typing_noise_detected() const {
54 RTC_DCHECK(thread_checker_.CalledOnValidThread());
Fredrik Solenberg2a877972017-12-15 16:42:15 +010055 return audio_transport_.typing_noise_detected();
56}
57
58void AudioState::AddSendingStream(webrtc::AudioSendStream* stream,
59 int sample_rate_hz, size_t num_channels) {
60 RTC_DCHECK(thread_checker_.CalledOnValidThread());
61 auto& properties = sending_streams_[stream];
62 properties.sample_rate_hz = sample_rate_hz;
63 properties.num_channels = num_channels;
64 UpdateAudioTransportWithSendingStreams();
Fredrik Solenbergaaedf752017-12-18 13:09:12 +010065
66 // Make sure recording is initialized; start recording if enabled.
67 auto* adm = config_.audio_device_module.get();
68 if (!adm->Recording()) {
69 if (adm->InitRecording() == 0) {
70 if (recording_enabled_) {
71 adm->StartRecording();
72 }
73 } else {
74 RTC_DLOG_F(LS_ERROR) << "Failed to initialize recording.";
75 }
76 }
Fredrik Solenberg2a877972017-12-15 16:42:15 +010077}
78
79void AudioState::RemoveSendingStream(webrtc::AudioSendStream* stream) {
80 RTC_DCHECK(thread_checker_.CalledOnValidThread());
81 auto count = sending_streams_.erase(stream);
82 RTC_DCHECK_EQ(1, count);
83 UpdateAudioTransportWithSendingStreams();
Fredrik Solenbergaaedf752017-12-18 13:09:12 +010084 if (sending_streams_.empty()) {
85 config_.audio_device_module->StopRecording();
86 }
solenberg566ef242015-11-06 15:34:49 -080087}
88
henrika5f6bf242017-11-01 11:06:56 +010089void AudioState::SetPlayout(bool enabled) {
Mirko Bonadei675513b2017-11-09 11:09:25 +010090 RTC_LOG(INFO) << "SetPlayout(" << enabled << ")";
henrika5f6bf242017-11-01 11:06:56 +010091 RTC_DCHECK(thread_checker_.CalledOnValidThread());
92 const bool currently_enabled = (null_audio_poller_ == nullptr);
93 if (enabled == currently_enabled) {
94 return;
95 }
henrika5f6bf242017-11-01 11:06:56 +010096 if (enabled) {
97 null_audio_poller_.reset();
98 }
99 // Will stop/start playout of the underlying device, if necessary, and
100 // remember the setting for when it receives subsequent calls of
101 // StartPlayout.
Fredrik Solenberg2a877972017-12-15 16:42:15 +0100102 voe_base_->SetPlayout(enabled);
henrika5f6bf242017-11-01 11:06:56 +0100103 if (!enabled) {
104 null_audio_poller_ =
Fredrik Solenberg2a877972017-12-15 16:42:15 +0100105 rtc::MakeUnique<NullAudioPoller>(&audio_transport_);
henrika5f6bf242017-11-01 11:06:56 +0100106 }
107}
108
109void AudioState::SetRecording(bool enabled) {
Mirko Bonadei675513b2017-11-09 11:09:25 +0100110 RTC_LOG(INFO) << "SetRecording(" << enabled << ")";
henrika5f6bf242017-11-01 11:06:56 +0100111 RTC_DCHECK(thread_checker_.CalledOnValidThread());
Fredrik Solenbergaaedf752017-12-18 13:09:12 +0100112 if (recording_enabled_ != enabled) {
113 recording_enabled_ = enabled;
114 if (enabled) {
115 if (!sending_streams_.empty()) {
116 config_.audio_device_module->StartRecording();
117 }
118 } else {
119 config_.audio_device_module->StopRecording();
120 }
121 }
Fredrik Solenberg2a877972017-12-15 16:42:15 +0100122}
123
124AudioState::Stats AudioState::GetAudioInputStats() const {
125 RTC_DCHECK(thread_checker_.CalledOnValidThread());
126 const voe::AudioLevel& audio_level = audio_transport_.audio_level();
127 Stats result;
128 result.audio_level = audio_level.LevelFullRange();
129 RTC_DCHECK_LE(0, result.audio_level);
130 RTC_DCHECK_GE(32767, result.audio_level);
131 result.quantized_audio_level = audio_level.Level();
132 RTC_DCHECK_LE(0, result.quantized_audio_level);
133 RTC_DCHECK_GE(9, result.quantized_audio_level);
134 result.total_energy = audio_level.TotalEnergy();
135 result.total_duration = audio_level.TotalDuration();
136 return result;
137}
138
139void AudioState::SetStereoChannelSwapping(bool enable) {
140 RTC_DCHECK(thread_checker_.CalledOnValidThread());
141 audio_transport_.SetStereoChannelSwapping(enable);
henrika5f6bf242017-11-01 11:06:56 +0100142}
143
solenberg566ef242015-11-06 15:34:49 -0800144// Reference count; implementation copied from rtc::RefCountedObject.
Niels Möller6f72f562017-10-19 13:15:17 +0200145void AudioState::AddRef() const {
146 rtc::AtomicOps::Increment(&ref_count_);
solenberg566ef242015-11-06 15:34:49 -0800147}
148
149// Reference count; implementation copied from rtc::RefCountedObject.
Niels Möller6f72f562017-10-19 13:15:17 +0200150rtc::RefCountReleaseStatus AudioState::Release() const {
151 if (rtc::AtomicOps::Decrement(&ref_count_) == 0) {
solenberg566ef242015-11-06 15:34:49 -0800152 delete this;
Niels Möller6f72f562017-10-19 13:15:17 +0200153 return rtc::RefCountReleaseStatus::kDroppedLastRef;
solenberg566ef242015-11-06 15:34:49 -0800154 }
Niels Möller6f72f562017-10-19 13:15:17 +0200155 return rtc::RefCountReleaseStatus::kOtherRefsRemained;
solenberg566ef242015-11-06 15:34:49 -0800156}
Fredrik Solenberg2a877972017-12-15 16:42:15 +0100157
158void AudioState::UpdateAudioTransportWithSendingStreams() {
159 RTC_DCHECK(thread_checker_.CalledOnValidThread());
160 std::vector<AudioSendStream*> sending_streams;
161 int max_sample_rate_hz = 8000;
162 size_t max_num_channels = 1;
163 for (const auto& kv : sending_streams_) {
164 sending_streams.push_back(kv.first);
165 max_sample_rate_hz = std::max(max_sample_rate_hz, kv.second.sample_rate_hz);
166 max_num_channels = std::max(max_num_channels, kv.second.num_channels);
167 }
168 audio_transport_.UpdateSendingStreams(std::move(sending_streams),
169 max_sample_rate_hz, max_num_channels);
170}
solenberg566ef242015-11-06 15:34:49 -0800171} // namespace internal
172
173rtc::scoped_refptr<AudioState> AudioState::Create(
174 const AudioState::Config& config) {
175 return rtc::scoped_refptr<AudioState>(new internal::AudioState(config));
176}
177} // namespace webrtc