• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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:
CrasAudioClientImpl()26   CrasAudioClientImpl() : cras_proxy_(NULL), weak_ptr_factory_(this) {}
27 
~CrasAudioClientImpl()28   virtual ~CrasAudioClientImpl() {
29   }
30 
31   // CrasAudioClient overrides:
AddObserver(Observer * observer)32   virtual void AddObserver(Observer* observer) OVERRIDE {
33     observers_.AddObserver(observer);
34   }
35 
RemoveObserver(Observer * observer)36   virtual void RemoveObserver(Observer* observer) OVERRIDE {
37     observers_.RemoveObserver(observer);
38   }
39 
HasObserver(Observer * observer)40   virtual bool HasObserver(Observer* observer) OVERRIDE {
41     return observers_.HasObserver(observer);
42   }
43 
GetVolumeState(const GetVolumeStateCallback & callback)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 
GetNodes(const GetNodesCallback & callback,const ErrorCallback & error_callback)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 
SetOutputNodeVolume(uint64 node_id,int32 volume)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 
SetOutputUserMute(bool mute_on)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 
SetInputNodeGain(uint64 node_id,int32 input_gain)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 
SetInputMute(bool mute_on)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 
SetActiveOutputNode(uint64 node_id)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 
SetActiveInputNode(uint64 node_id)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 
AddActiveInputNode(uint64 node_id)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 
RemoveActiveInputNode(uint64 node_id)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 
AddActiveOutputNode(uint64 node_id)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 
RemoveActiveOutputNode(uint64 node_id)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:
Init(dbus::Bus * bus)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.
SignalConnected(const std::string & interface_name,const std::string & signal_name,bool success)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 
NameOwnerChangedReceived(const std::string & old_owner,const std::string & new_owner)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.
OutputMuteChangedReceived(dbus::Signal * signal)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.
InputMuteChangedReceived(dbus::Signal * signal)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 
NodesChangedReceived(dbus::Signal * signal)271   void NodesChangedReceived(dbus::Signal* signal) {
272     FOR_EACH_OBSERVER(Observer, observers_, NodesChanged());
273   }
274 
ActiveOutputNodeChangedReceived(dbus::Signal * signal)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 
ActiveInputNodeChangedReceived(dbus::Signal * signal)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 
OnGetVolumeState(const GetVolumeStateCallback & callback,dbus::Response * response)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 
OnGetNodes(const GetNodesCallback & callback,dbus::Response * response)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 
OnError(const ErrorCallback & error_callback,dbus::ErrorResponse * response)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 
GetAudioNode(dbus::Response * response,dbus::MessageReader * array_reader,AudioNode * node)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 
~Observer()418 CrasAudioClient::Observer::~Observer() {
419 }
420 
AudioClientRestarted()421 void CrasAudioClient::Observer::AudioClientRestarted() {
422 }
423 
OutputMuteChanged(bool mute_on)424 void CrasAudioClient::Observer::OutputMuteChanged(bool mute_on) {
425 }
426 
InputMuteChanged(bool mute_on)427 void CrasAudioClient::Observer::InputMuteChanged(bool mute_on) {
428 }
429 
NodesChanged()430 void CrasAudioClient::Observer::NodesChanged() {
431 }
432 
ActiveOutputNodeChanged(uint64 node_id)433 void CrasAudioClient::Observer::ActiveOutputNodeChanged(uint64 node_id){
434 }
435 
ActiveInputNodeChanged(uint64 node_id)436 void CrasAudioClient::Observer::ActiveInputNodeChanged(uint64 node_id) {
437 }
438 
CrasAudioClient()439 CrasAudioClient::CrasAudioClient() {
440 }
441 
~CrasAudioClient()442 CrasAudioClient::~CrasAudioClient() {
443 }
444 
445 // static
Create()446 CrasAudioClient* CrasAudioClient::Create() {
447   return new CrasAudioClientImpl();
448 }
449 
450 }  // namespace chromeos
451