blob: a83b681252d0310feaebc2d5071ff366ececa313 [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);
solenberg566ef242015-11-06 15:34:49 -080035}
36
37AudioState::~AudioState() {
38 RTC_DCHECK(thread_checker_.CalledOnValidThread());
Fredrik Solenberg2a877972017-12-15 16:42:15 +010039 RTC_DCHECK(sending_streams_.empty());
solenberg566ef242015-11-06 15:34:49 -080040}
41
42VoiceEngine* AudioState::voice_engine() {
43 RTC_DCHECK(thread_checker_.CalledOnValidThread());
44 return config_.voice_engine;
45}
46
aleloidd310712016-11-17 06:28:59 -080047rtc::scoped_refptr<AudioMixer> AudioState::mixer() {
aleloi10111bc2016-11-17 06:48:48 -080048 RTC_DCHECK(thread_checker_.CalledOnValidThread());
aleloidd310712016-11-17 06:28:59 -080049 return config_.audio_mixer;
50}
51
solenberg566ef242015-11-06 15:34:49 -080052bool AudioState::typing_noise_detected() const {
53 RTC_DCHECK(thread_checker_.CalledOnValidThread());
Fredrik Solenberg2a877972017-12-15 16:42:15 +010054 return audio_transport_.typing_noise_detected();
55}
56
57void AudioState::AddSendingStream(webrtc::AudioSendStream* stream,
58 int sample_rate_hz, size_t num_channels) {
59 RTC_DCHECK(thread_checker_.CalledOnValidThread());
60 auto& properties = sending_streams_[stream];
61 properties.sample_rate_hz = sample_rate_hz;
62 properties.num_channels = num_channels;
63 UpdateAudioTransportWithSendingStreams();
64}
65
66void AudioState::RemoveSendingStream(webrtc::AudioSendStream* stream) {
67 RTC_DCHECK(thread_checker_.CalledOnValidThread());
68 auto count = sending_streams_.erase(stream);
69 RTC_DCHECK_EQ(1, count);
70 UpdateAudioTransportWithSendingStreams();
solenberg566ef242015-11-06 15:34:49 -080071}
72
henrika5f6bf242017-11-01 11:06:56 +010073void AudioState::SetPlayout(bool enabled) {
Mirko Bonadei675513b2017-11-09 11:09:25 +010074 RTC_LOG(INFO) << "SetPlayout(" << enabled << ")";
henrika5f6bf242017-11-01 11:06:56 +010075 RTC_DCHECK(thread_checker_.CalledOnValidThread());
76 const bool currently_enabled = (null_audio_poller_ == nullptr);
77 if (enabled == currently_enabled) {
78 return;
79 }
henrika5f6bf242017-11-01 11:06:56 +010080 if (enabled) {
81 null_audio_poller_.reset();
82 }
83 // Will stop/start playout of the underlying device, if necessary, and
84 // remember the setting for when it receives subsequent calls of
85 // StartPlayout.
Fredrik Solenberg2a877972017-12-15 16:42:15 +010086 voe_base_->SetPlayout(enabled);
henrika5f6bf242017-11-01 11:06:56 +010087 if (!enabled) {
88 null_audio_poller_ =
Fredrik Solenberg2a877972017-12-15 16:42:15 +010089 rtc::MakeUnique<NullAudioPoller>(&audio_transport_);
henrika5f6bf242017-11-01 11:06:56 +010090 }
91}
92
93void AudioState::SetRecording(bool enabled) {
Mirko Bonadei675513b2017-11-09 11:09:25 +010094 RTC_LOG(INFO) << "SetRecording(" << enabled << ")";
henrika5f6bf242017-11-01 11:06:56 +010095 RTC_DCHECK(thread_checker_.CalledOnValidThread());
96 // TODO(henrika): keep track of state as in SetPlayout().
henrika5f6bf242017-11-01 11:06:56 +010097 // Will stop/start recording of the underlying device, if necessary, and
98 // remember the setting for when it receives subsequent calls of
99 // StartPlayout.
Fredrik Solenberg2a877972017-12-15 16:42:15 +0100100 voe_base_->SetRecording(enabled);
101}
102
103AudioState::Stats AudioState::GetAudioInputStats() const {
104 RTC_DCHECK(thread_checker_.CalledOnValidThread());
105 const voe::AudioLevel& audio_level = audio_transport_.audio_level();
106 Stats result;
107 result.audio_level = audio_level.LevelFullRange();
108 RTC_DCHECK_LE(0, result.audio_level);
109 RTC_DCHECK_GE(32767, result.audio_level);
110 result.quantized_audio_level = audio_level.Level();
111 RTC_DCHECK_LE(0, result.quantized_audio_level);
112 RTC_DCHECK_GE(9, result.quantized_audio_level);
113 result.total_energy = audio_level.TotalEnergy();
114 result.total_duration = audio_level.TotalDuration();
115 return result;
116}
117
118void AudioState::SetStereoChannelSwapping(bool enable) {
119 RTC_DCHECK(thread_checker_.CalledOnValidThread());
120 audio_transport_.SetStereoChannelSwapping(enable);
henrika5f6bf242017-11-01 11:06:56 +0100121}
122
solenberg566ef242015-11-06 15:34:49 -0800123// Reference count; implementation copied from rtc::RefCountedObject.
Niels Möller6f72f562017-10-19 13:15:17 +0200124void AudioState::AddRef() const {
125 rtc::AtomicOps::Increment(&ref_count_);
solenberg566ef242015-11-06 15:34:49 -0800126}
127
128// Reference count; implementation copied from rtc::RefCountedObject.
Niels Möller6f72f562017-10-19 13:15:17 +0200129rtc::RefCountReleaseStatus AudioState::Release() const {
130 if (rtc::AtomicOps::Decrement(&ref_count_) == 0) {
solenberg566ef242015-11-06 15:34:49 -0800131 delete this;
Niels Möller6f72f562017-10-19 13:15:17 +0200132 return rtc::RefCountReleaseStatus::kDroppedLastRef;
solenberg566ef242015-11-06 15:34:49 -0800133 }
Niels Möller6f72f562017-10-19 13:15:17 +0200134 return rtc::RefCountReleaseStatus::kOtherRefsRemained;
solenberg566ef242015-11-06 15:34:49 -0800135}
Fredrik Solenberg2a877972017-12-15 16:42:15 +0100136
137void AudioState::UpdateAudioTransportWithSendingStreams() {
138 RTC_DCHECK(thread_checker_.CalledOnValidThread());
139 std::vector<AudioSendStream*> sending_streams;
140 int max_sample_rate_hz = 8000;
141 size_t max_num_channels = 1;
142 for (const auto& kv : sending_streams_) {
143 sending_streams.push_back(kv.first);
144 max_sample_rate_hz = std::max(max_sample_rate_hz, kv.second.sample_rate_hz);
145 max_num_channels = std::max(max_num_channels, kv.second.num_channels);
146 }
147 audio_transport_.UpdateSendingStreams(std::move(sending_streams),
148 max_sample_rate_hz, max_num_channels);
149}
solenberg566ef242015-11-06 15:34:49 -0800150} // namespace internal
151
152rtc::scoped_refptr<AudioState> AudioState::Create(
153 const AudioState::Config& config) {
154 return rtc::scoped_refptr<AudioState>(new internal::AudioState(config));
155}
156} // namespace webrtc