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   virtual void AddActiveInputNode(uint64 node_id) OVERRIDE {
    136     dbus::MethodCall method_call(cras::kCrasControlInterface,
    137                                  cras::kAddActiveInputNode);
    138     dbus::MessageWriter writer(&method_call);
    139     writer.AppendUint64(node_id);
    140     cras_proxy_->CallMethod(
    141         &method_call,
    142         dbus::ObjectProxy::TIMEOUT_USE_DEFAULT,
    143         dbus::ObjectProxy::EmptyResponseCallback());
    144   }
    145 
    146   virtual void RemoveActiveInputNode(uint64 node_id) OVERRIDE {
    147     dbus::MethodCall method_call(cras::kCrasControlInterface,
    148                                  cras::kRemoveActiveInputNode);
    149     dbus::MessageWriter writer(&method_call);
    150     writer.AppendUint64(node_id);
    151     cras_proxy_->CallMethod(
    152         &method_call,
    153         dbus::ObjectProxy::TIMEOUT_USE_DEFAULT,
    154         dbus::ObjectProxy::EmptyResponseCallback());
    155   }
    156 
    157   virtual void AddActiveOutputNode(uint64 node_id) OVERRIDE {
    158     dbus::MethodCall method_call(cras::kCrasControlInterface,
    159                                  cras::kAddActiveOutputNode);
    160     dbus::MessageWriter writer(&method_call);
    161     writer.AppendUint64(node_id);
    162     cras_proxy_->CallMethod(&method_call,
    163                             dbus::ObjectProxy::TIMEOUT_USE_DEFAULT,
    164                             dbus::ObjectProxy::EmptyResponseCallback());
    165   }
    166 
    167   virtual void RemoveActiveOutputNode(uint64 node_id) OVERRIDE {
    168     dbus::MethodCall method_call(cras::kCrasControlInterface,
    169                                  cras::kRemoveActiveOutputNode);
    170     dbus::MessageWriter writer(&method_call);
    171     writer.AppendUint64(node_id);
    172     cras_proxy_->CallMethod(&method_call,
    173                             dbus::ObjectProxy::TIMEOUT_USE_DEFAULT,
    174                             dbus::ObjectProxy::EmptyResponseCallback());
    175   }
    176 
    177  protected:
    178   virtual void Init(dbus::Bus* bus) OVERRIDE {
    179     cras_proxy_ = bus->GetObjectProxy(cras::kCrasServiceName,
    180                                       dbus::ObjectPath(cras::kCrasServicePath));
    181 
    182     // Monitor NameOwnerChanged signal.
    183     cras_proxy_->SetNameOwnerChangedCallback(
    184         base::Bind(&CrasAudioClientImpl::NameOwnerChangedReceived,
    185                    weak_ptr_factory_.GetWeakPtr()));
    186 
    187     // Monitor the D-Bus signal for output mute change.
    188     cras_proxy_->ConnectToSignal(
    189         cras::kCrasControlInterface,
    190         cras::kOutputMuteChanged,
    191         base::Bind(&CrasAudioClientImpl::OutputMuteChangedReceived,
    192                    weak_ptr_factory_.GetWeakPtr()),
    193         base::Bind(&CrasAudioClientImpl::SignalConnected,
    194                    weak_ptr_factory_.GetWeakPtr()));
    195 
    196     // Monitor the D-Bus signal for input mute change.
    197     cras_proxy_->ConnectToSignal(
    198         cras::kCrasControlInterface,
    199         cras::kInputMuteChanged,
    200         base::Bind(&CrasAudioClientImpl::InputMuteChangedReceived,
    201                    weak_ptr_factory_.GetWeakPtr()),
    202         base::Bind(&CrasAudioClientImpl::SignalConnected,
    203                    weak_ptr_factory_.GetWeakPtr()));
    204 
    205     // Monitor the D-Bus signal for nodes change.
    206     cras_proxy_->ConnectToSignal(
    207         cras::kCrasControlInterface,
    208         cras::kNodesChanged,
    209         base::Bind(&CrasAudioClientImpl::NodesChangedReceived,
    210                    weak_ptr_factory_.GetWeakPtr()),
    211         base::Bind(&CrasAudioClientImpl::SignalConnected,
    212                    weak_ptr_factory_.GetWeakPtr()));
    213 
    214     // Monitor the D-Bus signal for active output node change.
    215     cras_proxy_->ConnectToSignal(
    216         cras::kCrasControlInterface,
    217         cras::kActiveOutputNodeChanged,
    218         base::Bind(&CrasAudioClientImpl::ActiveOutputNodeChangedReceived,
    219                    weak_ptr_factory_.GetWeakPtr()),
    220         base::Bind(&CrasAudioClientImpl::SignalConnected,
    221                    weak_ptr_factory_.GetWeakPtr()));
    222 
    223     // Monitor the D-Bus signal for active input node change.
    224     cras_proxy_->ConnectToSignal(
    225         cras::kCrasControlInterface,
    226         cras::kActiveInputNodeChanged,
    227         base::Bind(&CrasAudioClientImpl::ActiveInputNodeChangedReceived,
    228                    weak_ptr_factory_.GetWeakPtr()),
    229         base::Bind(&CrasAudioClientImpl::SignalConnected,
    230                    weak_ptr_factory_.GetWeakPtr()));
    231   }
    232 
    233  private:
    234   // Called when the cras signal is initially connected.
    235   void SignalConnected(const std::string& interface_name,
    236                        const std::string& signal_name,
    237                        bool success) {
    238     LOG_IF(ERROR, !success)
    239         << "Failed to connect to cras signal:" << signal_name;
    240   }
    241 
    242   void NameOwnerChangedReceived(const std::string& old_owner,
    243                                 const std::string& new_owner) {
    244     FOR_EACH_OBSERVER(Observer, observers_, AudioClientRestarted());
    245   }
    246 
    247   // Called when a OutputMuteChanged signal is received.
    248   void OutputMuteChangedReceived(dbus::Signal* signal) {
    249     // Chrome should always call SetOutputUserMute api to set the output
    250     // mute state and monitor user_mute state from OutputMuteChanged signal.
    251     dbus::MessageReader reader(signal);
    252     bool system_mute, user_mute;
    253     if (!reader.PopBool(&system_mute) || !reader.PopBool(&user_mute)) {
    254       LOG(ERROR) << "Error reading signal from cras:"
    255                  << signal->ToString();
    256     }
    257     FOR_EACH_OBSERVER(Observer, observers_, OutputMuteChanged(user_mute));
    258   }
    259 
    260   // Called when a InputMuteChanged signal is received.
    261   void InputMuteChangedReceived(dbus::Signal* signal) {
    262     dbus::MessageReader reader(signal);
    263     bool mute;
    264     if (!reader.PopBool(&mute)) {
    265       LOG(ERROR) << "Error reading signal from cras:"
    266                  << signal->ToString();
    267     }
    268     FOR_EACH_OBSERVER(Observer, observers_, InputMuteChanged(mute));
    269   }
    270 
    271   void NodesChangedReceived(dbus::Signal* signal) {
    272     FOR_EACH_OBSERVER(Observer, observers_, NodesChanged());
    273   }
    274 
    275   void ActiveOutputNodeChangedReceived(dbus::Signal* signal) {
    276     dbus::MessageReader reader(signal);
    277     uint64 node_id;
    278     if (!reader.PopUint64(&node_id)) {
    279       LOG(ERROR) << "Error reading signal from cras:"
    280                  << signal->ToString();
    281     }
    282     FOR_EACH_OBSERVER(Observer, observers_, ActiveOutputNodeChanged(node_id));
    283   }
    284 
    285   void ActiveInputNodeChangedReceived(dbus::Signal* signal) {
    286     dbus::MessageReader reader(signal);
    287     uint64 node_id;
    288     if (!reader.PopUint64(&node_id)) {
    289       LOG(ERROR) << "Error reading signal from cras:"
    290                  << signal->ToString();
    291     }
    292     FOR_EACH_OBSERVER(Observer, observers_, ActiveInputNodeChanged(node_id));
    293   }
    294 
    295   void OnGetVolumeState(const GetVolumeStateCallback& callback,
    296                         dbus::Response* response) {
    297     bool success = true;
    298     VolumeState volume_state;
    299     if (response) {
    300       dbus::MessageReader reader(response);
    301       if (!reader.PopInt32(&volume_state.output_volume) ||
    302           !reader.PopBool(&volume_state.output_system_mute) ||
    303           !reader.PopInt32(&volume_state.input_gain) ||
    304           !reader.PopBool(&volume_state.input_mute) ||
    305           !reader.PopBool(&volume_state.output_user_mute)) {
    306         success = false;
    307         LOG(ERROR) << "Error reading response from cras: "
    308                    << response->ToString();
    309       }
    310     } else {
    311       success = false;
    312       LOG(ERROR) << "Error calling " << cras::kGetVolumeState;
    313     }
    314 
    315     callback.Run(volume_state, success);
    316   }
    317 
    318   void OnGetNodes(const GetNodesCallback& callback,
    319                   dbus::Response* response) {
    320     bool success = true;
    321     AudioNodeList node_list;
    322     if (response) {
    323       dbus::MessageReader response_reader(response);
    324       dbus::MessageReader array_reader(response);
    325       while (response_reader.HasMoreData()) {
    326         if (!response_reader.PopArray(&array_reader)) {
    327           success = false;
    328           LOG(ERROR) << "Error reading response from cras: "
    329                      << response->ToString();
    330           break;
    331         }
    332 
    333         AudioNode node;
    334         if (!GetAudioNode(response, &array_reader, &node)) {
    335           success = false;
    336           LOG(WARNING) << "Error reading audio node data from cras: "
    337                        << response->ToString();
    338           break;
    339         }
    340         // Filter out the "UNKNOWN" type of audio devices.
    341         if (node.type != "UNKNOWN")
    342           node_list.push_back(node);
    343       }
    344     }
    345 
    346     if (node_list.empty())
    347       return;
    348 
    349     callback.Run(node_list, success);
    350   }
    351 
    352   void OnError(const ErrorCallback& error_callback,
    353                dbus::ErrorResponse* response) {
    354     // Error response has optional error message argument.
    355     std::string error_name;
    356     std::string error_message;
    357     if (response) {
    358       dbus::MessageReader reader(response);
    359       error_name = response->GetErrorName();
    360       reader.PopString(&error_message);
    361     } else {
    362       error_name = kNoResponseError;
    363       error_message = "";
    364     }
    365     error_callback.Run(error_name, error_message);
    366   }
    367 
    368   bool GetAudioNode(dbus::Response* response,
    369                     dbus::MessageReader* array_reader,
    370                     AudioNode *node) {
    371     while (array_reader->HasMoreData()) {
    372       dbus::MessageReader dict_entry_reader(response);
    373       dbus::MessageReader value_reader(response);
    374       std::string key;
    375       if (!array_reader->PopDictEntry(&dict_entry_reader) ||
    376           !dict_entry_reader.PopString(&key) ||
    377           !dict_entry_reader.PopVariant(&value_reader)) {
    378          return false;
    379       }
    380 
    381       if (key == cras::kIsInputProperty) {
    382         if (!value_reader.PopBool(&node->is_input))
    383           return false;
    384       } else if (key == cras::kIdProperty) {
    385         if (!value_reader.PopUint64(&node->id))
    386           return false;
    387       } else if (key == cras::kDeviceNameProperty) {
    388         if (!value_reader.PopString(&node->device_name))
    389           return false;
    390       } else if (key == cras::kTypeProperty) {
    391         if (!value_reader.PopString(&node->type))
    392           return false;
    393       } else if (key == cras::kNameProperty) {
    394         if (!value_reader.PopString(&node->name))
    395           return false;
    396       } else if (key == cras::kActiveProperty) {
    397         if (!value_reader.PopBool(&node->active))
    398           return false;
    399       } else if (key == cras::kPluggedTimeProperty) {
    400         if (!value_reader.PopUint64(&node->plugged_time))
    401           return false;
    402       }
    403     }
    404 
    405     return true;
    406   }
    407 
    408   dbus::ObjectProxy* cras_proxy_;
    409   ObserverList<Observer> observers_;
    410 
    411   // Note: This should remain the last member so it'll be destroyed and
    412   // invalidate its weak pointers before any other members are destroyed.
    413   base::WeakPtrFactory<CrasAudioClientImpl> weak_ptr_factory_;
    414 
    415   DISALLOW_COPY_AND_ASSIGN(CrasAudioClientImpl);
    416 };
    417 
    418 CrasAudioClient::Observer::~Observer() {
    419 }
    420 
    421 void CrasAudioClient::Observer::AudioClientRestarted() {
    422 }
    423 
    424 void CrasAudioClient::Observer::OutputMuteChanged(bool mute_on) {
    425 }
    426 
    427 void CrasAudioClient::Observer::InputMuteChanged(bool mute_on) {
    428 }
    429 
    430 void CrasAudioClient::Observer::NodesChanged() {
    431 }
    432 
    433 void CrasAudioClient::Observer::ActiveOutputNodeChanged(uint64 node_id){
    434 }
    435 
    436 void CrasAudioClient::Observer::ActiveInputNodeChanged(uint64 node_id) {
    437 }
    438 
    439 CrasAudioClient::CrasAudioClient() {
    440 }
    441 
    442 CrasAudioClient::~CrasAudioClient() {
    443 }
    444 
    445 // static
    446 CrasAudioClient* CrasAudioClient::Create() {
    447   return new CrasAudioClientImpl();
    448 }
    449 
    450 }  // namespace chromeos
    451