| // 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/cras_audio_client.h" |
| |
| #include <stdint.h> |
| |
| #include <utility> |
| |
| #include "base/format_macros.h" |
| #include "base/functional/bind.h" |
| #include "base/functional/callback_helpers.h" |
| #include "base/logging.h" |
| #include "base/memory/raw_ptr.h" |
| #include "chromeos/ash/components/dbus/audio/fake_cras_audio_client.h" |
| #include "dbus/bus.h" |
| #include "dbus/message.h" |
| #include "dbus/object_path.h" |
| #include "dbus/object_proxy.h" |
| #include "third_party/cros_system_api/dbus/service_constants.h" |
| |
| namespace ash { |
| |
| namespace { |
| |
| CrasAudioClient* g_instance = nullptr; |
| |
| // The CrasAudioClient implementation used in production. |
| class CrasAudioClientImpl : public CrasAudioClient { |
| public: |
| explicit CrasAudioClientImpl(dbus::Bus* bus) { |
| cras_proxy_ = bus->GetObjectProxy(cras::kCrasServiceName, |
| dbus::ObjectPath(cras::kCrasServicePath)); |
| |
| // Monitor NameOwnerChanged signal. |
| cras_proxy_->SetNameOwnerChangedCallback( |
| base::BindRepeating(&CrasAudioClientImpl::NameOwnerChangedReceived, |
| weak_ptr_factory_.GetWeakPtr())); |
| |
| // Monitor the D-Bus signal for output mute change. |
| cras_proxy_->ConnectToSignal( |
| cras::kCrasControlInterface, cras::kOutputMuteChanged, |
| base::BindRepeating(&CrasAudioClientImpl::OutputMuteChangedReceived, |
| weak_ptr_factory_.GetWeakPtr()), |
| base::BindOnce(&CrasAudioClientImpl::SignalConnected, |
| weak_ptr_factory_.GetWeakPtr())); |
| |
| // Monitor the D-Bus signal for input mute change. |
| cras_proxy_->ConnectToSignal( |
| cras::kCrasControlInterface, cras::kInputMuteChanged, |
| base::BindRepeating(&CrasAudioClientImpl::InputMuteChangedReceived, |
| weak_ptr_factory_.GetWeakPtr()), |
| base::BindOnce(&CrasAudioClientImpl::SignalConnected, |
| weak_ptr_factory_.GetWeakPtr())); |
| |
| // Monitor the D-Bus signal for nodes change. |
| cras_proxy_->ConnectToSignal( |
| cras::kCrasControlInterface, cras::kNodesChanged, |
| base::BindRepeating(&CrasAudioClientImpl::NodesChangedReceived, |
| weak_ptr_factory_.GetWeakPtr()), |
| base::BindOnce(&CrasAudioClientImpl::SignalConnected, |
| weak_ptr_factory_.GetWeakPtr())); |
| |
| // Monitor the D-Bus signal for active output node change. |
| cras_proxy_->ConnectToSignal( |
| cras::kCrasControlInterface, cras::kActiveOutputNodeChanged, |
| base::BindRepeating( |
| &CrasAudioClientImpl::ActiveOutputNodeChangedReceived, |
| weak_ptr_factory_.GetWeakPtr()), |
| base::BindOnce(&CrasAudioClientImpl::SignalConnected, |
| weak_ptr_factory_.GetWeakPtr())); |
| |
| // Monitor the D-Bus signal for active input node change. |
| cras_proxy_->ConnectToSignal( |
| cras::kCrasControlInterface, cras::kActiveInputNodeChanged, |
| base::BindRepeating( |
| &CrasAudioClientImpl::ActiveInputNodeChangedReceived, |
| weak_ptr_factory_.GetWeakPtr()), |
| base::BindOnce(&CrasAudioClientImpl::SignalConnected, |
| weak_ptr_factory_.GetWeakPtr())); |
| |
| // Monitor the D-Bus signal for output node volume change. |
| cras_proxy_->ConnectToSignal( |
| cras::kCrasControlInterface, cras::kOutputNodeVolumeChanged, |
| base::BindRepeating( |
| &CrasAudioClientImpl::OutputNodeVolumeChangedReceived, |
| weak_ptr_factory_.GetWeakPtr()), |
| base::BindOnce(&CrasAudioClientImpl::SignalConnected, |
| weak_ptr_factory_.GetWeakPtr())); |
| |
| // Monitor the D-Bus signal for input node gain change. |
| cras_proxy_->ConnectToSignal( |
| cras::kCrasControlInterface, cras::kInputNodeGainChanged, |
| base::BindRepeating(&CrasAudioClientImpl::InputNodeGainChangedReceived, |
| weak_ptr_factory_.GetWeakPtr()), |
| base::BindOnce(&CrasAudioClientImpl::SignalConnected, |
| weak_ptr_factory_.GetWeakPtr())); |
| |
| // Monitor the D-Bus signal for hotword. |
| cras_proxy_->ConnectToSignal( |
| cras::kCrasControlInterface, cras::kHotwordTriggered, |
| base::BindRepeating(&CrasAudioClientImpl::HotwordTriggeredReceived, |
| weak_ptr_factory_.GetWeakPtr()), |
| base::BindOnce(&CrasAudioClientImpl::SignalConnected, |
| weak_ptr_factory_.GetWeakPtr())); |
| |
| // Monitor the D-Bus signal for changes in number of active streams. |
| cras_proxy_->ConnectToSignal( |
| cras::kCrasControlInterface, cras::kNumberOfActiveStreamsChanged, |
| base::BindRepeating( |
| &CrasAudioClientImpl::NumberOfActiveStreamsChangedReceived, |
| weak_ptr_factory_.GetWeakPtr()), |
| base::BindOnce(&CrasAudioClientImpl::SignalConnected, |
| weak_ptr_factory_.GetWeakPtr())); |
| |
| // Monitor the D-Bus signal for changes in number of input streams with |
| // permission per client type. |
| cras_proxy_->ConnectToSignal( |
| cras::kCrasControlInterface, |
| cras::kNumberOfInputStreamsWithPermissionChanged, |
| base::BindRepeating( |
| &CrasAudioClientImpl::NumberOfInputStreamsWithPermissionReceived, |
| weak_ptr_factory_.GetWeakPtr()), |
| base::BindOnce(&CrasAudioClientImpl::SignalConnected, |
| weak_ptr_factory_.GetWeakPtr()) |
| |
| ); |
| |
| // Monitor the D-Bus signal for changes in Bluetooth headset battery level. |
| cras_proxy_->ConnectToSignal( |
| cras::kCrasControlInterface, cras::kBluetoothBatteryChanged, |
| base::BindRepeating( |
| &CrasAudioClientImpl::BluetoothBatteryChangedReceived, |
| weak_ptr_factory_.GetWeakPtr()), |
| base::BindOnce(&CrasAudioClientImpl::SignalConnected, |
| weak_ptr_factory_.GetWeakPtr())); |
| |
| // Monitor the D-Bus signal for CRAS to trigger an audio related survey. |
| // The HaTS survey framework lives in Chrome and we use this signal as an |
| // interface for CRAS to suggest when is proper to trigger the survey from |
| // the system's perspective. |
| cras_proxy_->ConnectToSignal( |
| cras::kCrasControlInterface, cras::kSurveyTrigger, |
| base::BindRepeating(&CrasAudioClientImpl::SurveyTriggerReceived, |
| weak_ptr_factory_.GetWeakPtr()), |
| base::BindOnce(&CrasAudioClientImpl::SignalConnected, |
| weak_ptr_factory_.GetWeakPtr())); |
| |
| // Monitor the D-Bus signal for new speak-on-mute detection. |
| cras_proxy_->ConnectToSignal( |
| cras::kCrasControlInterface, cras::kSpeakOnMuteDetected, |
| base::BindRepeating(&CrasAudioClientImpl::SpeakOnMuteDetectedReceived, |
| weak_ptr_factory_.GetWeakPtr()), |
| base::BindOnce(&CrasAudioClientImpl::SignalConnected, |
| weak_ptr_factory_.GetWeakPtr())); |
| |
| cras_proxy_->ConnectToSignal( |
| cras::kCrasControlInterface, |
| cras::kNumberOfNonChromeOutputStreamsChanged, |
| base::BindRepeating( |
| &CrasAudioClientImpl::NumberOfNonChromeOutputStreamsChangedReceived, |
| weak_ptr_factory_.GetWeakPtr()), |
| base::BindOnce(&CrasAudioClientImpl::SignalConnected, |
| weak_ptr_factory_.GetWeakPtr())); |
| } |
| |
| CrasAudioClientImpl(const CrasAudioClientImpl&) = delete; |
| CrasAudioClientImpl& operator=(const CrasAudioClientImpl&) = delete; |
| |
| ~CrasAudioClientImpl() override = default; |
| |
| // CrasAudioClient overrides: |
| void AddObserver(Observer* observer) override { |
| observers_.AddObserver(observer); |
| } |
| |
| void RemoveObserver(Observer* observer) override { |
| observers_.RemoveObserver(observer); |
| } |
| |
| bool HasObserver(const Observer* observer) const override { |
| return observers_.HasObserver(observer); |
| } |
| |
| void GetVolumeState( |
| chromeos::DBusMethodCallback<VolumeState> callback) override { |
| dbus::MethodCall method_call(cras::kCrasControlInterface, |
| cras::kGetVolumeState); |
| cras_proxy_->CallMethod( |
| &method_call, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT, |
| base::BindOnce(&CrasAudioClientImpl::OnGetVolumeState, |
| weak_ptr_factory_.GetWeakPtr(), std::move(callback))); |
| } |
| |
| void GetDefaultOutputBufferSize( |
| chromeos::DBusMethodCallback<int> callback) override { |
| dbus::MethodCall method_call(cras::kCrasControlInterface, |
| cras::kGetDefaultOutputBufferSize); |
| cras_proxy_->CallMethod( |
| &method_call, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT, |
| base::BindOnce(&CrasAudioClientImpl::OnGetDefaultOutputBufferSize, |
| weak_ptr_factory_.GetWeakPtr(), std::move(callback))); |
| } |
| |
| void GetSystemAecSupported( |
| chromeos::DBusMethodCallback<bool> callback) override { |
| dbus::MethodCall method_call(cras::kCrasControlInterface, |
| cras::kGetSystemAecSupported); |
| cras_proxy_->CallMethod( |
| &method_call, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT, |
| base::BindOnce(&CrasAudioClientImpl::OnGetSystemAecSupported, |
| weak_ptr_factory_.GetWeakPtr(), std::move(callback))); |
| } |
| |
| void GetSystemAecGroupId( |
| chromeos::DBusMethodCallback<int32_t> callback) override { |
| dbus::MethodCall method_call(cras::kCrasControlInterface, |
| cras::kGetSystemAecGroupId); |
| |
| cras_proxy_->CallMethod( |
| &method_call, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT, |
| base::BindOnce(&CrasAudioClientImpl::OnGetSystemAecGroupId, |
| weak_ptr_factory_.GetWeakPtr(), std::move(callback))); |
| } |
| |
| void GetSystemNsSupported( |
| chromeos::DBusMethodCallback<bool> callback) override { |
| dbus::MethodCall method_call(cras::kCrasControlInterface, |
| cras::kGetSystemNsSupported); |
| cras_proxy_->CallMethod( |
| &method_call, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT, |
| base::BindOnce(&CrasAudioClientImpl::OnGetSystemNsSupported, |
| weak_ptr_factory_.GetWeakPtr(), std::move(callback))); |
| } |
| |
| void GetSystemAgcSupported( |
| chromeos::DBusMethodCallback<bool> callback) override { |
| dbus::MethodCall method_call(cras::kCrasControlInterface, |
| cras::kGetSystemAgcSupported); |
| cras_proxy_->CallMethod( |
| &method_call, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT, |
| base::BindOnce(&CrasAudioClientImpl::OnGetSystemAgcSupported, |
| weak_ptr_factory_.GetWeakPtr(), std::move(callback))); |
| } |
| |
| void GetNodes(chromeos::DBusMethodCallback<AudioNodeList> callback) override { |
| dbus::MethodCall method_call(cras::kCrasControlInterface, cras::kGetNodes); |
| cras_proxy_->CallMethod( |
| &method_call, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT, |
| base::BindOnce(&CrasAudioClientImpl::OnGetNodes, |
| weak_ptr_factory_.GetWeakPtr(), std::move(callback))); |
| } |
| |
| void GetNumberOfActiveOutputStreams( |
| chromeos::DBusMethodCallback<int> callback) override { |
| dbus::MethodCall method_call(cras::kCrasControlInterface, |
| cras::kGetNumberOfActiveOutputStreams); |
| cras_proxy_->CallMethod( |
| &method_call, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT, |
| base::BindOnce(&CrasAudioClientImpl::OnGetNumberOfActiveOutputStreams, |
| weak_ptr_factory_.GetWeakPtr(), std::move(callback))); |
| } |
| |
| void GetNumberOfInputStreamsWithPermission( |
| chromeos::DBusMethodCallback<base::flat_map<std::string, uint32_t>> |
| callback) override { |
| dbus::MethodCall method_call(cras::kCrasControlInterface, |
| cras::kGetNumberOfInputStreamsWithPermission); |
| cras_proxy_->CallMethod( |
| &method_call, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT, |
| base::BindOnce( |
| &CrasAudioClientImpl::OnGetNumberOfInputStreamsWithPermission, |
| weak_ptr_factory_.GetWeakPtr(), std::move(callback))); |
| } |
| |
| void GetDeprioritizeBtWbsMic( |
| chromeos::DBusMethodCallback<bool> callback) override { |
| dbus::MethodCall method_call(cras::kCrasControlInterface, |
| cras::kGetDeprioritizeBtWbsMic); |
| cras_proxy_->CallMethod( |
| &method_call, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT, |
| base::BindOnce(&CrasAudioClientImpl::OnGetDeprioritizeBtWbsMic, |
| weak_ptr_factory_.GetWeakPtr(), std::move(callback))); |
| } |
| |
| void GetNumberOfNonChromeOutputStreams( |
| chromeos::DBusMethodCallback<int32_t> callback) override { |
| dbus::MethodCall method_call(cras::kCrasControlInterface, |
| cras::kGetNumberOfNonChromeOutputStreams); |
| cras_proxy_->CallMethod( |
| &method_call, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT, |
| base::BindOnce( |
| &CrasAudioClientImpl::OnGetNumberOfNonChromeOutputStreams, |
| weak_ptr_factory_.GetWeakPtr(), std::move(callback))); |
| } |
| |
| void GetSpeakOnMuteDetectionEnabled( |
| chromeos::DBusMethodCallback<bool> callback) override { |
| dbus::MethodCall method_call(cras::kCrasControlInterface, |
| cras::kSpeakOnMuteDetectionEnabled); |
| cras_proxy_->CallMethod( |
| &method_call, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT, |
| base::BindOnce(&CrasAudioClientImpl::OnGetSpeakOnMuteDetectionEnabled, |
| weak_ptr_factory_.GetWeakPtr(), std::move(callback))); |
| } |
| |
| void SetOutputNodeVolume(uint64_t node_id, int32_t volume) override { |
| dbus::MethodCall method_call(cras::kCrasControlInterface, |
| cras::kSetOutputNodeVolume); |
| dbus::MessageWriter writer(&method_call); |
| writer.AppendUint64(node_id); |
| writer.AppendInt32(volume); |
| cras_proxy_->CallMethod(&method_call, |
| dbus::ObjectProxy::TIMEOUT_USE_DEFAULT, |
| base::DoNothing()); |
| } |
| |
| void SetOutputUserMute(bool mute_on) override { |
| dbus::MethodCall method_call(cras::kCrasControlInterface, |
| cras::kSetOutputUserMute); |
| dbus::MessageWriter writer(&method_call); |
| writer.AppendBool(mute_on); |
| cras_proxy_->CallMethod(&method_call, |
| dbus::ObjectProxy::TIMEOUT_USE_DEFAULT, |
| base::DoNothing()); |
| } |
| |
| void SetInputNodeGain(uint64_t node_id, int32_t input_gain) override { |
| dbus::MethodCall method_call(cras::kCrasControlInterface, |
| cras::kSetInputNodeGain); |
| dbus::MessageWriter writer(&method_call); |
| writer.AppendUint64(node_id); |
| writer.AppendInt32(input_gain); |
| cras_proxy_->CallMethod(&method_call, |
| dbus::ObjectProxy::TIMEOUT_USE_DEFAULT, |
| base::DoNothing()); |
| } |
| |
| void SetInputMute(bool mute_on) override { |
| dbus::MethodCall method_call(cras::kCrasControlInterface, |
| cras::kSetInputMute); |
| dbus::MessageWriter writer(&method_call); |
| writer.AppendBool(mute_on); |
| cras_proxy_->CallMethod(&method_call, |
| dbus::ObjectProxy::TIMEOUT_USE_DEFAULT, |
| base::DoNothing()); |
| } |
| |
| void SetNoiseCancellationEnabled(bool noise_cancellation_on) override { |
| VLOG(1) << "cras_audio_client: Setting noise cancellation state: " |
| << noise_cancellation_on; |
| dbus::MethodCall method_call(cras::kCrasControlInterface, |
| cras::kSetNoiseCancellationEnabled); |
| dbus::MessageWriter writer(&method_call); |
| writer.AppendBool(noise_cancellation_on); |
| cras_proxy_->CallMethod(&method_call, |
| dbus::ObjectProxy::TIMEOUT_USE_DEFAULT, |
| base::DoNothing()); |
| } |
| |
| void GetNoiseCancellationSupported( |
| chromeos::DBusMethodCallback<bool> callback) override { |
| VLOG(1) << "cras_audio_client: Requesting noise cancellation support."; |
| dbus::MethodCall method_call(cras::kCrasControlInterface, |
| cras::kIsNoiseCancellationSupported); |
| cras_proxy_->CallMethod( |
| &method_call, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT, |
| base::BindOnce(&CrasAudioClientImpl::OnGetNoiseCancellationSupported, |
| weak_ptr_factory_.GetWeakPtr(), std::move(callback))); |
| } |
| |
| void SetActiveOutputNode(uint64_t node_id) override { |
| dbus::MethodCall method_call(cras::kCrasControlInterface, |
| cras::kSetActiveOutputNode); |
| dbus::MessageWriter writer(&method_call); |
| writer.AppendUint64(node_id); |
| cras_proxy_->CallMethod(&method_call, |
| dbus::ObjectProxy::TIMEOUT_USE_DEFAULT, |
| base::DoNothing()); |
| } |
| |
| void SetActiveInputNode(uint64_t node_id) override { |
| dbus::MethodCall method_call(cras::kCrasControlInterface, |
| cras::kSetActiveInputNode); |
| dbus::MessageWriter writer(&method_call); |
| writer.AppendUint64(node_id); |
| cras_proxy_->CallMethod(&method_call, |
| dbus::ObjectProxy::TIMEOUT_USE_DEFAULT, |
| base::DoNothing()); |
| } |
| |
| void SetHotwordModel(uint64_t node_id, |
| const std::string& hotword_model, |
| chromeos::VoidDBusMethodCallback callback) override { |
| dbus::MethodCall method_call(cras::kCrasControlInterface, |
| cras::kSetHotwordModel); |
| dbus::MessageWriter writer(&method_call); |
| writer.AppendUint64(node_id); |
| writer.AppendString(hotword_model); |
| cras_proxy_->CallMethod( |
| &method_call, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT, |
| base::BindOnce(&CrasAudioClientImpl::OnSetHotwordModel, |
| weak_ptr_factory_.GetWeakPtr(), std::move(callback))); |
| } |
| |
| void SetFixA2dpPacketSize(bool enabled) override { |
| dbus::MethodCall method_call(cras::kCrasControlInterface, |
| cras::kSetFixA2dpPacketSize); |
| dbus::MessageWriter writer(&method_call); |
| writer.AppendBool(enabled); |
| cras_proxy_->CallMethod(&method_call, |
| dbus::ObjectProxy::TIMEOUT_USE_DEFAULT, |
| base::DoNothing()); |
| } |
| |
| void SetFlossEnabled(bool enabled) override { |
| dbus::MethodCall method_call(cras::kCrasControlInterface, |
| cras::kSetFlossEnabled); |
| dbus::MessageWriter writer(&method_call); |
| writer.AppendBool(enabled); |
| cras_proxy_->CallMethod(&method_call, |
| dbus::ObjectProxy::TIMEOUT_USE_DEFAULT, |
| base::DoNothing()); |
| } |
| |
| void SetSpeakOnMuteDetection(bool enabled) override { |
| dbus::MethodCall method_call(cras::kCrasControlInterface, |
| cras::kSetSpeakOnMuteDetection); |
| dbus::MessageWriter writer(&method_call); |
| writer.AppendBool(enabled); |
| cras_proxy_->CallMethod(&method_call, |
| dbus::ObjectProxy::TIMEOUT_USE_DEFAULT, |
| base::DoNothing()); |
| } |
| |
| void AddActiveInputNode(uint64_t node_id) override { |
| dbus::MethodCall method_call(cras::kCrasControlInterface, |
| cras::kAddActiveInputNode); |
| dbus::MessageWriter writer(&method_call); |
| writer.AppendUint64(node_id); |
| cras_proxy_->CallMethod(&method_call, |
| dbus::ObjectProxy::TIMEOUT_USE_DEFAULT, |
| base::DoNothing()); |
| } |
| |
| void RemoveActiveInputNode(uint64_t node_id) override { |
| dbus::MethodCall method_call(cras::kCrasControlInterface, |
| cras::kRemoveActiveInputNode); |
| dbus::MessageWriter writer(&method_call); |
| writer.AppendUint64(node_id); |
| cras_proxy_->CallMethod(&method_call, |
| dbus::ObjectProxy::TIMEOUT_USE_DEFAULT, |
| base::DoNothing()); |
| } |
| |
| void AddActiveOutputNode(uint64_t node_id) override { |
| dbus::MethodCall method_call(cras::kCrasControlInterface, |
| cras::kAddActiveOutputNode); |
| dbus::MessageWriter writer(&method_call); |
| writer.AppendUint64(node_id); |
| cras_proxy_->CallMethod(&method_call, |
| dbus::ObjectProxy::TIMEOUT_USE_DEFAULT, |
| base::DoNothing()); |
| } |
| |
| void RemoveActiveOutputNode(uint64_t node_id) override { |
| dbus::MethodCall method_call(cras::kCrasControlInterface, |
| cras::kRemoveActiveOutputNode); |
| dbus::MessageWriter writer(&method_call); |
| writer.AppendUint64(node_id); |
| cras_proxy_->CallMethod(&method_call, |
| dbus::ObjectProxy::TIMEOUT_USE_DEFAULT, |
| base::DoNothing()); |
| } |
| |
| void SwapLeftRight(uint64_t node_id, bool swap) override { |
| dbus::MethodCall method_call(cras::kCrasControlInterface, |
| cras::kSwapLeftRight); |
| dbus::MessageWriter writer(&method_call); |
| writer.AppendUint64(node_id); |
| writer.AppendBool(swap); |
| cras_proxy_->CallMethod(&method_call, |
| dbus::ObjectProxy::TIMEOUT_USE_DEFAULT, |
| base::DoNothing()); |
| } |
| |
| void SetDisplayRotation(uint64_t node_id, |
| cras::DisplayRotation rotation) override { |
| dbus::MethodCall method_call(cras::kCrasControlInterface, |
| cras::kSetDisplayRotation); |
| dbus::MessageWriter writer(&method_call); |
| writer.AppendUint64(node_id); |
| writer.AppendUint32(static_cast<uint32_t>(rotation)); |
| cras_proxy_->CallMethod(&method_call, |
| dbus::ObjectProxy::TIMEOUT_USE_DEFAULT, |
| base::DoNothing()); |
| } |
| |
| void SetGlobalOutputChannelRemix(int32_t channels, |
| const std::vector<double>& mixer) override { |
| dbus::MethodCall method_call(cras::kCrasControlInterface, |
| cras::kSetGlobalOutputChannelRemix); |
| dbus::MessageWriter writer(&method_call); |
| writer.AppendInt32(channels); |
| writer.AppendArrayOfDoubles(mixer.data(), mixer.size()); |
| cras_proxy_->CallMethod(&method_call, |
| dbus::ObjectProxy::TIMEOUT_USE_DEFAULT, |
| base::DoNothing()); |
| } |
| |
| void SetPlayerPlaybackStatus(const std::string& playback_status) override { |
| dbus::MethodCall method_call(cras::kCrasControlInterface, |
| cras::kSetPlayerPlaybackStatus); |
| dbus::MessageWriter writer(&method_call); |
| writer.AppendString(playback_status); |
| cras_proxy_->CallMethod(&method_call, |
| dbus::ObjectProxy::TIMEOUT_USE_DEFAULT, |
| base::DoNothing()); |
| } |
| |
| void SetPlayerIdentity(const std::string& identity) override { |
| dbus::MethodCall method_call(cras::kCrasControlInterface, |
| cras::kSetPlayerIdentity); |
| dbus::MessageWriter writer(&method_call); |
| writer.AppendString(identity); |
| cras_proxy_->CallMethod(&method_call, |
| dbus::ObjectProxy::TIMEOUT_USE_DEFAULT, |
| base::DoNothing()); |
| } |
| |
| void SetPlayerPosition(const int64_t& position) override { |
| dbus::MethodCall method_call(cras::kCrasControlInterface, |
| cras::kSetPlayerPosition); |
| dbus::MessageWriter writer(&method_call); |
| writer.AppendInt64(position); |
| cras_proxy_->CallMethod(&method_call, |
| dbus::ObjectProxy::TIMEOUT_USE_DEFAULT, |
| base::DoNothing()); |
| } |
| |
| void SetPlayerDuration(const int64_t& duration) override { |
| dbus::MethodCall method_call(cras::kCrasControlInterface, |
| cras::kSetPlayerMetadata); |
| dbus::MessageWriter writer(&method_call); |
| dbus::MessageWriter array_writer(nullptr); |
| dbus::MessageWriter dict_entry_writer(nullptr); |
| |
| writer.OpenArray("{sv}", &array_writer); |
| array_writer.OpenDictEntry(&dict_entry_writer); |
| dict_entry_writer.AppendString("length"); |
| dict_entry_writer.AppendVariantOfInt64(duration); |
| array_writer.CloseContainer(&dict_entry_writer); |
| writer.CloseContainer(&array_writer); |
| |
| cras_proxy_->CallMethod(&method_call, |
| dbus::ObjectProxy::TIMEOUT_USE_DEFAULT, |
| base::DoNothing()); |
| } |
| |
| void SetPlayerMetadata( |
| const std::map<std::string, std::string>& metadata) override { |
| dbus::MethodCall method_call(cras::kCrasControlInterface, |
| cras::kSetPlayerMetadata); |
| dbus::MessageWriter writer(&method_call); |
| dbus::MessageWriter array_writer(nullptr); |
| dbus::MessageWriter dict_entry_writer(nullptr); |
| |
| writer.OpenArray("{sv}", &array_writer); |
| |
| for (auto& it : metadata) { |
| array_writer.OpenDictEntry(&dict_entry_writer); |
| dict_entry_writer.AppendString(it.first); |
| dict_entry_writer.AppendVariantOfString(it.second); |
| array_writer.CloseContainer(&dict_entry_writer); |
| } |
| |
| writer.CloseContainer(&array_writer); |
| |
| cras_proxy_->CallMethod(&method_call, |
| dbus::ObjectProxy::TIMEOUT_USE_DEFAULT, |
| base::DoNothing()); |
| } |
| |
| void ResendBluetoothBattery() override { |
| dbus::MethodCall method_call(cras::kCrasControlInterface, |
| cras::kResendBluetoothBattery); |
| cras_proxy_->CallMethod(&method_call, |
| dbus::ObjectProxy::TIMEOUT_USE_DEFAULT, |
| base::DoNothing()); |
| } |
| |
| void WaitForServiceToBeAvailable( |
| chromeos::WaitForServiceToBeAvailableCallback callback) override { |
| cras_proxy_->WaitForServiceToBeAvailable(std::move(callback)); |
| } |
| |
| private: |
| // Called when the cras signal is initially connected. |
| void SignalConnected(const std::string& interface_name, |
| const std::string& signal_name, |
| bool success) { |
| LOG_IF(ERROR, !success) |
| << "Failed to connect to cras signal:" << signal_name; |
| } |
| |
| void NameOwnerChangedReceived(const std::string& old_owner, |
| const std::string& new_owner) { |
| for (auto& observer : observers_) { |
| observer.AudioClientRestarted(); |
| } |
| } |
| |
| // Called when a OutputMuteChanged signal is received. |
| void OutputMuteChangedReceived(dbus::Signal* signal) { |
| // Chrome should always call SetOutputUserMute api to set the output |
| // mute state and monitor user_mute state from OutputMuteChanged signal. |
| dbus::MessageReader reader(signal); |
| bool system_mute, user_mute; |
| if (!reader.PopBool(&system_mute) || !reader.PopBool(&user_mute)) { |
| LOG(ERROR) << "Error reading signal from cras:" << signal->ToString(); |
| } |
| for (auto& observer : observers_) { |
| observer.OutputMuteChanged(user_mute); |
| } |
| } |
| |
| // Called when a InputMuteChanged signal is received. |
| void InputMuteChangedReceived(dbus::Signal* signal) { |
| dbus::MessageReader reader(signal); |
| bool mute; |
| if (!reader.PopBool(&mute)) { |
| LOG(ERROR) << "Error reading signal from cras:" << signal->ToString(); |
| } |
| for (auto& observer : observers_) { |
| observer.InputMuteChanged(mute); |
| } |
| } |
| |
| void NodesChangedReceived(dbus::Signal* signal) { |
| for (auto& observer : observers_) { |
| observer.NodesChanged(); |
| } |
| } |
| |
| void ActiveOutputNodeChangedReceived(dbus::Signal* signal) { |
| dbus::MessageReader reader(signal); |
| uint64_t node_id; |
| if (!reader.PopUint64(&node_id)) { |
| LOG(ERROR) << "Error reading signal from cras:" << signal->ToString(); |
| } |
| for (auto& observer : observers_) { |
| observer.ActiveOutputNodeChanged(node_id); |
| } |
| } |
| |
| void ActiveInputNodeChangedReceived(dbus::Signal* signal) { |
| dbus::MessageReader reader(signal); |
| uint64_t node_id; |
| if (!reader.PopUint64(&node_id)) { |
| LOG(ERROR) << "Error reading signal from cras:" << signal->ToString(); |
| } |
| for (auto& observer : observers_) { |
| observer.ActiveInputNodeChanged(node_id); |
| } |
| } |
| |
| void OutputNodeVolumeChangedReceived(dbus::Signal* signal) { |
| dbus::MessageReader reader(signal); |
| uint64_t node_id; |
| int volume; |
| |
| if (!reader.PopUint64(&node_id)) { |
| LOG(ERROR) << "Error reading signal from cras:" << signal->ToString(); |
| } |
| if (!reader.PopInt32(&volume)) { |
| LOG(ERROR) << "Error reading signal from cras:" << signal->ToString(); |
| } |
| for (auto& observer : observers_) { |
| observer.OutputNodeVolumeChanged(node_id, volume); |
| } |
| } |
| |
| void InputNodeGainChangedReceived(dbus::Signal* signal) { |
| dbus::MessageReader reader(signal); |
| uint64_t node_id; |
| int gain; |
| |
| if (!reader.PopUint64(&node_id)) { |
| LOG(ERROR) << "Error reading signal from cras:" << signal->ToString(); |
| } |
| if (!reader.PopInt32(&gain)) { |
| LOG(ERROR) << "Error reading signal from cras:" << signal->ToString(); |
| } |
| for (auto& observer : observers_) { |
| observer.InputNodeGainChanged(node_id, gain); |
| } |
| } |
| |
| void HotwordTriggeredReceived(dbus::Signal* signal) { |
| dbus::MessageReader reader(signal); |
| int64_t tv_sec, tv_nsec; |
| |
| if (!reader.PopInt64(&tv_sec)) { |
| LOG(ERROR) << "Error reading signal from cras:" << signal->ToString(); |
| return; |
| } |
| |
| if (!reader.PopInt64(&tv_nsec)) { |
| LOG(ERROR) << "Error reading signal from cras:" << signal->ToString(); |
| return; |
| } |
| for (auto& observer : observers_) { |
| observer.HotwordTriggered(tv_sec, tv_nsec); |
| } |
| } |
| |
| void NumberOfActiveStreamsChangedReceived(dbus::Signal* signal) { |
| dbus::MessageReader reader(signal); |
| // We skip reading the output because it is not used by the observers. |
| for (auto& observer : observers_) { |
| observer.NumberOfActiveStreamsChanged(); |
| } |
| } |
| |
| void NumberOfInputStreamsWithPermissionReceived(dbus::Signal* signal) { |
| dbus::MessageReader signal_reader(signal); |
| dbus::MessageReader array_reader(nullptr); |
| base::flat_map<std::string, uint32_t> res; |
| while (signal_reader.HasMoreData()) { |
| if (!signal_reader.PopArray(&array_reader)) { |
| LOG(ERROR) << "Error reading signal from cras: " << signal->ToString(); |
| return; |
| } |
| std::string client_type; |
| uint32_t num_input_streams; |
| if (!GetNumerInputStreams(&array_reader, &client_type, |
| &num_input_streams)) { |
| LOG(ERROR) << "Error reading number of input streams from cras: " |
| << signal->ToString(); |
| return; |
| } |
| res[client_type] = num_input_streams; |
| } |
| |
| for (auto& observer : observers_) { |
| observer.NumberOfInputStreamsWithPermissionChanged(res); |
| } |
| } |
| |
| void BluetoothBatteryChangedReceived(dbus::Signal* signal) { |
| dbus::MessageReader reader(signal); |
| std::string address; |
| uint32_t level; |
| |
| if (!reader.PopString(&address)) { |
| LOG(ERROR) << "Error reading signal from cras:" << signal->ToString(); |
| return; |
| } |
| |
| if (!reader.PopUint32(&level)) { |
| LOG(ERROR) << "Error reading signal from cras:" << signal->ToString(); |
| return; |
| } |
| for (auto& observer : observers_) { |
| observer.BluetoothBatteryChanged(address, level); |
| } |
| } |
| |
| void OnGetVolumeState(chromeos::DBusMethodCallback<VolumeState> callback, |
| dbus::Response* response) { |
| if (!response) { |
| LOG(ERROR) << "Error calling " << cras::kGetVolumeState; |
| std::move(callback).Run(absl::nullopt); |
| return; |
| } |
| |
| VolumeState volume_state; |
| dbus::MessageReader reader(response); |
| if (!reader.PopInt32(&volume_state.output_volume) || |
| !reader.PopBool(&volume_state.output_system_mute) || |
| !reader.PopInt32(&volume_state.input_gain) || |
| !reader.PopBool(&volume_state.input_mute) || |
| !reader.PopBool(&volume_state.output_user_mute)) { |
| LOG(ERROR) << "Error reading response from cras: " |
| << response->ToString(); |
| std::move(callback).Run(absl::nullopt); |
| return; |
| } |
| |
| std::move(callback).Run(std::move(volume_state)); |
| } |
| |
| bool PopSurveyKeyValue(dbus::MessageReader* array_reader, |
| std::string* key, |
| std::string* val) { |
| dbus::MessageReader dict_entry_reader(nullptr); |
| |
| if (!array_reader->HasMoreData() || |
| !array_reader->PopDictEntry(&dict_entry_reader) || |
| !dict_entry_reader.PopString(key) || |
| !dict_entry_reader.PopVariantOfString(val)) { |
| return false; |
| } |
| |
| return true; |
| } |
| |
| void SurveyTriggerReceived(dbus::Signal* signal) { |
| dbus::MessageReader signal_reader(signal); |
| dbus::MessageReader array_reader(nullptr); |
| base::flat_map<std::string, std::string> res; |
| |
| while (signal_reader.HasMoreData()) { |
| if (!signal_reader.PopArray(&array_reader)) { |
| LOG(ERROR) << "Error reading signal from cras: " << signal->ToString(); |
| return; |
| } |
| |
| // Chrome HaTS survey system supports logging a map of survey specific |
| // data for better data interpretation. |
| // For general audio satisfaction survey as an example, we shall get the |
| // snapshot of stream type, client type and also active node type pair |
| // when the user closes a stream living longer than a specified perioid |
| // of time. We can use the data to identify the user scenario we'd like |
| // to improve, such as voice communication on Chrome through Bluetooth. |
| std::string key; |
| std::string val; |
| while (array_reader.HasMoreData()) { |
| if (!PopSurveyKeyValue(&array_reader, &key, &val)) { |
| LOG(ERROR) << "Error reading key value pairs of the data from cras: " |
| << signal->ToString(); |
| return; |
| } |
| |
| res[key] = val; |
| } |
| } |
| |
| for (auto& observer : observers_) { |
| observer.SurveyTriggered(res); |
| } |
| } |
| |
| void SpeakOnMuteDetectedReceived(dbus::Signal* signal) { |
| for (auto& observer : observers_) { |
| observer.SpeakOnMuteDetected(); |
| } |
| } |
| |
| void NumberOfNonChromeOutputStreamsChangedReceived(dbus::Signal* signal) { |
| for (auto& observer : observers_) { |
| observer.NumberOfNonChromeOutputStreamsChanged(); |
| } |
| } |
| |
| void OnGetDefaultOutputBufferSize(chromeos::DBusMethodCallback<int> callback, |
| dbus::Response* response) { |
| if (!response) { |
| LOG(ERROR) << "Error calling " << cras::kGetDefaultOutputBufferSize; |
| std::move(callback).Run(absl::nullopt); |
| return; |
| } |
| int32_t buffer_size = 0; |
| dbus::MessageReader reader(response); |
| if (!reader.PopInt32(&buffer_size)) { |
| LOG(ERROR) << "Error reading response from cras: " |
| << response->ToString(); |
| std::move(callback).Run(absl::nullopt); |
| return; |
| } |
| |
| std::move(callback).Run(buffer_size); |
| } |
| |
| void OnGetSystemAecSupported(chromeos::DBusMethodCallback<bool> callback, |
| dbus::Response* response) { |
| if (!response) { |
| LOG(ERROR) << "Error calling " << cras::kGetSystemAecSupported; |
| std::move(callback).Run(absl::nullopt); |
| return; |
| } |
| bool system_aec_supported = 0; |
| dbus::MessageReader reader(response); |
| if (!reader.PopBool(&system_aec_supported)) { |
| LOG(ERROR) << "Error reading response from cras: " |
| << response->ToString(); |
| std::move(callback).Run(absl::nullopt); |
| return; |
| } |
| |
| std::move(callback).Run(system_aec_supported); |
| } |
| |
| void OnGetSystemAecGroupId(chromeos::DBusMethodCallback<int32_t> callback, |
| dbus::Response* response) { |
| if (!response) { |
| LOG(ERROR) << "Error calling " << cras::kGetSystemAecGroupId; |
| std::move(callback).Run(absl::nullopt); |
| return; |
| } |
| int32_t system_aec_group_id = 0; |
| dbus::MessageReader reader(response); |
| if (!reader.PopInt32(&system_aec_group_id)) { |
| LOG(ERROR) << "Error reading response from cras: " |
| << response->ToString(); |
| std::move(callback).Run(absl::nullopt); |
| return; |
| } |
| |
| std::move(callback).Run(system_aec_group_id); |
| } |
| |
| void OnGetSystemNsSupported(chromeos::DBusMethodCallback<bool> callback, |
| dbus::Response* response) { |
| if (!response) { |
| LOG(ERROR) << "Error calling " << cras::kGetSystemNsSupported; |
| std::move(callback).Run(absl::nullopt); |
| return; |
| } |
| bool system_ns_supported = 0; |
| dbus::MessageReader reader(response); |
| if (!reader.PopBool(&system_ns_supported)) { |
| LOG(ERROR) << "Error reading response from cras: " |
| << response->ToString(); |
| std::move(callback).Run(absl::nullopt); |
| return; |
| } |
| |
| std::move(callback).Run(system_ns_supported); |
| } |
| |
| void OnGetSystemAgcSupported(chromeos::DBusMethodCallback<bool> callback, |
| dbus::Response* response) { |
| if (!response) { |
| LOG(ERROR) << "Error calling " << cras::kGetSystemAgcSupported; |
| std::move(callback).Run(absl::nullopt); |
| return; |
| } |
| bool system_agc_supported = 0; |
| dbus::MessageReader reader(response); |
| if (!reader.PopBool(&system_agc_supported)) { |
| LOG(ERROR) << "Error reading response from cras: " |
| << response->ToString(); |
| std::move(callback).Run(absl::nullopt); |
| return; |
| } |
| |
| std::move(callback).Run(system_agc_supported); |
| } |
| |
| void OnGetNodes(chromeos::DBusMethodCallback<AudioNodeList> callback, |
| dbus::Response* response) { |
| if (!response) { |
| std::move(callback).Run(absl::nullopt); |
| return; |
| } |
| |
| AudioNodeList node_list; |
| dbus::MessageReader response_reader(response); |
| dbus::MessageReader array_reader(response); |
| while (response_reader.HasMoreData()) { |
| if (!response_reader.PopArray(&array_reader)) { |
| LOG(ERROR) << "Error reading response from cras: " |
| << response->ToString(); |
| std::move(callback).Run(absl::nullopt); |
| return; |
| } |
| |
| AudioNode node; |
| if (!GetAudioNode(response, &array_reader, &node)) { |
| LOG(WARNING) << "Error reading audio node data from cras: " |
| << response->ToString(); |
| std::move(callback).Run(absl::nullopt); |
| return; |
| } |
| |
| // Filter out the "UNKNOWN" type of audio devices. |
| if (node.type != "UNKNOWN") { |
| node_list.push_back(std::move(node)); |
| } |
| } |
| |
| std::move(callback).Run(std::move(node_list)); |
| } |
| |
| void OnGetNumberOfNonChromeOutputStreams( |
| chromeos::DBusMethodCallback<int32_t> callback, |
| dbus::Response* response) { |
| if (!response) { |
| LOG(ERROR) << "Error calling " |
| << cras::kGetNumberOfNonChromeOutputStreams; |
| std::move(callback).Run(absl::nullopt); |
| return; |
| } |
| int32_t num_active_streams = 0; |
| dbus::MessageReader reader(response); |
| if (!reader.PopInt32(&num_active_streams)) { |
| LOG(ERROR) << "Error reading response from cras: " |
| << response->ToString(); |
| std::move(callback).Run(absl::nullopt); |
| return; |
| } |
| std::move(callback).Run(num_active_streams); |
| } |
| |
| void OnGetNumberOfActiveOutputStreams( |
| chromeos::DBusMethodCallback<int> callback, |
| dbus::Response* response) { |
| if (!response) { |
| LOG(ERROR) << "Error calling " << cras::kGetNumberOfActiveOutputStreams; |
| std::move(callback).Run(absl::nullopt); |
| return; |
| } |
| int32_t num_active_streams = 0; |
| dbus::MessageReader reader(response); |
| if (!reader.PopInt32(&num_active_streams)) { |
| LOG(ERROR) << "Error reading response from cras: " |
| << response->ToString(); |
| std::move(callback).Run(absl::nullopt); |
| return; |
| } |
| |
| std::move(callback).Run(num_active_streams); |
| } |
| |
| bool GetNumerInputStreams(dbus::MessageReader* array_reader, |
| std::string* client_type, |
| uint32_t* num_input_streams) { |
| while (array_reader->HasMoreData()) { |
| dbus::MessageReader dict_entry_reader(nullptr); |
| dbus::MessageReader value_reader(nullptr); |
| std::string key; |
| if (!array_reader->PopDictEntry(&dict_entry_reader) || |
| !dict_entry_reader.PopString(&key) || |
| !dict_entry_reader.PopVariant(&value_reader)) { |
| return false; |
| } |
| |
| if (key == cras::kClientType) { |
| if (!value_reader.PopString(client_type)) { |
| return false; |
| } |
| } else if (key == cras::kNumStreamsWithPermission) { |
| if (!value_reader.PopUint32(num_input_streams)) { |
| return false; |
| } |
| } |
| } |
| return true; |
| } |
| |
| void OnGetNumberOfInputStreamsWithPermission( |
| chromeos::DBusMethodCallback<base::flat_map<std::string, uint32_t>> |
| callback, |
| dbus::Response* response) { |
| if (!response) { |
| LOG(ERROR) << "Error calling " |
| << cras::kGetNumberOfInputStreamsWithPermission; |
| std::move(callback).Run(absl::nullopt); |
| return; |
| } |
| dbus::MessageReader response_reader(response); |
| dbus::MessageReader array_reader(nullptr); |
| base::flat_map<std::string, uint32_t> res; |
| while (response_reader.HasMoreData()) { |
| if (!response_reader.PopArray(&array_reader)) { |
| LOG(ERROR) << "Error reading response from cras: " |
| << response->ToString(); |
| std::move(callback).Run(absl::nullopt); |
| return; |
| } |
| std::string client_type; |
| uint32_t num_input_streams; |
| if (!GetNumerInputStreams(&array_reader, &client_type, |
| &num_input_streams)) { |
| LOG(ERROR) << "Error reading number of input streams from cras: " |
| << response->ToString(); |
| std::move(callback).Run(absl::nullopt); |
| return; |
| } |
| res[client_type] = num_input_streams; |
| } |
| |
| std::move(callback).Run(std::move(res)); |
| } |
| |
| void OnGetDeprioritizeBtWbsMic(chromeos::DBusMethodCallback<bool> callback, |
| dbus::Response* response) { |
| if (!response) { |
| LOG(ERROR) << "Error calling " |
| << "GetDeprioritizeBtWbsMic"; |
| std::move(callback).Run(absl::nullopt); |
| return; |
| } |
| bool deprioritize_bt_wbs_mic = 0; |
| dbus::MessageReader reader(response); |
| if (!reader.PopBool(&deprioritize_bt_wbs_mic)) { |
| LOG(ERROR) << "Error reading response from cras: " |
| << response->ToString(); |
| std::move(callback).Run(absl::nullopt); |
| return; |
| } |
| std::move(callback).Run(deprioritize_bt_wbs_mic); |
| } |
| |
| void OnSetHotwordModel(chromeos::VoidDBusMethodCallback callback, |
| dbus::Response* response) { |
| if (!response) { |
| LOG(ERROR) << "Failed to call SetHotwordModel."; |
| std::move(callback).Run(false); |
| return; |
| } |
| |
| dbus::MessageReader reader(response); |
| int32_t result; |
| if (!reader.PopInt32(&result)) { |
| LOG(ERROR) << "Failed to parse results from SetHotwordModel."; |
| std::move(callback).Run(false); |
| return; |
| } |
| |
| if (result != 0) { |
| LOG(ERROR) << "Errors in SetHotwordModel."; |
| std::move(callback).Run(false); |
| return; |
| } |
| |
| std::move(callback).Run(true); |
| } |
| |
| void OnGetNoiseCancellationSupported( |
| chromeos::DBusMethodCallback<bool> callback, |
| dbus::Response* response) { |
| if (!response) { |
| LOG(ERROR) << "Error calling " |
| << "GetNoiseCancellationSupported"; |
| std::move(callback).Run(absl::nullopt); |
| return; |
| } |
| bool is_noise_cancellation_supported = 0; |
| dbus::MessageReader reader(response); |
| if (!reader.PopBool(&is_noise_cancellation_supported)) { |
| LOG(ERROR) << "Error reading response from cras: " |
| << response->ToString(); |
| std::move(callback).Run(absl::nullopt); |
| return; |
| } |
| std::move(callback).Run(is_noise_cancellation_supported); |
| VLOG(1) << "cras_audio_client: Retrieved noise cancellation support: " |
| << is_noise_cancellation_supported; |
| } |
| |
| bool GetAudioNode(dbus::Response* response, |
| dbus::MessageReader* array_reader, |
| AudioNode* node) { |
| while (array_reader->HasMoreData()) { |
| dbus::MessageReader dict_entry_reader(response); |
| dbus::MessageReader value_reader(response); |
| std::string key; |
| if (!array_reader->PopDictEntry(&dict_entry_reader) || |
| !dict_entry_reader.PopString(&key) || |
| !dict_entry_reader.PopVariant(&value_reader)) { |
| return false; |
| } |
| |
| if (key == cras::kIsInputProperty) { |
| if (!value_reader.PopBool(&node->is_input)) { |
| return false; |
| } |
| } else if (key == cras::kIdProperty) { |
| if (!value_reader.PopUint64(&node->id)) { |
| return false; |
| } |
| } else if (key == cras::kDeviceNameProperty) { |
| if (!value_reader.PopString(&node->device_name)) { |
| return false; |
| } |
| } else if (key == cras::kTypeProperty) { |
| if (!value_reader.PopString(&node->type)) { |
| return false; |
| } |
| } else if (key == cras::kNameProperty) { |
| if (!value_reader.PopString(&node->name)) { |
| return false; |
| } |
| } else if (key == cras::kActiveProperty) { |
| if (!value_reader.PopBool(&node->active)) { |
| return false; |
| } |
| } else if (key == cras::kPluggedTimeProperty) { |
| if (!value_reader.PopUint64(&node->plugged_time)) { |
| return false; |
| } |
| } else if (key == cras::kStableDeviceIdProperty) { |
| if (!value_reader.PopUint64(&node->stable_device_id_v1)) { |
| return false; |
| } |
| } else if (key == cras::kStableDeviceIdNewProperty) { |
| if (!value_reader.PopUint64(&node->stable_device_id_v2)) { |
| return false; |
| } |
| node->has_v2_stable_device_id = true; |
| } else if (key == cras::kMaxSupportedChannelsProperty) { |
| if (!value_reader.PopUint32(&node->max_supported_channels)) { |
| return false; |
| } |
| } else if (key == cras::kAudioEffectProperty) { |
| if (!value_reader.PopUint32(&node->audio_effect)) { |
| return false; |
| } |
| } else if (key == cras::kNumberOfVolumeStepsProperty) { |
| if (!value_reader.PopInt32(&node->number_of_volume_steps)) { |
| return false; |
| } |
| } |
| } |
| |
| return true; |
| } |
| |
| void OnGetSpeakOnMuteDetectionEnabled( |
| chromeos::DBusMethodCallback<bool> callback, |
| dbus::Response* response) { |
| if (!response) { |
| LOG(ERROR) << "Error calling " |
| << "GetSpeakOnMuteDetectionEnabled"; |
| std::move(callback).Run(absl::nullopt); |
| return; |
| } |
| bool speak_on_mute_detection_enabled = false; |
| dbus::MessageReader reader(response); |
| if (!reader.PopBool(&speak_on_mute_detection_enabled)) { |
| LOG(ERROR) << "Error reading response from cras: " |
| << response->ToString(); |
| std::move(callback).Run(absl::nullopt); |
| return; |
| } |
| std::move(callback).Run(speak_on_mute_detection_enabled); |
| } |
| |
| raw_ptr<dbus::ObjectProxy, ExperimentalAsh> cras_proxy_ = nullptr; |
| base::ObserverList<Observer>::Unchecked observers_; |
| |
| // Note: This should remain the last member so it'll be destroyed and |
| // invalidate its weak pointers before any other members are destroyed. |
| base::WeakPtrFactory<CrasAudioClientImpl> weak_ptr_factory_{this}; |
| }; |
| |
| } // namespace |
| |
| CrasAudioClient::Observer::~Observer() = default; |
| |
| void CrasAudioClient::Observer::AudioClientRestarted() {} |
| |
| void CrasAudioClient::Observer::OutputMuteChanged(bool mute_on) {} |
| |
| void CrasAudioClient::Observer::InputMuteChanged(bool mute_on) {} |
| |
| void CrasAudioClient::Observer::NodesChanged() {} |
| |
| void CrasAudioClient::Observer::ActiveOutputNodeChanged(uint64_t node_id) {} |
| |
| void CrasAudioClient::Observer::ActiveInputNodeChanged(uint64_t node_id) {} |
| |
| void CrasAudioClient::Observer::OutputNodeVolumeChanged(uint64_t node_id, |
| int volume) {} |
| |
| void CrasAudioClient::Observer::InputNodeGainChanged(uint64_t node_id, |
| int gain) {} |
| |
| void CrasAudioClient::Observer::HotwordTriggered(uint64_t tv_sec, |
| uint64_t tv_nsec) {} |
| |
| void CrasAudioClient::Observer::NumberOfActiveStreamsChanged() {} |
| |
| void CrasAudioClient::Observer::BluetoothBatteryChanged( |
| const std::string& address, |
| uint32_t level) {} |
| |
| void CrasAudioClient::Observer::NumberOfInputStreamsWithPermissionChanged( |
| const base::flat_map<std::string, uint32_t>& num_input_streams) {} |
| |
| void CrasAudioClient::Observer::SurveyTriggered( |
| const base::flat_map<std::string, std::string>& survey_specific_data) {} |
| |
| void CrasAudioClient::Observer::SpeakOnMuteDetected() {} |
| |
| void CrasAudioClient::Observer::NumberOfNonChromeOutputStreamsChanged() {} |
| |
| CrasAudioClient::CrasAudioClient() { |
| DCHECK(!g_instance); |
| g_instance = this; |
| } |
| |
| CrasAudioClient::~CrasAudioClient() { |
| DCHECK_EQ(this, g_instance); |
| g_instance = nullptr; |
| } |
| |
| // static |
| void CrasAudioClient::Initialize(dbus::Bus* bus) { |
| DCHECK(bus); |
| new CrasAudioClientImpl(bus); |
| } |
| |
| // static |
| void CrasAudioClient::InitializeFake() { |
| new FakeCrasAudioClient(); |
| } |
| |
| // static |
| void CrasAudioClient::Shutdown() { |
| delete g_instance; |
| } |
| |
| // static |
| CrasAudioClient* CrasAudioClient::Get() { |
| return g_instance; |
| } |
| |
| } // namespace ash |