Hello there I'm back

This commit is contained in:
DaXcess
2023-09-18 14:02:59 +02:00
parent 7ae2184679
commit 1ffb07300f
17 changed files with 614 additions and 899 deletions
+99
View File
@@ -0,0 +1,99 @@
pub mod stream;
use librespot::{
connect::spirc::Spirc,
core::{config::ConnectConfig, 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::{SinkEvent, StreamSink},
librespot_ext::discovery::CredentialsExt,
utils,
};
use self::stream::Stream;
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(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()
}
}
+76
View File
@@ -0,0 +1,76 @@
use std::{
io::{Read, Seek, Write},
sync::{Arc, Condvar, Mutex},
};
use songbird::input::reader::MediaSource;
const MAX_SIZE: usize = 1 * 1024 * 1024;
#[derive(Clone)]
pub struct Stream {
inner: Arc<(Mutex<Vec<u8>>, Condvar)>,
}
impl Stream {
pub fn new() -> Self {
Self {
inner: Arc::new((Mutex::new(Vec::new()), Condvar::new())),
}
}
}
impl Read for Stream {
fn read(&mut self, buf: &mut [u8]) -> std::io::Result<usize> {
let (mutex, condvar) = &*self.inner;
let mut buffer = mutex.lock().expect("Mutex was poisoned");
log::trace!("Read!");
while buffer.is_empty() {
buffer = condvar.wait(buffer).expect("Mutex was poisoned");
}
let max_read = usize::min(buf.len(), buffer.len());
buf[0..max_read].copy_from_slice(&buffer[0..max_read]);
buffer.drain(0..max_read);
Ok(max_read)
}
}
impl Write for Stream {
fn write(&mut self, buf: &[u8]) -> std::io::Result<usize> {
let (mutex, condvar) = &*self.inner;
let mut buffer = mutex.lock().expect("Mutex was poisoned");
while buffer.len() + buf.len() > MAX_SIZE {
buffer = condvar.wait(buffer).unwrap();
}
buffer.extend_from_slice(buf);
condvar.notify_all();
Ok(buf.len())
}
fn flush(&mut self) -> std::io::Result<()> {
Ok(())
}
}
impl Seek for Stream {
fn seek(&mut self, _: std::io::SeekFrom) -> std::io::Result<u64> {
Ok(0)
}
}
impl MediaSource for Stream {
fn byte_len(&self) -> Option<u64> {
None
}
fn is_seekable(&self) -> bool {
false
}
}