| // Copyright 2022 The Chromium Authors |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "chrome/browser/ash/crosapi/audio_service_ash.h" |
| |
| #include "base/check.h" |
| #include "base/logging.h" |
| #include "base/ranges/algorithm.h" |
| #include "chrome/browser/profiles/profile.h" |
| #include "extensions/browser/api/audio/audio_device_id_calculator.h" |
| #include "extensions/browser/api/audio/audio_service_utils.h" |
| |
| namespace crosapi { |
| |
| // TODO: Add unit tests for AudioServiceAsh (b/235565865). |
| |
| AudioServiceAsh::Observer::Observer() = default; |
| AudioServiceAsh::Observer::~Observer() = default; |
| |
| void AudioServiceAsh::Observer::Initialize(extensions::AudioService* service) { |
| DCHECK(service); |
| audio_service_observation_.Observe(service); |
| } |
| |
| void AudioServiceAsh::Observer::OnLevelChanged(const std::string& id, |
| int level) { |
| for (auto& observer : observers_) { |
| observer->OnLevelChanged(id, level); |
| } |
| } |
| |
| void AudioServiceAsh::Observer::OnMuteChanged(bool is_input, bool is_muted) { |
| for (auto& observer : observers_) { |
| observer->OnMuteChanged(is_input, is_muted); |
| } |
| } |
| |
| void AudioServiceAsh::Observer::OnDevicesChanged( |
| const extensions::DeviceInfoList& devices) { |
| for (auto& observer : observers_) { |
| std::vector<mojom::AudioDeviceInfoPtr> result; |
| base::ranges::transform(devices, std::back_inserter(result), |
| extensions::ConvertAudioDeviceInfoToMojom); |
| observer->OnDeviceListChanged(std::move(result)); |
| } |
| } |
| |
| void AudioServiceAsh::Observer::AddCrosapiObserver( |
| mojo::PendingRemote<mojom::AudioChangeObserver> observer) { |
| mojo::Remote<mojom::AudioChangeObserver> remote(std::move(observer)); |
| observers_.Add(std::move(remote)); |
| } |
| |
| AudioServiceAsh::AudioServiceAsh() = default; |
| AudioServiceAsh::~AudioServiceAsh() = default; |
| |
| void AudioServiceAsh::Initialize(Profile* profile) { |
| DCHECK(profile); |
| if (stable_id_calculator_) { |
| // TODO: investigate why crosapi ash object inits are called more than once. |
| // (b/235203815) |
| LOG(WARNING) |
| << "AudioServiceAsh was already initialized. Not initializing again."; |
| return; |
| } |
| |
| stable_id_calculator_ = |
| std::make_unique<extensions::AudioDeviceIdCalculator>(profile); |
| service_ = |
| extensions::AudioService::CreateInstance(stable_id_calculator_.get()); |
| observer_.Initialize(service_.get()); |
| } |
| |
| void AudioServiceAsh::BindReceiver( |
| mojo::PendingReceiver<mojom::AudioService> pending_receiver) { |
| DCHECK(stable_id_calculator_); |
| DCHECK(service_); |
| receivers_.Add(this, std::move(pending_receiver)); |
| } |
| |
| void AudioServiceAsh::GetDevices(mojom::DeviceFilterPtr filter, |
| GetDevicesCallback callback) { |
| DCHECK(service_); |
| const auto ext_filter = extensions::ConvertDeviceFilterFromMojom(filter); |
| |
| auto extapi_callback = base::BindOnce( |
| [](GetDevicesCallback crosapi_callback, bool success, |
| std::vector<extensions::api::audio::AudioDeviceInfo> devices_src) { |
| absl::optional<std::vector<mojom::AudioDeviceInfoPtr>> result; |
| |
| if (success) { |
| result.emplace(); // construct empty vector in-place |
| result->reserve(devices_src.size()); |
| base::ranges::transform(devices_src, |
| std::back_inserter(result.value()), |
| extensions::ConvertAudioDeviceInfoToMojom); |
| } |
| |
| std::move(crosapi_callback).Run(std::move(result)); |
| }, |
| std::move(callback)); |
| |
| service_->GetDevices(ext_filter.get(), std::move(extapi_callback)); |
| } |
| |
| void AudioServiceAsh::GetMute(mojom::StreamType stream_type, |
| GetMuteCallback callback) { |
| DCHECK(service_); |
| |
| if (stream_type == mojom::StreamType::kNone) { |
| std::move(callback).Run(false, false); |
| return; |
| } |
| |
| const bool is_input = (stream_type == mojom::StreamType::kInput); |
| service_->GetMute(is_input, std::move(callback)); |
| } |
| |
| void AudioServiceAsh::SetActiveDeviceLists( |
| mojom::DeviceIdListsPtr ids, |
| SetActiveDeviceListsCallback callback) { |
| DCHECK(service_); |
| const extensions::DeviceIdList* input_devices = |
| ids ? &(ids->inputs) : nullptr; |
| const extensions::DeviceIdList* output_devices = |
| ids ? &(ids->outputs) : nullptr; |
| |
| service_->SetActiveDeviceLists(input_devices, output_devices, |
| std::move(callback)); |
| } |
| |
| void AudioServiceAsh::SetMute(mojom::StreamType stream_type, |
| bool is_muted, |
| SetMuteCallback callback) { |
| DCHECK(service_); |
| |
| if (stream_type == mojom::StreamType::kNone) { |
| std::move(callback).Run(false); |
| return; |
| } |
| |
| const bool is_input = (stream_type == mojom::StreamType::kInput); |
| service_->SetMute(is_input, is_muted, std::move(callback)); |
| } |
| |
| void AudioServiceAsh::SetProperties(const std::string& id, |
| mojom::AudioDevicePropertiesPtr properties, |
| SetPropertiesCallback callback) { |
| DCHECK(service_); |
| if (properties) { |
| service_->SetDeviceSoundLevel(id, properties->level, std::move(callback)); |
| } else { |
| std::move(callback).Run(false); |
| } |
| } |
| |
| void AudioServiceAsh::AddAudioChangeObserver( |
| mojo::PendingRemote<mojom::AudioChangeObserver> observer) { |
| observer_.AddCrosapiObserver(std::move(observer)); |
| } |
| |
| } // namespace crosapi |