Hardware: MacBookPro16,2 (13" 2020, T2). Kernel: linux-t2 7.2.4.arch1-2 (Watanare), t2bce_audio v0.02 (staging).
Userspace: PipeWire 1.6.8, WirePlumber 0.5.17, t2-apple-audio-dsp 16_2 graph (also reproduces on the raw PCM without DSP).
Symptom
Playback starts clean. After some minutes a crackle appears, grows steadily, becomes louder than the programme material, and vanishes instantly whenever the stream stops and restarts (e.g. a YouTube ad, loading a new video, pause/resume > 5 s). Then it builds up again.
Evidence
- PipeWire graph: 0 xruns, steady ~70 ms ALSA queue (
/proc/asound/card0/pcm0p/sub0/status sampled every 5 s for a minute), CPU idle.
- The digital signal captured at the ALSA node monitor is clean while the crackle is audible (no clipping, no discontinuities, kurtosis ~2.2, no impulsive outliers) -> the artefact is created below the ALSA node.
hw_params: period_size: 1, buffer_size: 16640, SNDRV_PCM_INFO_NO_PERIOD_WAKEUP.
- Reported pointer advance rate inside one session: 47999.61 frames/s (-8 ppm) measured against the driver's own
tstamp.
Root cause (from t2bce_audio/pcm.c at AdityaGarg8/t2bce 525498b5, "Update 1", 2026-09-13)
t2audio_playback_timer() runs every 1 ms (T2AUDIO_PLAYBACK_TICK_NS) and does
frames = elapsed_ns * runtime->rate / NSEC_PER_SEC, then t2audio_playback_copy() copies that many frames from the ALSA ring into the BCE shared buffer (buf->ptr) at bridge_pos, and t2audio_pcm_pointer() returns playback_frames % buffer_size.
The host-side write position is therefore driven purely by CLOCK_MONOTONIC, while the T2 consumes the shared buffer on its own audio clock. There is no feedback from the T2 on the playback path. Commit ab4b0ac2 ("correlate host and remote clock") only feeds the remote timestamps into the capture pointer (time_from_start = ktime_get_boottime() - stream->remote_timestamp); the playback branch of t2audio_pcm_pointer() still returns the timer-driven playback_frames. Any ppm difference between the two clocks accumulates: the copy position slowly walks into the T2's read position, first producing partial-buffer reads (crackle that grows with signal level), then full overlap. A stop/start (started cleared, bridge_pos/playback_frames reset) realigns the two positions, which is why the symptom resets on every stream restart. With a ~70 ms host lead and tens of ppm of drift, onset after 10-30 minutes matches what is observed.
Suggested fix
Rate-correct the host copy against T2 feedback (consumed position or the same remote timestamps the capture path already uses), or expose a real DMA position instead of a timer estimate; alternatively track the T2's read position and clamp bridge_pos so the host never overtakes it. Also consider a larger period_size (the current 1-frame period makes the ALSA core register a ~21 us CPU latency PM-QoS while the PCM is open, which blocks C2/C3 and heats the machine).
Workaround
Pausing playback for >5 s (so PipeWire stops/restarts the PCM) clears the crackle.
Filed here because issues are disabled on AdityaGarg8/t2bce and deqrocks/t2bce. Happy to test patches on this machine (Arch, linux-t2 from the arch-mact2 repo).
Hardware: MacBookPro16,2 (13" 2020, T2). Kernel: linux-t2 7.2.4.arch1-2 (Watanare),
t2bce_audiov0.02 (staging).Userspace: PipeWire 1.6.8, WirePlumber 0.5.17, t2-apple-audio-dsp 16_2 graph (also reproduces on the raw PCM without DSP).
Symptom
Playback starts clean. After some minutes a crackle appears, grows steadily, becomes louder than the programme material, and vanishes instantly whenever the stream stops and restarts (e.g. a YouTube ad, loading a new video, pause/resume > 5 s). Then it builds up again.
Evidence
/proc/asound/card0/pcm0p/sub0/statussampled every 5 s for a minute), CPU idle.hw_params:period_size: 1,buffer_size: 16640,SNDRV_PCM_INFO_NO_PERIOD_WAKEUP.tstamp.Root cause (from
t2bce_audio/pcm.cat AdityaGarg8/t2bce525498b5, "Update 1", 2026-09-13)t2audio_playback_timer()runs every 1 ms (T2AUDIO_PLAYBACK_TICK_NS) and doesframes = elapsed_ns * runtime->rate / NSEC_PER_SEC, thent2audio_playback_copy()copies that many frames from the ALSA ring into the BCE shared buffer (buf->ptr) atbridge_pos, andt2audio_pcm_pointer()returnsplayback_frames % buffer_size.The host-side write position is therefore driven purely by CLOCK_MONOTONIC, while the T2 consumes the shared buffer on its own audio clock. There is no feedback from the T2 on the playback path. Commit
ab4b0ac2("correlate host and remote clock") only feeds the remote timestamps into the capture pointer (time_from_start = ktime_get_boottime() - stream->remote_timestamp); the playback branch oft2audio_pcm_pointer()still returns the timer-drivenplayback_frames. Any ppm difference between the two clocks accumulates: the copy position slowly walks into the T2's read position, first producing partial-buffer reads (crackle that grows with signal level), then full overlap. A stop/start (startedcleared,bridge_pos/playback_framesreset) realigns the two positions, which is why the symptom resets on every stream restart. With a ~70 ms host lead and tens of ppm of drift, onset after 10-30 minutes matches what is observed.Suggested fix
Rate-correct the host copy against T2 feedback (consumed position or the same remote timestamps the capture path already uses), or expose a real DMA position instead of a timer estimate; alternatively track the T2's read position and clamp
bridge_posso the host never overtakes it. Also consider a largerperiod_size(the current 1-frame period makes the ALSA core register a ~21 us CPU latency PM-QoS while the PCM is open, which blocks C2/C3 and heats the machine).Workaround
Pausing playback for >5 s (so PipeWire stops/restarts the PCM) clears the crackle.
Filed here because issues are disabled on
AdityaGarg8/t2bceanddeqrocks/t2bce. Happy to test patches on this machine (Arch,linux-t2from the arch-mact2 repo).