Skip to content

Commit

Permalink
Merge branch 'dev' into resampling
Browse files Browse the repository at this point in the history
  • Loading branch information
JasonLG1979 authored Sep 3, 2023
2 parents a5529be + 054074c commit 6907ecd
Show file tree
Hide file tree
Showing 11 changed files with 106 additions and 37 deletions.
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,9 @@ https://github.com/librespot-org/librespot
- [all] `chrono` replaced with `time` (breaking)
- [all] `time` updated (CVE-2020-26235)
- [all] Improve lock contention and performance (breaking)
- [all] Use a single `player` instance. Eliminates occasional `player` and
`audio backend` restarts, which can cause issues with some playback
configurations.
- [audio] Files are now downloaded over the HTTPS CDN (breaking)
- [audio] Improve file opening and seeking performance (breaking)
- [core] MSRV is now 1.65 (breaking)
Expand Down
4 changes: 2 additions & 2 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

16 changes: 11 additions & 5 deletions connect/src/spirc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ use std::{
future::Future,
pin::Pin,
sync::atomic::{AtomicUsize, Ordering},
sync::Arc,
time::{SystemTime, UNIX_EPOCH},
};

Expand Down Expand Up @@ -77,8 +78,8 @@ enum SpircPlayStatus {
type BoxedStream<T> = Pin<Box<dyn FusedStream<Item = T> + Send>>;

struct SpircTask {
player: Player,
mixer: Box<dyn Mixer>,
player: Arc<Player>,
mixer: Arc<dyn Mixer>,

sequence: SeqGenerator<u32>,

Expand Down Expand Up @@ -272,8 +273,8 @@ impl Spirc {
config: ConnectConfig,
session: Session,
credentials: Credentials,
player: Player,
mixer: Box<dyn Mixer>,
player: Arc<Player>,
mixer: Arc<dyn Mixer>,
) -> Result<(Spirc, impl Future<Output = ()>), Error> {
let spirc_id = SPIRC_COUNTER.fetch_add(1, Ordering::AcqRel);
debug!("new Spirc[{}]", spirc_id);
Expand Down Expand Up @@ -663,6 +664,11 @@ impl SpircTask {
}

fn handle_player_event(&mut self, event: PlayerEvent) -> Result<(), Error> {
// update play_request_id
if let PlayerEvent::PlayRequestIdChanged { play_request_id } = event {
self.play_request_id = Some(play_request_id);
return Ok(());
}
// we only process events if the play_request_id matches. If it doesn't, it is
// an event that belongs to a previous track and only arrives now due to a race
// condition. In this case we have updated the state already and don't want to
Expand Down Expand Up @@ -1462,7 +1468,7 @@ impl SpircTask {
Some((track, index)) => {
self.state.set_playing_track_index(index);

self.play_request_id = Some(self.player.load(track, start_playing, position_ms));
self.player.load(track, start_playing, position_ms);

self.update_state_position(position_ms);
if start_playing {
Expand Down
2 changes: 1 addition & 1 deletion core/src/authentication.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ impl From<AuthenticationError> for Error {
}

/// The credentials are used to log into the Spotify API.
#[derive(Debug, Clone, Default, Serialize, Deserialize)]
#[derive(Debug, Clone, Default, Serialize, Deserialize, PartialEq)]
pub struct Credentials {
pub username: String,

Expand Down
8 changes: 7 additions & 1 deletion core/src/session.rs
Original file line number Diff line number Diff line change
Expand Up @@ -176,7 +176,13 @@ impl Session {
self.set_username(&reusable_credentials.username);
if let Some(cache) = self.cache() {
if store_credentials {
cache.save_credentials(&reusable_credentials);
let cred_changed = cache
.credentials()
.map(|c| c != reusable_credentials)
.unwrap_or(true);
if cred_changed {
cache.save_credentials(&reusable_credentials);
}
}
}

Expand Down
3 changes: 2 additions & 1 deletion examples/play_connect.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ use librespot_metadata::{Album, Metadata};
use librespot_playback::mixer::{softmixer::SoftMixer, Mixer, MixerConfig};
use librespot_protocol::spirc::TrackRef;
use std::env;
use std::sync::Arc;
use tokio::join;

#[tokio::main]
Expand Down Expand Up @@ -55,7 +56,7 @@ async fn main() {
session.clone(),
credentials,
player,
Box::new(SoftMixer::open(MixerConfig::default())),
Arc::new(SoftMixer::open(MixerConfig::default())),
)
.await
.unwrap();
Expand Down
4 changes: 2 additions & 2 deletions playback/src/audio_backend/jackaudio.rs
Original file line number Diff line number Diff line change
Expand Up @@ -55,8 +55,8 @@ impl Open for JackSink {
let client_name = client_name.unwrap_or_else(|| "librespot".to_string());
let (client, _status) =
Client::new(&client_name[..], ClientOptions::NO_START_SERVER).unwrap();
let ch_r = client.register_port("out_0", AudioOut::default()).unwrap();
let ch_l = client.register_port("out_1", AudioOut::default()).unwrap();
let ch_r = client.register_port("out_0", AudioOut).unwrap();
let ch_l = client.register_port("out_1", AudioOut).unwrap();
// buffer for samples from librespot (~10ms)
let (tx, rx) = sync_channel::<f32>(NUM_CHANNELS as usize * 1024 * AudioFormat::F32.size());
let jack_data = JackData {
Expand Down
10 changes: 6 additions & 4 deletions playback/src/mixer/mod.rs
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
use std::sync::Arc;

use crate::config::VolumeCtrl;

pub mod mappings;
use self::mappings::MappedCtrl;

pub struct NoOpVolume;

pub trait Mixer: Send {
pub trait Mixer: Send + Sync {
fn open(config: MixerConfig) -> Self
where
Self: Sized;
Expand Down Expand Up @@ -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> {
Box::new(M::open(config))
fn mk_sink<M: Mixer + 'static>(config: MixerConfig) -> Arc<dyn Mixer> {
Arc::new(M::open(config))
}

pub const MIXERS: &[(&str, MixerFn)] = &[
Expand Down
50 changes: 32 additions & 18 deletions playback/src/player.rs
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,6 @@ pub type PlayerResult = Result<(), Error>;
pub struct Player {
commands: Option<mpsc::UnboundedSender<PlayerCommand>>,
thread_handle: Option<thread::JoinHandle<()>>,
play_request_id_generator: SeqGenerator<u64>,
}

#[derive(PartialEq, Eq, Debug, Clone, Copy)]
Expand Down Expand Up @@ -79,14 +78,14 @@ struct PlayerInternal {
auto_normalise_as_album: bool,

player_id: usize,
play_request_id_generator: SeqGenerator<u64>,
}

pub static PLAYER_COUNTER: AtomicUsize = AtomicUsize::new(0);

enum PlayerCommand {
Load {
track_id: SpotifyId,
play_request_id: u64,
play: bool,
position_ms: u32,
},
Expand All @@ -97,6 +96,7 @@ enum PlayerCommand {
Pause,
Stop,
Seek(u32),
SetSession(Session),
AddEventSender(mpsc::UnboundedSender<PlayerEvent>),
SetSinkEventCallback(Option<SinkEventCallback>),
EmitVolumeChangedEvent(u16),
Expand All @@ -123,6 +123,10 @@ enum PlayerCommand {

#[derive(Debug, Clone)]
pub enum PlayerEvent {
// Play request id changed
PlayRequestIdChanged {
play_request_id: u64,
},
// Fired when the player is stopped (e.g. by issuing a "stop" command to the player).
Stopped {
play_request_id: u64,
Expand Down Expand Up @@ -318,7 +322,7 @@ impl Player {
session: Session,
volume_getter: Box<dyn VolumeGetter>,
sink_builder: F,
) -> Self
) -> Arc<Self>
where
F: FnOnce() -> Box<dyn Sink> + Send + 'static,
{
Expand Down Expand Up @@ -349,6 +353,7 @@ impl Player {
auto_normalise_as_album: false,

player_id,
play_request_id_generator: SeqGenerator::new(0),
};

// While PlayerInternal is written as a future, it still contains blocking code.
Expand Down Expand Up @@ -382,11 +387,17 @@ impl Player {
}
};

Self {
Arc::new(Self {
commands: Some(cmd_tx),
thread_handle: Some(handle),
play_request_id_generator: SeqGenerator::new(0),
})
}

pub fn is_invalid(&self) -> bool {
if let Some(handle) = self.thread_handle.as_ref() {
return handle.is_finished();
}
true
}

fn command(&self, cmd: PlayerCommand) {
Expand All @@ -397,16 +408,12 @@ impl Player {
}
}

pub fn load(&mut self, track_id: SpotifyId, start_playing: bool, position_ms: u32) -> u64 {
let play_request_id = self.play_request_id_generator.get();
pub fn load(&self, track_id: SpotifyId, start_playing: bool, position_ms: u32) {
self.command(PlayerCommand::Load {
track_id,
play_request_id,
play: start_playing,
position_ms,
});

play_request_id
}

pub fn preload(&self, track_id: SpotifyId) {
Expand All @@ -429,6 +436,10 @@ impl Player {
self.command(PlayerCommand::Seek(position_ms));
}

pub fn set_session(&self, session: Session) {
self.command(PlayerCommand::SetSession(session));
}

pub fn get_player_event_channel(&self) -> PlayerEventChannel {
let (event_sender, event_receiver) = mpsc::unbounded_channel();
self.command(PlayerCommand::AddEventSender(event_sender));
Expand Down Expand Up @@ -1264,10 +1275,6 @@ impl Future for PlayerInternal {
}
}

if self.session.is_invalid() {
return Poll::Ready(());
}

if (!self.state.is_playing()) && all_futures_completed_or_not_ready {
return Poll::Pending;
}
Expand Down Expand Up @@ -1515,10 +1522,15 @@ impl PlayerInternal {
fn handle_command_load(
&mut self,
track_id: SpotifyId,
play_request_id: u64,
play_request_id_option: Option<u64>,
play: bool,
position_ms: u32,
) -> PlayerResult {
let play_request_id =
play_request_id_option.unwrap_or(self.play_request_id_generator.get());

self.send_event(PlayerEvent::PlayRequestIdChanged { play_request_id });

if !self.config.gapless {
self.ensure_sink_stopped(play);
}
Expand Down Expand Up @@ -1771,7 +1783,7 @@ impl PlayerInternal {
{
return self.handle_command_load(
track_id,
play_request_id,
Some(play_request_id),
start_playback,
position_ms,
);
Expand Down Expand Up @@ -1828,10 +1840,9 @@ impl PlayerInternal {
match cmd {
PlayerCommand::Load {
track_id,
play_request_id,
play,
position_ms,
} => self.handle_command_load(track_id, play_request_id, play, position_ms)?,
} => self.handle_command_load(track_id, None, play, position_ms)?,

PlayerCommand::Preload { track_id } => self.handle_command_preload(track_id),

Expand All @@ -1843,6 +1854,8 @@ impl PlayerInternal {

PlayerCommand::Stop => self.handle_player_stop(),

PlayerCommand::SetSession(session) => self.session = session,

PlayerCommand::AddEventSender(sender) => self.event_senders.push(sender),

PlayerCommand::SetSinkEventCallback(callback) => self.sink_event_callback = callback,
Expand Down Expand Up @@ -2057,6 +2070,7 @@ impl fmt::Debug for PlayerCommand {
PlayerCommand::Pause => f.debug_tuple("Pause").finish(),
PlayerCommand::Stop => f.debug_tuple("Stop").finish(),
PlayerCommand::Seek(position) => f.debug_tuple("Seek").field(&position).finish(),
PlayerCommand::SetSession(_) => f.debug_tuple("SetSession").finish(),
PlayerCommand::AddEventSender(_) => f.debug_tuple("AddEventSender").finish(),
PlayerCommand::SetSinkEventCallback(_) => {
f.debug_tuple("SetSinkEventCallback").finish()
Expand Down
Loading

0 comments on commit 6907ecd

Please sign in to comment.