Bluetooth A2DP and HFP on Qualcomm's Snapdragon
February 28, 2017
The Snapdragon platform has all the necessary components for any kind of audio/voice processing system. This article looks at how you can use a Blueto...
The Snapdragon platform has all the necessary components for any kind of audio/voice processing system. This article looks at how you can use a Bluetooth radio chip with Snapdragon to create a complete Bluetooth audio system.
Using a QCA Bluetooth/Wi-Fi module with Snapdragon is a complete solution for Bluetooth use cases. In this article, we are going to provide some information about audio routing and BlueZ interfacing to make a Snapdragon platform (in this example APQ8009 – 200 series of Snapdragon) a hands-free device. In this platform, we are using WCD9326 with I2S interface as a front-end audio codec.
A QCA module has a bus interface dedicated to the APQ and, using this bus and customized host controller interface (HCI) driver, the user application can communicate with the Bluetooth interface in the same fashion it has before (Figure 1). The interface module has direct access to a low power audio subsystem (LPASS), using shared memory base communication. The LPASS is a Hexagon digital signal processor (DSP), which provides a platform for signal processing applications. This means that whatever processing needs to be done on Bluetooth streams can be done in LPASS, which is part of Snapdragon.
[Figure 1 | User application communicating with Bluetooth interface]
The human-computer interaction (HCI) interface on this platform is a shared, memory-based driver and you can use it with all kinds of Bluetooth stacks. We will be using BlueZ for our example.
Using the Advanced Audio Distribution Profile (A2DP) sink and the Hands-Free Profile (HFP), you could design a Bluetooth speaker/HFP device like those found in most car kits.
A2DP Sink profile
Let’s go through the steps for enabling this profile:
- Enable the profile in BlueZ configuration.
- Enable proper messages in DBus configuration. Add DBus message related to each interface by using
- Start listening to DBus for messages related to requesting connection and provide agent for establishing the connection using
- Register proper endpoint for A2DP sink using
media_register_endpointwith proper UUID for A2DP.
- Wait for set and select configuration messages on DBus, which will be triggered by remote device. Messages like SelectConfiguration will notify the proper setting for SBC codec.
- After configuring the codec (like SBC), listen for play message. After getting SetConfiguration message, open thread for next step.
- BlueZ stack provides file pointer to the audio stream that comes from remote device.
- Open that stream, read packets, decode them, and send them to output audio device.
At this level, the LPASS comes into place and the audio stream will be processed by the DSP. Using a Hexagon DSP with its software development kit (SDK), you can have any customized audio processing before it is passed to the APQ. For example, you can leave the Low Complexity Subband Coding (SBC) decoding to the DSP and/or do some filtering on audio stream. The audio interface on the high-level operating system (HLOS) is a standard one. For example, on Linux/Android, Advanced Linux Sound Architecture (ALSA) is the layer for audio. Using mixer commands on the ALSA side, you can control the audio route and this gives flexibility to the HLOS side.
To setup the speaker route, apply mixer commands to setup the CODEC.
cset "name='MI2S_RX Channels' 1"
cset "name='SLIM RX0 MUX' 1"
cset "name='RX INT7_1 MIX1 INP0' 5"
cset "name='COMP7 Switch' 1"
cset "name='SpkrLeft COMP Switch' 1"
cset "name='SpkrLeft BOOST Switch' 1"
cset "name='SpkrLeft SWR DAC_Port Switch' 1"
cset "name='PRI_MI2S_RX Audio Mixer MultiMedia2' 1"
Now, route the audio stream from the DSP to the speaker using any playback application that sends the stream to MultiMedia2.
Hands Free Profile
As BlueZ stack supports HFP, we can easily setup support for HFP as follows
- Setup BlueZ configuration to support HFP.
- Setup DBus configuration for having HFP messages.
- Set the HCI for voice with proper setting.
hciconfig hci0 class 4C0100
- Listen to pairing request and provide proper agent to complete the pairing.
- Enable Synchronous Connection-Oriented (SCO) connection.
- Wait for BlueZ stack to provide both RFCOMM and SCO sockets.
- When the SCO connection is established, LPASS will have the audio stream, both TX and RX, from Bluetooth interface module.
Now LPASS (Hexagon DSP) comes into place. The audio stream will go through DSP and pass to the APQ. Using existing modules on the DSP, you can easily set up an echo cancelling system for a HFP case. Also, there are existing modules that can be used for noise cancellation or suppression.
amixer cset name='MI2S_RX Channels' 'Two'
amixer cset name='SLIM RX0 MUX' 'AIF1_PB'
amixer cset name='SLIM RX1 MUX' 'AIF1_PB'
amixer cset name='RX INT7_1 MIX1 INP0' 'RX0'
amixer cset name='RX INT8_1 MIX1 INP0' 'RX1'
amixer cset name='COMP7 Switch' 1
amixer cset name='COMP8 Switch' 1
amixer cset name='SpkrLeft COMP Switch' 1
amixer cset name='SpkrLeft BOOST Switch' 1
amixer cset name='SpkrLeft VISENSE Switch' 1
amixer cset name='SpkrLeft SWR DAC_Port Switch' 1
amixer cset name='RX7 Digital Volume' 90
amixer cset name='RX8 Digital Volume' 90
amixer cset name='AIF1_CAP Mixer SLIM TX6' 1
amixer cset name='MI2S_TX Channels' 0
amixer cset name='SLIM TX6 MUX' 2
amixer cset name='ADC MUX6' 0
amixer cset name='DMIC MUX6' 1
amixer cset name='IIR0 INP0 MUX' 7
amixer cset name='PRI_MI2S_RX Port Mixer INTERNAL_BT_SCO_TX' 1
amixer cset name='HFP_INT_UL_HL Switch' 1
amixer cset name='INTERNAL_BT_SCO_RX Audio Mixer MultiMedia6' 1
amixer cset name='MultiMedia6 Mixer QUAT_MI2S_TX' 1
aplay -D hw:0,5 -P &
arec -D hw:0,17 -P -R 8000 -C 1 &
aplay -D hw:0,18 -P &
arec -D hw:0,18 -P -R 8000 -C 1 &
Using this loopback, the audio stream comes from Bluetooth, is routed to speaker and audio streams from the mic, and is routed to Bluetooth.
In all these cases, what you need to do is setup a topology (combination of audio/voice processing modules) in an RX or TX audio path, and define it in a topology. Then, load/send that topology ID to the DSP when it is needed.