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 |