From c5013bf9fc866fece5c358f28473627a6bd1ff10 Mon Sep 17 00:00:00 2001 From: Teddy Wing Date: Sun, 24 Mar 2019 21:54:30 +0100 Subject: HeadphoneKeyEventBluetooth: Add L2CAP connection Open a channel with Bluetooth headphones over L2CAP. The goal is to get button press events from the channel. Unfortunately, I seem to only be able to get press/release events from the "play" button but not the volume buttons. Weird. Not sure what's going on there yet. Is there a different channel for volume controls? Came across `kBluetoothSDPAttributeIdentifierRemoteAudioVolumeControl` in `BluetoothAssignedNumbers.h`. Is that interesting to us? --- DomeKey/HeadphoneKeyEventBluetooth.h | 6 ++++- DomeKey/HeadphoneKeyEventBluetooth.m | 49 ++++++++++++++++++++++++++++++++++-- 2 files changed, 52 insertions(+), 3 deletions(-) diff --git a/DomeKey/HeadphoneKeyEventBluetooth.h b/DomeKey/HeadphoneKeyEventBluetooth.h index a55a539..d92a77c 100644 --- a/DomeKey/HeadphoneKeyEventBluetooth.h +++ b/DomeKey/HeadphoneKeyEventBluetooth.h @@ -12,8 +12,12 @@ #import "HeadphoneKeyEventDelegate.h" #import "dome_key_map.h" -@interface HeadphoneKeyEventBluetooth : NSObject { +@interface HeadphoneKeyEventBluetooth : NSObject < + IOBluetoothDevicePairDelegate, + IOBluetoothL2CAPChannelDelegate +> { id _delegate; + IOBluetoothL2CAPChannel *_l2cap_channel; } - (instancetype)initWithDelegate:(id )delegate; diff --git a/DomeKey/HeadphoneKeyEventBluetooth.m b/DomeKey/HeadphoneKeyEventBluetooth.m index 74ae8b9..2f0c2c4 100644 --- a/DomeKey/HeadphoneKeyEventBluetooth.m +++ b/DomeKey/HeadphoneKeyEventBluetooth.m @@ -65,9 +65,54 @@ IOBluetoothSDPServiceRecord *service_record = [device getServiceRecordForUUID:[[IOBluetoothSDPUUID alloc] initWithUUID16:kBluetoothSDPUUID16ServiceClassAVRemoteControlController]]; - if (service_record) { - NSLog(@"Is remote controller"); + if (!service_record) { + NSLog(@"Not a remote control capable pair of headphones"); + return; } + + // BluetoothL2CAPPSM *psm = NULL; + IOReturn ret; + // ret = [service_record getL2CAPPSM:psm]; + // if (ret != kIOReturnSuccess) { + // NSLog(@"L2CAP PSM error: %d", ret); + // return; + // } + + IOBluetoothL2CAPChannel *l2cap; + ret = [device openL2CAPChannelAsync:&l2cap + // withPSM:*psm // (BluetoothL2CAPPSM)kBluetoothL2CAPPSMAVCTP + // Appears to only work for the Play/Pause button + withPSM:(BluetoothL2CAPPSM)kBluetoothL2CAPPSMAVCTP + delegate:self]; + if (ret != kIOReturnSuccess) { + _l2cap_channel = nil; + NSLog(@"L2CAP channel open error: %d", ret); + return; + } + + _l2cap_channel = l2cap; +} + +- (void)l2capChannelData:(IOBluetoothL2CAPChannel *)l2capChannel + data:(void *)dataPointer + length:(size_t)dataLength +{ + // for (size_t i = 0; i < dataLength; i++) { + // NSLog(@"L2CAP data: ?", dataPointer[i]); + // } + NSData *data = [NSData dataWithBytes:dataPointer length:dataLength]; + NSLog(@"L2CAP data: %@", data); +} + +- (void)l2capChannelOpenComplete:(IOBluetoothL2CAPChannel *)l2capChannel + status:(IOReturn)error +{ + NSLog(@"L2CAP channel open"); +} + +- (void)l2capChannelClosed:(IOBluetoothL2CAPChannel *)l2capChannel +{ + NSLog(@"L2CAP channel closed"); } @end -- cgit v1.2.3