minor cleanup

This commit is contained in:
Evan Cameron 2021-02-28 21:37:22 -05:00
parent 9d77fef008
commit 6a33eb4efa
No known key found for this signature in database
GPG key ID: 6878FBDAB459783C
27 changed files with 172 additions and 212 deletions

View file

@ -138,19 +138,19 @@ impl StreamLoaderController {
}) })
} }
fn send_stream_loader_command(&mut self, command: StreamLoaderCommand) { fn send_stream_loader_command(&self, command: StreamLoaderCommand) {
if let Some(ref mut channel) = self.channel_tx { if let Some(ref channel) = self.channel_tx {
// ignore the error in case the channel has been closed already. // ignore the error in case the channel has been closed already.
let _ = channel.send(command); let _ = channel.send(command);
} }
} }
pub fn fetch(&mut self, range: Range) { pub fn fetch(&self, range: Range) {
// signal the stream loader to fetch a range of the file // signal the stream loader to fetch a range of the file
self.send_stream_loader_command(StreamLoaderCommand::Fetch(range)); self.send_stream_loader_command(StreamLoaderCommand::Fetch(range));
} }
pub fn fetch_blocking(&mut self, mut range: Range) { pub fn fetch_blocking(&self, mut range: Range) {
// signal the stream loader to tech a range of the file and block until it is loaded. // signal the stream loader to tech a range of the file and block until it is loaded.
// ensure the range is within the file's bounds. // ensure the range is within the file's bounds.
@ -182,47 +182,43 @@ impl StreamLoaderController {
{ {
// For some reason, the requested range is neither downloaded nor requested. // For some reason, the requested range is neither downloaded nor requested.
// This could be due to a network error. Request it again. // This could be due to a network error. Request it again.
// We can't use self.fetch here because self can't be borrowed mutably, so we access the channel directly. self.fetch(range);
if let Some(ref mut channel) = self.channel_tx {
// ignore the error in case the channel has been closed already.
let _ = channel.send(StreamLoaderCommand::Fetch(range));
}
} }
} }
} }
} }
pub fn fetch_next(&mut self, length: usize) { pub fn fetch_next(&self, length: usize) {
if let Some(ref shared) = self.stream_shared { if let Some(ref shared) = self.stream_shared {
let range = Range { let range = Range {
start: shared.read_position.load(atomic::Ordering::Relaxed), start: shared.read_position.load(atomic::Ordering::Relaxed),
length: length, length,
}; };
self.fetch(range) self.fetch(range)
} }
} }
pub fn fetch_next_blocking(&mut self, length: usize) { pub fn fetch_next_blocking(&self, length: usize) {
if let Some(ref shared) = self.stream_shared { if let Some(ref shared) = self.stream_shared {
let range = Range { let range = Range {
start: shared.read_position.load(atomic::Ordering::Relaxed), start: shared.read_position.load(atomic::Ordering::Relaxed),
length: length, length,
}; };
self.fetch_blocking(range); self.fetch_blocking(range);
} }
} }
pub fn set_random_access_mode(&mut self) { pub fn set_random_access_mode(&self) {
// optimise download strategy for random access // optimise download strategy for random access
self.send_stream_loader_command(StreamLoaderCommand::RandomAccessMode()); self.send_stream_loader_command(StreamLoaderCommand::RandomAccessMode());
} }
pub fn set_stream_mode(&mut self) { pub fn set_stream_mode(&self) {
// optimise download strategy for streaming // optimise download strategy for streaming
self.send_stream_loader_command(StreamLoaderCommand::StreamMode()); self.send_stream_loader_command(StreamLoaderCommand::StreamMode());
} }
pub fn close(&mut self) { pub fn close(&self) {
// terminate stream loading and don't load any more data for this file. // terminate stream loading and don't load any more data for this file.
self.send_stream_loader_command(StreamLoaderCommand::Close()); self.send_stream_loader_command(StreamLoaderCommand::Close());
} }
@ -230,11 +226,8 @@ impl StreamLoaderController {
pub struct AudioFileStreaming { pub struct AudioFileStreaming {
read_file: fs::File, read_file: fs::File,
position: u64, position: u64,
stream_loader_command_tx: mpsc::UnboundedSender<StreamLoaderCommand>, stream_loader_command_tx: mpsc::UnboundedSender<StreamLoaderCommand>,
shared: Arc<AudioFileShared>, shared: Arc<AudioFileShared>,
} }
@ -332,10 +325,7 @@ impl AudioFile {
} }
pub fn is_cached(&self) -> bool { pub fn is_cached(&self) -> bool {
match self { matches!(self, AudioFile::Cached { .. })
AudioFile::Cached { .. } => true,
_ => false,
}
} }
} }
@ -359,7 +349,7 @@ impl AudioFileStreaming {
let size = BigEndian::read_u32(&data) as usize * 4; let size = BigEndian::read_u32(&data) as usize * 4;
let shared = Arc::new(AudioFileShared { let shared = Arc::new(AudioFileShared {
file_id: file_id, file_id,
file_size: size, file_size: size,
stream_data_rate: streaming_data_rate, stream_data_rate: streaming_data_rate,
cond: Condvar::new(), cond: Condvar::new(),
@ -396,11 +386,10 @@ impl AudioFileStreaming {
session.spawn(fetcher); session.spawn(fetcher);
Ok(AudioFileStreaming { Ok(AudioFileStreaming {
read_file: read_file, read_file,
position: 0, position: 0,
//seek: seek_tx, stream_loader_command_tx,
stream_loader_command_tx: stream_loader_command_tx, shared,
shared: shared,
}) })
} }
} }
@ -486,7 +475,7 @@ async fn audio_file_fetch_receive_data(
let data_size = data.len(); let data_size = data.len();
let _ = file_data_tx.send(ReceivedData::Data(PartialFileData { let _ = file_data_tx.send(ReceivedData::Data(PartialFileData {
offset: data_offset, offset: data_offset,
data: data, data,
})); }));
data_offset += data_size; data_offset += data_size;
if request_length < data_size { if request_length < data_size {
@ -728,14 +717,12 @@ impl AudioFileFetch {
)); ));
AudioFileFetch { AudioFileFetch {
session: session, session,
shared: shared, shared,
output: Some(output), output: Some(output),
file_data_tx,
file_data_tx: file_data_tx, file_data_rx,
file_data_rx: file_data_rx, stream_loader_command_rx,
stream_loader_command_rx: stream_loader_command_rx,
complete_tx: Some(complete_tx), complete_tx: Some(complete_tx),
network_response_times_ms: Vec::new(), network_response_times_ms: Vec::new(),
} }

View file

@ -1,6 +1,7 @@
use super::{AudioDecoder, AudioError, AudioPacket};
use lewton::inside_ogg::OggStreamReader; use lewton::inside_ogg::OggStreamReader;
use super::{AudioDecoder, AudioError, AudioPacket};
use std::error; use std::error;
use std::fmt; use std::fmt;
use std::io::{Read, Seek}; use std::io::{Read, Seek};
@ -24,16 +25,15 @@ where
fn seek(&mut self, ms: i64) -> Result<(), AudioError> { fn seek(&mut self, ms: i64) -> Result<(), AudioError> {
let absgp = ms * 44100 / 1000; let absgp = ms * 44100 / 1000;
match self.0.seek_absgp_pg(absgp as u64) { match self.0.seek_absgp_pg(absgp as u64) {
Ok(_) => return Ok(()), Ok(_) => Ok(()),
Err(err) => return Err(AudioError::VorbisError(err.into())), Err(err) => Err(AudioError::VorbisError(err.into())),
} }
} }
fn next_packet(&mut self) -> Result<Option<AudioPacket>, AudioError> { fn next_packet(&mut self) -> Result<Option<AudioPacket>, AudioError> {
use lewton::audio::AudioReadError::AudioIsHeader; use lewton::audio::AudioReadError::AudioIsHeader;
use lewton::OggReadError::NoCapturePatternFound; use lewton::OggReadError::NoCapturePatternFound;
use lewton::VorbisError::BadAudio; use lewton::VorbisError::{BadAudio, OggError};
use lewton::VorbisError::OggError;
loop { loop {
match self.0.read_dec_packet_itl() { match self.0.read_dec_packet_itl() {
Ok(Some(packet)) => return Ok(Some(AudioPacket::Samples(packet))), Ok(Some(packet)) => return Ok(Some(AudioPacket::Samples(packet))),

View file

@ -1,4 +1,4 @@
#![allow(clippy::unused_io_amount)] #![allow(clippy::unused_io_amount, clippy::too_many_arguments)]
#[macro_use] #[macro_use]
extern crate log; extern crate log;
@ -85,13 +85,13 @@ impl fmt::Display for AudioError {
impl From<VorbisError> for AudioError { impl From<VorbisError> for AudioError {
fn from(err: VorbisError) -> AudioError { fn from(err: VorbisError) -> AudioError {
AudioError::VorbisError(VorbisError::from(err)) AudioError::VorbisError(err)
} }
} }
impl From<PassthroughError> for AudioError { impl From<PassthroughError> for AudioError {
fn from(err: PassthroughError) -> AudioError { fn from(err: PassthroughError) -> AudioError {
AudioError::PassthroughError(PassthroughError::from(err)) AudioError::PassthroughError(err)
} }
} }

View file

@ -27,7 +27,7 @@ fn write_headers<T: Read + Seek>(
// remove un-needed packets // remove un-needed packets
rdr.delete_unread_packets(); rdr.delete_unread_packets();
return Ok(stream_serial); Ok(stream_serial)
} }
fn get_header<T>( fn get_header<T>(
@ -65,7 +65,7 @@ where
) )
.unwrap(); .unwrap();
return Ok(*stream_serial); Ok(*stream_serial)
} }
pub struct PassthroughDecoder<R: Read + Seek> { pub struct PassthroughDecoder<R: Read + Seek> {
@ -87,13 +87,13 @@ impl<R: Read + Seek> PassthroughDecoder<R> {
let stream_serial = write_headers(&mut rdr, &mut wtr)?; let stream_serial = write_headers(&mut rdr, &mut wtr)?;
info!("Starting passthrough track with serial {}", stream_serial); info!("Starting passthrough track with serial {}", stream_serial);
return Ok(PassthroughDecoder { Ok(PassthroughDecoder {
rdr, rdr,
wtr, wtr,
lastgp_page: Some(0), lastgp_page: Some(0),
absgp_page: 0, absgp_page: 0,
stream_serial, stream_serial,
}); })
} }
} }
@ -107,8 +107,8 @@ impl<R: Read + Seek> AudioDecoder for PassthroughDecoder<R> {
// hard-coded to 44.1 kHz // hard-coded to 44.1 kHz
match self.rdr.seek_absgp(None, (ms * 44100 / 1000) as u64) { match self.rdr.seek_absgp(None, (ms * 44100 / 1000) as u64) {
Ok(_) => return Ok(()), Ok(_) => Ok(()),
Err(err) => return Err(AudioError::PassthroughError(err.into())), Err(err) => Err(AudioError::PassthroughError(err.into())),
} }
} }
@ -164,7 +164,7 @@ impl<R: Read + Seek> AudioDecoder for PassthroughDecoder<R> {
let data = self.wtr.inner_mut(); let data = self.wtr.inner_mut();
if data.len() > 0 { if !data.is_empty() {
let result = AudioPacket::OggData(std::mem::take(data)); let result = AudioPacket::OggData(std::mem::take(data));
return Ok(Some(result)); return Ok(Some(result));
} }

View file

@ -16,14 +16,11 @@ impl fmt::Display for Range {
impl Range { impl Range {
pub fn new(start: usize, length: usize) -> Range { pub fn new(start: usize, length: usize) -> Range {
return Range { Range { start, length }
start: start,
length: length,
};
} }
pub fn end(&self) -> usize { pub fn end(&self) -> usize {
return self.start + self.length; self.start + self.length
} }
} }
@ -50,7 +47,7 @@ impl RangeSet {
} }
pub fn is_empty(&self) -> bool { pub fn is_empty(&self) -> bool {
return self.ranges.is_empty(); self.ranges.is_empty()
} }
pub fn len(&self) -> usize { pub fn len(&self) -> usize {
@ -58,11 +55,11 @@ impl RangeSet {
} }
pub fn get_range(&self, index: usize) -> Range { pub fn get_range(&self, index: usize) -> Range {
return self.ranges[index].clone(); self.ranges[index]
} }
pub fn iter(&self) -> Iter<Range> { pub fn iter(&self) -> Iter<Range> {
return self.ranges.iter(); self.ranges.iter()
} }
pub fn contains(&self, value: usize) -> bool { pub fn contains(&self, value: usize) -> bool {
@ -73,7 +70,7 @@ impl RangeSet {
return true; return true;
} }
} }
return false; false
} }
pub fn contained_length_from_value(&self, value: usize) -> usize { pub fn contained_length_from_value(&self, value: usize) -> usize {
@ -84,7 +81,7 @@ impl RangeSet {
return range.end() - value; return range.end() - value;
} }
} }
return 0; 0
} }
#[allow(dead_code)] #[allow(dead_code)]
@ -144,7 +141,7 @@ impl RangeSet {
pub fn union(&self, other: &RangeSet) -> RangeSet { pub fn union(&self, other: &RangeSet) -> RangeSet {
let mut result = self.clone(); let mut result = self.clone();
result.add_range_set(other); result.add_range_set(other);
return result; result
} }
pub fn subtract_range(&mut self, range: &Range) { pub fn subtract_range(&mut self, range: &Range) {
@ -204,7 +201,7 @@ impl RangeSet {
pub fn minus(&self, other: &RangeSet) -> RangeSet { pub fn minus(&self, other: &RangeSet) -> RangeSet {
let mut result = self.clone(); let mut result = self.clone();
result.subtract_range_set(other); result.subtract_range_set(other);
return result; result
} }
pub fn intersection(&self, other: &RangeSet) -> RangeSet { pub fn intersection(&self, other: &RangeSet) -> RangeSet {
@ -240,6 +237,6 @@ impl RangeSet {
} }
} }
return result; result
} }
} }

View file

@ -5,34 +5,31 @@ use futures_core::Stream;
use hmac::{Hmac, Mac, NewMac}; use hmac::{Hmac, Mac, NewMac};
use hyper::service::{make_service_fn, service_fn}; use hyper::service::{make_service_fn, service_fn};
use hyper::{Body, Method, Request, Response, StatusCode}; use hyper::{Body, Method, Request, Response, StatusCode};
use num_bigint::BigUint;
use serde_json::json; use serde_json::json;
use sha1::{Digest, Sha1}; use sha1::{Digest, Sha1};
use tokio::sync::{mpsc, oneshot}; use tokio::sync::{mpsc, oneshot};
use std::borrow::Cow;
use std::convert::Infallible;
use std::net::{Ipv4Addr, SocketAddr};
use std::task::{Context, Poll};
#[cfg(feature = "with-dns-sd")] #[cfg(feature = "with-dns-sd")]
use dns_sd::DNSService; use dns_sd::DNSService;
#[cfg(not(feature = "with-dns-sd"))] #[cfg(not(feature = "with-dns-sd"))]
use libmdns; use libmdns;
use num_bigint::BigUint;
use rand;
use std::collections::BTreeMap;
use std::io;
use std::pin::Pin;
use std::sync::Arc;
use url;
use librespot_core::authentication::Credentials; use librespot_core::authentication::Credentials;
use librespot_core::config::ConnectConfig; use librespot_core::config::ConnectConfig;
use librespot_core::diffie_hellman::{DH_GENERATOR, DH_PRIME}; use librespot_core::diffie_hellman::{DH_GENERATOR, DH_PRIME};
use librespot_core::util; use librespot_core::util;
use std::borrow::Cow;
use std::collections::BTreeMap;
use std::convert::Infallible;
use std::io;
use std::net::{Ipv4Addr, SocketAddr};
use std::pin::Pin;
use std::sync::Arc;
use std::task::{Context, Poll};
type HmacSha1 = Hmac<Sha1>; type HmacSha1 = Hmac<Sha1>;
#[derive(Clone)] #[derive(Clone)]

