BAP Part 2 — LC3 Codec & QoS Configurations

 

BAP Part 2 — LC3 Codec & QoS Configurations
Understanding codec naming, LTV structures, and low-latency vs high-reliability settings
LC3
Default Codec
16_2_1
Mandatory Setting
32 kbps
at 16_2_1

What is LC3?

LC3 stands for Low Complexity Communication Codec. It is the default and mandatory codec for BLE Audio. LC3 encodes audio at much lower bitrates than SBC while sounding better. At 32 kbps, LC3 sounds comparable to SBC at 128 kbps.

One important detail: LC3 is a single-channel codec. If you want stereo audio, you run two independent LC3 encoders — one per channel — and multiplex the two codec frames together into one packet called a Media Packet.

LC3 does not define its own transport format. BAP defines a packet format (the LC3 Media Packet) for carrying LC3-encoded data over isochronous streams.

Key Terms

LC3 LTV Structure Codec Setting (e.g. 16_2_1) Sampling Frequency Frame Duration Octets Per Frame SDU Interval Max Transport Latency Retransmission Number Presentation Delay QoS PAC Record

LTV Structures — How Codec Parameters Are Encoded

All codec parameters in BAP are carried in LTV (Length-Type-Value) structures. This is a compact binary format:

Length
1 byte — counts Type + Value bytes
Type
1 byte — identifies which parameter
Value
(Length − 1) bytes — the actual data

For example, the Sampling_Frequency LTV structure for 16 kHz looks like this in raw bytes:

/* LTV for Sampling_Frequency = 16000 Hz */
0x02  /* Length = 2 (1 byte Type + 1 byte Value) */
0x01  /* Type = Sampling_Frequency */
0x03  /* Value = 0x03 = 16000 Hz (see Bluetooth Assigned Numbers) */

/* LTV for Frame_Duration = 10 ms */
0x02  /* Length = 2 */
0x02  /* Type = Frame_Duration */
0x01  /* Value = 0x01 = 10 ms */

/* LTV for Octets_Per_Codec_Frame = 40 octets */
0x03  /* Length = 3 (1 byte Type + 2 bytes Value) */
0x04  /* Type = Octets_Per_Codec_Frame */
0x28 0x00  /* Value = 0x0028 = 40 (little-endian) */

These LTV structures are packed one after another in the Codec_Specific_Configuration field. This field appears inside PAC records (for capabilities) and in ASE characteristics (for active configuration).

Decoding the Codec Setting Name — What Does “16_2_1” Mean?

BAP uses a standardized naming convention for codec and QoS settings. Once you understand it, you can read any setting name at a glance.

16 _ 2 _ 1
16
Sampling Frequency
in kHz
16,000 Hz
2
Frame Duration index
1 = 7.5 ms   2 = 10 ms
10 ms frames
1
QoS Set index
1 = Low latency
2 = High reliability
16_2_1 → 16 kHz, 10 ms frames, 40 octets per frame, low-latency QoS (retransmit = 2, max latency = 10 ms)

Codec Capability Settings at a Glance

The table below shows the main codec settings defined by BAP. 16_2 and 24_2 are the mandatory settings. Everything else is optional.

Setting Freq (kHz) Frame (ms) Octets/Frame Bitrate Mandatory?
8_1 8 7.5 26 27.7 kbps Optional
8_2 8 10 30 24 kbps Optional
16_1 16 7.5 30 32 kbps Optional
16_2 16 10 40 32 kbps ✓ Mandatory
24_1 24 7.5 45 48 kbps Optional
24_2 24 10 60 48 kbps ✓ Mandatory (Sink only)
48_1 48 7.5 75 80 kbps Optional
48_2 48 10 100 80 kbps Optional
48_4 48 10 120 96 kbps Optional
48_6 48 10 155 124 kbps Optional

QoS Parameters — What They Mean

Once codec settings are agreed upon, the Unicast Client submits QoS parameters to the Unicast Server. These parameters control how the isochronous channel behaves in the Link Layer.

SDU_Interval
How often a new audio packet (SDU) is sent. Matches the LC3 frame duration. For 10 ms frames this is 10,000 µs.
Max_Transport_Latency
The maximum time (ms) the controller can take to deliver an SDU from transmitter to receiver, including retransmissions.
Retransmission_Number
How many times the controller retransmits each packet. Higher = more reliable but more bandwidth and latency.
Presentation_Delay
Time (µs) between the SDU sync reference and when the speaker actually plays the audio. Used to synchronize left/right earbuds.

QoS Set 1 vs Set 2 — Low Latency vs High Reliability

_1 (Low Latency)
Retransmit # 2
Max Transport Latency 10 ms (for 16_2)
Use case Voice calls, gaming
Low latency, accepts slightly more risk of lost packets.
_2 (High Reliability)
Retransmit # 13
Max Transport Latency 95 ms (for 16_2)
Use case Media streaming, hearing aids
High reliability, tolerates more latency to ensure every packet arrives.

