lowfi/src/audio.rs
Tal 02a4e688bd chore: update dependencies
for some reason, rodio decided it would be a great idea to change all of
the core terminology to be less technical. this is frankly strange, but
it's best not to use an outdated version of the dependency.

rodio is for some reason switching to a "breaking change every single
update" versioning model. why? i have frankly no idea, semver exists for
a reason and they decided just not to use it. 0.x.x is stupid, and
people should realize semver exists for a reason. to the total of zero
people who will read this, thanks for reading my short rant.
2026-03-05 20:34:45 +01:00

56 lines
1.7 KiB
Rust

//! Some simple audio related utilities.
pub mod waiter;
/// This gets the output stream while also shutting up alsa with [libc].
/// Uses raw libc calls, and therefore is functional only on Linux.
#[cfg(target_os = "linux")]
fn silent_get_output_stream() -> crate::Result<rodio::MixerDeviceSink> {
use libc::freopen;
use rodio::DeviceSinkBuilder;
use std::ffi::CString;
// Get the file descriptor to stderr from libc.
extern "C" {
static stderr: *mut libc::FILE;
}
// This is a bit of an ugly hack that basically just uses `libc` to redirect alsa's
// output to `/dev/null` so that it wont be shoved down our throats.
// The mode which to redirect terminal output with.
let mode = CString::new("w")?;
// First redirect to /dev/null, which basically silences alsa.
let null = CString::new("/dev/null")?;
// SAFETY: Simple enough to be impossible to fail. Hopefully.
unsafe {
freopen(null.as_ptr(), mode.as_ptr(), stderr);
};
// Make the MixerDeviceSink while stderr is still redirected to /dev/null.
let stream = DeviceSinkBuilder::open_default_sink()?;
// Redirect back to the current terminal, so that other output isn't silenced.
let tty = CString::new("/dev/tty")?;
// SAFETY: See the first call to `freopen`.
unsafe {
freopen(tty.as_ptr(), mode.as_ptr(), stderr);
};
Ok(stream)
}
/// Creates an audio stream, doing so silently on Linux.
pub fn stream() -> crate::Result<rodio::MixerDeviceSink> {
#[cfg(target_os = "linux")]
let mut stream = silent_get_output_stream()?;
#[cfg(not(target_os = "linux"))]
let mut stream = rodio::DeviceSinkBuilder::open_default_stream()?;
stream.log_on_drop(false);
Ok(stream)
}