// Copyright 2014 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #include "device/bluetooth/dbus/bluetooth_media_transport_client.h" #include "base/bind.h" #include "base/logging.h" #include "base/macros.h" #include "base/memory/ref_counted.h" #include "base/observer_list.h" #include "dbus/bus.h" #include "dbus/message.h" #include "dbus/object_manager.h" #include "dbus/object_proxy.h" #include "third_party/cros_system_api/dbus/service_constants.h" namespace { // TODO(mcchou): Add these service constants into dbus/service_constants.h // later. const char kBluetoothMediaTransportInterface[] = "org.bluez.MediaTransport1"; // Constants used to indicate exceptional error conditions. const char kNoResponseError[] = "org.chromium.Error.NoResponse"; const char kUnexpectedResponse[] = "org.chromium.Error.UnexpectedResponse"; // Method names of Media Transport interface. const char kAcquire[] = "Acquire"; const char kTryAcquire[] = "TryAcquire"; const char kRelease[] = "Release"; } // namespace namespace bluez { // static const char BluetoothMediaTransportClient::kDeviceProperty[] = "Device"; const char BluetoothMediaTransportClient::kUUIDProperty[] = "UUID"; const char BluetoothMediaTransportClient::kCodecProperty[] = "Codec"; const char BluetoothMediaTransportClient::kConfigurationProperty[] = "Configuration"; const char BluetoothMediaTransportClient::kStateProperty[] = "State"; const char BluetoothMediaTransportClient::kDelayProperty[] = "Delay"; const char BluetoothMediaTransportClient::kVolumeProperty[] = "Volume"; // static const char BluetoothMediaTransportClient::kStateIdle[] = "idle"; const char BluetoothMediaTransportClient::kStatePending[] = "pending"; const char BluetoothMediaTransportClient::kStateActive[] = "active"; BluetoothMediaTransportClient::Properties::Properties( dbus::ObjectProxy* object_proxy, const std::string& interface_name, const PropertyChangedCallback& callback) : dbus::PropertySet(object_proxy, interface_name, callback) { RegisterProperty(kDeviceProperty, &device); RegisterProperty(kUUIDProperty, &uuid); RegisterProperty(kCodecProperty, &codec); RegisterProperty(kConfigurationProperty, &configuration); RegisterProperty(kStateProperty, &state); RegisterProperty(kDelayProperty, &delay); RegisterProperty(kVolumeProperty, &volume); } BluetoothMediaTransportClient::Properties::~Properties() {} class BluetoothMediaTransportClientImpl : public BluetoothMediaTransportClient, public dbus::ObjectManager::Interface { public: BluetoothMediaTransportClientImpl() : object_manager_(nullptr), weak_ptr_factory_(this) {} ~BluetoothMediaTransportClientImpl() override { object_manager_->UnregisterInterface(kBluetoothMediaTransportInterface); } // dbus::ObjectManager::Interface overrides. dbus::PropertySet* CreateProperties( dbus::ObjectProxy* object_proxy, const dbus::ObjectPath& object_path, const std::string& interface_name) override { Properties* properties = new Properties( object_proxy, interface_name, base::Bind(&BluetoothMediaTransportClientImpl::OnPropertyChanged, weak_ptr_factory_.GetWeakPtr(), object_path)); return properties; } void ObjectAdded(const dbus::ObjectPath& object_path, const std::string& interface_name) override { VLOG(1) << "Remote Media Transport added: " << object_path.value(); FOR_EACH_OBSERVER(BluetoothMediaTransportClient::Observer, observers_, MediaTransportAdded(object_path)); } void ObjectRemoved(const dbus::ObjectPath& object_path, const std::string& interface_name) override { VLOG(1) << "Remote Media Transport removed: " << object_path.value(); FOR_EACH_OBSERVER(BluetoothMediaTransportClient::Observer, observers_, MediaTransportRemoved(object_path)); } // BluetoothMediaTransportClient overrides. void AddObserver(BluetoothMediaTransportClient::Observer* observer) override { DCHECK(observer); observers_.AddObserver(observer); } void RemoveObserver( BluetoothMediaTransportClient::Observer* observer) override { DCHECK(observer); observers_.RemoveObserver(observer); } Properties* GetProperties(const dbus::ObjectPath& object_path) override { DCHECK(object_manager_); return static_cast(object_manager_->GetProperties( object_path, kBluetoothMediaTransportInterface)); } void Acquire(const dbus::ObjectPath& object_path, const AcquireCallback& callback, const ErrorCallback& error_callback) override { VLOG(1) << "Acquire - transport: " << object_path.value(); DCHECK(object_manager_); dbus::MethodCall method_call(kBluetoothMediaTransportInterface, kAcquire); // Get object proxy. scoped_refptr object_proxy( object_manager_->GetObjectProxy(object_path)); // Call Acquire method of Media Transport interface. object_proxy->CallMethodWithErrorCallback( &method_call, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT, base::Bind(&BluetoothMediaTransportClientImpl::OnAcquireSuccess, weak_ptr_factory_.GetWeakPtr(), callback, error_callback), base::Bind(&BluetoothMediaTransportClientImpl::OnError, weak_ptr_factory_.GetWeakPtr(), error_callback)); } void TryAcquire(const dbus::ObjectPath& object_path, const AcquireCallback& callback, const ErrorCallback& error_callback) override { VLOG(1) << "TryAcquire - transport: " << object_path.value(); DCHECK(object_manager_); dbus::MethodCall method_call(kBluetoothMediaTransportInterface, kTryAcquire); // Get object proxy. scoped_refptr object_proxy( object_manager_->GetObjectProxy(object_path)); // Call TryAcquire method of Media Transport interface. object_proxy->CallMethodWithErrorCallback( &method_call, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT, base::Bind(&BluetoothMediaTransportClientImpl::OnAcquireSuccess, weak_ptr_factory_.GetWeakPtr(), callback, error_callback), base::Bind(&BluetoothMediaTransportClientImpl::OnError, weak_ptr_factory_.GetWeakPtr(), error_callback)); } void Release(const dbus::ObjectPath& object_path, const base::Closure& callback, const ErrorCallback& error_callback) override { VLOG(1) << "Release - transport: " << object_path.value(); DCHECK(object_manager_); dbus::MethodCall method_call(kBluetoothMediaTransportInterface, kRelease); // Get object proxy. scoped_refptr object_proxy( object_manager_->GetObjectProxy(object_path)); // Call TryAcquire method of Media Transport interface. object_proxy->CallMethodWithErrorCallback( &method_call, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT, base::Bind(&BluetoothMediaTransportClientImpl::OnSuccess, weak_ptr_factory_.GetWeakPtr(), callback), base::Bind(&BluetoothMediaTransportClientImpl::OnError, weak_ptr_factory_.GetWeakPtr(), error_callback)); } protected: void Init(dbus::Bus* bus) override { DCHECK(bus); object_manager_ = bus->GetObjectManager( bluetooth_object_manager::kBluetoothObjectManagerServiceName, dbus::ObjectPath( bluetooth_object_manager::kBluetoothObjectManagerServicePath)); object_manager_->RegisterInterface(kBluetoothMediaTransportInterface, this); } private: // Called by dbus::PropertySet when a property value is changed. void OnPropertyChanged(const dbus::ObjectPath& object_path, const std::string& property_name) { VLOG(1) << "Name of the changed property: " << property_name; // Dispatches the change to the corresponding property-changed handler. FOR_EACH_OBSERVER( BluetoothMediaTransportClient::Observer, observers_, MediaTransportPropertyChanged(object_path, property_name)); } // Called when a response for successful method call is received. void OnSuccess(const base::Closure& callback, dbus::Response* response) { DCHECK(response); callback.Run(); } // Called when a response for |Acquire|/|TryAcquire| method call is received. void OnAcquireSuccess(const AcquireCallback& callback, const ErrorCallback& error_callback, dbus::Response* response) { DCHECK(response); dbus::FileDescriptor fd; uint16_t read_mtu; uint16_t write_mtu; // Parse the response. dbus::MessageReader reader(response); if (reader.PopFileDescriptor(&fd) && reader.PopUint16(&read_mtu) && reader.PopUint16(&write_mtu)) { fd.CheckValidity(); DCHECK(fd.is_valid()); VLOG(1) << "OnAcquireSuccess - fd: " << fd.value() << ", read MTU: " << read_mtu << ", write MTU: " << write_mtu; // The ownership of the file descriptor is transferred to the user // application. callback.Run(&fd, read_mtu, write_mtu); return; } error_callback.Run( kUnexpectedResponse, "Failed to retrieve file descriptor, read MTU and write MTU."); } // Called when a response for a failed method call is received. void OnError(const ErrorCallback& error_callback, dbus::ErrorResponse* response) { DCHECK(response); // Error response has optional error message argument. std::string error_name; std::string error_message; if (response) { dbus::MessageReader reader(response); error_name = response->GetErrorName(); reader.PopString(&error_message); } else { error_name = kNoResponseError; } error_callback.Run(error_name, error_message); } dbus::ObjectManager* object_manager_; // List of observers interested in event notifications from us. base::ObserverList observers_; base::WeakPtrFactory weak_ptr_factory_; DISALLOW_COPY_AND_ASSIGN(BluetoothMediaTransportClientImpl); }; BluetoothMediaTransportClient::BluetoothMediaTransportClient() {} BluetoothMediaTransportClient::~BluetoothMediaTransportClient() {} BluetoothMediaTransportClient* BluetoothMediaTransportClient::Create() { return new BluetoothMediaTransportClientImpl(); } } // namespace bluez