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.
5 #include "chromeos/dbus/cras_audio_client.h"
9 #include "dbus/message.h"
10 #include "dbus/object_path.h"
11 #include "dbus/object_proxy.h"
12 #include "third_party/cros_system_api/dbus/service_constants.h"
16 // The CrasAudioClient implementation used in production.
17 class CrasAudioClientImpl
: public CrasAudioClient
{
19 explicit CrasAudioClientImpl(dbus::Bus
* bus
)
21 weak_ptr_factory_(this) {
22 cras_proxy_
= bus
->GetObjectProxy(
23 cras::kCrasServiceName
,
24 dbus::ObjectPath(cras::kCrasServicePath
));
26 // Monitor NameOwnerChanged signal.
27 cras_proxy_
->SetNameOwnerChangedCallback(
28 base::Bind(&CrasAudioClientImpl::NameOwnerChangedReceived
,
29 weak_ptr_factory_
.GetWeakPtr()));
31 // Monitor the D-Bus signal for output volume change.
32 cras_proxy_
->ConnectToSignal(
33 cras::kCrasControlInterface
,
34 cras::kOutputVolumeChanged
,
35 base::Bind(&CrasAudioClientImpl::OutputVolumeChangedReceived
,
36 weak_ptr_factory_
.GetWeakPtr()),
37 base::Bind(&CrasAudioClientImpl::SignalConnected
,
38 weak_ptr_factory_
.GetWeakPtr()));
40 // Monitor the D-Bus signal for output mute change.
41 cras_proxy_
->ConnectToSignal(
42 cras::kCrasControlInterface
,
43 cras::kOutputMuteChanged
,
44 base::Bind(&CrasAudioClientImpl::OutputMuteChangedReceived
,
45 weak_ptr_factory_
.GetWeakPtr()),
46 base::Bind(&CrasAudioClientImpl::SignalConnected
,
47 weak_ptr_factory_
.GetWeakPtr()));
49 // Monitor the D-Bus signal for input gain change.
50 cras_proxy_
->ConnectToSignal(
51 cras::kCrasControlInterface
,
52 cras::kInputGainChanged
,
53 base::Bind(&CrasAudioClientImpl::InputGainChangedReceived
,
54 weak_ptr_factory_
.GetWeakPtr()),
55 base::Bind(&CrasAudioClientImpl::SignalConnected
,
56 weak_ptr_factory_
.GetWeakPtr()));
58 // Monitor the D-Bus signal for input mute change.
59 cras_proxy_
->ConnectToSignal(
60 cras::kCrasControlInterface
,
61 cras::kInputMuteChanged
,
62 base::Bind(&CrasAudioClientImpl::InputMuteChangedReceived
,
63 weak_ptr_factory_
.GetWeakPtr()),
64 base::Bind(&CrasAudioClientImpl::SignalConnected
,
65 weak_ptr_factory_
.GetWeakPtr()));
67 // Monitor the D-Bus signal for nodes change.
68 cras_proxy_
->ConnectToSignal(
69 cras::kCrasControlInterface
,
71 base::Bind(&CrasAudioClientImpl::NodesChangedReceived
,
72 weak_ptr_factory_
.GetWeakPtr()),
73 base::Bind(&CrasAudioClientImpl::SignalConnected
,
74 weak_ptr_factory_
.GetWeakPtr()));
76 // Monitor the D-Bus signal for active output node change.
77 cras_proxy_
->ConnectToSignal(
78 cras::kCrasControlInterface
,
79 cras::kActiveOutputNodeChanged
,
80 base::Bind(&CrasAudioClientImpl::ActiveOutputNodeChangedReceived
,
81 weak_ptr_factory_
.GetWeakPtr()),
82 base::Bind(&CrasAudioClientImpl::SignalConnected
,
83 weak_ptr_factory_
.GetWeakPtr()));
85 // Monitor the D-Bus signal for active input node change.
86 cras_proxy_
->ConnectToSignal(
87 cras::kCrasControlInterface
,
88 cras::kActiveInputNodeChanged
,
89 base::Bind(&CrasAudioClientImpl::ActiveInputNodeChangedReceived
,
90 weak_ptr_factory_
.GetWeakPtr()),
91 base::Bind(&CrasAudioClientImpl::SignalConnected
,
92 weak_ptr_factory_
.GetWeakPtr()));
95 virtual ~CrasAudioClientImpl() {
98 // CrasAudioClient overrides:
99 virtual void AddObserver(Observer
* observer
) OVERRIDE
{
100 observers_
.AddObserver(observer
);
103 virtual void RemoveObserver(Observer
* observer
) OVERRIDE
{
104 observers_
.RemoveObserver(observer
);
107 virtual bool HasObserver(Observer
* observer
) OVERRIDE
{
108 return observers_
.HasObserver(observer
);
111 virtual void GetVolumeState(const GetVolumeStateCallback
& callback
) OVERRIDE
{
112 dbus::MethodCall
method_call(cras::kCrasControlInterface
,
113 cras::kGetVolumeState
);
114 cras_proxy_
->CallMethod(
116 dbus::ObjectProxy::TIMEOUT_USE_DEFAULT
,
117 base::Bind(&CrasAudioClientImpl::OnGetVolumeState
,
118 weak_ptr_factory_
.GetWeakPtr(), callback
));
121 virtual void GetNodes(const GetNodesCallback
& callback
) OVERRIDE
{
122 dbus::MethodCall
method_call(cras::kCrasControlInterface
,
124 cras_proxy_
->CallMethod(
126 dbus::ObjectProxy::TIMEOUT_USE_DEFAULT
,
127 base::Bind(&CrasAudioClientImpl::OnGetNodes
,
128 weak_ptr_factory_
.GetWeakPtr(), callback
));
131 virtual void SetOutputVolume(int32 volume
) OVERRIDE
{
132 dbus::MethodCall
method_call(cras::kCrasControlInterface
,
133 cras::kSetOutputVolume
);
134 dbus::MessageWriter
writer(&method_call
);
135 writer
.AppendInt32(volume
);
136 cras_proxy_
->CallMethod(
138 dbus::ObjectProxy::TIMEOUT_USE_DEFAULT
,
139 dbus::ObjectProxy::EmptyResponseCallback());
142 virtual void SetOutputMute(bool mute_on
) OVERRIDE
{
143 dbus::MethodCall
method_call(cras::kCrasControlInterface
,
144 cras::kSetOutputMute
);
145 dbus::MessageWriter
writer(&method_call
);
146 writer
.AppendBool(mute_on
);
147 cras_proxy_
->CallMethod(
149 dbus::ObjectProxy::TIMEOUT_USE_DEFAULT
,
150 dbus::ObjectProxy::EmptyResponseCallback());
153 virtual void SetInputGain(int32 input_gain
) OVERRIDE
{
154 dbus::MethodCall
method_call(cras::kCrasControlInterface
,
155 cras::kSetInputGain
);
156 dbus::MessageWriter
writer(&method_call
);
157 writer
.AppendInt32(input_gain
);
158 cras_proxy_
->CallMethod(
160 dbus::ObjectProxy::TIMEOUT_USE_DEFAULT
,
161 dbus::ObjectProxy::EmptyResponseCallback());
164 virtual void SetInputMute(bool mute_on
) OVERRIDE
{
165 dbus::MethodCall
method_call(cras::kCrasControlInterface
,
166 cras::kSetInputMute
);
167 dbus::MessageWriter
writer(&method_call
);
168 writer
.AppendBool(mute_on
);
169 cras_proxy_
->CallMethod(
171 dbus::ObjectProxy::TIMEOUT_USE_DEFAULT
,
172 dbus::ObjectProxy::EmptyResponseCallback());
175 virtual void SetActiveOutputNode(uint64 node_id
) OVERRIDE
{
176 dbus::MethodCall
method_call(cras::kCrasControlInterface
,
177 cras::kSetActiveOutputNode
);
178 dbus::MessageWriter
writer(&method_call
);
179 writer
.AppendUint64(node_id
);
180 cras_proxy_
->CallMethod(
182 dbus::ObjectProxy::TIMEOUT_USE_DEFAULT
,
183 dbus::ObjectProxy::EmptyResponseCallback());
186 virtual void SetActiveInputNode(uint64 node_id
) OVERRIDE
{
187 dbus::MethodCall
method_call(cras::kCrasControlInterface
,
188 cras::kSetActiveInputNode
);
189 dbus::MessageWriter
writer(&method_call
);
190 writer
.AppendUint64(node_id
);
191 cras_proxy_
->CallMethod(
193 dbus::ObjectProxy::TIMEOUT_USE_DEFAULT
,
194 dbus::ObjectProxy::EmptyResponseCallback());
198 // Called when the cras signal is initially connected.
199 void SignalConnected(const std::string
& interface_name
,
200 const std::string
& signal_name
,
202 LOG_IF(ERROR
, !success
)
203 << "Failed to connect to cras signal:" << signal_name
;
206 void NameOwnerChangedReceived(dbus::Signal
* signal
) {
207 FOR_EACH_OBSERVER(Observer
, observers_
, AudioClientRestarted());
210 // Called when a OutputVolumeChanged signal is received.
211 void OutputVolumeChangedReceived(dbus::Signal
* signal
) {
212 dbus::MessageReader
reader(signal
);
214 if (!reader
.PopInt32(&volume
)) {
215 LOG(ERROR
) << "Error reading signal from cras:"
216 << signal
->ToString();
218 FOR_EACH_OBSERVER(Observer
, observers_
, OutputVolumeChanged(volume
));
221 // Called when a OutputMuteChanged signal is received.
222 void OutputMuteChangedReceived(dbus::Signal
* signal
) {
223 dbus::MessageReader
reader(signal
);
225 if (!reader
.PopBool(&mute
)) {
226 LOG(ERROR
) << "Error reading signal from cras:"
227 << signal
->ToString();
229 FOR_EACH_OBSERVER(Observer
, observers_
, OutputMuteChanged(mute
));
232 // Called when a InputGainChanged signal is received.
233 void InputGainChangedReceived(dbus::Signal
* signal
) {
234 dbus::MessageReader
reader(signal
);
236 if (!reader
.PopInt32(&gain
)) {
237 LOG(ERROR
) << "Error reading signal from cras:"
238 << signal
->ToString();
240 FOR_EACH_OBSERVER(Observer
, observers_
, InputGainChanged(gain
));
243 // Called when a InputMuteChanged signal is received.
244 void InputMuteChangedReceived(dbus::Signal
* signal
) {
245 dbus::MessageReader
reader(signal
);
247 if (!reader
.PopBool(&mute
)) {
248 LOG(ERROR
) << "Error reading signal from cras:"
249 << signal
->ToString();
251 FOR_EACH_OBSERVER(Observer
, observers_
, InputMuteChanged(mute
));
254 void NodesChangedReceived(dbus::Signal
* signal
) {
255 FOR_EACH_OBSERVER(Observer
, observers_
, NodesChanged());
258 void ActiveOutputNodeChangedReceived(dbus::Signal
* signal
) {
259 dbus::MessageReader
reader(signal
);
261 if (!reader
.PopUint64(&node_id
)) {
262 LOG(ERROR
) << "Error reading signal from cras:"
263 << signal
->ToString();
265 FOR_EACH_OBSERVER(Observer
, observers_
, ActiveOutputNodeChanged(node_id
));
268 void ActiveInputNodeChangedReceived(dbus::Signal
* signal
) {
269 dbus::MessageReader
reader(signal
);
271 if (!reader
.PopUint64(&node_id
)) {
272 LOG(ERROR
) << "Error reading signal from cras:"
273 << signal
->ToString();
275 FOR_EACH_OBSERVER(Observer
, observers_
, ActiveInputNodeChanged(node_id
));
278 void OnGetVolumeState(const GetVolumeStateCallback
& callback
,
279 dbus::Response
* response
) {
281 VolumeState volume_state
;
283 dbus::MessageReader
reader(response
);
284 if (!reader
.PopInt32(&volume_state
.output_volume
) ||
285 !reader
.PopBool(&volume_state
.output_mute
) ||
286 !reader
.PopInt32(&volume_state
.input_gain
) ||
287 !reader
.PopBool(&volume_state
.input_mute
)) {
289 LOG(ERROR
) << "Error reading response from cras: "
290 << response
->ToString();
294 LOG(ERROR
) << "Error calling " << cras::kGetVolumeState
;
297 callback
.Run(volume_state
, success
);
300 void OnGetNodes(const GetNodesCallback
& callback
,
301 dbus::Response
* response
) {
303 AudioNodeList node_list
;
305 dbus::MessageReader
response_reader(response
);
306 dbus::MessageReader
array_reader(response
);
307 while (response_reader
.HasMoreData()) {
308 if (!response_reader
.PopArray(&array_reader
)) {
310 LOG(ERROR
) << "Error reading response from cras: "
311 << response
->ToString();
316 if (!GetAudioNode(response
, &array_reader
, &node
)) {
318 LOG(WARNING
) << "Error reading audio node data from cras: "
319 << response
->ToString();
323 node_list
.push_back(node
);
327 LOG(ERROR
) << "Error calling " << cras::kGetNodes
;
330 callback
.Run(node_list
, success
);
333 bool GetAudioNode(dbus::Response
* response
,
334 dbus::MessageReader
* array_reader
,
336 while (array_reader
->HasMoreData()) {
337 dbus::MessageReader
dict_entry_reader(response
);
338 dbus::MessageReader
value_reader(response
);
340 if (!array_reader
->PopDictEntry(&dict_entry_reader
) ||
341 !dict_entry_reader
.PopString(&key
) ||
342 !dict_entry_reader
.PopVariant(&value_reader
)) {
346 if (key
== cras::kIsInputProperty
) {
347 if (!value_reader
.PopBool(&node
->is_input
))
349 } else if (key
== cras::kIdProperty
) {
350 if (!value_reader
.PopUint64(&node
->id
))
352 } else if (key
== cras::kDeviceNameProperty
) {
353 if (!value_reader
.PopString(&node
->device_name
))
355 } else if (key
== cras::kTypeProperty
) {
356 if (!value_reader
.PopString(&node
->type
))
358 } else if (key
== cras::kNameProperty
) {
359 if (!value_reader
.PopString(&node
->name
))
361 } else if (key
== cras::kActiveProperty
) {
362 if (!value_reader
.PopBool(&node
->active
))
364 } else if (key
== cras::kPluggedTimeProperty
) {
365 if (!value_reader
.PopUint64(&node
->plugged_time
))
373 dbus::ObjectProxy
* cras_proxy_
;
374 ObserverList
<Observer
> observers_
;
376 // Note: This should remain the last member so it'll be destroyed and
377 // invalidate its weak pointers before any other members are destroyed.
378 base::WeakPtrFactory
<CrasAudioClientImpl
> weak_ptr_factory_
;
380 DISALLOW_COPY_AND_ASSIGN(CrasAudioClientImpl
);
383 // The CrasAudioClient implementation used on Linux desktop,
384 // which does nothing.
385 class CrasAudioClientStubImpl
: public CrasAudioClient
{
387 CrasAudioClientStubImpl() {
388 VLOG(1) << "CrasAudioClientStubImpl is created";
390 // Fake audio output nodes.
392 node_1
.is_input
= false;
394 node_1
.device_name
= "Fake Speaker";
395 node_1
.type
= "INTERNAL_SPEAKER";
396 node_1
.name
= "Speaker";
397 node_1
.active
= false;
398 node_list_
.push_back(node_1
);
401 node_2
.is_input
= false;
403 node_2
.device_name
= "Fake Headphone";
404 node_2
.type
= "HEADPHONE";
405 node_2
.name
= "Headphone";
406 node_2
.active
= true;
407 node_list_
.push_back(node_2
);
408 active_output_node_id_
= node_2
.id
;
411 node_3
.is_input
= false;
413 node_3
.device_name
= "Fake Audio Output";
414 node_3
.type
= "BLUETOOTH";
415 node_3
.name
= "Bluetooth Headphone";
416 node_3
.active
= false;
417 node_list_
.push_back(node_3
);
419 // Fake audio input ndoes
421 node_4
.is_input
= true;
423 node_4
.device_name
= "Fake Internal Mic";
424 node_4
.type
= "INTERNAL_MIC";
425 node_4
.name
= "Internal Mic";
426 node_4
.active
= false;
427 node_list_
.push_back(node_4
);
430 node_5
.is_input
= true;
432 node_5
.device_name
= "Fake Internal Mic";
434 node_5
.name
= "USB Mic";
435 node_5
.active
= true;
436 node_list_
.push_back(node_5
);
437 active_input_node_id_
= node_5
.id
;
439 virtual ~CrasAudioClientStubImpl() {
442 // CrasAudioClient overrides:
443 // TODO(jennyz): Implement the observers and callbacks in the stub for UI
445 virtual void AddObserver(Observer
* observer
) OVERRIDE
{
446 observers_
.AddObserver(observer
);
449 virtual void RemoveObserver(Observer
* observer
) OVERRIDE
{
450 observers_
.RemoveObserver(observer
);
453 virtual bool HasObserver(Observer
* observer
) OVERRIDE
{
454 return observers_
.HasObserver(observer
);
457 virtual void GetVolumeState(const GetVolumeStateCallback
& callback
) OVERRIDE
{
458 callback
.Run(volume_state_
, true);
461 virtual void GetNodes(const GetNodesCallback
& callback
)OVERRIDE
{
462 callback
.Run(node_list_
, true);
465 virtual void SetOutputVolume(int32 volume
) OVERRIDE
{
466 volume_state_
.output_volume
= volume
;
467 FOR_EACH_OBSERVER(Observer
,
469 OutputVolumeChanged(volume_state_
.output_volume
));
472 virtual void SetOutputMute(bool mute_on
) OVERRIDE
{
473 volume_state_
.output_mute
= mute_on
;
474 FOR_EACH_OBSERVER(Observer
,
476 OutputMuteChanged(volume_state_
.output_mute
));
479 virtual void SetInputGain(int32 input_gain
) OVERRIDE
{
480 volume_state_
.input_gain
= input_gain
;
481 FOR_EACH_OBSERVER(Observer
,
483 InputGainChanged(volume_state_
.input_gain
));
486 virtual void SetInputMute(bool mute_on
) OVERRIDE
{
487 volume_state_
.input_mute
= mute_on
;
488 FOR_EACH_OBSERVER(Observer
,
490 InputMuteChanged(volume_state_
.input_mute
));
493 virtual void SetActiveOutputNode(uint64 node_id
) OVERRIDE
{
494 if (active_output_node_id_
== node_id
)
497 for (size_t i
= 0; i
< node_list_
.size(); ++i
) {
498 if (node_list_
[i
].id
== active_output_node_id_
)
499 node_list_
[i
].active
= false;
500 else if (node_list_
[i
].id
== node_id
)
501 node_list_
[i
].active
= true;
503 active_output_node_id_
= node_id
;
504 FOR_EACH_OBSERVER(Observer
,
506 ActiveOutputNodeChanged(node_id
));
509 virtual void SetActiveInputNode(uint64 node_id
) OVERRIDE
{
510 if (active_input_node_id_
== node_id
)
513 for (size_t i
= 0; i
< node_list_
.size(); ++i
) {
514 if (node_list_
[i
].id
== active_input_node_id_
)
515 node_list_
[i
].active
= false;
516 else if (node_list_
[i
].id
== node_id
)
517 node_list_
[i
].active
= true;
519 active_input_node_id_
= node_id
;
520 FOR_EACH_OBSERVER(Observer
,
522 ActiveInputNodeChanged(node_id
));
526 VolumeState volume_state_
;
527 AudioNodeList node_list_
;
528 uint64 active_input_node_id_
;
529 uint64 active_output_node_id_
;
530 ObserverList
<Observer
> observers_
;
532 DISALLOW_COPY_AND_ASSIGN(CrasAudioClientStubImpl
);
535 CrasAudioClient::Observer::~Observer() {
538 void CrasAudioClient::Observer::AudioClientRestarted() {
541 void CrasAudioClient::Observer::OutputVolumeChanged(int32 volume
) {
544 void CrasAudioClient::Observer::OutputMuteChanged(bool mute_on
) {
547 void CrasAudioClient::Observer::InputGainChanged(int gain
) {
550 void CrasAudioClient::Observer::InputMuteChanged(bool mute_on
) {
553 void CrasAudioClient::Observer::NodesChanged() {
556 void CrasAudioClient::Observer::ActiveOutputNodeChanged(uint64 node_id
){
559 void CrasAudioClient::Observer::ActiveInputNodeChanged(uint64 node_id
) {
562 CrasAudioClient::CrasAudioClient() {
565 CrasAudioClient::~CrasAudioClient() {
569 CrasAudioClient
* CrasAudioClient::Create(
570 DBusClientImplementationType type
,
572 if (type
== REAL_DBUS_CLIENT_IMPLEMENTATION
) {
573 return new CrasAudioClientImpl(bus
);
575 DCHECK_EQ(STUB_DBUS_CLIENT_IMPLEMENTATION
, type
);
576 return new CrasAudioClientStubImpl();
579 } // namespace chromeos