fix: finally fix the alsa warnings with libc's freopen

This commit is contained in:
Tal 2024-10-02 22:56:01 +02:00
parent 5d2e6c6d23
commit c2baa53ded
5 changed files with 34 additions and 22 deletions

3
Cargo.lock generated
View File

@ -982,7 +982,7 @@ checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24"
[[package]] [[package]]
name = "lowfi" name = "lowfi"
version = "1.3.1" version = "1.3.2"
dependencies = [ dependencies = [
"Inflector", "Inflector",
"arc-swap", "arc-swap",
@ -992,6 +992,7 @@ dependencies = [
"eyre", "eyre",
"futures", "futures",
"lazy_static", "lazy_static",
"libc",
"rand", "rand",
"reqwest", "reqwest",
"rodio", "rodio",

View File

@ -1,6 +1,6 @@
[package] [package]
name = "lowfi" name = "lowfi"
version = "1.3.1" version = "1.3.2"
edition = "2021" edition = "2021"
description = "An extremely simple lofi player." description = "An extremely simple lofi player."
license = "MIT" license = "MIT"
@ -40,3 +40,4 @@ rodio = { version = "0.19.0", features = ["symphonia-mp3"], default-features = f
crossterm = "0.28.1" crossterm = "0.28.1"
Inflector = "0.11.4" Inflector = "0.11.4"
lazy_static = "1.5.0" lazy_static = "1.5.0"
libc = "0.2.159"

View File

@ -1,9 +1,7 @@
//! Responsible for the basic initialization & shutdown of the audio server & frontend. //! Responsible for the basic initialization & shutdown of the audio server & frontend.
use std::io::stdout;
use std::sync::Arc; use std::sync::Arc;
use crossterm::cursor::SavePosition;
use tokio::{sync::mpsc, task}; use tokio::{sync::mpsc, task};
use crate::player::Player; use crate::player::Player;
@ -12,13 +10,6 @@ use crate::player::{ui, Messages};
/// Initializes the audio server, and then safely stops /// Initializes the audio server, and then safely stops
/// it when the frontend quits. /// it when the frontend quits.
pub async fn play(alternate: bool) -> eyre::Result<()> { pub async fn play(alternate: bool) -> eyre::Result<()> {
// Save the position. This is important since later on we can revert to this position
// and clear any potential error messages that may have showed up.
// TODO: Figure how to set some sort of flag to hide error messages within alsa/rodio,
// TODO: Instead of just ignoring & clearing them after.
// TODO: Fix this, as it doesn't work with some terminals when the cursor is at the bottom of the terminal.
crossterm::execute!(stdout(), SavePosition)?;
let (tx, rx) = mpsc::channel(8); let (tx, rx) = mpsc::channel(8);
let player = Arc::new(Player::new().await?); let player = Arc::new(Player::new().await?);

View File

@ -6,6 +6,7 @@ use std::{collections::VecDeque, sync::Arc, time::Duration};
use arc_swap::ArcSwapOption; use arc_swap::ArcSwapOption;
use downloader::Downloader; use downloader::Downloader;
use libc::freopen;
use reqwest::Client; use reqwest::Client;
use rodio::{OutputStream, OutputStreamHandle, Sink}; use rodio::{OutputStream, OutputStreamHandle, Sink};
use tokio::{ use tokio::{
@ -85,12 +86,34 @@ unsafe impl Send for Player {}
unsafe impl Sync for Player {} unsafe impl Sync for Player {}
impl Player { impl Player {
/// This gets the output stream while also shutting up alsa.
fn get_output_stream() -> eyre::Result<(OutputStream, OutputStreamHandle)> {
extern "C" {
static stderr: *mut libc::FILE;
}
let mode = c"w".as_ptr();
// 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.
// SAFETY: Simple enough to be impossible to fail. Hopefully.
unsafe { freopen(c"/dev/null".as_ptr(), mode, stderr) };
let (stream, handle) = OutputStream::try_default()?;
// SAFETY: See the first call to `freopen`.
unsafe { freopen(c"/dev/tty".as_ptr(), mode, stderr) };
Ok((stream, handle))
}
/// Initializes the entire player, including audio devices & sink. /// Initializes the entire player, including audio devices & sink.
pub async fn new() -> eyre::Result<Self> { pub async fn new() -> eyre::Result<Self> {
let (_stream, handle) = OutputStream::try_default()?; let (_stream, handle) = Self::get_output_stream()?;
let sink = Sink::try_new(&handle)?; let sink = Sink::try_new(&handle)?;
Ok(Self { let player = Self {
tracks: RwLock::new(VecDeque::with_capacity(5)), tracks: RwLock::new(VecDeque::with_capacity(5)),
current: ArcSwapOption::new(None), current: ArcSwapOption::new(None),
client: Client::builder() client: Client::builder()
@ -104,7 +127,9 @@ impl Player {
sink, sink,
_handle: handle, _handle: handle,
_stream, _stream,
}) };
Ok(player)
} }
/// Just a shorthand for setting `current`. /// Just a shorthand for setting `current`.

View File

@ -13,7 +13,7 @@ use crate::tracks::TrackInfo;
use super::Player; use super::Player;
use crossterm::{ use crossterm::{
cursor::{Hide, MoveTo, MoveToColumn, MoveUp, RestorePosition, Show}, cursor::{Hide, MoveTo, MoveToColumn, MoveUp, Show},
event::{self, KeyCode, KeyModifiers}, event::{self, KeyCode, KeyModifiers},
style::{Print, Stylize}, style::{Print, Stylize},
terminal::{self, Clear, ClearType, EnterAlternateScreen, LeaveAlternateScreen}, terminal::{self, Clear, ClearType, EnterAlternateScreen, LeaveAlternateScreen},
@ -196,13 +196,7 @@ pub async fn start(
sender: Sender<Messages>, sender: Sender<Messages>,
alternate: bool, alternate: bool,
) -> eyre::Result<()> { ) -> eyre::Result<()> {
crossterm::execute!( crossterm::execute!(stdout(), Hide)?;
stdout(),
RestorePosition,
Clear(ClearType::CurrentLine),
Clear(ClearType::FromCursorDown),
Hide
)?;
terminal::enable_raw_mode()?; terminal::enable_raw_mode()?;