Skip to content

Add exclusive mode capability probing #63

Description

@HEnquist

WASAPI has no structured way to ask a device what it supports. The only option is calling IsFormatSupported for every combination of sample rate, channel count, sample format and channel mask, and brute forcing the full matrix is thousands of COM calls and several seconds per device.

CamillaDSP has a working implementation in src/wasapi_backend/capabilities.rs that prunes the search space:

  • probe the 48 kHz and 44.1 kHz families interleaved from the base rate upward, where the first hit establishes an upper channel count limit and a reduced format set that later probes reuse
  • narrow the format candidates as soon as the first channel count succeeds with fewer than the full set
  • cache the accepted channel mask per channel count and reuse it, which avoids mask renegotiation
  • per family early cutoff, so once a family has a hit, a miss at the next rate deactivates it, and the upward scan stops when both families are inactive
  • probe the remaining low rates and the 32 kHz family using only the channel counts found during the upward scan

That is roughly 200 lines of logic with nothing CamillaDSP specific in it, and it fits better here.

It should be more than a single call. Someone who already knows they want 48 kHz should not pay for the full scan. Something like:

  • supported formats at a given rate and channel count
  • supported channel counts and formats at a given rate
  • full scan over all rates, built on the two above

The channel mask cache has to be shared between calls to be worth anything, so this probably wants to be a struct holding the AudioClient and the cache, with the probes as methods on it.

The API should return the supported combinations as WaveFormat values, not a higher level format enum. CamillaDSP's WasapiSampleFormat exists to serve its cross-platform config, so mapping to labels belongs on the caller side. Same for serialization, the descriptor structs in CamillaDSP derive Serialize for the websocket API and that is caller business.

Using KS data ranges for better bounds

One way to get better bounds: WDM audio drivers already declare their capabilities as KS data ranges. KSPROPERTY_PIN_DATARANGES returns KSDATARANGE_AUDIO structures with MaximumChannels, MinimumBitsPerSample, MaximumBitsPerSample, MinimumSampleFrequency and MaximumSampleFrequency.

The interesting part is not only speed. The pruning above is aggressive because a blind scan is too expensive, and some of it trades away coverage:

  • the per family early cutoff stops at the first miss, so a device supporting 48, 96 and 384 but not 192 loses the top rate
  • the channel count bound comes from the first successful rate, so a higher rate that supports more channels is never seen
  • the format candidate list narrows after the first successful channel count, so a format that only works at some other channel count can be dropped

With declared limits for channels, bit depth and rate, those inferences could be replaced by real bounds, and the scan could afford to be less restrictive inside them. Whether it matters in practice is unmeasured, it may well be that nothing is missed on real hardware.

Caveats:

  • data ranges are cross products and over-report. A device declaring 2 to 8 channels and 44.1 to 192 kHz is not claiming every combination in that box works. They are an upper bound, so IsFormatSupported still has to confirm every hit.
  • some drivers declare very broad ranges, and then they add little
  • getting from a WASAPI endpoint to the KS pin needs checking. Probably through IDeviceTopology, walking to the connector and activating IKsControl on the device side part, then DeviceIoControl. That is a fair bit more plumbing than the COM calls used now.

Activity

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

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions