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"
10 #include "chromeos/dbus/cras_audio_client_stub_impl.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"
19 // Error name if cras dbus call fails with empty ErrorResponse.
20 const char kNoResponseError
[] =
21 "org.chromium.cras.Error.NoResponse";
23 // The CrasAudioClient implementation used in production.
24 class CrasAudioClientImpl
: public CrasAudioClient
{
26 CrasAudioClientImpl() : cras_proxy_(NULL
), weak_ptr_factory_(this) {}
28 virtual ~CrasAudioClientImpl() {
31 // CrasAudioClient overrides:
32 virtual void AddObserver(Observer
* observer
) OVERRIDE
{
33 observers_
.AddObserver(observer
);
36 virtual void RemoveObserver(Observer
* observer
) OVERRIDE
{
37 observers_
.RemoveObserver(observer
);
40 virtual bool HasObserver(Observer
* observer
) OVERRIDE
{
41 return observers_
.HasObserver(observer
);
44 virtual void GetVolumeState(const GetVolumeStateCallback
& callback
) OVERRIDE
{
45 dbus::MethodCall
method_call(cras::kCrasControlInterface
,
46 cras::kGetVolumeState
);
47 cras_proxy_
->CallMethod(
49 dbus::ObjectProxy::TIMEOUT_USE_DEFAULT
,
50 base::Bind(&CrasAudioClientImpl::OnGetVolumeState
,
51 weak_ptr_factory_
.GetWeakPtr(), callback
));
54 virtual void GetNodes(const GetNodesCallback
& callback
,
55 const ErrorCallback
& error_callback
) OVERRIDE
{
56 dbus::MethodCall
method_call(cras::kCrasControlInterface
,
58 cras_proxy_
->CallMethodWithErrorCallback(
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
));
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(
75 dbus::ObjectProxy::TIMEOUT_USE_DEFAULT
,
76 dbus::ObjectProxy::EmptyResponseCallback());
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(
86 dbus::ObjectProxy::TIMEOUT_USE_DEFAULT
,
87 dbus::ObjectProxy::EmptyResponseCallback());
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(
98 dbus::ObjectProxy::TIMEOUT_USE_DEFAULT
,
99 dbus::ObjectProxy::EmptyResponseCallback());
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(
109 dbus::ObjectProxy::TIMEOUT_USE_DEFAULT
,
110 dbus::ObjectProxy::EmptyResponseCallback());
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(
120 dbus::ObjectProxy::TIMEOUT_USE_DEFAULT
,
121 dbus::ObjectProxy::EmptyResponseCallback());
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(
131 dbus::ObjectProxy::TIMEOUT_USE_DEFAULT
,
132 dbus::ObjectProxy::EmptyResponseCallback());
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(
142 dbus::ObjectProxy::TIMEOUT_USE_DEFAULT
,
143 dbus::ObjectProxy::EmptyResponseCallback());
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(
153 dbus::ObjectProxy::TIMEOUT_USE_DEFAULT
,
154 dbus::ObjectProxy::EmptyResponseCallback());
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());
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());
178 virtual void Init(dbus::Bus
* bus
) OVERRIDE
{
179 cras_proxy_
= bus
->GetObjectProxy(cras::kCrasServiceName
,
180 dbus::ObjectPath(cras::kCrasServicePath
));
182 // Monitor NameOwnerChanged signal.
183 cras_proxy_
->SetNameOwnerChangedCallback(
184 base::Bind(&CrasAudioClientImpl::NameOwnerChangedReceived
,
185 weak_ptr_factory_
.GetWeakPtr()));
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()));
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()));
205 // Monitor the D-Bus signal for nodes change.
206 cras_proxy_
->ConnectToSignal(
207 cras::kCrasControlInterface
,
209 base::Bind(&CrasAudioClientImpl::NodesChangedReceived
,
210 weak_ptr_factory_
.GetWeakPtr()),
211 base::Bind(&CrasAudioClientImpl::SignalConnected
,
212 weak_ptr_factory_
.GetWeakPtr()));
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()));
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()));
234 // Called when the cras signal is initially connected.
235 void SignalConnected(const std::string
& interface_name
,
236 const std::string
& signal_name
,
238 LOG_IF(ERROR
, !success
)
239 << "Failed to connect to cras signal:" << signal_name
;
242 void NameOwnerChangedReceived(const std::string
& old_owner
,
243 const std::string
& new_owner
) {
244 FOR_EACH_OBSERVER(Observer
, observers_
, AudioClientRestarted());
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();
257 FOR_EACH_OBSERVER(Observer
, observers_
, OutputMuteChanged(user_mute
));
260 // Called when a InputMuteChanged signal is received.
261 void InputMuteChangedReceived(dbus::Signal
* signal
) {
262 dbus::MessageReader
reader(signal
);
264 if (!reader
.PopBool(&mute
)) {
265 LOG(ERROR
) << "Error reading signal from cras:"
266 << signal
->ToString();
268 FOR_EACH_OBSERVER(Observer
, observers_
, InputMuteChanged(mute
));
271 void NodesChangedReceived(dbus::Signal
* signal
) {
272 FOR_EACH_OBSERVER(Observer
, observers_
, NodesChanged());
275 void ActiveOutputNodeChangedReceived(dbus::Signal
* signal
) {
276 dbus::MessageReader
reader(signal
);
278 if (!reader
.PopUint64(&node_id
)) {
279 LOG(ERROR
) << "Error reading signal from cras:"
280 << signal
->ToString();
282 FOR_EACH_OBSERVER(Observer
, observers_
, ActiveOutputNodeChanged(node_id
));
285 void ActiveInputNodeChangedReceived(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_
, ActiveInputNodeChanged(node_id
));
295 void OnGetVolumeState(const GetVolumeStateCallback
& callback
,
296 dbus::Response
* response
) {
298 VolumeState volume_state
;
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
)) {
307 LOG(ERROR
) << "Error reading response from cras: "
308 << response
->ToString();
312 LOG(ERROR
) << "Error calling " << cras::kGetVolumeState
;
315 callback
.Run(volume_state
, success
);
318 void OnGetNodes(const GetNodesCallback
& callback
,
319 dbus::Response
* response
) {
321 AudioNodeList node_list
;
323 dbus::MessageReader
response_reader(response
);
324 dbus::MessageReader
array_reader(response
);
325 while (response_reader
.HasMoreData()) {
326 if (!response_reader
.PopArray(&array_reader
)) {
328 LOG(ERROR
) << "Error reading response from cras: "
329 << response
->ToString();
334 if (!GetAudioNode(response
, &array_reader
, &node
)) {
336 LOG(WARNING
) << "Error reading audio node data from cras: "
337 << response
->ToString();
340 // Filter out the "UNKNOWN" type of audio devices.
341 if (node
.type
!= "UNKNOWN")
342 node_list
.push_back(node
);
346 if (node_list
.empty())
349 callback
.Run(node_list
, success
);
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
;
358 dbus::MessageReader
reader(response
);
359 error_name
= response
->GetErrorName();
360 reader
.PopString(&error_message
);
362 error_name
= kNoResponseError
;
365 error_callback
.Run(error_name
, error_message
);
368 bool GetAudioNode(dbus::Response
* response
,
369 dbus::MessageReader
* array_reader
,
371 while (array_reader
->HasMoreData()) {
372 dbus::MessageReader
dict_entry_reader(response
);
373 dbus::MessageReader
value_reader(response
);
375 if (!array_reader
->PopDictEntry(&dict_entry_reader
) ||
376 !dict_entry_reader
.PopString(&key
) ||
377 !dict_entry_reader
.PopVariant(&value_reader
)) {
381 if (key
== cras::kIsInputProperty
) {
382 if (!value_reader
.PopBool(&node
->is_input
))
384 } else if (key
== cras::kIdProperty
) {
385 if (!value_reader
.PopUint64(&node
->id
))
387 } else if (key
== cras::kDeviceNameProperty
) {
388 if (!value_reader
.PopString(&node
->device_name
))
390 } else if (key
== cras::kTypeProperty
) {
391 if (!value_reader
.PopString(&node
->type
))
393 } else if (key
== cras::kNameProperty
) {
394 if (!value_reader
.PopString(&node
->name
))
396 } else if (key
== cras::kActiveProperty
) {
397 if (!value_reader
.PopBool(&node
->active
))
399 } else if (key
== cras::kPluggedTimeProperty
) {
400 if (!value_reader
.PopUint64(&node
->plugged_time
))
408 dbus::ObjectProxy
* cras_proxy_
;
409 ObserverList
<Observer
> observers_
;
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_
;
415 DISALLOW_COPY_AND_ASSIGN(CrasAudioClientImpl
);
418 CrasAudioClient::Observer::~Observer() {
421 void CrasAudioClient::Observer::AudioClientRestarted() {
424 void CrasAudioClient::Observer::OutputMuteChanged(bool mute_on
) {
427 void CrasAudioClient::Observer::InputMuteChanged(bool mute_on
) {
430 void CrasAudioClient::Observer::NodesChanged() {
433 void CrasAudioClient::Observer::ActiveOutputNodeChanged(uint64 node_id
){
436 void CrasAudioClient::Observer::ActiveInputNodeChanged(uint64 node_id
) {
439 CrasAudioClient::CrasAudioClient() {
442 CrasAudioClient::~CrasAudioClient() {
446 CrasAudioClient
* CrasAudioClient::Create() {
447 return new CrasAudioClientImpl();
450 } // namespace chromeos