Working with Bluetooth Devices

The MME Bluetooth devices. This section describes how to integrate Bluetooth devices into the MME, and provides some basic information about accessing Bluetooth device functionality through the MME:


Note: For information about how to get configuration values from a Bluetooth device, see Getting and setting external device options in the chapter External Devices, CD Changers and Streamed Media.

Integrating Bluetooth audio devices into the MME

The MME uses the io-fs-media interface to control playback on remote devices. This interface permits device agnostic playback control and metadata extraction, and lets the MME control playback without detailed knowledge of the underlying device.

To control Bluetooth audio devices, the MME uses the MediaFS interface provided by io-fs-media.


The MME, io-fs and the Bluetooth stack.


The MME uses the io-fs interface to control a Bluetooth audio device.

See also io-fs-media in the MME Utilities Reference.

To use Bluetooth devices with the MME you must integrate them into the MME. This integration requires three tasks:

  1. Create a Bluetooth device representation to MediaFS specification.
  2. Configure the MME for Bluetooth support.
  3. Control the Bluetooth device through the MME and play media.

Note: You should be familiar with the QNX MediaFS (Media File System) Specification before starting work on integrating Bluetooth devices into the MME. If you do not have the latest MediaFS specification, contact your QNX representative.

Creating a Bluetooth device representation to the MediaFS specification

The Aviage Bluetooth Integration Kit provides the resource manager framework required for representing Bluetooth devices via io-fs-media. This resource manager provides the ability to load user-created modules that uses the MediaFS specification to describe devices.

Access to a control device is specific to that device and depends on how the device is represented by the system. The access interface can be via any of:


Note:

You can also create your own resource manager to represent Bluetooth devices, following the MediaFS specification.


The io-fs-media module example

To facilitate development of new io-fs-media AVRCP modules describing Bluetooth devices, the Aviage Bluetooth Integration Kit includes an io-fs-media module example that implements the Bluetooth AVRCP (Audio/Video Remote Control Profile).

This example contains the complete framework required for io-fs-media modules that describe devices. You only need to modify device-specific sections to change the module so that it can access your required underlying control devices.


Note: Before compiling and using the sample io-fs-media module example that implements the Bluetooth AVRCP, you must:
  • have a board on which you can perform your tests
  • install the BSP package you will use (with the relevant drivers)

What the io-fs-media module example does

The io-fs-media AVRCP module is a plugin to the io-fs-media resource manager. When io-fs-media with an AVRCP module is started, it:

When it learns of a remote device, the io-fs-media resource manager registers a path, called the mountpoint, to the location of MediaFS filesystem. The default mountpoint used by the module provided with the Aviage Bluetooth Integration Kit is /fs/avrcp0. When you have configured the MCD, it will monitor the system for this path. See Modifying the MCD configuration file for Bluetooth below.


The io-fs-media MediaFS module hierarchy


The io-fs-media MediaFS module hierarchy

Since the io-fs-media AVRCP module implements only a subset of the MediaFS filesystem hierarchy, the only item at this path is the .FS_info. directory.

The .FS_info. directory contains MediaFS entries used for playback control and device information extraction. The directory for the io-fs-media AVRCP module contains only the info.xml file. The first request to read the info.xml file causes avrcp_getinfo() function to populate the file's contents.

All playback and metadata extraction messages are issued through an open file descriptor to the info.xml file. These are handled by the function avrcp_devctl(). This function and other major functions in avrcpexample.c are described below. For more detailed information about these and other functions in avrcpexample.c, see the source file.

avrcp_devctl()

The avrcp_devctl() function is the workhorse for all device control messages. It translates MediaFS playback and metadata extraction commands, then transmits them to the remote device. All commands handled by the avrcp_devctl() function require the addition of device-specific control code to the io-fs-media module example.

See Configuring the MME for Bluetooth support for more information about available commands.

avrcp_mount()

The avrcp_mount() function is the entrance point for the io-fs-media module. It allocates memory associated to the driver. After allocating memory and registering internal functions, avrcp_mount() enables a timer that handles polling for remote device insertions and removals.

You can modify the structure avrcp_device defined in the avrcpexample.h header file to store user data that persists for a mount period.

avrcp_options()

The avrcp_options() function passes arguments to the driver at the io-fs-media interface. The io-fs-media module example includes the following set of options:

