Verdin IMX8MM: configuring BT Audio

Hi,

My goal is to get working Bluetooth audio on the Verdin IMX8MM. I’m using the Verdin development board. The Hands-Free Profile works, and I can initiate and pick up calls from the Verdin module using ofono, but there is no audio. It seems that there is no sound device configured to use the I2S link to the BT module (AW-CM276NF).

I have been experimenting with a custom device tree overlay to use this I2S link for BT audio by creating an extra sound device, but have not been succesful. I have no prior experience with the device tree.

Using the Linux BSP 5.5:
TDX Wayland with XWayland 5.5.0-devel-20211125130402+build.0 (dunfell)
Verdin-iMX8MM_Reference-Minimal-Image

bluez-alsa 1.2.0

I was thinking of using an overlay like this, but as you can see I don’t know how to properly define the codec, routing and widgets. I noticed that pinctrl_wifi_i2s already properly defines the pinmuxing:

/dts-v1/;
/plugin/;

#include <dt-bindings/clock/imx8mm-clock.h>
#include <dt-bindings/gpio/gpio.h>

/ {
	compatible = "toradex,verdin-imx8mm";
};

/* VERDIN I2S_2 */
&sai6 {
	#sound-dai-cells = <0>;
	assigned-clock-parents = <&clk IMX8MM_AUDIO_PLL2_OUT>;
	assigned-clock-rates = <2048000>;
	assigned-clocks = <&clk IMX8MM_CLK_SAI6>;
	pinctrl-names = "default";
	pinctrl-0 = <&pinctrl_wifi_i2s>;
	status = "okay";
};

/ {
	sound_card2: sound-card2 {
		compatible = "simple-audio-card";
		simple-audio-card,bitclock-master = <&dailink_master2>;
		simple-audio-card,format = "i2s";
		simple-audio-card,frame-master = <&dailink_master2>;
		simple-audio-card,name = "imx8mm-aw276nf";
		simple-audio-card,routing =
			"LAUX", "Line In",
			"RAUX", "Line In";
		simple-audio-card,widgets =
			"Line Out", "Line Out",
			"Line", "Line In";
			
		dailink_master2: simple-audio-card,codec {
			sound-dai = <&codec1>;
			clocks = <&clk IMX8MM_CLK_SAI6_ROOT>;
		};
		
		simple-audio-card,cpu {
			sound-dai = <&sai6>;
		};
	};
};

/ {
	codec1: codec1 {
		 compatible = "linux,bt-sco";
		 #sound-dai-cells = <0>;
		 status = "okay";
	};
};

So far I have not been able to get an extra BT audio device to show up with aplay -L.

Is there a step-by-step guide to enabling BT audio?
Do both the mainline and proprietary NXP driver support BT audio?
How should we correctly add the AW-CM276NF PCM audio interface to the device tree?

Thanks for reading and kind regards,

Ernest

Update and small tutorial on how to get (most of) BT Audio working

I’ve been unable for now to get the PCM interface working. With a newer, better device tree overlay I could add another sound device but I haven’t succeeded in communicating over PCM/SAI6 properly.

However, I did get bluetooth audio working over SDIO/HCI. I updated BluezAlsa to v3.1.0 by using the below recipe (updated the Toradex recipe from meta-toradex-demos/recipes-connectivity/bluez-alsa). The old included package is quite out of date (v1.2.0) and misses some patches as well as support for ofono. Note that the Toradex recipe applied a patch file://0001-Fix-linkage-mark-external-variable-as-extern.patch which is out of date.

SUMMARY = "Bluetooth Audio ALSA Backend"
HOMEPAGE = "https://github.com/Arkq/bluez-alsa"
SECTION = "libs"

LICENSE = "MIT"
LIC_FILES_CHKSUM = "file://LICENSE;md5=72d868d66bdd5bf51fe67734431de057"

SRC_URI = " \
    git://github.com/Arkq/bluez-alsa.git;protocol=https;branch=master"
#    file://0001-Fix-linkage-mark-external-variable-as-extern.patch \
#"

SRCREV = "b09f373ea7dbc6e3ecbcb74d7299f5230cdc6e59"

SRC_URI += "file://bluez-alsa.service"

S  = "${WORKDIR}/git"

DEPENDS += "alsa-lib bluez5 systemd glib-2.0 sbc ofono"

PACKAGECONFIG[aac]  = "--enable-aac, --disable-aac, "
PACKAGECONFIG[aptx] = "--enable-aptx,--disable-aptx,"
PACKAGECONFIG[hcitop]   = "--enable-hcitop, --disable-hcitop,  libbsd ncurses"
PACKAGECONFIG[debug] = "--enable-debug, --disable-debug, "
PACKAGECONFIG[ofono] = "--enable-ofono, --disable-ofono, "

inherit autotools pkgconfig
inherit systemd

SYSTEMD_AUTO_ENABLE = "enable"
SYSTEMD_SERVICE_${PN} = "bluez-alsa.service"

PACKAGECONFIG += "hcitop"
PACKAGECONFIG += "debug"
PACKAGECONFIG += "ofono"

do_install_append () {
    install -d ${D}${base_libdir}/systemd/system
    install -m 0644 ${WORKDIR}/bluez-alsa.service ${D}${base_libdir}/systemd/system
}

FILES_${PN} += "\
    ${datadir}/alsa/alsa.conf.d/20-bluealsa.conf\
    ${libdir}/alsa-lib/libasound_module_ctl_bluealsa.so\
    ${libdir}/alsa-lib/libasound_module_pcm_bluealsa.so\
"

