@@ -2542,6 +2542,12 @@ frameworks, so the binary links only what every Mac already has.
25422542 directly, so there is no ` Pa_Terminate() ` /` Pa_Initialize() ` and no index renumbering: the
25432543 listener flags the death off its HAL thread, ` write() ` spends the one in-place reopen, and
25442544 ` poll() ` retries on ` SinkRecovery ` 's backoff.
2545+ - ** A replug is a notification too, not just a timeout.** A dying device says so itself; a
2546+ returning one cannot, so ` kAudioHardwarePropertyDevices ` is listened to as well and
2547+ ` SinkRecovery::rescan_soon() ` brings the owed rescan forward to the next tick. Without it the
2548+ backoff alone decides, and the hardware pass measured what that costs: a device physically back
2549+ at 21 s was not reopened until 41 s, because the 2 s ladder had already doubled past it. The
2550+ attempt still counts against the budget, so a burst of plug events cannot spin.
25452551- ** A moved system default is followed, and is not a recovery.** A bare ` -o coreaudio ` also
25462552 listens on ` kAudioHardwarePropertyDefaultOutputDevice ` ; ` poll() ` reopens on the new device
25472553 with the ring tail accounted as an outage gap. Deliberately outside ` SinkRecovery ` 's budget:
@@ -2592,19 +2598,18 @@ What it proved:
25922598 player in the same group was in phase** , which is the only real test the DAC offset has, and the
25932599 thing item 3 shipped without.
25942600
2595- Still open after that pass:
2596-
2597- - ** The volume ramp.** The full→half change was heard as a step or click. The arithmetic is not at
2598- fault — ` volume_ramp_step(48000) ` is 4473925 Q32/frame and 100→50 is a genuine 621-frame ramp —
2599- and mute, which is the * slowest* ramp at a full 20 ms, was reported clean. The likeliest reading
2600- is the slew rate being fast rather than absent, since ` VOLUME_RAMP_MS ` is a full-scale time and
2601- 100→50 is 12.9 ms. ` open_unit_() ` now logs the step at ` debug ` so the two cases can be told
2602- apart without ears; a second listen is owed before anything is changed, and if it is the slew
2603- rate then it belongs to item 13, which owns it for all three backends.
2604- - ** The outage-gap figure.** The harness's own ` recovery ` driver restarted its pacing clock every
2605- 0.5 s, leaving the ring dry between slices — ~ 5000 ppm of loss and audible popping with no
2606- outage at all, which swamped the measurement. Fixed in the harness; the number is owed from a
2607- re-run. The sink's recovery * mechanisms* are not in doubt, only the accounting figure.
2601+ A second round settled the two things the first left open, and turned up the listener gap above:
2602+
2603+ - ** The volume ramp is fine** , and the first round's "FAIL" was against a wrong expectation: 20 ms
2604+ is what a * full-scale* change takes, so 100→50 is 12.9 ms. ` open_unit_() ` now logs the step at
2605+ ` debug ` (4473925 Q32/frame at 48 kHz, non-zero, so ramping rather than snapping), and mute — the
2606+ largest change and therefore the slowest ramp — is clean. What is audible on full→half is the
2607+ slew rate, which is item 13's and shared by all three backends.
2608+ - ** The outage gap is reported, not swallowed.** Across a ~ 10 s unplug the reported frame count
2609+ froze exactly, then jumped by 33.9 s of audio in one step on replug; of roughly 30 s of silence
2610+ only ~ 84 ms went permanently unaccounted, and the residual is flat rather than growing. The
2611+ first round could not measure this because the harness restarted its pacing clock every 0.5 s
2612+ and lost ~ 5000 ppm of its own.
26082613
26092614Underneath the pass, CI carries the rest: the backend compiles clean under ` -Werror ` on the
26102615` macos-arm64 ` leg, that leg's ` otool -L ` guard reports only CoreAudio, AudioToolbox,
0 commit comments