Wasapi capture doesn't work: Stream is spawned but callback not called
Los mantenedores suelen responder en 1 día
Nadie ha tomado este issue todavía.
Evaluación
- Dificultad
- 4/5
- Tiempo estimado
- 3-5 días
- Aptitud para principiantes
- 35/100
- Tipo de issue
- Error
- Claridad
- Bastante claro
- Estado de actividad
- Estancado
- Stack tecnológico
- rust
- Área
- audio-video-rtc
Línea de trabajo
Start with the linked swyh-rs loopback capture implementation and compare it with the supplied capture_output_audio flow, especially how it selects the device and builds the input stream on Windows WASAPI. Check the CPAL WASAPI stream and callback behavior; the report says Linux calls the callback while Windows does not. Done means identifying why the callback is not called and confirming a working loopback capture path.
Escrito por el modelo de indexación a partir del texto del issue.
Descripción
I'm trying to do Wasapi loopback capture but it's not working:
Even though my input stream is spawned, the stream callback never gets called. Why could that be?
It prints this:
[DEBUG] Try capturing system audio
[INFO ] Capturing audio from: Line (Steinberg UR22mkII )
[INFO ] Default audio cfg: SupportedStreamConfig { channels: 2, sample_rate: SampleRate(44100), buffer_size: Unknown, sample_format: F32 }
build_stream F32
stream is playing
still playing
still playing
still playing
But it should ALSO print wave_reader called (from inside the wave_reader stream callback), but it never prints this and so I'm not receiving any audio frames through the channel in my application.
I based my code on the implementation of loopback capture in https://github.com/dheijl/swyh-rs:
https://github.com/dheijl/swyh-rs/blob/e6709b2f546af6cf272ded9529f6dc5d95145453/src/main.rs#L849
In swyh it apparently works (but I can't test that application because I don't have a streaming server/receiver).
I just refactored the code a little bit, but apart from that it's the same.
Any idea why the stream callback (wave_reader) doesn't get called?
(Note: On linux, wave_reader does get called and I receive audio frames over the channel. They are all 0.0, but that's a different issue, probably a linux issue rather than cpal issue?)
use super::*;
use anyhow::{Context, Result};
use cpal::{Device, Sample, SampleFormat, Stream, StreamError, SupportedStreamConfig};
use device::*;
use std::{
sync::{
atomic::{AtomicBool, Ordering},
mpsc::channel,
Arc,
},
thread,
};
pub fn capture_live_audio_input(
m_audio_device: Option<String>,
terminate_capture: Arc<AtomicBool>,
) -> Result<(BidirAudioChannel, AudioFormat)> {
let (audio_to_vis, vis_to_audio) = BidirAudioChannel::duplex_unbounded();
// spawn new thread as workaround: https://github.com/RustAudio/rodio/issues/214
let (tx, rx) = channel();
let _thread_capture = thread::Builder::new()
.name("capture".to_string())
.spawn(move || -> Result<_> {
let output_device = match m_audio_device {
Some(name) => unwropt!(
get_audio_output_devices()
.into_iter()
.find_map(|device| (device.name().ok().as_deref() == Some(&name)).then_some(device)),
"audio device not found"
),
None => unwropt!(get_default_audio_output_device(), "no default audio device"),
};
// capture system audio
debug!("Try capturing system audio");
let (stream, audio_format) =
capture_output_audio(&output_device, audio_to_vis).context("Could not capture audio")?;
tx.send(audio_format).unwrap();
stream.play().context("stream.play()")?;
println!("stream is playing");
// stream shouldn't be dropped, but it's not Send, so we need to keep this thread alive
while !terminate_capture.load(Ordering::SeqCst) {
std::thread::sleep(std::time::Duration::from_millis(100));
println!("still playing");
}
Ok(())
})
.expect("spawn");
let audio_format = rx.recv()?;
Ok((vis_to_audio, audio_format))
}
/// capture the audio stream from the default audio output device
/// sets up an input stream for the wave_reader in the appropriate format (f32/i16/u16)
fn capture_output_audio(
output_device: &Device,
audio_to_vis: BidirAudioChannel,
) -> Result<(Stream, AudioFormat)> {
info!(
"Capturing audio from: {}",
output_device.name().context("Could not get default audio device name")?
);
let audio_cfg = output_device.default_output_config().context("No default output config found")?;
let audio_format =
AudioFormat { sample_rate: audio_cfg.sample_rate().0, channel_count: audio_cfg.channels() as usize };
info!("Default audio cfg: {:?}", audio_cfg);
fn build_stream<T: Sample>(
output_device: &Device,
audio_cfg: SupportedStreamConfig,
audio_format: AudioFormat,
audio_to_vis: BidirAudioChannel,
) -> Result<(Stream, AudioFormat)> {
println!("build_stream {:?}", T::FORMAT);
fn wave_reader<T: Sample>(samples: &[T], audio_to_vis: &BidirAudioChannel) {
println!("wave_reader called");
let mut f32_samples =
audio_to_vis.rx.try_recv().unwrap_or_else(|_| Vec::with_capacity(samples.len()));
f32_samples.clear();
f32_samples.extend(samples.iter().map(|x| x.to_f32()));
println!("wave_reader {}", f32_samples.len());
let _ = audio_to_vis.tx.send(f32_samples);
}
match output_device.build_input_stream(
&audio_cfg.config(),
move |data, _: &_| wave_reader::<T>(data, &audio_to_vis),
|e| error!("Error on audio input stream: {}", e),
) {
Ok(stream) => Ok((stream, audio_format)),
Err(e) => {
bail!("Error capturing {:?} audio stream: {}", T::FORMAT, e);
}
}
}
match audio_cfg.sample_format() {
SampleFormat::F32 => build_stream::<f32>(output_device, audio_cfg, audio_format, audio_to_vis),
SampleFormat::I16 => build_stream::<i16>(output_device, audio_cfg, audio_format, audio_to_vis),
SampleFormat::U16 => build_stream::<u16>(output_device, audio_cfg, audio_format, audio_to_vis),
}
}
Btw, if you're wondering why I'm spawning a new thread (compared to swyh):
If I don't create the stream in the separate thread, I get this:
Os { code: -2147417850, kind: Other, message: "Cannot change thread mode after it is set." }', C:\Users\me.cargo\registry\src\github.com-1ecc6299db9ec823\cpal-0.13.1\src\host\wasapi\com.rs:13:77
It's this issue: https://github.com/RustAudio/rodio/issues/214
My application uses winit, and apparently this combination causes this issue:
https://github.com/RustAudio/rodio/issues/214#issuecomment-640979469
https://github.com/rust-windowing/winit/issues/1185
That's why I'm spawning a new thread for the stream (which I'm then keeping alive to prevent the stream from getting dropped).
But that's the only difference to swyh that I see. So I'm wondering why the stream callback is not being called.
- Lenguaje dominante
- Rust
- Estrellas
- 4k
- Forks
- 554
- Merge medio
- 3 d 3 h
- PR fusionados (30 d)
- 4
Preparar el entorno
- Incluye un Dockerfile o un archivo de Docker Compose
- Sin plantilla de pull request
- Leer la guía de contribución
Primeros pasos
- Lee el issue completo y luego la guía de contribución del proyecto.
- Comenta en el issue que vas a ocuparte — evita que dos personas hagan lo mismo.
- Haz un fork del repositorio y trabaja en una rama.
- Abre un pull request que haga referencia al número del issue.
Más de RustAudio/cpal
-
aaudio: dynamic buffer tuning never grows the buffer (set_buffer_size_in_frames reports Err on success)Posiblemente ocupada @dannyward630 la tomó hace 4 días. Abiertohost - aaudio platform - android
Dificultad 2/5 1-3 horas Aptitud para principiantes 79/100
Los mantenedores suelen responder en 1 día
-
WebAudio wasm build fails with wasm-bindgen panic=unwind closuresPosiblemente ocupada @bogusyogi la tomó hace 12 días. Abiertohost - webaudio platform - web
Dificultad 2/5 1-3 horas Aptitud para principiantes 75/100
RustAudio/cpal#1394 · 1 comentario ·
Los mantenedores suelen responder en 1 día
-
New WASAPI implementationAbiertocode quality dependencies host - wasapi platform - windows
Dificultad 5/5 Más de una semana Aptitud para principiantes 35/100
RustAudio/cpal#1416 · 1 comentario ·
Los mantenedores suelen responder en 1 día
-
host - pipewire platform - linux
Dificultad 4/5 1-2 días Aptitud para principiantes 52/100
RustAudio/cpal#1405 · 2 comentarios ·
Los mantenedores suelen responder en 1 día
-
WASAPI: default-device activation fails with RPC_E_CHANGED_MODE after endpoint-notification callbacks put thread-pool threads into an STAPosiblemente ocupada @dannyward630 la tomó hace 5 días. Abiertocorrectness host - wasapi platform - windows
Dificultad 4/5 3-5 días Aptitud para principiantes 20/100
RustAudio/cpal#1402 · 1 comentario ·
Los mantenedores suelen responder en 1 día
Todos los issues de RustAudio/cpal
Issues similares
-
Dificultad 2/5 1-3 horas Aptitud para principiantes 78/100
Los mantenedores suelen responder en 1 día
-
memory_patch_page drops the `#` of headings like `## Notes on C#`Posiblemente ocupada @viniciusdsandrade la tomó hoy. Abierto
Dificultad 2/5 1-3 horas Aptitud para principiantes 85/100
akitaonrails/ai-memory#1859 ·
Los mantenedores suelen responder en 1 día
-
Dificultad 2/5 1-3 horas Aptitud para principiantes 78/100
wealthfolio/wealthfolio#2376 ·
Los mantenedores suelen responder en 1 día
-
kind/bug kind/security
Dificultad 2/5 1-3 horas Aptitud para principiantes 82/100
spiceai/spiceai#15826 · 1 comentario ·
Los mantenedores suelen responder en 1 día
-
area:cli bug dotnet good first issue priority:medium
Dificultad 2/5 1-3 horas Aptitud para principiantes 76/100
rtk-ai/rtk#4844 · 1 comentario ·
Los mantenedores suelen responder en 1 día