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 |
index fb1ddf7d6ec09565442cde1013ddaeed52f93150..29b0a068dcf6b840402f790ec67106d46294360c 100644 |
--- a/device/bluetooth/bluetooth_audio_sink_chromeos.cc |
+++ b/device/bluetooth/bluetooth_audio_sink_chromeos.cc |
@@ -4,12 +4,15 @@ |
#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 "chromeos/dbus/dbus_thread_manager.h" |
#include "dbus/message.h" |
@@ -23,6 +26,10 @@ 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; |
@@ -78,24 +85,26 @@ BluetoothAudioSinkChromeOS::BluetoothAudioSinkChromeOS( |
scoped_refptr<device::BluetoothAdapter> adapter) |
: state_(BluetoothAudioSink::STATE_INVALID), |
volume_(BluetoothAudioSink::kInvalidVolume), |
- read_mtu_(nullptr), |
- write_mtu_(nullptr), |
+ read_mtu_(kInvalidReadMtu), |
+ write_mtu_(kInvalidWriteMtu), |
+ read_failed_logged_(false), |
adapter_(adapter), |
weak_ptr_factory_(this) { |
VLOG(1) << "BluetoothAudioSinkChromeOS created"; |
DCHECK(adapter_.get()); |
DCHECK(adapter_->IsPresent()); |
+ DCHECK(DBusThreadManager::IsInitialized()); |
adapter_->AddObserver(this); |
- chromeos::BluetoothMediaClient* media = |
+ BluetoothMediaClient* media = |
DBusThreadManager::Get()->GetBluetoothMediaClient(); |
DCHECK(media); |
media->AddObserver(this); |
- chromeos::BluetoothMediaTransportClient *transport = |
- chromeos::DBusThreadManager::Get()->GetBluetoothMediaTransportClient(); |
+ BluetoothMediaTransportClient* transport = |
+ DBusThreadManager::Get()->GetBluetoothMediaTransportClient(); |
DCHECK(transport); |
transport->AddObserver(this); |
@@ -114,13 +123,13 @@ BluetoothAudioSinkChromeOS::~BluetoothAudioSinkChromeOS() { |
adapter_->RemoveObserver(this); |
- chromeos::BluetoothMediaClient* media = |
+ BluetoothMediaClient* media = |
DBusThreadManager::Get()->GetBluetoothMediaClient(); |
DCHECK(media); |
media->RemoveObserver(this); |
- chromeos::BluetoothMediaTransportClient *transport = |
- chromeos::DBusThreadManager::Get()->GetBluetoothMediaTransportClient(); |
+ BluetoothMediaTransportClient* transport = |
+ DBusThreadManager::Get()->GetBluetoothMediaTransportClient(); |
DCHECK(transport); |
transport->RemoveObserver(this); |
} |
@@ -133,7 +142,7 @@ void BluetoothAudioSinkChromeOS::Unregister( |
if (!DBusThreadManager::IsInitialized()) |
error_callback.Run(BluetoothAudioSink::ERROR_NOT_UNREGISTERED); |
- chromeos::BluetoothMediaClient* media = |
+ BluetoothMediaClient* media = |
DBusThreadManager::Get()->GetBluetoothMediaClient(); |
DCHECK(media); |
@@ -217,7 +226,7 @@ void BluetoothAudioSinkChromeOS::MediaTransportPropertyChanged( |
VLOG(1) << "MediaTransportPropertyChanged: " << property_name; |
// Retrieves the property set of the transport object with |object_path|. |
- chromeos::BluetoothMediaTransportClient::Properties* properties = |
+ BluetoothMediaTransportClient::Properties* properties = |
DBusThreadManager::Get() |
->GetBluetoothMediaTransportClient() |
->GetProperties(object_path); |
@@ -270,6 +279,7 @@ void BluetoothAudioSinkChromeOS::ClearConfiguration( |
const ObjectPath& transport_path) { |
if (transport_path != transport_path_) |
return; |
+ |
VLOG(1) << "ClearConfiguration"; |
StateChanged(BluetoothAudioSink::STATE_DISCONNECTED); |
} |
@@ -309,7 +319,7 @@ void BluetoothAudioSinkChromeOS::Register( |
media_path_ = static_cast<BluetoothAdapterChromeOS*>( |
adapter_.get())->object_path(); |
- chromeos::BluetoothMediaClient* media = |
+ BluetoothMediaClient* media = |
DBusThreadManager::Get()->GetBluetoothMediaClient(); |
DCHECK(media); |
media->RegisterEndpoint( |
@@ -322,17 +332,84 @@ void BluetoothAudioSinkChromeOS::Register( |
weak_ptr_factory_.GetWeakPtr(), error_callback)); |
} |
+void BluetoothAudioSinkChromeOS::OnFileCanReadWithoutBlocking(int fd) { |
+ ReadFromFile(); |
+} |
+ |
+void BluetoothAudioSinkChromeOS::OnFileCanWriteWithoutBlocking(int fd) { |
+ // Do nothing for now. |
+} |
+ |
BluetoothMediaEndpointServiceProvider* |
BluetoothAudioSinkChromeOS::GetEndpointServiceProvider() { |
return media_endpoint_.get(); |
} |
+void BluetoothAudioSinkChromeOS::AcquireFD() { |
+ VLOG(1) << "AcquireFD - transport path: " << transport_path_.value(); |
+ |
+ read_failed_logged_ = false; |
armansito
2015/03/12 03:42:55
I would rename this variable to something like |re
Miao
2015/03/12 22:33:32
Done.
|
+ |
+ DBusThreadManager::Get()->GetBluetoothMediaTransportClient()->Acquire( |
+ transport_path_, |
+ base::Bind(&BluetoothAudioSinkChromeOS::OnAcquireSucceeded, |
+ weak_ptr_factory_.GetWeakPtr()), |
+ base::Bind(&BluetoothAudioSinkChromeOS::OnAcquireFailed, |
+ weak_ptr_factory_.GetWeakPtr())); |
+} |
+ |
+void BluetoothAudioSinkChromeOS::WatchFD() { |
+ DCHECK(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(); |
armansito
2015/03/12 03:42:55
Add a comment here saying that this will close the
Miao
2015/03/12 22:33:32
Done.
|
+} |
+ |
+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_failed_logged_) { |
+ VLOG(1) << "ReadFromFile - failed"; |
+ read_failed_logged_ = true; |
+ } |
+ return; |
+ } |
+ |
+ VLOG(1) << "ReadFromFile - read " << size << " bytes"; |
+ FOR_EACH_OBSERVER(BluetoothAudioSink::Observer, observers_, |
+ BluetoothAudioSinkDataAvailable(this, data_.get(), size)); |
+} |
+ |
void BluetoothAudioSinkChromeOS::StateChanged( |
BluetoothAudioSink::State state) { |
if (state == state_) |
return; |
- VLOG(1) << "StateChnaged: " << StateToString(state); |
+ VLOG(1) << "StateChanged - state: " << StateToString(state); |
switch (state) { |
case BluetoothAudioSink::STATE_INVALID: |
@@ -342,18 +419,13 @@ void BluetoothAudioSinkChromeOS::StateChanged( |
ResetTransport(); |
break; |
case BluetoothAudioSink::STATE_IDLE: |
- // TODO(mcchou): BUG=441581 |
- // Triggered by MediaTransportPropertyChanged and SetConfiguration. |
- // Stop watching on file descriptor if there is one. |
+ StopWatchingFD(); |
break; |
case BluetoothAudioSink::STATE_PENDING: |
- // TODO(mcchou): BUG=441581 |
- // Call BluetoothMediaTransportClient::Acquire() to get fd and mtus. |
+ AcquireFD(); |
break; |
case BluetoothAudioSink::STATE_ACTIVE: |
- // TODO(mcchou): BUG=441581 |
- // Read from fd and call DataAvailable. |
- ReadFromFD(); |
+ WatchFD(); |
break; |
default: |
break; |
@@ -397,7 +469,7 @@ void BluetoothAudioSinkChromeOS::OnRegisterFailed( |
void BluetoothAudioSinkChromeOS::OnUnregisterSucceeded( |
const base::Closure& callback) { |
- VLOG(1) << "Unregisterd"; |
+ VLOG(1) << "Unregisterd - endpoint: " << endpoint_path_.value(); |
armansito
2015/03/12 03:42:55
nit: s/Unregisterd/Unregistered/
Miao
2015/03/12 22:33:32
Done.
|
// Once the state becomes STATE_INVALID, media, media transport and media |
// endpoint will be reset. |
@@ -415,12 +487,51 @@ void BluetoothAudioSinkChromeOS::OnUnregisterFailed( |
error_callback.Run(BluetoothAudioSink::ERROR_NOT_UNREGISTERED); |
} |
-void BluetoothAudioSinkChromeOS::ReadFromFD() { |
- DCHECK_GE(fd_.value(), 0); |
+void BluetoothAudioSinkChromeOS::OnAcquireSucceeded( |
+ const int fd, |
+ const uint16_t read_mtu, |
+ const uint16_t write_mtu) { |
+ DCHECK_GT(fd, kInvalidFd); |
+ DCHECK_GT(read_mtu, kInvalidReadMtu); |
+ DCHECK_GT(write_mtu, kInvalidWriteMtu); |
+ |
+ // Avoids unnecessary memory reallocation if read MTU doesn't change. |
armansito
2015/03/12 03:42:55
Nice!
Miao
2015/03/12 22:33:32
:)
|
+ 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) { |
+ file_.reset(new base::File(fd)); |
+ 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"; |
+} |
- // TODO(mcchou): BUG=441581 |
- // Read from file descriptor using watcher and create a buffer to contain the |
- // data. Notify |Observers_| while there is audio data available. |
+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() { |
@@ -430,15 +541,18 @@ void BluetoothAudioSinkChromeOS::ResetMedia() { |
} |
void BluetoothAudioSinkChromeOS::ResetTransport() { |
- VLOG(1) << "ResetTransport"; |
- |
- if (transport_path_.value() == "") |
+ if (!transport_path_.IsValid()) { |
+ VLOG(1) << "ResetTransport - skip"; |
return; |
- transport_path_ = dbus::ObjectPath(""); |
+ } |
+ |
+ VLOG(1) << "ResetTransport - clean-up"; |
+ |
VolumeChanged(BluetoothAudioSink::kInvalidVolume); |
- read_mtu_ = 0; |
- write_mtu_ = 0; |
- fd_.PutValue(-1); |
+ transport_path_ = dbus::ObjectPath(""); |
+ read_mtu_ = kInvalidReadMtu; |
+ write_mtu_ = kInvalidWriteMtu; |
+ file_.reset(); |
} |
void BluetoothAudioSinkChromeOS::ResetEndpoint() { |