BLE Audio course : Roles & Streaming Terminology

BLE Audio course : Roles & Streaming Terminology
CAP · BAP · Core Roles · CIG · CIS · BIG · SDU · PDU
3
Role Layers
CIG/CIS
Unicast Groups
BIG
Broadcast Group

BLE Audio introduces new role names at each layer of the stack and a precise vocabulary for audio streams. Understanding what Initiator, Acceptor, CIS, CIG, and BIG mean is essential before working on any BLE Audio profile or BlueZ implementation.

1. Role Naming Across Layers

Why Three Sets of Names?

Each layer adds more specificity. The same physical device has a different role name at each layer — this is intentional because higher layers define more precise responsibilities.

BLE Audio Role Names Per Layer
Layer Phone / Laptop Side Earbud / Hearing Aid Side
Core (BT Spec) Central
Sends commands
Peripheral
Responds to commands
BAP (Basic Audio Profile) Client
Reads/writes GATT characteristics
Server
Hosts GATT services (ASCS, PACS)
CAP (Common Audio Profile) Initiator
Sets up & schedules Isochronous Streams
Acceptor
Accepts & participates in streams
Key Rule: There is always one Initiator but there can be multiple Acceptors (e.g. left + right earbud). Only Initiators can broadcast audio — when acting as a Broadcast Source they are called Broadcasters.

2. Streaming Terminology

Audio Channel → Audio Stream → Isochronous Stream

BLE Audio uses three nested terms to describe how audio travels. Each has a precise scope:

Audio Data Flow — Terminology Mapping
Audio IN
(Analogue)
LC3
Encode
SDU
Core packs
PDU
Air Tx
PDU
received
LC3
Decode
Audio OUT
(Speaker)
◄─────────────── Isochronous Stream (SDU → PDU transport, retransmissions, sync) ───────────────►
◄──────────────────── Audio Stream (encoded audio over Isochronous Stream, BAP-defined) ────────────────────►
◄────────────────────── Audio Channel (end-to-end: analogue in to analogue out, unidirectional) ──────────────────────►
Term What it covers Direction
Audio Channel Full end-to-end path: analogue IN → BT → analogue OUT. Like a wired headphone connection. Unidirectional
Audio Stream Encoded audio flowing over an Isochronous Stream. Defined in BAP. Goes from encoder output to decoder input. Unidirectional
Isochronous Stream Transport mechanism: SDUs packaged into PDUs, sent over air. Includes retransmissions and buffering for multi-stream sync. Uni or Bi

3. CIG, CIS and BIG — Grouping Streams

Connected Isochronous Group (CIG) and Broadcast Isochronous Group (BIG)

The Core bundles related Isochronous Streams into groups so they share a time reference — critical for synchronized playback on two earbuds.

Unicast vs Broadcast Grouping
UNICAST
CIG
Connected Isochronous Group
CIS 0
CIS 1
Requires ACL connection first.
One or more CISes per CIG.
BROADCAST
BIG
Broadcast Isochronous Group
BIS 0
BIS 1
No ACL connection needed.
Any scanner can receive it.

Phone → Two Earbuds: Bidirectional CIS (Preferred) vs Two Separate CISes
❌ Two Separate CISes (wastes airtime)
📱 Phone
(Initiator)
CIS 0 →
🎧 Earbud
(Acceptor)
← CIS 1
2 separate streams, 2 time slots
✅ Bidirectional CIS (saves airtime)
📱 Phone
(Initiator)
↔ CIS 0
(both directions)
🎧 Earbud
(Acceptor)
1 stream, carries both directions — preferred choice

4. BlueZ: Setting Up a CIS (ISO Socket API)

BlueZ ISO Socket — CIS Connection Example

BlueZ 5.64+ introduced the ISO socket API (BTPROTO_ISO) for CIS and BIS. This maps directly to the CIG/CIS model.

/* Step 1: Create ISO socket (Initiator / Central side) */ int sk = socket(PF_BLUETOOTH, SOCK_SEQPACKET, BTPROTO_ISO); /* Step 2: Bind to local adapter */ struct sockaddr_iso src_addr = { .iso_family = AF_BLUETOOTH, .iso_bdaddr = *BDADDR_ANY, /* local adapter */ .iso_bdaddr_type = BDADDR_LE_PUBLIC, }; bind(sk, (struct sockaddr *)&src_addr, sizeof(src_addr)); /* Step 3: Set QoS parameters — this configures the CIG/CIS */ struct bt_iso_qos qos = { .ucast = { .cig = BT_ISO_QOS_CIG_UNSET, /* kernel picks CIG ID */ .cis = BT_ISO_QOS_CIS_UNSET, /* kernel picks CIS ID */ .sdu = 120, /* max SDU size in bytes (LC3 frame) */ .latency = 10, /* max transport latency in ms */ .rtn = 2, /* retransmission number */ .in = { .phy = BT_ISO_PHY_2M, .sdu = 40 }, /* mic stream */ .out = { .phy = BT_ISO_PHY_2M, .sdu = 120 }, /* speaker */ }, }; setsockopt(sk, SOL_BLUETOOTH, BT_ISO_QOS, &qos, sizeof(qos)); /* Step 4: Connect — triggers HCI LE Set CIG Parameters + LE Create CIS */ struct sockaddr_iso dst_addr = { .iso_family = AF_BLUETOOTH, .iso_bdaddr = remote_bdaddr, /* earbud address */ .iso_bdaddr_type = BDADDR_LE_PUBLIC, }; connect(sk, (struct sockaddr *)&dst_addr, sizeof(dst_addr)); /* Step 5: Send / receive encoded LC3 audio frames */ write(sk, lc3_frame, lc3_frame_len); /* Initiator → Acceptor */ read(sk, buf, sizeof(buf)); /* Acceptor mic → Initiator */
What happens under the hood: The connect() call triggers HCI LE Set CIG Parameters (to configure the CIG at the controller) followed by LE Create CIS. BlueZ maps these automatically from the QoS struct — you don’t write HCI commands manually.
/* For BIS (Broadcast) — Broadcaster side */ int sk = socket(PF_BLUETOOTH, SOCK_SEQPACKET, BTPROTO_ISO); struct bt_iso_qos qos = { .bcast = { .big = BT_ISO_QOS_BIG_UNSET, .bis = BT_ISO_QOS_BIS_UNSET, .sdu = 120, .latency = 10, .rtn = 2, .sync_interval = 0, /* auto */ .out = { .phy = BT_ISO_PHY_2M, .sdu = 120 }, }, }; setsockopt(sk, SOL_BLUETOOTH, BT_ISO_QOS, &qos, sizeof(qos)); /* Bind to adapter and call connect() with BDADDR_ANY to start BIG */ struct sockaddr_iso addr = { .iso_family = AF_BLUETOOTH, .iso_bdaddr = *BDADDR_ANY, .iso_bdaddr_type = BDADDR_LE_PUBLIC, .iso_bc_sid = 0x00, .iso_num_bis = 2, /* left + right earbud streams */ }; bind(sk, (struct sockaddr *)&addr, sizeof(addr)); /* Broadcast source starts sending automatically after bind+listen */

Key Takeaways
Initiator = Central = Client — always sets up the stream
Acceptor = Peripheral = Server — accepts the stream
CIG/CIS = unicast (with ACL) | BIG/BIS = broadcast (no ACL)
Bidirectional CIS preferred — saves airtime vs two CISes
BlueZ uses BTPROTO_ISO sockets — QoS struct maps to HCI CIG params

Leave a Reply

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