avrcp_timer()

The function avrcp_timer() is used to detect the presence of a remote device to mount and register its path. To use this function you must add device-specific code to the io-fs-media module that will communicate the presence of a remote device so that it can be mounted.

Because the mountpoint for the io-fs-media module can be registered and unregistered, if a remote device is present and available to play, avrcp_timer() registers its mount path. If the remote device is removed from the system, avrcp_timer() unregisters the mount path.

The mount process

The mount process has two stages:

  1. Establish a valid connection to the resource manager or AVRCP controller.
  2. Confirm that the remote device is connected.

If the resource manager or the AVRCP controller is unavailable, the io-fs-media module uses the avrcp_timer() function's “poll” until it detects that the required resource is available for mounting.

The poll rate is set by the user in the configuration options. See above.

The avrcpexample.h header file

The avrcpexample.h defines the structure avrcp_device and several constants used by the io-fs-media AVRCP module.

#include <inttypes.h>
#include "media.h"

#define AVRCP_NAME        "AVRCP"
#define NAME_BUF_SIZE     512
#define AVCP_METADATA_MAX 1024

struct avrcp_device {
    struct mediafsdevice  mediafs;
    char *                devpath;
    int                   fd;
    char                  dname[AVCP_METADATA_MAX];
    char                  dserial[AVCP_METADATA_MAX];
    uint16_t              verbose;
};

The structure avrcp_device is the principle AVCP device structure. It is defined in the avrcpexample.h header file and carries information about these devices. It can be extended to hold data about an underlying device. Its standard members include:

Member Type Description
mediafs struct
mediafsdevice
An opaque structure; it must be present and first.
devpath char The pathname to the AVCP device resource manager.
fd int The file descriptor connection to device resource manager, or -1 if not connected
dname
[AVCP_METADATA_MAX]
char Bluetooth-friendly name
dserial
[AVCP_METADATA_MAX]
char Bluetooth address (used as device serial number)
verbose uint16_t The log level verbosity

Modifying the io-fs-media module example

This section describes how to modify and build the io-fs-media module example.

Adding device-specific code to the module

The Aviage Bluetooth Integration Kit includes a set of files that make up the io-fs-media module. These files include:

The only file that requires changes for integration is the avrcpexample.c file. Sections of this file that require the addition of device-specific code are denoted by comments, as follows:

Below is an example of a section of the avrcpexample.c file that requires device-specific code:

case DCMD_MEDIA_PREV_TRACK:
    // -- START DEVICECODE
    // -- TASK: Issue command to skip to the previous track on
    //          the remote device.
    //          Device control may be supported. If not supported,
    //          status=ENOTSUP.
    //          Device control can fail.
    // -- PSEUDOCODE:
    //    status = DEVICEFUNC_PREV_TRACK();
    // -- END DEVICECODE
	break;

Building the module

After you have added the required device-specific code to the io-fs-media module, you can build it as follows:

  1. Copy the sample modules to your home directory:
    # cp -R $QNX_TARGET/examples ~/examples
  2. In your home directory, make and install the module:
    # cd ~/examples/io-fs/drvr/media/avrcpexample
    # make install

To build all sample modules, you can make them from the ~/examples/io-fs directory, as follows:

# cd ~/examples/io-fs
# make install

Using the io-fs-media module

After you have added all your device-specific code to the io-fs-media module, you can use io-fs-media to load it. Starting the module is as simple as running an instance of io-fs-media with the driver, as follows:

# io-fs-media -davrcpexample

You can also pass options to the module, as follows:

# io-fs-media -davrcpexample,verbose=10,mount=/fs/alt/mount/point

See avrcp_options() for a list of options.

If the remote device is present, then your application should register a new mount point. You can use the ls commandline instruction to examine the mountpoint:

# ls /fs/avrcp0

You can add multiple devices by running separate instances of the module, as follows:

# io-fs-media -davrcpexample,dev=/dev/avrcp0,mount=/fs/avrcp0
# io-fs-media -davrcpexample,dev=/dev/avrcp1,mount=/fs/avrcp1
# io-fs-media -davrcpexample,dev=/dev/avrcp2,mount=/fs/avrcp2

Messages for controlling Bluetooth devices

This section lists the messages that you can send to Bluetooth devices to control playback and to extract metadata.


