| // Copyright 2013 The Chromium Authors |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "chromeos/ash/components/dbus/audio/fake_cras_audio_client.h" |
| |
| #include <utility> |
| |
| #include "base/functional/bind.h" |
| #include "base/logging.h" |
| #include "base/ranges/algorithm.h" |
| #include "base/task/single_thread_task_runner.h" |
| |
| namespace ash { |
| |
| namespace { |
| |
| FakeCrasAudioClient* g_instance = nullptr; |
| |
| } // namespace |
| |
| const uint32_t kInputMaxSupportedChannels = 1; |
| const uint32_t kOutputMaxSupportedChannels = 2; |
| |
| const uint32_t kInputAudioEffect = 1; |
| const uint32_t kOutputAudioEffect = 0; |
| |
| const int32_t kInputNumberOfVolumeSteps = 0; |
| const int32_t kOutputNumberOfVolumeSteps = 25; |
| |
| FakeCrasAudioClient::FakeCrasAudioClient() { |
| CHECK(!g_instance); |
| g_instance = this; |
| |
| VLOG(1) << "FakeCrasAudioClient is created"; |
| |
| // Fake audio output nodes. |
| AudioNode output_1; |
| output_1.is_input = false; |
| output_1.id = 0x100000001; |
| output_1.stable_device_id_v1 = 10001; |
| output_1.max_supported_channels = kOutputMaxSupportedChannels; |
| output_1.audio_effect = kOutputAudioEffect; |
| output_1.device_name = "Fake Speaker"; |
| output_1.type = "INTERNAL_SPEAKER"; |
| output_1.name = "Speaker"; |
| output_1.number_of_volume_steps = kOutputNumberOfVolumeSteps; |
| node_list_.push_back(output_1); |
| |
| AudioNode output_2; |
| output_2.is_input = false; |
| output_2.id = 0x200000001; |
| output_2.stable_device_id_v1 = 10002; |
| output_2.max_supported_channels = kOutputMaxSupportedChannels; |
| output_2.audio_effect = kOutputAudioEffect; |
| output_2.device_name = "Fake Headphone"; |
| output_2.type = "HEADPHONE"; |
| output_2.name = "Headphone"; |
| output_2.number_of_volume_steps = kOutputNumberOfVolumeSteps; |
| node_list_.push_back(output_2); |
| |
| AudioNode output_3; |
| output_3.is_input = false; |
| output_3.id = 0x300000001; |
| output_3.stable_device_id_v1 = 10003; |
| output_3.max_supported_channels = kOutputMaxSupportedChannels; |
| output_3.audio_effect = kOutputAudioEffect; |
| output_3.device_name = "Fake Bluetooth Headphone"; |
| output_3.type = "BLUETOOTH"; |
| output_3.name = "Headphone"; |
| output_3.number_of_volume_steps = kOutputNumberOfVolumeSteps; |
| node_list_.push_back(output_3); |
| |
| AudioNode output_4; |
| output_4.is_input = false; |
| output_4.id = 0x400000001; |
| output_4.stable_device_id_v1 = 10004; |
| output_4.max_supported_channels = kOutputMaxSupportedChannels; |
| output_4.audio_effect = kOutputAudioEffect; |
| output_4.device_name = "Fake HDMI Speaker"; |
| output_4.type = "HDMI"; |
| output_4.name = "HDMI Speaker"; |
| output_4.number_of_volume_steps = kOutputNumberOfVolumeSteps; |
| node_list_.push_back(output_4); |
| |
| // Fake audio input nodes |
| AudioNode input_1; |
| input_1.is_input = true; |
| input_1.id = 0x100000002; |
| input_1.stable_device_id_v1 = 20001; |
| input_1.max_supported_channels = kInputMaxSupportedChannels; |
| input_1.audio_effect = kInputAudioEffect; |
| input_1.device_name = "Fake Internal Mic"; |
| input_1.type = "INTERNAL_MIC"; |
| input_1.name = "Internal Mic"; |
| input_1.number_of_volume_steps = kInputNumberOfVolumeSteps; |
| node_list_.push_back(input_1); |
| |
| AudioNode input_2; |
| input_2.is_input = true; |
| input_2.id = 0x200000002; |
| input_2.stable_device_id_v1 = 20002; |
| input_2.max_supported_channels = kInputMaxSupportedChannels; |
| input_2.audio_effect = kInputAudioEffect; |
| input_2.device_name = "Fake USB Mic"; |
| input_2.type = "USB"; |
| input_2.name = "Mic"; |
| input_2.number_of_volume_steps = kInputNumberOfVolumeSteps; |
| node_list_.push_back(input_2); |
| |
| AudioNode input_3; |
| input_3.is_input = true; |
| input_3.id = 0x300000002; |
| input_3.stable_device_id_v1 = 20003; |
| input_3.max_supported_channels = kInputMaxSupportedChannels; |
| input_3.audio_effect = kInputAudioEffect; |
| input_3.device_name = "Fake Mic Jack"; |
| input_3.type = "MIC"; |
| input_3.name = "Some type of Mic"; |
| input_3.number_of_volume_steps = kInputNumberOfVolumeSteps; |
| node_list_.push_back(input_3); |
| } |
| |
| FakeCrasAudioClient::~FakeCrasAudioClient() { |
| CHECK_EQ(this, g_instance); |
| g_instance = nullptr; |
| } |
| |
| // static |
| FakeCrasAudioClient* FakeCrasAudioClient::Get() { |
| return g_instance; |
| } |
| |
| void FakeCrasAudioClient::AddObserver(Observer* observer) { |
| observers_.AddObserver(observer); |
| } |
| |
| void FakeCrasAudioClient::RemoveObserver(Observer* observer) { |
| observers_.RemoveObserver(observer); |
| } |
| |
| bool FakeCrasAudioClient::HasObserver(const Observer* observer) const { |
| return observers_.HasObserver(observer); |
| } |
| |
| void FakeCrasAudioClient::GetVolumeState( |
| chromeos::DBusMethodCallback<VolumeState> callback) { |
| std::move(callback).Run(volume_state_); |
| } |
| |
| void FakeCrasAudioClient::GetDefaultOutputBufferSize( |
| chromeos::DBusMethodCallback<int> callback) { |
| std::move(callback).Run(512); |
| } |
| |
| void FakeCrasAudioClient::GetSystemAecSupported( |
| chromeos::DBusMethodCallback<bool> callback) { |
| std::move(callback).Run(false); |
| } |
| |
| void FakeCrasAudioClient::GetSystemAecGroupId( |
| chromeos::DBusMethodCallback<int32_t> callback) { |
| std::move(callback).Run(1); |
| } |
| |
| void FakeCrasAudioClient::GetSystemNsSupported( |
| chromeos::DBusMethodCallback<bool> callback) { |
| std::move(callback).Run(false); |
| } |
| |
| void FakeCrasAudioClient::GetSystemAgcSupported( |
| chromeos::DBusMethodCallback<bool> callback) { |
| std::move(callback).Run(false); |
| } |
| |
| void FakeCrasAudioClient::GetNodes( |
| chromeos::DBusMethodCallback<AudioNodeList> callback) { |
| std::move(callback).Run(node_list_); |
| } |
| |
| void FakeCrasAudioClient::GetNumberOfNonChromeOutputStreams( |
| chromeos::DBusMethodCallback<int32_t> callback) { |
| std::move(callback).Run(number_non_chrome_output_streams_); |
| } |
| |
| void FakeCrasAudioClient::GetNumberOfActiveOutputStreams( |
| chromeos::DBusMethodCallback<int> callback) { |
| std::move(callback).Run(0); |
| } |
| |
| void FakeCrasAudioClient::GetNumberOfInputStreamsWithPermission( |
| chromeos::DBusMethodCallback<ClientTypeToInputStreamCount> callback) { |
| std::move(callback).Run(active_input_streams_); |
| } |
| |
| void FakeCrasAudioClient::GetDeprioritizeBtWbsMic( |
| chromeos::DBusMethodCallback<bool> callback) { |
| std::move(callback).Run(false); |
| } |
| |
| void FakeCrasAudioClient::GetSpeakOnMuteDetectionEnabled( |
| chromeos::DBusMethodCallback<bool> callback) { |
| std::move(callback).Run(false); |
| } |
| |
| void FakeCrasAudioClient::SetOutputNodeVolume(uint64_t node_id, |
| int32_t volume) { |
| if (enable_volume_change_events_) { |
| if (send_volume_change_events_synchronous_) { |
| NotifyOutputNodeVolumeChangedForTesting(node_id, volume); |
| } else { |
| base::SingleThreadTaskRunner::GetCurrentDefault()->PostTask( |
| FROM_HERE, |
| base::BindOnce( |
| &FakeCrasAudioClient::NotifyOutputNodeVolumeChangedForTesting, |
| weak_ptr_factory_.GetWeakPtr(), node_id, volume)); |
| } |
| } |
| } |
| |
| void FakeCrasAudioClient::SetOutputUserMute(bool mute_on) { |
| volume_state_.output_user_mute = mute_on; |
| for (auto& observer : observers_) { |
| observer.OutputMuteChanged(volume_state_.output_user_mute); |
| } |
| } |
| |
| void FakeCrasAudioClient::SetInputNodeGain(uint64_t node_id, |
| int32_t input_gain) { |
| if (enable_gain_change_events_) { |
| NotifyInputNodeGainChangedForTesting(node_id, input_gain); |
| } |
| } |
| |
| void FakeCrasAudioClient::SetInputMute(bool mute_on) { |
| volume_state_.input_mute = mute_on; |
| for (auto& observer : observers_) { |
| observer.InputMuteChanged(volume_state_.input_mute); |
| } |
| } |
| |
| void FakeCrasAudioClient::SetNoiseCancellationSupported( |
| bool noise_cancellation_supported) { |
| noise_cancellation_supported_ = noise_cancellation_supported; |
| } |
| |
| void FakeCrasAudioClient::SetNoiseCancellationEnabled( |
| bool noise_cancellation_on) { |
| noise_cancellation_enabled_ = noise_cancellation_on; |
| ++noise_cancellation_enabled_counter_; |
| } |
| |
| void FakeCrasAudioClient::GetNoiseCancellationSupported( |
| chromeos::DBusMethodCallback<bool> callback) { |
| std::move(callback).Run(noise_cancellation_supported_); |
| } |
| |
| uint32_t FakeCrasAudioClient::GetNoiseCancellationEnabledCount() { |
| return noise_cancellation_enabled_counter_; |
| } |
| |
| void FakeCrasAudioClient::SetNumberOfNonChromeOutputStreams(int32_t streams) { |
| number_non_chrome_output_streams_ = streams; |
| for (auto& observer : observers_) { |
| observer.NumberOfNonChromeOutputStreamsChanged(); |
| } |
| } |
| |
| void FakeCrasAudioClient::SetActiveOutputNode(uint64_t node_id) { |
| if (active_output_node_id_ == node_id) { |
| return; |
| } |
| |
| for (size_t i = 0; i < node_list_.size(); ++i) { |
| if (node_list_[i].id == active_output_node_id_) { |
| node_list_[i].active = false; |
| } else if (node_list_[i].id == node_id) { |
| node_list_[i].active = true; |
| } |
| } |
| active_output_node_id_ = node_id; |
| for (auto& observer : observers_) { |
| observer.ActiveOutputNodeChanged(node_id); |
| } |
| } |
| |
| void FakeCrasAudioClient::SetActiveInputNode(uint64_t node_id) { |
| if (active_input_node_id_ == node_id) { |
| return; |
| } |
| |
| for (size_t i = 0; i < node_list_.size(); ++i) { |
| if (node_list_[i].id == active_input_node_id_) { |
| node_list_[i].active = false; |
| } else if (node_list_[i].id == node_id) { |
| node_list_[i].active = true; |
| } |
| } |
| active_input_node_id_ = node_id; |
| for (auto& observer : observers_) { |
| observer.ActiveInputNodeChanged(node_id); |
| } |
| } |
| |
| void FakeCrasAudioClient::SetHotwordModel( |
| uint64_t node_id, |
| const std::string& hotword_model, |
| chromeos::VoidDBusMethodCallback callback) {} |
| |
| void FakeCrasAudioClient::SetFixA2dpPacketSize(bool enabled) {} |
| |
| void FakeCrasAudioClient::SetFlossEnabled(bool enabled) {} |
| |
| void FakeCrasAudioClient::SetSpeakOnMuteDetection(bool enabled) { |
| speak_on_mute_detection_enabled_ = enabled; |
| } |
| |
| void FakeCrasAudioClient::AddActiveInputNode(uint64_t node_id) { |
| for (size_t i = 0; i < node_list_.size(); ++i) { |
| if (node_list_[i].id == node_id) { |
| node_list_[i].active = true; |
| } |
| } |
| } |
| |
| void FakeCrasAudioClient::RemoveActiveInputNode(uint64_t node_id) { |
| for (size_t i = 0; i < node_list_.size(); ++i) { |
| if (node_list_[i].id == node_id) { |
| node_list_[i].active = false; |
| } |
| } |
| } |
| |
| void FakeCrasAudioClient::SwapLeftRight(uint64_t node_id, bool swap) {} |
| |
| void FakeCrasAudioClient::SetDisplayRotation(uint64_t node_id, |
| cras::DisplayRotation rotation) {} |
| |
| void FakeCrasAudioClient::SetGlobalOutputChannelRemix( |
| int32_t channels, |
| const std::vector<double>& mixer) {} |
| |
| void FakeCrasAudioClient::SetPlayerPlaybackStatus( |
| const std::string& playback_status) {} |
| |
| void FakeCrasAudioClient::SetPlayerIdentity( |
| const std::string& playback_identity) {} |
| |
| void FakeCrasAudioClient::SetPlayerPosition(const int64_t& position) {} |
| |
| void FakeCrasAudioClient::SetPlayerDuration(const int64_t& duration) {} |
| |
| void FakeCrasAudioClient::SetPlayerMetadata( |
| const std::map<std::string, std::string>& metadata) {} |
| |
| void FakeCrasAudioClient::AddActiveOutputNode(uint64_t node_id) { |
| for (size_t i = 0; i < node_list_.size(); ++i) { |
| if (node_list_[i].id == node_id) { |
| node_list_[i].active = true; |
| } |
| } |
| } |
| |
| void FakeCrasAudioClient::ResendBluetoothBattery() { |
| for (auto& observer : observers_) { |
| observer.BluetoothBatteryChanged("11:22:33:44:55:66", battery_level_); |
| } |
| } |
| |
| void FakeCrasAudioClient::WaitForServiceToBeAvailable( |
| chromeos::WaitForServiceToBeAvailableCallback callback) { |
| std::move(callback).Run(true); |
| } |
| |
| void FakeCrasAudioClient::RemoveActiveOutputNode(uint64_t node_id) { |
| for (size_t i = 0; i < node_list_.size(); ++i) { |
| if (node_list_[i].id == node_id) { |
| node_list_[i].active = false; |
| } |
| } |
| } |
| |
| void FakeCrasAudioClient::InsertAudioNodeToList(const AudioNode& audio_node) { |
| auto iter = FindNode(audio_node.id); |
| if (iter != node_list_.end()) { |
| (*iter) = audio_node; |
| } else { |
| node_list_.push_back(audio_node); |
| } |
| for (auto& observer : observers_) { |
| observer.NodesChanged(); |
| } |
| } |
| |
| void FakeCrasAudioClient::RemoveAudioNodeFromList(const uint64_t& node_id) { |
| auto iter = FindNode(node_id); |
| if (iter != node_list_.end()) { |
| node_list_.erase(iter); |
| for (auto& observer : observers_) { |
| observer.NodesChanged(); |
| } |
| } |
| } |
| |
| void FakeCrasAudioClient::SetAudioNodesForTesting( |
| const AudioNodeList& audio_nodes) { |
| node_list_ = audio_nodes; |
| } |
| |
| void FakeCrasAudioClient::SetAudioNodesAndNotifyObserversForTesting( |
| const AudioNodeList& new_nodes) { |
| SetAudioNodesForTesting(new_nodes); |
| for (auto& observer : observers_) { |
| observer.NodesChanged(); |
| } |
| } |
| |
| void FakeCrasAudioClient::NotifyOutputNodeVolumeChangedForTesting( |
| uint64_t node_id, |
| int volume) { |
| for (auto& observer : observers_) { |
| observer.OutputNodeVolumeChanged(node_id, volume); |
| } |
| } |
| |
| void FakeCrasAudioClient::NotifyInputNodeGainChangedForTesting(uint64_t node_id, |
| int gain) { |
| for (auto& observer : observers_) { |
| observer.InputNodeGainChanged(node_id, gain); |
| } |
| } |
| |
| void FakeCrasAudioClient::NotifyHotwordTriggeredForTesting(uint64_t tv_sec, |
| uint64_t tv_nsec) { |
| for (auto& observer : observers_) { |
| observer.HotwordTriggered(tv_sec, tv_nsec); |
| } |
| } |
| |
| void FakeCrasAudioClient::SetBluetoothBattteryLevelForTesting(uint32_t level) { |
| battery_level_ = level; |
| } |
| |
| void FakeCrasAudioClient::SetActiveInputStreamsWithPermission( |
| const ClientTypeToInputStreamCount& input_streams) { |
| active_input_streams_ = input_streams; |
| for (auto& observer : observers_) { |
| observer.NumberOfInputStreamsWithPermissionChanged(active_input_streams_); |
| } |
| } |
| |
| AudioNodeList::iterator FakeCrasAudioClient::FindNode(uint64_t node_id) { |
| return base::ranges::find(node_list_, node_id, &AudioNode::id); |
| } |
| |
| void FakeCrasAudioClient::SetForceRespectUiGains(bool force_respect_ui_gains) {} |
| |
| } // namespace ash |