Updating trunk VERSION from 2139.0 to 2140.0
[chromium-blink-merge.git] / chromeos / dbus / cras_audio_client.cc
blobaa22c96b0e6a83a8313cebabb6bcf39d7ae28270
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"
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"
17 namespace chromeos {
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 {
25 public:
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(
48 &method_call,
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,
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));
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());
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());
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());
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());
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());
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());
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());
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());
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());
177 protected:
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,
208 cras::kNodesChanged,
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()));
233 private:
234 // Called when the cras signal is initially connected.
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;
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);
263 bool mute;
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);
277 uint64 node_id;
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);
287 uint64 node_id;
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) {
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();
310 } else {
311 success = false;
312 LOG(ERROR) << "Error calling " << cras::kGetVolumeState;
315 callback.Run(volume_state, success);
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;
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;
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())
347 return;
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;
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 = "";
365 error_callback.Run(error_name, error_message);
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;
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;
405 return true;
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() {
445 // static
446 CrasAudioClient* CrasAudioClient::Create() {
447 return new CrasAudioClientImpl();
450 } // namespace chromeos