Skip to content

t2bce_audio: playback crackle builds up over minutes and resets on stream restart (timer-driven copy drifts against the T2 read position) — MacBookPro16,2, linux-t2 7.2.4 #28

Description

@Real-Bimox

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).

Activity

  1. 0xFlo commented on Sep 16, 2026

    @0xFlo

    Confirming this on MacBookPro16,1 (16" 2019), same kernel and driver version as your report.

    Model:      MacBookPro16,1 (Mac-E1008331FDC96864)
    Kernel:     7.2.4-arch1-Watanare-T2-2-t2
    Driver:     t2bce_audio 0.02 (staging), srcversion A4BC0767B62E451D7DF4BD7
    Userspace:  PipeWire 1.6.8, WirePlumber 0.5.17
    DSP graph:  /usr/share/t2-linux-audio/16_1/graph.json
    

    Symptoms match yours exactly: playback starts clean, a crackle appears after several minutes and grows, and pausing for more than ~5 seconds clears it completely for another few minutes.

    One extra data point that supports the timer-drift analysis: userspace sees nothing wrong while the crackle is plainly audible. Captured during an active episode:

    $ pw-top -b -n 2
    R   34   1024  48000   1.4ms  71.8us  0.06  0.00    0   S24_32 6 48000 alsa_output.hw_Audio_0
    R   78      0      0   6.1us   1.2ms  0.00  0.05    0         F32P 6 0  + effect_output.t2-161-speakers
    R  143   1024  48000  28.0us  29.5us  0.00  0.00    0    F32LE 2 48000  + Google Chrome
    

    ERR is 0 on every node, and the ALSA buffer never comes close to draining:

    $ cat /proc/asound/card0/pcm0p/sub0/status
    state: RUNNING
    delay       : 1892
    avail       : 14748
    avail_max   : 15660        (buffer_size 16640)
    

    journalctl --user -u pipewire -u wireplumber stays completely silent for the whole episode. So no xrun is ever reported upward, which is what you would expect if the position is synthesised from CLOCK_MONOTONIC rather than read back from the T2. The fabricated period is visible in hw_params too:

    period_size: 1
    buffer_size: 16640
    

    Two things ruled out locally, in case it saves anyone else the detour:

    • Not thermal. This machine idles hot (~70C, dGPU drives the internal panel and cannot runtime-suspend) and that was my first suspicion. It reproduces on a cold machine at idle temperatures, so package throttling is not required.
    • Not userspace scheduling. PipeWire runs SCHED_OTHER nice 0 on every thread here including data-loop.0, because rtkit-daemon is masked on this install. Even so, no node reports a missed deadline during an episode and the DSP chain uses ~1.2ms of a 21.3ms budget, so the audio thread is comfortably keeping up. Whatever is corrupting the stream is below PipeWire.

    I also briefly suspected output level, since the sink was at 1.00 while the 16,1 DSP profile ships state.default-volume = 0.75. A single drop to 0.55 coincided with it clearing, but that was not a controlled test and I would not read anything into it, especially given your note that it reproduces on the raw PCM with the DSP chain bypassed.

    Happy to test a patch on 16,1 if that would help confirm the fix across models.

  2. romanbdotcom commented on Sep 19, 2026

    @romanbdotcom

    Confirm, same happening in here. Macbook Pro 16inch, 2019 model. Linux Debian 13 with KDE.
    Kernel : 7.2.6-1-t2-trixie

  3. michelkroon commented on Sep 19, 2026

    @michelkroon

    Same issue here. Macbook Pro 13inch 2020 model. Fedora 44 with GNOME.
    Kernel: 7.2.6-300.t2.fc44

    I moved back to Kernel: 7.1.9-200.t2.fc44.x86_64 where the issue was not present.

    Don't know what to do for debugging or providing the correct information for the dev's to find the issue unfortunately.

  4. WittyNameHere commented on Sep 21, 2026

    @WittyNameHere

    Same problem here, Macbook Air 2019. Bluefin/Fedora atomic from kansei-os repo. Image includes "t2linux-audio-2.2.0-1.20260917git9527bff.fc44.noarch"

    I found that by changing the power plan to the latency-performance setting (sudo tuned-adm profile latency-performance) I was able to play music from MPV for four hours without detectable distortion.

    Update: Over the past few days it's started so power plans just delay it if anything

  5. tonybo commented on Sep 22, 2026

    @tonybo

    same syndrome here: kernel 7.2.4-arch1-Watanare-T2-2-t2

  6. WittyNameHere commented on Sep 25, 2026

    @WittyNameHere

    Everyone wiith the issue

    Getting PID:

    $ ps -eo pid,rtprio,comm | grep bce_dma
        ###     50 irq/45-bce_dma
    

    The ### is the PID.
    Boost it's scheduling priority:
    $ sudo chrt -f -p 15 ###

    It's not permanent (won't survive a reboot, so jjust do that if you want to undo it), but it can be made permanent if it helps. And I can't promise that it'll get rid if the issue for people who have audio playing endlessly; as it should extend the time needed to kick in, so it's a simple bandage until a kernel patch can solve the bug. For me it at least delays it long enough that I can play streaming audio for five hours without popping and glitching. And it's less obsusive than the only other option I could think of (a timer in cron resetting pipewire every hour, an inelegeant solution.)

  7. deqrocks commented on Sep 28, 2026

    @deqrocks

    This is fixed on latest Kait2en's t2bce_audio and will be pulled to t2linux soon.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions