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: 26 CrasAudioClientImpl() : cras_proxy_(NULL), weak_ptr_factory_(this) {} 27 28 virtual ~CrasAudioClientImpl() { 29 } 30 31 // CrasAudioClient overrides: 32 virtual void AddObserver(Observer* observer) OVERRIDE { 33 observers_.AddObserver(observer); 34 } 35 36 virtual void RemoveObserver(Observer* observer) OVERRIDE { 37 observers_.RemoveObserver(observer); 38 } 39 40 virtual bool HasObserver(Observer* observer) OVERRIDE { 41 return observers_.HasObserver(observer); 42 } 43 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 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 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 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 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 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 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 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 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 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 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 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: 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. 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 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. 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. 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 271 void NodesChangedReceived(dbus::Signal* signal) { 272 FOR_EACH_OBSERVER(Observer, observers_, NodesChanged()); 273 } 274 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 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 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 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 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 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 418 CrasAudioClient::Observer::~Observer() { 419 } 420 421 void CrasAudioClient::Observer::AudioClientRestarted() { 422 } 423 424 void CrasAudioClient::Observer::OutputMuteChanged(bool mute_on) { 425 } 426 427 void CrasAudioClient::Observer::InputMuteChanged(bool mute_on) { 428 } 429 430 void CrasAudioClient::Observer::NodesChanged() { 431 } 432 433 void CrasAudioClient::Observer::ActiveOutputNodeChanged(uint64 node_id){ 434 } 435 436 void CrasAudioClient::Observer::ActiveInputNodeChanged(uint64 node_id) { 437 } 438 439 CrasAudioClient::CrasAudioClient() { 440 } 441 442 CrasAudioClient::~CrasAudioClient() { 443 } 444 445 // static 446 CrasAudioClient* CrasAudioClient::Create() { 447 return new CrasAudioClientImpl(); 448 } 449 450 } // namespace chromeos 451