Merge from Chromium at DEPS revision r198571
This commit was generated by merge_to_master.py.
Change-Id: I951118a03836157090561764dd2627f0add8118f
diff --git a/chromeos/dbus/cras_audio_client.cc b/chromeos/dbus/cras_audio_client.cc
new file mode 100644
index 0000000..ec20ea7
--- /dev/null
+++ b/chromeos/dbus/cras_audio_client.cc
@@ -0,0 +1,579 @@
+// Copyright (c) 2013 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/cras_audio_client.h"
+
+#include "base/bind.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 chromeos {
+
+// The CrasAudioClient implementation used in production.
+class CrasAudioClientImpl : public CrasAudioClient {
+ public:
+ explicit CrasAudioClientImpl(dbus::Bus* bus)
+ : cras_proxy_(NULL),
+ weak_ptr_factory_(this) {
+ cras_proxy_ = bus->GetObjectProxy(
+ cras::kCrasServiceName,
+ dbus::ObjectPath(cras::kCrasServicePath));
+
+ // Monitor NameOwnerChanged signal.
+ cras_proxy_->SetNameOwnerChangedCallback(
+ base::Bind(&CrasAudioClientImpl::NameOwnerChangedReceived,
+ weak_ptr_factory_.GetWeakPtr()));
+
+ // Monitor the D-Bus signal for output volume change.
+ cras_proxy_->ConnectToSignal(
+ cras::kCrasControlInterface,
+ cras::kOutputVolumeChanged,
+ base::Bind(&CrasAudioClientImpl::OutputVolumeChangedReceived,
+ weak_ptr_factory_.GetWeakPtr()),
+ base::Bind(&CrasAudioClientImpl::SignalConnected,
+ weak_ptr_factory_.GetWeakPtr()));
+
+ // Monitor the D-Bus signal for output mute change.
+ cras_proxy_->ConnectToSignal(
+ cras::kCrasControlInterface,
+ cras::kOutputMuteChanged,
+ base::Bind(&CrasAudioClientImpl::OutputMuteChangedReceived,
+ weak_ptr_factory_.GetWeakPtr()),
+ base::Bind(&CrasAudioClientImpl::SignalConnected,
+ weak_ptr_factory_.GetWeakPtr()));
+
+ // Monitor the D-Bus signal for input gain change.
+ cras_proxy_->ConnectToSignal(
+ cras::kCrasControlInterface,
+ cras::kInputGainChanged,
+ base::Bind(&CrasAudioClientImpl::InputGainChangedReceived,
+ weak_ptr_factory_.GetWeakPtr()),
+ base::Bind(&CrasAudioClientImpl::SignalConnected,
+ weak_ptr_factory_.GetWeakPtr()));
+
+ // Monitor the D-Bus signal for input mute change.
+ cras_proxy_->ConnectToSignal(
+ cras::kCrasControlInterface,
+ cras::kInputMuteChanged,
+ base::Bind(&CrasAudioClientImpl::InputMuteChangedReceived,
+ weak_ptr_factory_.GetWeakPtr()),
+ base::Bind(&CrasAudioClientImpl::SignalConnected,
+ weak_ptr_factory_.GetWeakPtr()));
+
+ // Monitor the D-Bus signal for nodes change.
+ cras_proxy_->ConnectToSignal(
+ cras::kCrasControlInterface,
+ cras::kNodesChanged,
+ base::Bind(&CrasAudioClientImpl::NodesChangedReceived,
+ weak_ptr_factory_.GetWeakPtr()),
+ base::Bind(&CrasAudioClientImpl::SignalConnected,
+ weak_ptr_factory_.GetWeakPtr()));
+
+ // Monitor the D-Bus signal for active output node change.
+ cras_proxy_->ConnectToSignal(
+ cras::kCrasControlInterface,
+ cras::kActiveOutputNodeChanged,
+ base::Bind(&CrasAudioClientImpl::ActiveOutputNodeChangedReceived,
+ weak_ptr_factory_.GetWeakPtr()),
+ base::Bind(&CrasAudioClientImpl::SignalConnected,
+ weak_ptr_factory_.GetWeakPtr()));
+
+ // Monitor the D-Bus signal for active input node change.
+ cras_proxy_->ConnectToSignal(
+ cras::kCrasControlInterface,
+ cras::kActiveInputNodeChanged,
+ base::Bind(&CrasAudioClientImpl::ActiveInputNodeChangedReceived,
+ weak_ptr_factory_.GetWeakPtr()),
+ base::Bind(&CrasAudioClientImpl::SignalConnected,
+ weak_ptr_factory_.GetWeakPtr()));
+ }
+
+ virtual ~CrasAudioClientImpl() {
+ }
+
+ // CrasAudioClient overrides:
+ virtual void AddObserver(Observer* observer) OVERRIDE {
+ observers_.AddObserver(observer);
+ }
+
+ virtual void RemoveObserver(Observer* observer) OVERRIDE {
+ observers_.RemoveObserver(observer);
+ }
+
+ virtual bool HasObserver(Observer* observer) OVERRIDE {
+ return observers_.HasObserver(observer);
+ }
+
+ virtual void GetVolumeState(const GetVolumeStateCallback& callback) OVERRIDE {
+ dbus::MethodCall method_call(cras::kCrasControlInterface,
+ cras::kGetVolumeState);
+ cras_proxy_->CallMethod(
+ &method_call,
+ dbus::ObjectProxy::TIMEOUT_USE_DEFAULT,
+ base::Bind(&CrasAudioClientImpl::OnGetVolumeState,
+ weak_ptr_factory_.GetWeakPtr(), callback));
+ }
+
+ virtual void GetNodes(const GetNodesCallback& callback) OVERRIDE {
+ dbus::MethodCall method_call(cras::kCrasControlInterface,
+ cras::kGetNodes);
+ cras_proxy_->CallMethod(
+ &method_call,
+ dbus::ObjectProxy::TIMEOUT_USE_DEFAULT,
+ base::Bind(&CrasAudioClientImpl::OnGetNodes,
+ weak_ptr_factory_.GetWeakPtr(), callback));
+ }
+
+ virtual void SetOutputVolume(int32 volume) OVERRIDE {
+ dbus::MethodCall method_call(cras::kCrasControlInterface,
+ cras::kSetOutputVolume);
+ dbus::MessageWriter writer(&method_call);
+ writer.AppendInt32(volume);
+ cras_proxy_->CallMethod(
+ &method_call,
+ dbus::ObjectProxy::TIMEOUT_USE_DEFAULT,
+ dbus::ObjectProxy::EmptyResponseCallback());
+ }
+
+ virtual void SetOutputMute(bool mute_on) OVERRIDE {
+ dbus::MethodCall method_call(cras::kCrasControlInterface,
+ cras::kSetOutputMute);
+ dbus::MessageWriter writer(&method_call);
+ writer.AppendBool(mute_on);
+ cras_proxy_->CallMethod(
+ &method_call,
+ dbus::ObjectProxy::TIMEOUT_USE_DEFAULT,
+ dbus::ObjectProxy::EmptyResponseCallback());
+ }
+
+ virtual void SetInputGain(int32 input_gain) OVERRIDE {
+ dbus::MethodCall method_call(cras::kCrasControlInterface,
+ cras::kSetInputGain);
+ dbus::MessageWriter writer(&method_call);
+ writer.AppendInt32(input_gain);
+ cras_proxy_->CallMethod(
+ &method_call,
+ dbus::ObjectProxy::TIMEOUT_USE_DEFAULT,
+ dbus::ObjectProxy::EmptyResponseCallback());
+ }
+
+ virtual 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,
+ dbus::ObjectProxy::EmptyResponseCallback());
+ }
+
+ virtual void SetActiveOutputNode(uint64 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,
+ dbus::ObjectProxy::EmptyResponseCallback());
+ }
+
+ virtual void SetActiveInputNode(uint64 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,
+ dbus::ObjectProxy::EmptyResponseCallback());
+ }
+
+ 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(dbus::Signal* signal) {
+ FOR_EACH_OBSERVER(Observer, observers_, AudioClientRestarted());
+ }
+
+ // Called when a OutputVolumeChanged signal is received.
+ void OutputVolumeChangedReceived(dbus::Signal* signal) {
+ dbus::MessageReader reader(signal);
+ int32 volume;
+ if (!reader.PopInt32(&volume)) {
+ LOG(ERROR) << "Error reading signal from cras:"
+ << signal->ToString();
+ }
+ FOR_EACH_OBSERVER(Observer, observers_, OutputVolumeChanged(volume));
+ }
+
+ // Called when a OutputMuteChanged signal is received.
+ void OutputMuteChangedReceived(dbus::Signal* signal) {
+ dbus::MessageReader reader(signal);
+ bool mute;
+ if (!reader.PopBool(&mute)) {
+ LOG(ERROR) << "Error reading signal from cras:"
+ << signal->ToString();
+ }
+ FOR_EACH_OBSERVER(Observer, observers_, OutputMuteChanged(mute));
+ }
+
+ // Called when a InputGainChanged signal is received.
+ void InputGainChangedReceived(dbus::Signal* signal) {
+ dbus::MessageReader reader(signal);
+ int32 gain;
+ if (!reader.PopInt32(&gain)) {
+ LOG(ERROR) << "Error reading signal from cras:"
+ << signal->ToString();
+ }
+ FOR_EACH_OBSERVER(Observer, observers_, InputGainChanged(gain));
+ }
+
+ // 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_EACH_OBSERVER(Observer, observers_, InputMuteChanged(mute));
+ }
+
+ void NodesChangedReceived(dbus::Signal* signal) {
+ FOR_EACH_OBSERVER(Observer, observers_, NodesChanged());
+ }
+
+ void ActiveOutputNodeChangedReceived(dbus::Signal* signal) {
+ dbus::MessageReader reader(signal);
+ uint64 node_id;
+ if (!reader.PopUint64(&node_id)) {
+ LOG(ERROR) << "Error reading signal from cras:"
+ << signal->ToString();
+ }
+ FOR_EACH_OBSERVER(Observer, observers_, ActiveOutputNodeChanged(node_id));
+ }
+
+ void ActiveInputNodeChangedReceived(dbus::Signal* signal) {
+ dbus::MessageReader reader(signal);
+ uint64 node_id;
+ if (!reader.PopUint64(&node_id)) {
+ LOG(ERROR) << "Error reading signal from cras:"
+ << signal->ToString();
+ }
+ FOR_EACH_OBSERVER(Observer, observers_, ActiveInputNodeChanged(node_id));
+ }
+
+ void OnGetVolumeState(const GetVolumeStateCallback& callback,
+ dbus::Response* response) {
+ bool success = true;
+ VolumeState volume_state;
+ if (response) {
+ dbus::MessageReader reader(response);
+ if (!reader.PopInt32(&volume_state.output_volume) ||
+ !reader.PopBool(&volume_state.output_mute) ||
+ !reader.PopInt32(&volume_state.input_gain) ||
+ !reader.PopBool(&volume_state.input_mute)) {
+ success = false;
+ LOG(ERROR) << "Error reading response from cras: "
+ << response->ToString();
+ }
+ } else {
+ success = false;
+ LOG(ERROR) << "Error calling " << cras::kGetVolumeState;
+ }
+
+ callback.Run(volume_state, success);
+ }
+
+ void OnGetNodes(const GetNodesCallback& callback,
+ dbus::Response* response) {
+ bool success = true;
+ AudioNodeList node_list;
+ if (response) {
+ dbus::MessageReader response_reader(response);
+ dbus::MessageReader array_reader(response);
+ while (response_reader.HasMoreData()) {
+ if (!response_reader.PopArray(&array_reader)) {
+ success = false;
+ LOG(ERROR) << "Error reading response from cras: "
+ << response->ToString();
+ break;
+ }
+
+ AudioNode node;
+ if (!GetAudioNode(response, &array_reader, &node)) {
+ success = false;
+ LOG(WARNING) << "Error reading audio node data from cras: "
+ << response->ToString();
+ break;
+ }
+
+ node_list.push_back(node);
+ }
+ } else {
+ success = false;
+ LOG(ERROR) << "Error calling " << cras::kGetNodes;
+ }
+
+ callback.Run(node_list, success);
+ }
+
+ 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;
+ }
+ }
+
+ return true;
+ }
+
+ dbus::ObjectProxy* cras_proxy_;
+ ObserverList<Observer> 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_;
+
+ DISALLOW_COPY_AND_ASSIGN(CrasAudioClientImpl);
+};
+
+// The CrasAudioClient implementation used on Linux desktop,
+// which does nothing.
+class CrasAudioClientStubImpl : public CrasAudioClient {
+ public:
+ CrasAudioClientStubImpl() {
+ VLOG(1) << "CrasAudioClientStubImpl is created";
+
+ // Fake audio output nodes.
+ AudioNode node_1;
+ node_1.is_input = false;
+ node_1.id = 10001;
+ node_1.device_name = "Fake Speaker";
+ node_1.type = "INTERNAL_SPEAKER";
+ node_1.name = "Speaker";
+ node_1.active = false;
+ node_list_.push_back(node_1);
+
+ AudioNode node_2;
+ node_2.is_input = false;
+ node_2.id = 10002;
+ node_2.device_name = "Fake Headphone";
+ node_2.type = "HEADPHONE";
+ node_2.name = "Headphone";
+ node_2.active = true;
+ node_list_.push_back(node_2);
+ active_output_node_id_ = node_2.id;
+
+ AudioNode node_3;
+ node_3.is_input = false;
+ node_3.id = 10003;
+ node_3.device_name = "Fake Audio Output";
+ node_3.type = "BLUETOOTH";
+ node_3.name = "Bluetooth Headphone";
+ node_3.active = false;
+ node_list_.push_back(node_3);
+
+ // Fake audio input ndoes
+ AudioNode node_4;
+ node_4.is_input = true;
+ node_4.id = 10004;
+ node_4.device_name = "Fake Internal Mic";
+ node_4.type = "INTERNAL_MIC";
+ node_4.name = "Internal Mic";
+ node_4.active = false;
+ node_list_.push_back(node_4);
+
+ AudioNode node_5;
+ node_5.is_input = true;
+ node_5.id = 10005;
+ node_5.device_name = "Fake Internal Mic";
+ node_5.type = "USB";
+ node_5.name = "USB Mic";
+ node_5.active = true;
+ node_list_.push_back(node_5);
+ active_input_node_id_ = node_5.id;
+ }
+ virtual ~CrasAudioClientStubImpl() {
+ }
+
+ // CrasAudioClient overrides:
+ // TODO(jennyz): Implement the observers and callbacks in the stub for UI
+ // testing.
+ virtual void AddObserver(Observer* observer) OVERRIDE {
+ observers_.AddObserver(observer);
+ }
+
+ virtual void RemoveObserver(Observer* observer) OVERRIDE {
+ observers_.RemoveObserver(observer);
+ }
+
+ virtual bool HasObserver(Observer* observer) OVERRIDE {
+ return observers_.HasObserver(observer);
+ }
+
+ virtual void GetVolumeState(const GetVolumeStateCallback& callback) OVERRIDE {
+ callback.Run(volume_state_, true);
+ }
+
+ virtual void GetNodes(const GetNodesCallback& callback)OVERRIDE {
+ callback.Run(node_list_, true);
+ }
+
+ virtual void SetOutputVolume(int32 volume) OVERRIDE {
+ volume_state_.output_volume = volume;
+ FOR_EACH_OBSERVER(Observer,
+ observers_,
+ OutputVolumeChanged(volume_state_.output_volume));
+ }
+
+ virtual void SetOutputMute(bool mute_on) OVERRIDE {
+ volume_state_.output_mute = mute_on;
+ FOR_EACH_OBSERVER(Observer,
+ observers_,
+ OutputMuteChanged(volume_state_.output_mute));
+ }
+
+ virtual void SetInputGain(int32 input_gain) OVERRIDE {
+ volume_state_.input_gain = input_gain;
+ FOR_EACH_OBSERVER(Observer,
+ observers_,
+ InputGainChanged(volume_state_.input_gain));
+ }
+
+ virtual void SetInputMute(bool mute_on) OVERRIDE {
+ volume_state_.input_mute = mute_on;
+ FOR_EACH_OBSERVER(Observer,
+ observers_,
+ InputMuteChanged(volume_state_.input_mute));
+ }
+
+ virtual void SetActiveOutputNode(uint64 node_id) OVERRIDE {
+ 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_EACH_OBSERVER(Observer,
+ observers_,
+ ActiveOutputNodeChanged(node_id));
+ }
+
+ virtual void SetActiveInputNode(uint64 node_id) OVERRIDE {
+ 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_EACH_OBSERVER(Observer,
+ observers_,
+ ActiveInputNodeChanged(node_id));
+ }
+
+ private:
+ VolumeState volume_state_;
+ AudioNodeList node_list_;
+ uint64 active_input_node_id_;
+ uint64 active_output_node_id_;
+ ObserverList<Observer> observers_;
+
+ DISALLOW_COPY_AND_ASSIGN(CrasAudioClientStubImpl);
+};
+
+CrasAudioClient::Observer::~Observer() {
+}
+
+void CrasAudioClient::Observer::AudioClientRestarted() {
+}
+
+void CrasAudioClient::Observer::OutputVolumeChanged(int32 volume) {
+}
+
+void CrasAudioClient::Observer::OutputMuteChanged(bool mute_on) {
+}
+
+void CrasAudioClient::Observer::InputGainChanged(int gain) {
+}
+
+void CrasAudioClient::Observer::InputMuteChanged(bool mute_on) {
+}
+
+void CrasAudioClient::Observer::NodesChanged() {
+}
+
+void CrasAudioClient::Observer::ActiveOutputNodeChanged(uint64 node_id){
+}
+
+void CrasAudioClient::Observer::ActiveInputNodeChanged(uint64 node_id) {
+}
+
+CrasAudioClient::CrasAudioClient() {
+}
+
+CrasAudioClient::~CrasAudioClient() {
+}
+
+// static
+CrasAudioClient* CrasAudioClient::Create(
+ DBusClientImplementationType type,
+ dbus::Bus* bus) {
+ if (type == REAL_DBUS_CLIENT_IMPLEMENTATION) {
+ return new CrasAudioClientImpl(bus);
+ }
+ DCHECK_EQ(STUB_DBUS_CLIENT_IMPLEMENTATION, type);
+ return new CrasAudioClientStubImpl();
+}
+
+} // namespace chromeos