Got `Cannot change thread mode after it is set` on windows
running
rodio::default_output_device();
on windows got
thread 'main' panicked at 'called `Result::unwrap()` on an `Err` value: Os { code: -2147417850, kind: Other, message: "Cannot change thread mode after it is set." }', libcore/result.rs:1009:5
Are you using SDL, by any chance? I ran into this exact same issue, and it seemed to go away when I moved the call to rodio::default_output_device() to before SDL got initialized.
In particular, it seemed to start falling over for me any time I initialized Rodio after SDL's game controller module, which seems... strange, and probably coincidental.
If you're not using SDL, hopefully that at least gives you an idea of how you might be able to work around your issue.
I've had this problem with SDL too
@17cupsofcoffee Yes, I'm using SDL and solved with moving the call before SDL initialization, thanks for the solution, valid workaround for now.
If anyone else runs into this issue, make sure you move Rodio's initialization all the way before SDL, not just early enough into SDL's initialization that it starts working - the latter seems like a valid workaround until someone turns on some extra settings and it breaks again 😅
I got the same problem while use rodio functions in rust dll lib and call it from c#
[DllImport("djmadest_api.dll")]
private static extern IntPtr init_default_device();
[DllImport("djmadest_api.dll")]
private static extern void play_from_file(IntPtr sink, IntPtr filename);
// in main class
IntPtr device = init_default_device(); // panic here thread '<unnamed>' panicked at 'called `Result::unwrap()` on an `Err` value: Os { code: -2147417850, kind: Other, message: "Cannot change thread mode after it is set." }', src\libcore\result.rs:1165:5
IntPtr filename = Marshal.StringToHGlobalAnsi("music.mp3");
Rust code:
#[no_mangle]
pub extern fn init_default_device () -> Box<rodio::Sink> {
println!("Initing audio device");
let device = rodio::default_output_device().unwrap();
let sink = Box::new(rodio::Sink::new(&device));
println!("Done!");
return sink;
}
I get a similar error
thread 'main' panicked at 'called `Result::unwrap()` on an `Err` value: Os { code: -2147417850, kind: Other, message: "Cannot change thread mode after it is set." }', C:\Users\woelper\.cargo\registry\src\github.com-1ecc6299db9ec823\cpal-0.10.0\src\host\wasapi\com.rs:13:9
as soon as I use it along with imgui-rs (imgui-glium-renderer + glium + imgui-winit-support + winit as recommended).
@woelper did you manage to solve it? I tried it with glium too, but failed to make a sound. If I moved the playback to an async function it didn't work, new thread didn't work, moving it to top of main also fail :)
@woelper did you manage to solve it? I tried it with glium too, but failed to make a sound. If I moved the playback to an async function it didn't work, new thread didn't work, moving it to top of
mainalso fail :)
Well, I did manage to work around it - I used imgui_gfx_renderer and it worked. If you have a similar issue with imgui-rs and rodio you can try that too. If it helps you can look at the support module I am using here: https://git.schdbr.de/woelper/sampler/src/master/src/support_ogl/mod.rs
I ran into this issue as well and found these related issues: https://github.com/RustAudio/cpal/pull/330 https://github.com/rust-windowing/winit/issues/1185
It seems this happens with versions of winit starting with 0.20. The easiest workaround is to spawn a separate thread for Rodio.
I'm also running into this issue on Win 8.1, I'm not using SDL but glium.
thread 'main' panicked at 'called
Result::unwrap()on anErrvalue: 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.11.0\src\host\wasapi\com.rs:13:9
Moving the call to rodio::play_raw before everything else also doesn't work.
It panics with:
thread 'main' panicked at 'OleInitialize failed! Result was: `RPC_E_CHANGED_MODE`', /rustc/e82734e56b2a50d38e0937d08f559d15dbe8e46b\src\libstd\macros.rs:13:23
stack backtrace:
0: backtrace::backtrace::trace_unsynchronized
at C:\Users\VssAdministrator\.cargo\registry\src\github.com-1ecc6299db9ec823\backtrace-0.3.46\src\backtrace\mod.rs:66
1: std::sys_common::backtrace::_print_fmt
at /rustc/e82734e56b2a50d38e0937d08f559d15dbe8e46b\/src\libstd\sys_common\backtrace.rs:78
2: std::sys_common::backtrace::_print::{{impl}}::fmt
at /rustc/e82734e56b2a50d38e0937d08f559d15dbe8e46b\/src\libstd\sys_common\backtrace.rs:59
3: core::fmt::write
at /rustc/e82734e56b2a50d38e0937d08f559d15dbe8e46b\/src\libcore\fmt\mod.rs:1069
4: std::io::Write::write_fmt<std::sys::windows::stdio::Stderr>
at /rustc/e82734e56b2a50d38e0937d08f559d15dbe8e46b\/src\libstd\io\mod.rs:1504
5: std::sys_common::backtrace::_print
at /rustc/e82734e56b2a50d38e0937d08f559d15dbe8e46b\/src\libstd\sys_common\backtrace.rs:62
6: std::sys_common::backtrace::print
at /rustc/e82734e56b2a50d38e0937d08f559d15dbe8e46b\/src\libstd\sys_common\backtrace.rs:49
7: std::panicking::default_hook::{{closure}}
at /rustc/e82734e56b2a50d38e0937d08f559d15dbe8e46b\/src\libstd\panicking.rs:198
8: std::panicking::default_hook
at /rustc/e82734e56b2a50d38e0937d08f559d15dbe8e46b\/src\libstd\panicking.rs:218
9: std::panicking::rust_panic_with_hook
at /rustc/e82734e56b2a50d38e0937d08f559d15dbe8e46b\/src\libstd\panicking.rs:511
10: std::panicking::begin_panic<str*>
at /rustc/e82734e56b2a50d38e0937d08f559d15dbe8e46b\src\libstd\panicking.rs:438
11: winit::platform_impl::platform::window::{{impl}}::new::{{closure}}<()>
at /rustc/e82734e56b2a50d38e0937d08f559d15dbe8e46b\src\libstd\macros.rs:13
12: core::result::Result<winit::platform_impl::platform::window::Window, winit::error::OsError>::map<winit::platform_impl::platform::window::Window,winit::error::OsError,winit::platform_impl::platform::window::Window,closure-0>
at /rustc/e82734e56b2a50d38e0937d08f559d15dbe8e46b\src\libcore\result.rs:519
13: winit::platform_impl::platform::window::Window::new<()>
at C:\Users\me\.cargo\registry\src\github.com-1ecc6299db9ec823\winit-0.22.1\src\platform_impl\windows\window.rs:73
14: winit::window::WindowBuilder::build<()>
at C:\Users\me\.cargo\registry\src\github.com-1ecc6299db9ec823\winit-0.22.1\src\window.rs:333
15: glutin::platform_impl::platform_impl::Context::new_windowed<()>
at C:\Users\me\.cargo\registry\src\github.com-1ecc6299db9ec823\glutin-0.24.0\src\platform_impl\windows\mod.rs:55
16: glutin::ContextBuilder<glutin::context::NotCurrent>::build_windowed<glutin::context::NotCurrent,()>
at C:\Users\me\.cargo\registry\src\github.com-1ecc6299db9ec823\glutin-0.24.0\src\windowed.rs:362
17: glium::backend::glutin::Display::new<glutin::context::NotCurrent,()>
at C:\Users\me\.cargo\git\checkouts\glium-35f4d224ff76160d\63986f2\src\backend\glutin\mod.rs:70
Moving the call to rodio::play_raw into a new spawned thread also doesn't work: It causes the same panic.
Does anyone have a workaround?
EDIT: Ah, if I move the call to rodio::default_output_device() also into the newly spawned thread, it works. But the thread immediately terminates since play_raw spawns its own background thread for playback. It would be nicer if it didn't require spawning another thread just for being able to call rodio::default_output_device() :)
Hm, with this workaround I can't pause the playback:
let source = Decoder::new(BufReader::new(File::open(in_path_audio)?))?;
thread::Builder::new()
.spawn(move || {
let device = rodio::default_output_device().unwrap();
rodio::play_raw(&device, source.convert_samples());
})
.unwrap();
When I try this, it plays no sound:
let source = BufReader::new(File::open(in_path_audio)?);
let playback_sink = thread::Builder::new()
.spawn(move || {
let device = rodio::default_output_device().unwrap();
rodio::play_once(&device, source)
})
.expect("spawn")
.join()
.expect("join")?;
playback_sink.play();
With this it also plays no sound:
thread::Builder::new()
.spawn(move || {
let device = rodio::default_output_device().unwrap();
rodio::play_once(&device, source).unwrap();
})
.expect("spawn")
.join()
.expect("join");
Only with this it plays the sound, but then I can't pause/resume the sink:
thread::Builder::new()
.spawn(move || {
let device = rodio::default_output_device().unwrap();
rodio::play_once(&device, source).unwrap().detach();
})
.expect("spawn")
.join()
.expect("join");
Why doesn't it play any sound unless I detach the sink?
How can I keep the sink so that I can pause/resume it but so that it actually plays audio?
Here's what I did:
use std::sync::mpsc::{self, Sender};
use std::thread;
use rodio::Sink;
pub struct Audio {
control_channel: Sender<bool>,
}
impl Audio {
pub fn new() -> Self {
let audio_source = rodio::source::SineWave::new(1024);
let (tx, rx) = mpsc::channel();
thread::spawn(move || {
let device = rodio::default_output_device().unwrap();
let sink = Sink::new(&device);
sink.pause();
sink.append(audio_source);
while let Ok(should_play) = rx.recv() {
if should_play {
sink.play();
} else {
sink.pause();
}
}
});
Self {
control_channel: tx,
}
}
pub fn play(&self) {
self.control_channel.send(true).unwrap();
}
pub fn pause(&self) {
self.control_channel.send(false).unwrap();
}
}
I am using Glium and Rodio together in my project, I don't need drag-and-drop so I was able to work around this issue by disabling drag and drop support in glium per changelog.
I'm still learning rust, so I'm not in a position to know whether this issue is a glium issue, or a rodio issue.