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
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:
A PACS characteristic. Tells the client which context types this device is permanently capable of handling. Rarely changes.
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.
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 PACSSupported_Sink_Contexts = 0x0006(bits 1+2 set = Unspecified + Conversational)
|
⟶
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 |
/* 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 |
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.
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 |
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
Number of Sink ASEs ≥ number of bits set to 1 in Sink Audio Locations
Number of Sink ASEs ≥ (number of Audio Locations ÷ max channels per ASE)
| 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.
One bearer. Serialized: send request → wait for response → send next. Slower but universally supported.
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.
