Home | History | Annotate | Download | only in dbus
      1 // Copyright (c) 2013 The Chromium Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 #include "chromeos/dbus/cras_audio_client.h"
      6 
      7 #include "base/bind.h"
      8 #include "base/format_macros.h"
      9 #include "base/strings/stringprintf.h"
     10 #include "chromeos/dbus/cras_audio_client_stub_impl.h"
     11 #include "dbus/bus.h"
     12 #include "dbus/message.h"
     13 #include "dbus/object_path.h"
     14 #include "dbus/object_proxy.h"
     15 #include "third_party/cros_system_api/dbus/service_constants.h"
     16 
     17 namespace chromeos {
     18 
     19 // Error name if cras dbus call fails with empty ErrorResponse.
     20 const char kNoResponseError[] =
     21     "org.chromium.cras.Error.NoResponse";
     22 
     23 // The CrasAudioClient implementation used in production.
     24 class CrasAudioClientImpl : public CrasAudioClient {
     25  public:
     26   CrasAudioClientImpl() : cras_proxy_(NULL), weak_ptr_factory_(this) {}
     27 
     28   virtual ~CrasAudioClientImpl() {
     29   }
     30 
     31   // CrasAudioClient overrides:
     32   virtual void AddObserver(Observer* observer) OVERRIDE {
     33     observers_.AddObserver(observer);
     34   }
     35 
     36   virtual void RemoveObserver(Observer* observer) OVERRIDE {
     37     observers_.RemoveObserver(observer);
     38   }
     39 
     40   virtual bool HasObserver(Observer* observer) OVERRIDE {
     41     return observers_.HasObserver(observer);
     42   }
     43 
     44   virtual void GetVolumeState(const GetVolumeStateCallback& callback) OVERRIDE {
     45     dbus::MethodCall method_call(cras::kCrasControlInterface,
     46                                  cras::kGetVolumeState);
     47     cras_proxy_->CallMethod(
     48         &method_call,
     49         dbus::ObjectProxy::TIMEOUT_USE_DEFAULT,
     50         base::Bind(&CrasAudioClientImpl::OnGetVolumeState,
     51                    weak_ptr_factory_.GetWeakPtr(), callback));
     52   }
     53 
     54   virtual void GetNodes(const GetNodesCallback& callback,
     55                         const ErrorCallback& error_callback) OVERRIDE {
     56     dbus::MethodCall method_call(cras::kCrasControlInterface,
     57                                  cras::kGetNodes);
     58     cras_proxy_->CallMethodWithErrorCallback(
     59         &method_call,
     60         dbus::ObjectProxy::TIMEOUT_USE_DEFAULT,
     61         base::Bind(&CrasAudioClientImpl::OnGetNodes,
     62                    weak_ptr_factory_.GetWeakPtr(), callback),
     63         base::Bind(&CrasAudioClientImpl::OnError,
     64                    weak_ptr_factory_.GetWeakPtr(), error_callback));
     65   }
     66 
     67   virtual void SetOutputNodeVolume(uint64 node_id, int32 volume) OVERRIDE {
     68     dbus::MethodCall method_call(cras::kCrasControlInterface,
     69                                  cras::kSetOutputNodeVolume);
     70     dbus::MessageWriter writer(&method_call);
     71     writer.AppendUint64(node_id);
     72     writer.AppendInt32(volume);
     73     cras_proxy_->CallMethod(
     74         &method_call,
     75         dbus::ObjectProxy::TIMEOUT_USE_DEFAULT,
     76         dbus::ObjectProxy::EmptyResponseCallback());
     77   }
     78 
     79   virtual void SetOutputUserMute(bool mute_on) OVERRIDE {
     80     dbus::MethodCall method_call(cras::kCrasControlInterface,
     81                                  cras::kSetOutputUserMute);
     82     dbus::MessageWriter writer(&method_call);
     83     writer.AppendBool(mute_on);
     84     cras_proxy_->CallMethod(
     85         &method_call,
     86         dbus::ObjectProxy::TIMEOUT_USE_DEFAULT,
     87         dbus::ObjectProxy::EmptyResponseCallback());
     88   }
     89 
     90   virtual void SetInputNodeGain(uint64 node_id, int32 input_gain) OVERRIDE {
     91     dbus::MethodCall method_call(cras::kCrasControlInterface,
     92                                  cras::kSetInputNodeGain);
     93     dbus::MessageWriter writer(&method_call);
     94     writer.AppendUint64(node_id);
     95     writer.AppendInt32(input_gain);
     96     cras_proxy_->CallMethod(
     97         &method_call,
     98         dbus::ObjectProxy::TIMEOUT_USE_DEFAULT,
     99         dbus::ObjectProxy::EmptyResponseCallback());
    100   }
    101 
    102   virtual void SetInputMute(bool mute_on) OVERRIDE {
    103     dbus::MethodCall method_call(cras::kCrasControlInterface,
    104                                  cras::kSetInputMute);
    105     dbus::MessageWriter writer(&method_call);
    106     writer.AppendBool(mute_on);
    107     cras_proxy_->CallMethod(
    108         &method_call,
    109         dbus::ObjectProxy::TIMEOUT_USE_DEFAULT,
    110         dbus::ObjectProxy::EmptyResponseCallback());
    111   }
    112 
    113   virtual void SetActiveOutputNode(uint64 node_id) OVERRIDE {
    114     dbus::MethodCall method_call(cras::kCrasControlInterface,
    115                                  cras::kSetActiveOutputNode);
    116     dbus::MessageWriter writer(&method_call);
    117     writer.AppendUint64(node_id);
    118     cras_proxy_->CallMethod(
    119         &method_call,
    120         dbus::ObjectProxy::TIMEOUT_USE_DEFAULT,
    121         dbus::ObjectProxy::EmptyResponseCallback());
    122   }
    123 
    124   virtual void SetActiveInputNode(uint64 node_id) OVERRIDE {
    125     dbus::MethodCall method_call(cras::kCrasControlInterface,
    126                                  cras::kSetActiveInputNode);
    127     dbus::MessageWriter writer(&method_call);
    128     writer.AppendUint64(node_id);
    129     cras_proxy_->CallMethod(
    130         &method_call,
    131         dbus::ObjectProxy::TIMEOUT_USE_DEFAULT,
    132         dbus::ObjectProxy::EmptyResponseCallback());
    133   }
    134 
    135  protected:
    136   virtual void Init(dbus::Bus* bus) OVERRIDE {
    137     cras_proxy_ = bus->GetObjectProxy(cras::kCrasServiceName,
    138                                       dbus::ObjectPath(cras::kCrasServicePath));
    139 
    140     // Monitor NameOwnerChanged signal.
    141     cras_proxy_->SetNameOwnerChangedCallback(
    142         base::Bind(&CrasAudioClientImpl::NameOwnerChangedReceived,
    143                    weak_ptr_factory_.GetWeakPtr()));
    144 
    145     // Monitor the D-Bus signal for output mute change.
    146     cras_proxy_->ConnectToSignal(
    147         cras::kCrasControlInterface,
    148         cras::kOutputMuteChanged,
    149         base::Bind(&CrasAudioClientImpl::OutputMuteChangedReceived,
    150                    weak_ptr_factory_.GetWeakPtr()),
    151         base::Bind(&CrasAudioClientImpl::SignalConnected,
    152                    weak_ptr_factory_.GetWeakPtr()));
    153 
    154     // Monitor the D-Bus signal for input mute change.
    155     cras_proxy_->ConnectToSignal(
    156         cras::kCrasControlInterface,
    157         cras::kInputMuteChanged,
    158         base::Bind(&CrasAudioClientImpl::InputMuteChangedReceived,
    159                    weak_ptr_factory_.GetWeakPtr()),
    160         base::Bind(&CrasAudioClientImpl::SignalConnected,
    161                    weak_ptr_factory_.GetWeakPtr()));
    162 
    163     // Monitor the D-Bus signal for nodes change.
    164     cras_proxy_->ConnectToSignal(
    165         cras::kCrasControlInterface,
    166         cras::kNodesChanged,
    167         base::Bind(&CrasAudioClientImpl::NodesChangedReceived,
    168                    weak_ptr_factory_.GetWeakPtr()),
    169         base::Bind(&CrasAudioClientImpl::SignalConnected,
    170                    weak_ptr_factory_.GetWeakPtr()));
    171 
    172     // Monitor the D-Bus signal for active output node change.
    173     cras_proxy_->ConnectToSignal(
    174         cras::kCrasControlInterface,
    175         cras::kActiveOutputNodeChanged,
    176         base::Bind(&CrasAudioClientImpl::ActiveOutputNodeChangedReceived,
    177                    weak_ptr_factory_.GetWeakPtr()),
    178         base::Bind(&CrasAudioClientImpl::SignalConnected,
    179                    weak_ptr_factory_.GetWeakPtr()));
    180 
    181     // Monitor the D-Bus signal for active input node change.
    182     cras_proxy_->ConnectToSignal(
    183         cras::kCrasControlInterface,
    184         cras::kActiveInputNodeChanged,
    185         base::Bind(&CrasAudioClientImpl::ActiveInputNodeChangedReceived,
    186                    weak_ptr_factory_.GetWeakPtr()),
    187         base::Bind(&CrasAudioClientImpl::SignalConnected,
    188                    weak_ptr_factory_.GetWeakPtr()));
    189   }
    190 
    191  private:
    192   // Called when the cras signal is initially connected.
    193   void SignalConnected(const std::string& interface_name,
    194                        const std::string& signal_name,
    195                        bool success) {
    196     LOG_IF(ERROR, !success)
    197         << "Failed to connect to cras signal:" << signal_name;
    198   }
    199 
    200   void NameOwnerChangedReceived(const std::string& old_owner,
    201                                 const std::string& new_owner) {
    202     FOR_EACH_OBSERVER(Observer, observers_, AudioClientRestarted());
    203   }
    204 
    205   // Called when a OutputMuteChanged signal is received.
    206   void OutputMuteChangedReceived(dbus::Signal* signal) {
    207     // Chrome should always call SetOutputUserMute api to set the output
    208     // mute state and monitor user_mute state from OutputMuteChanged signal.
    209     dbus::MessageReader reader(signal);
    210     bool system_mute, user_mute;
    211     if (!reader.PopBool(&system_mute) || !reader.PopBool(&user_mute)) {
    212       LOG(ERROR) << "Error reading signal from cras:"
    213                  << signal->ToString();
    214     }
    215     FOR_EACH_OBSERVER(Observer, observers_, OutputMuteChanged(user_mute));
    216   }
    217 
    218   // Called when a InputMuteChanged signal is received.
    219   void InputMuteChangedReceived(dbus::Signal* signal) {
    220     dbus::MessageReader reader(signal);
    221     bool mute;
    222     if (!reader.PopBool(&mute)) {
    223       LOG(ERROR) << "Error reading signal from cras:"
    224                  << signal->ToString();
    225     }
    226     FOR_EACH_OBSERVER(Observer, observers_, InputMuteChanged(mute));
    227   }
    228 
    229   void NodesChangedReceived(dbus::Signal* signal) {
    230     FOR_EACH_OBSERVER(Observer, observers_, NodesChanged());
    231   }
    232 
    233   void ActiveOutputNodeChangedReceived(dbus::Signal* signal) {
    234     dbus::MessageReader reader(signal);
    235     uint64 node_id;
    236     if (!reader.PopUint64(&node_id)) {
    237       LOG(ERROR) << "Error reading signal from cras:"
    238                  << signal->ToString();
    239     }
    240     FOR_EACH_OBSERVER(Observer, observers_, ActiveOutputNodeChanged(node_id));
    241   }
    242 
    243   void ActiveInputNodeChangedReceived(dbus::Signal* signal) {
    244     dbus::MessageReader reader(signal);
    245     uint64 node_id;
    246     if (!reader.PopUint64(&node_id)) {
    247       LOG(ERROR) << "Error reading signal from cras:"
    248                  << signal->ToString();
    249     }
    250     FOR_EACH_OBSERVER(Observer, observers_, ActiveInputNodeChanged(node_id));
    251   }
    252 
    253   void OnGetVolumeState(const GetVolumeStateCallback& callback,
    254                         dbus::Response* response) {
    255     bool success = true;
    256     VolumeState volume_state;
    257     if (response) {
    258       dbus::MessageReader reader(response);
    259       if (!reader.PopInt32(&volume_state.output_volume) ||
    260           !reader.PopBool(&volume_state.output_system_mute) ||
    261           !reader.PopInt32(&volume_state.input_gain) ||
    262           !reader.PopBool(&volume_state.input_mute) ||
    263           !reader.PopBool(&volume_state.output_user_mute)) {
    264         success = false;
    265         LOG(ERROR) << "Error reading response from cras: "
    266                    << response->ToString();
    267       }
    268     } else {
    269       success = false;
    270       LOG(ERROR) << "Error calling " << cras::kGetVolumeState;
    271     }
    272 
    273     callback.Run(volume_state, success);
    274   }
    275 
    276   void OnGetNodes(const GetNodesCallback& callback,
    277                   dbus::Response* response) {
    278     bool success = true;
    279     AudioNodeList node_list;
    280     if (response) {
    281       dbus::MessageReader response_reader(response);
    282       dbus::MessageReader array_reader(response);
    283       while (response_reader.HasMoreData()) {
    284         if (!response_reader.PopArray(&array_reader)) {
    285           success = false;
    286           LOG(ERROR) << "Error reading response from cras: "
    287                      << response->ToString();
    288           break;
    289         }
    290 
    291         AudioNode node;
    292         if (!GetAudioNode(response, &array_reader, &node)) {
    293           success = false;
    294           LOG(WARNING) << "Error reading audio node data from cras: "
    295                        << response->ToString();
    296           break;
    297         }
    298         // Filter out the "UNKNOWN" type of audio devices.
    299         if (node.type != "UNKNOWN")
    300           node_list.push_back(node);
    301       }
    302     }
    303 
    304     if (node_list.empty())
    305       return;
    306 
    307     callback.Run(node_list, success);
    308   }
    309 
    310   void OnError(const ErrorCallback& error_callback,
    311                dbus::ErrorResponse* response) {
    312     // Error response has optional error message argument.
    313     std::string error_name;
    314     std::string error_message;
    315     if (response) {
    316       dbus::MessageReader reader(response);
    317       error_name = response->GetErrorName();
    318       reader.PopString(&error_message);
    319     } else {
    320       error_name = kNoResponseError;
    321       error_message = "";
    322     }
    323     error_callback.Run(error_name, error_message);
    324   }
    325 
    326   bool GetAudioNode(dbus::Response* response,
    327                     dbus::MessageReader* array_reader,
    328                     AudioNode *node) {
    329     while (array_reader->HasMoreData()) {
    330       dbus::MessageReader dict_entry_reader(response);
    331       dbus::MessageReader value_reader(response);
    332       std::string key;
    333       if (!array_reader->PopDictEntry(&dict_entry_reader) ||
    334           !dict_entry_reader.PopString(&key) ||
    335           !dict_entry_reader.PopVariant(&value_reader)) {
    336          return false;
    337       }
    338 
    339       if (key == cras::kIsInputProperty) {
    340         if (!value_reader.PopBool(&node->is_input))
    341           return false;
    342       } else if (key == cras::kIdProperty) {
    343         if (!value_reader.PopUint64(&node->id))
    344           return false;
    345       } else if (key == cras::kDeviceNameProperty) {
    346         if (!value_reader.PopString(&node->device_name))
    347           return false;
    348       } else if (key == cras::kTypeProperty) {
    349         if (!value_reader.PopString(&node->type))
    350           return false;
    351       } else if (key == cras::kNameProperty) {
    352         if (!value_reader.PopString(&node->name))
    353           return false;
    354       } else if (key == cras::kActiveProperty) {
    355         if (!value_reader.PopBool(&node->active))
    356           return false;
    357       } else if (key == cras::kPluggedTimeProperty) {
    358         if (!value_reader.PopUint64(&node->plugged_time))
    359           return false;
    360       }
    361     }
    362 
    363     return true;
    364   }
    365 
    366   dbus::ObjectProxy* cras_proxy_;
    367   ObserverList<Observer> observers_;
    368 
    369   // Note: This should remain the last member so it'll be destroyed and
    370   // invalidate its weak pointers before any other members are destroyed.
    371   base::WeakPtrFactory<CrasAudioClientImpl> weak_ptr_factory_;
    372 
    373   DISALLOW_COPY_AND_ASSIGN(CrasAudioClientImpl);
    374 };
    375 
    376 CrasAudioClient::Observer::~Observer() {
    377 }
    378 
    379 void CrasAudioClient::Observer::AudioClientRestarted() {
    380 }
    381 
    382 void CrasAudioClient::Observer::OutputMuteChanged(bool mute_on) {
    383 }
    384 
    385 void CrasAudioClient::Observer::InputMuteChanged(bool mute_on) {
    386 }
    387 
    388 void CrasAudioClient::Observer::NodesChanged() {
    389 }
    390 
    391 void CrasAudioClient::Observer::ActiveOutputNodeChanged(uint64 node_id){
    392 }
    393 
    394 void CrasAudioClient::Observer::ActiveInputNodeChanged(uint64 node_id) {
    395 }
    396 
    397 CrasAudioClient::CrasAudioClient() {
    398 }
    399 
    400 CrasAudioClient::~CrasAudioClient() {
    401 }
    402 
    403 // static
    404 CrasAudioClient* CrasAudioClient::Create() {
    405   return new CrasAudioClientImpl();
    406 }
    407 
    408 }  // namespace chromeos
    409