BAP Part 5 — The Missing Pieces

 

BAP Part 5 — The Missing Pieces
Context Types, Targeted Announcements, PAC Record Structure, Link Layer Features, ASE Count Rules & GATT Requirements
12
Context Types
64
Min ATT_MTU (octets)
0x01
Targeted Announcement

Why This Part Exists

After reviewing all four previous parts against the full 148-page spec, six important concepts were identified as missing. These are not edge cases — they appear throughout stream setup and capability exchange. A student implementing BAP will hit all six of them within the first few hours of writing code.

This part fills those gaps completely.

Key Terms in This Part

Context Type Supported Audio Contexts Available Audio Contexts Streaming_Audio_Contexts Targeted Announcement General Announcement PAC Record CIS Central / Peripheral Isochronous Broadcaster Synchronized Receiver ATT_MTU EATT Write Long ASE count rule

Gap 1 — Audio Context Types

Context Types are one of the most fundamental concepts in BLE Audio and BAP. They describe what kind of audio is being streamed. A Context Type is a bitmask — each bit represents a different audio use case. Context Types appear in three places:

Supported Audio Contexts
A PACS characteristic. Tells the client which context types this device is permanently capable of handling. Rarely changes.
Available Audio Contexts
A PACS characteristic. Tells the client which context types the device is currently free to handle right now. Changes dynamically. The client subscribes to notifications for this.
Streaming_Audio_Contexts
An LTV structure in the Metadata of the Enable or Update Metadata operation. Tells the server what context type this specific stream is for.

All Context Types (from Bluetooth Assigned Numbers)

Bit Context Type Description / Typical Use
0 Prohibited Never used. Reserved.
1 Unspecified ★ Audio whose context is unknown or not described by any other type. Every Unicast Server and Broadcast Sink must support this bit.
2 Conversational Phone calls, VoIP, video calls — bidirectional voice audio with time-sensitive delivery
3 Media Music, podcast, video playback — general media streaming
4 Game Interactive audio from games where low latency is critical
5 Instructional Verbal instructions, navigation prompts — audio that guides the user
6 Voice Assistants Human-device speech interaction (Siri, Google Assistant, Alexa)
7 Live Live performances, events — audience loop assistive listening (e.g. airport PA, conference)
8 Sound Effects Keyboard clicks, UI sounds, short effects that supplement visual information
9 Notifications Message alerts, email tones
10 Ringtone Incoming call ringtone
11 Alerts Alarms, timers — time-critical audio alerts
12 Emergency Alarm Emergency broadcast — fire alarms, public safety alerts

How Context Types Flow Through a Stream Setup

Step 1 — Unicast Server exposes PACS
Supported_Sink_Contexts = 0x0006
(bits 1+2 set = Unspecified + Conversational)

Available_Sink_Contexts = 0x0006
(currently free for both)

Client reads / gets notifications
Step 2 — Client reads Available Audio Contexts
Client decides to start a phone call. It checks Available_Sink_Contexts, sees Conversational (bit 2) is available.

If bit is 0 → server is busy / unavailable for that context

Enable operation
Step 3 — Client writes Streaming_Audio_Contexts in Enable Metadata
LTV: Type=0x02 (Streaming_Audio_Contexts), Value=0x0004 (bit 2 = Conversational)

Server now knows this CIS is for a phone call

Mandatory context type: Every Unicast Server and Broadcast Sink must support the Unspecified context type (bit 1). If a Unicast Client sends audio with Streaming_Audio_Contexts = Unspecified, the server must accept it. This prevents interoperability failures when context type is unknown.

/* Read Available Audio Contexts characteristic via BlueZ D-Bus
 * UUID: 00002bcd-0000-1000-8000-00805f9b34fb (Available Audio Contexts) */

/* The value is 4 bytes: [Available_Sink_Contexts 2 bytes LE] [Available_Source_Contexts 2 bytes LE] */

/* Example: parse the 4-byte value */
void parse_available_audio_contexts(uint8_t *data, size_t len)
{
    if (len < 4) return;

    uint16_t sink_ctx   = data[0] | (data[1] << 8);
    uint16_t source_ctx = data[2] | (data[3] << 8);

    /* Check if conversational (bit 2 = 0x0004) is available for sink */
    if (sink_ctx & 0x0004)
        printf("Server available for Conversational audio (sink)\n");

    /* Check if media (bit 3 = 0x0008) is available for sink */
    if (sink_ctx & 0x0008)
        printf("Server available for Media audio (sink)\n");

    /* Unspecified (bit 1 = 0x0002) - always mandatory to support */
    if (sink_ctx & 0x0002)
        printf("Server supports Unspecified context (sink)\n");
}

Gap 2 — Targeted vs General Announcements

When a Unicast Server is advertising and available for audio, it must include a specific Service Data AD structure in its Extended Advertising PDUs. This is how a scanning Unicast Client knows — before connecting — whether the server is asking for a connection or just passively available.

Field Size Value / Description
Length 1 byte Length of Type + Value fields
Type 1 byte 0x16 = «Service Data – 16-bit UUID»
ASCS Service UUID 2 bytes 0x184E — identifies this as a BAP Unicast Server
Announcement Type 1 byte 0x00 = General    0x01 = Targeted
Available Audio Contexts 4 bytes The current Available Audio Contexts value (which context types are free right now)
Metadata_Length 1 byte 0x00 if no metadata, else length of following LTV structures
Metadata variable Only present if Metadata_Length ≠ 0x00
General Announcement (0x00)

The server is connectable but not asking for a connection. The phone should only connect if it has audio to send that matches one of the available context types. Example: earbuds in your ears, idle, not on a call — connectable but not demanding attention.

Targeted Announcement (0x01)

The server is actively requesting a connection. Example: earbuds coming out of the case for the first time, or a device that detected an incoming call needs the phone to connect immediately and route audio.

The Unicast Client uses this information to decide whether to connect. If it sees a Targeted Announcement, it should connect immediately. If it sees a General Announcement, it should only connect if it actually has audio of a matching context type to send.

Gap 3 — PAC Record Structure

A PAC (Published Audio Capability) record is the binary structure inside the Sink PAC and Source PAC GATT characteristics. One PAC characteristic can contain multiple PAC records, each describing one set of codec capabilities. A server typically has one record per supported codec (e.g., one for LC3, one for vendor codec).

PAC Characteristic value (can hold 1 or more records)
Record Count (1 byte) Number of PAC records in this characteristic
PAC Record [0]
Codec_ID (5 bytes) Octet 0: Coding_Format (0x06 = LC3)
Octets 1–2: Company ID (0x0000 for standard)
Octets 3–4: Vendor codec ID (0x0000 for standard)
Codec_Specific_Capabilities_Length (1 byte) Length of the following LTV structures
Codec_Specific_Capabilities (variable) LTV structures:
• Supported_Sampling_Frequencies (bitmap)
• Supported_Frame_Durations (bitmap)
• Supported_Audio_Channel_Counts (bitmap, optional)
• Supported_Octets_per_Codec_Frame (min + max, 4 bytes)
Metadata_Length (1 byte) 0x00 if no metadata. Otherwise length of following LTV.
Metadata (variable, optional) Optional LTV: Preferred_Audio_Contexts — hints which context type this PAC record is optimised for

The Supported_Sampling_Frequencies field is a bitmask — one bit per supported frequency. For example, a value of 0x0060 means bits 5 and 6 are set — 16 kHz and 24 kHz are supported. The Unicast Client reads this to know what codec settings it can request.

/* Example raw PAC characteristic value for a Sink PAC
 * supporting LC3 at 16kHz and 24kHz, 7.5ms and 10ms frames, mono only */

