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) {
for (IOBluetoothDevice* device in devices) {
std::string device_address =
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,
DCHECK(device_inquiry_ == inquiry);
std::string device_address = base::SysNSStringToUTF8([device addressString]);
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_,
DeviceAdded(this, device_mac.get()));
discovered_devices_.insert(device_address);
......
......@@ -17,11 +17,17 @@
class IOBluetoothDevice;
#endif
namespace base {
class SequencedTaskRunner;
} // namespace base
namespace device {
class BluetoothDeviceMac : public BluetoothDevice {
public:
explicit BluetoothDeviceMac(IOBluetoothDevice* device);
explicit BluetoothDeviceMac(
const scoped_refptr<base::SequencedTaskRunner>& ui_task_runner,
IOBluetoothDevice* device);
virtual ~BluetoothDeviceMac();
// BluetoothDevice override
......@@ -81,6 +87,8 @@ class BluetoothDeviceMac : public BluetoothDevice {
// List of observers interested in event notifications from us.
ObserverList<Observer> observers_;
scoped_refptr<base::SequencedTaskRunner> ui_task_runner_;
// (retained)
IOBluetoothDevice* device_;
DISALLOW_COPY_AND_ASSIGN(BluetoothDeviceMac);
......
......@@ -13,6 +13,7 @@
#include "base/basictypes.h"
#include "base/hash.h"
#include "base/sequenced_task_runner.h"
#include "base/strings/string_number_conversions.h"
#include "base/strings/stringprintf.h"
#include "base/strings/sys_string_conversions.h"
......@@ -36,8 +37,6 @@
namespace {
const char kFailedToConnect[] = "Connection failed";
// Converts |uuid| to a IOBluetoothSDPUUID instance.
//
// |uuid| must be in the format of XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX.
......@@ -64,9 +63,12 @@ IOBluetoothSDPUUID* GetIOBluetoothSDPUUID(const std::string& uuid) {
namespace device {
BluetoothDeviceMac::BluetoothDeviceMac(IOBluetoothDevice* device)
: BluetoothDevice(), device_([device retain]) {
}
BluetoothDeviceMac::BluetoothDeviceMac(
const scoped_refptr<base::SequencedTaskRunner>& ui_task_runner,
IOBluetoothDevice* device)
: BluetoothDevice(),
ui_task_runner_(ui_task_runner),
device_([device retain]) {}
BluetoothDeviceMac::~BluetoothDeviceMac() {
[device_ release];
......@@ -199,9 +201,8 @@ void BluetoothDeviceMac::ConnectToService(
[device_ getServiceRecordForUUID:GetIOBluetoothSDPUUID(
service_uuid.canonical_value())];
if (record != nil) {
BluetoothServiceRecordMac service_record(record);
scoped_refptr<BluetoothSocket> socket(
BluetoothSocketMac::CreateBluetoothSocket(service_record));
BluetoothSocketMac::CreateBluetoothSocket(ui_task_runner_, record));
if (socket.get() != NULL)
callback.Run(socket);
}
......@@ -211,10 +212,9 @@ void BluetoothDeviceMac::ConnectToProfile(
BluetoothProfile* profile,
const base::Closure& callback,
const ConnectToProfileErrorCallback& error_callback) {
if (static_cast<BluetoothProfileMac*>(profile)->Connect(device_))
callback.Run();
else
error_callback.Run(kFailedToConnect);
DCHECK(ui_task_runner_->RunsTasksOnCurrentThread());
static_cast<BluetoothProfileMac*>(profile)
->Connect(ui_task_runner_, device_, callback, error_callback);
}
void BluetoothDeviceMac::SetOutOfBandPairingData(
......
......@@ -18,6 +18,10 @@
class IOBluetoothDevice;
#endif
namespace base {
class SequencedTaskRunner;
} // namespace base
namespace device {
class BluetoothProfileMac : public BluetoothProfile {
......@@ -27,10 +31,15 @@ class BluetoothProfileMac : public BluetoothProfile {
virtual void SetConnectionCallback(
const ConnectionCallback& callback) OVERRIDE;
// Makes an outgoing connection to |device|.
// This method runs |socket_callback_| with the socket and returns true if the
// connection is made successfully.
bool Connect(IOBluetoothDevice* device);
typedef base::Callback<void(const std::string&)> ErrorCallback;
// Makes an outgoing connection to |device|, calling |callback| on succes or
// |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:
friend BluetoothProfile;
......
......@@ -12,14 +12,32 @@
#include <vector>
#include "base/basictypes.h"
#include "base/bind.h"
#include "base/location.h"
#include "base/logging.h"
#include "base/memory/ref_counted.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_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 {
const char kNoConnectionCallback[] = "Connection callback not set";
const char kProfileNotFound[] = "Profile not found";
// Converts |uuid| to a IOBluetoothSDPUUID instance.
//
// |uuid| must be in the format of XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX.
......@@ -42,6 +60,54 @@ IOBluetoothSDPUUID* GetIOBluetoothSDPUUID(const std::string& uuid) {
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 device {
......@@ -63,23 +129,37 @@ void BluetoothProfileMac::SetConnectionCallback(
connection_callback_ = callback;
}
bool BluetoothProfileMac::Connect(IOBluetoothDevice* device) {
if (connection_callback_.is_null())
return false;
IOBluetoothSDPServiceRecord* record =
[device getServiceRecordForUUID:GetIOBluetoothSDPUUID(
uuid_.canonical_value())];
if (record != nil) {
scoped_refptr<BluetoothSocket> socket(
BluetoothSocketMac::CreateBluetoothSocket(record));
if (socket.get() != NULL) {
BluetoothDeviceMac device_mac(device);
connection_callback_.Run(&device_mac, socket);
return true;
void BluetoothProfileMac::Connect(
const scoped_refptr<base::SequencedTaskRunner>& ui_task_runner,
IOBluetoothDevice* device,
const base::Closure& success_callback,
const ErrorCallback& error_callback) {
DCHECK(ui_task_runner->RunsTasksOnCurrentThread());
if (connection_callback_.is_null()) {
error_callback.Run(kNoConnectionCallback);
return;
}
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
......@@ -5,9 +5,15 @@
#ifndef DEVICE_BLUETOOTH_BLUETOOTH_SOCKET_MAC_H_
#define DEVICE_BLUETOOTH_BLUETOOTH_SOCKET_MAC_H_
#include <queue>
#include <string>
#include <IOKit/IOreturn.h>
#include "base/memory/linked_ptr.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"
#ifdef __OBJC__
......@@ -21,8 +27,8 @@ class IOBluetoothSDPServiceRecord;
#endif
namespace net {
class GrowableIOBuffer;
class IOBuffer;
class IOBufferWithSize;
} // namespace net
namespace device {
......@@ -30,16 +36,20 @@ namespace device {
class BluetoothServiceRecord;
// 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 {
public:
// TODO(youngki): This method is deprecated; remove this method when
// BluetoothServiceRecord is removed.
static scoped_refptr<BluetoothSocket> CreateBluetoothSocket(
const BluetoothServiceRecord& service_record);
static scoped_refptr<BluetoothSocket> CreateBluetoothSocket(
static scoped_refptr<BluetoothSocketMac> CreateBluetoothSocket(
const scoped_refptr<base::SequencedTaskRunner>& ui_task_runner,
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:
virtual void Close() OVERRIDE;
virtual void Disconnect(const base::Closure& callback) OVERRIDE;
......@@ -53,22 +63,77 @@ class BluetoothSocketMac : public BluetoothSocket {
const ErrorCompletionCallback& error_callback) OVERRIDE;
// 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,
size_t length);
// called by BluetoothRFCOMMChannelDelegate.
void OnChannelWriteComplete(IOBluetoothRFCOMMChannel* rfcomm_channel,
void* refcon,
IOReturn status);
protected:
virtual ~BluetoothSocketMac();
private:
explicit BluetoothSocketMac(IOBluetoothRFCOMMChannel* rfcomm_channel);
void ResetIncomingDataBuffer();
BluetoothSocketMac(
const scoped_refptr<base::SequencedTaskRunner>& ui_task_runner,
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_;
scoped_refptr<net::GrowableIOBuffer> incoming_data_buffer_;
std::string error_message_;
// (retained) The IOBluetooth RFCOMM channel used to issue commands.
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);
};
......
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