libfoksalaudio 1.2.9

foksal audio library
Documentation
use anyhow::Result;
use crossbeam_channel as cbeam_chan;
use serde::Serialize;
use std::{
    collections::HashMap,
    net::SocketAddr,
    path::{Path, PathBuf},
};
use tokio::sync::{mpsc as tokio_chan, oneshot};

use crate::{
    Volume,
    queue::{Queue, QueueMode},
    sink::{PlaybackState, SinkRequest},
};
use libfoksalcommon::net::{request::PlayerSubTarget, response::EventNotif};

type PlayerSubscribersMap =
    HashMap<(PlayerSubTarget, SocketAddr), tokio_chan::UnboundedSender<EventNotif>>;

#[derive(Clone, Serialize)]
#[serde(tag = "player_event", rename_all = "snake_case")]
pub enum PlayerEvent {
    QueueContent { queue: Vec<PathBuf> },
    QueuePos { pos: Option<usize> },
    QueueMode { mode: QueueMode },
    CurrentSong { uri: PathBuf, id: usize },
    PlaybackState { state: PlaybackState },
    Volume { volume: u8 },
    Elapsed { seconds: u64 },
}

pub struct Player {
    queue: Queue,
    subscribers: PlayerSubscribersMap,
    tx_sink_request: cbeam_chan::Sender<SinkRequest>,
    tx_mpris_event: tokio_chan::UnboundedSender<PlayerEvent>,
}

impl Player {
    pub fn new(
        tx_sink_request: cbeam_chan::Sender<SinkRequest>,
        tx_mpris_event: tokio_chan::UnboundedSender<PlayerEvent>,
    ) -> Self {
        Self {
            queue: Queue::new(),
            subscribers: HashMap::new(),
            tx_sink_request,
            tx_mpris_event,
        }
    }

    pub fn add_subscriber(
        &mut self,
        target: PlayerSubTarget,
        addr: SocketAddr,
        send_to: tokio_chan::UnboundedSender<EventNotif>,
    ) {
        self.subscribers.insert((target, addr), send_to);
    }

    pub fn remove_subscriber(&mut self, target: PlayerSubTarget, addr: SocketAddr) {
        self.subscribers.remove(&(target, addr));
    }

    pub fn queue(&self) -> &Queue {
        &self.queue
    }

    pub async fn playback_state(&self) -> PlaybackState {
        let (tx, rx) = oneshot::channel();
        let _ = self.tx_sink_request.send(SinkRequest::GetState(tx));
        rx.await.unwrap_or_default()
    }

    pub fn cur_song(&self) -> Option<&Path> {
        self.queue.cur().map(|c| c.0)
    }

    pub fn cur_id(&self) -> Option<usize> {
        self.queue.cur().map(|c| c.1)
    }

    pub async fn volume(&self) -> u8 {
        let (tx, rx) = oneshot::channel();
        let _ = self.tx_sink_request.send(SinkRequest::GetVolume(tx));
        rx.await.unwrap_or_default().0
    }

    pub async fn elapsed(&self) -> u64 {
        let (tx, rx) = oneshot::channel();
        let _ = self.tx_sink_request.send(SinkRequest::GetElapsed(tx));
        rx.await.unwrap_or_default()
    }

    pub fn add_to_queue(
        &mut self,
        uris: Vec<impl AsRef<Path> + Into<PathBuf>>,
        pos: Option<usize>,
    ) -> Result<()> {
        let res = match pos {
            Some(pos) => self.queue.insert(&uris, pos),
            None => {
                self.queue.push(&uris);
                Ok(())
            }
        };
        if res.is_ok() {
            self.notify_queue_content();
        }

        res
    }

    pub fn remove_from_queue(&mut self, pos: usize) -> Result<()> {
        if self.queue.pos().is_some_and(|p| p == pos) {
            self.stop();
        }
        let prev_pos = self.queue.pos();
        self.queue.remove(pos)?;
        self.notify_queue_content();
        if prev_pos != self.queue.pos() {
            self.notify_queue_pos();
        }

        Ok(())
    }

    pub fn queue_move(&mut self, from: usize, to: usize) -> Result<()> {
        self.queue.move_pos(from, to)?;
        self.notify_queue_content();
        self.notify_queue_pos();

        Ok(())
    }

    pub fn play(&mut self, pos: usize) -> Result<()> {
        self.queue.move_to(pos)?;
        let uri = self.queue.get(pos)?;
        let id = self.queue.get_id(pos)?;
        self.play_from_uri(uri, id);
        self.notify_queue_pos();

        Ok(())
    }

    pub fn add_and_play(&mut self, uris: Vec<impl AsRef<Path> + Into<PathBuf>>) {
        self.queue.push_and_move_to(&uris);
        self.notify_queue_content();
        self.next();
    }

