Index: device/bluetooth/bluetooth_audio_sink_chromeos.cc |
diff --git a/device/bluetooth/bluetooth_audio_sink_chromeos.cc b/device/bluetooth/bluetooth_audio_sink_chromeos.cc |
deleted file mode 100644 |
index 9bb4b601d189d76759ce27ff32662ea5b6894a02..0000000000000000000000000000000000000000 |
--- a/device/bluetooth/bluetooth_audio_sink_chromeos.cc |
+++ /dev/null |
@@ -1,575 +0,0 @@ |
-// Copyright 2015 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/bluetooth_audio_sink_chromeos.h" |
- |
-#include <unistd.h> |
- |
-#include <algorithm> |
-#include <sstream> |
-#include <string> |
-#include <vector> |
- |
-#include "base/debug/stack_trace.h" |
-#include "base/files/file_util.h" |
-#include "base/logging.h" |
-#include "dbus/message.h" |
-#include "device/bluetooth/bluetooth_adapter_chromeos.h" |
-#include "device/bluetooth/dbus/bluez_dbus_manager.h" |
- |
-using dbus::ObjectPath; |
-using device::BluetoothAudioSink; |
- |
-namespace { |
- |
-// TODO(mcchou): Add the constant to dbus/service_constants.h. |
-const char kBluetoothAudioSinkServicePath[] = "/org/chromium/AudioSink"; |
- |
-const int kInvalidFd = -1; |
-const uint16_t kInvalidReadMtu = 0; |
-const uint16_t kInvalidWriteMtu = 0; |
- |
-ObjectPath GenerateEndpointPath() { |
- static unsigned int sequence_number = 0; |
- ++sequence_number; |
- std::stringstream path; |
- path << kBluetoothAudioSinkServicePath << "/endpoint" << sequence_number; |
- return ObjectPath(path.str()); |
-} |
- |
-std::string StateToString(const BluetoothAudioSink::State& state) { |
- switch (state) { |
- case BluetoothAudioSink::STATE_INVALID: |
- return "invalid"; |
- case BluetoothAudioSink::STATE_DISCONNECTED: |
- return "disconnected"; |
- case BluetoothAudioSink::STATE_IDLE: |
- return "idle"; |
- case BluetoothAudioSink::STATE_PENDING: |
- return "pending"; |
- case BluetoothAudioSink::STATE_ACTIVE: |
- return "active"; |
- default: |
- return "unknown"; |
- } |
-} |
- |
-std::string ErrorCodeToString(const BluetoothAudioSink::ErrorCode& error_code) { |
- switch (error_code) { |
- case BluetoothAudioSink::ERROR_UNSUPPORTED_PLATFORM: |
- return "unsupported platform"; |
- case BluetoothAudioSink::ERROR_INVALID_ADAPTER: |
- return "invalid adapter"; |
- case BluetoothAudioSink::ERROR_NOT_REGISTERED: |
- return "not registered"; |
- case BluetoothAudioSink::ERROR_NOT_UNREGISTERED: |
- return "not unregistered"; |
- default: |
- return "unknown"; |
- } |
-} |
- |
-// A dummy error callback for calling Unregister() in destructor. |
-void UnregisterErrorCallback( |
- device::BluetoothAudioSink::ErrorCode error_code) { |
- VLOG(1) << "UnregisterErrorCallback - " << ErrorCodeToString(error_code) |
- << "(" << error_code << ")"; |
-} |
- |
-} // namespace |
- |
-namespace chromeos { |
- |
-BluetoothAudioSinkChromeOS::BluetoothAudioSinkChromeOS( |
- scoped_refptr<device::BluetoothAdapter> adapter) |
- : state_(BluetoothAudioSink::STATE_INVALID), |
- volume_(BluetoothAudioSink::kInvalidVolume), |
- read_mtu_(kInvalidReadMtu), |
- write_mtu_(kInvalidWriteMtu), |
- read_has_failed_(false), |
- adapter_(adapter), |
- weak_ptr_factory_(this) { |
- VLOG(1) << "BluetoothAudioSinkChromeOS created"; |
- |
- CHECK(adapter_.get()); |
- CHECK(adapter_->IsPresent()); |
- CHECK(bluez::BluezDBusManager::IsInitialized()); |
- |
- adapter_->AddObserver(this); |
- |
- bluez::BluetoothMediaClient* media = |
- bluez::BluezDBusManager::Get()->GetBluetoothMediaClient(); |
- CHECK(media); |
- media->AddObserver(this); |
- |
- bluez::BluetoothMediaTransportClient* transport = |
- bluez::BluezDBusManager::Get()->GetBluetoothMediaTransportClient(); |
- CHECK(transport); |
- transport->AddObserver(this); |
- |
- StateChanged(device::BluetoothAudioSink::STATE_DISCONNECTED); |
-} |
- |
-BluetoothAudioSinkChromeOS::~BluetoothAudioSinkChromeOS() { |
- VLOG(1) << "BluetoothAudioSinkChromeOS destroyed"; |
- |
- DCHECK(adapter_.get()); |
- |
- if (state_ != BluetoothAudioSink::STATE_INVALID && media_endpoint_.get()) { |
- Unregister(base::Bind(&base::DoNothing), |
- base::Bind(&UnregisterErrorCallback)); |
- } |
- |
- adapter_->RemoveObserver(this); |
- |
- bluez::BluetoothMediaClient* media = |
- bluez::BluezDBusManager::Get()->GetBluetoothMediaClient(); |
- CHECK(media); |
- media->RemoveObserver(this); |
- |
- bluez::BluetoothMediaTransportClient* transport = |
- bluez::BluezDBusManager::Get()->GetBluetoothMediaTransportClient(); |
- CHECK(transport); |
- transport->RemoveObserver(this); |
-} |
- |
-void BluetoothAudioSinkChromeOS::Unregister( |
- const base::Closure& callback, |
- const device::BluetoothAudioSink::ErrorCallback& error_callback) { |
- VLOG(1) << "Unregister"; |
- |
- if (!bluez::BluezDBusManager::IsInitialized()) |
- error_callback.Run(BluetoothAudioSink::ERROR_NOT_UNREGISTERED); |
- |
- bluez::BluetoothMediaClient* media = |
- bluez::BluezDBusManager::Get()->GetBluetoothMediaClient(); |
- CHECK(media); |
- |
- media->UnregisterEndpoint( |
- media_path_, |
- endpoint_path_, |
- base::Bind(&BluetoothAudioSinkChromeOS::OnUnregisterSucceeded, |
- weak_ptr_factory_.GetWeakPtr(), callback), |
- base::Bind(&BluetoothAudioSinkChromeOS::OnUnregisterFailed, |
- weak_ptr_factory_.GetWeakPtr(), error_callback)); |
-} |
- |
-void BluetoothAudioSinkChromeOS::AddObserver( |
- BluetoothAudioSink::Observer* observer) { |
- CHECK(observer); |
- observers_.AddObserver(observer); |
-} |
- |
-void BluetoothAudioSinkChromeOS::RemoveObserver( |
- BluetoothAudioSink::Observer* observer) { |
- CHECK(observer); |
- observers_.RemoveObserver(observer); |
-} |
- |
-BluetoothAudioSink::State BluetoothAudioSinkChromeOS::GetState() const { |
- return state_; |
-} |
- |
-uint16_t BluetoothAudioSinkChromeOS::GetVolume() const { |
- return volume_; |
-} |
- |
-void BluetoothAudioSinkChromeOS::Register( |
- const BluetoothAudioSink::Options& options, |
- const base::Closure& callback, |
- const BluetoothAudioSink::ErrorCallback& error_callback) { |
- VLOG(1) << "Register"; |
- |
- DCHECK(adapter_.get()); |
- DCHECK_EQ(state_, BluetoothAudioSink::STATE_DISCONNECTED); |
- |
- // Gets system bus. |
- dbus::Bus* system_bus = bluez::BluezDBusManager::Get()->GetSystemBus(); |
- |
- // Creates a Media Endpoint with newly-generated path. |
- endpoint_path_ = GenerateEndpointPath(); |
- media_endpoint_.reset(bluez::BluetoothMediaEndpointServiceProvider::Create( |
- system_bus, endpoint_path_, this)); |
- |
- DCHECK(media_endpoint_.get()); |
- |
- // Creates endpoint properties with |options|. |
- options_ = options; |
- bluez::BluetoothMediaClient::EndpointProperties endpoint_properties; |
- endpoint_properties.uuid = |
- bluez::BluetoothMediaClient::kBluetoothAudioSinkUUID; |
- endpoint_properties.codec = options_.codec; |
- endpoint_properties.capabilities = options_.capabilities; |
- |
- media_path_ = static_cast<BluetoothAdapterChromeOS*>( |
- adapter_.get())->object_path(); |
- |
- bluez::BluetoothMediaClient* media = |
- bluez::BluezDBusManager::Get()->GetBluetoothMediaClient(); |
- CHECK(media); |
- media->RegisterEndpoint( |
- media_path_, |
- endpoint_path_, |
- endpoint_properties, |
- base::Bind(&BluetoothAudioSinkChromeOS::OnRegisterSucceeded, |
- weak_ptr_factory_.GetWeakPtr(), callback), |
- base::Bind(&BluetoothAudioSinkChromeOS::OnRegisterFailed, |
- weak_ptr_factory_.GetWeakPtr(), error_callback)); |
-} |
- |
-bluez::BluetoothMediaEndpointServiceProvider* |
-BluetoothAudioSinkChromeOS::GetEndpointServiceProvider() { |
- return media_endpoint_.get(); |
-} |
- |
-void BluetoothAudioSinkChromeOS::AdapterPresentChanged( |
- device::BluetoothAdapter* adapter, bool present) { |
- VLOG(1) << "AdapterPresentChanged: " << present; |
- |
- if (adapter != adapter_.get()) |
- return; |
- |
- if (adapter->IsPresent()) { |
- StateChanged(BluetoothAudioSink::STATE_DISCONNECTED); |
- } else { |
- adapter_->RemoveObserver(this); |
- StateChanged(BluetoothAudioSink::STATE_INVALID); |
- } |
-} |
- |
-void BluetoothAudioSinkChromeOS::AdapterPoweredChanged( |
- device::BluetoothAdapter* adapter, bool powered) { |
- VLOG(1) << "AdapterPoweredChanged: " << powered; |
- |
- if (adapter != adapter_.get()) |
- return; |
- |
- // Regardless of the new powered state, |state_| goes to STATE_DISCONNECTED. |
- // If false, the transport is closed, but the endpoint is still valid for use. |
- // If true, the previous transport has been torn down, so the |state_| has to |
- // be disconnected before SetConfigruation is called. |
- if (state_ != BluetoothAudioSink::STATE_INVALID) |
- StateChanged(BluetoothAudioSink::STATE_DISCONNECTED); |
-} |
- |
-void BluetoothAudioSinkChromeOS::MediaRemoved(const ObjectPath& object_path) { |
- if (object_path == media_path_) { |
- VLOG(1) << "MediaRemoved: " << object_path.value(); |
- StateChanged(BluetoothAudioSink::STATE_INVALID); |
- } |
-} |
- |
-void BluetoothAudioSinkChromeOS::MediaTransportRemoved( |
- const ObjectPath& object_path) { |
- // Whenever powered of |adapter_| turns false while present stays true, media |
- // transport object should be removed accordingly, and the state should be |
- // changed to STATE_DISCONNECTED. |
- if (object_path == transport_path_) { |
- VLOG(1) << "MediaTransportRemoved: " << object_path.value(); |
- StateChanged(BluetoothAudioSink::STATE_DISCONNECTED); |
- } |
-} |
- |
-void BluetoothAudioSinkChromeOS::MediaTransportPropertyChanged( |
- const ObjectPath& object_path, |
- const std::string& property_name) { |
- if (object_path != transport_path_) |
- return; |
- |
- VLOG(1) << "MediaTransportPropertyChanged: " << property_name; |
- |
- // Retrieves the property set of the transport object with |object_path|. |
- bluez::BluetoothMediaTransportClient::Properties* properties = |
- bluez::BluezDBusManager::Get() |
- ->GetBluetoothMediaTransportClient() |
- ->GetProperties(object_path); |
- |
- // Dispatches a property changed event to the corresponding handler. |
- if (property_name == properties->state.name()) { |
- if (properties->state.value() == |
- bluez::BluetoothMediaTransportClient::kStateIdle) { |
- StateChanged(BluetoothAudioSink::STATE_IDLE); |
- } else if (properties->state.value() == |
- bluez::BluetoothMediaTransportClient::kStatePending) { |
- StateChanged(BluetoothAudioSink::STATE_PENDING); |
- } else if (properties->state.value() == |
- bluez::BluetoothMediaTransportClient::kStateActive) { |
- StateChanged(BluetoothAudioSink::STATE_ACTIVE); |
- } |
- } else if (property_name == properties->volume.name()) { |
- VolumeChanged(properties->volume.value()); |
- } |
-} |
- |
-void BluetoothAudioSinkChromeOS::SetConfiguration( |
- const ObjectPath& transport_path, |
- const TransportProperties& properties) { |
- VLOG(1) << "SetConfiguration"; |
- transport_path_ = transport_path; |
- |
- // The initial state for a connection should be "idle". |
- if (properties.state != bluez::BluetoothMediaTransportClient::kStateIdle) { |
- VLOG(1) << "SetConfiugration - unexpected state :" << properties.state; |
- return; |
- } |
- |
- // Updates |volume_| if the volume level is provided in |properties|. |
- if (properties.volume.get()) { |
- VolumeChanged(*properties.volume); |
- } |
- |
- StateChanged(BluetoothAudioSink::STATE_IDLE); |
-} |
- |
-void BluetoothAudioSinkChromeOS::SelectConfiguration( |
- const std::vector<uint8_t>& capabilities, |
- const SelectConfigurationCallback& callback) { |
- VLOG(1) << "SelectConfiguration"; |
- callback.Run(options_.capabilities); |
-} |
- |
-void BluetoothAudioSinkChromeOS::ClearConfiguration( |
- const ObjectPath& transport_path) { |
- if (transport_path != transport_path_) |
- return; |
- |
- VLOG(1) << "ClearConfiguration"; |
- StateChanged(BluetoothAudioSink::STATE_DISCONNECTED); |
-} |
- |
-void BluetoothAudioSinkChromeOS::Released() { |
- VLOG(1) << "Released"; |
- StateChanged(BluetoothAudioSink::STATE_INVALID); |
-} |
- |
-void BluetoothAudioSinkChromeOS::OnFileCanReadWithoutBlocking(int fd) { |
- ReadFromFile(); |
-} |
- |
-void BluetoothAudioSinkChromeOS::OnFileCanWriteWithoutBlocking(int fd) { |
- // Do nothing for now. |
-} |
- |
-void BluetoothAudioSinkChromeOS::AcquireFD() { |
- VLOG(1) << "AcquireFD - transport path: " << transport_path_.value(); |
- |
- read_has_failed_ = false; |
- |
- bluez::BluezDBusManager::Get()->GetBluetoothMediaTransportClient()->Acquire( |
- transport_path_, |
- base::Bind(&BluetoothAudioSinkChromeOS::OnAcquireSucceeded, |
- weak_ptr_factory_.GetWeakPtr()), |
- base::Bind(&BluetoothAudioSinkChromeOS::OnAcquireFailed, |
- weak_ptr_factory_.GetWeakPtr())); |
-} |
- |
-void BluetoothAudioSinkChromeOS::WatchFD() { |
- CHECK(file_.get() && file_->IsValid()); |
- |
- VLOG(1) << "WatchFD - file: " << file_->GetPlatformFile() |
- << ", file validity: " << file_->IsValid(); |
- |
- base::MessageLoopForIO::current()->WatchFileDescriptor( |
- file_->GetPlatformFile(), true, base::MessageLoopForIO::WATCH_READ, |
- &fd_read_watcher_, this); |
-} |
- |
-void BluetoothAudioSinkChromeOS::StopWatchingFD() { |
- if (!file_.get()) { |
- VLOG(1) << "StopWatchingFD - skip"; |
- return; |
- } |
- |
- bool stopped = fd_read_watcher_.StopWatchingFileDescriptor(); |
- VLOG(1) << "StopWatchingFD - watch stopped: " << stopped; |
- CHECK(stopped); |
- |
- read_mtu_ = kInvalidReadMtu; |
- write_mtu_ = kInvalidWriteMtu; |
- file_.reset(); // This will close the file descriptor. |
-} |
- |
-void BluetoothAudioSinkChromeOS::ReadFromFile() { |
- DCHECK(file_.get() && file_->IsValid()); |
- DCHECK(data_.get()); |
- |
- int size = file_->ReadAtCurrentPosNoBestEffort(data_.get(), read_mtu_); |
- |
- if (size == -1) { |
- // To reduce the number of logs, log only once for multiple failures. |
- if (!read_has_failed_) { |
- VLOG(1) << "ReadFromFile - failed"; |
- read_has_failed_ = true; |
- } |
- return; |
- } |
- |
- VLOG(1) << "ReadFromFile - read " << size << " bytes"; |
- FOR_EACH_OBSERVER( |
- BluetoothAudioSink::Observer, observers_, |
- BluetoothAudioSinkDataAvailable(this, data_.get(), size, read_mtu_)); |
-} |
- |
-void BluetoothAudioSinkChromeOS::StateChanged( |
- BluetoothAudioSink::State state) { |
- if (state == state_) |
- return; |
- |
- VLOG(1) << "StateChanged - state: " << StateToString(state); |
- |
- switch (state) { |
- case BluetoothAudioSink::STATE_INVALID: |
- ResetMedia(); |
- ResetEndpoint(); |
- case BluetoothAudioSink::STATE_DISCONNECTED: |
- ResetTransport(); |
- break; |
- case BluetoothAudioSink::STATE_IDLE: |
- StopWatchingFD(); |
- break; |
- case BluetoothAudioSink::STATE_PENDING: |
- AcquireFD(); |
- break; |
- case BluetoothAudioSink::STATE_ACTIVE: |
- WatchFD(); |
- break; |
- default: |
- break; |
- } |
- |
- state_ = state; |
- FOR_EACH_OBSERVER(BluetoothAudioSink::Observer, observers_, |
- BluetoothAudioSinkStateChanged(this, state_)); |
-} |
- |
-void BluetoothAudioSinkChromeOS::VolumeChanged(uint16_t volume) { |
- if (volume == volume_) |
- return; |
- |
- VLOG(1) << "VolumeChanged: " << volume; |
- |
- volume_ = std::min(volume, BluetoothAudioSink::kInvalidVolume); |
- FOR_EACH_OBSERVER(BluetoothAudioSink::Observer, observers_, |
- BluetoothAudioSinkVolumeChanged(this, volume_)); |
-} |
- |
-void BluetoothAudioSinkChromeOS::OnRegisterSucceeded( |
- const base::Closure& callback) { |
- DCHECK(media_endpoint_.get()); |
- VLOG(1) << "OnRegisterSucceeded"; |
- |
- StateChanged(BluetoothAudioSink::STATE_DISCONNECTED); |
- callback.Run(); |
-} |
- |
-void BluetoothAudioSinkChromeOS::OnRegisterFailed( |
- const BluetoothAudioSink::ErrorCallback& error_callback, |
- const std::string& error_name, |
- const std::string& error_message) { |
- VLOG(1) << "OnRegisterFailed - error name: " << error_name |
- << ", error message: " << error_message; |
- |
- ResetEndpoint(); |
- error_callback.Run(BluetoothAudioSink::ERROR_NOT_REGISTERED); |
-} |
- |
-void BluetoothAudioSinkChromeOS::OnUnregisterSucceeded( |
- const base::Closure& callback) { |
- VLOG(1) << "Unregistered - endpoint: " << endpoint_path_.value(); |
- |
- // Once the state becomes STATE_INVALID, media, media transport and media |
- // endpoint will be reset. |
- StateChanged(BluetoothAudioSink::STATE_INVALID); |
- callback.Run(); |
-} |
- |
-void BluetoothAudioSinkChromeOS::OnUnregisterFailed( |
- const device::BluetoothAudioSink::ErrorCallback& error_callback, |
- const std::string& error_name, |
- const std::string& error_message) { |
- VLOG(1) << "OnUnregisterFailed - error name: " << error_name |
- << ", error message: " << error_message; |
- |
- error_callback.Run(BluetoothAudioSink::ERROR_NOT_UNREGISTERED); |
-} |
- |
-void BluetoothAudioSinkChromeOS::OnAcquireSucceeded( |
- dbus::FileDescriptor* fd, |
- const uint16_t read_mtu, |
- const uint16_t write_mtu) { |
- CHECK(fd); |
- fd->CheckValidity(); |
- CHECK(fd->is_valid() && fd->value() != kInvalidFd); |
- CHECK_GT(read_mtu, kInvalidReadMtu); |
- CHECK_GT(write_mtu, kInvalidWriteMtu); |
- |
- // Avoids unnecessary memory reallocation if read MTU doesn't change. |
- if (read_mtu != read_mtu_) { |
- read_mtu_ = read_mtu; |
- data_.reset(new char[read_mtu_]); |
- VLOG(1) << "OnAcquireSucceeded - allocate " << read_mtu_ |
- << " bytes of memory"; |
- } |
- |
- write_mtu_ = write_mtu; |
- |
- // Avoids closing the same file descriptor caused by reassignment. |
- if (!file_.get() || file_->GetPlatformFile() != fd->value()) { |
- // Takes ownership of the file descriptor. |
- file_.reset(new base::File(fd->TakeValue())); |
- DCHECK(file_->IsValid()); |
- VLOG(1) << "OnAcquireSucceeded - update file"; |
- } |
- |
- VLOG(1) << "OnAcquireSucceeded - file: " << file_->GetPlatformFile() |
- << ", read MTU: " << read_mtu_ << ", write MTU: " << write_mtu_; |
-} |
- |
-void BluetoothAudioSinkChromeOS::OnAcquireFailed( |
- const std::string& error_name, |
- const std::string& error_message) { |
- VLOG(1) << "OnAcquireFailed - error name: " << error_name |
- << ", error message: " << error_message; |
-} |
- |
-void BluetoothAudioSinkChromeOS::OnReleaseFDSucceeded() { |
- VLOG(1) << "OnReleaseFDSucceeded"; |
-} |
- |
-void BluetoothAudioSinkChromeOS::OnReleaseFDFailed( |
- const std::string& error_name, |
- const std::string& error_message) { |
- VLOG(1) << "OnReleaseFDFailed - error name: " << error_name |
- << ", error message: " << error_message; |
-} |
- |
-void BluetoothAudioSinkChromeOS::ResetMedia() { |
- VLOG(1) << "ResetMedia"; |
- |
- media_path_ = dbus::ObjectPath(""); |
-} |
- |
-void BluetoothAudioSinkChromeOS::ResetTransport() { |
- if (!transport_path_.IsValid()) { |
- VLOG(1) << "ResetTransport - skip"; |
- return; |
- } |
- |
- VLOG(1) << "ResetTransport - clean-up"; |
- |
- VolumeChanged(BluetoothAudioSink::kInvalidVolume); |
- transport_path_ = dbus::ObjectPath(""); |
- read_mtu_ = kInvalidReadMtu; |
- write_mtu_ = kInvalidWriteMtu; |
- file_.reset(); |
-} |
- |
-void BluetoothAudioSinkChromeOS::ResetEndpoint() { |
- VLOG(1) << "ResetEndpoint"; |
- |
- endpoint_path_ = ObjectPath(""); |
- media_endpoint_ = nullptr; |
-} |
- |
-} // namespace chromeos |