<feed xmlns='http://www.w3.org/2005/Atom'>
<title>DomeKey, branch bluetooth-headset-compatibility</title>
<subtitle>Control your computer with a pair of headphones</subtitle>
<link rel='alternate' type='text/html' href='https://git.teddywing.com/DomeKey/'/>
<entry>
<title>HeadphoneKeyEventBluetooth: Add L2CAP connection</title>
<updated>2019-03-24T20:54:30+00:00</updated>
<author>
<name>Teddy Wing</name>
</author>
<published>2019-03-24T20:54:30+00:00</published>
<link rel='alternate' type='text/html' href='https://git.teddywing.com/DomeKey/commit/?id=c5013bf9fc866fece5c358f28473627a6bd1ff10'/>
<id>c5013bf9fc866fece5c358f28473627a6bd1ff10</id>
<content type='text'>
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?
</content>
<content type='xhtml'>
<div xmlns='http://www.w3.org/1999/xhtml'>
<pre>
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?
</pre>
</div>
</content>
</entry>
<entry>
<title>HeadphoneKeyEventBluetooth: Determine Bluetooth device class</title>
<updated>2019-03-24T18:10:40+00:00</updated>
<author>
<name>Teddy Wing</name>
</author>
<published>2019-03-24T18:10:40+00:00</published>
<link rel='alternate' type='text/html' href='https://git.teddywing.com/DomeKey/commit/?id=28a6eafbf3ba46abe4560cecd4696457f5615137'/>
<id>28a6eafbf3ba46abe4560cecd4696457f5615137</id>
<content type='text'>
Learn how to find out if a device is a pair of headphones with remote
control capabilities.

This produces the following output:

    2019-03-24 19:07:46.265 DomeKey[59146:1474861] Device class major: 4
    2019-03-24 19:07:46.266 DomeKey[59146:1474861] Device class minor: 6
    2019-03-24 19:07:46.266 DomeKey[59146:1474861] Class of device: 2360344
    2019-03-24 19:07:46.266 DomeKey[59146:1474861] Service class major: 288
    2019-03-24 19:07:46.266 DomeKey[59146:1474861] Major audio
    2019-03-24 19:07:46.266 DomeKey[59146:1474861] Minor audio
    2019-03-24 19:07:46.266 DomeKey[59146:1474861] Is remote controller

Other potentially useful but unused constants are:

    kBluetoothSDPUUID16ServiceClassAVRemoteControlTarget
    kBluetoothSDPUUID16ServiceClassAVRemoteControl
    kBluetoothSDPUUID16ServiceClassAVRemoteControlController

in IOBluetooth's `BluetoothAssignedNumbers.h`.

From this, we should be able to figure out if a device is a remote
control-capable pair of headphones.
</content>
<content type='xhtml'>
<div xmlns='http://www.w3.org/1999/xhtml'>
<pre>
Learn how to find out if a device is a pair of headphones with remote
control capabilities.

This produces the following output:

    2019-03-24 19:07:46.265 DomeKey[59146:1474861] Device class major: 4
    2019-03-24 19:07:46.266 DomeKey[59146:1474861] Device class minor: 6
    2019-03-24 19:07:46.266 DomeKey[59146:1474861] Class of device: 2360344
    2019-03-24 19:07:46.266 DomeKey[59146:1474861] Service class major: 288
    2019-03-24 19:07:46.266 DomeKey[59146:1474861] Major audio
    2019-03-24 19:07:46.266 DomeKey[59146:1474861] Minor audio
    2019-03-24 19:07:46.266 DomeKey[59146:1474861] Is remote controller

Other potentially useful but unused constants are:

    kBluetoothSDPUUID16ServiceClassAVRemoteControlTarget
    kBluetoothSDPUUID16ServiceClassAVRemoteControl
    kBluetoothSDPUUID16ServiceClassAVRemoteControlController

in IOBluetooth's `BluetoothAssignedNumbers.h`.

From this, we should be able to figure out if a device is a remote
control-capable pair of headphones.
</pre>
</div>
</content>
</entry>
<entry>
<title>HeadphoneKeyEventBluetooth: Listen for Bluetooth device pairing</title>
<updated>2019-03-24T11:50:05+00:00</updated>
<author>
<name>Teddy Wing</name>
</author>
<published>2019-03-24T11:45:52+00:00</published>
<link rel='alternate' type='text/html' href='https://git.teddywing.com/DomeKey/commit/?id=c484af9d5844fa29be77d098542a74e313dad4c6'/>
<id>c484af9d5844fa29be77d098542a74e313dad4c6</id>
<content type='text'>
Register a delegate that gets called when Bluetooth devices are paired
with the Mac.

We now need to determine if the paired device is a pair of headphones
(ideally if we can figure out media remote control capability that would
be helpful), and then connect to them over L2CAP to get AVRCP messages.

The `devicePairingFinished:error:` delegate method was a test. Leaving
it in as a reminder that we also need to implement functionality that
looks for already-connected Bluetooth headphones when DomeKey launches.
</content>
<content type='xhtml'>
<div xmlns='http://www.w3.org/1999/xhtml'>
<pre>
Register a delegate that gets called when Bluetooth devices are paired
with the Mac.

We now need to determine if the paired device is a pair of headphones
(ideally if we can figure out media remote control capability that would
be helpful), and then connect to them over L2CAP to get AVRCP messages.

The `devicePairingFinished:error:` delegate method was a test. Leaving
it in as a reminder that we also need to implement functionality that
looks for already-connected Bluetooth headphones when DomeKey launches.
</pre>
</div>
</content>
</entry>
<entry>
<title>HeadphoneKeyEventBluetooth: Initial thought with MPRemoteCommandCenter</title>
<updated>2019-03-24T11:36:42+00:00</updated>
<author>
<name>Teddy Wing</name>
</author>
<published>2019-03-24T11:36:42+00:00</published>
<link rel='alternate' type='text/html' href='https://git.teddywing.com/DomeKey/commit/?id=519038bde17082020265d5ae5bda80f493f91b20'/>
<id>519038bde17082020265d5ae5bda80f493f91b20</id>
<content type='text'>
Turns out that `MPRemoteCommandCenter` seems to work for the 'play'
button, but it has no interface for volume buttons. I remember
discovering the volume button problem when I last looked into it several
months ago, but since forgot.

This was an attempt at replicating the method in:
https://github.com/russellhancox/btrcd/blob/c3e375f/btrcd/AppDelegate.m
by setting up an `MPRemoteCommandCenter` and calling
`addTargetWithHandler:` on each button to invoke a custom handler.

Committing this for reference. In order to get volume button
functionality, we'll have to dive into lower level Bluetooth events with
AVRCP. Seems that newer headphones might even use something newer than
AVRCP, so I wonder if we'll have to use multiple Bluetooth remote
control profiles.

A bit of a pain, as there doesn't seem to be a pre-built interface for
us to do this, but I'm learning more about interacting with IOBluetooth.
Also, `MPRemoteCommandCenter` is an OS X 10.12 Sierra API, so if there's
something we can use that's available on earlier OSes, that's a plus.
</content>
<content type='xhtml'>
<div xmlns='http://www.w3.org/1999/xhtml'>
<pre>
Turns out that `MPRemoteCommandCenter` seems to work for the 'play'
button, but it has no interface for volume buttons. I remember
discovering the volume button problem when I last looked into it several
months ago, but since forgot.

This was an attempt at replicating the method in:
https://github.com/russellhancox/btrcd/blob/c3e375f/btrcd/AppDelegate.m
by setting up an `MPRemoteCommandCenter` and calling
`addTargetWithHandler:` on each button to invoke a custom handler.

Committing this for reference. In order to get volume button
functionality, we'll have to dive into lower level Bluetooth events with
AVRCP. Seems that newer headphones might even use something newer than
AVRCP, so I wonder if we'll have to use multiple Bluetooth remote
control profiles.

A bit of a pain, as there doesn't seem to be a pre-built interface for
us to do this, but I'm learning more about interacting with IOBluetooth.
Also, `MPRemoteCommandCenter` is an OS X 10.12 Sierra API, so if there's
something we can use that's available on earlier OSes, that's a plus.
</pre>
</div>
</content>
</entry>
<entry>
<title>Extract headphone key listener to `HeadphoneKeyEventWired`</title>
<updated>2019-03-23T13:13:09+00:00</updated>
<author>
<name>Teddy Wing</name>
</author>
<published>2019-03-23T13:13:09+00:00</published>
<link rel='alternate' type='text/html' href='https://git.teddywing.com/DomeKey/commit/?id=8aba8891e027dc1aa5d352fb60240e704e5628d8'/>
<id>8aba8891e027dc1aa5d352fb60240e704e5628d8</id>
<content type='text'>
Move the DDHidLib headphone button event listener from `HeadphoneKey` to
`HeadphoneKeyEventWired`. This creates a common interface for both wired
and wireless Bluetooth headphones.

The DDHidLib listener now lives in its own class dedicated to wired
headphones. A new `HeadphoneKeyEventBluetooth` will set up the event
listener for Bluetooth headphones.

Both `HeadphoneKeyEvent_` listeners call a delegate method set up on
`HeadphoneKey` that relays the pressed headphone button.
</content>
<content type='xhtml'>
<div xmlns='http://www.w3.org/1999/xhtml'>
<pre>
Move the DDHidLib headphone button event listener from `HeadphoneKey` to
`HeadphoneKeyEventWired`. This creates a common interface for both wired
and wireless Bluetooth headphones.

The DDHidLib listener now lives in its own class dedicated to wired
headphones. A new `HeadphoneKeyEventBluetooth` will set up the event
listener for Bluetooth headphones.

Both `HeadphoneKeyEvent_` listeners call a delegate method set up on
`HeadphoneKey` that relays the pressed headphone button.
</pre>
</div>
</content>
</entry>
<entry>
<title>Add files for headphone events</title>
<updated>2019-03-22T21:35:09+00:00</updated>
<author>
<name>Teddy Wing</name>
</author>
<published>2019-03-22T21:35:09+00:00</published>
<link rel='alternate' type='text/html' href='https://git.teddywing.com/DomeKey/commit/?id=f0ca208cd4d347a5273480a21ee05230b855c3e5'/>
<id>f0ca208cd4d347a5273480a21ee05230b855c3e5</id>
<content type='text'>
A few files to abstract interaction with wired and Bluetooth headphones
so that we can get events from both using a consistent interface in
`HeadphoneKey`.
</content>
<content type='xhtml'>
<div xmlns='http://www.w3.org/1999/xhtml'>
<pre>
A few files to abstract interaction with wired and Bluetooth headphones
so that we can get events from both using a consistent interface in
`HeadphoneKey`.
</pre>
</div>
</content>
</entry>
<entry>
<title>Update TODO</title>
<updated>2018-11-23T05:34:40+00:00</updated>
<author>
<name>Teddy Wing</name>
</author>
<published>2018-11-23T05:34:40+00:00</published>
<link rel='alternate' type='text/html' href='https://git.teddywing.com/DomeKey/commit/?id=943230d891282c4998f166f1cfd000def6b7f0a2'/>
<id>943230d891282c4998f166f1cfd000def6b7f0a2</id>
<content type='text'>
</content>
<content type='xhtml'>
<div xmlns='http://www.w3.org/1999/xhtml'>
<pre>
</pre>
</div>
</content>
</entry>
<entry>
<title>HomebrewFormula: Add `--reload-mappings` mention in Caveats</title>
<updated>2018-11-22T22:36:28+00:00</updated>
<author>
<name>Teddy Wing</name>
</author>
<published>2018-11-22T22:36:28+00:00</published>
<link rel='alternate' type='text/html' href='https://git.teddywing.com/DomeKey/commit/?id=a8a36293283f4df90f37e29bdc654908ec943e6b'/>
<id>a8a36293283f4df90f37e29bdc654908ec943e6b</id>
<content type='text'>
Instruct users to reload mappings if `dome-key` is running. This could
happen if the install commands were copy-pasted from the website:

    $ brew install teddywing/DomeKey/dome-key
    $ brew services start teddywing/DomeKey/dome-key

At this point, `dome-key` would already have been started, and the new
mappings wouldn't be loaded into the running process.

Also indent the shell commands to differentiate them from the text.
</content>
<content type='xhtml'>
<div xmlns='http://www.w3.org/1999/xhtml'>
<pre>
Instruct users to reload mappings if `dome-key` is running. This could
happen if the install commands were copy-pasted from the website:

    $ brew install teddywing/DomeKey/dome-key
    $ brew services start teddywing/DomeKey/dome-key

At this point, `dome-key` would already have been started, and the new
mappings wouldn't be loaded into the running process.

Also indent the shell commands to differentiate them from the text.
</pre>
</div>
</content>
</entry>
<entry>
<title>HomebrewFormula/dome-key.rb: Repackage with latest changes</title>
<updated>2018-11-22T20:16:16+00:00</updated>
<author>
<name>Teddy Wing</name>
</author>
<published>2018-11-22T20:16:16+00:00</published>
<link rel='alternate' type='text/html' href='https://git.teddywing.com/DomeKey/commit/?id=bffe56397945195c76bf95a81c0281aef5430803'/>
<id>bffe56397945195c76bf95a81c0281aef5430803</id>
<content type='text'>
Only significant change is the addition of the license to the man page.
</content>
<content type='xhtml'>
<div xmlns='http://www.w3.org/1999/xhtml'>
<pre>
Only significant change is the addition of the license to the man page.
</pre>
</div>
</content>
</entry>
<entry>
<title>Add README</title>
<updated>2018-11-22T18:53:36+00:00</updated>
<author>
<name>Teddy Wing</name>
</author>
<published>2018-11-22T18:53:36+00:00</published>
<link rel='alternate' type='text/html' href='https://git.teddywing.com/DomeKey/commit/?id=14f115daf0f63d2dce85d1eb24d957524d7341cf'/>
<id>14f115daf0f63d2dce85d1eb24d957524d7341cf</id>
<content type='text'>
</content>
<content type='xhtml'>
<div xmlns='http://www.w3.org/1999/xhtml'>
<pre>
</pre>
</div>
</content>
</entry>
</feed>
