LC3 Codec: Overview and Encoder Interfaces

 

LC3 Codec: Overview and Encoder Interfaces
Chapter 2, Sections 2.1 and 2.2 — LC3 Specification v1.0 (Bluetooth SIG)
Series
LC3 Deep Dive
Chapter
2 — Sections 2.1 & 2.2
Level
Beginner–Intermediate

This tutorial introduces the LC3 (Low Complexity Communication Codec) — the audio codec defined for Bluetooth LE Audio. You will learn what LC3 is, why it exists, how it handles audio frames, and exactly what the encoder needs as input and produces as output. No DSP background needed to follow this post.

Keywords

LC3 Codec Bluetooth LE Audio PCM Audio Encoder Interface Frame Duration Bitrate byte_count LE Audio

2.1 What is LC3?

LC3 stands for Low Complexity Communication Codec. It was designed by the Bluetooth SIG (originally for hearing aid applications) and is now the core audio codec for Bluetooth LE Audio. It can encode both speech and music across a wide range of bitrates and sampling frequencies.

Think of LC3 like this: you have raw audio coming in as PCM samples (the same raw format stored in WAV files). LC3 takes a small chunk of that audio (called a frame), compresses it into a small packet of bytes, and sends those bytes over Bluetooth. On the other end, the LC3 decoder reconstructs the audio from those bytes.

The key design goals of LC3 are: low delay, low CPU complexity, and high quality at low bitrates — all critical for battery-powered hearing aids and wireless earbuds.

Frame Intervals and Sampling Frequencies

LC3 processes audio in fixed-size frames. A frame is a block of PCM samples covering either 10 ms or 7.5 ms of audio. You choose one or the other at session setup — it cannot change mid-stream.

For a sampling rate of 44.1 kHz, LC3 uses the same frame size as 48 kHz, which means the actual frame duration is slightly longer: 10.884 ms instead of 10 ms, and 8.163 ms instead of 7.5 ms. This is an important detail when working with 44.1 kHz audio.

Sampling Rate (fs) 10 ms Frame Size (Nf samples) 7.5 ms Frame Size (Nf samples)
8,000 Hz 80 60
16,000 Hz 160 120
24,000 Hz 240 180
32,000 Hz 320 240
44,100 Hz 480 (same as 48k) 360 (same as 48k)
48,000 Hz 480 360

Note: 44.1 kHz uses 480/360 samples but the real-time duration is slightly longer because 480/44100 ≠ 10/1000.

Algorithmic Delay

The Total Codec Algorithmic Delay is the end-to-end delay introduced by encoding + decoding. It equals the frame duration plus an extra look-ahead window that the MDCT (the transform inside the encoder) needs to process a complete frame.

Frame Duration Sampling Rate Total Algorithmic Delay
10 ms 8–48 kHz 12.5 ms
10 ms 44.1 kHz 13.605 ms
7.5 ms 8–48 kHz 11.5 ms
7.5 ms 44.1 kHz 12.517 ms

For real-time applications like hearing aids or Bluetooth calls, 11.5–12.5 ms total delay is excellent. Compare this to older codecs like SBC which can reach 20–30 ms.

Bitrate and Payload Size

LC3 does not have a fixed bitrate. Instead, the profile or application tells the encoder how many bytes to put in each compressed frame. This is called byte_count. The encoder always produces a payload of exactly that many bytes.

Parameter Value What It Means
byte_count range 20 to 400 bytes Per channel, per frame
Bitrate range (10 ms) 16,000 – 320,000 bps 20 bytes × 8 × 100 fps = 16 kbps
Bitrate range (7.5 ms) 21,334 – 426,667 bps Shorter frame = more frames per second
Bitrate mode Constant or variable byte_count can change per frame

The LC3 payload does not include timestamps or sequence numbers. That is handled by the Bluetooth transport layer above it (e.g. the ISO channel in LE Audio).

2.2 Encoder Interfaces

The LC3 encoder works in two phases: session setup (done once at the beginning) and per-frame encoding (done for every audio frame). Here is what each phase requires.

Session Configuration Parameters (set once)

These parameters are fixed for the entire session. Both the encoder and decoder must be configured with the same values (except bits_per_audio_sample which can differ).

