Summary
On Windows, build_input_stream and build_output_stream fail with E_INVALIDARG (0x80070057) for some Bluetooth headsets (first report: Shokz Loop120), taking down both the headset capture and the subsequent Realtek speakers capture in the same session. Audio recording is broken for the affected user until they swap devices.
Observed log
ERROR screenpipe_audio::core::stream: Failed to build input stream: A backend-specific error has occurred: Параметр задан неверно. (0x80070057)
(Russian locale — "Параметр задан неверно" = "The parameter is incorrect", i.e. Windows E_INVALIDARG.)
Three consecutive failures in the same session, same error code:
Headset Microphone (Loop120 by Shokz) (input)
Headphones (Loop120 by Shokz) (output)
Speakers (Realtek(R) Audio) (output) — fails immediately after the Bluetooth device fails
[DEVICE_RECOVERY] starts each one, then WASAPI rejects the stream config.
Hypothesis (medium confidence — not verified on real hardware)
crates/screenpipe-audio/src/core/device.rs:340-366 picks the stream config by max sample rate:
let best_config = configs.iter()
.max_by(|a, b| {
a.max_sample_rate().0.cmp(&b.max_sample_rate().0)
.then(a.channels().cmp(&b.channels()))
})
.ok_or_else(|| anyhow!(\"No supported output configurations found\"))?;
(*best_config).with_sample_rate(best_config.max_sample_rate())
Suspected failure mode on the Loop120:
- Windows exposes both A2DP (48 kHz stereo) and HFP/HSP (16 kHz mono) configs for the same Bluetooth device.
max_by(max_sample_rate) picks 48 kHz stereo.
- Headset is currently negotiated in HFP mode (because mic capture is being opened), so WASAPI rejects the 48 kHz stereo request with
E_INVALIDARG.
Not yet verified that those are the actual advertised configs. The Realtek-speakers follow-on failure might be the same class (wrong config chosen) or a separate WASAPI state issue triggered by the prior failure — unclear.
Why we can't just ship a fix
- The bug is device- and driver-specific.
- Even writing a targeted
build_input_stream retry requires knowing which (rate, channels, bit depth, buffer size) tuples the device actually accepts.
- Unit-testing with mocked cpal configs validates the refactor but not the real-world WASAPI handshake.
Plan
Step 1 — Ship a diagnostic patch (no behavior change)
Before build_input_stream / build_output_stream, log:
- every entry in
device.supported_input_configs() / supported_output_configs() (rate range, channels, sample_format, buffer_size)
- the output of
device.default_input_config() / default_output_config()
- which config we picked and why
Ship this in the next release. Ask reporters to re-send logs with the enriched output.
Step 2 — Fix based on real data
With actual config lists from failing devices in hand, implement:
- Prefer
default_*_config() over max-rate greedy pick (this matches whatever the Windows audio mixer is currently negotiated to).
- On
E_INVALIDARG, retry progressively: default rate → 16 kHz mono → 8 kHz mono, with buffer size unset (let WASAPI choose).
- For Bluetooth devices specifically, detect HFP mode (common indicator: sample rate ≤ 16 kHz advertised in the current config) and don't try to force A2DP rates.
Step 3 — Regression guard
Add an integration test that covers the config-picker logic with a mocked cpal device exposing conflicting A2DP+HFP configs (rate ranges that don't overlap). Won't catch every driver-level quirk but prevents regressing the picker logic.
Workaround for affected users
Settings → Audio Devices → deselect the Bluetooth headset entries and select the laptop's built-in mic + speakers. Re-enable the BT headset once a fix ships.
Code references
crates/screenpipe-audio/src/core/device.rs:340-366 — the greedy max-rate config picker
crates/screenpipe-audio/src/core/stream.rs:237-254 — build_input_stream call site that surfaces the error
crates/screenpipe-audio/src/audio_manager/device_monitor.rs — the [DEVICE_RECOVERY] loop that immediately retries and re-triggers the same failure
Related
First report from a Windows Pro user with a Shokz Loop120 headset + Realtek onboard audio. No prior reports of 0x80070057 / Shokz / Loop120 across the full feedback corpus (0/557).
Summary
On Windows,
build_input_streamandbuild_output_streamfail withE_INVALIDARG(0x80070057) for some Bluetooth headsets (first report: Shokz Loop120), taking down both the headset capture and the subsequent Realtek speakers capture in the same session. Audio recording is broken for the affected user until they swap devices.Observed log
(Russian locale — "Параметр задан неверно" = "The parameter is incorrect", i.e. Windows
E_INVALIDARG.)Three consecutive failures in the same session, same error code:
Headset Microphone (Loop120 by Shokz) (input)Headphones (Loop120 by Shokz) (output)Speakers (Realtek(R) Audio) (output)— fails immediately after the Bluetooth device fails[DEVICE_RECOVERY]starts each one, then WASAPI rejects the stream config.Hypothesis (medium confidence — not verified on real hardware)
crates/screenpipe-audio/src/core/device.rs:340-366picks the stream config by max sample rate:Suspected failure mode on the Loop120:
max_by(max_sample_rate)picks 48 kHz stereo.E_INVALIDARG.Not yet verified that those are the actual advertised configs. The Realtek-speakers follow-on failure might be the same class (wrong config chosen) or a separate WASAPI state issue triggered by the prior failure — unclear.
Why we can't just ship a fix
build_input_streamretry requires knowing which (rate, channels, bit depth, buffer size) tuples the device actually accepts.Plan
Step 1 — Ship a diagnostic patch (no behavior change)
Before
build_input_stream/build_output_stream, log:device.supported_input_configs()/supported_output_configs()(rate range, channels, sample_format, buffer_size)device.default_input_config()/default_output_config()Ship this in the next release. Ask reporters to re-send logs with the enriched output.
Step 2 — Fix based on real data
With actual config lists from failing devices in hand, implement:
default_*_config()over max-rate greedy pick (this matches whatever the Windows audio mixer is currently negotiated to).E_INVALIDARG, retry progressively: default rate → 16 kHz mono → 8 kHz mono, with buffer size unset (let WASAPI choose).Step 3 — Regression guard
Add an integration test that covers the config-picker logic with a mocked cpal device exposing conflicting A2DP+HFP configs (rate ranges that don't overlap). Won't catch every driver-level quirk but prevents regressing the picker logic.
Workaround for affected users
Settings → Audio Devices → deselect the Bluetooth headset entries and select the laptop's built-in mic + speakers. Re-enable the BT headset once a fix ships.
Code references
crates/screenpipe-audio/src/core/device.rs:340-366— the greedy max-rate config pickercrates/screenpipe-audio/src/core/stream.rs:237-254—build_input_streamcall site that surfaces the errorcrates/screenpipe-audio/src/audio_manager/device_monitor.rs— the[DEVICE_RECOVERY]loop that immediately retries and re-triggers the same failureRelated
First report from a Windows Pro user with a Shokz Loop120 headset + Realtek onboard audio. No prior reports of
0x80070057/Shokz/Loop120across the full feedback corpus (0/557).