| Index: device/bluetooth/bluetooth_rfcomm_channel_mac.mm
|
| diff --git a/device/bluetooth/bluetooth_rfcomm_channel_mac.mm b/device/bluetooth/bluetooth_rfcomm_channel_mac.mm
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..8697ef6e929b2af7a8c597d217efd640686506ff
|
| --- /dev/null
|
| +++ b/device/bluetooth/bluetooth_rfcomm_channel_mac.mm
|
| @@ -0,0 +1,168 @@
|
| +// 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/bluetooth_rfcomm_channel_mac.h"
|
| +
|
| +#include "base/logging.h"
|
| +#include "device/bluetooth/bluetooth_device_mac.h"
|
| +#include "device/bluetooth/bluetooth_socket_mac.h"
|
| +
|
| +// A simple delegate class for an open RFCOMM channel that forwards methods to
|
| +// its wrapped |channel_|.
|
| +@interface BluetoothRfcommChannelDelegate
|
| + : NSObject <IOBluetoothRFCOMMChannelDelegate> {
|
| + @private
|
| + device::BluetoothRfcommChannelMac* channel_; // weak
|
| +}
|
| +
|
| +- (id)initWithChannel:(device::BluetoothRfcommChannelMac*)channel;
|
| +
|
| +@end
|
| +
|
| +@implementation BluetoothRfcommChannelDelegate
|
| +
|
| +- (id)initWithChannel:(device::BluetoothRfcommChannelMac*)channel {
|
| + if ((self = [super init]))
|
| + channel_ = channel;
|
| +
|
| + return self;
|
| +}
|
| +
|
| +- (void)rfcommChannelOpenComplete:(IOBluetoothRFCOMMChannel*)rfcommChannel
|
| + status:(IOReturn)error {
|
| + channel_->OnChannelOpenComplete(rfcommChannel, error);
|
| +}
|
| +
|
| +- (void)rfcommChannelWriteComplete:(IOBluetoothRFCOMMChannel*)rfcommChannel
|
| + refcon:(void*)refcon
|
| + status:(IOReturn)error {
|
| + channel_->OnChannelWriteComplete(rfcommChannel, refcon, error);
|
| +}
|
| +
|
| +- (void)rfcommChannelData:(IOBluetoothRFCOMMChannel*)rfcommChannel
|
| + data:(void*)dataPointer
|
| + length:(size_t)dataLength {
|
| + channel_->OnChannelDataReceived(rfcommChannel, dataPointer, dataLength);
|
| +}
|
| +
|
| +- (void)rfcommChannelClosed:(IOBluetoothRFCOMMChannel*)rfcommChannel {
|
| + channel_->OnChannelClosed(rfcommChannel);
|
| +}
|
| +
|
| +@end
|
| +
|
| +namespace device {
|
| +
|
| +BluetoothRfcommChannelMac::BluetoothRfcommChannelMac(
|
| + BluetoothSocketMac* socket,
|
| + IOBluetoothRFCOMMChannel* channel)
|
| + : channel_(channel),
|
| + delegate_(nil) {
|
| + SetSocket(socket);
|
| +}
|
| +
|
| +BluetoothRfcommChannelMac::~BluetoothRfcommChannelMac() {
|
| + [channel_ setDelegate:nil];
|
| + [channel_ closeChannel];
|
| +}
|
| +
|
| +// static
|
| +scoped_ptr<BluetoothRfcommChannelMac> BluetoothRfcommChannelMac::OpenAsync(
|
| + BluetoothSocketMac* socket,
|
| + IOBluetoothDevice* device,
|
| + uint8 channel_id,
|
| + IOReturn* status) {
|
| + DCHECK(socket);
|
| + scoped_ptr<BluetoothRfcommChannelMac> channel(
|
| + new BluetoothRfcommChannelMac(socket, nil));
|
| +
|
| + // Retain the delegate, because IOBluetoothDevice's
|
| + // |-openRFCOMMChannelAsync:withChannelID:delegate:| assumes that it can take
|
| + // ownership of the delegate without calling |-retain| on it...
|
| + DCHECK(channel->delegate_);
|
| + [channel->delegate_ retain];
|
| + IOBluetoothRFCOMMChannel* rfcomm_channel;
|
| + *status = [device openRFCOMMChannelAsync:&rfcomm_channel
|
| + withChannelID:channel_id
|
| + delegate:channel->delegate_];
|
| + if (*status == kIOReturnSuccess) {
|
| + // Note: No need to retain the |rfcomm_channel| -- the returned channel is
|
| + // already retained.
|
| + channel->channel_.reset(rfcomm_channel);
|
| + } else {
|
| + channel.reset();
|
| + }
|
| +
|
| + return channel.Pass();
|
| +}
|
| +
|
| +void BluetoothRfcommChannelMac::SetSocket(BluetoothSocketMac* socket) {
|
| + BluetoothChannelMac::SetSocket(socket);
|
| + if (!this->socket())
|
| + return;
|
| +
|
| + // Now that the socket is set, it's safe to associate a delegate, which can
|
| + // call back to the socket.
|
| + DCHECK(!delegate_);
|
| + delegate_.reset(
|
| + [[BluetoothRfcommChannelDelegate alloc] initWithChannel:this]);
|
| + [channel_ setDelegate:delegate_];
|
| +}
|
| +
|
| +std::string BluetoothRfcommChannelMac::GetDeviceAddress() {
|
| + return BluetoothDeviceMac::GetDeviceAddress([channel_ getDevice]);
|
| +}
|
| +
|
| +uint16_t BluetoothRfcommChannelMac::GetOutgoingMTU() {
|
| + return [channel_ getMTU];
|
| +}
|
| +
|
| +IOReturn BluetoothRfcommChannelMac::WriteAsync(void* data,
|
| + uint16_t length,
|
| + void* refcon) {
|
| + DCHECK_LE(length, GetOutgoingMTU());
|
| + return [channel_ writeAsync:data length:length refcon:refcon];
|
| +}
|
| +
|
| +void BluetoothRfcommChannelMac::OnChannelOpenComplete(
|
| + IOBluetoothRFCOMMChannel* channel,
|
| + IOReturn status) {
|
| + if (channel_) {
|
| + DCHECK_EQ(channel_, channel);
|
| + } else {
|
| + // The (potentially) asynchronous connection occurred synchronously.
|
| + // Should only be reachable from OpenAsync().
|
| + DCHECK_EQ(status, kIOReturnSuccess);
|
| + }
|
| +
|
| + socket()->OnChannelOpenComplete(
|
| + BluetoothDeviceMac::GetDeviceAddress([channel getDevice]), status);
|
| +}
|
| +
|
| +void BluetoothRfcommChannelMac::OnChannelClosed(
|
| + IOBluetoothRFCOMMChannel* channel) {
|
| + DCHECK_EQ(channel_, channel);
|
| + socket()->OnChannelClosed();
|
| +}
|
| +
|
| +void BluetoothRfcommChannelMac::OnChannelDataReceived(
|
| + IOBluetoothRFCOMMChannel* channel,
|
| + void* data,
|
| + size_t length) {
|
| + DCHECK_EQ(channel_, channel);
|
| + socket()->OnChannelDataReceived(data, length);
|
| +}
|
| +
|
| +void BluetoothRfcommChannelMac::OnChannelWriteComplete(
|
| + IOBluetoothRFCOMMChannel* channel,
|
| + void* refcon,
|
| + IOReturn status) {
|
| + // Note: We use "CHECK" below to ensure we never run into unforeseen
|
| + // occurrences of asynchronous callbacks, which could lead to data
|
| + // corruption.
|
| + CHECK_EQ(channel_, channel);
|
| + socket()->OnChannelWriteComplete(refcon, status);
|
| +}
|
| +
|
| +} // namespace device
|
|
|