Use single player and mixer instances

This commit is contained in:
Jarkko Lehtoranta 2023-06-13 17:56:40 +03:00
parent c6b62b82d4
commit e3db0994bc
No known key found for this signature in database
GPG key ID: E539048C587D1F09
6 changed files with 48 additions and 39 deletions

View file

@ -3,6 +3,7 @@ use std::{
future::Future, future::Future,
pin::Pin, pin::Pin,
sync::atomic::{AtomicUsize, Ordering}, sync::atomic::{AtomicUsize, Ordering},
sync::Arc,
time::{SystemTime, UNIX_EPOCH}, time::{SystemTime, UNIX_EPOCH},
}; };
@ -77,8 +78,8 @@ enum SpircPlayStatus {
type BoxedStream<T> = Pin<Box<dyn FusedStream<Item = T> + Send>>; type BoxedStream<T> = Pin<Box<dyn FusedStream<Item = T> + Send>>;
struct SpircTask { struct SpircTask {
player: Player, player: Arc<Player>,
mixer: Box<dyn Mixer>, mixer: Arc<dyn Mixer>,
sequence: SeqGenerator<u32>, sequence: SeqGenerator<u32>,
@ -272,8 +273,8 @@ impl Spirc {
config: ConnectConfig, config: ConnectConfig,
session: Session, session: Session,
credentials: Credentials, credentials: Credentials,
player: Player, player: Arc<Player>,
mixer: Box<dyn Mixer>, mixer: Arc<dyn Mixer>,
) -> Result<(Spirc, impl Future<Output = ()>), Error> { ) -> Result<(Spirc, impl Future<Output = ()>), Error> {
let spirc_id = SPIRC_COUNTER.fetch_add(1, Ordering::AcqRel); let spirc_id = SPIRC_COUNTER.fetch_add(1, Ordering::AcqRel);
debug!("new Spirc[{}]", spirc_id); debug!("new Spirc[{}]", spirc_id);

View file

@ -40,7 +40,7 @@ async fn main() {
exit(1); exit(1);
} }
let mut player = Player::new(player_config, session, Box::new(NoOpVolume), move || { let player = Player::new(player_config, session, Box::new(NoOpVolume), move || {
backend(None, audio_format) backend(None, audio_format)
}); });

View file

@ -17,6 +17,7 @@ use librespot_metadata::{Album, Metadata};
use librespot_playback::mixer::{softmixer::SoftMixer, Mixer, MixerConfig}; use librespot_playback::mixer::{softmixer::SoftMixer, Mixer, MixerConfig};
use librespot_protocol::spirc::TrackRef; use librespot_protocol::spirc::TrackRef;
use std::env; use std::env;
use std::sync::Arc;
use tokio::join; use tokio::join;
#[tokio::main] #[tokio::main]
@ -54,7 +55,7 @@ async fn main() {
session.clone(), session.clone(),
credentials, credentials,
player, player,
Box::new(SoftMixer::open(MixerConfig::default())), Arc::new(SoftMixer::open(MixerConfig::default())),
) )
.await .await
.unwrap(); .unwrap();

View file

@ -1,3 +1,5 @@
use std::sync::Arc;
use crate::config::VolumeCtrl; use crate::config::VolumeCtrl;
pub mod mappings; pub mod mappings;
@ -5,7 +7,7 @@ use self::mappings::MappedCtrl;
pub struct NoOpVolume; pub struct NoOpVolume;
pub trait Mixer: Send { pub trait Mixer: Send + Sync {
fn open(config: MixerConfig) -> Self fn open(config: MixerConfig) -> Self
where where
Self: Sized; Self: Sized;
@ -55,10 +57,10 @@ impl Default for MixerConfig {
} }
} }
pub type MixerFn = fn(MixerConfig) -> Box<dyn Mixer>; pub type MixerFn = fn(MixerConfig) -> Arc<dyn Mixer>;
fn mk_sink<M: Mixer + 'static>(config: MixerConfig) -> Box<dyn Mixer> { fn mk_sink<M: Mixer + 'static>(config: MixerConfig) -> Arc<dyn Mixer> {
Box::new(M::open(config)) Arc::new(M::open(config))
} }
pub const MIXERS: &[(&str, MixerFn)] = &[ pub const MIXERS: &[(&str, MixerFn)] = &[

View file

@ -420,7 +420,7 @@ impl Player {
session: Session, session: Session,
volume_getter: Box<dyn VolumeGetter + Send>, volume_getter: Box<dyn VolumeGetter + Send>,
sink_builder: F, sink_builder: F,
) -> Self ) -> Arc<Self>
where where
F: FnOnce() -> Box<dyn Sink> + Send + 'static, F: FnOnce() -> Box<dyn Sink> + Send + 'static,
{ {
@ -490,10 +490,10 @@ impl Player {
debug!("PlayerInternal thread finished."); debug!("PlayerInternal thread finished.");
}); });
Self { Arc::new(Self {
commands: Some(cmd_tx), commands: Some(cmd_tx),
thread_handle: Some(handle), thread_handle: Some(handle),
} })
} }
pub fn is_invalid(&self) -> bool { pub fn is_invalid(&self) -> bool {
@ -1390,10 +1390,6 @@ impl Future for PlayerInternal {
} }
} }
if self.session.is_invalid() {
return Poll::Ready(());
}
if (!self.state.is_playing()) && all_futures_completed_or_not_ready { if (!self.state.is_playing()) && all_futures_completed_or_not_ready {
return Poll::Pending; return Poll::Pending;
} }

