After discovering the nearby Bluetooth devices either using StartDiscovery without filter or with SetDiscovertFilter, next big step is to connect with the device and access the functionalities provided by the device. The connection process involves two steps,
- Pairing – Authenticating and trusting the end bluetooth device
- Connect itself
Here connection can be initiated either by the Bluetooth device or by the Bluetooth adapter itself on behalf of application. The Authentication mechanism involves accepting the device/adapter using PIN/confirmation key. We are not going in details about the Secure Simple Pairing (SSP) of Bluetooth here as bluetoothd hides all the details already. Bluez5 uses Agent style implementation of authentication in favor to the external application. To understand in details, lets assume the following use case,
- User wants to connect to the Car Infotainment System (IVI) using bluetooth and initiates the connection from the mobile device. In this case, IVI head unit displays the PIN/confirmation code based on its Agent configurations. Then the user enters the same PIN or confirm yes/no from the mobile device. In this use case,
- IVI wants to show up the confirmation/PIN in its own wizard or pop (e.g GTK)
- Mobile device wants to pop up confirmation/Input field in its wizard
In favor of such implementations, Bluez5 provide Agent style API’s i.e Bluetooth Application can register it’s capability (yes/no confirmation or PIN entry) and also it’s own wizard implementation with the bluetoothd. Whenever there is a new connection from a device, bluetoothd automatically takes care to callback the registered API (where wizard or user application is implemented).
From the flow diagram, you can see,
- UI application registers its capability with method callbacks with bluetoothd
- StartDiscovery for scanning new devices
- Pair with the device
- bluetoothd callsback the API in UI for PIN/confirmation about the authentication
- Based on the response, bluetoothd decides to proceed or not for pairing
- Followed by Connect call to the Device1 interface (we will explore this interface in detail in next few blogs)
To get started with connection and for the completeness of the API’s coverage in adapter-api.txt, we will first explore the “ConnectDevice” API introduced in Bluez 5.49. As of this blogging date, this API is marked experimental for testing (mostly stable). To explore the below example on ConnectDevice, one must run the bluetoothd service/daemon in experimental mode by passing “-E” as argument.
Code:
ConnectDevice: This API is introduced in favor of answering following questions,
When this API is useful?
- When you already have the MAC address of end bluetooth Device to connect with, then you don’t need to scan for the device (with or without filter) and connect it.
- StartDiscovery + Pair + Connect => ConnectDevice
How you will have MAC address before scanning?
- When you have other communication (wired or wireless) medium to exchange the MAC address
- For example, NFC OOB can be used to exchange the MAC address
- Testing Bluetooth with same device (MAC address known)
In such cases ConnectDevice can be directly called with “MAC address” of the bluetooth device to connect with as argument (as string, not as object path). In addition to the MAC address, Address Type (optional argument) can also be specified as argument to this method. For simplicity and better understanding we are going stick to only MAC address.
Before using the ConnectDevice method, we need to register our own agent which needs to be called for pairing process. Again for simplicity and for better understanding we are registering “NoInputOutput” without any method callbacks. This means, our bluetooth adapters Agen capability is similar to the one in Bluetooth headset, where user doesn’t need to care about pairing authentication. We will explore in detail about Agen API and all the methods in next blog before getting into device-api.
This example program takes the MAC address (XX:YY:ZZ:AA:BB:CC format) as argument which is directly fed into ConnectDevice method. Also note that this example uses Linux signal handler for SIGINT (Control + c from console) to gracefully handle the program exit.