1 // Copyright 2014 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "device/bluetooth/bluetooth_rfcomm_channel_mac.h"
7 #include "base/logging.h"
8 #include "device/bluetooth/bluetooth_classic_device_mac.h"
9 #include "device/bluetooth/bluetooth_socket_mac.h"
11 // A simple delegate class for an open RFCOMM channel that forwards methods to
12 // its wrapped |channel_|.
13 @interface BluetoothRfcommChannelDelegate
14 : NSObject <IOBluetoothRFCOMMChannelDelegate> {
16 device::BluetoothRfcommChannelMac* channel_; // weak
19 - (id)initWithChannel:(device::BluetoothRfcommChannelMac*)channel;
23 @implementation BluetoothRfcommChannelDelegate
25 - (id)initWithChannel:(device::BluetoothRfcommChannelMac*)channel {
26 if ((self = [super init]))
32 - (void)rfcommChannelOpenComplete:(IOBluetoothRFCOMMChannel*)rfcommChannel
33 status:(IOReturn)error {
34 channel_->OnChannelOpenComplete(rfcommChannel, error);
37 - (void)rfcommChannelWriteComplete:(IOBluetoothRFCOMMChannel*)rfcommChannel
39 status:(IOReturn)error {
40 channel_->OnChannelWriteComplete(rfcommChannel, refcon, error);
43 - (void)rfcommChannelData:(IOBluetoothRFCOMMChannel*)rfcommChannel
44 data:(void*)dataPointer
45 length:(size_t)dataLength {
46 channel_->OnChannelDataReceived(rfcommChannel, dataPointer, dataLength);
49 - (void)rfcommChannelClosed:(IOBluetoothRFCOMMChannel*)rfcommChannel {
50 channel_->OnChannelClosed(rfcommChannel);
57 BluetoothRfcommChannelMac::BluetoothRfcommChannelMac(
58 BluetoothSocketMac* socket,
59 IOBluetoothRFCOMMChannel* channel)
65 BluetoothRfcommChannelMac::~BluetoothRfcommChannelMac() {
66 [channel_ setDelegate:nil];
67 [channel_ closeChannel];
71 scoped_ptr<BluetoothRfcommChannelMac> BluetoothRfcommChannelMac::OpenAsync(
72 BluetoothSocketMac* socket,
73 IOBluetoothDevice* device,
74 BluetoothRFCOMMChannelID channel_id,
77 scoped_ptr<BluetoothRfcommChannelMac> channel(
78 new BluetoothRfcommChannelMac(socket, nil));
80 // Retain the delegate, because IOBluetoothDevice's
81 // |-openRFCOMMChannelAsync:withChannelID:delegate:| assumes that it can take
82 // ownership of the delegate without calling |-retain| on it...
83 DCHECK(channel->delegate_);
84 [channel->delegate_ retain];
85 IOBluetoothRFCOMMChannel* rfcomm_channel;
86 *status = [device openRFCOMMChannelAsync:&rfcomm_channel
87 withChannelID:channel_id
88 delegate:channel->delegate_];
89 if (*status == kIOReturnSuccess) {
90 // Note: No need to retain the |rfcomm_channel| -- the returned channel is
92 channel->channel_.reset(rfcomm_channel);
97 return channel.Pass();
100 void BluetoothRfcommChannelMac::SetSocket(BluetoothSocketMac* socket) {
101 BluetoothChannelMac::SetSocket(socket);
105 // Now that the socket is set, it's safe to associate a delegate, which can
106 // call back to the socket.
109 [[BluetoothRfcommChannelDelegate alloc] initWithChannel:this]);
110 [channel_ setDelegate:delegate_];
113 IOBluetoothDevice* BluetoothRfcommChannelMac::GetDevice() {
114 return [channel_ getDevice];
117 uint16_t BluetoothRfcommChannelMac::GetOutgoingMTU() {
118 return [channel_ getMTU];
121 IOReturn BluetoothRfcommChannelMac::WriteAsync(void* data,
124 DCHECK_LE(length, GetOutgoingMTU());
125 return [channel_ writeAsync:data length:length refcon:refcon];
128 void BluetoothRfcommChannelMac::OnChannelOpenComplete(
129 IOBluetoothRFCOMMChannel* channel,
132 DCHECK_EQ(channel_, channel);
134 // The (potentially) asynchronous connection occurred synchronously.
135 // Should only be reachable from OpenAsync().
136 DCHECK_EQ(status, kIOReturnSuccess);
139 socket()->OnChannelOpenComplete(
140 BluetoothClassicDeviceMac::GetDeviceAddress([channel getDevice]), status);
143 void BluetoothRfcommChannelMac::OnChannelClosed(
144 IOBluetoothRFCOMMChannel* channel) {
145 DCHECK_EQ(channel_, channel);
146 socket()->OnChannelClosed();
149 void BluetoothRfcommChannelMac::OnChannelDataReceived(
150 IOBluetoothRFCOMMChannel* channel,
153 DCHECK_EQ(channel_, channel);
154 socket()->OnChannelDataReceived(data, length);
157 void BluetoothRfcommChannelMac::OnChannelWriteComplete(
158 IOBluetoothRFCOMMChannel* channel,
161 // Note: We use "CHECK" below to ensure we never run into unforeseen
162 // occurrences of asynchronous callbacks, which could lead to data
164 CHECK_EQ(channel_, channel);
165 socket()->OnChannelWriteComplete(refcon, status);
168 } // namespace device