AudioHardwareCreateProcessTap delivers all-zero buffers while system audio is audible

Summary

Using AudioHardwareCreateProcessTap + AudioHardwareCreateAggregateDevice for system audio capture. During long sessions, the AudioDeviceIOProc callback continues firing normally but every PCM sample is exactly 0.0f — while the system is producing audible output.


Environment

FieldValue
macOS26.5 Beta
HardwareMacBook Air (M2)
APIAudioHardwareCreateProcessTap + AudioHardwareCreateAggregateDevice
TapCATapDescription, processes = [], .unmuted, private
Format48,000 Hz, Float32, interleaved stereo
Aggregate anchorkAudioAggregateDeviceMainSubDeviceKey = current default output UID

Observed behavior

After running normally for several minutes, the stream transitions into an all-zero state:

  1. AudioDeviceIOProc continues to fire at expected cadence
  2. Frame count, timestamps (mHostTime, mSampleTime), and mDataByteSize all look normal
  3. AudioBufferList pointers are valid
  4. Every sample in every buffer is exactly 0.0f
  5. Other apps are still producing audible output through the same output device
  6. The condition may self-recover or persist until the session is stopped

Confirmed via RMS logging both inside the IOProc and after the ring buffer consumer — data is zero on delivery, not introduced downstream.

Example: 51-minute session on MacBook Air M2

Segment 1 (~7 min): Three all-zero periods: 60 s, 53 s, 141 s. Real PCM briefly returned between them.

Segment 2 (~44 min): Two all-zero periods: 16 min 3 s, 3 min 8 s. IOProc cadence, timestamp deltas, default output UID, and kAudioDevicePropertyDeviceIsRunningSomewhere all remained normal throughout.


What I have ruled out

  • Actual silence: User was in an active video call and could hear participants through the output device.
  • Default output device change: Monitored kAudioHardwarePropertyDefaultOutputDevice — no change during affected periods.
  • IOProc stall: Heartbeat and kAudioDevicePropertyDeviceIsRunningSomewhere remained normal.
  • Aggregate device destroyed: AudioObjectGetPropertyData on the aggregate UID continued returning the expected device.
  • Tap descriptor misconfiguration: The same tap produces valid PCM earlier in the same session, so this is not a startup-time issue.

Why detection is hard

All-zero buffers from a broken tap are indistinguishable from legitimate silence (muted participant, waiting room, paused media). kAudioProcessPropertyIsRunningOutput reports whether a process has active output IO, not whether it is contributing non-zero samples — a muted Zoom call still reports true.


Possible correlations

  • Sample-rate renegotiation on the output device (44.1 kHz ↔ 48 kHz) when another app changes output
  • Bluetooth device state changes (AirPods sleep/wake) where UID stays the same
  • MacBook Air more frequently affected than MacBook Pro
  • Always occurs after extended uptime — first few minutes are consistently clean

Current workaround

Full teardown and rebuild restores real PCM. Restarting the IOProc alone or recreating only the aggregate device is not reliable — both the Process Tap and Aggregate Device must be destroyed and recreated.

1. AudioDeviceStop
2. AudioDeviceDestroyIOProcID
3. AudioHardwareDestroyAggregateDevice
4. AudioHardwareDestroyProcessTap
5. AudioHardwareCreateProcessTap
6. AudioHardwareCreateAggregateDevice
7. Create + start new IOProc

Applying this automatically is risky because it cannot be reliably distinguished from legitimate silence.


Questions

  1. Expected failure mode? Can a Process Tap continue delivering zero-filled buffers while the system output is audible? Is this expected under certain device or routing conditions?

  2. Detection signal? Is there any HAL property, notification, or diagnostic counter that distinguishes "sources are genuinely silent" from "the tap data path has stopped receiving the real mix"?

  3. Targeted recovery? Is there a supported way to re-anchor or reset the tap data path without destroying and recreating both objects?

  4. Full rebuild as intended workaround? If so, it would help to confirm this so developers can converge on a consistent approach.

  5. Mixer activity signal? kAudioProcessPropertyIsRunningOutput reflects IO registration, not sample contribution. Is there any AudioProcess property that indicates a process is currently delivering non-zero audio to the system mixer?

AudioHardwareCreateProcessTap delivers all-zero buffers while system audio is audible
 
 
Q