QoS Settings Reference (selected configurations)

QoS Set Codec SDU Interval Max SDU (octets) Retransmit # Max Latency (ms) Presentation Delay
16_2_1 16_2 10,000 µs 40 2 10 40,000 µs
16_2_2 16_2 10,000 µs 40 13 95 40,000 µs
24_2_1 24_2 10,000 µs 60 2 10 40,000 µs
24_2_2 24_2 10,000 µs 60 13 95 40,000 µs
48_2_1 48_2 10,000 µs 100 5 20 40,000 µs
48_2_2 48_2 10,000 µs 100 13 95 40,000 µs

Presentation Delay — Synchronizing Left and Right Earbuds

Presentation Delay is one of the most important concepts in BLE Audio. It solves the problem of left and right earbuds playing audio at slightly different times.

Phone transmits
SDU
Transport
Latency
Controller
receives SDU
Presentation
Delay
Earbud plays
audio
Also at same
moment ↓
Other earbud
plays audio

The Unicast Client picks a single Presentation_Delay value that falls within the supported range of all Unicast Servers in the same CIG. Both left and right earbuds wait until the same point in time before rendering audio — achieving synchronization without a wired connection.

How Stereo Audio Works — Multi-channel LC3

Because LC3 is mono, stereo is handled by running two LC3 encoders in parallel. BAP defines an Audio_Channel_Allocation LTV to assign each channel to a spatial location (Front Left, Front Right, etc.).

Front Left (FL)
Front Right (FR)
LC3 encoder
LC3 encoder
Media Packet (one SDU)
CF[FL]
CF[FR]
Codec frames ordered lowest to highest
Audio_Channel_Allocation bit index

For a stereo earbud scenario, the phone sends one SDU with two codec frames inside it. The Audio_Channel_Allocation LTV tells the receiver which frame is FL and which is FR. Codec_Frame_Blocks_Per_SDU can be set to >1 if you want to bundle multiple time-periods into one SDU (useful for reducing packet overhead).

BlueZ Code — Setting Up a CIS with QoS 16_2_1

In BlueZ, isochronous streams are set up using ISO sockets introduced in Linux kernel 5.10+. Below is how you configure a CIG with the 16_2_1 settings in C using the BlueZ socket API.

#include <stdio.h>
#include <string.h>
#include <sys/socket.h>
#include <bluetooth/bluetooth.h>
#include <bluetooth/hci.h>
#include <bluetooth/iso.h>   /* BlueZ ISO socket header */

int create_cis_socket_16_2_1(void)
{
    int fd;
    struct sockaddr_iso src_addr = {
        .sa_family = AF_BLUETOOTH,
        .v.cis.dev_id = 0,   /* hci0 */
    };

    /* BT_ISO_QOS for QoS configuration set 16_2_1 */
    struct bt_iso_qos qos = {
        .cig = BT_ISO_QOS_CIG_UNSET,
        .cis = BT_ISO_QOS_CIS_UNSET,
        .in  = {
            .interval    = 10000,   /* SDU interval: 10 ms in µs */
            .latency     = 10,      /* Max transport latency: 10 ms */
            .sdu         = 40,      /* Max SDU size: 40 octets (16_2 codec) */
            .phy         = BT_ISO_PHY_2M,
            .rtn         = 2,       /* Retransmission number: 2 (low latency set _1) */
        },
        .out = {
            .interval    = 10000,
            .latency     = 10,
            .sdu         = 40,
            .phy         = BT_ISO_PHY_2M,
            .rtn         = 2,
        },
    };

    /* Create ISO socket (AF_BLUETOOTH, SOCK_SEQPACKET, BTPROTO_ISO) */
    fd = socket(AF_BLUETOOTH, SOCK_SEQPACKET, BTPROTO_ISO);
    if (fd < 0) {
        perror("socket");
        return -1;
    }

    /* Set QoS options before bind/connect */
    if (setsockopt(fd, SOL_BLUETOOTH, BT_ISO_QOS, &qos, sizeof(qos)) < 0) {
        perror("setsockopt BT_ISO_QOS");
        return -1;
    }

    /* Bind to local adapter */
    if (bind(fd, (struct sockaddr *)&src_addr, sizeof(src_addr)) < 0) {
        perror("bind");
        return -1;
    }

    return fd;  /* ready to connect() to the remote device */
}
Note: The bt_iso_qos structure and BT_ISO_QOS socket option are part of the BlueZ kernel socket API. You need kernel 5.10+ and BlueZ 5.56+ for CIS support. For BIS (broadcast), a different structure bt_iso_qos.bcast is used.

Next: Unicast and Broadcast Streaming Procedures

In Part 3 we walk through the complete step-by-step streaming procedures — the ASE state machine for unicast audio, and the BASE structure and state machine for broadcast audio — with BlueZ examples throughout.

Read Part 3 →

Leave a Reply

Your email address will not be published. Required fields are marked *