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"
8 #include "base/format_macros.h"
9 #include "base/strings/stringprintf.h"
11 #include "dbus/message.h"
12 #include "dbus/object_path.h"
13 #include "dbus/object_proxy.h"
14 #include "third_party/cros_system_api/dbus/service_constants.h"
18 // Error name if cras dbus call fails with empty ErrorResponse.
19 const char kNoResponseError
[] =
20 "org.chromium.cras.Error.NoResponse";
22 // The CrasAudioClient implementation used in production.
23 class CrasAudioClientImpl
: public CrasAudioClient
{
25 CrasAudioClientImpl() : cras_proxy_(NULL
), weak_ptr_factory_(this) {}
27 virtual ~CrasAudioClientImpl() {
30 // CrasAudioClient overrides:
31 virtual void AddObserver(Observer
* observer
) override
{
32 observers_
.AddObserver(observer
);
35 virtual void RemoveObserver(Observer
* observer
) override
{
36 observers_
.RemoveObserver(observer
);
39 virtual bool HasObserver(Observer
* observer
) override
{
40 return observers_
.HasObserver(observer
);
43 virtual void GetVolumeState(const GetVolumeStateCallback
& callback
) override
{
44 dbus::MethodCall
method_call(cras::kCrasControlInterface
,
45 cras::kGetVolumeState
);
46 cras_proxy_
->CallMethod(
48 dbus::ObjectProxy::TIMEOUT_USE_DEFAULT
,
49 base::Bind(&CrasAudioClientImpl::OnGetVolumeState
,
50 weak_ptr_factory_
.GetWeakPtr(), callback
));
53 virtual void GetNodes(const GetNodesCallback
& callback
,
54 const ErrorCallback
& error_callback
) override
{
55 dbus::MethodCall
method_call(cras::kCrasControlInterface
,
57 cras_proxy_
->CallMethodWithErrorCallback(
59 dbus::ObjectProxy::TIMEOUT_USE_DEFAULT
,
60 base::Bind(&CrasAudioClientImpl::OnGetNodes
,
61 weak_ptr_factory_
.GetWeakPtr(), callback
),
62 base::Bind(&CrasAudioClientImpl::OnError
,
63 weak_ptr_factory_
.GetWeakPtr(), error_callback
));
66 virtual void SetOutputNodeVolume(uint64 node_id
, int32 volume
) override
{
67 dbus::MethodCall
method_call(cras::kCrasControlInterface
,
68 cras::kSetOutputNodeVolume
);
69 dbus::MessageWriter
writer(&method_call
);
70 writer
.AppendUint64(node_id
);
71 writer
.AppendInt32(volume
);
72 cras_proxy_
->CallMethod(
74 dbus::ObjectProxy::TIMEOUT_USE_DEFAULT
,
75 dbus::ObjectProxy::EmptyResponseCallback());
78 virtual void SetOutputUserMute(bool mute_on
) override
{
79 dbus::MethodCall
method_call(cras::kCrasControlInterface
,
80 cras::kSetOutputUserMute
);
81 dbus::MessageWriter
writer(&method_call
);
82 writer
.AppendBool(mute_on
);
83 cras_proxy_
->CallMethod(
85 dbus::ObjectProxy::TIMEOUT_USE_DEFAULT
,
86 dbus::ObjectProxy::EmptyResponseCallback());
89 virtual void SetInputNodeGain(uint64 node_id
, int32 input_gain
) override
{
90 dbus::MethodCall
method_call(cras::kCrasControlInterface
,
91 cras::kSetInputNodeGain
);
92 dbus::MessageWriter
writer(&method_call
);
93 writer
.AppendUint64(node_id
);
94 writer
.AppendInt32(input_gain
);
95 cras_proxy_
->CallMethod(
97 dbus::ObjectProxy::TIMEOUT_USE_DEFAULT
,
98 dbus::ObjectProxy::EmptyResponseCallback());
101 virtual void SetInputMute(bool mute_on
) override
{
102 dbus::MethodCall
method_call(cras::kCrasControlInterface
,
103 cras::kSetInputMute
);
104 dbus::MessageWriter
writer(&method_call
);
105 writer
.AppendBool(mute_on
);
106 cras_proxy_
->CallMethod(
108 dbus::ObjectProxy::TIMEOUT_USE_DEFAULT
,
109 dbus::ObjectProxy::EmptyResponseCallback());
112 virtual void SetActiveOutputNode(uint64 node_id
) override
{
113 dbus::MethodCall
method_call(cras::kCrasControlInterface
,
114 cras::kSetActiveOutputNode
);
115 dbus::MessageWriter
writer(&method_call
);
116 writer
.AppendUint64(node_id
);
117 cras_proxy_
->CallMethod(
119 dbus::ObjectProxy::TIMEOUT_USE_DEFAULT
,
120 dbus::ObjectProxy::EmptyResponseCallback());
123 virtual void SetActiveInputNode(uint64 node_id
) override
{
124 dbus::MethodCall
method_call(cras::kCrasControlInterface
,
125 cras::kSetActiveInputNode
);
126 dbus::MessageWriter
writer(&method_call
);
127 writer
.AppendUint64(node_id
);
128 cras_proxy_
->CallMethod(
130 dbus::ObjectProxy::TIMEOUT_USE_DEFAULT
,
131 dbus::ObjectProxy::EmptyResponseCallback());
134 virtual void AddActiveInputNode(uint64 node_id
) override
{
135 dbus::MethodCall
method_call(cras::kCrasControlInterface
,
136 cras::kAddActiveInputNode
);
137 dbus::MessageWriter
writer(&method_call
);
138 writer
.AppendUint64(node_id
);
139 cras_proxy_
->CallMethod(
141 dbus::ObjectProxy::TIMEOUT_USE_DEFAULT
,
142 dbus::ObjectProxy::EmptyResponseCallback());
145 virtual void RemoveActiveInputNode(uint64 node_id
) override
{
146 dbus::MethodCall
method_call(cras::kCrasControlInterface
,
147 cras::kRemoveActiveInputNode
);
148 dbus::MessageWriter
writer(&method_call
);
149 writer
.AppendUint64(node_id
);
150 cras_proxy_
->CallMethod(
152 dbus::ObjectProxy::TIMEOUT_USE_DEFAULT
,
153 dbus::ObjectProxy::EmptyResponseCallback());
156 virtual void AddActiveOutputNode(uint64 node_id
) override
{
157 dbus::MethodCall
method_call(cras::kCrasControlInterface
,
158 cras::kAddActiveOutputNode
);
159 dbus::MessageWriter
writer(&method_call
);
160 writer
.AppendUint64(node_id
);
161 cras_proxy_
->CallMethod(&method_call
,
162 dbus::ObjectProxy::TIMEOUT_USE_DEFAULT
,
163 dbus::ObjectProxy::EmptyResponseCallback());
166 virtual void RemoveActiveOutputNode(uint64 node_id
) override
{
167 dbus::MethodCall
method_call(cras::kCrasControlInterface
,
168 cras::kRemoveActiveOutputNode
);
169 dbus::MessageWriter
writer(&method_call
);
170 writer
.AppendUint64(node_id
);
171 cras_proxy_
->CallMethod(&method_call
,
172 dbus::ObjectProxy::TIMEOUT_USE_DEFAULT
,
173 dbus::ObjectProxy::EmptyResponseCallback());
176 virtual void SwapLeftRight(uint64 node_id
, bool swap
) override
{
177 dbus::MethodCall
method_call(cras::kCrasControlInterface
,
178 cras::kSwapLeftRight
);
179 dbus::MessageWriter
writer(&method_call
);
180 writer
.AppendUint64(node_id
);
181 writer
.AppendBool(swap
);
182 cras_proxy_
->CallMethod(&method_call
,
183 dbus::ObjectProxy::TIMEOUT_USE_DEFAULT
,
184 dbus::ObjectProxy::EmptyResponseCallback());
188 virtual void Init(dbus::Bus
* bus
) override
{
189 cras_proxy_
= bus
->GetObjectProxy(cras::kCrasServiceName
,
190 dbus::ObjectPath(cras::kCrasServicePath
));
192 // Monitor NameOwnerChanged signal.
193 cras_proxy_
->SetNameOwnerChangedCallback(
194 base::Bind(&CrasAudioClientImpl::NameOwnerChangedReceived
,
195 weak_ptr_factory_
.GetWeakPtr()));
197 // Monitor the D-Bus signal for output mute change.
198 cras_proxy_
->ConnectToSignal(
199 cras::kCrasControlInterface
,
200 cras::kOutputMuteChanged
,
201 base::Bind(&CrasAudioClientImpl::OutputMuteChangedReceived
,
202 weak_ptr_factory_
.GetWeakPtr()),
203 base::Bind(&CrasAudioClientImpl::SignalConnected
,
204 weak_ptr_factory_
.GetWeakPtr()));
206 // Monitor the D-Bus signal for input mute change.
207 cras_proxy_
->ConnectToSignal(
208 cras::kCrasControlInterface
,
209 cras::kInputMuteChanged
,
210 base::Bind(&CrasAudioClientImpl::InputMuteChangedReceived
,
211 weak_ptr_factory_
.GetWeakPtr()),
212 base::Bind(&CrasAudioClientImpl::SignalConnected
,
213 weak_ptr_factory_
.GetWeakPtr()));
215 // Monitor the D-Bus signal for nodes change.
216 cras_proxy_
->ConnectToSignal(
217 cras::kCrasControlInterface
,
219 base::Bind(&CrasAudioClientImpl::NodesChangedReceived
,
220 weak_ptr_factory_
.GetWeakPtr()),
221 base::Bind(&CrasAudioClientImpl::SignalConnected
,
222 weak_ptr_factory_
.GetWeakPtr()));
224 // Monitor the D-Bus signal for active output node change.
225 cras_proxy_
->ConnectToSignal(
226 cras::kCrasControlInterface
,
227 cras::kActiveOutputNodeChanged
,
228 base::Bind(&CrasAudioClientImpl::ActiveOutputNodeChangedReceived
,
229 weak_ptr_factory_
.GetWeakPtr()),
230 base::Bind(&CrasAudioClientImpl::SignalConnected
,
231 weak_ptr_factory_
.GetWeakPtr()));
233 // Monitor the D-Bus signal for active input node change.
234 cras_proxy_
->ConnectToSignal(
235 cras::kCrasControlInterface
,
236 cras::kActiveInputNodeChanged
,
237 base::Bind(&CrasAudioClientImpl::ActiveInputNodeChangedReceived
,
238 weak_ptr_factory_
.GetWeakPtr()),
239 base::Bind(&CrasAudioClientImpl::SignalConnected
,
240 weak_ptr_factory_
.GetWeakPtr()));
244 // Called when the cras signal is initially connected.
245 void SignalConnected(const std::string
& interface_name
,
246 const std::string
& signal_name
,
248 LOG_IF(ERROR
, !success
)
249 << "Failed to connect to cras signal:" << signal_name
;
252 void NameOwnerChangedReceived(const std::string
& old_owner
,
253 const std::string
& new_owner
) {
254 FOR_EACH_OBSERVER(Observer
, observers_
, AudioClientRestarted());
257 // Called when a OutputMuteChanged signal is received.
258 void OutputMuteChangedReceived(dbus::Signal
* signal
) {
259 // Chrome should always call SetOutputUserMute api to set the output
260 // mute state and monitor user_mute state from OutputMuteChanged signal.
261 dbus::MessageReader
reader(signal
);
262 bool system_mute
, user_mute
;
263 if (!reader
.PopBool(&system_mute
) || !reader
.PopBool(&user_mute
)) {
264 LOG(ERROR
) << "Error reading signal from cras:"
265 << signal
->ToString();
267 FOR_EACH_OBSERVER(Observer
, observers_
, OutputMuteChanged(user_mute
));
270 // Called when a InputMuteChanged signal is received.
271 void InputMuteChangedReceived(dbus::Signal
* signal
) {
272 dbus::MessageReader
reader(signal
);
274 if (!reader
.PopBool(&mute
)) {
275 LOG(ERROR
) << "Error reading signal from cras:"
276 << signal
->ToString();
278 FOR_EACH_OBSERVER(Observer
, observers_
, InputMuteChanged(mute
));
281 void NodesChangedReceived(dbus::Signal
* signal
) {
282 FOR_EACH_OBSERVER(Observer
, observers_
, NodesChanged());
285 void ActiveOutputNodeChangedReceived(dbus::Signal
* signal
) {
286 dbus::MessageReader
reader(signal
);
288 if (!reader
.PopUint64(&node_id
)) {
289 LOG(ERROR
) << "Error reading signal from cras:"
290 << signal
->ToString();
292 FOR_EACH_OBSERVER(Observer
, observers_
, ActiveOutputNodeChanged(node_id
));
295 void ActiveInputNodeChangedReceived(dbus::Signal
* signal
) {
296 dbus::MessageReader
reader(signal
);
298 if (!reader
.PopUint64(&node_id
)) {
299 LOG(ERROR
) << "Error reading signal from cras:"
300 << signal
->ToString();
302 FOR_EACH_OBSERVER(Observer
, observers_
, ActiveInputNodeChanged(node_id
));
305 void OnGetVolumeState(const GetVolumeStateCallback
& callback
,
306 dbus::Response
* response
) {
308 VolumeState volume_state
;
310 dbus::MessageReader
reader(response
);
311 if (!reader
.PopInt32(&volume_state
.output_volume
) ||
312 !reader
.PopBool(&volume_state
.output_system_mute
) ||
313 !reader
.PopInt32(&volume_state
.input_gain
) ||
314 !reader
.PopBool(&volume_state
.input_mute
) ||
315 !reader
.PopBool(&volume_state
.output_user_mute
)) {
317 LOG(ERROR
) << "Error reading response from cras: "
318 << response
->ToString();
322 LOG(ERROR
) << "Error calling " << cras::kGetVolumeState
;
325 callback
.Run(volume_state
, success
);
328 void OnGetNodes(const GetNodesCallback
& callback
,
329 dbus::Response
* response
) {
331 AudioNodeList node_list
;
333 dbus::MessageReader
response_reader(response
);
334 dbus::MessageReader
array_reader(response
);
335 while (response_reader
.HasMoreData()) {
336 if (!response_reader
.PopArray(&array_reader
)) {
338 LOG(ERROR
) << "Error reading response from cras: "
339 << response
->ToString();
344 if (!GetAudioNode(response
, &array_reader
, &node
)) {
346 LOG(WARNING
) << "Error reading audio node data from cras: "
347 << response
->ToString();
350 // Filter out the "UNKNOWN" type of audio devices.
351 if (node
.type
!= "UNKNOWN")
352 node_list
.push_back(node
);
356 if (node_list
.empty())
359 callback
.Run(node_list
, success
);
362 void OnError(const ErrorCallback
& error_callback
,
363 dbus::ErrorResponse
* response
) {
364 // Error response has optional error message argument.
365 std::string error_name
;
366 std::string error_message
;
368 dbus::MessageReader
reader(response
);
369 error_name
= response
->GetErrorName();
370 reader
.PopString(&error_message
);
372 error_name
= kNoResponseError
;
375 error_callback
.Run(error_name
, error_message
);
378 bool GetAudioNode(dbus::Response
* response
,
379 dbus::MessageReader
* array_reader
,
381 while (array_reader
->HasMoreData()) {
382 dbus::MessageReader
dict_entry_reader(response
);
383 dbus::MessageReader
value_reader(response
);
385 if (!array_reader
->PopDictEntry(&dict_entry_reader
) ||
386 !dict_entry_reader
.PopString(&key
) ||
387 !dict_entry_reader
.PopVariant(&value_reader
)) {
391 if (key
== cras::kIsInputProperty
) {
392 if (!value_reader
.PopBool(&node
->is_input
))
394 } else if (key
== cras::kIdProperty
) {
395 if (!value_reader
.PopUint64(&node
->id
))
397 } else if (key
== cras::kDeviceNameProperty
) {
398 if (!value_reader
.PopString(&node
->device_name
))
400 } else if (key
== cras::kTypeProperty
) {
401 if (!value_reader
.PopString(&node
->type
))
403 } else if (key
== cras::kNameProperty
) {
404 if (!value_reader
.PopString(&node
->name
))
406 } else if (key
== cras::kActiveProperty
) {
407 if (!value_reader
.PopBool(&node
->active
))
409 } else if (key
== cras::kPluggedTimeProperty
) {
410 if (!value_reader
.PopUint64(&node
->plugged_time
))
418 dbus::ObjectProxy
* cras_proxy_
;
419 ObserverList
<Observer
> observers_
;
421 // Note: This should remain the last member so it'll be destroyed and
422 // invalidate its weak pointers before any other members are destroyed.
423 base::WeakPtrFactory
<CrasAudioClientImpl
> weak_ptr_factory_
;
425 DISALLOW_COPY_AND_ASSIGN(CrasAudioClientImpl
);
428 CrasAudioClient::Observer::~Observer() {
431 void CrasAudioClient::Observer::AudioClientRestarted() {
434 void CrasAudioClient::Observer::OutputMuteChanged(bool mute_on
) {
437 void CrasAudioClient::Observer::InputMuteChanged(bool mute_on
) {
440 void CrasAudioClient::Observer::NodesChanged() {
443 void CrasAudioClient::Observer::ActiveOutputNodeChanged(uint64 node_id
){
446 void CrasAudioClient::Observer::ActiveInputNodeChanged(uint64 node_id
) {
449 CrasAudioClient::CrasAudioClient() {
452 CrasAudioClient::~CrasAudioClient() {
456 CrasAudioClient
* CrasAudioClient::Create() {
457 return new CrasAudioClientImpl();
460 } // namespace chromeos