use std::sync::mpsc::{channel, Receiver, Sender}; use std::thread::JoinHandle; use mps_interpreter::tokens::MpsTokenReader; use super::os_controls::SystemControlWrapper; use super::player_wrapper::{ControlAction, MpsPlayerServer, PlayerAction}; use super::MpsPlayer; use super::PlaybackError; /// A controller for a MpsPlayer running on another thread. /// This receives and sends events like media buttons and script errors for the MpsPlayer. pub struct MpsController { control: Sender, event: Receiver, handle: JoinHandle<()>, sys_ctrl: SystemControlWrapper, } impl MpsController { pub fn create MpsPlayer + Send + 'static, T: MpsTokenReader>( player_gen: F, ) -> Self { let (control_tx, control_rx) = channel(); let (event_tx, event_rx) = channel(); let mut sys_ctrl = SystemControlWrapper::new(control_tx.clone()); sys_ctrl.init(); let handle = MpsPlayerServer::spawn(player_gen, control_tx.clone(), control_rx, event_tx, false); Self { control: control_tx, event: event_rx, handle: handle, sys_ctrl: sys_ctrl, } } pub fn create_repl MpsPlayer + Send + 'static, T: MpsTokenReader>( player_gen: F, ) -> Self { let (control_tx, control_rx) = channel(); let (event_tx, event_rx) = channel(); let mut sys_ctrl = SystemControlWrapper::new(control_tx.clone()); sys_ctrl.init(); let handle = MpsPlayerServer::spawn(player_gen, control_tx.clone(), control_rx, event_tx, true); Self { control: control_tx, event: event_rx, handle: handle, sys_ctrl: sys_ctrl, } } fn send_confirm(&self, to_send: ControlAction) -> Result<(), PlaybackError> { self.control .send(to_send.clone()) .map_err(PlaybackError::from_err)?; let mut response = self.event.recv().map_err(PlaybackError::from_err)?; while !response.is_acknowledgement() { Self::handle_event(response)?; response = self.event.recv().map_err(PlaybackError::from_err)?; } if let PlayerAction::Acknowledge(action) = response { if action == to_send { Ok(()) } else { Err(PlaybackError { msg: "Incorrect acknowledgement received for MpsController control action" .into(), }) } } else { Err(PlaybackError { msg: "Invalid acknowledgement received for MpsController control action".into(), }) } } fn handle_event(event: PlayerAction) -> Result<(), PlaybackError> { match event { PlayerAction::Acknowledge(_) => Ok(()), PlayerAction::Exception(e) => Err(e), PlayerAction::End => Ok(()), PlayerAction::Empty => Ok(()), } } pub fn next(&self) -> Result<(), PlaybackError> { self.send_confirm(ControlAction::Next { ack: true }) } pub fn previous(&self) -> Result<(), PlaybackError> { self.send_confirm(ControlAction::Previous { ack: true }) } pub fn play(&self) -> Result<(), PlaybackError> { self.send_confirm(ControlAction::Play { ack: true }) } pub fn pause(&self) -> Result<(), PlaybackError> { self.send_confirm(ControlAction::Pause { ack: true }) } pub fn stop(&self) -> Result<(), PlaybackError> { self.send_confirm(ControlAction::Stop { ack: true }) } pub fn enqueue(&self, count: usize) -> Result<(), PlaybackError> { self.send_confirm(ControlAction::Enqueue { amount: count, ack: true, }) } pub fn ping(&self) -> Result<(), PlaybackError> { self.send_confirm(ControlAction::NoOp { ack: true }) } pub fn exit(self) -> Result<(), PlaybackError> { self.send_confirm(ControlAction::Exit { ack: true })?; self.sys_ctrl.exit(); match self.handle.join() { Ok(x) => Ok(x), Err(_) => Err(PlaybackError { msg: "MpsPlayerServer did not exit correctly".into(), }), } } pub fn wait_for_done(&self) -> Result<(), PlaybackError> { loop { let msg = self.event.recv().map_err(PlaybackError::from_err)?; if let PlayerAction::End = msg { break; } else { Self::handle_event(msg)?; } } Ok(()) } pub fn wait_for_empty(&self) -> Result<(), PlaybackError> { for msg in self.event.try_iter() { Self::handle_event(msg)?; } self.control .send(ControlAction::CheckEmpty { ack: true }) .map_err(PlaybackError::from_err)?; loop { let msg = self.event.recv().map_err(PlaybackError::from_err)?; if let PlayerAction::Empty = msg { break; } else { Self::handle_event(msg)?; } } Ok(()) } /// Check for any errors in the event queue. /// This is non-blocking, so it only handles events sent since the last time events were handled. pub fn check(&self) -> Vec { let mut result = Vec::new(); for msg in self.event.try_iter() { if let Err(e) = Self::handle_event(msg) { result.push(e); } } result } /// Like check(), but it also waits for an acknowledgement to ensure it gets the latest events. pub fn check_ack(&self) -> Vec { let mut result = Vec::new(); let to_send = ControlAction::NoOp { ack: true }; if let Err(e) = self .control .send(to_send.clone()) .map_err(PlaybackError::from_err) { result.push(e); } for msg in self.event.iter() { if let PlayerAction::Acknowledge(action) = msg { if action == to_send { break; } else { result.push(PlaybackError { msg: "Incorrect acknowledgement received for MpsController control action" .into(), }); } } else if let Err(e) = Self::handle_event(msg) { result.push(e); } } result } }