uint8_t pac_value[] = {
    0x01,        /* Record_Count = 1 PAC record */

    /* PAC Record 0 */
    0x06,        /* Codec_ID[0]: 0x06 = LC3 */
    0x00, 0x00,  /* Codec_ID[1-2]: Company ID = 0x0000 */
    0x00, 0x00,  /* Codec_ID[3-4]: Vendor codec ID = 0x0000 */

    0x0A,        /* Codec_Specific_Capabilities_Length = 10 bytes */

    /* LTV 1: Supported_Sampling_Frequencies */
    0x03,        /* Length = 3 (1 Type + 2 Value) */
    0x01,        /* Type = Supported_Sampling_Frequencies */
    0x60, 0x00,  /* Value = 0x0060: bits 5+6 = 16kHz + 24kHz */

    /* LTV 2: Supported_Frame_Durations */
    0x02,        /* Length = 2 (1 Type + 1 Value) */
    0x02,        /* Type = Supported_Frame_Durations */
    0x03,        /* Value = 0x03: bits 0+1 = 7.5ms + 10ms supported */

    /* LTV 3: Supported_Octets_per_Codec_Frame */
    0x05,        /* Length = 5 (1 Type + 2+2 Value) */
    0x04,        /* Type = Supported_Octets_per_Codec_Frame */
    0x1E, 0x00,  /* Min = 30 octets (little-endian) */
    0x3C, 0x00,  /* Max = 60 octets (little-endian) */

    0x00,        /* Metadata_Length = 0 (no metadata) */
};

Gap 4 — Link Layer Feature Requirements Per Role

BAP specifies which Bluetooth Link Layer (LL) features must be present in each device depending on its role. These are controller-level capabilities, not host-level. Understanding this table tells you what hardware is actually required for each role.

LL Feature Unicast Server Unicast Client Broadcast Source Broadcast Sink Scan Delegator Broadcast Assistant
LE Encryption M M C M M M
LE Extended Advertising M M M M M M
LE Periodic Advertising X X M M M M
PAST Sender X X X X O O
PAST Recipient X X X X O X
CIS Central X M X X X X
CIS Peripheral M X X X X X
Isochronous Broadcaster X X M X X X
Synchronized Receiver X X X M X O
What this means in practice: If you are building a Unicast Client (phone), your Bluetooth controller must support CIS Central. If you are building a Unicast Server (earbud), the controller must support CIS Peripheral. A Broadcast Source controller must support Isochronous Broadcaster. A Broadcast Sink controller must support Synchronized Receiver. LE Extended Advertising is mandatory for every single role — legacy advertising is not sufficient for BLE Audio.

Gap 5 — How Many ASE Characteristics Must a Server Expose?

This is a rule students always struggle with. The number of Sink ASE and Source ASE GATT characteristics a Unicast Server must expose depends on two things: how many Audio Locations it supports and whether it supports channel multiplexing.

Rule: Number of Sink ASEs Required

Without multiplexing (1 channel per ASE)

Number of Sink ASEs ≥ number of bits set to 1 in Sink Audio Locations

Example: Supports FL + FR (2 locations) → must expose at least 2 Sink ASE characteristics
With multiplexing (N channels per ASE)

Number of Sink ASEs ≥ (number of Audio Locations ÷ max channels per ASE)

Example: 2 locations, max 2 channels/ASE → ⌈2/2⌉ = 1 Sink ASE sufficient

Device Type Audio Locations Multiplexing? Min Sink ASEs
Mono earbud 1 (e.g. FL) No 1
Stereo earbud (Config 6i) 2 (FL + FR) No 2
Stereo earbud (Config 4 — multiplexed) 2 (FL + FR) Yes (2ch/ASE) 1
TWS left earbud (in Config 6ii) 1 (FL only) No 1

Gap 6 — ATT_MTU, EATT, and Required GATT Sub-Procedures

ATT_MTU: Minimum 64 Octets

Both the Unicast Server and Unicast Client must negotiate an ATT_MTU of at least 64 octets. The default ATT_MTU after connection is only 23 octets — too small for BAP operations. The client must send an Exchange MTU request immediately after connection and service discovery.

Why 64? The Config QoS operation for two ASEs in one CIG needs to fit in a single write. The ASE Control Point characteristic value can get long when configuring multiple ASEs at once. If the MTU is too small, the client must use Write Long Characteristic Values (ATT Prepare Write + Execute Write), which is slower.

