mirror of
https://github.com/talwat/lowfi
synced 2025-12-07 23:47:46 +00:00
fix: make audio waiter actually work
This commit is contained in:
parent
20a87d5363
commit
1f3a751a90
29
src/audio.rs
29
src/audio.rs
@ -1,11 +1,4 @@
|
||||
use std::{
|
||||
sync::{atomic::AtomicBool, Arc},
|
||||
thread::sleep,
|
||||
time::Duration,
|
||||
};
|
||||
|
||||
use rodio::Sink;
|
||||
use tokio::sync::mpsc;
|
||||
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.
|
||||
@ -47,23 +40,3 @@ pub fn silent_get_output_stream() -> eyre::Result<rodio::OutputStream, crate::Er
|
||||
|
||||
Ok(stream)
|
||||
}
|
||||
|
||||
static LISTEN: AtomicBool = AtomicBool::new(false);
|
||||
pub fn playing(status: bool) {
|
||||
LISTEN.store(status, std::sync::atomic::Ordering::Relaxed);
|
||||
}
|
||||
|
||||
pub fn waiter(sink: Arc<Sink>, tx: mpsc::Sender<crate::Message>) -> crate::Result<()> {
|
||||
loop {
|
||||
if Arc::strong_count(&sink) == 1 {
|
||||
break Ok(());
|
||||
}
|
||||
|
||||
sleep(Duration::from_millis(100));
|
||||
sink.sleep_until_end();
|
||||
|
||||
if LISTEN.load(std::sync::atomic::Ordering::Relaxed) {
|
||||
tx.blocking_send(crate::Message::Next)?;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
49
src/audio/waiter.rs
Normal file
49
src/audio/waiter.rs
Normal file
@ -0,0 +1,49 @@
|
||||
use std::{sync::Arc, thread::sleep, time::Duration};
|
||||
|
||||
use rodio::Sink;
|
||||
use tokio::{
|
||||
sync::{broadcast, mpsc},
|
||||
task::{self, JoinHandle},
|
||||
};
|
||||
|
||||
use crate::ui::{self, Update};
|
||||
|
||||
pub struct Handle {
|
||||
_task: JoinHandle<()>,
|
||||
}
|
||||
|
||||
impl Handle {
|
||||
pub fn new(
|
||||
sink: Arc<Sink>,
|
||||
tx: mpsc::Sender<crate::Message>,
|
||||
rx: broadcast::Receiver<ui::Update>,
|
||||
) -> Self {
|
||||
Self {
|
||||
_task: task::spawn_blocking(|| Self::waiter(sink, tx, rx)),
|
||||
}
|
||||
}
|
||||
|
||||
fn waiter(
|
||||
sink: Arc<Sink>,
|
||||
tx: mpsc::Sender<crate::Message>,
|
||||
mut rx: broadcast::Receiver<ui::Update>,
|
||||
) {
|
||||
'main: loop {
|
||||
if !matches!(rx.blocking_recv(), Ok(Update::Track(_))) {
|
||||
continue;
|
||||
}
|
||||
|
||||
while !sink.empty() {
|
||||
if matches!(rx.try_recv(), Ok(Update::Quit)) {
|
||||
break 'main;
|
||||
}
|
||||
|
||||
sleep(Duration::from_millis(8));
|
||||
}
|
||||
|
||||
if let Err(_) = tx.try_send(crate::Message::Next) {
|
||||
break;
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -46,4 +46,7 @@ pub enum Error {
|
||||
|
||||
#[error("ui failure")]
|
||||
UI(#[from] ui::Error),
|
||||
|
||||
#[error("join error")]
|
||||
JoinError(#[from] tokio::task::JoinError),
|
||||
}
|
||||
|
||||
@ -5,9 +5,6 @@ pub enum Message {
|
||||
/// Deliberate user request to go to the next song.
|
||||
Next,
|
||||
|
||||
/// Sent by the audio waiter whenever it believes a track has ended.
|
||||
End,
|
||||
|
||||
/// When a track is loaded after the caller previously being told to wait.
|
||||
/// If a track is taken from the queue, then there is no waiting, so this
|
||||
/// is never actually sent.
|
||||
|
||||
@ -1,15 +1,12 @@
|
||||
use std::sync::Arc;
|
||||
|
||||
use tokio::{
|
||||
sync::{
|
||||
broadcast,
|
||||
mpsc::{self, Receiver},
|
||||
},
|
||||
task::JoinHandle,
|
||||
use tokio::sync::{
|
||||
broadcast,
|
||||
mpsc::{self, Receiver, Sender},
|
||||
};
|
||||
|
||||
use crate::{
|
||||
audio,
|
||||
audio::waiter,
|
||||
bookmark::Bookmarks,
|
||||
download::{self, Downloader},
|
||||
tracks::{self, List},
|
||||
@ -38,14 +35,15 @@ pub struct Player {
|
||||
broadcast: broadcast::Sender<ui::Update>,
|
||||
current: Current,
|
||||
ui: ui::Handle,
|
||||
waiter: JoinHandle<crate::Result<()>>,
|
||||
_tx: Sender<crate::Message>,
|
||||
_waiter: waiter::Handle,
|
||||
_stream: rodio::OutputStream,
|
||||
}
|
||||
|
||||
impl Drop for Player {
|
||||
fn drop(&mut self) {
|
||||
self.sink.stop();
|
||||
self.waiter.abort();
|
||||
self.broadcast.send(ui::Update::Quit).unwrap();
|
||||
}
|
||||
}
|
||||
|
||||
@ -88,25 +86,20 @@ impl Player {
|
||||
|
||||
let list = List::load(args.track_list.as_ref()).await?;
|
||||
let state = ui::State::initial(sink.clone(), &args, current.clone(), list.name.clone());
|
||||
let ui = ui::Handle::init(tx.clone(), urx, state.clone(), &args).await?;
|
||||
|
||||
let volume = PersistentVolume::load().await?;
|
||||
sink.set_volume(volume.float());
|
||||
let bookmarks = Bookmarks::load().await?;
|
||||
let downloader = Downloader::init(args.buffer_size, list, tx.clone()).await;
|
||||
|
||||
let clone = sink.clone();
|
||||
let waiter = tokio::task::spawn_blocking(move || audio::waiter(clone, tx));
|
||||
|
||||
Ok(Self {
|
||||
downloader: Downloader::init(args.buffer_size, list, tx.clone()).await,
|
||||
ui: ui::Handle::init(tx.clone(), urx.resubscribe(), state.clone(), &args).await?,
|
||||
_waiter: waiter::Handle::new(sink.clone(), tx.clone(), urx),
|
||||
bookmarks: Bookmarks::load().await?,
|
||||
current,
|
||||
downloader,
|
||||
broadcast: utx,
|
||||
rx,
|
||||
sink,
|
||||
bookmarks,
|
||||
ui,
|
||||
waiter,
|
||||
_tx: tx,
|
||||
_stream: stream,
|
||||
})
|
||||
}
|
||||
@ -129,21 +122,18 @@ impl Player {
|
||||
pub async fn run(mut self) -> crate::Result<()> {
|
||||
while let Some(message) = self.rx.recv().await {
|
||||
match message {
|
||||
Message::Next | Message::Init | Message::Loaded | Message::End => {
|
||||
Message::Next | Message::Init | Message::Loaded => {
|
||||
if message == Message::Next && self.current.loading() {
|
||||
continue;
|
||||
}
|
||||
|
||||
audio::playing(false);
|
||||
self.sink.stop();
|
||||
|
||||
match self.downloader.track().await {
|
||||
download::Output::Loading(progress) => {
|
||||
self.set_current(Current::Loading(progress)).await?;
|
||||
}
|
||||
download::Output::Queued(queued) => {
|
||||
self.play(queued).await?;
|
||||
audio::playing(true);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@ -94,6 +94,10 @@ impl List {
|
||||
x.to_owned()
|
||||
};
|
||||
|
||||
if let Some(progress) = progress {
|
||||
progress.store(100, Ordering::Relaxed);
|
||||
}
|
||||
|
||||
let result = tokio::fs::read(path.clone()).await.track(x)?;
|
||||
result.into()
|
||||
} else {
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user