Skip to content

fix(sounds): validate sample rate + guard playback (Win11 XONAR crash)#30

Merged
larsrollik merged 4 commits into
mainfrom
bug/sound-sample-rate-fallback
Jun 25, 2026
Merged

fix(sounds): validate sample rate + guard playback (Win11 XONAR crash)#30
larsrollik merged 4 commits into
mainfrom
bug/sound-sample-rate-fallback

Conversation

@larsrollik

Copy link
Copy Markdown
Member

Follow-up to the default-output fallback: fixes a session crash on the Win11
rig and makes the reward chirp actually play.

Symptom

Device found (Speakers (XONAR SOUND CARD), id 10) but the stream/sd.play
failed with Invalid sample rate [PaErrorCode -9997] at 192000 Hz, and the
sd.play exception propagated into the Bpod softcode thread → session aborted.

Cause

  • sample_rate_dict hardcodes 192000 for XONAR SOUND CARD. Under WASAPI shared
    mode on Windows the device is locked to its mixer format and rejects 192000
    (works on Linux / exclusive mode, hence the hardcode).
  • The sd.play fallback had no error guard, so the failure crashed the trial loop.

Fix

  • Validate the chosen rate via sd.check_output_settings at init; on rejection,
    fall back to the device's default_samplerate so the stream opens. Cards that
    genuinely support 192000 are unaffected.
  • Guard the sd.play fallback (best-effort): an audio error logs a warning and
    never crashes the session (it runs in the Bpod softcode thread).

Tests: +1 (rate fallback); 4 sound tests green; mypy clean.

The reward chirp crashed the session on Windows: the device was found
(XONAR SOUND CARD) but the hardcoded 192000 Hz from sample_rate_dict is rejected
by WASAPI shared mode (PaErrorCode -9997), and the sd.play fallback raised that
error inside the Bpod softcode thread, aborting the trial loop.

- Validate the chosen rate with sd.check_output_settings at init; if the device
  rejects it, fall back to the device's reported default_samplerate (so the
  stream opens at a supported rate). Cards that do 192000 are unaffected.
- Wrap the sd.play fallback in try/except so an audio backend error logs a
  warning instead of crashing the session.

Tests: +1 rate fallback; 4 sound tests green.
@larsrollik larsrollik requested a review from a team as a code owner June 25, 2026 13:08
The XONAR supports 192000, but WASAPI shared mode is locked to the Windows
mixer/default-format rate, so requesting 192000 either errors (-9997) or
resamples too slow (right sound, "deflated"/longer). Keep the full rate and
auto-enable WASAPI exclusive on Windows when the chosen rate exceeds the
device's shared default, binding the device directly at its native rate.
The rate validation now runs in exclusive mode; if even that is rejected it
falls back to the shared default rate (correct speed) instead of deflating.

Tests: exclusive auto-enable + full-rate-kept, and shared-default fallback.
Exclusive mode opened but produced no output on the XONAR endpoint under test,
so auto-enabling it for high device-native rates made the reward sound silent.
Use shared mode and, when the device rejects the configured rate, fall back to
its default rate (audible, correct speed) rather than going silent or playing
deflated. Exclusive stays opt-in via use_wasapi_exclusive. Full 192000 on the
XONAR depends on its Windows driver preset (7.1 channels / 192000), documented
separately.

Tests: shared-default fallback; 4 sound tests green.
The output stream can open at a different rate than requested; sounds are
generated after setup_sound_device at self.sample_rate, so if the stream
actually runs slower the buffer plays too slow ("deflated"). After opening,
adopt self._stream.samplerate as the generation rate so buffer rate always
matches playback rate (correct speed at whatever rate the device provides).
The stream-open log now reports the actual rate.
@larsrollik larsrollik merged commit e38032a into main Jun 25, 2026
7 checks passed
@larsrollik larsrollik deleted the bug/sound-sample-rate-fallback branch June 25, 2026 13:44
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.

1 participant