EATT (Enhanced ATT)

EATT is an optional but important improvement. With standard ATT (Unenhanced ATT), only one request can be in flight at a time — you must wait for a response before sending the next request. EATT opens multiple parallel L2CAP channels (using Enhanced Credit Based Flow Control), allowing multiple GATT operations to be in progress simultaneously. This significantly speeds up service discovery on devices with many characteristics.

Unenhanced ATT (default)

One bearer. Serialized: send request → wait for response → send next. Slower but universally supported.

EATT (optional, recommended)

Multiple parallel bearers. Read multiple characteristics simultaneously. Faster service discovery. Required MTU ≥ 64 on each bearer.

Required GATT Sub-Procedures for Unicast Client

GATT Sub-Procedure Requirement Why it matters
Exchange MTU Mandatory Must be done first to get MTU ≥ 64
Discover All Primary Services C.1 (one of) Find PACS and ASCS services
Discover Primary Services by UUID C.1 (one of) Faster — search directly by PACS/ASCS UUID
Discover All Characteristic Descriptors Mandatory Needed to find CCCD handles for notifications
Read Characteristic Value Mandatory Read PAC records, ASE states, Audio Contexts
Write Characteristic Value Mandatory Write to ASE Control Point
Write Long Characteristic Values Mandatory Needed when Config QoS for multiple ASEs exceeds MTU — uses ATT Prepare Write + Execute Write
Write Without Response Mandatory Some ASE control writes use this path
Notifications Mandatory ASE state changes, ASE Control Point responses, Available Audio Contexts changes
Write Characteristic Descriptors Mandatory Write CCCD = 0x0001 to enable notifications

/* BlueZ: Exchange MTU immediately after connection
 * This must happen before any BAP GATT operations */

#include <bluetooth/gatt.h>

void exchange_mtu(GDBusConnection *conn, const char *device_path)
{
    /* BlueZ handles MTU exchange automatically when using
     * the D-Bus GATT API (AcquireWrite/AcquireNotify).
     * For manual HCI-level control, send ATT_EXCHANGE_MTU_REQ
     * with client_rx_mtu = 512 (or at least 64).
     *
     * The controller must respond with server_rx_mtu.
     * Effective MTU = min(client_rx_mtu, server_rx_mtu).
     * BAP requires effective MTU >= 64 octets. */

    /* Via bluetoothctl you can verify:
     * [bluetooth]# gatt.list-attributes <device>
     * The MTU shown must be >= 64 for BAP to work correctly */
}

Complete Gap Summary — What Was Added in This Part

# Gap Spec Section Why Students Need It
1 Audio Context Types 3.5.2.1, 5.4, 5.5 Appear in every Enable operation Metadata. Without understanding them you cannot set up a stream correctly.
2 Targeted vs General Announcements 3.5.3, Table 3.7 Determines when a phone decides to connect to earbuds. Embedded in the advertising data format.
3 PAC Record Structure 3.5.2, 4.3.1 The binary format you parse when reading PACS. Every PACS implementation reads and writes these.
4 Link Layer Feature Requirements 3.4, Table 3.4 Tells you what Bluetooth controller hardware features are mandatory for each role. Critical for hardware selection.
5 ASE Count Rules 3.5.3 Determines how many ASE GATT characteristics a server must expose based on Audio Locations and channel multiplexing.
6 ATT_MTU, EATT, GATT Sub-Procedures 3.5.1, 3.6.1, 3.6.2, Table 3.8 MTU must be exchanged to ≥ 64 before BAP operations. Write Long is mandatory for multi-ASE Config QoS.

BAP Series Is Now Complete

All five parts together cover the full 148 pages of the BAP spec — roles, services, LC3 codec, QoS settings, audio configurations 1–14, streaming procedures for both unicast and broadcast, GAP connection parameters, security, and now context types, announcements, PAC records, LL features, ASE count rules, and ATT requirements.

BLE Audio Series Bluetooth Classic Series

Leave a Reply

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