Wasapi capture doesn't work: Stream is spawned but callback not called
Maintainer thường phản hồi trong vòng 1 ngày
Chưa có ai nhận issue này.
Đánh giá
- Độ khó
- 4/5
- Thời gian dự kiến
- 3-5 ngày
- Mức phù hợp với người mới
- 35/100
- Loại issue
- Lỗi
- Độ rõ ràng
- Khá rõ ràng
- Mức độ hoạt động
- Đình trệ
- Công nghệ
- rust
- Lĩnh vực
- audio-video-rtc
Hướng nghiên cứu
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.
Do mô hình lập chỉ mục viết ra từ nội dung của issue.
Mô tả
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.
- Ngôn ngữ chính
- Rust
- Star
- 4k
- Fork
- 554
- Merge trung bình
- 3 ngày 3 giờ
- Pull request đã merge (30 ngày)
- 4
Chuẩn bị môi trường
- Có Dockerfile hoặc tệp Docker Compose
- Không có mẫu pull request
- Đọc hướng dẫn đóng góp
Bắt đầu từ đâu
- Đọc hết issue, rồi đọc hướng dẫn đóng góp của dự án.
- Bình luận trên issue rằng bạn sẽ nhận — tránh hai người làm cùng một việc.
- Fork repository và làm thay đổi trên một nhánh.
- Mở pull request có tham chiếu số hiệu của issue.
Issue khác của RustAudio/cpal
-
aaudio: dynamic buffer tuning never grows the buffer (set_buffer_size_in_frames reports Err on success)Có thể đã có người làm @dannyward630 đã nhận 5 ngày trước. Đang mởhost - aaudio platform - android
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 79/100
Maintainer thường phản hồi trong vòng 1 ngày
-
WebAudio wasm build fails with wasm-bindgen panic=unwind closuresCó thể đã có người làm @bogusyogi đã nhận 13 ngày trước. Đang mởhost - webaudio platform - web
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 75/100
RustAudio/cpal#1394 · 1 bình luận ·
Maintainer thường phản hồi trong vòng 1 ngày
-
New WASAPI implementationĐang mởcode quality dependencies host - wasapi platform - windows
Độ khó 5/5 Hơn một tuần Mức phù hợp với người mới 35/100
RustAudio/cpal#1416 · 1 bình luận ·
Maintainer thường phản hồi trong vòng 1 ngày
-
host - pipewire platform - linux
Độ khó 4/5 1-2 ngày Mức phù hợp với người mới 52/100
RustAudio/cpal#1405 · 2 bình luận ·
Maintainer thường phản hồi trong vòng 1 ngày
-
WASAPI: default-device activation fails with RPC_E_CHANGED_MODE after endpoint-notification callbacks put thread-pool threads into an STACó thể đã có người làm @dannyward630 đã nhận 6 ngày trước. Đang mởcorrectness host - wasapi platform - windows
Độ khó 4/5 3-5 ngày Mức phù hợp với người mới 20/100
RustAudio/cpal#1402 · 1 bình luận ·
Maintainer thường phản hồi trong vòng 1 ngày
Tất cả issue của RustAudio/cpal
Issue tương tự
-
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 62/100
calcit-lang/caps#16 ·
-
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 85/100
penso/herdr-gpui#934 ·
Maintainer thường phản hồi trong vòng 1 ngày
-
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 76/100
Y-ASLant/ElegantClipboard#178 ·
-
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 82/100
linxiv-dev/linXiv#384 · 1 bình luận ·
Maintainer thường phản hồi trong vòng 1 ngày
-
priority middle
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 70/100
KATO-Hiro/AtCoderClans#12945 ·
Maintainer thường phản hồi trong vòng 1 ngày