Parameter Allowed Values Description
{Fs, Nms, Nf} Fs = 8/16/24/32/44.1/48 kHz
Nms = 7.5 or 10 ms
The sampling rate, frame duration in ms, and resulting frame size in samples. All three must match the decoder.
Nc 1 to Nc_max (set by profile) Number of audio channels. Each channel is encoded independently as a mono stream.
bits_per_audio_sample_enc 16, 24, or 32 bits Bit depth of the input PCM. Can be different from the decoder’s output bit depth.

Per-Frame Inputs (provided for every frame)

Input Size / Range Description
byte_count[Nc] 20 to 400 bytes per channel How many bytes the encoder should produce for this frame, per channel. This controls the bitrate. For mono, it is a single value equal to nbytes.
InputPCM[Nc] Nc × Nf × (bits/8) bytes Raw PCM audio data for all channels. Each channel has Nf samples. Samples are integers in the range [−2^(s-1), 2^(s-1)−1] where s is the bit depth.

Per-Frame Output

Output Size Description
payloadTX[Nc] Exactly byte_count[k] bytes per channel k The compressed audio payload for each channel. The total size for all channels is the sum of all byte_count[k] values. This payload is sent over the Bluetooth LE ISO channel.

The output payload size is always exactly byte_count — the encoder fills the payload to the exact byte boundary. There is no padding or variable-length framing inside the payload itself.

LC3 in BlueZ — Codec Configuration

In BlueZ, the LC3 codec parameters (sampling rate, frame duration, bitrate) are exchanged through the BAP (Basic Audio Profile) codec configuration mechanism. When you register a codec via the BlueZ Media API, you supply a Capabilities structure that encodes these LC3 session parameters as LTV (Length-Type-Value) fields defined in the Bluetooth Assigned Numbers document.

Example: LC3 codec configuration structure used with BlueZ ISO sockets

/* LC3 Codec_Specific_Configuration LTV fields (Bluetooth Assigned Numbers) */
/* These are the session parameters passed to the LC3 encoder at init time   */

struct lc3_config {
    uint8_t  sampling_freq;      /* 0x01 = 8kHz, 0x03 = 16kHz, 0x05 = 24kHz,
                                    0x06 = 32kHz, 0x07 = 44.1kHz, 0x08 = 48kHz */
    uint8_t  frame_duration;     /* 0x00 = 7.5ms, 0x01 = 10ms                   */
    uint8_t  channel_alloc;      /* Audio channel allocation bitmask             */
    uint16_t octets_per_frame;   /* byte_count: 20 to 400                        */
    uint8_t  frames_per_sdu;     /* Number of LC3 frames per Bluetooth SDU       */
};

/* BlueZ ISO socket: set codec config via setsockopt before connect/bind */
struct bt_iso_qos qos = {
    .ucast = {
        .cig  = BT_ISO_QOS_CIG_UNSET,
        .cis  = BT_ISO_QOS_CIS_UNSET,
        .sdu  = 100,   /* octets_per_frame for 48kHz 10ms at ~80kbps */
        .phy  = BT_ISO_PHY_2M,
        .rtn  = 2,
    }
};
setsockopt(fd, SOL_BLUETOOTH, BT_ISO_QOS, &qos, sizeof(qos));

The octets_per_frame field in the codec config maps directly to the LC3 spec’s byte_count parameter — it is what the encoder reads each frame to know how many bytes to produce.

Quick Summary

What Key Point
LC3 is a Block-based transform audio codec designed for Bluetooth LE Audio
Frame durations 7.5 ms or 10 ms — chosen once at session start
Supported sample rates 8 / 16 / 24 / 32 / 44.1 / 48 kHz
Bitrate Controlled by byte_count (20–400 bytes/frame/channel)
Encoder inputs PCM samples + byte_count per frame
Encoder output payloadTX — exactly byte_count bytes per channel
Total delay 11.5 ms (7.5 ms mode) or 12.5 ms (10 ms mode)

Next in this Series

Continue with Section 2.3 and 2.4 — LC3 Fixed vs Variable Bitrate Operation and Decoder Interfaces

Next Tutorial → All Tutorials

Leave a Reply

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