3 — Section 3.2
3.2.1 to 3.2.5
Intermediate
This tutorial explains the core parameters that govern how the LC3 codec operates: the supported sampling rates, how bit depth is handled, how frame size is calculated from those parameters, and how the bit budget for a frame is computed. These parameters are the foundation for all encoding and decoding decisions.
3.2.1 Audio Channels
LC3 processes one audio channel at a time. The entire specification describes a single-channel codec. Stereo or multi-channel audio is handled by running multiple independent mono LC3 encoders/decoders in parallel — one per channel. There is no cross-channel coding or joint stereo in LC3 itself. The number of channels (Nc) and any channel relationship is defined by the Bluetooth audio profile above.
3.2.2 Sampling Rates
LC3 supports six sampling rates. For 44.1 kHz, the codec uses the same frame configuration as 48 kHz — this avoids implementing a separate code path. The slightly longer actual frame duration at 44.1 kHz is absorbed by the fscal factor.
A sampling rate index (fsind) is computed to look up parameters from tables throughout the spec:
| fs (Hz) | fsind | fscal | Application |
|---|---|---|---|
| 8,000 | 0 | 1 | NB telephony, hearing aids |
| 16,000 | 1 | 1 | HA-SQ speech quality |
| 24,000 | 2 | 1 | HA-HQ, SSWB audio |
| 32,000 | 3 | 1 | SWB, broadcast quality |
| 44,100 | 4 | 48000/44100 ≈ 1.0884 | CD/music, uses 48k frame config |
| 48,000 | 4 | 1 | FB audio, highest quality |
Note: 44.1 kHz and 48 kHz share the same fsind = 4. The fscal factor is the only difference between the two.
3.2.3 Bits per Sample
The LC3 algorithm is designed to work with input PCM samples in the range:
- Minimum bit depth: 16 bits per sample
- Maximum bit depth: 32 bits per sample
- Typical values: 16, 24, or 32 bits
The encoder’s input bit depth (bits_per_audio_sample_enc) and the decoder’s output bit depth (bits_per_audio_sample_dec) can be different. For example, a 24-bit encoded stream can be decoded to 16-bit output. The scaling is applied at the encoder’s input stage (Section 3.3.3) and at the decoder’s output stage (Section 3.4.10).
3.2.4 Frame Size and Delay
The frame size in samples is calculated directly from the sampling rate and frame duration:
For 48 kHz, 10 ms: NF = (48000 × 1 × 10) / 1000 = 480 samples. For 44.1 kHz, 10 ms: NF = (44100 × 1.0884 × 10) / 1000 = 480 samples (same).
The algorithmic delay D is:
Where Z (leading zeros in the MDCT window) is:
| Frame Duration (Nms) | Z (leading zeros) | Delay D |
|---|---|---|
| 7.5 ms | 7NF / 30 | 11.5 ms (8–48 kHz) / ~12.5 ms (44.1 kHz) |
| 10 ms | 3NF / 8 | 12.5 ms (8–48 kHz) / ~13.6 ms (44.1 kHz) |
The delay is entirely from the MDCT look-ahead (the Z leading zeros in the window). There is no extra processing delay beyond what the transform itself introduces.
3.2.5 Bit Budget and Bitrate
The encoder receives nbytes (the byte_count) as an external input for each frame. This defines the total bit budget for everything: side information, SNS, TNS, LTPF, global gain, and the spectral coefficients themselves.
Key relationships:
bitrate = ⌈ 8000 × nbytes / (Nms × fscal) ⌉ (in bps)
To convert a target bitrate (in bps) to nbytes for session setup:
The result is floored (rounded down) so that nbytes is always an integer. The codec works on byte boundaries — nbytes is always an integer between 20 and 400.
| Frame Mode | Min nbytes | Max nbytes | Bitrate Range |
|---|---|---|---|
| 10 ms | 20 | 400 | 16,000 – 320,000 bps |
| 7.5 ms | 20 | 400 | 21,334 – 426,667 bps |
| 10 ms at 44.1 kHz | 20 | 400 | 14,700 – 294,000 bps |
| 7.5 ms at 44.1 kHz | 20 | 400 | 19,600 – 392,000 bps |
The spec only guarantees verified algorithm behavior in the 20–400 bytes range. Using nbytes outside this range is not supported.
Parameters in BlueZ BAP Configuration
In BlueZ, when you configure an LC3 codec via the BAP (Basic Audio Profile), the parameters from Section 3.2 appear directly in the Codec_Specific_Configuration LTV structure. Here is how they map:
/* Convert desired bitrate to nbytes (LC3 spec Section 3.2.5 formula) */
/* For 48 kHz, 10ms frame at 80 kbps: */
double bitrate = 80000.0; /* bits per second */
double Nms = 10.0; /* frame duration ms */
double fscal = 1.0; /* 1.0 for all rates except 44.1 kHz */
int nbytes = (int)floor(bitrate * Nms * fscal / 8000.0);
/* nbytes = floor(80000 * 10 * 1 / 8000) = floor(100) = 100 bytes */
/* Frame size NF for 48 kHz, 10ms */
int fs = 48000;
int NF = (int)(fs * fscal * Nms / 1000.0); /* = 480 samples */
/* Leading zeros Z for 10 ms frame */
int Z = (3 * NF) / 8; /* = 180 for NF=480 */
/* Algorithmic delay D in ms */
double D = 1000.0 * (2 * NF - 2 * Z) / (double)fs;
/* D = 1000 * (960 - 360) / 48000 = 1000 * 600 / 48000 = 12.5 ms */
/* These values map to BlueZ ISO QoS: */
/* qos.ucast.sdu = nbytes = 100 bytes for this example */
printf("nbytes=%d NF=%d Z=%d delay=%.1fms\n", nbytes, NF, Z, D);
/* Output: nbytes=100 NF=480 Z=180 delay=12.5ms */
Next in this Series
Section 3.3 Encoding Part 1 — Encoder module pipeline, input signal, input scaling, and LD-MDCT analysis
