108 lines
2.4 KiB
Rust
108 lines
2.4 KiB
Rust
use librespot::{
|
|
connect::spirc::Spirc,
|
|
core::{
|
|
config::{ConnectConfig, SessionConfig},
|
|
session::Session,
|
|
},
|
|
discovery::Credentials,
|
|
playback::{
|
|
config::{Bitrate, PlayerConfig, VolumeCtrl},
|
|
mixer::{self, MixerConfig},
|
|
player::{Player as SpotifyPlayer, PlayerEvent},
|
|
},
|
|
};
|
|
use tokio::sync::mpsc::UnboundedReceiver;
|
|
|
|
use crate::{
|
|
audio::{stream::Stream, SinkEvent, StreamSink},
|
|
librespot_ext::discovery::CredentialsExt,
|
|
utils,
|
|
};
|
|
|
|
pub struct Player {
|
|
stream: Stream,
|
|
session: Option<Session>,
|
|
}
|
|
|
|
impl Player {
|
|
pub fn create() -> Self {
|
|
Self {
|
|
stream: Stream::new(),
|
|
session: None,
|
|
}
|
|
}
|
|
|
|
pub async fn start(
|
|
&mut self,
|
|
token: &str,
|
|
device_name: &str,
|
|
) -> Result<
|
|
(
|
|
Spirc,
|
|
(UnboundedReceiver<PlayerEvent>, UnboundedReceiver<SinkEvent>),
|
|
),
|
|
Box<dyn std::error::Error>,
|
|
> {
|
|
let username = utils::spotify::get_username(token).await?;
|
|
|
|
let player_config = PlayerConfig {
|
|
bitrate: Bitrate::Bitrate96,
|
|
..Default::default()
|
|
};
|
|
|
|
let credentials = Credentials::with_token(username, token);
|
|
|
|
// Shutdown old session (cannot be done in the stop function)
|
|
if let Some(session) = self.session.take() {
|
|
session.shutdown()
|
|
}
|
|
|
|
// Connect the session
|
|
let (session, _) = Session::connect(
|
|
SessionConfig {
|
|
ap_port: Some(9999), // Force the use of ap.spotify.com, which has the lowest latency
|
|
..Default::default()
|
|
},
|
|
credentials,
|
|
None,
|
|
false,
|
|
)
|
|
.await?;
|
|
self.session = Some(session.clone());
|
|
|
|
let mixer = (mixer::find(Some("softvol")).expect("to exist"))(MixerConfig {
|
|
volume_ctrl: VolumeCtrl::Linear,
|
|
..Default::default()
|
|
});
|
|
|
|
let stream = self.get_stream();
|
|
let (tx, rx) = tokio::sync::mpsc::unbounded_channel();
|
|
let (player, receiver) = SpotifyPlayer::new(
|
|
player_config,
|
|
session.clone(),
|
|
mixer.get_soft_volume(),
|
|
move || Box::new(StreamSink::new(stream, tx)),
|
|
);
|
|
|
|
let (spirc, spirc_task) = Spirc::new(
|
|
ConnectConfig {
|
|
name: device_name.into(),
|
|
// 50%
|
|
initial_volume: Some(65535 / 2),
|
|
..Default::default()
|
|
},
|
|
session.clone(),
|
|
player,
|
|
mixer,
|
|
);
|
|
|
|
tokio::spawn(spirc_task);
|
|
|
|
Ok((spirc, (receiver, rx)))
|
|
}
|
|
|
|
pub fn get_stream(&self) -> Stream {
|
|
self.stream.clone()
|
|
}
|
|
}
|