    pub fn volume_change(&self, delta: i8) {
        let _ = self.tx_sink_request.send(SinkRequest::VolChange(delta));
    }

    pub fn volume_set(&self, volume: u8) {
        let _ = self.tx_sink_request.send(SinkRequest::VolSet(volume));
    }

    pub fn seek_by(&self, seconds: isize) {
        let _ = self.tx_sink_request.send(SinkRequest::SeekBy(seconds));
    }

    pub fn seek_to(&self, seconds: usize) {
        let _ = self.tx_sink_request.send(SinkRequest::SeekTo(seconds));
    }

    pub fn pause(&self) {
        let _ = self.tx_sink_request.send(SinkRequest::Pause);
    }

    pub fn resume(&self) {
        let _ = self.tx_sink_request.send(SinkRequest::Resume);
    }

    pub fn toggle(&self) {
        let _ = self.tx_sink_request.send(SinkRequest::Toggle);
    }

    pub fn stop(&mut self) {
        let _ = self.tx_sink_request.send(SinkRequest::Stop);
        self.queue.stop();
        self.notify_queue_pos();
    }

    pub fn next(&mut self) {
        self.queue.move_to_next();
        match self.queue.cur() {
            Some((uri, id)) => self.play_from_uri(uri, id),
            None => self.stop(),
        }
        self.notify_queue_pos();
    }

    pub fn prev(&mut self) {
        self.queue.move_to_prev();
        match self.queue.cur() {
            Some((uri, id)) => self.play_from_uri(uri, id),
            None => self.stop(),
        }
        self.notify_queue_pos();
    }

    pub fn queue_seq(&mut self) {
        self.queue.set_mode_seq();
        self.notify_queue_mode();
    }

    pub fn queue_loop(&mut self) {
        self.queue.set_mode_loop();
        self.notify_queue_mode();
    }

    pub fn queue_random(&mut self) {
        self.queue.set_mode_random();
        self.notify_queue_mode();
    }

    pub fn queue_single(&mut self) {
        self.queue.set_mode_single();
        self.notify_queue_mode();
    }

    pub fn queue_clear(&mut self) {
        self.queue.clear();
        let _ = self.tx_sink_request.send(SinkRequest::Stop);
        self.notify_queue_pos();
        self.notify_queue_content();
    }

    pub fn notify_queue_pos(&self) {
        let pos = self.queue.pos();
        self.notify_subscribers(PlayerSubTarget::Player, PlayerEvent::QueuePos { pos });
    }

    pub fn notify_queue_content(&self) {
        let queue = self.queue.list_cloned();
        self.notify_subscribers(PlayerSubTarget::Player, PlayerEvent::QueueContent { queue });
    }

    pub fn notify_playback_state(&self, state: PlaybackState) {
        let ev = PlayerEvent::PlaybackState { state };
        self.notify_subscribers(PlayerSubTarget::Player, ev.clone());
        self.notify_mpris(ev);
    }

    pub fn notify_queue_mode(&self) {
        let mode = self.queue.mode();
        let ev = PlayerEvent::QueueMode { mode };
        self.notify_subscribers(PlayerSubTarget::Player, ev.clone());
        self.notify_mpris(ev);
    }

    pub fn notify_volume(&self, Volume(volume): Volume) {
        let ev = PlayerEvent::Volume { volume };
        self.notify_subscribers(PlayerSubTarget::Player, ev.clone());
        self.notify_mpris(ev);
    }

    pub fn notify_elapsed(&self, seconds: u64) {
        self.notify_subscribers(PlayerSubTarget::Player, PlayerEvent::Elapsed { seconds });
    }

    pub fn notify_song(&self, uri: impl AsRef<Path>, id: usize) {
        let ev = PlayerEvent::CurrentSong {
            uri: uri.as_ref().to_path_buf(),
            id,
        };
        self.notify_subscribers(PlayerSubTarget::Player, ev.clone());
        self.notify_mpris(ev);
    }

    fn play_from_uri(&self, uri: impl AsRef<Path>, id: usize) {
        let _ = self
            .tx_sink_request
            .send(SinkRequest::Play(uri.as_ref().to_path_buf()));
        self.notify_song(uri, id);
    }

    fn notify_subscribers(&self, target: PlayerSubTarget, event: PlayerEvent) {
        for (sub, send_to) in self.subscribers.iter() {
            let (sub_target, sub_addr) = sub;
            if *sub_target == target {
                let _ = send_to.send(EventNotif::new(event.clone(), *sub_addr));
            }
        }
    }

    fn notify_mpris(&self, event: PlayerEvent) {
        let _ = self.tx_mpris_event.send(event);
    }
}