Note:
  • Remote devices differ, so device-specific control codes may not support some commands. If a command is not required and is not supported, it must return an error with errno set to ENOTSUP.
  • All state modification control messages must be synchronous. A requested action must either complete or fail before returning. For example, if the state modifier DCMD_MEDIA_PLAY message is issued, upon return of the devctl() call, the underlying device must be in a playing state, or have returned a POSIX error indicating why the command failed.
  • For more information about commands, see the MediaFS specification.

Playback messages

Playback of media tracks on a Bluetooth device occurs on the device. The start and manage playback the io-fs-media module sends control messages to the Bluetooth device. The table below lists playback commands implemented for AVRCP 1.0 and 1.3 devices. Required commands are marked with an asterisk (*). All others are optional.

AVRCP 1.0

The io-fs-media driver implements the following playback devctls for AVRCP 1.0 devices:

AVRCP 1.3

In addition to the playback commands listed above, the following optional shuffle and repeat commands devctls are implemented for AVRCP 1.3 devices:

Metadata messages

Metadata extraction commands retrieve metadata about the currently playing file. All strings returned by the metadata extraction commands must be UTF-8 encoded. All metadata extraction commands are optional.

Using Bluetooth devices with the MME

This section describes:

Configuring the MME for Bluetooth support

After you have modified your io-fs-media module and have it running, you must configure the MME to enable Bluetooth support. You need to:

Modifying the MCD configuration file for Bluetooth

To enable Bluetooth support, add an entry to the MCD configuration file to instruct the MCD to monitor the path for Bluetooth devices. For example:

[/fs/avrcp*]
Callout     = PATH_MEDIA_PROCMGR
Argument    = /proc/mount
Priority    = 11,10
Start Rule  = INSERTED
Stop Rule   = EJECTED

For more information about the MCD, see the MME Utilities Reference.

Enabling Bluetooth support in the slots table

The Bluetooth slot type is MME_SLOTTYPE_MEDIAFS (4), and the storagetype is MME_STORAGETYPE_A2DP (12). To enable Bluetooth support, you need to add an entry such as the following in the slots table:

INSERT INTO slots(path,zoneid, name, slottype)
    VALUES('/fs/avrcp0', 1, 'Bluetooth', 4);

Note: The slottype for Bluetooth support must be 4.

Playing media on Bluetooth devices

If you have configured the MME correctly to support Bluetooth devices, on learning of the insertion of a Bluetooth device, the MME:

You can use this file ID to create a track session with a single track for the device, then issue commands to start and manage playback. Playback remains on the Bluetooth device, and the MME does not have access to information about an individual track on the device unless the track is being played.

MME playback features supported for Bluetooth devices

The MME supports calls to the following playback functions for Bluetooth devices:


Caution: Do not set autopause (mme_setautopause()) for control contexts with a Bluetooth phone. Because Bluetooth phones control their own playback, if you set autopause for a control context with a Bluetooth phone:
  • playback from the device may produce unexpected behavior
  • metadata and other track information requested from the device may be invalid

Below are sample sequences showing how to use the MME commandline utility (mmecli)to:

Query the mediastores table

# qdbc -d mme "select msid,slotid,storage_type, mountpath \
    from mediastores"
Rows: 2  Cols: 4
Names:  +msid+slotid+storage_type+mountpath+
00000:  |1|1|2|/media/drive|
00001:  |2|9|2|/fs/avrcp0|

Query the library table

# qdbc -d mme "select fid,msid,folderid,ftype,filename, title \
    from library where msid=2"
Rows: 1  Cols: 6
Names:  +fid+msid+folderid+ftype+filename+title+
00000:  |2|2|2|5||Bluetooth|

Create a track session and start playback on the Bluetooth device

# mmecli newtrksession l "Select fid from library where msid=2"
(rc=0,errno=0) new trksessionid=2.  Execution Time=0.010

# mmecli settrksession 2
(rc=0,errno=0) Set trksessionid=2.  Execution Time=0.031

# mmecli play
(rc=0,errno=i0) Playing from tracksession fid = 2.  Execution Time=0.038

Getting metadata

The MME has access to metadata for a track on a Bluetooth device only when the device is playing the track. To obtain this metadata, query the MME's nowplaying table.

Audio routing

The MME does not handle audio routing for the io-fs-media module. You must configure your system to properly route audio from Bluetooth devices to the desired output location.