Send player event messages over futures aware channel.

This commit is contained in:
Simon Persson 2018-02-20 23:09:48 +01:00
parent 2eb4aa61d3
commit 93af49aadf
4 changed files with 49 additions and 47 deletions

View file

@ -1,7 +1,4 @@
use std::str::FromStr;
use core::spotify_id::SpotifyId;
use std::sync::mpsc::Sender;
use player::PlayerEvent;
#[derive(Clone, Copy, Debug, Hash, PartialOrd, Ord, PartialEq, Eq)]
pub enum Bitrate {
@ -31,14 +28,12 @@ impl Default for Bitrate {
#[derive(Clone, Debug)]
pub struct PlayerConfig {
pub bitrate: Bitrate,
pub event_sender : Option<Sender<PlayerEvent>>,
}
impl Default for PlayerConfig {
fn default() -> PlayerConfig {
PlayerConfig {
bitrate: Bitrate::default(),
event_sender: None,
}
}
}

View file

@ -1,5 +1,6 @@
use futures::sync::oneshot;
use futures::{future, Future};
use futures::sync::mpsc::{UnboundedReceiver, UnboundedSender, unbounded};
use std;
use std::borrow::Cow;
use std::io::{Read, Seek, SeekFrom, Result};
@ -32,6 +33,7 @@ struct PlayerInternal {
sink: Box<Sink>,
sink_running: bool,
audio_filter: Option<Box<AudioFilter + Send>>,
event_sender: UnboundedSender<PlayerEvent>,
}
enum PlayerCommand {
@ -58,14 +60,15 @@ pub enum PlayerEvent {
}
}
type PlayerEventChannel = UnboundedReceiver<PlayerEvent>;
impl Player {
pub fn new<F>(config: PlayerConfig, session: Session,
audio_filter: Option<Box<AudioFilter + Send>>,
sink_builder: F) -> Player
sink_builder: F) -> (Player, PlayerEventChannel)
where F: FnOnce() -> Box<Sink> + Send + 'static
{
let (cmd_tx, cmd_rx) = std::sync::mpsc::channel();
let (event_sender, event_receiver) = unbounded();
let handle = thread::spawn(move || {
debug!("new Player[{}]", session.session_id());
@ -79,15 +82,14 @@ impl Player {
sink: sink_builder(),
sink_running: false,
audio_filter: audio_filter,
event_sender: event_sender,
};
internal.run();
});
Player {
commands: Some(cmd_tx),
thread_handle: Some(handle),
}
(Player { commands: Some(cmd_tx), thread_handle: Some(handle) },
event_receiver)
}
fn command(&self, cmd: PlayerCommand) {
@ -414,11 +416,9 @@ impl PlayerInternal {
}
fn send_event(&mut self, event: PlayerEvent) {
if let Some(ref s) = self.config.event_sender {
match s.send(event.clone()) {
Ok(_) => info!("Sent event {:?} to event listener.", event),
Err(err) => error!("Failed to send event {:?} to listener: {:?}", event, err)
}
match self.event_sender.unbounded_send(event.clone()) {
Ok(_) => info!("Sent event {:?} to event listener.", event),
Err(err) => error!("Failed to send event {:?} to listener: {:?}", event, err)
}
}

View file

@ -9,6 +9,7 @@ extern crate tokio_signal;
use env_logger::LogBuilder;
use futures::{Future, Async, Poll, Stream};
use futures::sync::mpsc::UnboundedReceiver;
use std::env;
use std::io::{self, stderr, Write};
use std::path::PathBuf;
@ -28,7 +29,7 @@ use librespot::playback::audio_backend::{self, Sink, BACKENDS};
use librespot::playback::config::{Bitrate, PlayerConfig};
use librespot::connect::discovery::{discovery, DiscoveryStream};
use librespot::playback::mixer::{self, Mixer};
use librespot::playback::player::Player;
use librespot::playback::player::{Player, PlayerEvent};
use librespot::connect::spirc::{Spirc, SpircTask};
mod player_event_handler;
@ -86,6 +87,7 @@ struct Setup {
credentials: Option<Credentials>,
enable_discovery: bool,
zeroconf_port: u16,
player_event_program: Option<String>,
}
fn setup(args: &[String]) -> Setup {
@ -185,10 +187,7 @@ fn setup(args: &[String]) -> Setup {
.map(|bitrate| Bitrate::from_str(bitrate).expect("Invalid bitrate"))
.unwrap_or(Bitrate::default());
PlayerConfig {
bitrate: bitrate,
event_sender: matches.opt_str("onevent").map(run_program_on_events)
}
PlayerConfig { bitrate: bitrate }
};
let connect_config = {
@ -216,6 +215,7 @@ fn setup(args: &[String]) -> Setup {
enable_discovery: enable_discovery,
zeroconf_port: zeroconf_port,
mixer: mixer,
player_event_program: matches.opt_str("onevent"),
}
}
@ -237,6 +237,9 @@ struct Main {
connect: Box<Future<Item=Session, Error=io::Error>>,
shutdown: bool,
player_event_channel: Option<UnboundedReceiver<PlayerEvent>>,
player_event_program: Option<String>,
}
impl Main {
@ -257,6 +260,9 @@ impl Main {
spirc_task: None,
shutdown: false,
signal: Box::new(tokio_signal::ctrl_c(&handle).flatten_stream()),
player_event_channel: None,
player_event_program: setup.player_event_program,
};
if setup.enable_discovery {
@ -314,13 +320,14 @@ impl Future for Main {
let audio_filter = mixer.get_audio_filter();
let backend = self.backend;
let player = Player::new(player_config, session.clone(), audio_filter, move || {
let (player, event_channel) = Player::new(player_config, session.clone(), audio_filter, move || {
(backend)(device)
});
let (spirc, spirc_task) = Spirc::new(connect_config, session, player, mixer);
self.spirc = Some(spirc);
self.spirc_task = Some(spirc_task);
self.player_event_channel = Some(event_channel);
progress = true;
}
@ -348,6 +355,14 @@ impl Future for Main {
}
}
if let Some(ref mut player_event_channel) = self.player_event_channel {
if let Async::Ready(Some(event)) = player_event_channel.poll().unwrap() {
if let Some(ref program) = self.player_event_program {
run_program_on_events(event, program);
}
}
}
if !progress {
return Ok(Async::NotReady);
}

View file

@ -1,6 +1,4 @@
use std::process::Command;
use std::sync::mpsc::{channel, Sender};
use std::thread;
use std::collections::HashMap;
use librespot::playback::player::PlayerEvent;
@ -15,28 +13,22 @@ fn run_program(program: &str, env_vars: HashMap<&str, String>) {
info!("Exit status: {}", status);
}
pub fn run_program_on_events(onevent: String) -> Sender<PlayerEvent> {
let (sender, receiver) = channel();
thread::spawn(move || {
while let Ok(msg) = receiver.recv() {
let mut env_vars = HashMap::new();
match msg {
PlayerEvent::Changed { old_track_id, new_track_id } => {
env_vars.insert("PLAYER_EVENT", "change".to_string());
env_vars.insert("OLD_TRACK_ID", old_track_id.to_base16());
env_vars.insert("TRACK_ID", new_track_id.to_base16());
},
PlayerEvent::Started { track_id } => {
env_vars.insert("PLAYER_EVENT", "start".to_string());
env_vars.insert("TRACK_ID", track_id.to_base16());
}
PlayerEvent::Stopped { track_id } => {
env_vars.insert("PLAYER_EVENT", "stop".to_string());
env_vars.insert("TRACK_ID", track_id.to_base16());
}
}
run_program(&onevent, env_vars);
pub fn run_program_on_events(event: PlayerEvent, onevent: &str) {
let mut env_vars = HashMap::new();
match event {
PlayerEvent::Changed { old_track_id, new_track_id } => {
env_vars.insert("PLAYER_EVENT", "change".to_string());
env_vars.insert("OLD_TRACK_ID", old_track_id.to_base16());
env_vars.insert("TRACK_ID", new_track_id.to_base16());
},
PlayerEvent::Started { track_id } => {
env_vars.insert("PLAYER_EVENT", "start".to_string());
env_vars.insert("TRACK_ID", track_id.to_base16());
}
});
sender
PlayerEvent::Stopped { track_id } => {
env_vars.insert("PLAYER_EVENT", "stop".to_string());
env_vars.insert("TRACK_ID", track_id.to_base16());
}
}
run_program(onevent, env_vars);
}