FILES_${PN}-staticdev += "\
    ${libdir}/alsa-lib/libasound_module_ctl_bluealsa.a\
    ${libdir}/alsa-lib/libasound_module_pcm_bluealsa.a\
"

What works well:

I now start BluezAlsa as bluealsa -p hfp-ofono -p a2dp-sink -p a2dp-source which allows me to receive A2DP music from a phone and play it back to another bluetooth device acting as an A2DP sink. The ofono integration with the HF profile also works well together with the nau8822 codec on the dev board, I can clearly hear the voice data.

Bug:

When acting as an A2DP sink and receiving data from my phone, and playing it back to the nau8822 as described by the steps below, there is a serious problem with buffer underruns. Every few seconds the buffer is empty. You can hear a noisy discontinuity at that time, and the music is slightly sped up. When BluezAlsa is built with --enable-debug it generates this error:

bluealsa-aplay: D: ../../../git/utils/aplay/aplay.c:471: An underrun has occurred

Strangely, when playing the audio to another BT device (speaker), it sounds just fine.

Using the following line to play to the nau8822 at 32 kHz also works well:

arecord -D bluealsa:DEV=90:78:B2:5A:77:2A,PROFILE=a2dp -f S16_LE -c 2 -r 32000 | aplay

BT Audio: Steps

  • Start BluezAlsa with desired profiles
  • Connect to the bluetooth device via bluetoothctl
  • Reconnect to properly discover services

A2DP

To act as an A2DP sink → source:

  • Run bluealsa-aplay --profile-a2dp & to play received A2DP data to the default device (nau8822)
  • Or, run bluealsa-aplay -D bluealsa:DEV=<MAC>,PROFILE=a2dp --profile-a2dp & to play to another BT device

To act as an A2DP source:

  • aplay -D bluealsa:DEV=<MAC>,PROFILE=a2dp audio_file.wav

For calls (HFP/Ofono):

Same system, but using SCO instead of A2DP. I downloaded the ofono test scripts separately from its repository.

  • Run bluealsa-aplay --profile-sco & to play received SCO (voice) data to the default device (nau8822)
  • Use ofono’s dial-number test script or manually place a call on your (connected) phone
  • After placing the call, route the microphone data to the bluetooth device (bluealsa-aplay is not duplex, see Using BlueALSA with HFP and HSP Devices · Arkq/bluez-alsa Wiki · GitHub for information and the source of this command): { sleep 1; arecord -D plughw:0,0 -t raw -r 8000 -f s16_le -c 1 --period-time=10000 --buffer-time=30000; } | aplay -D bluealsa:DEV=01:23:45:67:89:AB,PROFILE=sco -t raw -f s16_le -c 1 -r 8000 --period-time=20000 --buffer-time=60000

As the last command is quite cumbersome I put it in a file that I execute.

Hi @Ernest!

I would like to really thank you for your nice tutorial on how to get BT Audio to work.

Based on your modification of the bluez-alsa recipe and the rest of the information I could use BT Audio in several different ways:

  • ModuleBT → BT speaker :loud_sound:

  • Phone (Spotify/Youtube/etc or Call) → BTModule → audio file

  • Phone (Spotify/Youtube/etc) → BTModule → Speaker connected to audio output :loud_sound:

  • Phone (Call) → BTModule → Speaker :loud_sound: and Mic :studio_microphone:ModuleBT → Phone (Call)

  • Phone (Spotify/Youtube/etc) → BTModuleBT → BT Headphone :loud_sound:

Using alsaloop (from the same Github Wiki that you referenced) is a great way of making it neat and reusable.

About your An underrun has occurred bug, from what I know, this usually happens when the “amount” of data sent to a sound card is not the “amount” expected. This is the case when e.g. the output expects S16_LE @ 44.1 kHz and receives S16_LE @ 8 kHz.

So, maybe adjusting the sampling could make it work.

Also, as soon as we can, we will create an article describing and explaining all these steps.in

Best regards,

Thanks for the kind words Henrique :slight_smile:

Indeed, using arecord -D bluealsa:DEV=<MAC>,PROFILE=a2dp -f S16_LE -c 2 -r 32000 | aplay to play at 32 kHz does not produce the underrun as noted in my post. With the PCM interface I’m sure a higher sampling rate would be possible.

I’m testing the same steps in Torizon now. Things seem to work similarly and it is easier to set up the packages and compile bluez-alsa inside a privileged Debian container. The a2dp-sink worked fine, but I have to do some further testing on ofono calls today.

1 Like

Everything works on Torizon. Bluez-alsa needs to be compiled without mSBC support as this doesn’t work well with the current Torizon kernel version. If compiled with support it will try mSBC and garble the audio. The downside is that we don’t get the advantages of mSBC and are stuck with 8 kHz audio for calls instead of 16 kHz.

According to borine, Audio playback garbled with mSBC codec · Issue #268 · Arkq/bluez-alsa · GitHub, you need a kernel version of “5.12 and later, 5.10.18 and later, or 5.11.1 and later” to use mSBC.

1 Like

Hi @Ernest !

It is great that you are able to use TorizonCore as well.

Also, just to be sure, you are using the mainline driver or NXP’s proprietary one?

For my tests, the mainline driver worked well (although I had no requirement other than actually being able to listen to music/phonecall and being able to talk something)

Best regards,

Hi @henrique.tx,

Yes, this is all with the mainline driver. We did get access to the NXP driver but then got it working this way, and deemed it unnecessary to try and bring up the PCM interface (which was the reason we were going to mess with the NXP driver in the first place). Our requirements are pretty much the same as yours. It would certainly be interesting to see how to use the PCM interface though!

Kind regards,

Ernest Van Hoecke