Repository navigation
fix(dice): publish unconfirmed-clock devices and offer every CLOCK_CAPS rate without EAP (#189, #223) - #222
Merged
Merged
Conversation
The 2626 is the first captured DICE device with no catalog row: it publishes through the generic DICE fallback. Two streams each way (16 + 10 PCM, MIDI on stream 0), no EAP, and its firmware lists 8 clock source names, not 13. pydice accepted only 13; it now accepts 1 to 13. The fixture is the build-19 report from the issue (the build-33 report has the same registers in a newer format pydice does not parse yet). SessionShape can carry a real GUID, and with it the unit directory's Model_ID: the generic fallback checks the GUID's DICE layout, which the synthetic OUI-prefixed GUID does not follow. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Since 21e01580 (between builds 19 and 21) publication waits for clock
preparation, and any failure there refused the device ("geometry load
failed") with no retry until the next bus reset. Issue #189: a
FireStudio 2626 published on build 19 and no longer appeared in
CoreAudio; its build-33 dump shows our owner claim and CLOCK_ACCEPTED,
then nothing.
The preparation made fatal what the TCAT driver treats as advisory.
PaeFireStudio RestartStreaming (0xd8e2), the driver this device shipped
with, waits up to 150 ms for CLOCK_ACCEPTED and up to 1 s for lock,
keeps waiting through a failed STATUS read, logs a timeout and creates
the streams anyway; only a failed write stops it. 21e01580 itself
describes the lock wait as advisory. Ours ended on one failed GLOBAL
poll read, on no acceptance within 150 ms, and at the 3 s deadline.
Now:
- a failed GLOBAL poll read is retried until the deadline; a stale
generation or a cancellation still ends the preparation;
- 150 ms without CLOCK_ACCEPTED logs and goes on to wait for a settled
STATUS, as before;
- at the deadline the preparation logs the last GLOBAL state and
completes, so the device is described and published.
Failed writes, a foreign owner and an unsupported version still fail.
Stream start keeps its own lock gate: an unlocked device is published
but not enabled (clock-never-locks goldens: the start now runs and
times out on that gate, ending with ENABLE=0 and no streams, as before).
Which failure the 2626 hit is not known without its log; the tests
cover each one on its captured registers.
Tests: a failed poll read (busy, timeout) and an unconfirmed clock on
the 2626 image complete; the 2626 is published through a failed poll
read via the DICE adapter; an unlocked Venice F24 completes preparation
and its start does not enable. All four fail on the old code, the
adapter test with "geometry-load-failed".
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A DICE device without EAP describes its channel layout only for the current rate, so only the attach rate was ever offered (ZED-R16 in #223, FireStudio 2626 in #189). Follow the TCAT driver instead: announce every CLOCK_CAPS rate, set the clock, then read the layout (Saffire.kext performFormatChange -> RestartStreaming -> PopulateDeviceStruct -> CreateStreams). - A rate with an unread layout carries the current layout as a placeholder (RateFormation::layoutProvisional) for the HAL format list. - A host rate change to it reads the layout once the clock locks and installs only that measured layout; an unreadable one rolls back. - A placeholder never replaces a measured layout, also after a bus reset. - Capacity for a placeholder is reserved at the protocol limit, so a device attached at 2x can still switch to 1x. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes the regression reported in #189, and offers every supported rate on DICE devices without EAP (#223): a PreSonus FireStudio 2626 appeared in CoreAudio on build 19 and not on builds 21 or 33.
Cause
Since 21e01580 (between builds 19 and 21), a DICE device is published only after clock preparation succeeds: owner claim,
GLOBAL_ENABLE=0,CLOCK_SELECT, then polling GLOBAL until the clock is confirmed. Any failure there refused the device (geometry-load-failed), and nothing retried until the next bus reset. The build-33 dump in #189 shows our owner claim andCLOCK_ACCEPTED, then nothing.The preparation made fatal what the TCAT driver treats as advisory. PaeFireStudio
RestartStreaming(0xd8e2), the driver this device shipped with, waits up to 150 ms forCLOCK_ACCEPTEDand up to 1 s for lock, keeps waiting through a failed STATUS read, logs a timeout and creates the streams anyway. Only a failed write stops it. Ours ended on a single failed GLOBAL poll read, on no acceptance within 150 ms, and at the 3 s deadline.Change
CLOCK_ACCEPTEDis logged, and the wait for a settled STATUS continues.Which of these the 2626 actually hit is not known without its log. The new
[DiceInit] clock unconfirmed …/no CLOCK_ACCEPTED …lines will show it.Rates on DICE devices without EAP (#223)
A DICE device without the EAP extension never offered 88.2/96 kHz. The ZED-R16 in #223 and this 2626 (CLOCK_CAPS 0x13FF001E) are two examples. Such a device reports channel layouts only for its current rate, in the TX/RX stream registers. We offered a rate only when we knew its layout, so only the attach rate appeared in CoreAudio. The layout for another rate was learned only when the device changed rate by itself (#190), never when the host asked for that rate. The closed PR #224 worked around this for one device with a hard-coded table.
The TCAT driver works without that knowledge. Saffire.kext
performFormatChangechecks the rate against CLOCK_CAPS.RestartStreamingthen sets CLOCK_SELECT and waits for the clock. FinallyPopulateDeviceStructreads the TX/RX layout andCreateStreamsrebuilds the audio streams. The layout is read after the switch, not before. This branch now does the same:LayoutProvisional.Not tested on hardware. Open question: how apps react when the channel count changes after a rate switch. EAP devices already change channel count at that point.
Fixture
The 2626's register dump from #189 is added as a test fixture. It is the first captured DICE device with no catalog row, so it goes through the generic DICE fallback: two streams each way (16 + 10 PCM), no EAP, 8 clock source names. pydice now accepts 1 to 13 names. The build-19 report is used because pydice does not parse the build-33 report format yet.
Testing
geometry-load-failed.clock-never-locksgoldens updated: the start now runs and times out on its own lock gate, ending with ENABLE=0 and no streams, as before.🤖 Generated with Claude Code