// Copyright 2015 The Chromium 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 "chromeos/dbus/audio_dsp_client.h" #include "base/bind.h" #include "base/memory/weak_ptr.h" #include "base/message_loop/message_loop.h" #include "base/observer_list.h" #include "dbus/bus.h" #include "dbus/message.h" #include "dbus/object_path.h" #include "dbus/object_proxy.h" namespace chromeos { namespace { // TODO(benchan): Move these DBus constants to system_api. namespace audio_dsp { const char kAudioDspInterface[] = "org.chromium.AudioDsp"; const char kAudioDspServiceName[] = "org.chromium.AudioDsp"; const char kAudioDspServicePath[] = "/org/chromium/AudioDsp"; const char kInitializeMethod[] = "Initialize"; const char kSetStandbyModeMethod[] = "SetStandbyMode"; const char kSetNightModeMethod[] = "SetNightMode"; const char kSetTrebleMethod[] = "SetTreble"; const char kSetBassMethod[] = "SetBass"; const char kGetNightModeMethod[] = "GetNightMode"; const char kGetTrebleMethod[] = "GetTreble"; const char kGetBassMethod[] = "GetBass"; const char kGetCapabilitiesOEMMethod[] = "GetCapabilitiesOEM"; const char kSetCapabilitiesOEMMethod[] = "SetCapabilitiesOEM"; const char kGetFilterConfigOEMMethod[] = "GetFilterConfigOEM"; const char kSetFilterConfigOEMMethod[] = "SetFilterConfigOEM"; const char kSetSourceTypeMethod[] = "SetSourceType"; const char kAmplifierVolumeChangedMethod[] = "AmplifierVolumeChanged"; const char kErrorSignal[] = "Error"; } // namespace audio_dsp void OnVoidDBusMethod(const VoidDBusMethodCallback& callback, dbus::Response* response) { callback.Run(response ? DBUS_METHOD_CALL_SUCCESS : DBUS_METHOD_CALL_FAILURE); } void OnBoolDBusMethod(const BoolDBusMethodCallback& callback, dbus::Response* response) { if (!response) { callback.Run(DBUS_METHOD_CALL_FAILURE, false); return; } dbus::MessageReader reader(response); bool result; if (!reader.PopBool(&result)) { callback.Run(DBUS_METHOD_CALL_FAILURE, false); return; } callback.Run(DBUS_METHOD_CALL_SUCCESS, result); } void OnDoubleDBusMethod( const AudioDspClient::DoubleDBusMethodCallback& callback, dbus::Response* response) { bool ok = false; double result = 0.0; if (response) { dbus::MessageReader reader(response); ok = reader.PopDouble(&result); } callback.Run(ok ? DBUS_METHOD_CALL_SUCCESS : DBUS_METHOD_CALL_FAILURE, result); } void OnTwoStringDBusMethod( const AudioDspClient::TwoStringDBusMethodCallback& callback, dbus::Response* response) { std::string result1; std::string result2; bool ok = false; if (response) { dbus::MessageReader reader(response); ok = reader.PopString(&result1) && reader.PopString(&result2); } callback.Run(ok ? DBUS_METHOD_CALL_SUCCESS : DBUS_METHOD_CALL_FAILURE, result1, result2); } void OnThreeStringDBusMethod( const AudioDspClient::ThreeStringDBusMethodCallback& callback, dbus::Response* response) { std::string result1; std::string result2; std::string result3; bool ok = false; if (response) { dbus::MessageReader reader(response); ok = reader.PopString(&result1) && reader.PopString(&result2) && reader.PopString(&result3); } callback.Run(ok ? DBUS_METHOD_CALL_SUCCESS : DBUS_METHOD_CALL_FAILURE, result1, result2, result3); } // The AudioDspClient implementation. class AudioDspClientImpl : public AudioDspClient { public: AudioDspClientImpl() : proxy_(nullptr), signal_connected_(false), weak_ptr_factory_(this) {} ~AudioDspClientImpl() override {} // DBusClient overrides: void Init(dbus::Bus* bus) override; // AudioDspClient overrides: void AddObserver(Observer* observer) override; void RemoveObserver(Observer* observer) override; void Initialize(const BoolDBusMethodCallback& callback) override; void SetStandbyMode(bool standby, const VoidDBusMethodCallback& callback) override; void SetNightMode(bool standby, const VoidDBusMethodCallback& callback) override; void GetNightMode(const BoolDBusMethodCallback& callback) override; void SetTreble(double db_fs, const VoidDBusMethodCallback& callback) override; void GetTreble(const DoubleDBusMethodCallback& callback) override; void SetBass(double db_fs, const VoidDBusMethodCallback& callback) override; void GetBass(const DoubleDBusMethodCallback& callback) override; void GetCapabilitiesOEM( const ThreeStringDBusMethodCallback& callback) override; void SetCapabilitiesOEM(uint32 speaker_id, const std::string& speaker_capabilities, const std::string& driver_capabilities, const VoidDBusMethodCallback& callback) override; void GetFilterConfigOEM(uint32 speaker_id, const TwoStringDBusMethodCallback& callback) override; void SetFilterConfigOEM(const std::string& speaker_config, const std::string& driver_config, const VoidDBusMethodCallback& callback) override; void SetSourceType(uint16 source_type, const VoidDBusMethodCallback& callback) override; void AmplifierVolumeChanged(double db_spl, const VoidDBusMethodCallback& callback) override; private: // Handles Error signal and notifies |observers_|. void OnError(dbus::Signal* signal); // Handles the result of signal connection setup. void OnSignalConnected(const std::string& interface, const std::string& signal, bool succeeded); dbus::ObjectProxy* proxy_; // True when |proxy_| has been connected to the Error signal. bool signal_connected_; // List of observers interested in event notifications from us. base::ObserverList 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 weak_ptr_factory_; DISALLOW_COPY_AND_ASSIGN(AudioDspClientImpl); }; void AudioDspClientImpl::Init(dbus::Bus* bus) { proxy_ = bus->GetObjectProxy(audio_dsp::kAudioDspServiceName, dbus::ObjectPath(audio_dsp::kAudioDspServicePath)); DCHECK(proxy_); } void AudioDspClientImpl::AddObserver(Observer* observer) { DCHECK(observer); if (!signal_connected_) { signal_connected_ = true; DCHECK(proxy_); proxy_->ConnectToSignal(audio_dsp::kAudioDspInterface, audio_dsp::kErrorSignal, base::Bind(&AudioDspClientImpl::OnError, weak_ptr_factory_.GetWeakPtr()), base::Bind(&AudioDspClientImpl::OnSignalConnected, weak_ptr_factory_.GetWeakPtr())); } observers_.AddObserver(observer); } void AudioDspClientImpl::RemoveObserver(Observer* observer) { DCHECK(observer); observers_.RemoveObserver(observer); } void AudioDspClientImpl::Initialize(const BoolDBusMethodCallback& callback) { dbus::MethodCall method_call(audio_dsp::kAudioDspInterface, audio_dsp::kInitializeMethod); DCHECK(proxy_); proxy_->CallMethod(&method_call, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT, base::Bind(&OnBoolDBusMethod, callback)); } void AudioDspClientImpl::SetStandbyMode( bool standby, const VoidDBusMethodCallback& callback) { dbus::MethodCall method_call(audio_dsp::kAudioDspInterface, audio_dsp::kSetStandbyModeMethod); dbus::MessageWriter writer(&method_call); writer.AppendBool(standby); DCHECK(proxy_); proxy_->CallMethod(&method_call, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT, base::Bind(&OnVoidDBusMethod, callback)); } void AudioDspClientImpl::SetNightMode(bool night_mode, const VoidDBusMethodCallback& callback) { dbus::MethodCall method_call(audio_dsp::kAudioDspInterface, audio_dsp::kSetNightModeMethod); dbus::MessageWriter writer(&method_call); writer.AppendBool(night_mode); DCHECK(proxy_); proxy_->CallMethod(&method_call, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT, base::Bind(&OnVoidDBusMethod, callback)); } void AudioDspClientImpl::GetNightMode(const BoolDBusMethodCallback& callback) { dbus::MethodCall method_call(audio_dsp::kAudioDspInterface, audio_dsp::kGetNightModeMethod); dbus::MessageWriter writer(&method_call); DCHECK(proxy_); proxy_->CallMethod(&method_call, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT, base::Bind(&OnBoolDBusMethod, callback)); } void AudioDspClientImpl::SetTreble(double db_fs, const VoidDBusMethodCallback& callback) { dbus::MethodCall method_call(audio_dsp::kAudioDspInterface, audio_dsp::kSetTrebleMethod); dbus::MessageWriter writer(&method_call); writer.AppendDouble(db_fs); DCHECK(proxy_); proxy_->CallMethod(&method_call, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT, base::Bind(&OnVoidDBusMethod, callback)); } void AudioDspClientImpl::GetTreble(const DoubleDBusMethodCallback& callback) { dbus::MethodCall method_call(audio_dsp::kAudioDspInterface, audio_dsp::kGetTrebleMethod); dbus::MessageWriter writer(&method_call); DCHECK(proxy_); proxy_->CallMethod(&method_call, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT, base::Bind(&OnDoubleDBusMethod, callback)); } void AudioDspClientImpl::SetBass(double db_fs, const VoidDBusMethodCallback& callback) { dbus::MethodCall method_call(audio_dsp::kAudioDspInterface, audio_dsp::kSetBassMethod); dbus::MessageWriter writer(&method_call); writer.AppendDouble(db_fs); DCHECK(proxy_); proxy_->CallMethod(&method_call, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT, base::Bind(&OnVoidDBusMethod, callback)); } void AudioDspClientImpl::GetBass(const DoubleDBusMethodCallback& callback) { dbus::MethodCall method_call(audio_dsp::kAudioDspInterface, audio_dsp::kGetBassMethod); dbus::MessageWriter writer(&method_call); DCHECK(proxy_); proxy_->CallMethod(&method_call, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT, base::Bind(&OnDoubleDBusMethod, callback)); } void AudioDspClientImpl::GetCapabilitiesOEM( const ThreeStringDBusMethodCallback& callback) { dbus::MethodCall method_call(audio_dsp::kAudioDspInterface, audio_dsp::kGetCapabilitiesOEMMethod); dbus::MessageWriter writer(&method_call); DCHECK(proxy_); proxy_->CallMethod(&method_call, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT, base::Bind(&OnThreeStringDBusMethod, callback)); } void AudioDspClientImpl::SetCapabilitiesOEM( uint32 speaker_id, const std::string& speaker_capabilities, const std::string& driver_capabilities, const VoidDBusMethodCallback& callback) { dbus::MethodCall method_call(audio_dsp::kAudioDspInterface, audio_dsp::kSetCapabilitiesOEMMethod); dbus::MessageWriter writer(&method_call); writer.AppendInt32(speaker_id); writer.AppendString(speaker_capabilities); writer.AppendString(driver_capabilities); DCHECK(proxy_); proxy_->CallMethod(&method_call, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT, base::Bind(&OnVoidDBusMethod, callback)); } void AudioDspClientImpl::GetFilterConfigOEM( uint32 speaker_id, const TwoStringDBusMethodCallback& callback) { dbus::MethodCall method_call(audio_dsp::kAudioDspInterface, audio_dsp::kGetFilterConfigOEMMethod); dbus::MessageWriter writer(&method_call); writer.AppendInt32(speaker_id); DCHECK(proxy_); proxy_->CallMethod(&method_call, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT, base::Bind(&OnTwoStringDBusMethod, callback)); } void AudioDspClientImpl::SetFilterConfigOEM( const std::string& speaker_config, const std::string& driver_config, const VoidDBusMethodCallback& callback) { dbus::MethodCall method_call(audio_dsp::kAudioDspInterface, audio_dsp::kSetFilterConfigOEMMethod); dbus::MessageWriter writer(&method_call); writer.AppendString(speaker_config); writer.AppendString(driver_config); DCHECK(proxy_); proxy_->CallMethod(&method_call, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT, base::Bind(&OnVoidDBusMethod, callback)); } void AudioDspClientImpl::SetSourceType(uint16 source_type, const VoidDBusMethodCallback& callback) { dbus::MethodCall method_call(audio_dsp::kAudioDspInterface, audio_dsp::kSetSourceTypeMethod); dbus::MessageWriter writer(&method_call); writer.AppendUint16(source_type); DCHECK(proxy_); proxy_->CallMethod(&method_call, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT, base::Bind(&OnVoidDBusMethod, callback)); } void AudioDspClientImpl::AmplifierVolumeChanged( double db_spl, const VoidDBusMethodCallback& callback) { dbus::MethodCall method_call(audio_dsp::kAudioDspInterface, audio_dsp::kAmplifierVolumeChangedMethod); dbus::MessageWriter writer(&method_call); writer.AppendDouble(db_spl); DCHECK(proxy_); proxy_->CallMethod(&method_call, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT, base::Bind(&OnVoidDBusMethod, callback)); } void AudioDspClientImpl::OnError(dbus::Signal* signal) { dbus::MessageReader reader(signal); int32 error_code = 0; if (!reader.PopInt32(&error_code)) { LOG(ERROR) << "Invalid signal: " << signal->ToString(); return; } FOR_EACH_OBSERVER(Observer, observers_, OnError(error_code)); } void AudioDspClientImpl::OnSignalConnected(const std::string& interface, const std::string& signal, bool succeeded) { LOG_IF(ERROR, !succeeded) << "Connect to " << interface << " " << signal << " failed."; } } // anonymous namespace AudioDspClient::AudioDspClient() { } AudioDspClient::~AudioDspClient() { } // static AudioDspClient* AudioDspClient::Create() { return new AudioDspClientImpl(); } } // namespace chromeos