blob: 1b613c28d9da37183affa13767676e5d285e5430 [file] [log] [blame]
// Copyright 2018 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "src/media/audio/audio_core/audio_device_settings.h"
#include <lib/zx/clock.h>
#include <trace/event.h>
#include "src/media/audio/audio_core/audio_driver.h"
namespace media::audio {
AudioDeviceSettings::AudioDeviceSettings(const audio_stream_unique_id_t& uid, const HwGainState& hw,
bool is_input)
: uid_(uid), is_input_(is_input), can_agc_(hw.can_agc) {
gain_state_.gain_db = hw.cur_gain;
gain_state_.muted = hw.cur_mute;
gain_state_.agc_enabled = hw.can_agc && hw.cur_agc;
}
AudioDeviceSettings::AudioDeviceSettings(const AudioDeviceSettings& o)
: uid_(o.uid_), is_input_(o.is_input_), can_agc_(o.can_agc_) {
std::lock_guard<std::mutex> lock(o.settings_lock_);
gain_state_.gain_db = o.gain_state_.gain_db;
gain_state_.muted = o.gain_state_.muted;
gain_state_.agc_enabled = o.gain_state_.agc_enabled;
}
bool AudioDeviceSettings::SetGainInfo(const fuchsia::media::AudioGainInfo& req,
uint32_t set_flags) {
TRACE_DURATION("audio", "AudioDeviceSettings::SetGainInfo");
std::lock_guard<std::mutex> lock(settings_lock_);
audio_set_gain_flags_t dirtied = gain_state_dirty_flags_;
if ((set_flags & fuchsia::media::SetAudioGainFlag_GainValid) &&
(gain_state_.gain_db != req.gain_db)) {
gain_state_.gain_db = req.gain_db;
dirtied = static_cast<audio_set_gain_flags_t>(dirtied | AUDIO_SGF_GAIN_VALID);
}
bool mute_tgt = (req.flags & fuchsia::media::AudioGainInfoFlag_Mute) != 0;
if ((set_flags & fuchsia::media::SetAudioGainFlag_MuteValid) && (gain_state_.muted != mute_tgt)) {
gain_state_.muted = mute_tgt;
dirtied = static_cast<audio_set_gain_flags_t>(dirtied | AUDIO_SGF_MUTE_VALID);
}
bool agc_tgt = (req.flags & fuchsia::media::AudioGainInfoFlag_AgcEnabled) != 0;
if ((set_flags & fuchsia::media::SetAudioGainFlag_AgcValid) &&
(gain_state_.agc_enabled != agc_tgt)) {
gain_state_.agc_enabled = agc_tgt;
dirtied = static_cast<audio_set_gain_flags_t>(dirtied | AUDIO_SGF_AGC_VALID);
}
bool needs_wake = (!gain_state_dirty_flags_ && dirtied);
gain_state_dirty_flags_ = dirtied;
return needs_wake;
}
void AudioDeviceSettings::GetGainInfo(fuchsia::media::AudioGainInfo* out_info) const {
TRACE_DURATION("audio", "AudioDeviceSettings::GetGainInfo");
FX_DCHECK(out_info != nullptr);
// TODO(35439): consider eliminating the acquisition of this lock. In theory, the only mutation
// of gain state happens during SetGainInfo, which is supposed to only be called from the
// AudioDeviceManager, which should be functionally single threaded as it is called only from the
// main service message loop. Since GetGainInfo should only be called from the device manager as
// well, we should not need the settings_lock_ to observe the gain state from this method.
//
// Conversely, if we had an efficient reader/writer lock, we should only need to obtain this lock
// for read which should always succeed without contention.
std::lock_guard<std::mutex> lock(settings_lock_);
out_info->gain_db = gain_state_.gain_db;
out_info->flags = 0;
if (gain_state_.muted) {
out_info->flags |= fuchsia::media::AudioGainInfoFlag_Mute;
}
if (can_agc_) {
out_info->flags |= fuchsia::media::AudioGainInfoFlag_AgcSupported;
if (gain_state_.agc_enabled) {
out_info->flags |= fuchsia::media::AudioGainInfoFlag_AgcEnabled;
}
}
}
audio_set_gain_flags_t AudioDeviceSettings::SnapshotGainState(GainState* out_state) {
TRACE_DURATION("audio", "AudioDeviceSettings::SnapshotGainState");
FX_DCHECK(out_state != nullptr);
audio_set_gain_flags_t ret;
{
std::lock_guard<std::mutex> lock(settings_lock_);
*out_state = gain_state_;
ret = gain_state_dirty_flags_;
gain_state_dirty_flags_ = static_cast<audio_set_gain_flags_t>(0);
}
return ret;
}
} // namespace media::audio