lowfi/src/audio/waiter.rs
Tal 6802db1a1e
feat: better task management (#113)
* docs: attempt to explain tasks.rs

* fix: switch to using a joinset

* chore: remove unused tokio-utils import

* style: reorganize code
2025-12-28 17:12:40 +01:00

54 lines
1.4 KiB
Rust

use std::{sync::Arc, time::Duration};
use rodio::Sink;
use tokio::{
sync::{mpsc, Notify},
time,
};
/// Background loop that waits for the sink to drain and then attempts
/// to send a `Message::Next` to the provided channel.
async fn waiter(
sink: Arc<Sink>,
tx: mpsc::Sender<crate::Message>,
notify: Arc<Notify>,
) -> crate::Result<()> {
loop {
notify.notified().await;
while !sink.empty() {
time::sleep(Duration::from_millis(16)).await;
}
if tx.try_send(crate::Message::Next).is_err() {
break Ok(());
}
}
}
/// Lightweight helper that waits for the current sink to drain and then
/// notifies the player to advance to the next track.
pub struct Handle {
/// Notification primitive used to wake the waiter.
notify: Arc<Notify>,
}
impl Handle {
/// Notify the waiter that playback state may have changed and it should
/// re-check the sink emptiness condition.
pub fn notify(&self) {
self.notify.notify_one();
}
}
impl crate::Tasks {
/// Create a new `Handle` which watches the provided `sink` and sends
/// `Message::Next` down `tx` when the sink becomes empty.
pub fn waiter(&mut self, sink: Arc<Sink>) -> Handle {
let notify = Arc::new(Notify::new());
self.spawn(waiter(sink, self.tx(), notify.clone()));
Handle { notify }
}
}