Skip to content

Windows: audio stream build fails with E_INVALIDARG (0x80070057) on Bluetooth headsets #3020

@louis030195

Description

@louis030195

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:

  1. Headset Microphone (Loop120 by Shokz) (input)
  2. Headphones (Loop120 by Shokz) (output)
  3. 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-254build_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).

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions