OLD | NEW |
(Empty) | |
| 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. |
| 4 |
| 5 #include "device/bluetooth/bluetooth_rfcomm_channel_mac.h" |
| 6 |
| 7 #include "base/logging.h" |
| 8 #include "device/bluetooth/bluetooth_device_mac.h" |
| 9 #include "device/bluetooth/bluetooth_socket_mac.h" |
| 10 |
| 11 // A simple delegate class for an open RFCOMM channel that forwards methods to |
| 12 // its wrapped |channel_|. |
| 13 @interface BluetoothRfcommChannelDelegate |
| 14 : NSObject <IOBluetoothRFCOMMChannelDelegate> { |
| 15 @private |
| 16 device::BluetoothRfcommChannelMac* channel_; // weak |
| 17 } |
| 18 |
| 19 - (id)initWithChannel:(device::BluetoothRfcommChannelMac*)channel; |
| 20 |
| 21 @end |
| 22 |
| 23 @implementation BluetoothRfcommChannelDelegate |
| 24 |
| 25 - (id)initWithChannel:(device::BluetoothRfcommChannelMac*)channel { |
| 26 if ((self = [super init])) |
| 27 channel_ = channel; |
| 28 |
| 29 return self; |
| 30 } |
| 31 |
| 32 - (void)rfcommChannelOpenComplete:(IOBluetoothRFCOMMChannel*)rfcommChannel |
| 33 status:(IOReturn)error { |
| 34 channel_->OnChannelOpenComplete(rfcommChannel, error); |
| 35 } |
| 36 |
| 37 - (void)rfcommChannelWriteComplete:(IOBluetoothRFCOMMChannel*)rfcommChannel |
| 38 refcon:(void*)refcon |
| 39 status:(IOReturn)error { |
| 40 channel_->OnChannelWriteComplete(rfcommChannel, refcon, error); |
| 41 } |
| 42 |
| 43 - (void)rfcommChannelData:(IOBluetoothRFCOMMChannel*)rfcommChannel |
| 44 data:(void*)dataPointer |
| 45 length:(size_t)dataLength { |
| 46 channel_->OnChannelDataReceived(rfcommChannel, dataPointer, dataLength); |
| 47 } |
| 48 |
| 49 - (void)rfcommChannelClosed:(IOBluetoothRFCOMMChannel*)rfcommChannel { |
| 50 channel_->OnChannelClosed(rfcommChannel); |
| 51 } |
| 52 |
| 53 @end |
| 54 |
| 55 namespace device { |
| 56 |
| 57 BluetoothRfcommChannelMac::BluetoothRfcommChannelMac( |
| 58 BluetoothSocketMac* socket, |
| 59 IOBluetoothRFCOMMChannel* channel) |
| 60 : channel_(channel), |
| 61 delegate_(nil) { |
| 62 SetSocket(socket); |
| 63 } |
| 64 |
| 65 BluetoothRfcommChannelMac::~BluetoothRfcommChannelMac() { |
| 66 [channel_ setDelegate:nil]; |
| 67 [channel_ closeChannel]; |
| 68 } |
| 69 |
| 70 // static |
| 71 scoped_ptr<BluetoothRfcommChannelMac> BluetoothRfcommChannelMac::OpenAsync( |
| 72 BluetoothSocketMac* socket, |
| 73 IOBluetoothDevice* device, |
| 74 uint8 channel_id, |
| 75 IOReturn* status) { |
| 76 DCHECK(socket); |
| 77 scoped_ptr<BluetoothRfcommChannelMac> channel( |
| 78 new BluetoothRfcommChannelMac(socket, nil)); |
| 79 |
| 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 |
| 91 // already retained. |
| 92 channel->channel_.reset(rfcomm_channel); |
| 93 } else { |
| 94 channel.reset(); |
| 95 } |
| 96 |
| 97 return channel.Pass(); |
| 98 } |
| 99 |
| 100 void BluetoothRfcommChannelMac::SetSocket(BluetoothSocketMac* socket) { |
| 101 BluetoothChannelMac::SetSocket(socket); |
| 102 if (!this->socket()) |
| 103 return; |
| 104 |
| 105 // Now that the socket is set, it's safe to associate a delegate, which can |
| 106 // call back to the socket. |
| 107 DCHECK(!delegate_); |
| 108 delegate_.reset( |
| 109 [[BluetoothRfcommChannelDelegate alloc] initWithChannel:this]); |
| 110 [channel_ setDelegate:delegate_]; |
| 111 } |
| 112 |
| 113 std::string BluetoothRfcommChannelMac::GetDeviceAddress() { |
| 114 return BluetoothDeviceMac::GetDeviceAddress([channel_ getDevice]); |
| 115 } |
| 116 |
| 117 uint16_t BluetoothRfcommChannelMac::GetOutgoingMTU() { |
| 118 return [channel_ getMTU]; |
| 119 } |
| 120 |
| 121 IOReturn BluetoothRfcommChannelMac::WriteAsync(void* data, |
| 122 uint16_t length, |
| 123 void* refcon) { |
| 124 DCHECK_LE(length, GetOutgoingMTU()); |
| 125 return [channel_ writeAsync:data length:length refcon:refcon]; |
| 126 } |
| 127 |
| 128 void BluetoothRfcommChannelMac::OnChannelOpenComplete( |
| 129 IOBluetoothRFCOMMChannel* channel, |
| 130 IOReturn status) { |
| 131 if (channel_) { |
| 132 DCHECK_EQ(channel_, channel); |
| 133 } else { |
| 134 // The (potentially) asynchronous connection occurred synchronously. |
| 135 // Should only be reachable from OpenAsync(). |
| 136 DCHECK_EQ(status, kIOReturnSuccess); |
| 137 } |
| 138 |
| 139 socket()->OnChannelOpenComplete( |
| 140 BluetoothDeviceMac::GetDeviceAddress([channel getDevice]), status); |
| 141 } |
| 142 |
| 143 void BluetoothRfcommChannelMac::OnChannelClosed( |
| 144 IOBluetoothRFCOMMChannel* channel) { |
| 145 DCHECK_EQ(channel_, channel); |
| 146 socket()->OnChannelClosed(); |
| 147 } |
| 148 |
| 149 void BluetoothRfcommChannelMac::OnChannelDataReceived( |
| 150 IOBluetoothRFCOMMChannel* channel, |
| 151 void* data, |
| 152 size_t length) { |
| 153 DCHECK_EQ(channel_, channel); |
| 154 socket()->OnChannelDataReceived(data, length); |
| 155 } |
| 156 |
| 157 void BluetoothRfcommChannelMac::OnChannelWriteComplete( |
| 158 IOBluetoothRFCOMMChannel* channel, |
| 159 void* refcon, |
| 160 IOReturn status) { |
| 161 // Note: We use "CHECK" below to ensure we never run into unforeseen |
| 162 // occurrences of asynchronous callbacks, which could lead to data |
| 163 // corruption. |
| 164 CHECK_EQ(channel_, channel); |
| 165 socket()->OnChannelWriteComplete(refcon, status); |
| 166 } |
| 167 |
| 168 } // namespace device |
OLD | NEW |