Skip to content

Audio pipeline: AudioInputChoice foundation for the device-driven format list - #1678

Merged
Mysticial merged 4 commits into
mainfrom
audio-input-choice-foundation
Oct 23, 2026
Merged

Mysticial merged 4 commits into
mainfrom
audio-input-choice-foundation

Conversation

@pa-devbot

Copy link
Copy Markdown
Collaborator

Step A of replacing the AudioChannelFormat preset enum with device-driven AudioFormat-based input choices. Pure addition — nothing consumes the new API yet, so behavior is unchanged.

What's in

  • AudioInputChoice (AudioInfo.h): the shape the pipeline consumes (AudioFormat) plus, for the misreporting capture-card case, what the device physically emits (1ch×96000 read as 2ch×48000), is_reinterpreted(), and the R/L swap_channels() flag. display_name() renders the dropdown string in the existing style — "2 x 48,000 Hz (Stereo)", "1 x 96,000 Hz (Mono)", "6 x 48,000 Hz (5.1)" — with standard layout names only for standard layouts and the existing "Interleaved Stereo L/R" / "R/L" strings for the reinterpretations.
  • input_choices(supported, preferred): pure policy function — drops invalid entries, collapses duplicates by (rate, channels, config) with the preferred sample format winning, sorts by rate then channels, appends the two 2ch×48000 reinterpretations only when the sole supported format is 1ch×96000, and sets preferred_index to the exact match (else 0).
  • AudioDeviceInfo::supported_choices() / preferred_choice_index() (input devices only): Qt 6.10's QAudioDevice has no supportedFormats(), so enumerate_supported_formats() probes the standard grid (11 rates × 8 channel counts) with isFormatSupported(), trying the device's sample formats preferred-first per shape. The card default (prefer the L/R reinterpretation; R/L for MiraBox) matches the existing preferred-format behavior.
  • AudioInfo_Tests.{h,cpp}: 5 gate tests — naming, choice flags, sort/dedupe, the card-quirk rule, empty/invalid.