View file

@ -1715,6 +1715,31 @@ async fn main() {
exit(1); exit(1);
} }
let mixer_config = setup.mixer_config.clone();
let mixer = (setup.mixer)(mixer_config);
let player_config = setup.player_config.clone();
let soft_volume = mixer.get_soft_volume();
let format = setup.format;
let backend = setup.backend;
let device = setup.device.clone();
let player = Player::new(player_config, session.clone(), soft_volume, move || {
(backend)(device, format)
});
if let Some(player_event_program) = setup.player_event_program.clone() {
_event_handler = Some(EventHandler::new(
player.get_player_event_channel(),
&player_event_program,
));
if setup.emit_sink_events {
player.set_sink_event_callback(Some(Box::new(move |sink_status| {
run_program_on_sink_events(sink_status, &player_event_program)
})));
}
}
loop { loop {
tokio::select! { tokio::select! {
credentials = async { credentials = async {
@ -1749,32 +1774,16 @@ async fn main() {
_ = async {}, if connecting && last_credentials.is_some() => { _ = async {}, if connecting && last_credentials.is_some() => {
if session.is_invalid() { if session.is_invalid() {
session = Session::new(setup.session_config.clone(), setup.cache.clone()); session = Session::new(setup.session_config.clone(), setup.cache.clone());
player.set_session(session.clone());
} }
let mixer_config = setup.mixer_config.clone();
let mixer = (setup.mixer)(mixer_config);
let player_config = setup.player_config.clone();
let connect_config = setup.connect_config.clone(); let connect_config = setup.connect_config.clone();
let soft_volume = mixer.get_soft_volume(); let (spirc_, spirc_task_) = match Spirc::new(connect_config,
let format = setup.format; session.clone(),
let backend = setup.backend; last_credentials.clone().unwrap_or_default(),
let device = setup.device.clone(); player.clone(),
let player = Player::new(player_config, session.clone(), soft_volume, move || { mixer.clone()).await {
(backend)(device, format)
});
if let Some(player_event_program) = setup.player_event_program.clone() {
_event_handler = Some(EventHandler::new(player.get_player_event_channel(), &player_event_program));
if setup.emit_sink_events {
player.set_sink_event_callback(Some(Box::new(move |sink_status| {
run_program_on_sink_events(sink_status, &player_event_program)
})));
}
};
let (spirc_, spirc_task_) = match Spirc::new(connect_config, session.clone(), last_credentials.clone().unwrap_or_default(), player, mixer).await {
Ok((spirc_, spirc_task_)) => (spirc_, spirc_task_), Ok((spirc_, spirc_task_)) => (spirc_, spirc_task_),
Err(e) => { Err(e) => {
error!("could not initialize spirc: {}", e); error!("could not initialize spirc: {}", e);