### Install components
Source: https://github.com/arkq/bluez-alsa/blob/master/INSTALL.md
Install the built components onto the local system.
```sh
sudo make install
```
--------------------------------
### bluetoothctl session example
Source: https://github.com/arkq/bluez-alsa/wiki/Bluetooth-Pairing-And-Connecting
An example session using the bluetoothctl command-line tool for Bluetooth pairing and connection management. Lines starting with '[bluetooth]# ' are user prompts.
```bash
# Start bluetoothctl
[bluetooth]# power on
[bluetooth]# agent on
[bluetooth]# default-agent
# Pair with Bluetooth Headphones
[bluetooth]# scan on
Discovery started
[CHG] Controller C0:25:06:81:23:45 Discovering: yes
[NEW] Device C4:67:B5:37:02:02 Excellent Headset
[bluetooth]# pair C4:67:B5:37:02:02
Attempting to pair with C4:67:B5:37:02:02
[CHG] Device C4:67:B5:37:02:02 Paired: yes
Pairing C4:67:B5:37:02:02: succeeded
# Trust and connect to Headphones
[bluetooth]# trust C4:67:B5:37:02:02
[CHG] Device C4:67:B5:37:02:02 Trusted: yes
Changing C4:67:B5:37:02:02: trusted: yes
[bluetooth]# connect C4:67:B5:37:02:02
Attempting to connect to C4:67:B5:37:02:02
Connection successful
[CHG] Device C4:67:B5:37:02:02 ServicesResolved: yes
# Pair with Mobile Phone (as responder)
# First, make the BlueALSA host discoverable
[bluetooth]# discoverable on
[bluetooth]# pairable on
# On the Mobile Phone, initiate pairing with the BlueALSA host (04:42:1A:55:01:01)
# After the phone prompts for confirmation, accept it.
# Once paired, trust and connect to the phone
[bluetooth]# trust B8:27:EB:B5:03:03
[CHG] Device B8:27:EB:B5:03:03 Trusted: yes
Changing B8:27:EB:B5:03:03: trusted: yes
[bluetooth]# connect B8:27:EB:B5:03:03
Attempting to connect to B8:27:EB:B5:03:03
Connection successful
[CHG] Device B8:27:EB:B5:03:03 ServicesResolved: yes
# Exit bluetoothctl
[bluetooth]# exit
```
--------------------------------
### Fedora Dependencies
Source: https://github.com/arkq/bluez-alsa/wiki/Installation-from-source
Installs the required tools and essential development libraries for Fedora.
```sh
sudo dnf install git automake libtool pkgconfig gcc python3-docutils
sudo dnf install alsa-lib-devel bluez-libs-devel dbus-glib-devel sbc-devel
```
--------------------------------
### Example command to run the script
Source: https://github.com/arkq/bluez-alsa/wiki/Using-BlueALSA-with-HFP-and-HSP-Devices
This example shows how to set environment variables for ALSA devices and latency, and then run the bluealsa-audio-agent script.
```shell
BA_HF_SPEAKER="plughw:0,0" BA_HF_MICROPHONE="plughw:0,0" BA_HF_LATENCY=60 bluealsa-audio-agent
```
--------------------------------
### Debian/Raspberry Pi OS/Ubuntu Dependencies
Source: https://github.com/arkq/bluez-alsa/wiki/Installation-from-source
Installs the required tools and essential development libraries for Debian-based systems.
```sh
sudo apt-get install git automake build-essential libtool pkg-config python3-docutils
sudo apt-get install libasound2-dev libbluetooth-dev libdbus-1-dev libglib2.0-dev libsbc-dev
```
--------------------------------
### Install to a packageable directory
Source: https://github.com/arkq/bluez-alsa/blob/master/INSTALL.md
Install components into a specific directory for packaging and copying to other hosts.
```sh
sudo make DESTDIR=$(pwd)/BLUEALSA install
```
--------------------------------
### Install LC3plus library and header
Source: https://github.com/arkq/bluez-alsa/wiki/Installation-from-source
Commands to manually copy the built LC3plus library and header file to system locations.
```shell
sudo cp libLC3plus.so /usr/local/lib
sudo cp lc3plus.h /usr/local/include
```
--------------------------------
### D-Bus Policy Example
Source: https://github.com/arkq/bluez-alsa/blob/master/INSTALL.md
Example D-Bus policy file required to enable the bluealsad daemon to register with D-Bus as a service. This policy grants permissions for a specific user to own the service and for members of the 'audio' group to use BlueALSA PCMs and mixer.
```xml
```
--------------------------------
### Uninstall and Install
Source: https://github.com/arkq/bluez-alsa/wiki/Migrating-from-release-4.3.1-or-earlier
Instructions for uninstalling the old version and installing the new version of bluez-alsa from source.
```shell
cd
# Uninstall the old version
git checkout v4.3.1 # or earlier used version
make && sudo make uninstall
# Install the new version
git checkout master
make && sudo make install
```
--------------------------------
### PipeWire integration script example
Source: https://github.com/arkq/bluez-alsa/wiki/PulseAudio-integration
A bash script example for automating the addition of BlueALSA devices to PipeWire, with configuration variables.
```bash
#!/bin/bash
# Some variables which can be used to customise this script.
# Select which device types to exclude from loading into pipewire.
# A space separated list of types, where valid types are:
# a2dp_source a2dp_sink sco_source sco_sink
# outputs (speakers, headphones) are "sinks",
# inputs (microphones) are "sources".
# By default no devices are excluded
# For example, to exclude all sources (recommended when using with
# bluealsa-aplay):
# EXCLUDE="a2dp_source sco_source"
EXCLUDE="a2dp_source sco_source sco_sink"
# Change this if you wish to use a different icon for clients such as
# pavucontrol.
ICON_NAME="bluetooth"
# For BlueALSA playback devices only, set this to "yes" to use the most recently
# connected BlueALSA PCM as the PipeWire or PulseAudio default device.
SET_DEFAULT_SINK=yes
```
--------------------------------
### Arch Dependencies
Source: https://github.com/arkq/bluez-alsa/wiki/Installation-from-source
Installs the required tools and essential development libraries for Arch Linux.
```sh
sudo pacman -S git base-devel python-docutils
sudo pacman -S alsa-lib bluez-libs dbus glib2 sbc
```
--------------------------------
### Status command example output
Source: https://github.com/arkq/bluez-alsa/blob/master/doc/bluealsactl.1.rst
Example output for the 'status' command, showing service information, adapters, and profiles.
```text
Service: org.bluealsa
Version: v4.1.1
Adapters: hci0 hci1
Profiles:
A2DP-source : SBC AAC
HFP-AG : CVSD mSBC
HSP-AG : CVSD
```
--------------------------------
### Install BlueALSA to a specific directory
Source: https://github.com/arkq/bluez-alsa/wiki/Installation-from-source
Command to install BlueALSA into a directory tree for transfer to another machine.
```console
make DESTDIR=$(pwd)/BLUEALSA install
```
--------------------------------
### Install required packages
Source: https://github.com/arkq/bluez-alsa/wiki/Setting-up-a-USB-audio-device-as-a-Bluetooth-speaker-under-Ubuntu
Installs the necessary bluez and bluez-alsa-utils packages on Ubuntu 22.04.
```shell
sudo apt install bluez bluez-alsa-utils
```
--------------------------------
### Info command example output for Volume and Mute
Source: https://github.com/arkq/bluez-alsa/blob/master/doc/bluealsactl.1.rst
Example output for the 'info' command showing ChannelMap, Volume, and Mute properties.
```text
ChannelMap: FC FL FR RL RR LFE
Volume: 127 127 127 127 127 127
Mute: off off off off off off
```
--------------------------------
### asym plugin example
Source: https://github.com/arkq/bluez-alsa/wiki/Using-BlueALSA-with-other-ALSA-plugins
This example demonstrates how to use the 'asym' plugin to direct playback streams to a BlueALSA device and capture streams from the system's default microphone.
```alsa
pcm.asym_demo {
type asym
playback.pcm "bluealsa"
capture.pcm "sysdefault"
hint.description "Playback to Bluetooth, capture from local microphone"
}
```
--------------------------------
### file PCM device example with placeholders
Source: https://github.com/arkq/bluez-alsa/wiki/ALSA-devices-with-bluealsa‐aplay
Example of using placeholders in the filename for the file PCM device.
```console
bluealsa-aplay --pcm=file:/tmp/recording-%f-%r-%c.pcm
```
--------------------------------
### Info command example output for Available and Selected codecs (verbose)
Source: https://github.com/arkq/bluez-alsa/blob/master/doc/bluealsactl.1.rst
Example output for the 'info --verbose' command, showing available and selected codecs with their capabilities/configurations.
```text
Available codecs: SBC:ffff02fa AAC:c0ffff035b60
Selected codec: AAC:400084035b60
```
--------------------------------
### Example of changing codec and sample rate
Source: https://github.com/arkq/bluez-alsa/blob/master/doc/bluealsactl.1.rst
This example demonstrates how to change the channel count and sample rate for a specific PCM path using the 'aac' codec.
```bash
bluealsactl codec -c6 -r96000 PCM_PATH aac
```
--------------------------------
### alsaequal plugin examples
Source: https://github.com/arkq/bluez-alsa/wiki/Using-BlueALSA-with-other-ALSA-plugins
Examples of using the alsaequal plugin to pass the PCM stream through a graphic equalizer.
```shell
ctl.bt-headset-equal {
type equal
controls ".alsaequal-bt-headset.bin"
}
pcm.bt-headset-equal {
type plug
slave.pcm {
type equal
slave.pcm {
type plug
slave.pcm {
type bluealsa
device "11:22:33:44:55:66"
profile "a2dp"
}
}
controls ".alsaequal-bt-headset.bin"
}
}
```
--------------------------------
### Example aplay -L output
Source: https://github.com/arkq/bluez-alsa/wiki/Using-BlueALSA-with-dmix
Example output of 'aplay -L' showing a configured Bluetooth audio playback device.
```text
Jabra MOVE v2.3.0 A2DP
Jabra MOVE v2.3.0 (A2DP) Bluetooth Audio Playback
```
--------------------------------
### Example OPTIONS environment variable definition
Source: https://github.com/arkq/bluez-alsa/wiki/|-ARCHIVE:-Systemd-integration-(outdated-and-deprecated)
Example of how to define the OPTIONS environment variable in /etc/default/bluealsa to pass command-line options to bluealsa.
```shell
OPTIONS="-p a2dp-source -p a2dp-sink"
```
--------------------------------
### Starting jackd with BlueALSA backend
Source: https://github.com/arkq/bluez-alsa/wiki/Using-BlueALSA-with-the-JACK-Audio-Connection-Kit
This command starts the jackd server using the ALSA backend and specifying BlueALSA as the playback device.
```console
jackd -r -d alsa -P bluealsa -n 3 -S -o 2
```
--------------------------------
### Example systemd unit file for bluealsa
Source: https://github.com/arkq/bluez-alsa/wiki/|-ARCHIVE:-Systemd-integration-(outdated-and-deprecated)
This is an example unit file to manage bluealsa with systemd, to be saved as /usr/local/lib/systemd/system/bluealsa.service.
```systemd
[Unit]
Description=Bluealsa daemon
Documentation=https://github.com/Arkq/bluez-alsa/
After=dbus-org.bluez.service
Requires=dbus-org.bluez.service
[Service]
Type=dbus
BusName=org.bluealsa
;by default enable A2DP source profile only - can be overridden in the EnvironmentFile
Environment="OPTIONS=--profile=a2dp-source"
EnvironmentFile=-/etc/default/bluealsa
ExecStart=/usr/bin/bluealsa $OPTIONS
Restart=on-failure
ProtectSystem=strict
ProtectHome=true
PrivateTmp=true
PrivateDevices=true
RemoveIPC=true
RestrictAddressFamilies=AF_UNIX AF_BLUETOOTH
; Also non-privileged can user be used
; this example assumes a user and group called 'bluealsa' exist
;User=bluealsa
;Group=bluealsa
;NoNewPrivileges=true
[Install]
WantedBy=bluetooth.target
```
--------------------------------
### file plugin example
Source: https://github.com/arkq/bluez-alsa/wiki/Using-BlueALSA-with-other-ALSA-plugins
This example shows how to use the 'file' plugin to save an audio stream to a WAV file while playing or capturing from the default BlueALSA device.
```alsa
pcm.file_demo {
type file
slave.pcm "bluealsa"
file "file-plugin-demo-%r:%c:%f.wav"
format "wav"
hint.description "Copy bluetooth audio stream to file"
}
```
--------------------------------
### Example override file for enabling aptX codec
Source: https://github.com/arkq/bluez-alsa/wiki/Systemd-integration
An example of a drop-in override file content to enable the aptX codec for the bluealsa service.
```ini
[Service]
ExecStart=
ExecStart=/usr/bin/bluealsad -S -p a2dp-source -p a2dp-sink -c aptx
```
--------------------------------
### Example Usage
Source: https://github.com/arkq/bluez-alsa/blob/master/doc/bluealsa-rfcomm.1.rst
This example shows how to connect to a Bluetooth device using bluealsa-rfcomm and interact with it via RFCOMM terminal commands.
```bash
bluealsa-rfcomm /org/bluealsa/hci0/dev_1C_48_F9_9D_81_5C
1C:48:F9:9D:81:5C> RING
> AT+IPHONEACCEV=2,1,6,2,0
> AT+CKPD=200
disconnected
```
--------------------------------
### Event-driven Example
Source: https://github.com/arkq/bluez-alsa/wiki/Using-the-BlueALSA-D‐Bus-API
This C code demonstrates how to use the BlueALSA ObjectManager to respond to signals from BlueALSA PCMs and RFCOMMs, reporting connection, disconnection, and property change events.
```c
/*
* bluealsa-monitor.c
*
* Print BlueALSA PCM and RFCOMM connection, disconnection and property change
* events.
*/
#include
#include "org.bluealsa.h"
/* Handler called when an object managed by the BlueALSA object manager is
* created. */
static void on_object_added(
GDBusObjectManager* self,
GDBusObject* object,
gpointer user_data) {
BluealsaPCM1 *pcm;
BluealsaRFCOMM1 *rfcomm;
gchar *s;
GVariant *v;
/* The object may be either a PCM or a RFCOMM, so we distinguish
* them by first trying to obtain the PCM1 interface using
* bluealsa_object_get_pcm1(), and if that fails then try to get the
* RFCOMM1 interface using bluealsa_object_get_rfcomm1() */
if ((pcm = bluealsa_object_get_pcm1(BLUEALSA_OBJECT(object)))) {
g_print("PCM added:\n");
g_print("\tobject path: %s\n", g_dbus_object_get_object_path(object));
g_print("\tdevice: %s\n", bluealsa_pcm1_get_device(pcm));
g_print("\ttransport: %s\n", bluealsa_pcm1_get_transport(pcm));
g_print("\tmode: %s\n", bluealsa_pcm1_get_mode(pcm));
g_print("\tsequence number: %u\n", bluealsa_pcm1_get_sequence(pcm));
g_print("\tcodec: %s\n", bluealsa_pcm1_get_codec(pcm));
v = bluealsa_pcm1_get_codec_configuration(pcm);
if (v) {
gsize n;
const guint8 *config = g_variant_get_fixed_array(v, &n, sizeof(guint8));
g_print("\tcodec configuration: ");
for (gsize i = 0; i < n; i++)
g_print("%02hhx", config[i]);
g_print("\n");
}
g_print("\taudio format: %#4x\n", bluealsa_pcm1_get_format(pcm));
g_print("\taudio channels: %u\n", bluealsa_pcm1_get_channels(pcm));
const gchar *const *channel_ptr = bluealsa_pcm1_get_channel_map(pcm);
g_print("\taudio channel map: [ ");
while (channel_ptr && *channel_ptr)
g_print("%s ", *channel_ptr++);
g_print("]\n");
g_print("\taudio rate: %u\n", bluealsa_pcm1_get_rate(pcm));
v = bluealsa_pcm1_get_volume(pcm);
if (v) {
s = g_variant_print(v, FALSE);
g_print("\tvolume: %s\n", s);
g_free(s);
}
g_print("\tsoft volume: %s\n", bluealsa_pcm1_get_soft_volume(pcm) ? "yes" : "no");
g_print("\trunning: %s\n", bluealsa_pcm1_get_running(pcm) ? "yes" : "no");
g_print("\tdelay: %u\n", bluealsa_pcm1_get_delay(pcm));
g_print("\tclient delay: %d\n", bluealsa_pcm1_get_client_delay(pcm));
/* The pcm object remains valid until the profile connection is closed.
* So it is safe to save the pcm pointer for use outside this function,
* until we are notified that it has been removed by the object_removed
* signal. When we are finished with the pcm we free it by
* dereferencing it. In this example we do not use the pcm outside of
* this function, so we dereference it here. */
g_object_unref(pcm);
return;
}
if ((rfcomm = bluealsa_object_get_rfcomm1(BLUEALSA_OBJECT(object)))) {
g_print("RFCOMM added:\n");
g_print("\tobject path: %s\n", g_dbus_object_get_object_path(object));
g_print("\ttransport: %s\n", bluealsa_rfcomm1_get_transport(rfcomm));
g_print("\tbattery charge: %hhd\n", bluealsa_rfcomm1_get_battery(rfcomm));
/* Note: the "Features" property is always empty when the object is
* first added, so we do not report it here. */
/* Just the same as with a pcm object, we dereference the rfcomm
* object when we are finished with it. */
g_object_unref(rfcomm);
return;
}
}
/* Handler called when an object managed by the BlueALSA object manager is
* removed. */
static void on_object_removed(
GDBusObjectManager* self,
GDBusObject* object,
gpointer user_data) {
BluealsaPCM1 *pcm;
BluealsaRFCOMM1 *rfcomm;
if ((pcm = bluealsa_object_peek_pcm1(BLUEALSA_OBJECT(object)))) {
g_print("PCM removed:\n");
g_print("\tobject path: %s\n", g_dbus_object_get_object_path(object));
}
else if ((rfcomm = bluealsa_object_peek_rfcomm1(BLUEALSA_OBJECT(object)))) {
g_print("RFCOMM removed:\n");
g_print("\tobject path: %s\n", g_dbus_object_get_object_path(object));
}
/* Note: if the pcm or rfcomm object was previously saved then it must
* be dereferenced in order to free it. In this example that is not
* necessary.
*/
}
/* Handler called when a Property of an object managed by the BlueALSA object
* manager changes its value. */
static void on_interface_proxy_properties_changed(
GDBusObjectManagerClient *manager,
GDBusObjectProxy *object_proxy,
GDBusProxy *interface_proxy,
GVariant *changed_properties,
const gchar *const *invalidated_properties,
gpointer user_data) {
GVariantIter iter;
gchar *key;
GVariant *value;
gchar *s;
/* Notes:
```
--------------------------------
### Asynchronous GetCodecs Method Call Example
Source: https://github.com/arkq/bluez-alsa/wiki/Using-the-BlueALSA-D‐Bus-API
This C code example demonstrates how to invoke the PCM1 GetCodecs method asynchronously using the BlueALSA D-Bus API. It includes the necessary headers, callback function, and main function to set up the D-Bus proxy and initiate the asynchronous call.
```c
#include
#include "org.bluealsa.h"
static GMainLoop *main_loop = NULL;
static void print_channels(GVariant *channels) {
const guint8 *val;
gsize count;
gsize i;
val = g_variant_get_fixed_array(channels, &count, sizeof(*val));
g_print(" channels:");
for (i = 0; i < count; i++)
g_print(" %hhu", val[i]);
g_print("\n");
}
static void print_rates(GVariant *rates) {
const guint32 *val;
gsize count;
gsize i;
val = g_variant_get_fixed_array(rates, &count, sizeof(*val));
g_print(" rates:");
for (i = 0; i < count; i++)
g_print(" %u", val[i]);
g_print("\n");
}
static void iterate_caps(GVariantIter *capabilities) {
GVariant *value;
gchar *key;
while (g_variant_iter_loop(capabilities, "{sv}", &key, &value)) {
if (g_strcmp0(key, "Channels") == 0)
print_channels(value);
else if (g_strcmp0(key, "Rates") == 0)
print_rates(value);
}
}
/**
* This function is the call-back invoked by D-Bus when the response to the
* GetCodecs request arrives. */
static void get_codecs_result(GObject* source_object, GAsyncResult* res, gpointer data) {
BluealsaPCM1 *pcm = BLUEALSA_PCM1(source_object);
GVariant *out_codecs; /* type="a{sa{sv}}" */
GVariantIter iter;
GVariantIter *caps;
GError *error = NULL;
gchar *codec;
/* Call the appropriate "*_finish()" function to retrieve the result data
* from the result message. */
if (bluealsa_pcm1_call_get_codecs_finish(pcm, &out_codecs, res, &error)) {
g_variant_iter_init(&iter, out_codecs);
while (g_variant_iter_loop(&iter, "{sa{sv}}", &codec, &caps)) {
g_print("%s\n", codec);
iterate_caps(caps);
}
}
else {
g_printerr("GetCodecs failed: %s\n", error->message);
g_error_free(error);
}
/* In this simple example we quit the main loop after we have processed
* the response message. */
g_main_loop_quit(main_loop);
}
int main(int argc, char *argv[]) {
BluealsaPCM1 *pcm = NULL;
const gchar *object_path;
GError *error = NULL;
gpointer user_data = NULL;
if (argc < 2) {
g_print("Usage: %s PCM_PATH\n", argv[0]);
exit(EXIT_FAILURE);
}
object_path = argv[1];
if (!g_variant_is_object_path(object_path)) {
g_print("Invalid object path [%s]\n", object_path);
return(EXIT_FAILURE);
}
pcm = bluealsa_pcm1_proxy_new_for_bus_sync(
G_BUS_TYPE_SYSTEM,
G_DBUS_PROXY_FLAGS_NONE,
"org.bluealsa",
object_path,
NULL,
&error);
if (!pcm) {
if (error)
g_print("Failed to create D-Bus proxy PCM (%s)\n", error->message);
return(EXIT_FAILURE);
}
/* Call the GetCodecs method asynchronously */
bluealsa_pcm1_call_get_codecs(
pcm,
G_DBUS_CALL_FLAGS_NONE,
-1,
NULL,
get_codecs_result,
user_data);
/* Run the glib main loop to collect the method response */
main_loop = g_main_loop_new(NULL, TRUE);
g_main_loop_run(main_loop);
g_object_unref(pcm);
return EXIT_SUCCESS;
}
```
--------------------------------
### Event-Driven Example
Source: https://github.com/arkq/bluez-alsa/wiki/Using-the-BlueALSA-D‐Bus-API
This C code demonstrates an event-driven approach to interacting with the BlueALSA D-Bus API. It connects to the system bus, sets up signal handlers for object additions, removals, and property changes, and then enters a main loop to process events.
```c
static void on_interface_proxy_properties_changed(GDBusProxy *proxy, const gchar *interface_name, GVariant *changed_properties, const gchar *const *invalidated_properties, gpointer user_data) {
GVariantIter iter;
GVariant *value;
const gchar *key;
char *s;
GDBusObjectProxy *object_proxy = G_DBUS_OBJECT_PROXY(g_dbus_proxy_get_object(proxy));
/*
* 1. The property value has already been changed in the associated PCM1 or
* RFCOMM1 object before this handler is called.
*
* 2. If we need to know which object interface this property relates
* to, we can do something like:
*
* if (BLUEALSA_IS_PCM1(interface_proxy)) {
* BluealsaPCM1 *pcm = BLUEALSA_PCM1(interface_proxy);
* ... actions for PCM1 interface
* }
* else if (BLUEALSA_IS_RFCOMM1(interface_proxy)) {
* BluealsaRFCOMM1 *rfcomm = BLUEALSA_RFCOMM1(interface_proxy);
* ... actions for RFCOMM1 interface
* }
*/
g_print("Properties Changed on %s:\n", g_dbus_object_get_object_path(G_DBUS_OBJECT(object_proxy)));
g_variant_iter_init(&iter, changed_properties);
while (g_variant_iter_next(&iter, "{&sv}", &key, &value)){
s = g_variant_print(value, FALSE);
g_print("\t%s: %s\n", key, s);
g_free(s);
g_variant_unref(value);
}
}
int main() {
GDBusObjectManager *manager;
GError *error = NULL;
manager = bluealsa_object_manager_client_new_for_bus_sync(
G_BUS_TYPE_SYSTEM,
G_DBUS_OBJECT_MANAGER_CLIENT_FLAGS_NONE,
"org.bluealsa",
"/org/bluealsa",
NULL,
&error);
if (error) {
g_printerr("Failed to create object manager (%s)\n", error->message);
exit(EXIT_FAILURE);
}
g_signal_connect(manager,
"object-added",
G_CALLBACK(on_object_added),
NULL);
g_signal_connect(manager,
"object-removed",
G_CALLBACK(on_object_removed),
NULL);
g_signal_connect(manager,
"interface_proxy_properties_changed",
G_CALLBACK(on_interface_proxy_properties_changed),
NULL);
GMainLoop *main_loop;
main_loop = g_main_loop_new(NULL, TRUE);
g_main_loop_run(main_loop);
g_object_unref(manager);
return EXIT_SUCCESS;
}
```
--------------------------------
### Display configure help
Source: https://github.com/arkq/bluez-alsa/wiki/Installation-from-source
Command to display all available configure script options and environment variables.
```shell
../configure --help
```
--------------------------------
### List Connected PCMs
Source: https://github.com/arkq/bluez-alsa/wiki/Using-the-BlueALSA-D‐Bus-API
A C example demonstrating how to use the generated ObjectManager code to retrieve and print a list of connected PCM object paths, similar to the functionality of 'bluealsactl list-pcms'.
```c
/*
* bluealsa-list.c
*
* Print a list of connected BlueALSA PCM object paths
*/
#include
#include "org.bluealsa.h"
int main() {
GDBusObjectManager *manager;
GError *error = NULL;
GList *bluealsa_objects = NULL;
manager = bluealsa_object_manager_client_new_for_bus_sync(
G_BUS_TYPE_SYSTEM,
G_DBUS_OBJECT_MANAGER_CLIENT_FLAGS_NONE,
"org.bluealsa",
"/org/bluealsa",
NULL,
&error);
if (error) {
g_printerr("Failed to create object manager client (%s)\n", error->message);
exit(EXIT_FAILURE);
}
bluealsa_objects = g_dbus_object_manager_get_objects(manager);
for (GList *item = g_list_first(bluealsa_objects); item; item = item->next) {
GDBusObject *object = item->data;
if (bluealsa_object_peek_pcm1(BLUEALSA_OBJECT(object)))
g_print("%s\n", g_dbus_object_get_object_path(object));
g_object_unref(object);
}
g_list_free(bluealsa_objects);
g_object_unref(manager);
return EXIT_SUCCESS;
}
```
--------------------------------
### Print the Properties of a connected BlueALSA PCM
Source: https://github.com/arkq/bluez-alsa/wiki/Using-the-BlueALSA-D‐Bus-API
This C example demonstrates how to access a specific BlueALSA PCM using its D-Bus object path and print its properties, including device, transport, mode, codec, format, channels, rate, volume, and supported codecs.
```c
/*
* bluealsa-info.c
*
* Print the Properties of a connected BlueALSA PCM
*/
#include
#include "org.bluealsa.h"
/* Macros to extract loudness and mute component from encoded Volume property */
#define BA_LOUDNESS(x) (x & 0x7F)
#define BA_MUTED(x) (x & 0x80)
/* Convert encoded Format property to name of equivalent ALSA PCM format */
static const gchar *alsa_format_name(guint16 format) {
switch (format) {
case 0x0108:
return "U8";
case 0x8210:
return "S16_LE";
case 0x8318:
return "S24_3LE";
case 0x8418:
return "S24_LE";
case 0x8420:
return "S32_LE";
default:
return "UNKNOWN";
}
}
int main(int argc, char *argv[]) {
BluealsaPCM1 *pcm = NULL;
const gchar *object_path;
const gchar *device;
GVariant *v;
GError *error = NULL;
if (argc < 2) {
g_printerr("Usage: %s PCM_PATH\n", argv[0]);
exit(EXIT_FAILURE);
}
object_path = argv[1];
if (!g_variant_is_object_path(object_path)) {
g_printerr("Invalid object path [%s]\n", object_path);
exit(EXIT_FAILURE);
}
pcm = bluealsa_pcm1_proxy_new_for_bus_sync(
G_BUS_TYPE_SYSTEM,
G_DBUS_PROXY_FLAGS_NONE,
"org.bluealsa",
object_path,
NULL,
&error);
if (!pcm) {
if (error)
g_printerr("Failed to create D-Bus proxy PCM (%s)\n", error->message);
exit(EXIT_FAILURE);
}
g_print("object path: %s\n", object_path);
device = bluealsa_pcm1_get_device(pcm);
if (!device) {
g_printerr("Object path does not represent a connected PCM\n");
exit(EXIT_FAILURE);
}
g_print("device: %s\n", device);
g_print("transport: %s\n", bluealsa_pcm1_get_transport(pcm));
g_print("mode: %s\n", bluealsa_pcm1_get_mode(pcm));
g_print("sequence number: %u\n", bluealsa_pcm1_get_sequence(pcm));
g_print("codec: %s\n", bluealsa_pcm1_get_codec(pcm));
/* The CodecConfiguration property is returned as a GVariant containing an
* array of bytes. Here we print the value as a single hexadecimal string
* (as used by the Bluealsa utility a2dpconf). */
v = bluealsa_pcm1_get_codec_configuration(pcm);
if (v) {
gsize n;
const guint8 *config = g_variant_get_fixed_array(v, &n, sizeof(guint8));
g_print("codec configuration: ");
for (gsize i = 0; i < n; i++)
g_print("%02hhx", config[i]);
g_print("\n");
}
g_print("audio format: %s\n", alsa_format_name(bluealsa_pcm1_get_format(pcm)));
g_print("audio channels: %u\n", bluealsa_pcm1_get_channels(pcm));
const gchar *const *channel_ptr = bluealsa_pcm1_get_channel_map(pcm);
g_print("audio channel map: [ ");
while (channel_ptr && *channel_ptr)
g_print("%s ", *channel_ptr++);
g_print("]\n");
g_print("audio rate: %u\n", bluealsa_pcm1_get_rate(pcm));
/* The Volume property is returned as a GVariant containing an array of
* bytes representing encoded loudness and mute values, one value for each
* channel. */
v = bluealsa_pcm1_get_volume(pcm);
if (v) {
gsize len;
const guint8 *volume = g_variant_get_fixed_array(v, &len, sizeof(guint8));
for (gsize i = 0; i < len; i++)
g_print("volume channel %zu: %hhu%s\n", i,
BA_LOUDNESS(volume[i]),
BA_MUTED(volume[i]) ? " (muted)" : "");
}
g_print("soft volume: %s\n", bluealsa_pcm1_get_soft_volume(pcm) ? "yes" : "no");
g_print("running: %s\n", bluealsa_pcm1_get_running(pcm) ? "yes" : "no");
g_print("delay: %u\n", bluealsa_pcm1_get_delay(pcm));
g_print("client delay: %d\n", bluealsa_pcm1_get_client_delay(pcm));
/* Obtain the set of supported codecs by invoking the GetCodecs method. */
if (bluealsa_pcm1_call_get_codecs_sync(
pcm,
G_DBUS_CALL_FLAGS_NONE,
-1,
&v,
NULL,
&error)) {
GVariantIter iter;
GVariant *child;
gchar *key;
g_print("supported codecs: [");
g_variant_iter_init(&iter, v);
while (g_variant_iter_next(&iter, "{sa{sv}}", &key, &child))
g_print(" %s", key);
g_print(" ]\n");
}
if (error)
g_error_free(error);
g_object_unref(pcm);
return EXIT_SUCCESS;
}
```
--------------------------------
### Makefile for BlueALSA Compilation
Source: https://github.com/arkq/bluez-alsa/wiki/Using-the-BlueALSA-D‐Bus-API
This Makefile compiles the BlueALSA interface XML file and example source files into executable programs. It includes definitions for compiler flags, libraries, and code generation arguments.
```make
IFACE_XML := org.bluealsa.xml
GLIB_CFLAGS := -I/usr/include/gio-unix-2.0 -I/usr/include/glib-2.0 -I/usr/lib/x86_64-linux-gnu/glib-2.0/include -I/usr/include/sysprof-6 -pthread
GLIB_LIBS := -lgio-2.0 -lgobject-2.0 -lglib-2.0
CODEGEN_ARGS := \
--interface-prefix org.bluealsa \
--c-generate-object-manager \
--c-generate-autocleanup all \
--c-namespace Bluealsa \
--glib-min-required 2.64 \
--annotate "org.bluealsa.PCM1:CodecConfiguration" org.gtk.GDBus.C.ForceGVariant yes \
--annotate "org.bluealsa.PCM1:Volume" org.gtk.GDBus.C.ForceGVariant yes
PROGRAMS := bluealsa-list bluealsa-info bluealsa-monitor bluealsa-open bluealsa-async
all: $(PROGRAMS)
bluealsa-list: bluealsa-list.o org.bluealsa.o
$(CC) $(CFLAGS) $(LDFLAGS) -o $@ $^ $(GLIB_LIBS)
bluealsa-info: bluealsa-info.o org.bluealsa.o
$(CC) $(CFLAGS) $(LDFLAGS) -o $@ $^ $(GLIB_LIBS)
bluealsa-monitor: bluealsa-monitor.o org.bluealsa.o
$(CC) $(CFLAGS) $(LDFLAGS) -o $@ $^ $(GLIB_LIBS)
bluealsa-open: bluealsa-open.o org.bluealsa.o
$(CC) $(CFLAGS) $(LDFLAGS) -o $@ $^ $(GLIB_LIBS)
bluealsa-async: bluealsa-async.o org.bluealsa.o
$(CC) $(CFLAGS) -o $@ $^ $(GLIB_LIBS)
org.bluealsa.c: $(IFACE_XML)
gdbus-codegen --body \
$(CODEGEN_ARGS) \
--output $@ $<
org.bluealsa.h: $(IFACE_XML)
gdbus-codegen --header \
$(CODEGEN_ARGS) \
--output $@ $<
org.bluealsa.o: org.bluealsa.c org.bluealsa.h
$(CC) $(CFLAGS) $(GLIB_CFLAGS) -c -o $@ $<
bluealsa-list.o: bluealsa-list.c org.bluealsa.h
$(CC) $(CFLAGS) $(GLIB_CFLAGS) -c -o $@ $<
bluealsa-info.o: bluealsa-info.c org.bluealsa.h
$(CC) $(CFLAGS) $(GLIB_CFLAGS) -c -o $@ $<
bluealsa-monitor.o: bluealsa-monitor.c org.bluealsa.h
$(CC) $(CFLAGS) $(GLIB_CFLAGS) -c -o $@ $<
bluealsa-open.o: bluealsa-open.c org.bluealsa.h
$(CC) $(CFLAGS) $(GLIB_CFLAGS) -c -o $@ $<
bluealsa-async.o: bluealsa-async.c org.bluealsa.h
$(CC) $(CFLAGS) $(GLIB_CFLAGS) -c -o $@ $<
clean:
$(RM) $(PROGRAMS) org.bluealsa.[ch] *.o
```
--------------------------------
### Sending OK after Starting Audio Stream
Source: https://github.com/arkq/bluez-alsa/wiki/Using-BlueALSA-with-HFP-and-HSP-Devices
Example of sending the OK response after the 'real' audio stream has been started, in the context of implementing a gateway device.
```console
user@host:~ bluealsa-rfcomm /org/bluealsa/hci0/dev_01_23_45_67_89_AB
> AT+CKPD=200
01:23:45:67:89:AB> OK
```
--------------------------------
### Sending and receiving PCM audio streams
Source: https://github.com/arkq/bluez-alsa/wiki/Using-the-BlueALSA-D‐Bus-API
This C example demonstrates how to use the PCM Open() method to read and write audio streams, transferring audio between the BlueALSA PCM and standard input or output. This functionality is similar to the `bluealsactl open` command.
```c
/*
* bluealsa-open.c
*
* Transfer raw PCM audio data via stdin or stdout
*/
#include
#include
#include
#include "org.bluealsa.h"
int main(int argc, char *argv[]) {
BluealsaPCM1 *pcm = NULL;
const gchar *object_path;
gint fd_pcm = -1;
gint fd_ctrl = -1;
gboolean needs_drain = FALSE;
gboolean drained = FALSE;
gssize count;
gchar ctrl_response[3] = {0};
GUnixFDList *fd_list = NULL;
GInputStream *input_stream = NULL;
GOutputStream *output_stream = NULL;
GInputStream *input_ctrl = NULL;
GOutputStream *output_ctrl = NULL;
GError *error = NULL;
if (argc < 2) {
g_printerr("Usage: %s PCM_PATH\n", argv[0]);
exit(EXIT_FAILURE);
}
object_path = argv[1];
if (!g_variant_is_object_path(object_path)) {
g_printerr("Invalid object path [%s]\n", object_path);
goto fail;
}
pcm = bluealsa_pcm1_proxy_new_for_bus_sync(
G_BUS_TYPE_SYSTEM,
G_DBUS_PROXY_FLAGS_NONE,
"org.bluealsa",
object_path,
NULL,
&error);
if (!pcm) {
if (error)
g_printerr("Failed to create D-Bus proxy PCM (%s)\n", error->message);
goto fail;
}
if (!(bluealsa_pcm1_call_open_sync(
pcm,
G_DBUS_CALL_FLAGS_NONE,
-1,
NULL,
NULL,
NULL,
&fd_list,
NULL,
&error))) {
if (error)
g_printerr("Unable to open PCM (%s)\n", error->message);
goto fail;
}
fd_pcm = g_unix_fd_list_get(fd_list, 0, &error);
fd_ctrl = g_unix_fd_list_get(fd_list, 1, &error);
g_object_unref(fd_list);
if (strcmp(bluealsa_pcm1_get_mode(pcm), "source") == 0) {
input_stream = g_unix_input_stream_new(fd_pcm, TRUE);
output_stream = g_unix_output_stream_new(STDOUT_FILENO, FALSE);
}
else {
input_stream = g_unix_input_stream_new(STDIN_FILENO, FALSE);
output_stream = g_unix_output_stream_new(fd_pcm, TRUE);
needs_drain = TRUE;
}
input_ctrl = g_unix_input_stream_new(fd_ctrl, TRUE);
output_ctrl = g_unix_output_stream_new(fd_ctrl, TRUE);
count = 0;
do {
count = g_output_stream_splice(
output_stream,
input_stream,
G_OUTPUT_STREAM_SPLICE_NONE,
NULL,
&error);
}
while (count > 0);
if (count == 0 && needs_drain) {
if (g_output_stream_write(output_ctrl, "Drain", 5, NULL, &error) == 5) {
if (g_input_stream_read(input_ctrl, ctrl_response, 2, NULL, &error) == 2 &&
* "Sending and receiving PCM audio streams"
```
--------------------------------
### Optimize for minimum size
Source: https://github.com/arkq/bluez-alsa/wiki/Installation-from-source
Compile BlueALSA with optimization flags for minimum size.
```console
make CFLAGS="-Os -s"
```
--------------------------------
### Configure with options
Source: https://github.com/arkq/bluez-alsa/blob/master/INSTALL.md
After choosing desired options, create a build directory and run configure.
```sh
mkdir build && cd build
../configure [ OPTION ... ]
```
--------------------------------
### Emulate Bluetooth headset with A2DP and HSP support
Source: https://github.com/arkq/bluez-alsa/blob/master/doc/bluealsad.8.rst
This example shows how to start the bluealsad daemon to emulate a Bluetooth headset with A2DP and HSP support.
```bash
bluealsad -p a2dp-sink -p hsp-hs
```
--------------------------------
### View all configuration options
Source: https://github.com/arkq/bluez-alsa/blob/master/INSTALL.md
Run this command to see a complete list of all available configuration options.
```sh
./configure --help
```
--------------------------------
### Optimize for speed and size compromise
Source: https://github.com/arkq/bluez-alsa/wiki/Installation-from-source
Compile BlueALSA with optimization flags for a balance between speed and size.
```console
make CFLAGS="-O2 -s"
```
--------------------------------
### Defining a new PCM with bluealsa slave and hints
Source: https://github.com/arkq/bluez-alsa/wiki/|-ARCHIVE:-Using-the-BlueALSA-ALSA-pcm-plugin
Example of defining a new PCM entry with a bluealsa slave and a 'show on' hint.
```shell
pcm.bt-headphones {
type plug
slave.pcm {
type bluealsa
device "00:11:22:33:44:55"
profile "a2dp"
}
hint {
show on
description "My Bluetooth headphones"
}
}
```
--------------------------------
### Optimize for maximum speed
Source: https://github.com/arkq/bluez-alsa/wiki/Installation-from-source
Compile BlueALSA with optimization flags for maximum speed.
```console
make CFLAGS="-Ofast -s"
```
--------------------------------
### Create Build Directory
Source: https://github.com/arkq/bluez-alsa/wiki/Installation-from-source
Creates a new directory for the build products, keeping them separate from the source code.
```sh
mkdir build
cd build
```
--------------------------------
### sysdefault PCM device example
Source: https://github.com/arkq/bluez-alsa/wiki/ALSA-devices-with-bluealsa‐aplay
Example of how to use the sysdefault PCM device with a specific card.
```console
bluealsa-aplay --pcm=sysdefault:CARD=1
```
--------------------------------
### Example PropertyChanged Event
Source: https://github.com/arkq/bluez-alsa/blob/master/doc/bluealsactl.1.rst
An example of how the PropertyChanged event is displayed for a stereo A2DP PCM with the right channel muted.
```text
PropertyChanged PCM_PATH Volume 127 127[M]
```
--------------------------------
### Build LC3plus shared library
Source: https://github.com/arkq/bluez-alsa/wiki/Installation-from-source
Command to build the LC3plus shared library from source.
```console
make libLC3plus.so
```
--------------------------------
### Release build with AAC, aptX, oFono, and mSBC
Source: https://github.com/arkq/bluez-alsa/wiki/Installation-from-source
Generates a release build with support for AAC, aptX, oFono, and mSBC.
```shell
../configure --enable-aac --enable-aptx --with-libopenaptx --enable-ofono --enable-msbc
```
--------------------------------
### vdownmix plugin examples
Source: https://github.com/arkq/bluez-alsa/wiki/Using-BlueALSA-with-other-ALSA-plugins
Examples of using the vdownmix plugin to convert multi-channel streams to stereo.
```shell
pcm.!bluealsa_surround40 {
type plug
slave {
channels 4
pcm {
type vdownmix
slave.pcm bluealsa
}
}
}
pcm.!bluealsa_surround51 {
type plug
slave {
channels 6
pcm {
type vdownmix
slave.pcm bluealsa
}
}
}
```
--------------------------------
### Loopback device with format conversion using plug plugin
Source: https://github.com/arkq/bluez-alsa/wiki/Using-BlueALSA-with-dmix
This example demonstrates using the Loopback device with format conversion. The capture side is set to a specific format, and the playback side uses the 'plug' plugin for conversion.
```shell
arecord -f float_le -c 2 -r 8000 -D hw:Loopback,1 capture.wav &
aplay -D plughw:Loopback,0 /usr/share/sounds/alsa/Front_Center.wav
```
--------------------------------
### Example ALSA pcm configuration
Source: https://github.com/arkq/bluez-alsa/wiki/Using-BlueALSA-with-dmix
Example of how an ALSA pcm configuration appears for a connected Bluetooth device.
```text
Simple mixer control 'Jabra MOVE v2.3.0 A2DP',0
```
--------------------------------
### Optimize for debugging
Source: https://github.com/arkq/bluez-alsa/wiki/Installation-from-source
Compile BlueALSA with optimization flags for debugging.
```console
make CFLAGS="-Og -g"
```
--------------------------------
### Clone BlueALSA Source Code
Source: https://github.com/arkq/bluez-alsa/wiki/Installation-from-source
Clones the BlueALSA source code from Github and navigates into the directory.
```sh
git clone https://github.com/arkq/bluez-alsa.git
cd bluez-alsa
```
--------------------------------
### Stream format identifier example 2
Source: https://github.com/arkq/bluez-alsa/blob/master/doc/org.bluealsa.PCM1.7.rst
Example of a stream format identifier: signed 24-bit 4 bytes little-endian.
```text
0x8418 - signed 24-bit 4 bytes little-endian
```
--------------------------------
### Stream format identifier example 1
Source: https://github.com/arkq/bluez-alsa/blob/master/doc/org.bluealsa.PCM1.7.rst
Example of a stream format identifier: unsigned 16-bit 2 bytes big-endian.
```text
0x4210 - unsigned 16-bit 2 bytes big-endian
```
--------------------------------
### Start BlueALSA manually from the command line
Source: https://github.com/arkq/bluez-alsa/wiki/|-ARCHIVE:-Systemd-integration-(outdated-and-deprecated)
Commands to start and stop the bluealsa.service using systemctl.
```bash
sudo systemctl start bluealsa.service
```
```bash
sudo systemctl stop bluealsa.service
```
--------------------------------
### Simple debug build
Source: https://github.com/arkq/bluez-alsa/wiki/Installation-from-source
Generates a simple debug build without additional options.
```shell
../configure --enable-debug
```
--------------------------------
### Compile the project
Source: https://github.com/arkq/bluez-alsa/blob/master/INSTALL.md
Run this command in the build directory to compile the project.
```sh
make
```