Notes

  • Qt gotcha discovered while building this: QAudioFormat::setChannelCount() resets the channel config, so all builders set the count before the config (pinned by the card-quirk test, which checks the reinterpreted entry's config).
  • AudioFormat copy/destroy is first instantiated in AudioInfo_Tests.cpp — it includes Pimpl.tpp, same pattern as the other TUs that materialize an AudioFormat.

Verification

  • -Werror clean on aarch64; full command-line suite 18,220 / 0 (was 18,215 on main; +5 new tests).
  • Follow-up steps (separate PRs): B — pipeline goes choice-driven (enum mapped 1:1, UI unchanged); C — widget + state callbacks switch to the device-driven list; D — enum removal.

…riven format list.

Step A of replacing the AudioChannelFormat preset enum with device-driven
AudioFormat-based input choices (design agreed in #audio-pipeline-redesign).
Pure addition: nothing consumes the new API yet, so behavior is unchanged.

- AudioInputChoice: the shape the pipeline consumes (AudioFormat) plus,
  for the misreporting capture-card case, what the device physically emits
  (1ch x 96000 read as 2ch x 48000), an is_reinterpreted flag, and the
  R/L channel-swap flag. display_name() renders the dropdown string in the
  existing "2 x 48,000 Hz (Stereo)" style, with standard layout names
  (Mono, Stereo, 2.1, 3.1, 5.0, 5.1, 7.0, 7.1) only for standard layouts
  and the existing "Interleaved Stereo L/R" / "R/L" strings for the
  reinterpretations.
- input_choices(supported, preferred): the pure policy function - drops
  invalid entries, collapses duplicates by (rate, channels, config) with
  the preferred sample format winning, sorts by rate then channels, and
  appends the two 2ch x 48000 reinterpretations when the only supported
  format is 1ch x 96000. preferred_index is the exact match, else 0.
- AudioDeviceInfo gains supported_choices() / preferred_choice_index(),
  populated for input devices only: QAudioDevice (Qt6) does not enumerate
  full formats, so enumerate_supported_formats() probes the standard grid
  (11 rates x 8 channel counts) with isFormatSupported(), trying the
  device's sample formats preferred-first per shape. The card-default rule
  (prefer the L/R reinterpretation; R/L for MiraBox) follows the existing
  preferred-format behavior. Note: Qt's setChannelCount() resets the
  channel config, so the builders set the count before the config.
- AudioInfo_Tests.{h,cpp}: 5 gate tests covering the naming, the choice
  flags, sort/dedupe, the card-quirk rule, and the empty/invalid cases.

Verified: -Werror clean aarch64, full command-line suite 18,220 passed /
0 failed (was 18,215 on main; +5 new tests).
…ates.

@kuroneko: format_rate_comma() duplicated Common/Cpp/PrettyPrint.h's
tostr_u_commas(); drop the local helper and call the shared one instead.

Verified: -Werror clean aarch64; full command-line suite 18,220 / 0 / 0
(naming gates pin the "44,100"-style strings).
…e list.

Per @kuroneko's review of input_choices():

- Dedup of duplicate (rate, channels, config) shapes now keeps the
  highest quality sample format by a fixed preference order
  (float > int32 > int16 > uint8) instead of the device's preferred
  sample format. enumerate_supported_formats() probes each shape in
  that same quality order, so real devices offer float where supported
  instead of the device-preferred type.
- The choice list is now sorted for display: channel count descending,
  then sample rate descending (the capture-card reinterpretations stay
  appended after the native choices).
- preferred_index: the exact match of the device's preferred format
  still wins; when the preferred format is invalid or unavailable the
  fallback is the highest quality score instead of index 0, where
  score = type x channel x sqrt(rate) with float 1.0 / int32 0.9 /
  int16 0.5 / uint8 0.1, 2ch 2.0 / Nch 2 - 1/N, and sqrt(rate), so the
  usual float stereo 48k / 44.1k shapes top the fallback while higher
  quality unusual formats still climb.

Gate tests updated: InputChoices_SortDedupe pins the new display order,
the fixed dedup preference and a score-vs-first-entry fallback case;
InputChoices_CardQuirk pins the score fallback on the 1ch x 96000-only
device (L/R reinterpretation beats the native entry, ties keep the
earlier index).

Verified: -Werror clean aarch64; full command-line suite 18,220 / 0 / 0.
@Mysticial
Mysticial force-pushed the audio-input-choice-foundation branch from 0b5b5fc to 7c63d8f Compare October 23, 2026 10:28
@Mysticial
Mysticial merged commit 183701a into main Oct 23, 2026
7 checks passed
@Mysticial
Mysticial deleted the audio-input-choice-foundation branch October 23, 2026 10:45
Mysticial pushed a commit that referenced this pull request Oct 24, 2026
Deletes the last of the fixed input-format preset machinery, now that the
pipeline, session state, options/JSON, and UI all run on the device-driven
AudioInputChoice (Steps A-C, #1678 / #1707 / #1711):

- AudioChannelFormat enum, AUDIO_FORMAT_LABELS, and set_format().
- AudioDeviceInfo::supported_formats() / preferred_format_index() and the
  dead preferred_format(); the legacy supported_input_formats() grid-to-
  preset mapping (its #if 0 debug remnants included).
- all_input_devices(): the same-display-name dedupe now scores on the
  number of input choices instead of the legacy format list (+ the
  preferred-preset-match bonus, which has no choice-world analogue); the
  winMM shadow-device comment notes QTBUG-75781 is a Qt5-era artifact that
  no longer occurs on Qt6.
- Stale comments in AudioInfo_Tests and StreamHistorySession::clear().

The shared enumerate_supported_formats() grid probe stays: it feeds
build_input_choices(). format_to_str() stays: it is still used to log
output device preferred formats.

Co-authored-by: PA Dev Bot <344001113+pa-devbot@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants