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