2026.07.11

from radio to waveform

hardware ~8 min read

getting audio from a phone to a speaker without wires runs through three separate worlds: a radio protocol that agrees on how the two sides talk, a digital bus that shuttles the decoded samples around, and an analog stage that turns numbers back into a voltage.

Bluetooth and the A2DP stack

bluetooth can be seen as an umbrella term; it’s not really its own, singular thing. it encapsulates profiles that have different jobs and bluetooth itself is a protocol for these profiles. the core Bluetooth stack provides the physical radio links and basic data transport. profiles are layered on top as specific job descriptions so that the two connecting devices know exactly what to expect from each other, rather than firing data at one another blindly.

A2DP stands for Advanced Audio Distribution Profile. it strictly handles the heavy lifting of audio streaming, while AVRCP runs in “parallel” to handle the control signals (play, pause, skip, volume).

The Stack underneath A2DP

A2DP → AVDTP → L2CAP |--------SBC codec-------|

A2DP is dictating what is happening. AVDTP and L2CAP are protocols underneath that dictate how it happens.

AVDTP (Audio/Video Distribution Transport Protocol) is responsible for establishing audio endpoints and handles codec negotiation. it asks the sink what it supports, cross-references it with the source, and verifies parameters so that both devices are speaking the same language with one another.

L2CAP (Logical Link Control and Adaptation Protocol) handles the data transport mechanics. it takes the continuous stream of SBC-encoded audio (more on this in a bit), slices it up into specifically sized packets, and puts them on the radio to transmit. it can also act as a multiplexer to juggle multiple streams of data at once (receive dense audio packets and handle control commands simultaneously over the same wireless connection).

SBC (Subband Coding) is the universal codec (coder-decoder) for the A2DP profile. every Bluetooth device is required to support it to guarantee there is a working fallback for any device trying to communicate with another. SBC relies on psychoacoustics to split the audio spectrum into several frequency “subbands” (hence the name). it dynamically assigns fewer bits in frequency bands where human ears struggle to hear differences and saves a lot of bandwidth doing so. SBC is lossy, meaning any data that is removed is permanently destroyed and cannot be recovered by the decoder on the receiving end.

Getting PCM to the DAC: I2S vs SPI

here’s the situation: the decoded PCM is sitting in memory. It needs to get to the DAC. Why not use the SPI peripheral which moves data (bits) between two devices instead of I2S?

The Nature of the Data

when you use SPI to read a sensor or write to flash, timing becomes a constraint. instead of the continuous/real-time timing I2S offers, you are given “bursty” samples. this is because SPI is transaction-oriented by design. It’s great for handling general-purpose data in registers and files because it’s architected around discrete “start/transfer x bytes/stop” operations, but leads to audible clicking/popping in the audio itself because gaps in the audio get created.

this is why I2S is necessary: it’s specifically used for audio streaming and uses a clock that runs continuously at a fixed rate set by the audio, unlike SPI’s clock which is not fixed and reliant on the software’s pacing.

A Stereo Problem

additionally, when working with stereo speakers, the left and right channels need to arrive perfectly sequential. SPI uses a channel-selector GPIO pin, but you cannot just tell the SPI peripheral that X bits from the pin are for the left speaker and the next X bits are for the right speaker. the reason is because SPI uses spatial selection: it is able to select which device is on the bus, such as an SD card, a display, or a sensor, but cannot tell what parts of the data stream correspond to specific channels.

since I2S is specifically for audio streaming, it selects which part of the audio (instead of which device) you are talking to. adding a WS/LCK line, you can categorize LOW as the left channel and HIGH as the right channel to be able to correctly map the stereo audio for the speakers.

How often does the WS line toggle relative to the audio?

WS completes one full cycle per stereo sample pair. since the sample rate is fixed (44.1 kHz), sample rate = WS frequency. then, the bit clock (BCK) has to be fast enough to shift all the bits in that time BCK = sample_rate × bits_per_sample × channels which is 44,100 x 16 x 2 = 1,411,200 bits per second.

in short: the bit clock runs at sample_rate × bits × channels because it must clock out every audio bit in real time; for 16-bit stereo at 44.1 kHz that’s ~1.41 MHz, exactly 32x the word-select clock.

Crossing Into Analog

everything up to this point has been discrete numbers.

the DAC is the boundary between digital and analog signals, though the quality ceiling is determined upstream from the component itself. the compression that occurs (lossy SBC) permanently removes information from the audio being transmitted. A good DAC does its best to keep the ceiling set by the compression.

unlike digital signals, analog signals are continuous. they directly measure and mirror real-world, physical phenomena. in turn, the signal can take on any infinite, fractional value within its given range which gives rise to the issue of noise.

What the DAC Does

simply put, the DAC takes in a sequence of discrete, time spaced values and transforms them into a smooth, continuous waveform that matches the audio being streamed.

now more technical: the DAC takes in discrete pulse code modulation (PCM) samples at an fs (sampling frequency), 44.1 kHz since we’re dealing with CD quality, and turns this into a continuous analog voltage.

why voltage?

voltage helps tremendously when bridging the digital world to the physical one. Speakers, for example, don’t have any digital input. they are fundamentally electromagnetic devices, coils that move in a magnetic field. using Ohm’s law, you can infer that the necessary current going into the speaker is only possible because of a corresponding voltage.

Delta-Sigma At a Conceptual Level

once the DAC takes in these PCM samples coming in over the bus, as stated above briefly, it needs to convert these digital signals into voltage values. getting 16 bit, high-fidelity audio accuracy from a R-2R/resistor-ladder approach (hardware architecture for building a DAC) is unrealistic (demands hyper-precise analog manufacturing), so delta-sigma sidesteps this complexity by trading amplitude resolution for time resolution (fast digital switching and oversampling).

it would be naive to simply take each digital sample and hold the corresponding voltage (until the next sample comes) because this would create a staircase waveform. in this context, the sharp edges would contain the original audio signal + a large amount of image noise. as a result, you’d have to apply an aggressive analog filter to cut everything above a certain frequency, which is 1) very hard to build and 2) introduces phase distortion.

the delta-sigma architecture is used instead and works by oversampling the input data to smoothen the sharp edged staircase waveform (spreads the same amount of information over more time chunks) and using a fast, pre-built quantizer along with a feedback loop to remove the resulting quantization noise out of the audible frequency range for humans and into the ultrasonic range.

no need for a complex filter now. Since the audio and “noise” are separated, you can use a simple, low-pass filter to smooth out the remaining high-frequency noise.

The Clock

a typical I2S DAC needs a fast master clock to run its internal oversampling. normally, the source has to generate and route this as a 4th wire. Tying the SCK pin to GND tells the chip to run its internal phase-locked loop (PLL) instead. A PLL compares its own internally generated clock against an external reference clock. It takes note of if there is clock lag/drift and adjusts a voltage-controlled oscillator (VCO) to speed up/slow down the internal clock to match the reference again.

The payoff is wiring 3 lines instead of 4.

← all notes