Commit 3b017562 authored by rpaquay@chromium.org's avatar rpaquay@chromium.org

MacOS implementation of BluetoothSocket.

BUG=343725,343651

Review URL: https://codereview.chromium.org/229463003

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@263018 0039d316-1c4b-4281-b951-d872f2087c98
parent 0e343eda
...@@ -265,7 +265,7 @@ void BluetoothAdapterMac::UpdateDevices(NSArray* devices) { ...@@ -265,7 +265,7 @@ void BluetoothAdapterMac::UpdateDevices(NSArray* devices) {
for (IOBluetoothDevice* device in devices) { for (IOBluetoothDevice* device in devices) {
std::string device_address = std::string device_address =
base::SysNSStringToUTF8([device addressString]); base::SysNSStringToUTF8([device addressString]);
devices_[device_address] = new BluetoothDeviceMac(device); devices_[device_address] = new BluetoothDeviceMac(ui_task_runner_, device);
} }
} }
...@@ -290,7 +290,8 @@ void BluetoothAdapterMac::DeviceFound(IOBluetoothDeviceInquiry* inquiry, ...@@ -290,7 +290,8 @@ void BluetoothAdapterMac::DeviceFound(IOBluetoothDeviceInquiry* inquiry,
DCHECK(device_inquiry_ == inquiry); DCHECK(device_inquiry_ == inquiry);
std::string device_address = base::SysNSStringToUTF8([device addressString]); std::string device_address = base::SysNSStringToUTF8([device addressString]);
if (discovered_devices_.find(device_address) == discovered_devices_.end()) { if (discovered_devices_.find(device_address) == discovered_devices_.end()) {
scoped_ptr<BluetoothDeviceMac> device_mac(new BluetoothDeviceMac(device)); scoped_ptr<BluetoothDeviceMac> device_mac(
new BluetoothDeviceMac(ui_task_runner_, device));
FOR_EACH_OBSERVER(BluetoothAdapter::Observer, observers_, FOR_EACH_OBSERVER(BluetoothAdapter::Observer, observers_,
DeviceAdded(this, device_mac.get())); DeviceAdded(this, device_mac.get()));
discovered_devices_.insert(device_address); discovered_devices_.insert(device_address);
......
...@@ -17,11 +17,17 @@ ...@@ -17,11 +17,17 @@
class IOBluetoothDevice; class IOBluetoothDevice;
#endif #endif
namespace base {
class SequencedTaskRunner;
} // namespace base
namespace device { namespace device {
class BluetoothDeviceMac : public BluetoothDevice { class BluetoothDeviceMac : public BluetoothDevice {
public: public:
explicit BluetoothDeviceMac(IOBluetoothDevice* device); explicit BluetoothDeviceMac(
const scoped_refptr<base::SequencedTaskRunner>& ui_task_runner,
IOBluetoothDevice* device);
virtual ~BluetoothDeviceMac(); virtual ~BluetoothDeviceMac();
// BluetoothDevice override // BluetoothDevice override
...@@ -81,6 +87,8 @@ class BluetoothDeviceMac : public BluetoothDevice { ...@@ -81,6 +87,8 @@ class BluetoothDeviceMac : public BluetoothDevice {
// List of observers interested in event notifications from us. // List of observers interested in event notifications from us.
ObserverList<Observer> observers_; ObserverList<Observer> observers_;
scoped_refptr<base::SequencedTaskRunner> ui_task_runner_;
// (retained)
IOBluetoothDevice* device_; IOBluetoothDevice* device_;
DISALLOW_COPY_AND_ASSIGN(BluetoothDeviceMac); DISALLOW_COPY_AND_ASSIGN(BluetoothDeviceMac);
......
...@@ -13,6 +13,7 @@ ...@@ -13,6 +13,7 @@
#include "base/basictypes.h" #include "base/basictypes.h"
#include "base/hash.h" #include "base/hash.h"
#include "base/sequenced_task_runner.h"
#include "base/strings/string_number_conversions.h" #include "base/strings/string_number_conversions.h"
#include "base/strings/stringprintf.h" #include "base/strings/stringprintf.h"
#include "base/strings/sys_string_conversions.h" #include "base/strings/sys_string_conversions.h"
...@@ -36,8 +37,6 @@ ...@@ -36,8 +37,6 @@
namespace { namespace {
const char kFailedToConnect[] = "Connection failed";
// Converts |uuid| to a IOBluetoothSDPUUID instance. // Converts |uuid| to a IOBluetoothSDPUUID instance.
// //
// |uuid| must be in the format of XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX. // |uuid| must be in the format of XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX.
...@@ -64,9 +63,12 @@ IOBluetoothSDPUUID* GetIOBluetoothSDPUUID(const std::string& uuid) { ...@@ -64,9 +63,12 @@ IOBluetoothSDPUUID* GetIOBluetoothSDPUUID(const std::string& uuid) {
namespace device { namespace device {
BluetoothDeviceMac::BluetoothDeviceMac(IOBluetoothDevice* device) BluetoothDeviceMac::BluetoothDeviceMac(
: BluetoothDevice(), device_([device retain]) { const scoped_refptr<base::SequencedTaskRunner>& ui_task_runner,
} IOBluetoothDevice* device)
: BluetoothDevice(),
ui_task_runner_(ui_task_runner),
device_([device retain]) {}
BluetoothDeviceMac::~BluetoothDeviceMac() { BluetoothDeviceMac::~BluetoothDeviceMac() {
[device_ release]; [device_ release];
...@@ -199,9 +201,8 @@ void BluetoothDeviceMac::ConnectToService( ...@@ -199,9 +201,8 @@ void BluetoothDeviceMac::ConnectToService(
[device_ getServiceRecordForUUID:GetIOBluetoothSDPUUID( [device_ getServiceRecordForUUID:GetIOBluetoothSDPUUID(
service_uuid.canonical_value())]; service_uuid.canonical_value())];
if (record != nil) { if (record != nil) {
BluetoothServiceRecordMac service_record(record);
scoped_refptr<BluetoothSocket> socket( scoped_refptr<BluetoothSocket> socket(
BluetoothSocketMac::CreateBluetoothSocket(service_record)); BluetoothSocketMac::CreateBluetoothSocket(ui_task_runner_, record));
if (socket.get() != NULL) if (socket.get() != NULL)
callback.Run(socket); callback.Run(socket);
} }
...@@ -211,10 +212,9 @@ void BluetoothDeviceMac::ConnectToProfile( ...@@ -211,10 +212,9 @@ void BluetoothDeviceMac::ConnectToProfile(
BluetoothProfile* profile, BluetoothProfile* profile,
const base::Closure& callback, const base::Closure& callback,
const ConnectToProfileErrorCallback& error_callback) { const ConnectToProfileErrorCallback& error_callback) {
if (static_cast<BluetoothProfileMac*>(profile)->Connect(device_)) DCHECK(ui_task_runner_->RunsTasksOnCurrentThread());
callback.Run(); static_cast<BluetoothProfileMac*>(profile)
else ->Connect(ui_task_runner_, device_, callback, error_callback);
error_callback.Run(kFailedToConnect);
} }
void BluetoothDeviceMac::SetOutOfBandPairingData( void BluetoothDeviceMac::SetOutOfBandPairingData(
......
...@@ -18,6 +18,10 @@ ...@@ -18,6 +18,10 @@
class IOBluetoothDevice; class IOBluetoothDevice;
#endif #endif
namespace base {
class SequencedTaskRunner;
} // namespace base
namespace device { namespace device {
class BluetoothProfileMac : public BluetoothProfile { class BluetoothProfileMac : public BluetoothProfile {
...@@ -27,10 +31,15 @@ class BluetoothProfileMac : public BluetoothProfile { ...@@ -27,10 +31,15 @@ class BluetoothProfileMac : public BluetoothProfile {
virtual void SetConnectionCallback( virtual void SetConnectionCallback(
const ConnectionCallback& callback) OVERRIDE; const ConnectionCallback& callback) OVERRIDE;
// Makes an outgoing connection to |device|. typedef base::Callback<void(const std::string&)> ErrorCallback;
// This method runs |socket_callback_| with the socket and returns true if the
// connection is made successfully. // Makes an outgoing connection to |device|, calling |callback| on succes or
bool Connect(IOBluetoothDevice* device); // |error_callback| on error. If successful, this method also calls
// |connection_callback_| before calling |callback|.
void Connect(const scoped_refptr<base::SequencedTaskRunner>& ui_task_runner,
IOBluetoothDevice* device,
const base::Closure& callback,
const ErrorCallback& error_callback);
private: private:
friend BluetoothProfile; friend BluetoothProfile;
......
...@@ -12,14 +12,32 @@ ...@@ -12,14 +12,32 @@
#include <vector> #include <vector>
#include "base/basictypes.h" #include "base/basictypes.h"
#include "base/bind.h"
#include "base/location.h"
#include "base/logging.h" #include "base/logging.h"
#include "base/memory/ref_counted.h" #include "base/memory/ref_counted.h"
#include "base/strings/string_number_conversions.h" #include "base/strings/string_number_conversions.h"
#include "base/strings/sys_string_conversions.h"
#include "base/thread_task_runner_handle.h"
#include "device/bluetooth/bluetooth_adapter_factory.h"
#include "device/bluetooth/bluetooth_device_mac.h" #include "device/bluetooth/bluetooth_device_mac.h"
#include "device/bluetooth/bluetooth_socket_mac.h" #include "device/bluetooth/bluetooth_socket_mac.h"
// Replicate specific 10.7 SDK declarations for building with prior SDKs.
#if !defined(MAC_OS_X_VERSION_10_7) || \
MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_7
@interface IOBluetoothDevice (LionSDKDeclarations)
- (NSString*)addressString;
@end
#endif // MAC_OS_X_VERSION_10_7
namespace { namespace {
const char kNoConnectionCallback[] = "Connection callback not set";
const char kProfileNotFound[] = "Profile not found";
// Converts |uuid| to a IOBluetoothSDPUUID instance. // Converts |uuid| to a IOBluetoothSDPUUID instance.
// //
// |uuid| must be in the format of XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX. // |uuid| must be in the format of XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX.
...@@ -42,6 +60,54 @@ IOBluetoothSDPUUID* GetIOBluetoothSDPUUID(const std::string& uuid) { ...@@ -42,6 +60,54 @@ IOBluetoothSDPUUID* GetIOBluetoothSDPUUID(const std::string& uuid) {
length:uuid_bytes_vector.size()]; length:uuid_bytes_vector.size()];
} }
void OnSocketConnectUI(
scoped_refptr<base::SequencedTaskRunner> ui_task_runner,
scoped_refptr<device::BluetoothSocketMac> socket,
const base::Closure& success_callback,
const device::BluetoothProfileMac::ErrorCallback& error_callback) {
DCHECK(ui_task_runner->RunsTasksOnCurrentThread());
socket->Connect(success_callback, error_callback);
}
void OnConnectSuccessUIWithAdapter(
scoped_refptr<base::SequencedTaskRunner> ui_task_runner,
const base::Closure& callback,
const device::BluetoothProfileMac::ConnectionCallback& connection_callback,
const std::string& device_address,
scoped_refptr<device::BluetoothSocketMac> socket,
scoped_refptr<device::BluetoothAdapter> adapter) {
DCHECK(ui_task_runner->RunsTasksOnCurrentThread());
const device::BluetoothDevice* device = adapter->GetDevice(device_address);
if (device) {
connection_callback.Run(device, socket);
callback.Run();
}
}
void OnConnectSuccessUI(
scoped_refptr<base::SequencedTaskRunner> ui_task_runner,
const base::Closure& callback,
const device::BluetoothProfileMac::ConnectionCallback& connection_callback,
const std::string& device_address,
scoped_refptr<device::BluetoothSocketMac> socket) {
DCHECK(ui_task_runner->RunsTasksOnCurrentThread());
device::BluetoothAdapterFactory::GetAdapter(
base::Bind(&OnConnectSuccessUIWithAdapter,
ui_task_runner,
callback,
connection_callback,
device_address,
socket));
}
void OnConnectErrorUI(
scoped_refptr<base::SequencedTaskRunner> ui_task_runner,
const device::BluetoothProfileMac::ErrorCallback& error_callback,
const std::string& error) {
DCHECK(ui_task_runner->RunsTasksOnCurrentThread());
error_callback.Run(error);
}
} // namespace } // namespace
namespace device { namespace device {
...@@ -63,23 +129,37 @@ void BluetoothProfileMac::SetConnectionCallback( ...@@ -63,23 +129,37 @@ void BluetoothProfileMac::SetConnectionCallback(
connection_callback_ = callback; connection_callback_ = callback;
} }
bool BluetoothProfileMac::Connect(IOBluetoothDevice* device) { void BluetoothProfileMac::Connect(
if (connection_callback_.is_null()) const scoped_refptr<base::SequencedTaskRunner>& ui_task_runner,
return false; IOBluetoothDevice* device,
const base::Closure& success_callback,
IOBluetoothSDPServiceRecord* record = const ErrorCallback& error_callback) {
[device getServiceRecordForUUID:GetIOBluetoothSDPUUID( DCHECK(ui_task_runner->RunsTasksOnCurrentThread());
uuid_.canonical_value())]; if (connection_callback_.is_null()) {
if (record != nil) { error_callback.Run(kNoConnectionCallback);
scoped_refptr<BluetoothSocket> socket( return;
BluetoothSocketMac::CreateBluetoothSocket(record));
if (socket.get() != NULL) {
BluetoothDeviceMac device_mac(device);
connection_callback_.Run(&device_mac, socket);
return true;
} }
IOBluetoothSDPServiceRecord* record = [device
getServiceRecordForUUID:GetIOBluetoothSDPUUID(uuid_.canonical_value())];
if (record == nil) {
error_callback.Run(kProfileNotFound);
return;
} }
return false;
std::string device_address = base::SysNSStringToUTF8([device addressString]);
scoped_refptr<BluetoothSocketMac> socket(
BluetoothSocketMac::CreateBluetoothSocket(ui_task_runner, record));
OnSocketConnectUI(
ui_task_runner,
socket,
base::Bind(OnConnectSuccessUI,
ui_task_runner,
success_callback,
connection_callback_,
device_address,
socket),
base::Bind(OnConnectErrorUI, ui_task_runner, error_callback));
} }
} // namespace device } // namespace device
...@@ -5,9 +5,15 @@ ...@@ -5,9 +5,15 @@
#ifndef DEVICE_BLUETOOTH_BLUETOOTH_SOCKET_MAC_H_ #ifndef DEVICE_BLUETOOTH_BLUETOOTH_SOCKET_MAC_H_
#define DEVICE_BLUETOOTH_BLUETOOTH_SOCKET_MAC_H_ #define DEVICE_BLUETOOTH_BLUETOOTH_SOCKET_MAC_H_
#include <queue>
#include <string> #include <string>
#include <IOKit/IOreturn.h>
#include "base/memory/linked_ptr.h"
#include "base/memory/ref_counted.h" #include "base/memory/ref_counted.h"
#include "base/sequenced_task_runner.h"
#include "base/threading/thread_checker.h"
#include "device/bluetooth/bluetooth_socket.h" #include "device/bluetooth/bluetooth_socket.h"
#ifdef __OBJC__ #ifdef __OBJC__
...@@ -21,8 +27,8 @@ class IOBluetoothSDPServiceRecord; ...@@ -21,8 +27,8 @@ class IOBluetoothSDPServiceRecord;
#endif #endif
namespace net { namespace net {
class GrowableIOBuffer;
class IOBuffer; class IOBuffer;
class IOBufferWithSize;
} // namespace net } // namespace net
namespace device { namespace device {
...@@ -30,16 +36,20 @@ namespace device { ...@@ -30,16 +36,20 @@ namespace device {
class BluetoothServiceRecord; class BluetoothServiceRecord;
// This class is an implementation of BluetoothSocket class for OSX platform. // This class is an implementation of BluetoothSocket class for OSX platform.
// All methods of this class must all be called on the UI thread, as per Chrome
// guidelines on performing Async IO on UI thread on MacOS.
class BluetoothSocketMac : public BluetoothSocket { class BluetoothSocketMac : public BluetoothSocket {
public: public:
// TODO(youngki): This method is deprecated; remove this method when static scoped_refptr<BluetoothSocketMac> CreateBluetoothSocket(
// BluetoothServiceRecord is removed. const scoped_refptr<base::SequencedTaskRunner>& ui_task_runner,
static scoped_refptr<BluetoothSocket> CreateBluetoothSocket(
const BluetoothServiceRecord& service_record);
static scoped_refptr<BluetoothSocket> CreateBluetoothSocket(
IOBluetoothSDPServiceRecord* record); IOBluetoothSDPServiceRecord* record);
// Connect to the peer device and calls |success_callback| when the
// connection has been established successfully. If an error occurs, calls
// |error_callback| with a system error message.
void Connect(const base::Closure& success_callback,
const ErrorCompletionCallback& error_callback);
// Overriden from BluetoothSocket: // Overriden from BluetoothSocket:
virtual void Close() OVERRIDE; virtual void Close() OVERRIDE;
virtual void Disconnect(const base::Closure& callback) OVERRIDE; virtual void Disconnect(const base::Closure& callback) OVERRIDE;
...@@ -53,22 +63,77 @@ class BluetoothSocketMac : public BluetoothSocket { ...@@ -53,22 +63,77 @@ class BluetoothSocketMac : public BluetoothSocket {
const ErrorCompletionCallback& error_callback) OVERRIDE; const ErrorCompletionCallback& error_callback) OVERRIDE;
// called by BluetoothRFCOMMChannelDelegate. // called by BluetoothRFCOMMChannelDelegate.
void OnDataReceived(IOBluetoothRFCOMMChannel* rfcomm_channel, void OnChannelOpened(IOBluetoothRFCOMMChannel* rfcomm_channel,
IOReturn status);
// called by BluetoothRFCOMMChannelDelegate.
void OnChannelClosed(IOBluetoothRFCOMMChannel* rfcomm_channel);
// called by BluetoothRFCOMMChannelDelegate.
void OnChannelDataReceived(IOBluetoothRFCOMMChannel* rfcomm_channel,
void* data, void* data,
size_t length); size_t length);
// called by BluetoothRFCOMMChannelDelegate.
void OnChannelWriteComplete(IOBluetoothRFCOMMChannel* rfcomm_channel,
void* refcon,
IOReturn status);
protected: protected:
virtual ~BluetoothSocketMac(); virtual ~BluetoothSocketMac();
private: private:
explicit BluetoothSocketMac(IOBluetoothRFCOMMChannel* rfcomm_channel); BluetoothSocketMac(
const scoped_refptr<base::SequencedTaskRunner>& ui_task_runner,
void ResetIncomingDataBuffer(); IOBluetoothSDPServiceRecord* record);
IOBluetoothRFCOMMChannel* rfcomm_channel_; struct SendRequest {
SendRequest();
~SendRequest();
int buffer_size;
SendCompletionCallback success_callback;
ErrorCompletionCallback error_callback;
IOReturn status;
int active_async_writes;
bool error_signaled;
};
struct ReceiveCallbacks {
ReceiveCallbacks();
~ReceiveCallbacks();
ReceiveCompletionCallback success_callback;
ReceiveErrorCompletionCallback error_callback;
};
struct ConnectCallbacks {
ConnectCallbacks();
~ConnectCallbacks();
base::Closure success_callback;
ErrorCompletionCallback error_callback;
};
void ReleaseChannel();
bool connecting() const { return connect_callbacks_; }
// Used to verify all methods are called on the same thread.
base::ThreadChecker thread_checker_;
// Task Runner for the UI thread, used to post tasks.
scoped_refptr<base::SequencedTaskRunner> ui_task_runner_;
// (retained) The Bluetooth Service definition.
IOBluetoothSDPServiceRecord* record_;
// (weak) The RFCOMM channel delegate. Released when the channel is closed.
BluetoothRFCOMMChannelDelegate* delegate_; BluetoothRFCOMMChannelDelegate* delegate_;
scoped_refptr<net::GrowableIOBuffer> incoming_data_buffer_; // (retained) The IOBluetooth RFCOMM channel used to issue commands.
std::string error_message_; IOBluetoothRFCOMMChannel* rfcomm_channel_;
// Connection callbacks -- when a pending async connection is active.
scoped_ptr<ConnectCallbacks> connect_callbacks_;
// Packets received while there is no pending "receive" callback.
std::queue<scoped_refptr<net::IOBufferWithSize> > receive_queue_;
// Receive callbacks -- when a receive call is active.
scoped_ptr<ReceiveCallbacks> receive_callbacks_;
// Send queue -- one entry per pending send operation.
std::queue<linked_ptr<SendRequest> > send_queue_;
DISALLOW_COPY_AND_ASSIGN(BluetoothSocketMac); DISALLOW_COPY_AND_ASSIGN(BluetoothSocketMac);
}; };
......
This diff is collapsed.
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment