Partly because I have just upgraded to a new Mac with USB C connectors (which is not compatible with my old clicker) and partly because I'm considering going in a new direction in terms of presenting (yes, that's right ... this time I'm reinventing the presentation wheel), I thought it would be cool to have more controls than just on/off/next slide/back up.
I have also had experience using a FLiRC infra-red remote with a Raspberry Pi to provide an MP3 jukebox.
I have been very impressed with both the reliability and range of the bluetooth remote I have on my Roku 4, and wondered if that kind of unit could be connected to a Mac for all kinds of remote control purposes.
I did some research on the internet and decided to go out and buy a PlayStation PS4 media remote six months ago (apparently this is no longer available new). Today I finally had the time and energy to open the box and experiment with it.
The first thing I discovered, of course, was that it needed a couple of AAA batteries in order to work. Fortunately I happened to have 36 sitting in a box in a cupboard, so that was no problem. I now have a "working" remote: how do I connect it to my Mac and use it?
Fortunately it comes with a handy little guide that purports to explain this, at least for pairing with a PS4. I'm going to assume that the Mac bluetooth stack is compatible with the PS4 stack and just go for it.
The first instruction is to open up "Bluetooth Devices" on the PS4, so I open up "System Preferences" and select "Bluetooth" which, unless you have configured something else, turns Bluetooth on and makes your Mac discoverable. While doing this, I decided to add the Bluetooth menu to the menu bar.
The next instructions are to press the "PS" button once to activate the remote and then hold down the "PS" and "SHARE" buttons at the same time until a red LED (previously invisible) starts flashing.
I think when doing this, if you move your mouse away from the Bluetooth window, it stops being discoverable - anyway, I had to click back in that window in order to make the "PDP Media Remote" appear. Then it was just a simple matter of clicking "Connect" and I was done. Remote control connected.
I am not going to claim that is the "hard bit" done. That was merely a gateway. I was expecting that to work, but obviously if it had not worked, I would have been completely stumped.
The question now is, when I push buttons on the remote, how do I make things happen on the computer?
JDK and Bluetooth
I know from previous lifetimes, that Java "supports" Bluetooth through something called "JSR-82" which is an interoperability standard. However, this does not seem to be part of the standard Java SE distribution (I think it is standard on J2ME and Android).
After some digging, I determined that probably the best thing to use was an open-source library called "BlueCove" which, in spite of not having been updated in 11 years, seems to be pretty much the only extant Bluetooth stack for J2SE. I wouldn't like to say if it is "supported" or not.
In fact, just about everything to do with J2SE and Bluetooth seems to be old - from about the time when I was dealing with it before, strangely enough (at the time, it all seemed cutting edge). I dug up an article from 2004 which tries to describe architecture, API and usage all in one fell swoop - and needs serious unpacking to understand; moreover it is written in terms of J2ME, CLDC and CDC, all of which have slipped out of usage in the iPhone era. Anyway, let's see if we can get something working at least.
This appears to be a minimally viable program that obtains a discovery agent:
import javax.bluetooth.BluetoothStateException;import javax.bluetooth.DiscoveryAgent;import javax.bluetooth.LocalDevice;public class Main {public static void main(String[] args) throws BluetoothStateException {LocalDevice me = LocalDevice.getLocalDevice();DiscoveryAgent agent = me.getDiscoveryAgent();}}
Sadly, running this appears to bring the enterprise to an end:
Native Library bluecove not availableException in thread "main" javax.bluetooth.BluetoothStateException: BlueCove library bluecove not availableat com.intel.bluetooth.BlueCoveImpl.loadNativeLibraries(BlueCoveImpl.java:381)at com.intel.bluetooth.BlueCoveImpl.detectStack(BlueCoveImpl.java:434)at com.intel.bluetooth.BlueCoveImpl.access$500(BlueCoveImpl.java:65)at com.intel.bluetooth.BlueCoveImpl$1.run(BlueCoveImpl.java:1020)at java.security.AccessController.doPrivileged(Native Method)at com.intel.bluetooth.BlueCoveImpl.detectStackPrivileged(BlueCoveImpl.java:1018)at com.intel.bluetooth.BlueCoveImpl.getBluetoothStack(BlueCoveImpl.java:1011)at javax.bluetooth.LocalDevice.getLocalDeviceInstance(LocalDevice.java:75)at javax.bluetooth.LocalDevice.getLocalDevice(LocalDevice.java:95)at com.gmmapowell.bluetooth.remote.Main.main(Main.java:10)
Bluecove depends on a "native" (JNI) library which has to be compiled for the appropriate operating system. Googling around the internet produces a number of people who have encountered this problem, but basically nobody has overcome it. It would seem that there are three problems piled on top of each other:
- The library has not been updated in 12 years;
- In the meantime, MacOS has moved from 32-bit to 64-bit;
- A key supporting bluetooth library "has been removed" (I am unsure which).
In short, you are completely hosed.
JavaScript API
My original goal was to use this with JavaScript as part of a Web Application. But I thought it would probably be easier to experiment with Java first. However, this has turned out not to be the case.
Digging around on the internet, there is an emerging (i.e. not yet well-supported) standard for using Bluetooth on the Web. In Chrome at least, it is possible to discover devices. Google provides an example which allows you to discover nearby devices and pair them. This all works very well and enables me to determine that my device name is "PDP Media Remote". I can replicate their code with my own simpler example:
<html><head><script>async function discover() {console.log("discovering PDP Media Remote");const device =await navigator.bluetooth.requestDevice({filters:[{name:"PDP Media Remote"}]}); console.log(device);const services = await device.gatt.connect();console.log(services);}</script></head><body><button id='doDiscovery' onclick='discover()'>Discover</button><div id='info'></div></body></html>
Sadly, however, this also fails on the second step, when I attempt to "connect" the device. It reports that it is an "unknown" device and thus it cannot be handled.
Conclusion
It doesn't seem possible to develop bluetooth applications on a Mac in Java using Java SE and bluecove. Furthermore, JavaScript doesn't seem to recognize my PDP remote.