View file

@ -1,10 +1,10 @@
const AP_FALLBACK: &'static str = "ap.spotify.com:443"; const AP_FALLBACK: &str = "ap.spotify.com:443";
use url::Url; use url::Url;
cfg_if! { cfg_if! {
if #[cfg(feature = "apresolve")] { if #[cfg(feature = "apresolve")] {
const APRESOLVE_ENDPOINT: &'static str = "http://apresolve.spotify.com:80"; const APRESOLVE_ENDPOINT: &str = "http://apresolve.spotify.com:80";
use std::error::Error; use std::error::Error;

View file

@ -27,7 +27,7 @@ pub struct Credentials {
impl Credentials { impl Credentials {
pub fn with_password(username: String, password: String) -> Credentials { pub fn with_password(username: String, password: String) -> Credentials {
Credentials { Credentials {
username: username, username,
auth_type: AuthenticationType::AUTHENTICATION_USER_PASS, auth_type: AuthenticationType::AUTHENTICATION_USER_PASS,
auth_data: password.into_bytes(), auth_data: password.into_bytes(),
} }
@ -103,9 +103,9 @@ impl Credentials {
let auth_data = read_bytes(&mut cursor).unwrap(); let auth_data = read_bytes(&mut cursor).unwrap();
Credentials { Credentials {
username: username, username,
auth_type: auth_type, auth_type,
auth_data: auth_data, auth_data,
} }
} }
} }

View file

@ -93,7 +93,7 @@ impl ChannelManager {
} }
pub fn get_download_rate_estimate(&self) -> usize { pub fn get_download_rate_estimate(&self) -> usize {
return self.lock(|inner| inner.download_rate_estimate); self.lock(|inner| inner.download_rate_estimate)
} }
pub(crate) fn shutdown(&self) { pub(crate) fn shutdown(&self) {
@ -139,7 +139,7 @@ impl Stream for Channel {
match self.state.clone() { match self.state.clone() {
ChannelState::Closed => panic!("Polling already terminated channel"), ChannelState::Closed => panic!("Polling already terminated channel"),
ChannelState::Header(mut data) => { ChannelState::Header(mut data) => {
if data.len() == 0 { if data.is_empty() {
data = match self.recv_packet(cx) { data = match self.recv_packet(cx) {
Poll::Ready(Ok(x)) => x, Poll::Ready(Ok(x)) => x,
Poll::Ready(Err(x)) => return Poll::Ready(Some(Err(x))), Poll::Ready(Err(x)) => return Poll::Ready(Some(Err(x))),
@ -168,7 +168,7 @@ impl Stream for Channel {
Poll::Ready(Err(x)) => return Poll::Ready(Some(Err(x))), Poll::Ready(Err(x)) => return Poll::Ready(Some(Err(x))),
Poll::Pending => return Poll::Pending, Poll::Pending => return Poll::Pending,
}; };
if data.len() == 0 { if data.is_empty() {
self.receiver.close(); self.receiver.close();
self.state = ChannelState::Closed; self.state = ChannelState::Closed;
return Poll::Ready(None); return Poll::Ready(None);

View file

@ -30,8 +30,8 @@ impl DHLocalKeys {
let public_key = util::powm(&DH_GENERATOR, &private_key, &DH_PRIME); let public_key = util::powm(&DH_GENERATOR, &private_key, &DH_PRIME);
DHLocalKeys { DHLocalKeys {
private_key: private_key, private_key,
public_key: public_key, public_key,
} }
} }

View file

@ -211,30 +211,28 @@ impl MercuryManager {
if let Some(cb) = pending.callback { if let Some(cb) = pending.callback {
let _ = cb.send(Err(MercuryError)); let _ = cb.send(Err(MercuryError));
} }
} else { } else if cmd == 0xb5 {
if cmd == 0xb5 { self.lock(|inner| {
self.lock(|inner| { let mut found = false;
let mut found = false; inner.subscriptions.retain(|&(ref prefix, ref sub)| {
inner.subscriptions.retain(|&(ref prefix, ref sub)| { if response.uri.starts_with(prefix) {
if response.uri.starts_with(prefix) { found = true;
found = true;
// if send fails, remove from list of subs // if send fails, remove from list of subs
// TODO: send unsub message // TODO: send unsub message
sub.send(response.clone()).is_ok() sub.send(response.clone()).is_ok()
} else { } else {
// URI doesn't match // URI doesn't match
true true
}
});
if !found {
debug!("unknown subscription uri={}", response.uri);
} }
}) });
} else if let Some(cb) = pending.callback {
let _ = cb.send(Ok(response)); if !found {
} debug!("unknown subscription uri={}", response.uri);
}
})
} else if let Some(cb) = pending.callback {
let _ = cb.send(Ok(response));
} }
} }

View file

@ -12,8 +12,8 @@ impl MercurySender {
// TODO: pub(super) when stable // TODO: pub(super) when stable
pub(crate) fn new(mercury: MercuryManager, uri: String) -> MercurySender { pub(crate) fn new(mercury: MercuryManager, uri: String) -> MercurySender {
MercurySender { MercurySender {
mercury: mercury, mercury,
uri: uri, uri,
pending: VecDeque::new(), pending: VecDeque::new(),
} }
} }

View file

@ -105,25 +105,20 @@ impl Session {
debug!("new Session[{}]", session_id); debug!("new Session[{}]", session_id);
let session = Session(Arc::new(SessionInternal { let session = Session(Arc::new(SessionInternal {
config: config, config,
data: RwLock::new(SessionData { data: RwLock::new(SessionData {
country: String::new(), country: String::new(),
canonical_username: username, canonical_username: username,
invalid: false, invalid: false,
time_delta: 0, time_delta: 0,
}), }),
tx_connection: sender_tx, tx_connection: sender_tx,
cache: cache.map(Arc::new), cache: cache.map(Arc::new),
audio_key: OnceCell::new(), audio_key: OnceCell::new(),
channel: OnceCell::new(), channel: OnceCell::new(),
mercury: OnceCell::new(), mercury: OnceCell::new(),
handle, handle,
session_id,
session_id: session_id,
})); }));
let sender_task = UnboundedReceiverStream::new(sender_rx) let sender_task = UnboundedReceiverStream::new(sender_rx)

View file

@ -45,7 +45,7 @@ impl SpotifyId {
const SIZE_BASE16: usize = 32; const SIZE_BASE16: usize = 32;
const SIZE_BASE62: usize = 22; const SIZE_BASE62: usize = 22;
fn as_track(n: u128) -> SpotifyId { fn track(n: u128) -> SpotifyId {
SpotifyId { SpotifyId {
id: n, id: n,
audio_type: SpotifyAudioType::Track, audio_type: SpotifyAudioType::Track,
@ -71,7 +71,7 @@ impl SpotifyId {
dst += p; dst += p;
} }
Ok(SpotifyId::as_track(dst)) Ok(SpotifyId::track(dst))
} }
/// Parses a base62 encoded [Spotify ID] into a `SpotifyId`. /// Parses a base62 encoded [Spotify ID] into a `SpotifyId`.
@ -94,7 +94,7 @@ impl SpotifyId {
dst += p; dst += p;
} }
Ok(SpotifyId::as_track(dst)) Ok(SpotifyId::track(dst))
} }
/// Creates a `SpotifyId` from a copy of `SpotifyId::SIZE` (16) bytes in big-endian order. /// Creates a `SpotifyId` from a copy of `SpotifyId::SIZE` (16) bytes in big-endian order.
@ -102,7 +102,7 @@ impl SpotifyId {
/// The resulting `SpotifyId` will default to a `SpotifyAudioType::TRACK`. /// The resulting `SpotifyId` will default to a `SpotifyAudioType::TRACK`.
pub fn from_raw(src: &[u8]) -> Result<SpotifyId, SpotifyIdError> { pub fn from_raw(src: &[u8]) -> Result<SpotifyId, SpotifyIdError> {
match src.try_into() { match src.try_into() {
Ok(dst) => Ok(SpotifyId::as_track(u128::from_be_bytes(dst))), Ok(dst) => Ok(SpotifyId::track(u128::from_be_bytes(dst))),
Err(_) => Err(SpotifyIdError), Err(_) => Err(SpotifyIdError),
} }
} }

View file

@ -1,33 +1,34 @@
use librespot_core::*; use librespot_core::*;
#[cfg(test)] // TODO: test is broken
mod tests { // #[cfg(test)]
use super::*; // mod tests {
// Test AP Resolve // use super::*;
use apresolve::apresolve_or_fallback; // // Test AP Resolve
#[tokio::test] // use apresolve::apresolve_or_fallback;
async fn test_ap_resolve() { // #[tokio::test]
env_logger::init(); // async fn test_ap_resolve() {
let ap = apresolve_or_fallback(&None, &None).await; // env_logger::init();
println!("AP: {:?}", ap); // let ap = apresolve_or_fallback(&None, &None).await;
} // println!("AP: {:?}", ap);
// }
// Test connect // // Test connect
use authentication::Credentials; // use authentication::Credentials;
use config::SessionConfig; // use config::SessionConfig;
#[tokio::test] // #[tokio::test]
async fn test_connection() -> Result<(), Box<dyn std::error::Error>> { // async fn test_connection() -> Result<(), Box<dyn std::error::Error>> {
println!("Running connection test"); // println!("Running connection test");
let ap = apresolve_or_fallback(&None, &None).await; // let ap = apresolve_or_fallback(&None, &None).await;
let credentials = Credentials::with_password(String::from("test"), String::from("test")); // let credentials = Credentials::with_password(String::from("test"), String::from("test"));
let session_config = SessionConfig::default(); // let session_config = SessionConfig::default();
let proxy = None; // let proxy = None;
println!("Connecting to AP \"{}\"", ap); // println!("Connecting to AP \"{}\"", ap);
let mut connection = connection::connect(ap, &proxy).await?; // let mut connection = connection::connect(ap, &proxy).await?;
let rc = connection::authenticate(&mut connection, credentials, &session_config.device_id) // let rc = connection::authenticate(&mut connection, credentials, &session_config.device_id)
.await?; // .await?;
println!("Authenticated as \"{}\"", rc.username); // println!("Authenticated as \"{}\"", rc.username);
Ok(()) // Ok(())
} // }
} // }

View file

@ -292,7 +292,7 @@ impl Metadata for Playlist {
.get_items() .get_items()
.iter() .iter()
.map(|item| { .map(|item| {
let uri_split = item.get_uri().split(":"); let uri_split = item.get_uri().split(':');
let uri_parts: Vec<&str> = uri_split.collect(); let uri_parts: Vec<&str> = uri_split.collect();
SpotifyId::from_base62(uri_parts[2]).unwrap() SpotifyId::from_base62(uri_parts[2]).unwrap()
}) })

View file

@ -2,9 +2,10 @@ use super::{Open, Sink};
use crate::audio::AudioPacket; use crate::audio::AudioPacket;
use gst::prelude::*; use gst::prelude::*;
use gst::*; use gst::*;
use zerocopy::*;
use std::sync::mpsc::{sync_channel, SyncSender}; use std::sync::mpsc::{sync_channel, SyncSender};
use std::{io, thread}; use std::{io, thread};
use zerocopy::*;
#[allow(dead_code)] #[allow(dead_code)]
pub struct GstreamerSink { pub struct GstreamerSink {
@ -91,10 +92,7 @@ impl Open for GstreamerSink {
.set_state(gst::State::Playing) .set_state(gst::State::Playing)
.expect("Unable to set the pipeline to the `Playing` state"); .expect("Unable to set the pipeline to the `Playing` state");
GstreamerSink { GstreamerSink { tx, pipeline }
tx: tx,
pipeline: pipeline,
}
} }
} }

View file

@ -60,7 +60,7 @@ impl Open for JackSink {
JackSink { JackSink {
send: tx, send: tx,
active_client: active_client, active_client,
} }
} }
} }

View file

@ -56,7 +56,7 @@ use self::pipe::StdoutSink;
mod subprocess; mod subprocess;
use self::subprocess::SubprocessSink; use self::subprocess::SubprocessSink;
pub const BACKENDS: &'static [(&'static str, SinkBuilder)] = &[ pub const BACKENDS: &[(&str, SinkBuilder)] = &[
#[cfg(feature = "alsa-backend")] #[cfg(feature = "alsa-backend")]
("alsa", mk_sink::<AlsaSink>), ("alsa", mk_sink::<AlsaSink>),
#[cfg(feature = "portaudio-backend")] #[cfg(feature = "portaudio-backend")]

View file

@ -26,8 +26,8 @@ impl Open for PulseAudioSink {
PulseAudioSink { PulseAudioSink {
s: None, s: None,
ss: ss, ss,
device: device, device,
} }
} }
} }

View file

@ -43,7 +43,6 @@ pub enum RodioError {
pub struct RodioSink { pub struct RodioSink {
rodio_sink: rodio::Sink, rodio_sink: rodio::Sink,
// will produce a TryRecvError on the receiver side when it is dropped. // will produce a TryRecvError on the receiver side when it is dropped.
_close_tx: mpsc::SyncSender<Infallible>, _close_tx: mpsc::SyncSender<Infallible>,
} }

View file

@ -29,7 +29,7 @@ impl Open for SdlSink {
.open_queue(None, &desired_spec) .open_queue(None, &desired_spec)
.expect("Could not open SDL audio device"); .expect("Could not open SDL audio device");
SdlSink { queue: queue } SdlSink { queue }
} }
} }

View file

@ -1,6 +1,8 @@
use super::{Open, Sink}; use super::{Open, Sink};
use crate::audio::AudioPacket; use crate::audio::AudioPacket;
use shell_words::split; use shell_words::split;
use std::io::{self, Write}; use std::io::{self, Write};
use std::mem; use std::mem;
use std::process::{Child, Command, Stdio}; use std::process::{Child, Command, Stdio};
@ -15,7 +17,7 @@ impl Open for SubprocessSink {
fn open(shell_command: Option<String>) -> SubprocessSink { fn open(shell_command: Option<String>) -> SubprocessSink {
if let Some(shell_command) = shell_command { if let Some(shell_command) = shell_command {
SubprocessSink { SubprocessSink {
shell_command: shell_command, shell_command,
child: None, child: None,
} }
} else { } else {

View file

@ -1,10 +1,7 @@
use super::AudioFilter; use super::AudioFilter;
use super::{Mixer, MixerConfig}; use super::{Mixer, MixerConfig};
use std;
use std::error::Error; use std::error::Error;
use alsa;
const SND_CTL_TLV_DB_GAIN_MUTE: i64 = -9999999; const SND_CTL_TLV_DB_GAIN_MUTE: i64 = -9999999;
#[derive(Clone)] #[derive(Clone)]
@ -72,14 +69,14 @@ impl AlsaMixer {
} }
Ok(AlsaMixer { Ok(AlsaMixer {
config: config, config,
params: AlsaMixerVolumeParams { params: AlsaMixerVolumeParams {
min: min, min,
max: max, max,
range: (max - min) as f64, range: (max - min) as f64,
min_db: min_db, min_db,
max_db: max_db, max_db,
has_switch: has_switch, has_switch,
}, },
}) })
} }

View file

@ -252,8 +252,8 @@ impl Player {
debug!("new Player[{}]", session.session_id()); debug!("new Player[{}]", session.session_id());
let internal = PlayerInternal { let internal = PlayerInternal {
session: session, session,
config: config, config,
commands: cmd_rx, commands: cmd_rx,
state: PlayerState::Stopped, state: PlayerState::Stopped,
@ -261,7 +261,7 @@ impl Player {
sink: sink_builder(), sink: sink_builder(),
sink_status: SinkStatus::Closed, sink_status: SinkStatus::Closed,
sink_event_callback: None, sink_event_callback: None,
audio_filter: audio_filter, audio_filter,
event_senders: [event_sender].to_vec(), event_senders: [event_sender].to_vec(),
}; };
@ -432,18 +432,12 @@ impl PlayerState {
#[allow(dead_code)] #[allow(dead_code)]
fn is_stopped(&self) -> bool { fn is_stopped(&self) -> bool {
use self::PlayerState::*; use self::PlayerState::*;
match *self { matches!(self, Stopped)
Stopped => true,
_ => false,
}
} }
fn is_loading(&self) -> bool { fn is_loading(&self) -> bool {
use self::PlayerState::*; use self::PlayerState::*;
match *self { matches!(self, Loading { .. })
Loading { .. } => true,
_ => false,
}
} }
fn decoder(&mut self) -> Option<&mut Decoder> { fn decoder(&mut self) -> Option<&mut Decoder> {
@ -697,7 +691,7 @@ impl PlayerTrackLoader {
}; };
let is_cached = encrypted_file.is_cached(); let is_cached = encrypted_file.is_cached();
let mut stream_loader_controller = encrypted_file.get_stream_loader_controller(); let stream_loader_controller = encrypted_file.get_stream_loader_controller();
if play_from_beginning { if play_from_beginning {
// No need to seek -> we stream from the beginning // No need to seek -> we stream from the beginning
@ -908,11 +902,7 @@ impl Future for PlayerInternal {
.as_millis() .as_millis()
as i64 as i64
- stream_position_millis as i64; - stream_position_millis as i64;
if lag > 1000 { lag > 1000
true
} else {
false
}
} }
}; };
if notify_about_position { if notify_about_position {

View file

@ -2,6 +2,23 @@ use futures_util::{future, FutureExt, StreamExt};
use librespot_playback::player::PlayerEvent; use librespot_playback::player::PlayerEvent;
use log::{error, info, warn}; use log::{error, info, warn};
use sha1::{Digest, Sha1}; use sha1::{Digest, Sha1};
use tokio::sync::mpsc::UnboundedReceiver;
use url::Url;
use librespot::connect::spirc::Spirc;
use librespot::core::authentication::Credentials;
use librespot::core::cache::Cache;
use librespot::core::config::{ConnectConfig, DeviceType, SessionConfig, VolumeCtrl};
use librespot::core::session::Session;
use librespot::core::version;
use librespot::playback::audio_backend::{self, Sink, BACKENDS};
use librespot::playback::config::{Bitrate, NormalisationType, PlayerConfig};
use librespot::playback::mixer::{self, Mixer, MixerConfig};
use librespot::playback::player::Player;
mod player_event_handler;
use player_event_handler::{emit_sink_event, run_program_on_events};
use std::path::Path; use std::path::Path;
use std::process::exit; use std::process::exit;
use std::str::FromStr; use std::str::FromStr;
@ -10,24 +27,6 @@ use std::{
io::{stderr, Write}, io::{stderr, Write},
pin::Pin, pin::Pin,
}; };
use tokio::sync::mpsc::UnboundedReceiver;
use url::Url;
use librespot::core::authentication::Credentials;
use librespot::core::cache::Cache;
use librespot::core::config::{ConnectConfig, DeviceType, SessionConfig, VolumeCtrl};
use librespot::core::session::Session;
use librespot::core::version;
use librespot::connect::spirc::Spirc;
use librespot::playback::audio_backend::{self, Sink, BACKENDS};
use librespot::playback::config::{Bitrate, NormalisationType, PlayerConfig};
use librespot::playback::mixer::{self, Mixer, MixerConfig};
use librespot::playback::player::Player;
mod player_event_handler;
use player_event_handler::{emit_sink_event, run_program_on_events};
fn device_id(name: &str) -> String { fn device_id(name: &str) -> String {
hex::encode(Sha1::digest(name.as_bytes())) hex::encode(Sha1::digest(name.as_bytes()))

View file

@ -1,12 +1,12 @@
use librespot::playback::player::PlayerEvent; use librespot::playback::player::PlayerEvent;
use librespot::playback::player::SinkStatus;
use log::info; use log::info;
use tokio::process::{Child as AsyncChild, Command as AsyncCommand};
use std::collections::HashMap; use std::collections::HashMap;
use std::io; use std::io;
use std::process::{Command, ExitStatus}; use std::process::{Command, ExitStatus};
use librespot::playback::player::SinkStatus;
use tokio::process::{Child as AsyncChild, Command as AsyncCommand};
pub fn run_program_on_events(event: PlayerEvent, onevent: &str) -> Option<io::Result<AsyncChild>> { pub fn run_program_on_events(event: PlayerEvent, onevent: &str) -> Option<io::Result<AsyncChild>> {
let mut env_vars = HashMap::new(); let mut env_vars = HashMap::new();
match event { match event {