From 5e8e2ba8c59dbc3684244ca5180e930550e4cafc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Johan=20F=C3=B6rberg?= Date: Sat, 8 Jan 2022 15:48:33 +0100 Subject: [PATCH 01/39] examples/playlist_tracks: Use normal URI parser --- examples/playlist_tracks.rs | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/examples/playlist_tracks.rs b/examples/playlist_tracks.rs index 75c656bb..0bf17ee7 100644 --- a/examples/playlist_tracks.rs +++ b/examples/playlist_tracks.rs @@ -1,4 +1,5 @@ use std::env; +use std::process; use librespot::core::authentication::Credentials; use librespot::core::config::SessionConfig; @@ -18,11 +19,13 @@ async fn main() { } let credentials = Credentials::with_password(&args[1], &args[2]); - let uri_split = args[3].split(':'); - let uri_parts: Vec<&str> = uri_split.collect(); - println!("{}, {}, {}", uri_parts[0], uri_parts[1], uri_parts[2]); - - let plist_uri = SpotifyId::from_base62(uri_parts[2]).unwrap(); + let plist_uri = SpotifyId::from_uri(&args[3]).unwrap_or_else(|_| { + eprintln!( + "PLAYLIST should be a playlist URI such as: \ + \"spotify:playlist:37i9dQZF1DXec50AjHrNTq\"" + ); + process::exit(1); + }); let session = Session::connect(session_config, credentials, None) .await From c6e97a7f8ab4b7d97b82427071b2f1555557e0cc Mon Sep 17 00:00:00 2001 From: Jason Gray Date: Mon, 17 Jan 2022 15:57:30 -0600 Subject: [PATCH 02/39] Save some more CPU cycles in the limiter (#939) Optimise limiter CPU usage --- playback/src/config.rs | 2 +- playback/src/player.rs | 112 ++++++++++++++++++++++------------------- src/main.rs | 4 +- 3 files changed, 62 insertions(+), 56 deletions(-) diff --git a/playback/src/config.rs b/playback/src/config.rs index 4070a26a..f1276adb 100644 --- a/playback/src/config.rs +++ b/playback/src/config.rs @@ -130,7 +130,7 @@ pub struct PlayerConfig { pub normalisation: bool, pub normalisation_type: NormalisationType, pub normalisation_method: NormalisationMethod, - pub normalisation_pregain_db: f32, + pub normalisation_pregain_db: f64, pub normalisation_threshold_dbfs: f64, pub normalisation_attack_cf: f64, pub normalisation_release_cf: f64, diff --git a/playback/src/player.rs b/playback/src/player.rs index f863b0e9..b5603491 100644 --- a/playback/src/player.rs +++ b/playback/src/player.rs @@ -214,10 +214,10 @@ pub fn coefficient_to_duration(coefficient: f64) -> Duration { #[derive(Clone, Copy, Debug)] pub struct NormalisationData { - track_gain_db: f32, - track_peak: f32, - album_gain_db: f32, - album_peak: f32, + track_gain_db: f64, + track_peak: f64, + album_gain_db: f64, + album_peak: f64, } impl NormalisationData { @@ -225,10 +225,10 @@ impl NormalisationData { const SPOTIFY_NORMALIZATION_HEADER_START_OFFSET: u64 = 144; file.seek(SeekFrom::Start(SPOTIFY_NORMALIZATION_HEADER_START_OFFSET))?; - let track_gain_db = file.read_f32::()?; - let track_peak = file.read_f32::()?; - let album_gain_db = file.read_f32::()?; - let album_peak = file.read_f32::()?; + let track_gain_db = file.read_f32::()? as f64; + let track_peak = file.read_f32::()? as f64; + let album_gain_db = file.read_f32::()? as f64; + let album_peak = file.read_f32::()? as f64; let r = NormalisationData { track_gain_db, @@ -246,17 +246,17 @@ impl NormalisationData { } let (gain_db, gain_peak) = if config.normalisation_type == NormalisationType::Album { - (data.album_gain_db as f64, data.album_peak as f64) + (data.album_gain_db, data.album_peak) } else { - (data.track_gain_db as f64, data.track_peak as f64) + (data.track_gain_db, data.track_peak) }; - let normalisation_power = gain_db + config.normalisation_pregain_db as f64; + let normalisation_power = gain_db + config.normalisation_pregain_db; let mut normalisation_factor = db_to_ratio(normalisation_power); if normalisation_power + ratio_to_db(gain_peak) > config.normalisation_threshold_dbfs { let limited_normalisation_factor = - db_to_ratio(config.normalisation_threshold_dbfs as f64) / gain_peak; + db_to_ratio(config.normalisation_threshold_dbfs) / gain_peak; let limited_normalisation_power = ratio_to_db(limited_normalisation_factor); if config.normalisation_method == NormalisationMethod::Basic { @@ -279,7 +279,7 @@ impl NormalisationData { normalisation_factor * 100.0 ); - normalisation_factor as f64 + normalisation_factor } } @@ -1305,54 +1305,60 @@ impl PlayerInternal { // Engineering Society, 60, 399-408. if self.config.normalisation_method == NormalisationMethod::Dynamic { - // steps 1 + 2: half-wave rectification and conversion into dB - let abs_sample_db = ratio_to_db(sample.abs()); + // Some tracks have samples that are precisely 0.0. That's silence + // and we know we don't need to limit that, in which we can spare + // the CPU cycles. + // + // Also, calling `ratio_to_db(0.0)` returns `inf` and would get the + // peak detector stuck. Also catch the unlikely case where a sample + // is decoded as `NaN` or some other non-normal value. + let limiter_db = if sample.is_normal() { + // step 1-2: half-wave rectification and conversion into dB + let abs_sample_db = ratio_to_db(sample.abs()); - // Some tracks have samples that are precisely 0.0, but ratio_to_db(0.0) - // returns -inf and gets the peak detector stuck. - if !abs_sample_db.is_normal() { - continue; - } + // step 3-4: gain computer with soft knee and subtractor + let bias_db = abs_sample_db - threshold_db; + let knee_boundary_db = bias_db * 2.0; - // step 3: gain computer with soft knee - let biased_sample = abs_sample_db - threshold_db; - let limited_sample = if 2.0 * biased_sample < -knee_db { - abs_sample_db - } else if 2.0 * biased_sample.abs() <= knee_db { - abs_sample_db - - (biased_sample + knee_db / 2.0).powi(2) - / (2.0 * knee_db) + if knee_boundary_db < -knee_db { + 0.0 + } else if knee_boundary_db.abs() <= knee_db { + abs_sample_db + - (abs_sample_db + - (bias_db + knee_db / 2.0).powi(2) + / (2.0 * knee_db)) + } else { + abs_sample_db - threshold_db + } } else { - threshold_db as f64 + 0.0 }; - // step 4: subtractor - let limiter_input = abs_sample_db - limited_sample; - - // Spare the CPU unless the limiter is active or we are riding a peak. - if !(limiter_input > 0.0 + // Spare the CPU unless (1) the limiter is engaged, (2) we + // were in attack or (3) we were in release, and that attack/ + // release wasn't finished yet. + if limiter_db > 0.0 || self.normalisation_integrator > 0.0 - || self.normalisation_peak > 0.0) + || self.normalisation_peak > 0.0 { - continue; + // step 5: smooth, decoupled peak detector + self.normalisation_integrator = f64::max( + limiter_db, + release_cf * self.normalisation_integrator + + (1.0 - release_cf) * limiter_db, + ); + self.normalisation_peak = attack_cf + * self.normalisation_peak + + (1.0 - attack_cf) * self.normalisation_integrator; + + // step 6: make-up gain applied later (volume attenuation) + // Applying the standard normalisation factor here won't work, + // because there are tracks with peaks as high as 6 dB above + // the default threshold, so that would clip. + + // steps 7-8: conversion into level and multiplication into gain stage + *sample *= db_to_ratio(-self.normalisation_peak); } - - // step 5: smooth, decoupled peak detector - self.normalisation_integrator = f64::max( - limiter_input, - release_cf * self.normalisation_integrator - + (1.0 - release_cf) * limiter_input, - ); - self.normalisation_peak = attack_cf * self.normalisation_peak - + (1.0 - attack_cf) * self.normalisation_integrator; - - // step 6: make-up gain applied later (volume attenuation) - // Applying the standard normalisation factor here won't work, - // because there are tracks with peaks as high as 6 dB above - // the default threshold, so that would clip. - - // steps 7-8: conversion into level and multiplication into gain stage - *sample *= db_to_ratio(-self.normalisation_peak); } } } diff --git a/src/main.rs b/src/main.rs index 6c432808..f43500fe 100644 --- a/src/main.rs +++ b/src/main.rs @@ -187,7 +187,7 @@ fn get_setup() -> Setup { const VALID_INITIAL_VOLUME_RANGE: RangeInclusive = 0..=100; const VALID_VOLUME_RANGE: RangeInclusive = 0.0..=100.0; const VALID_NORMALISATION_KNEE_RANGE: RangeInclusive = 0.0..=10.0; - const VALID_NORMALISATION_PREGAIN_RANGE: RangeInclusive = -10.0..=10.0; + const VALID_NORMALISATION_PREGAIN_RANGE: RangeInclusive = -10.0..=10.0; const VALID_NORMALISATION_THRESHOLD_RANGE: RangeInclusive = -10.0..=0.0; const VALID_NORMALISATION_ATTACK_RANGE: RangeInclusive = 1..=500; const VALID_NORMALISATION_RELEASE_RANGE: RangeInclusive = 1..=1000; @@ -1339,7 +1339,7 @@ fn get_setup() -> Setup { .unwrap_or(player_default_config.normalisation_type); normalisation_pregain_db = opt_str(NORMALISATION_PREGAIN) - .map(|pregain| match pregain.parse::() { + .map(|pregain| match pregain.parse::() { Ok(value) if (VALID_NORMALISATION_PREGAIN_RANGE).contains(&value) => value, _ => { let valid_values = &format!( From ceebb374f0db8848a8d4135c5a06b466f2d963e1 Mon Sep 17 00:00:00 2001 From: Jason Gray Date: Sun, 23 Jan 2022 12:02:04 -0600 Subject: [PATCH 03/39] Remove unsafe code (#940) Remove unsafe code --- CHANGELOG.md | 1 + core/src/cache.rs | 17 ++- core/src/spotify_id.rs | 34 +++-- metadata/src/lib.rs | 262 +++++++++++++++++++++++------------- playback/src/player.rs | 7 +- src/player_event_handler.rs | 124 +++++++++++++---- 6 files changed, 295 insertions(+), 150 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index c0a91a29..74809104 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -28,6 +28,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - [main] Prevent hang when discovery is disabled and there are no credentials or when bad credentials are given. - [main] Don't panic when parsing options. Instead list valid values and exit. - [main] `--alsa-mixer-device` and `--alsa-mixer-index` now fallback to the card and index specified in `--device`. +- [core] Removed unsafe code (breaking) ### Removed - [playback] `alsamixer`: previously deprecated option `mixer-card` has been removed. diff --git a/core/src/cache.rs b/core/src/cache.rs index da2ad022..f8b0ca2c 100644 --- a/core/src/cache.rs +++ b/core/src/cache.rs @@ -351,12 +351,17 @@ impl Cache { } fn file_path(&self, file: FileId) -> Option { - self.audio_location.as_ref().map(|location| { - let name = file.to_base16(); - let mut path = location.join(&name[0..2]); - path.push(&name[2..]); - path - }) + match file.to_base16() { + Ok(name) => self.audio_location.as_ref().map(|location| { + let mut path = location.join(&name[0..2]); + path.push(&name[2..]); + path + }), + Err(e) => { + warn!("Invalid FileId: {}", e.utf8_error()); + None + } + } } pub fn file(&self, file: FileId) -> Option { diff --git a/core/src/spotify_id.rs b/core/src/spotify_id.rs index e6e2bae0..10298a42 100644 --- a/core/src/spotify_id.rs +++ b/core/src/spotify_id.rs @@ -2,6 +2,7 @@ use std::convert::TryInto; use std::fmt; +use std::string::FromUtf8Error; #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] pub enum SpotifyAudioType { @@ -136,7 +137,7 @@ impl SpotifyId { /// Returns the `SpotifyId` as a base16 (hex) encoded, `SpotifyId::SIZE_BASE16` (32) /// character long `String`. - pub fn to_base16(&self) -> String { + pub fn to_base16(&self) -> Result { to_base16(&self.to_raw(), &mut [0u8; SpotifyId::SIZE_BASE16]) } @@ -144,7 +145,7 @@ impl SpotifyId { /// character long `String`. /// /// [canonically]: https://developer.spotify.com/documentation/web-api/#spotify-uris-and-ids - pub fn to_base62(&self) -> String { + pub fn to_base62(&self) -> Result { let mut dst = [0u8; 22]; let mut i = 0; let n = self.id; @@ -182,10 +183,7 @@ impl SpotifyId { dst.reverse(); - unsafe { - // Safety: We are only dealing with ASCII characters. - String::from_utf8_unchecked(dst.to_vec()) - } + String::from_utf8(dst.to_vec()) } /// Returns a copy of the `SpotifyId` as an array of `SpotifyId::SIZE` (16) bytes in @@ -202,7 +200,7 @@ impl SpotifyId { /// be encoded as `unknown`. /// /// [Spotify URI]: https://developer.spotify.com/documentation/web-api/#spotify-uris-and-ids - pub fn to_uri(&self) -> String { + pub fn to_uri(&self) -> Result { // 8 chars for the "spotify:" prefix + 1 colon + 22 chars base62 encoded ID = 31 // + unknown size audio_type. let audio_type: &str = self.audio_type.into(); @@ -210,9 +208,10 @@ impl SpotifyId { dst.push_str("spotify:"); dst.push_str(audio_type); dst.push(':'); - dst.push_str(&self.to_base62()); + let base62 = self.to_base62()?; + dst.push_str(&base62); - dst + Ok(dst) } } @@ -220,7 +219,7 @@ impl SpotifyId { pub struct FileId(pub [u8; 20]); impl FileId { - pub fn to_base16(&self) -> String { + pub fn to_base16(&self) -> Result { to_base16(&self.0, &mut [0u8; 40]) } } @@ -233,12 +232,12 @@ impl fmt::Debug for FileId { impl fmt::Display for FileId { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - f.write_str(&self.to_base16()) + f.write_str(&self.to_base16().unwrap_or_default()) } } #[inline] -fn to_base16(src: &[u8], buf: &mut [u8]) -> String { +fn to_base16(src: &[u8], buf: &mut [u8]) -> Result { let mut i = 0; for v in src { buf[i] = BASE16_DIGITS[(v >> 4) as usize]; @@ -246,10 +245,7 @@ fn to_base16(src: &[u8], buf: &mut [u8]) -> String { i += 2; } - unsafe { - // Safety: We are only dealing with ASCII characters. - String::from_utf8_unchecked(buf.to_vec()) - } + String::from_utf8(buf.to_vec()) } #[cfg(test)] @@ -366,7 +362,7 @@ mod tests { audio_type: c.kind, }; - assert_eq!(id.to_base62(), c.base62); + assert_eq!(id.to_base62().unwrap(), c.base62); } } @@ -389,7 +385,7 @@ mod tests { audio_type: c.kind, }; - assert_eq!(id.to_base16(), c.base16); + assert_eq!(id.to_base16().unwrap(), c.base16); } } @@ -415,7 +411,7 @@ mod tests { audio_type: c.kind, }; - assert_eq!(id.to_uri(), c.uri); + assert_eq!(id.to_uri().unwrap(), c.uri); } } diff --git a/metadata/src/lib.rs b/metadata/src/lib.rs index 2ed9273e..435633ad 100644 --- a/metadata/src/lib.rs +++ b/metadata/src/lib.rs @@ -7,12 +7,12 @@ extern crate log; extern crate async_trait; pub mod cover; - use std::collections::HashMap; +use std::string::FromUtf8Error; use librespot_core::mercury::MercuryError; use librespot_core::session::Session; -use librespot_core::spotify_id::{FileId, SpotifyAudioType, SpotifyId}; +use librespot_core::spotify_id::{FileId, SpotifyAudioType, SpotifyId, SpotifyIdError}; use librespot_protocol as protocol; use protobuf::Message; @@ -83,33 +83,48 @@ trait AudioFiles { #[async_trait] impl AudioFiles for Track { async fn get_audio_item(session: &Session, id: SpotifyId) -> Result { - let item = Self::get(session, id).await?; - Ok(AudioItem { - id, - uri: format!("spotify:track:{}", id.to_base62()), - files: item.files, - name: item.name, - duration: item.duration, - available: item.available, - alternatives: Some(item.alternatives), - }) + match id.to_base62() { + Err(e) => { + warn!("Invalid Track SpotifyId: {}", e); + Err(MercuryError) + } + Ok(uri) => { + let item = Self::get(session, id).await?; + Ok(AudioItem { + id, + uri: format!("spotify:track:{}", uri), + files: item.files, + name: item.name, + duration: item.duration, + available: item.available, + alternatives: Some(item.alternatives), + }) + } + } } } #[async_trait] impl AudioFiles for Episode { async fn get_audio_item(session: &Session, id: SpotifyId) -> Result { - let item = Self::get(session, id).await?; - - Ok(AudioItem { - id, - uri: format!("spotify:episode:{}", id.to_base62()), - files: item.files, - name: item.name, - duration: item.duration, - available: item.available, - alternatives: None, - }) + match id.to_base62() { + Err(e) => { + warn!("Invalid Episode SpotifyId: {}", e); + Err(MercuryError) + } + Ok(uri) => { + let item = Self::get(session, id).await?; + Ok(AudioItem { + id, + uri: format!("spotify:episode:{}", uri), + files: item.files, + name: item.name, + duration: item.duration, + available: item.available, + alternatives: None, + }) + } + } } } @@ -117,16 +132,38 @@ impl AudioFiles for Episode { pub trait Metadata: Send + Sized + 'static { type Message: protobuf::Message; - fn request_url(id: SpotifyId) -> String; - fn parse(msg: &Self::Message, session: &Session) -> Self; + fn request_url(id: SpotifyId) -> Result; + fn parse(msg: &Self::Message, session: &Session) -> Result; async fn get(session: &Session, id: SpotifyId) -> Result { - let uri = Self::request_url(id); - let response = session.mercury().get(uri).await?; - let data = response.payload.first().expect("Empty payload"); - let msg = Self::Message::parse_from_bytes(data).unwrap(); - - Ok(Self::parse(&msg, session)) + match Self::request_url(id) { + Err(e) => { + warn!("Invalid SpotifyId: {}", e); + Err(MercuryError) + } + Ok(uri) => { + let response = session.mercury().get(uri).await?; + match response.payload.first() { + None => { + warn!("Empty payload"); + Err(MercuryError) + } + Some(data) => match Self::Message::parse_from_bytes(data) { + Err(e) => { + warn!("Error parsing message from bytes: {}", e); + Err(MercuryError) + } + Ok(msg) => match Self::parse(&msg, session) { + Err(e) => { + warn!("Error parsing message: {:?}", e); + Err(MercuryError) + } + Ok(parsed_msg) => Ok(parsed_msg), + }, + }, + } + } + } } } @@ -192,101 +229,125 @@ pub struct Artist { impl Metadata for Track { type Message = protocol::metadata::Track; - fn request_url(id: SpotifyId) -> String { - format!("hm://metadata/3/track/{}", id.to_base16()) + fn request_url(id: SpotifyId) -> Result { + let id = id.to_base16()?; + Ok(format!("hm://metadata/3/track/{}", id)) } - fn parse(msg: &Self::Message, session: &Session) -> Self { + fn parse(msg: &Self::Message, session: &Session) -> Result { let country = session.country(); let artists = msg .get_artist() .iter() - .filter(|artist| artist.has_gid()) - .map(|artist| SpotifyId::from_raw(artist.get_gid()).unwrap()) - .collect::>(); + .filter_map(|artist| { + if artist.has_gid() { + SpotifyId::from_raw(artist.get_gid()).ok() + } else { + None + } + }) + .collect(); let files = msg .get_file() .iter() - .filter(|file| file.has_file_id()) - .map(|file| { - let mut dst = [0u8; 20]; - dst.clone_from_slice(file.get_file_id()); - (file.get_format(), FileId(dst)) + .filter_map(|file| { + if file.has_file_id() { + let mut dst = [0u8; 20]; + dst.clone_from_slice(file.get_file_id()); + Some((file.get_format(), FileId(dst))) + } else { + None + } }) .collect(); - Track { - id: SpotifyId::from_raw(msg.get_gid()).unwrap(), + Ok(Track { + id: SpotifyId::from_raw(msg.get_gid())?, name: msg.get_name().to_owned(), duration: msg.get_duration(), - album: SpotifyId::from_raw(msg.get_album().get_gid()).unwrap(), + album: SpotifyId::from_raw(msg.get_album().get_gid())?, artists, files, alternatives: msg .get_alternative() .iter() - .map(|alt| SpotifyId::from_raw(alt.get_gid()).unwrap()) + .filter_map(|alt| SpotifyId::from_raw(alt.get_gid()).ok()) .collect(), available: parse_restrictions(msg.get_restriction(), &country, "premium"), - } + }) } } impl Metadata for Album { type Message = protocol::metadata::Album; - fn request_url(id: SpotifyId) -> String { - format!("hm://metadata/3/album/{}", id.to_base16()) + fn request_url(id: SpotifyId) -> Result { + let id = id.to_base16()?; + Ok(format!("hm://metadata/3/album/{}", id)) } - fn parse(msg: &Self::Message, _: &Session) -> Self { + fn parse(msg: &Self::Message, _: &Session) -> Result { let artists = msg .get_artist() .iter() - .filter(|artist| artist.has_gid()) - .map(|artist| SpotifyId::from_raw(artist.get_gid()).unwrap()) - .collect::>(); + .filter_map(|artist| { + if artist.has_gid() { + SpotifyId::from_raw(artist.get_gid()).ok() + } else { + None + } + }) + .collect(); let tracks = msg .get_disc() .iter() .flat_map(|disc| disc.get_track()) - .filter(|track| track.has_gid()) - .map(|track| SpotifyId::from_raw(track.get_gid()).unwrap()) - .collect::>(); + .filter_map(|track| { + if track.has_gid() { + SpotifyId::from_raw(track.get_gid()).ok() + } else { + None + } + }) + .collect(); let covers = msg .get_cover_group() .get_image() .iter() - .filter(|image| image.has_file_id()) - .map(|image| { - let mut dst = [0u8; 20]; - dst.clone_from_slice(image.get_file_id()); - FileId(dst) + .filter_map(|image| { + if image.has_file_id() { + let mut dst = [0u8; 20]; + dst.clone_from_slice(image.get_file_id()); + Some(FileId(dst)) + } else { + None + } }) - .collect::>(); + .collect(); - Album { - id: SpotifyId::from_raw(msg.get_gid()).unwrap(), + Ok(Album { + id: SpotifyId::from_raw(msg.get_gid())?, name: msg.get_name().to_owned(), artists, tracks, covers, - } + }) } } impl Metadata for Playlist { type Message = protocol::playlist4changes::SelectedListContent; - fn request_url(id: SpotifyId) -> String { - format!("hm://playlist/v2/playlist/{}", id.to_base62()) + fn request_url(id: SpotifyId) -> Result { + let id = id.to_base62()?; + Ok(format!("hm://playlist/v2/playlist/{}", id)) } - fn parse(msg: &Self::Message, _: &Session) -> Self { + fn parse(msg: &Self::Message, _: &Session) -> Result { let tracks = msg .get_contents() .get_items() @@ -306,23 +367,24 @@ impl Metadata for Playlist { ); } - Playlist { + Ok(Playlist { revision: msg.get_revision().to_vec(), name: msg.get_attributes().get_name().to_owned(), tracks, user: msg.get_owner_username().to_string(), - } + }) } } impl Metadata for Artist { type Message = protocol::metadata::Artist; - fn request_url(id: SpotifyId) -> String { - format!("hm://metadata/3/artist/{}", id.to_base16()) + fn request_url(id: SpotifyId) -> Result { + let id = id.to_base16()?; + Ok(format!("hm://metadata/3/artist/{}", id)) } - fn parse(msg: &Self::Message, session: &Session) -> Self { + fn parse(msg: &Self::Message, session: &Session) -> Result { let country = session.country(); let top_tracks: Vec = match msg @@ -333,17 +395,22 @@ impl Metadata for Artist { Some(tracks) => tracks .get_track() .iter() - .filter(|track| track.has_gid()) - .map(|track| SpotifyId::from_raw(track.get_gid()).unwrap()) - .collect::>(), + .filter_map(|track| { + if track.has_gid() { + SpotifyId::from_raw(track.get_gid()).ok() + } else { + None + } + }) + .collect(), None => Vec::new(), }; - Artist { - id: SpotifyId::from_raw(msg.get_gid()).unwrap(), + Ok(Artist { + id: SpotifyId::from_raw(msg.get_gid())?, name: msg.get_name().to_owned(), top_tracks, - } + }) } } @@ -351,11 +418,12 @@ impl Metadata for Artist { impl Metadata for Episode { type Message = protocol::metadata::Episode; - fn request_url(id: SpotifyId) -> String { - format!("hm://metadata/3/episode/{}", id.to_base16()) + fn request_url(id: SpotifyId) -> Result { + let id = id.to_base16()?; + Ok(format!("hm://metadata/3/episode/{}", id)) } - fn parse(msg: &Self::Message, session: &Session) -> Self { + fn parse(msg: &Self::Message, session: &Session) -> Result { let country = session.country(); let files = msg @@ -379,9 +447,9 @@ impl Metadata for Episode { dst.clone_from_slice(image.get_file_id()); FileId(dst) }) - .collect::>(); + .collect(); - Episode { + Ok(Episode { id: SpotifyId::from_raw(msg.get_gid()).unwrap(), name: msg.get_name().to_owned(), external_url: msg.get_external_url().to_owned(), @@ -392,24 +460,30 @@ impl Metadata for Episode { files, available: parse_restrictions(msg.get_restriction(), &country, "premium"), explicit: msg.get_explicit().to_owned(), - } + }) } } impl Metadata for Show { type Message = protocol::metadata::Show; - fn request_url(id: SpotifyId) -> String { - format!("hm://metadata/3/show/{}", id.to_base16()) + fn request_url(id: SpotifyId) -> Result { + let id = id.to_base16()?; + Ok(format!("hm://metadata/3/show/{}", id)) } - fn parse(msg: &Self::Message, _: &Session) -> Self { + fn parse(msg: &Self::Message, _: &Session) -> Result { let episodes = msg .get_episode() .iter() - .filter(|episode| episode.has_gid()) - .map(|episode| SpotifyId::from_raw(episode.get_gid()).unwrap()) - .collect::>(); + .filter_map(|episode| { + if episode.has_gid() { + SpotifyId::from_raw(episode.get_gid()).ok() + } else { + None + } + }) + .collect(); let covers = msg .get_covers() @@ -421,15 +495,15 @@ impl Metadata for Show { dst.clone_from_slice(image.get_file_id()); FileId(dst) }) - .collect::>(); + .collect(); - Show { + Ok(Show { id: SpotifyId::from_raw(msg.get_gid()).unwrap(), name: msg.get_name().to_owned(), publisher: msg.get_publisher().to_owned(), episodes, covers, - } + }) } } diff --git a/playback/src/player.rs b/playback/src/player.rs index b5603491..b2bdea0c 100644 --- a/playback/src/player.rs +++ b/playback/src/player.rs @@ -740,7 +740,10 @@ impl PlayerTrackLoader { let audio = match self.find_available_alternative(audio).await { Some(audio) => audio, None => { - warn!("<{}> is not available", spotify_id.to_uri()); + warn!( + "<{}> is not available", + spotify_id.to_uri().unwrap_or_default() + ); return None; } }; @@ -748,7 +751,7 @@ impl PlayerTrackLoader { if audio.duration < 0 { error!( "Track duration for <{}> cannot be {}", - spotify_id.to_uri(), + spotify_id.to_uri().unwrap_or_default(), audio.duration ); return None; diff --git a/src/player_event_handler.rs b/src/player_event_handler.rs index 4c75128c..785290ed 100644 --- a/src/player_event_handler.rs +++ b/src/player_event_handler.rs @@ -5,6 +5,7 @@ use tokio::process::{Child as AsyncChild, Command as AsyncCommand}; use std::collections::HashMap; use std::io; +use std::io::{Error, ErrorKind}; use std::process::{Command, ExitStatus}; pub fn run_program_on_events(event: PlayerEvent, onevent: &str) -> Option> { @@ -13,45 +14,110 @@ pub fn run_program_on_events(event: PlayerEvent, onevent: &str) -> Option { - env_vars.insert("PLAYER_EVENT", "changed".to_string()); - env_vars.insert("OLD_TRACK_ID", old_track_id.to_base62()); - env_vars.insert("TRACK_ID", new_track_id.to_base62()); - } - PlayerEvent::Started { track_id, .. } => { - env_vars.insert("PLAYER_EVENT", "started".to_string()); - env_vars.insert("TRACK_ID", track_id.to_base62()); - } - PlayerEvent::Stopped { track_id, .. } => { - env_vars.insert("PLAYER_EVENT", "stopped".to_string()); - env_vars.insert("TRACK_ID", track_id.to_base62()); - } + } => match old_track_id.to_base62() { + Err(e) => { + return Some(Err(Error::new( + ErrorKind::InvalidData, + format!( + "PlayerEvent::Changed: Invalid old track id: {}", + e.utf8_error() + ), + ))) + } + Ok(old_id) => match new_track_id.to_base62() { + Err(e) => { + return Some(Err(Error::new( + ErrorKind::InvalidData, + format!( + "PlayerEvent::Changed: Invalid new track id: {}", + e.utf8_error() + ), + ))) + } + Ok(new_id) => { + env_vars.insert("PLAYER_EVENT", "changed".to_string()); + env_vars.insert("OLD_TRACK_ID", old_id); + env_vars.insert("TRACK_ID", new_id); + } + }, + }, + PlayerEvent::Started { track_id, .. } => match track_id.to_base62() { + Err(e) => { + return Some(Err(Error::new( + ErrorKind::InvalidData, + format!("PlayerEvent::Started: Invalid track id: {}", e.utf8_error()), + ))) + } + Ok(id) => { + env_vars.insert("PLAYER_EVENT", "started".to_string()); + env_vars.insert("TRACK_ID", id); + } + }, + PlayerEvent::Stopped { track_id, .. } => match track_id.to_base62() { + Err(e) => { + return Some(Err(Error::new( + ErrorKind::InvalidData, + format!("PlayerEvent::Stopped: Invalid track id: {}", e.utf8_error()), + ))) + } + Ok(id) => { + env_vars.insert("PLAYER_EVENT", "stopped".to_string()); + env_vars.insert("TRACK_ID", id); + } + }, PlayerEvent::Playing { track_id, duration_ms, position_ms, .. - } => { - env_vars.insert("PLAYER_EVENT", "playing".to_string()); - env_vars.insert("TRACK_ID", track_id.to_base62()); - env_vars.insert("DURATION_MS", duration_ms.to_string()); - env_vars.insert("POSITION_MS", position_ms.to_string()); - } + } => match track_id.to_base62() { + Err(e) => { + return Some(Err(Error::new( + ErrorKind::InvalidData, + format!("PlayerEvent::Playing: Invalid track id: {}", e.utf8_error()), + ))) + } + Ok(id) => { + env_vars.insert("PLAYER_EVENT", "playing".to_string()); + env_vars.insert("TRACK_ID", id); + env_vars.insert("DURATION_MS", duration_ms.to_string()); + env_vars.insert("POSITION_MS", position_ms.to_string()); + } + }, PlayerEvent::Paused { track_id, duration_ms, position_ms, .. - } => { - env_vars.insert("PLAYER_EVENT", "paused".to_string()); - env_vars.insert("TRACK_ID", track_id.to_base62()); - env_vars.insert("DURATION_MS", duration_ms.to_string()); - env_vars.insert("POSITION_MS", position_ms.to_string()); - } - PlayerEvent::Preloading { track_id, .. } => { - env_vars.insert("PLAYER_EVENT", "preloading".to_string()); - env_vars.insert("TRACK_ID", track_id.to_base62()); - } + } => match track_id.to_base62() { + Err(e) => { + return Some(Err(Error::new( + ErrorKind::InvalidData, + format!("PlayerEvent::Paused: Invalid track id: {}", e.utf8_error()), + ))) + } + Ok(id) => { + env_vars.insert("PLAYER_EVENT", "paused".to_string()); + env_vars.insert("TRACK_ID", id); + env_vars.insert("DURATION_MS", duration_ms.to_string()); + env_vars.insert("POSITION_MS", position_ms.to_string()); + } + }, + PlayerEvent::Preloading { track_id, .. } => match track_id.to_base62() { + Err(e) => { + return Some(Err(Error::new( + ErrorKind::InvalidData, + format!( + "PlayerEvent::Preloading: Invalid track id: {}", + e.utf8_error() + ), + ))) + } + Ok(id) => { + env_vars.insert("PLAYER_EVENT", "preloading".to_string()); + env_vars.insert("TRACK_ID", id); + } + }, PlayerEvent::VolumeSet { volume } => { env_vars.insert("PLAYER_EVENT", "volume_set".to_string()); env_vars.insert("VOLUME", volume.to_string()); From 03e71f6e0a94265c3a3106e34a87264cc9e825fd Mon Sep 17 00:00:00 2001 From: Jason Gray Date: Thu, 27 Jan 2022 00:40:59 -0600 Subject: [PATCH 04/39] simplify get_factor (#942) Simplify `get_factor` --- CHANGELOG.md | 1 + playback/src/player.rs | 58 ++++++++++++++++++++++++++++++++---------- 2 files changed, 46 insertions(+), 13 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 74809104..c1a8fd73 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -29,6 +29,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - [main] Don't panic when parsing options. Instead list valid values and exit. - [main] `--alsa-mixer-device` and `--alsa-mixer-index` now fallback to the card and index specified in `--device`. - [core] Removed unsafe code (breaking) +- [playback] Adhere to ReplayGain spec when calculating gain normalisation factor. ### Removed - [playback] `alsamixer`: previously deprecated option `mixer-card` has been removed. diff --git a/playback/src/player.rs b/playback/src/player.rs index b2bdea0c..48129177 100644 --- a/playback/src/player.rs +++ b/playback/src/player.rs @@ -31,6 +31,7 @@ use crate::{MS_PER_PAGE, NUM_CHANNELS, PAGES_PER_MS, SAMPLES_PER_SECOND}; const PRELOAD_NEXT_TRACK_BEFORE_END_DURATION_MS: u32 = 30000; pub const DB_VOLTAGE_RATIO: f64 = 20.0; +pub const PCM_AT_0DBFS: f64 = 1.0; pub struct Player { commands: Option>, @@ -251,26 +252,57 @@ impl NormalisationData { (data.track_gain_db, data.track_peak) }; - let normalisation_power = gain_db + config.normalisation_pregain_db; - let mut normalisation_factor = db_to_ratio(normalisation_power); + // As per the ReplayGain 1.0 & 2.0 (proposed) spec: + // https://wiki.hydrogenaud.io/index.php?title=ReplayGain_1.0_specification#Clipping_prevention + // https://wiki.hydrogenaud.io/index.php?title=ReplayGain_2.0_specification#Clipping_prevention + let normalisation_factor = if config.normalisation_method == NormalisationMethod::Basic { + // For Basic Normalisation, factor = min(ratio of (ReplayGain + PreGain), 1.0 / peak level). + // https://wiki.hydrogenaud.io/index.php?title=ReplayGain_1.0_specification#Peak_amplitude + // https://wiki.hydrogenaud.io/index.php?title=ReplayGain_2.0_specification#Peak_amplitude + // We then limit that to 1.0 as not to exceed dBFS (0.0 dB). + let factor = f64::min( + db_to_ratio(gain_db + config.normalisation_pregain_db), + PCM_AT_0DBFS / gain_peak, + ); - if normalisation_power + ratio_to_db(gain_peak) > config.normalisation_threshold_dbfs { - let limited_normalisation_factor = - db_to_ratio(config.normalisation_threshold_dbfs) / gain_peak; - let limited_normalisation_power = ratio_to_db(limited_normalisation_factor); + if factor > PCM_AT_0DBFS { + info!( + "Lowering gain by {:.2} dB for the duration of this track to avoid potentially exceeding dBFS.", + ratio_to_db(factor) + ); - if config.normalisation_method == NormalisationMethod::Basic { - warn!("Limiting gain to {:.2} dB for the duration of this track to stay under normalisation threshold.", limited_normalisation_power); - normalisation_factor = limited_normalisation_factor; + PCM_AT_0DBFS } else { + factor + } + } else { + // For Dynamic Normalisation it's up to the player to decide, + // factor = ratio of (ReplayGain + PreGain). + // We then let the dynamic limiter handle gain reduction. + let factor = db_to_ratio(gain_db + config.normalisation_pregain_db); + let threshold_ratio = db_to_ratio(config.normalisation_threshold_dbfs); + + if factor > PCM_AT_0DBFS { + let factor_db = gain_db + config.normalisation_pregain_db; + let limiting_db = factor_db + config.normalisation_threshold_dbfs.abs(); + warn!( - "This track will at its peak be subject to {:.2} dB of dynamic limiting.", - normalisation_power - limited_normalisation_power + "This track may exceed dBFS by {:.2} dB and be subject to {:.2} dB of dynamic limiting at it's peak.", + factor_db, limiting_db + ); + } else if factor > threshold_ratio { + let limiting_db = gain_db + + config.normalisation_pregain_db + + config.normalisation_threshold_dbfs.abs(); + + info!( + "This track may be subject to {:.2} dB of dynamic limiting at it's peak.", + limiting_db ); } - warn!("Please lower pregain to avoid."); - } + factor + }; debug!("Normalisation Data: {:?}", data); debug!( From c8971dce63f24a2e19da07fd5ce52e09bfdcf40e Mon Sep 17 00:00:00 2001 From: Roderick van Domburg Date: Thu, 27 Jan 2022 18:39:28 +0100 Subject: [PATCH 05/39] Fix Alsa softvol linear mapping (#950) Use `--volume-range` overrides --- CHANGELOG.md | 1 + playback/src/mixer/alsamixer.rs | 15 +++++++++++++-- 2 files changed, 14 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index c1a8fd73..24d1a17a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -30,6 +30,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - [main] `--alsa-mixer-device` and `--alsa-mixer-index` now fallback to the card and index specified in `--device`. - [core] Removed unsafe code (breaking) - [playback] Adhere to ReplayGain spec when calculating gain normalisation factor. +- [playback] `alsa`: Use `--volume-range` overrides for softvol controls ### Removed - [playback] `alsamixer`: previously deprecated option `mixer-card` has been removed. diff --git a/playback/src/mixer/alsamixer.rs b/playback/src/mixer/alsamixer.rs index 55398cb7..c04e6ee8 100644 --- a/playback/src/mixer/alsamixer.rs +++ b/playback/src/mixer/alsamixer.rs @@ -84,7 +84,7 @@ impl Mixer for AlsaMixer { warn!("Alsa rounding error detected, setting maximum dB to {:.2} instead of {:.2}", ZERO_DB.to_db(), max_millibel.to_db()); max_millibel = ZERO_DB; } else { - warn!("Please manually set with `--volume-ctrl` if this is incorrect"); + warn!("Please manually set `--volume-range` if this is incorrect"); } } (min_millibel, max_millibel) @@ -104,12 +104,23 @@ impl Mixer for AlsaMixer { let min_db = min_millibel.to_db() as f64; let max_db = max_millibel.to_db() as f64; - let db_range = f64::abs(max_db - min_db); + let mut db_range = f64::abs(max_db - min_db); // Synchronize the volume control dB range with the mixer control, // unless it was already set with a command line option. if !config.volume_ctrl.range_ok() { + if db_range > 100.0 { + debug!("Alsa mixer reported dB range > 100, which is suspect"); + warn!("Please manually set `--volume-range` if this is incorrect"); + } config.volume_ctrl.set_db_range(db_range); + } else { + let db_range_override = config.volume_ctrl.db_range(); + debug!( + "Alsa dB volume range was detected as {} but overridden as {}", + db_range, db_range_override + ); + db_range = db_range_override; } // For hardware controls with a small range (24 dB or less), From 3c749a8f0e66df865701bbfa36df37e8ef258b9e Mon Sep 17 00:00:00 2001 From: JasonLG1979 Date: Thu, 27 Jan 2022 17:00:08 -0600 Subject: [PATCH 06/39] Remove basic normalisation deprecation warning --- src/main.rs | 18 ++---------------- 1 file changed, 2 insertions(+), 16 deletions(-) diff --git a/src/main.rs b/src/main.rs index f43500fe..c70f39da 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1293,12 +1293,7 @@ fn get_setup() -> Setup { normalisation_method = opt_str(NORMALISATION_METHOD) .as_deref() .map(|method| { - warn!( - "`--{}` / `-{}` will be deprecated in a future release.", - NORMALISATION_METHOD, NORMALISATION_METHOD_SHORT - ); - - let method = NormalisationMethod::from_str(method).unwrap_or_else(|_| { + NormalisationMethod::from_str(method).unwrap_or_else(|_| { invalid_error_msg( NORMALISATION_METHOD, NORMALISATION_METHOD_SHORT, @@ -1308,16 +1303,7 @@ fn get_setup() -> Setup { ); exit(1); - }); - - if matches!(method, NormalisationMethod::Basic) { - warn!( - "`--{}` / `-{}` {:?} will be deprecated in a future release.", - NORMALISATION_METHOD, NORMALISATION_METHOD_SHORT, method - ); - } - - method + }) }) .unwrap_or(player_default_config.normalisation_method); From edb98d5c1dce233f30ac4781bf74a939701291e9 Mon Sep 17 00:00:00 2001 From: JasonLG1979 Date: Mon, 31 Jan 2022 18:20:10 -0600 Subject: [PATCH 07/39] Prevent shuffle crash fixes https://github.com/librespot-org/librespot/issues/959 --- connect/src/spirc.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/connect/src/spirc.rs b/connect/src/spirc.rs index 344f63b7..b574ff52 100644 --- a/connect/src/spirc.rs +++ b/connect/src/spirc.rs @@ -668,15 +668,15 @@ impl SpircTask { self.state.set_shuffle(frame.get_state().get_shuffle()); if self.state.get_shuffle() { let current_index = self.state.get_playing_track_index(); - { - let tracks = self.state.mut_track(); + let tracks = self.state.mut_track(); + if !tracks.is_empty() { tracks.swap(0, current_index as usize); if let Some((_, rest)) = tracks.split_first_mut() { let mut rng = rand::thread_rng(); rest.shuffle(&mut rng); } + self.state.set_playing_track_index(0); } - self.state.set_playing_track_index(0); } else { let context = self.state.get_context_uri(); debug!("{:?}", context); From d54f3982a0b265e11270d2743d847853727dc67f Mon Sep 17 00:00:00 2001 From: JasonLG1979 Date: Tue, 1 Feb 2022 17:48:13 -0600 Subject: [PATCH 08/39] update changelog --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 24d1a17a..6db058bd 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -31,6 +31,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - [core] Removed unsafe code (breaking) - [playback] Adhere to ReplayGain spec when calculating gain normalisation factor. - [playback] `alsa`: Use `--volume-range` overrides for softvol controls +- [connect] Don't panic when activating shuffle without previous interaction. ### Removed - [playback] `alsamixer`: previously deprecated option `mixer-card` has been removed. From 6f6d330bce17061ea5960a593f5c0579a0a822f6 Mon Sep 17 00:00:00 2001 From: Michael Herger Date: Mon, 7 Feb 2022 23:37:29 +0100 Subject: [PATCH 09/39] Only log runtime argument if it starts with a dash "-" When there's a value that corresponds to an argument name used in the same command line, the logging of the arguments gets confused and logs the matching argument, but without the leading dash: ``` % target/debug/librespot -n c --verbose -c /path/to/my/cache [2022-02-07T22:32:25Z INFO librespot] librespot 0.3.1 55ced49 (Built on 2022-02-07, Build ID: qaEB8kEW, Profile: debug) [2022-02-07T22:32:25Z TRACE librespot] Command line argument(s): [2022-02-07T22:32:25Z TRACE librespot] -n "c" [2022-02-07T22:32:25Z TRACE librespot] c "/path/to/my/cache" [2022-02-07T22:32:25Z TRACE librespot] --verbose [2022-02-07T22:32:25Z TRACE librespot] -c "/path/to/my/cache" ``` Here we're using the literal `c` as the device name, and the `-c` argument. Thus the `c /path/to/my/cache` is logged in addition to `-c /path...`. After checking whether the key has a leading dash, this issue is gone: ``` % target/debug/librespot -n c --verbose -c /path/to/my/cache [2022-02-07T22:32:41Z INFO librespot] librespot 0.3.1 55ced49 (Built on 2022-02-07, Build ID: qaEB8kEW, Profile: debug) [2022-02-07T22:32:41Z TRACE librespot] Command line argument(s): [2022-02-07T22:32:41Z TRACE librespot] -n "c" [2022-02-07T22:32:41Z TRACE librespot] --verbose [2022-02-07T22:32:41Z TRACE librespot] -c "/path/to/my/cache" ``` --- src/main.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/main.rs b/src/main.rs index c70f39da..e9969f50 100644 --- a/src/main.rs +++ b/src/main.rs @@ -661,6 +661,7 @@ fn get_setup() -> Setup { let opt = key.trim_start_matches('-'); if index > 0 + && key.starts_with('-') && &args[index - 1] != key && matches.opt_defined(opt) && matches.opt_present(opt) From 616809b64c1d517cd6cf120ab1bc39f2cd7b0a2a Mon Sep 17 00:00:00 2001 From: Jason Gray Date: Sun, 13 Feb 2022 15:50:32 -0600 Subject: [PATCH 10/39] Quantum-realm level normalisation optimization (#965) This saves up to 1-2% CPU useage on a PI 4 depending on how much normalisation is actually being done. * We don't need to test against EPSILON. The factor will never be over 1.0 in basic normalisation mode. * Don't check the normalisation mode EVERY sample. * Do as little math as possible by simplfiying all equations as much as possible (while still retaining the textbook equations in comments). * Misc cleanup --- playback/src/convert.rs | 40 +++++------ playback/src/dither.rs | 6 +- playback/src/player.rs | 147 +++++++++++++++++++++------------------- 3 files changed, 96 insertions(+), 97 deletions(-) diff --git a/playback/src/convert.rs b/playback/src/convert.rs index 962ade66..1bc8a88e 100644 --- a/playback/src/convert.rs +++ b/playback/src/convert.rs @@ -23,14 +23,15 @@ pub struct Converter { impl Converter { pub fn new(dither_config: Option) -> Self { - if let Some(ref ditherer_builder) = dither_config { - let ditherer = (ditherer_builder)(); - info!("Converting with ditherer: {}", ditherer.name()); - Self { - ditherer: Some(ditherer), + match dither_config { + Some(ditherer_builder) => { + let ditherer = (ditherer_builder)(); + info!("Converting with ditherer: {}", ditherer.name()); + Self { + ditherer: Some(ditherer), + } } - } else { - Self { ditherer: None } + None => Self { ditherer: None }, } } @@ -52,18 +53,15 @@ impl Converter { const SCALE_S16: f64 = 32768.; pub fn scale(&mut self, sample: f64, factor: f64) -> f64 { - let dither = match self.ditherer { - Some(ref mut d) => d.noise(), - None => 0.0, - }; - // From the many float to int conversion methods available, match what // the reference Vorbis implementation uses: sample * 32768 (for 16 bit) - let int_value = sample * factor + dither; // Casting float to integer rounds towards zero by default, i.e. it // truncates, and that generates larger error than rounding to nearest. - int_value.round() + match self.ditherer.as_mut() { + Some(d) => (sample * factor + d.noise()).round(), + None => (sample * factor).round(), + } } // Special case for samples packed in a word of greater bit depth (e.g. @@ -79,11 +77,12 @@ impl Converter { let max = factor - 1.0; if int_value < min { - return min; + min } else if int_value > max { - return max; + max + } else { + int_value } - int_value } pub fn f64_to_f32(&mut self, samples: &[f64]) -> Vec { @@ -109,12 +108,7 @@ impl Converter { pub fn f64_to_s24_3(&mut self, samples: &[f64]) -> Vec { samples .iter() - .map(|sample| { - // Not as DRY as calling f32_to_s24 first, but this saves iterating - // over all samples twice. - let int_value = self.clamping_scale(*sample, Self::SCALE_S24) as i32; - i24::from_s24(int_value) - }) + .map(|sample| i24::from_s24(self.clamping_scale(*sample, Self::SCALE_S24) as i32)) .collect() } diff --git a/playback/src/dither.rs b/playback/src/dither.rs index 0f667917..4b8a427c 100644 --- a/playback/src/dither.rs +++ b/playback/src/dither.rs @@ -3,7 +3,7 @@ use rand::SeedableRng; use rand_distr::{Distribution, Normal, Triangular, Uniform}; use std::fmt; -const NUM_CHANNELS: usize = 2; +use crate::NUM_CHANNELS; // Dithering lowers digital-to-analog conversion ("requantization") error, // linearizing output, lowering distortion and replacing it with a constant, @@ -102,7 +102,7 @@ impl GaussianDitherer { pub struct HighPassDitherer { active_channel: usize, - previous_noises: [f64; NUM_CHANNELS], + previous_noises: [f64; NUM_CHANNELS as usize], cached_rng: SmallRng, distribution: Uniform, } @@ -111,7 +111,7 @@ impl Ditherer for HighPassDitherer { fn new() -> Self { Self { active_channel: 0, - previous_noises: [0.0; NUM_CHANNELS], + previous_noises: [0.0; NUM_CHANNELS as usize], cached_rng: create_rng(), distribution: Uniform::new_inclusive(-0.5, 0.5), // 1 LSB +/- 1 LSB (previous) = 2 LSB } diff --git a/playback/src/player.rs b/playback/src/player.rs index 48129177..74ba1fc4 100644 --- a/playback/src/player.rs +++ b/playback/src/player.rs @@ -760,7 +760,16 @@ impl PlayerTrackLoader { position_ms: u32, ) -> Option { let audio = match AudioItem::get_audio_item(&self.session, spotify_id).await { - Ok(audio) => audio, + Ok(audio) => match self.find_available_alternative(audio).await { + Some(audio) => audio, + None => { + warn!( + "<{}> is not available", + spotify_id.to_uri().unwrap_or_default() + ); + return None; + } + }, Err(e) => { error!("Unable to load audio item: {:?}", e); return None; @@ -769,17 +778,6 @@ impl PlayerTrackLoader { info!("Loading <{}> with Spotify URI <{}>", audio.name, audio.uri); - let audio = match self.find_available_alternative(audio).await { - Some(audio) => audio, - None => { - warn!( - "<{}> is not available", - spotify_id.to_uri().unwrap_or_default() - ); - return None; - } - }; - if audio.duration < 0 { error!( "Track duration for <{}> cannot be {}", @@ -809,26 +807,24 @@ impl PlayerTrackLoader { ], }; - let entry = formats.iter().find_map(|format| { - if let Some(&file_id) = audio.files.get(format) { - Some((*format, file_id)) - } else { - None - } - }); - - let (format, file_id) = match entry { - Some(t) => t, - None => { - warn!("<{}> is not available in any supported format", audio.name); - return None; - } - }; + let (format, file_id) = + match formats + .iter() + .find_map(|format| match audio.files.get(format) { + Some(&file_id) => Some((*format, file_id)), + _ => None, + }) { + Some(t) => t, + None => { + warn!("<{}> is not available in any supported format", audio.name); + return None; + } + }; let bytes_per_second = self.stream_data_rate(format); let play_from_beginning = position_ms == 0; - // This is only a loop to be able to reload the file if an error occured + // This is only a loop to be able to reload the file if an error occurred // while opening a cached file. loop { let encrypted_file = AudioFile::open( @@ -1321,25 +1317,30 @@ impl PlayerInternal { // For the basic normalisation method, a normalisation factor of 1.0 indicates that // there is nothing to normalise (all samples should pass unaltered). For the // dynamic method, there may still be peaks that we want to shave off. - if self.config.normalisation - && !(f64::abs(normalisation_factor - 1.0) <= f64::EPSILON - && self.config.normalisation_method == NormalisationMethod::Basic) - { - // zero-cost shorthands - let threshold_db = self.config.normalisation_threshold_dbfs; - let knee_db = self.config.normalisation_knee_db; - let attack_cf = self.config.normalisation_attack_cf; - let release_cf = self.config.normalisation_release_cf; + if self.config.normalisation { + if self.config.normalisation_method == NormalisationMethod::Basic + && normalisation_factor < 1.0 + { + for sample in data.iter_mut() { + *sample *= normalisation_factor; + } + } else if self.config.normalisation_method + == NormalisationMethod::Dynamic + { + // zero-cost shorthands + let threshold_db = self.config.normalisation_threshold_dbfs; + let knee_db = self.config.normalisation_knee_db; + let attack_cf = self.config.normalisation_attack_cf; + let release_cf = self.config.normalisation_release_cf; - for sample in data.iter_mut() { - *sample *= normalisation_factor; // for both the basic and dynamic limiter + for sample in data.iter_mut() { + *sample *= normalisation_factor; + + // Feedforward limiter in the log domain + // After: Giannoulis, D., Massberg, M., & Reiss, J.D. (2012). Digital Dynamic + // Range Compressor Design—A Tutorial and Analysis. Journal of The Audio + // Engineering Society, 60, 399-408. - // Feedforward limiter in the log domain - // After: Giannoulis, D., Massberg, M., & Reiss, J.D. (2012). Digital Dynamic - // Range Compressor Design—A Tutorial and Analysis. Journal of The Audio - // Engineering Society, 60, 399-408. - if self.config.normalisation_method == NormalisationMethod::Dynamic - { // Some tracks have samples that are precisely 0.0. That's silence // and we know we don't need to limit that, in which we can spare // the CPU cycles. @@ -1348,22 +1349,26 @@ impl PlayerInternal { // peak detector stuck. Also catch the unlikely case where a sample // is decoded as `NaN` or some other non-normal value. let limiter_db = if sample.is_normal() { - // step 1-2: half-wave rectification and conversion into dB - let abs_sample_db = ratio_to_db(sample.abs()); - - // step 3-4: gain computer with soft knee and subtractor - let bias_db = abs_sample_db - threshold_db; + // step 1-4: half-wave rectification and conversion into dB + // and gain computer with soft knee and subtractor + let bias_db = ratio_to_db(sample.abs()) - threshold_db; let knee_boundary_db = bias_db * 2.0; if knee_boundary_db < -knee_db { 0.0 } else if knee_boundary_db.abs() <= knee_db { - abs_sample_db - - (abs_sample_db - - (bias_db + knee_db / 2.0).powi(2) - / (2.0 * knee_db)) + // The textbook equation: + // ratio_to_db(sample.abs()) - (ratio_to_db(sample.abs()) - (bias_db + knee_db / 2.0).powi(2) / (2.0 * knee_db)) + // Simplifies to: + // ((2.0 * bias_db) + knee_db).powi(2) / (8.0 * knee_db) + // Which in our case further simplifies to: + // (knee_boundary_db + knee_db).powi(2) / (8.0 * knee_db) + // because knee_boundary_db is 2.0 * bias_db. + (knee_boundary_db + knee_db).powi(2) / (8.0 * knee_db) } else { - abs_sample_db - threshold_db + // Textbook: + // ratio_to_db(sample.abs()) - threshold_db, which is already our bias_db. + bias_db } } else { 0.0 @@ -1377,14 +1382,24 @@ impl PlayerInternal { || self.normalisation_peak > 0.0 { // step 5: smooth, decoupled peak detector + // Textbook: + // release_cf * self.normalisation_integrator + (1.0 - release_cf) * limiter_db + // Simplifies to: + // release_cf * self.normalisation_integrator - release_cf * limiter_db + limiter_db self.normalisation_integrator = f64::max( limiter_db, release_cf * self.normalisation_integrator - + (1.0 - release_cf) * limiter_db, + - release_cf * limiter_db + + limiter_db, ); + // Textbook: + // attack_cf * self.normalisation_peak + (1.0 - attack_cf) * self.normalisation_integrator + // Simplifies to: + // attack_cf * self.normalisation_peak - attack_cf * self.normalisation_integrator + self.normalisation_integrator self.normalisation_peak = attack_cf * self.normalisation_peak - + (1.0 - attack_cf) * self.normalisation_integrator; + - attack_cf * self.normalisation_integrator + + self.normalisation_integrator; // step 6: make-up gain applied later (volume attenuation) // Applying the standard normalisation factor here won't work, @@ -1897,15 +1912,8 @@ impl PlayerInternal { } fn send_event(&mut self, event: PlayerEvent) { - let mut index = 0; - while index < self.event_senders.len() { - match self.event_senders[index].send(event.clone()) { - Ok(_) => index += 1, - Err(_) => { - self.event_senders.remove(index); - } - } - } + self.event_senders + .retain(|sender| sender.send(event.clone()).is_ok()); } fn load_track( @@ -2079,10 +2087,7 @@ impl Seek for Subfile { }; let newpos = self.stream.seek(pos)?; - if newpos > self.offset { - Ok(newpos - self.offset) - } else { - Ok(0) - } + + Ok(newpos.saturating_sub(self.offset)) } } From e0e23c9167db6f56a6645c32ea73bb627e5f9d13 Mon Sep 17 00:00:00 2001 From: JasonLG1979 Date: Mon, 7 Mar 2022 20:12:18 -0600 Subject: [PATCH 11/39] Use the librespot name arg for the app name in the PulseAudio backend This sets the name displayed by PulseAudio to Librespot - Instance Name if a name is given otherwise Librespot (the default name). This also sets the correct "role" as per the docs: https://www.freedesktop.org/wiki/Software/PulseAudio/Documentation/Developer/Clients/ApplicationProperties/ PA_PROP_MEDIA_ROLE "This is a property of the actual streamed data, not so much the application" Roles are used for policies, things like automatically muting a music player when a call comes in and whatnot. For bonus points this also sets PULSE_PROP_application.icon_name to audio-x-generic so that we get a nice icon in the PulseAudio settings by our name instead of a missing icon placeholder. --- CHANGELOG.md | 3 ++ playback/src/audio_backend/pulseaudio.rs | 41 +++++++++++++----------- src/main.rs | 37 +++++++++++++++++++++ 3 files changed, 62 insertions(+), 19 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 6db058bd..d93b636c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -23,6 +23,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - [main] Add a `-q`, `--quiet` option that changes the logging level to warn. - [main] Add a short name for every flag and option. - [main] Add the ability to parse environment variables. +- [playback] `pulseaudio`: set the PulseAudio name to match librespot's device name via `PULSE_PROP_application.name` environment variable (user set env var value takes precedence). (breaking) +- [playback] `pulseaudio`: set icon to `audio-x-generic` so we get an icon instead of a placeholder via `PULSE_PROP_application.icon_name` environment variable (user set env var value takes precedence). (breaking) +- [playback] `pulseaudio`: set values to: `PULSE_PROP_application.version`, `PULSE_PROP_application.process.binary`, `PULSE_PROP_stream.description`, `PULSE_PROP_media.software` and `PULSE_PROP_media.role` environment variables (user set env var values take precedence). (breaking) ### Fixed - [main] Prevent hang when discovery is disabled and there are no credentials or when bad credentials are given. diff --git a/playback/src/audio_backend/pulseaudio.rs b/playback/src/audio_backend/pulseaudio.rs index 7487517f..b92acefa 100644 --- a/playback/src/audio_backend/pulseaudio.rs +++ b/playback/src/audio_backend/pulseaudio.rs @@ -5,11 +5,9 @@ use crate::decoder::AudioPacket; use crate::{NUM_CHANNELS, SAMPLE_RATE}; use libpulse_binding::{self as pulse, error::PAErr, stream::Direction}; use libpulse_simple_binding::Simple; +use std::env; use thiserror::Error; -const APP_NAME: &str = "librespot"; -const STREAM_NAME: &str = "Spotify endpoint"; - #[derive(Debug, Error)] enum PulseError { #[error(" Unsupported Pulseaudio Sample Spec, Format {pulse_format:?} ({format:?}), Channels {channels}, Rate {rate}")] @@ -47,13 +45,18 @@ impl From for SinkError { } pub struct PulseAudioSink { - s: Option, + sink: Option, device: Option, + app_name: String, + stream_desc: String, format: AudioFormat, } impl Open for PulseAudioSink { fn open(device: Option, format: AudioFormat) -> Self { + let app_name = env::var("PULSE_PROP_application.name").unwrap_or_default(); + let stream_desc = env::var("PULSE_PROP_stream.description").unwrap_or_default(); + let mut actual_format = format; if actual_format == AudioFormat::F64 { @@ -64,8 +67,10 @@ impl Open for PulseAudioSink { info!("Using PulseAudioSink with format: {:?}", actual_format); Self { - s: None, + sink: None, device, + app_name, + stream_desc, format: actual_format, } } @@ -73,7 +78,7 @@ impl Open for PulseAudioSink { impl Sink for PulseAudioSink { fn start(&mut self) -> SinkResult<()> { - if self.s.is_none() { + if self.sink.is_none() { // PulseAudio calls S24 and S24_3 different from the rest of the world let pulse_format = match self.format { AudioFormat::F32 => pulse::sample::Format::FLOAT32NE, @@ -84,13 +89,13 @@ impl Sink for PulseAudioSink { _ => unreachable!(), }; - let ss = pulse::sample::Spec { + let sample_spec = pulse::sample::Spec { format: pulse_format, channels: NUM_CHANNELS, rate: SAMPLE_RATE, }; - if !ss.is_valid() { + if !sample_spec.is_valid() { let pulse_error = PulseError::InvalidSampleSpec { pulse_format, format: self.format, @@ -101,30 +106,28 @@ impl Sink for PulseAudioSink { return Err(SinkError::from(pulse_error)); } - let s = Simple::new( + let sink = Simple::new( None, // Use the default server. - APP_NAME, // Our application's name. + &self.app_name, // Our application's name. Direction::Playback, // Direction. self.device.as_deref(), // Our device (sink) name. - STREAM_NAME, // Description of our stream. - &ss, // Our sample format. + &self.stream_desc, // Description of our stream. + &sample_spec, // Our sample format. None, // Use default channel map. None, // Use default buffering attributes. ) .map_err(PulseError::ConnectionRefused)?; - self.s = Some(s); + self.sink = Some(sink); } Ok(()) } fn stop(&mut self) -> SinkResult<()> { - let s = self.s.as_mut().ok_or(PulseError::NotConnected)?; + let sink = self.sink.take().ok_or(PulseError::NotConnected)?; - s.drain().map_err(PulseError::DrainFailure)?; - - self.s = None; + sink.drain().map_err(PulseError::DrainFailure)?; Ok(()) } @@ -133,9 +136,9 @@ impl Sink for PulseAudioSink { impl SinkAsBytes for PulseAudioSink { fn write_bytes(&mut self, data: &[u8]) -> SinkResult<()> { - let s = self.s.as_mut().ok_or(PulseError::NotConnected)?; + let sink = self.sink.as_mut().ok_or(PulseError::NotConnected)?; - s.write(data).map_err(PulseError::OnWrite)?; + sink.write(data).map_err(PulseError::OnWrite)?; Ok(()) } diff --git a/src/main.rs b/src/main.rs index e9969f50..8d81834d 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1124,6 +1124,43 @@ fn get_setup() -> Setup { exit(1); } + #[cfg(feature = "pulseaudio-backend")] + { + if env::var("PULSE_PROP_application.name").is_err() { + let pulseaudio_name = if name != connect_default_config.name { + format!("{} - {}", connect_default_config.name, name) + } else { + name.clone() + }; + + env::set_var("PULSE_PROP_application.name", pulseaudio_name); + } + + if env::var("PULSE_PROP_application.version").is_err() { + env::set_var("PULSE_PROP_application.version", version::SEMVER); + } + + if env::var("PULSE_PROP_application.icon_name").is_err() { + env::set_var("PULSE_PROP_application.icon_name", "audio-x-generic"); + } + + if env::var("PULSE_PROP_application.process.binary").is_err() { + env::set_var("PULSE_PROP_application.process.binary", "librespot"); + } + + if env::var("PULSE_PROP_stream.description").is_err() { + env::set_var("PULSE_PROP_stream.description", "Spotify Connect endpoint"); + } + + if env::var("PULSE_PROP_media.software").is_err() { + env::set_var("PULSE_PROP_media.software", "Spotify"); + } + + if env::var("PULSE_PROP_media.role").is_err() { + env::set_var("PULSE_PROP_media.role", "music"); + } + } + let initial_volume = opt_str(INITIAL_VOLUME) .map(|initial_volume| { let volume = match initial_volume.parse::() { From 10c9a0f8eab743a2d59268eed0a2eac53a270ab8 Mon Sep 17 00:00:00 2001 From: Gnarflord Date: Thu, 19 May 2022 18:37:21 +0200 Subject: [PATCH 12/39] Use libmdns 0.7 to avoid packet 47 error --- discovery/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/discovery/Cargo.toml b/discovery/Cargo.toml index 9b4d415e..4dccdc1e 100644 --- a/discovery/Cargo.toml +++ b/discovery/Cargo.toml @@ -15,7 +15,7 @@ form_urlencoded = "1.0" futures-core = "0.3" hmac = "0.11" hyper = { version = "0.14", features = ["server", "http1", "tcp"] } -libmdns = "0.6" +libmdns = "0.7" log = "0.4" rand = "0.8" serde_json = "1.0.25" From 7efc62b9cad876bb438af8ab75458db6d2db17dc Mon Sep 17 00:00:00 2001 From: Jason Gray Date: Thu, 19 May 2022 15:23:14 -0500 Subject: [PATCH 13/39] Remove the volume sample iteration (#986) Move volume calculations out of their own separate samples iteration and into the normalisation iteration --- examples/play.rs | 3 +- playback/src/mixer/mod.rs | 16 ++- playback/src/mixer/softmixer.rs | 23 ++-- playback/src/player.rs | 205 ++++++++++++++++---------------- src/main.rs | 4 +- 5 files changed, 126 insertions(+), 125 deletions(-) diff --git a/examples/play.rs b/examples/play.rs index d6c7196d..6156cb7b 100644 --- a/examples/play.rs +++ b/examples/play.rs @@ -6,6 +6,7 @@ use librespot::core::session::Session; use librespot::core::spotify_id::SpotifyId; use librespot::playback::audio_backend; use librespot::playback::config::{AudioFormat, PlayerConfig}; +use librespot::playback::mixer::NoOpVolume; use librespot::playback::player::Player; #[tokio::main] @@ -30,7 +31,7 @@ async fn main() { .await .unwrap(); - let (mut player, _) = Player::new(player_config, session, None, move || { + let (mut player, _) = Player::new(player_config, session, Box::new(NoOpVolume), move || { backend(None, audio_format) }); diff --git a/playback/src/mixer/mod.rs b/playback/src/mixer/mod.rs index a3c7a5a1..0a8b8d6c 100644 --- a/playback/src/mixer/mod.rs +++ b/playback/src/mixer/mod.rs @@ -3,6 +3,8 @@ use crate::config::VolumeCtrl; pub mod mappings; use self::mappings::MappedCtrl; +pub struct NoOpVolume; + pub trait Mixer: Send { fn open(config: MixerConfig) -> Self where @@ -11,13 +13,19 @@ pub trait Mixer: Send { fn set_volume(&self, volume: u16); fn volume(&self) -> u16; - fn get_audio_filter(&self) -> Option> { - None + fn get_soft_volume(&self) -> Box { + Box::new(NoOpVolume) } } -pub trait AudioFilter { - fn modify_stream(&self, data: &mut [f64]); +pub trait VolumeGetter { + fn attenuation_factor(&self) -> f64; +} + +impl VolumeGetter for NoOpVolume { + fn attenuation_factor(&self) -> f64 { + 1.0 + } } pub mod softmixer; diff --git a/playback/src/mixer/softmixer.rs b/playback/src/mixer/softmixer.rs index cefc2de5..93da5fec 100644 --- a/playback/src/mixer/softmixer.rs +++ b/playback/src/mixer/softmixer.rs @@ -1,7 +1,7 @@ use std::sync::atomic::{AtomicU64, Ordering}; use std::sync::Arc; -use super::AudioFilter; +use super::VolumeGetter; use super::{MappedCtrl, VolumeCtrl}; use super::{Mixer, MixerConfig}; @@ -35,10 +35,8 @@ impl Mixer for SoftMixer { .store(mapped_volume.to_bits(), Ordering::Relaxed) } - fn get_audio_filter(&self) -> Option> { - Some(Box::new(SoftVolumeApplier { - volume: self.volume.clone(), - })) + fn get_soft_volume(&self) -> Box { + Box::new(SoftVolume(self.volume.clone())) } } @@ -46,17 +44,10 @@ impl SoftMixer { pub const NAME: &'static str = "softvol"; } -struct SoftVolumeApplier { - volume: Arc, -} +struct SoftVolume(Arc); -impl AudioFilter for SoftVolumeApplier { - fn modify_stream(&self, data: &mut [f64]) { - let volume = f64::from_bits(self.volume.load(Ordering::Relaxed)); - if volume < 1.0 { - for x in data.iter_mut() { - *x *= volume; - } - } +impl VolumeGetter for SoftVolume { + fn attenuation_factor(&self) -> f64 { + f64::from_bits(self.0.load(Ordering::Relaxed)) } } diff --git a/playback/src/player.rs b/playback/src/player.rs index 74ba1fc4..a6935010 100644 --- a/playback/src/player.rs +++ b/playback/src/player.rs @@ -25,7 +25,7 @@ use crate::core::spotify_id::SpotifyId; use crate::core::util::SeqGenerator; use crate::decoder::{AudioDecoder, AudioPacket, DecoderError, PassthroughDecoder, VorbisDecoder}; use crate::metadata::{AudioItem, FileFormat}; -use crate::mixer::AudioFilter; +use crate::mixer::VolumeGetter; use crate::{MS_PER_PAGE, NUM_CHANNELS, PAGES_PER_MS, SAMPLES_PER_SECOND}; @@ -58,7 +58,7 @@ struct PlayerInternal { sink: Box, sink_status: SinkStatus, sink_event_callback: Option, - audio_filter: Option>, + volume_getter: Box, event_senders: Vec>, converter: Converter, @@ -319,7 +319,7 @@ impl Player { pub fn new( config: PlayerConfig, session: Session, - audio_filter: Option>, + volume_getter: Box, sink_builder: F, ) -> (Player, PlayerEventChannel) where @@ -369,7 +369,7 @@ impl Player { sink: sink_builder(), sink_status: SinkStatus::Closed, sink_event_callback: None, - audio_filter, + volume_getter, event_senders: [event_sender].to_vec(), converter, @@ -1314,109 +1314,110 @@ impl PlayerInternal { Some(mut packet) => { if !packet.is_empty() { if let AudioPacket::Samples(ref mut data) = packet { + // Get the volume for the packet. + // In the case of hardware volume control this will + // always be 1.0 (no change). + let volume = self.volume_getter.attenuation_factor(); + // For the basic normalisation method, a normalisation factor of 1.0 indicates that // there is nothing to normalise (all samples should pass unaltered). For the // dynamic method, there may still be peaks that we want to shave off. - if self.config.normalisation { - if self.config.normalisation_method == NormalisationMethod::Basic - && normalisation_factor < 1.0 - { - for sample in data.iter_mut() { - *sample *= normalisation_factor; - } - } else if self.config.normalisation_method - == NormalisationMethod::Dynamic - { - // zero-cost shorthands - let threshold_db = self.config.normalisation_threshold_dbfs; - let knee_db = self.config.normalisation_knee_db; - let attack_cf = self.config.normalisation_attack_cf; - let release_cf = self.config.normalisation_release_cf; - - for sample in data.iter_mut() { - *sample *= normalisation_factor; - - // Feedforward limiter in the log domain - // After: Giannoulis, D., Massberg, M., & Reiss, J.D. (2012). Digital Dynamic - // Range Compressor Design—A Tutorial and Analysis. Journal of The Audio - // Engineering Society, 60, 399-408. - - // Some tracks have samples that are precisely 0.0. That's silence - // and we know we don't need to limit that, in which we can spare - // the CPU cycles. - // - // Also, calling `ratio_to_db(0.0)` returns `inf` and would get the - // peak detector stuck. Also catch the unlikely case where a sample - // is decoded as `NaN` or some other non-normal value. - let limiter_db = if sample.is_normal() { - // step 1-4: half-wave rectification and conversion into dB - // and gain computer with soft knee and subtractor - let bias_db = ratio_to_db(sample.abs()) - threshold_db; - let knee_boundary_db = bias_db * 2.0; - - if knee_boundary_db < -knee_db { - 0.0 - } else if knee_boundary_db.abs() <= knee_db { - // The textbook equation: - // ratio_to_db(sample.abs()) - (ratio_to_db(sample.abs()) - (bias_db + knee_db / 2.0).powi(2) / (2.0 * knee_db)) - // Simplifies to: - // ((2.0 * bias_db) + knee_db).powi(2) / (8.0 * knee_db) - // Which in our case further simplifies to: - // (knee_boundary_db + knee_db).powi(2) / (8.0 * knee_db) - // because knee_boundary_db is 2.0 * bias_db. - (knee_boundary_db + knee_db).powi(2) / (8.0 * knee_db) - } else { - // Textbook: - // ratio_to_db(sample.abs()) - threshold_db, which is already our bias_db. - bias_db - } - } else { - 0.0 - }; - - // Spare the CPU unless (1) the limiter is engaged, (2) we - // were in attack or (3) we were in release, and that attack/ - // release wasn't finished yet. - if limiter_db > 0.0 - || self.normalisation_integrator > 0.0 - || self.normalisation_peak > 0.0 - { - // step 5: smooth, decoupled peak detector - // Textbook: - // release_cf * self.normalisation_integrator + (1.0 - release_cf) * limiter_db - // Simplifies to: - // release_cf * self.normalisation_integrator - release_cf * limiter_db + limiter_db - self.normalisation_integrator = f64::max( - limiter_db, - release_cf * self.normalisation_integrator - - release_cf * limiter_db - + limiter_db, - ); - // Textbook: - // attack_cf * self.normalisation_peak + (1.0 - attack_cf) * self.normalisation_integrator - // Simplifies to: - // attack_cf * self.normalisation_peak - attack_cf * self.normalisation_integrator + self.normalisation_integrator - self.normalisation_peak = attack_cf - * self.normalisation_peak - - attack_cf * self.normalisation_integrator - + self.normalisation_integrator; - - // step 6: make-up gain applied later (volume attenuation) - // Applying the standard normalisation factor here won't work, - // because there are tracks with peaks as high as 6 dB above - // the default threshold, so that would clip. - - // steps 7-8: conversion into level and multiplication into gain stage - *sample *= db_to_ratio(-self.normalisation_peak); - } - } + // No matter the case we apply volume attenuation last if there is any. + if !self.config.normalisation && volume < 1.0 { + for sample in data.iter_mut() { + *sample *= volume; } - } + } else if self.config.normalisation_method == NormalisationMethod::Basic + && (normalisation_factor < 1.0 || volume < 1.0) + { + for sample in data.iter_mut() { + *sample *= normalisation_factor * volume; + } + } else if self.config.normalisation_method == NormalisationMethod::Dynamic { + // zero-cost shorthands + let threshold_db = self.config.normalisation_threshold_dbfs; + let knee_db = self.config.normalisation_knee_db; + let attack_cf = self.config.normalisation_attack_cf; + let release_cf = self.config.normalisation_release_cf; - // Apply volume attenuation last. TODO: make this so we can chain - // the normaliser and mixer as a processing pipeline. - if let Some(ref editor) = self.audio_filter { - editor.modify_stream(data) + for sample in data.iter_mut() { + *sample *= normalisation_factor; + + // Feedforward limiter in the log domain + // After: Giannoulis, D., Massberg, M., & Reiss, J.D. (2012). Digital Dynamic + // Range Compressor Design—A Tutorial and Analysis. Journal of The Audio + // Engineering Society, 60, 399-408. + + // Some tracks have samples that are precisely 0.0. That's silence + // and we know we don't need to limit that, in which we can spare + // the CPU cycles. + // + // Also, calling `ratio_to_db(0.0)` returns `inf` and would get the + // peak detector stuck. Also catch the unlikely case where a sample + // is decoded as `NaN` or some other non-normal value. + let limiter_db = if sample.is_normal() { + // step 1-4: half-wave rectification and conversion into dB + // and gain computer with soft knee and subtractor + let bias_db = ratio_to_db(sample.abs()) - threshold_db; + let knee_boundary_db = bias_db * 2.0; + + if knee_boundary_db < -knee_db { + 0.0 + } else if knee_boundary_db.abs() <= knee_db { + // The textbook equation: + // ratio_to_db(sample.abs()) - (ratio_to_db(sample.abs()) - (bias_db + knee_db / 2.0).powi(2) / (2.0 * knee_db)) + // Simplifies to: + // ((2.0 * bias_db) + knee_db).powi(2) / (8.0 * knee_db) + // Which in our case further simplifies to: + // (knee_boundary_db + knee_db).powi(2) / (8.0 * knee_db) + // because knee_boundary_db is 2.0 * bias_db. + (knee_boundary_db + knee_db).powi(2) / (8.0 * knee_db) + } else { + // Textbook: + // ratio_to_db(sample.abs()) - threshold_db, which is already our bias_db. + bias_db + } + } else { + 0.0 + }; + + // Spare the CPU unless (1) the limiter is engaged, (2) we + // were in attack or (3) we were in release, and that attack/ + // release wasn't finished yet. + if limiter_db > 0.0 + || self.normalisation_integrator > 0.0 + || self.normalisation_peak > 0.0 + { + // step 5: smooth, decoupled peak detector + // Textbook: + // release_cf * self.normalisation_integrator + (1.0 - release_cf) * limiter_db + // Simplifies to: + // release_cf * self.normalisation_integrator - release_cf * limiter_db + limiter_db + self.normalisation_integrator = f64::max( + limiter_db, + release_cf * self.normalisation_integrator + - release_cf * limiter_db + + limiter_db, + ); + // Textbook: + // attack_cf * self.normalisation_peak + (1.0 - attack_cf) * self.normalisation_integrator + // Simplifies to: + // attack_cf * self.normalisation_peak - attack_cf * self.normalisation_integrator + self.normalisation_integrator + self.normalisation_peak = attack_cf * self.normalisation_peak + - attack_cf * self.normalisation_integrator + + self.normalisation_integrator; + + // step 6: make-up gain applied later (volume attenuation) + // Applying the standard normalisation factor here won't work, + // because there are tracks with peaks as high as 6 dB above + // the default threshold, so that would clip. + + // steps 7-8: conversion into level and multiplication into gain stage + *sample *= db_to_ratio(-self.normalisation_peak); + } + + *sample *= volume; + } } } diff --git a/src/main.rs b/src/main.rs index 8d81834d..59ab0ce6 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1648,12 +1648,12 @@ async fn main() { let player_config = setup.player_config.clone(); let connect_config = setup.connect_config.clone(); - let audio_filter = mixer.get_audio_filter(); + let soft_volume = mixer.get_soft_volume(); let format = setup.format; let backend = setup.backend; let device = setup.device.clone(); let (player, event_channel) = - Player::new(player_config, session.clone(), audio_filter, move || { + Player::new(player_config, session.clone(), soft_volume, move || { (backend)(device, format) }); From c4af90f5febaa99b80e1ae9fbed8f638150728f5 Mon Sep 17 00:00:00 2001 From: Hugo Osvaldo Barrera Date: Tue, 3 May 2022 22:20:14 +0200 Subject: [PATCH 14/39] Avoid crashing when Avahi is not available When librespot is built with Avahi turned on, it will crash if Avahi is later not available at runtime. This change avoids it crashing hard when Avahi is not available; librespot will merely warn of the issue. This affects some distribution packages too, where the maintainer might prefer leaving Avahi support enabled, but many setups don't (or can't) run Avahi. Co-authored-by: Nick Steel --- CHANGELOG.md | 1 + discovery/src/lib.rs | 3 +-- src/main.rs | 17 +++++++++-------- 3 files changed, 11 insertions(+), 10 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index d93b636c..a1d92e1b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -35,6 +35,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - [playback] Adhere to ReplayGain spec when calculating gain normalisation factor. - [playback] `alsa`: Use `--volume-range` overrides for softvol controls - [connect] Don't panic when activating shuffle without previous interaction. +- [main] Fix crash when built with Avahi support but Avahi is locally unavailable. ### Removed - [playback] `alsamixer`: previously deprecated option `mixer-card` has been removed. diff --git a/discovery/src/lib.rs b/discovery/src/lib.rs index b1249a0d..b2e65586 100644 --- a/discovery/src/lib.rs +++ b/discovery/src/lib.rs @@ -111,8 +111,7 @@ impl Builder { None, port, &["VERSION=1.0", "CPath=/"], - ) - .unwrap(); + ).map_err(|e| Error::DnsSdError(io::Error::new(io::ErrorKind::Unsupported, e)))?; } else { let responder = libmdns::Responder::spawn(&tokio::runtime::Handle::current())?; diff --git a/src/main.rs b/src/main.rs index 59ab0ce6..7ec21a5a 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1581,19 +1581,15 @@ async fn main() { if setup.enable_discovery { let device_id = setup.session_config.device_id.clone(); - - discovery = match librespot::discovery::Discovery::builder(device_id) + match librespot::discovery::Discovery::builder(device_id) .name(setup.connect_config.name.clone()) .device_type(setup.connect_config.device_type) .port(setup.zeroconf_port) .launch() { - Ok(d) => Some(d), - Err(e) => { - error!("Discovery Error: {}", e); - exit(1); - } - } + Ok(d) => discovery = Some(d), + Err(err) => warn!("Could not initialise discovery: {}.", err), + }; } if let Some(credentials) = setup.credentials { @@ -1606,6 +1602,11 @@ async fn main() { ) .fuse(), ); + } else if discovery.is_none() { + error!( + "Discovery is unavailable and no credentials provided. Authentication is not possible." + ); + exit(1); } loop { From 4fd7ac24ce637a9668bcd69718aa899d7ca00480 Mon Sep 17 00:00:00 2001 From: Hugo Osvaldo Barrera Date: Thu, 5 May 2022 00:19:29 +0200 Subject: [PATCH 15/39] Bump MSRV to 1.53 See: https://github.com/librespot-org/librespot/pull/997 --- .github/workflows/test.yml | 2 +- CHANGELOG.md | 1 + COMPILING.md | 2 +- 3 files changed, 3 insertions(+), 2 deletions(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 6e447ff9..ab92d984 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -64,7 +64,7 @@ jobs: matrix: os: [ubuntu-latest] toolchain: - - 1.48 # MSRV (Minimum supported rust version) + - 1.53 # MSRV (Minimum supported rust version) - stable - beta experimental: [false] diff --git a/CHANGELOG.md b/CHANGELOG.md index d93b636c..77672a68 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -16,6 +16,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - [playback] `Sink`: `write()` now receives ownership of the packet (breaking). - [playback] `pipe`: create file if it doesn't already exist - [playback] More robust dynamic limiter for very wide dynamic range (breaking) +- [build] The MSRV is now 1.53. ### Added - [cache] Add `disable-credential-cache` flag (breaking). diff --git a/COMPILING.md b/COMPILING.md index 39ae20cc..a76d9a36 100644 --- a/COMPILING.md +++ b/COMPILING.md @@ -7,7 +7,7 @@ In order to compile librespot, you will first need to set up a suitable Rust bui ### Install Rust The easiest, and recommended way to get Rust is to use [rustup](https://rustup.rs). Once that’s installed, Rust's standard tools should be set up and ready to use. -*Note: The current minimum required Rust version at the time of writing is 1.48, you can find the current minimum version specified in the `.github/workflow/test.yml` file.* +*Note: The current minimum required Rust version at the time of writing is 1.53, you can find the current minimum version specified in the `.github/workflow/test.yml` file.* #### Additional Rust tools - `rustfmt` To ensure a consistent codebase, we utilise [`rustfmt`](https://github.com/rust-lang/rustfmt) and [`clippy`](https://github.com/rust-lang/rust-clippy), which are installed by default with `rustup` these days, else they can be installed manually with: From 9de1f38e926de827cf2f05b4d0e42600a568c384 Mon Sep 17 00:00:00 2001 From: "Bernhard M. Wiedemann" Date: Mon, 2 May 2022 13:18:53 +0200 Subject: [PATCH 16/39] Allow to override build_id with SOURCE_DATE_EPOCH in order to make builds reproducible. See https://reproducible-builds.org/ for why this is good and https://reproducible-builds.org/specs/source-date-epoch/ for the definition of this variable. This PR was done while working on reproducible builds for openSUSE. --- core/build.rs | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/core/build.rs b/core/build.rs index 8e61c912..dd16cc0f 100644 --- a/core/build.rs +++ b/core/build.rs @@ -1,5 +1,6 @@ use rand::distributions::Alphanumeric; use rand::Rng; +use std::env; use vergen::{generate_cargo_keys, ConstantsFlags}; fn main() { @@ -7,11 +8,17 @@ fn main() { flags.toggle(ConstantsFlags::REBUILD_ON_HEAD_CHANGE); generate_cargo_keys(ConstantsFlags::all()).expect("Unable to generate the cargo keys!"); - let build_id: String = rand::thread_rng() - .sample_iter(Alphanumeric) - .take(8) - .map(char::from) - .collect(); + let build_id: String; + match env::var("SOURCE_DATE_EPOCH") { + Ok(val) => build_id = val, + Err(_) => { + build_id = rand::thread_rng() + .sample_iter(Alphanumeric) + .take(8) + .map(char::from) + .collect() + } + } println!("cargo:rustc-env=LIBRESPOT_BUILD_ID={}", build_id); } From 6c2491b9a3d170dd3cb8a74a6b3cd82a6d9e13b1 Mon Sep 17 00:00:00 2001 From: Louis Seubert Date: Fri, 20 May 2022 12:53:44 +0200 Subject: [PATCH 17/39] adding callback for reusable credentials (#983) This allows more control over how the credentials are saved to the cache --- CHANGELOG.md | 2 ++ core/src/session.rs | 11 +++++++---- core/tests/connect.rs | 1 + examples/get_token.rs | 2 +- examples/play.rs | 2 +- examples/playlist_tracks.rs | 2 +- src/main.rs | 5 ++++- 7 files changed, 17 insertions(+), 8 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 2b205977..1e37fae3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -16,6 +16,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - [playback] `Sink`: `write()` now receives ownership of the packet (breaking). - [playback] `pipe`: create file if it doesn't already exist - [playback] More robust dynamic limiter for very wide dynamic range (breaking) +- [core] `Session`: `connect()` now returns the long-term credentials. +- [core] `Session`: `connect()` now accespt a flag if the credentails should be stored via the cache. - [build] The MSRV is now 1.53. ### Added diff --git a/core/src/session.rs b/core/src/session.rs index 6c4abc54..6c8bf93f 100644 --- a/core/src/session.rs +++ b/core/src/session.rs @@ -66,7 +66,8 @@ impl Session { config: SessionConfig, credentials: Credentials, cache: Option, - ) -> Result { + store_credentials: bool, + ) -> Result<(Session, Credentials), SessionError> { let ap = apresolve(config.proxy.as_ref(), config.ap_port).await; info!("Connecting to AP \"{}\"", ap); @@ -76,18 +77,20 @@ impl Session { connection::authenticate(&mut conn, credentials, &config.device_id).await?; info!("Authenticated as \"{}\" !", reusable_credentials.username); if let Some(cache) = &cache { - cache.save_credentials(&reusable_credentials); + if store_credentials { + cache.save_credentials(&reusable_credentials); + } } let session = Session::create( conn, config, cache, - reusable_credentials.username, + reusable_credentials.username.clone(), tokio::runtime::Handle::current(), ); - Ok(session) + Ok((session, reusable_credentials)) } fn create( diff --git a/core/tests/connect.rs b/core/tests/connect.rs index 8b95e437..e6aa7c66 100644 --- a/core/tests/connect.rs +++ b/core/tests/connect.rs @@ -13,6 +13,7 @@ async fn test_connection() { SessionConfig::default(), Credentials::with_password("test", "test"), None, + false, ) .await; diff --git a/examples/get_token.rs b/examples/get_token.rs index 636155e0..4d9e1f1c 100644 --- a/examples/get_token.rs +++ b/examples/get_token.rs @@ -20,7 +20,7 @@ async fn main() { println!("Connecting.."); let credentials = Credentials::with_password(&args[1], &args[2]); - let session = Session::connect(session_config, credentials, None) + let (session, _) = Session::connect(session_config, credentials, None, false) .await .unwrap(); diff --git a/examples/play.rs b/examples/play.rs index 6156cb7b..a91b6851 100644 --- a/examples/play.rs +++ b/examples/play.rs @@ -27,7 +27,7 @@ async fn main() { let backend = audio_backend::find(None).unwrap(); println!("Connecting .."); - let session = Session::connect(session_config, credentials, None) + let (session, _) = Session::connect(session_config, credentials, None, false) .await .unwrap(); diff --git a/examples/playlist_tracks.rs b/examples/playlist_tracks.rs index 0bf17ee7..8dbe1d5f 100644 --- a/examples/playlist_tracks.rs +++ b/examples/playlist_tracks.rs @@ -27,7 +27,7 @@ async fn main() { process::exit(1); }); - let session = Session::connect(session_config, credentials, None) + let (session, _) = Session::connect(session_config, credentials, None, false) .await .unwrap(); diff --git a/src/main.rs b/src/main.rs index 7ec21a5a..55df381d 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1599,6 +1599,7 @@ async fn main() { setup.session_config.clone(), credentials, setup.cache.clone(), + true, ) .fuse(), ); @@ -1634,6 +1635,7 @@ async fn main() { setup.session_config.clone(), credentials, setup.cache.clone(), + true, ).fuse()); }, None => { @@ -1643,7 +1645,7 @@ async fn main() { } }, session = &mut connecting, if !connecting.is_terminated() => match session { - Ok(session) => { + Ok((session,_)) => { let mixer_config = setup.mixer_config.clone(); let mixer = (setup.mixer)(mixer_config); let player_config = setup.player_config.clone(); @@ -1711,6 +1713,7 @@ async fn main() { setup.session_config.clone(), credentials, setup.cache.clone(), + true ).fuse()); }, _ => { From 3d298768b3d1933443c115db1d2bdf836418c0fb Mon Sep 17 00:00:00 2001 From: Sean McNamara Date: Sat, 21 May 2022 14:55:55 -0400 Subject: [PATCH 18/39] Backport #964 GStreamer backend cleanup (#979) --- CHANGELOG.md | 3 +- Cargo.lock | 342 ++++++++++++++++++++---- playback/Cargo.toml | 10 +- playback/src/audio_backend/gstreamer.rs | 238 ++++++++++------- 4 files changed, 445 insertions(+), 148 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 1e37fae3..13e7594d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -18,7 +18,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - [playback] More robust dynamic limiter for very wide dynamic range (breaking) - [core] `Session`: `connect()` now returns the long-term credentials. - [core] `Session`: `connect()` now accespt a flag if the credentails should be stored via the cache. -- [build] The MSRV is now 1.53. +- [chore] The MSRV is now 1.53. +- [playback] `gstreamer`: create own context, set correct states and use sync handler ### Added - [cache] Add `disable-credential-cache` flag (breaking). diff --git a/Cargo.lock b/Cargo.lock index 07f1e23d..10738efd 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2,6 +2,21 @@ # It is not intended for manual editing. version = 3 +[[package]] +name = "addr2line" +version = "0.17.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9ecd88a8c8378ca913a680cd98f0f13ac67383d35993f86c90a70e3f137816b" +dependencies = [ + "gimli", +] + +[[package]] +name = "adler" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" + [[package]] name = "aes" version = "0.6.0" @@ -82,6 +97,12 @@ version = "1.0.44" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "61604a8f862e1d5c3229fdd78f8b02c68dcf73a4c4b05fd636d12240aaa242c1" +[[package]] +name = "array-init" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6945cc5422176fc5e602e590c2878d2c2acd9a4fe20a4baa7c28022521698ec6" + [[package]] name = "async-trait" version = "0.1.51" @@ -110,6 +131,21 @@ version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cdb031dd78e28731d87d56cc8ffef4a8f36ca26c38fe2de700543e627f8a464a" +[[package]] +name = "backtrace" +version = "0.3.64" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5e121dee8023ce33ab248d9ce1493df03c3b38a659b240096fcbd7048ff9c31f" +dependencies = [ + "addr2line", + "cc", + "cfg-if 1.0.0", + "libc", + "miniz_oxide", + "object", + "rustc-demangle", +] + [[package]] name = "base64" version = "0.13.0" @@ -192,6 +228,15 @@ dependencies = [ "nom", ] +[[package]] +name = "cfg-expr" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b412e83326147c2bb881f8b40edfbf9905b9b8abaebd0e47ca190ba62fda8f0e" +dependencies = [ + "smallvec", +] + [[package]] name = "cfg-if" version = "0.1.10" @@ -421,6 +466,12 @@ dependencies = [ "termcolor", ] +[[package]] +name = "fixedbitset" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "37ab347416e802de484e4d03c7316c48f1ecb56574dfd4a46a80f173ce1de04d" + [[package]] name = "fnv" version = "1.0.7" @@ -561,6 +612,12 @@ dependencies = [ "wasi", ] +[[package]] +name = "gimli" +version = "0.26.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "78cc372d058dcf6d5ecd98510e7fbc9e5aec4d21de70f65fea8fecebcd881bd4" + [[package]] name = "glib" version = "0.10.3" @@ -573,13 +630,32 @@ dependencies = [ "futures-executor", "futures-task", "futures-util", - "glib-macros", - "glib-sys", - "gobject-sys", + "glib-macros 0.10.1", + "glib-sys 0.10.1", + "gobject-sys 0.10.0", "libc", "once_cell", ] +[[package]] +name = "glib" +version = "0.14.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7c515f1e62bf151ef6635f528d05b02c11506de986e43b34a5c920ef0b3796a4" +dependencies = [ + "bitflags", + "futures-channel", + "futures-core", + "futures-executor", + "futures-task", + "glib-macros 0.14.1", + "glib-sys 0.14.0", + "gobject-sys 0.14.0", + "libc", + "once_cell", + "smallvec", +] + [[package]] name = "glib-macros" version = "0.10.1" @@ -588,7 +664,7 @@ checksum = "41486a26d1366a8032b160b59065a59fb528530a46a49f627e7048fb8c064039" dependencies = [ "anyhow", "heck", - "itertools", + "itertools 0.9.0", "proc-macro-crate 0.1.5", "proc-macro-error", "proc-macro2", @@ -596,6 +672,21 @@ dependencies = [ "syn", ] +[[package]] +name = "glib-macros" +version = "0.14.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2aad66361f66796bfc73f530c51ef123970eb895ffba991a234fcf7bea89e518" +dependencies = [ + "anyhow", + "heck", + "proc-macro-crate 1.1.0", + "proc-macro-error", + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "glib-sys" version = "0.10.1" @@ -603,7 +694,17 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c7e9b997a66e9a23d073f2b1abb4dbfc3925e0b8952f67efd8d9b6e168e4cdc1" dependencies = [ "libc", - "system-deps", + "system-deps 1.3.2", +] + +[[package]] +name = "glib-sys" +version = "0.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1c1d60554a212445e2a858e42a0e48cece1bd57b311a19a9468f70376cf554ae" +dependencies = [ + "libc", + "system-deps 3.2.0", ] [[package]] @@ -618,28 +719,38 @@ version = "0.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "952133b60c318a62bf82ee75b93acc7e84028a093e06b9e27981c2b6fe68218c" dependencies = [ - "glib-sys", + "glib-sys 0.10.1", "libc", - "system-deps", + "system-deps 1.3.2", +] + +[[package]] +name = "gobject-sys" +version = "0.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aa92cae29759dae34ab5921d73fff5ad54b3d794ab842c117e36cafc7994c3f5" +dependencies = [ + "glib-sys 0.14.0", + "libc", + "system-deps 3.2.0", ] [[package]] name = "gstreamer" -version = "0.16.7" +version = "0.17.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9ff5d0f7ff308ae37e6eb47b6ded17785bdea06e438a708cd09e0288c1862f33" +checksum = "c6a255f142048ba2c4a4dce39106db1965abe355d23f4b5335edea43a553faa4" dependencies = [ "bitflags", "cfg-if 1.0.0", "futures-channel", "futures-core", "futures-util", - "glib", - "glib-sys", - "gobject-sys", + "glib 0.14.8", "gstreamer-sys", "libc", "muldiv", + "num-integer", "num-rational", "once_cell", "paste", @@ -649,76 +760,102 @@ dependencies = [ [[package]] name = "gstreamer-app" -version = "0.16.5" +version = "0.17.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cc80888271338c3ede875d8cafc452eb207476ff5539dcbe0018a8f5b827af0e" +checksum = "f73b8d33b1bbe9f22d0cf56661a1d2a2c9a0e099ea10e5f1f347be5038f5c043" dependencies = [ "bitflags", "futures-core", "futures-sink", - "glib", - "glib-sys", - "gobject-sys", + "glib 0.14.8", "gstreamer", "gstreamer-app-sys", "gstreamer-base", - "gstreamer-sys", "libc", "once_cell", ] [[package]] name = "gstreamer-app-sys" -version = "0.9.1" +version = "0.17.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "813f64275c9e7b33b828b9efcf9dfa64b95996766d4de996e84363ac65b87e3d" +checksum = "41865cfb8a5ddfa1161734a0d068dcd4689da852be0910b40484206408cfeafa" dependencies = [ - "glib-sys", + "glib-sys 0.14.0", "gstreamer-base-sys", "gstreamer-sys", "libc", - "system-deps", + "system-deps 3.2.0", +] + +[[package]] +name = "gstreamer-audio" +version = "0.17.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "420b6bcb1759231f01172751da094e7afa5cd9edf40bee7475f5bc86df433c57" +dependencies = [ + "array-init", + "bitflags", + "cfg-if 1.0.0", + "glib 0.14.8", + "gstreamer", + "gstreamer-audio-sys", + "gstreamer-base", + "libc", + "once_cell", +] + +[[package]] +name = "gstreamer-audio-sys" +version = "0.17.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d066ddfd05f63836f35ac4a5830d5bb2f7f3d6c33c870e9b15c667d20f65d7f6" +dependencies = [ + "glib-sys 0.14.0", + "gobject-sys 0.14.0", + "gstreamer-base-sys", + "gstreamer-sys", + "libc", + "system-deps 3.2.0", ] [[package]] name = "gstreamer-base" -version = "0.16.5" +version = "0.17.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bafd01c56f59cb10f4b5a10f97bb4bdf8c2b2784ae5b04da7e2d400cf6e6afcf" +checksum = "2c0c1d8c62eb5d08fb80173609f2eea71d385393363146e4e78107facbd67715" dependencies = [ "bitflags", - "glib", - "glib-sys", - "gobject-sys", + "cfg-if 1.0.0", + "glib 0.14.8", "gstreamer", "gstreamer-base-sys", - "gstreamer-sys", "libc", ] [[package]] name = "gstreamer-base-sys" -version = "0.9.1" +version = "0.17.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a4b7b6dc2d6e160a1ae28612f602bd500b3fa474ce90bf6bb2f08072682beef5" +checksum = "28169a7b58edb93ad8ac766f0fa12dcd36a2af4257a97ee10194c7103baf3e27" dependencies = [ - "glib-sys", - "gobject-sys", + "glib-sys 0.14.0", + "gobject-sys 0.14.0", "gstreamer-sys", "libc", - "system-deps", + "system-deps 3.2.0", ] [[package]] name = "gstreamer-sys" -version = "0.9.1" +version = "0.17.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fc1f154082d01af5718c5f8a8eb4f565a4ea5586ad8833a8fc2c2aa6844b601d" +checksum = "a81704feeb3e8599913bdd1e738455c2991a01ff4a1780cb62200993e454cc3e" dependencies = [ - "glib-sys", - "gobject-sys", + "glib-sys 0.14.0", + "gobject-sys 0.14.0", "libc", - "system-deps", + "system-deps 3.2.0", ] [[package]] @@ -941,6 +1078,15 @@ dependencies = [ "either", ] +[[package]] +name = "itertools" +version = "0.10.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a9a9d19fa1e79b6215ff29b9d6880b706147f16e9b1dbb1e4e5947b5b02bc5e3" +dependencies = [ + "either", +] + [[package]] name = "itoa" version = "0.4.8" @@ -1273,9 +1419,10 @@ dependencies = [ "cpal", "futures-executor", "futures-util", - "glib", + "glib 0.10.3", "gstreamer", "gstreamer-app", + "gstreamer-audio", "jack", "lewton", "libpulse-binding", @@ -1285,6 +1432,7 @@ dependencies = [ "librespot-metadata", "log", "ogg", + "parking_lot", "portaudio-rs", "rand", "rand_distr", @@ -1356,6 +1504,16 @@ version = "0.3.16" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2a60c7ce501c71e03a9c9c0d35b861413ae925bd979cc7a4e30d060069aaac8d" +[[package]] +name = "miniz_oxide" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a92518e98c078586bc6c934028adcca4c92a53d6a958196de835170a01d84e4b" +dependencies = [ + "adler", + "autocfg", +] + [[package]] name = "mio" version = "0.7.14" @@ -1380,9 +1538,9 @@ dependencies = [ [[package]] name = "muldiv" -version = "0.2.1" +version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0419348c027fa7be448d2ae7ea0e4e04c2334c31dc4e74ab29f00a2a7ca69204" +checksum = "b5136edda114182728ccdedb9f5eda882781f35fa6e80cc360af12a8932507f3" [[package]] name = "multimap" @@ -1531,9 +1689,9 @@ dependencies = [ [[package]] name = "num-rational" -version = "0.3.2" +version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "12ac428b1cb17fce6f731001d307d351ec70a6d202fc2e60f7d4c5e42d8f4f07" +checksum = "d41702bd167c2df5520b384281bc111a4b5efcf7fbc4c9c222c815b07e0a6a6a" dependencies = [ "autocfg", "num-integer", @@ -1582,6 +1740,15 @@ dependencies = [ "syn", ] +[[package]] +name = "object" +version = "0.27.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "67ac1d3f9a1d3616fd9a60c8d74296f22406a238b6a72f5cc1e6f314df4ffbf9" +dependencies = [ + "memchr", +] + [[package]] name = "oboe" version = "0.4.4" @@ -1643,11 +1810,14 @@ version = "0.8.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d76e8e1493bcac0d2766c42737f34458f1c8c50c0d23bcb24ea953affb273216" dependencies = [ + "backtrace", "cfg-if 1.0.0", "instant", "libc", + "petgraph", "redox_syscall", "smallvec", + "thread-id", "winapi", ] @@ -1679,6 +1849,16 @@ version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d4fd5641d01c8f18a23da7b6fe29298ff4b55afcccdf78973b24cf3175fee32e" +[[package]] +name = "petgraph" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "467d164a6de56270bd7c4d070df81d07beace25012d5103ced4e9ff08d6afdb7" +dependencies = [ + "fixedbitset", + "indexmap", +] + [[package]] name = "pin-project-lite" version = "0.2.7" @@ -1942,6 +2122,12 @@ dependencies = [ "winapi", ] +[[package]] +name = "rustc-demangle" +version = "0.1.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7ef03e0a2b150c7a90d01faf6254c9c48a41e95fb2a8c2ac1c6f0d2b9aefc342" + [[package]] name = "rustc-hash" version = "1.1.0" @@ -1998,7 +2184,7 @@ checksum = "41a29aa21f175b5a41a6e26da572d5e5d1ee5660d35f9f9d0913e8a802098f74" dependencies = [ "cfg-if 0.1.10", "libc", - "version-compare", + "version-compare 0.0.10", ] [[package]] @@ -2102,9 +2288,9 @@ checksum = "9def91fd1e018fe007022791f865d0ccc9b3a0d5001e01aabb8b40e46000afb5" [[package]] name = "smallvec" -version = "1.7.0" +version = "1.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1ecab6c735a6bb4139c0caafd0cc3635748bbb3acf4550e8138122099251f309" +checksum = "f2dd574626839106c320a323308629dcb1acfc96e32a8cba364ddc61ac23ee83" [[package]] name = "socket2" @@ -2134,6 +2320,12 @@ version = "0.18.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "57bd81eb48f4c437cadc685403cad539345bf703d78e63707418431cecd4522b" +[[package]] +name = "strum" +version = "0.21.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aaf86bbcfd1fa9670b7a129f64fc0c9fcbbfe4f1bc4210e9e98fe71ffc12cde2" + [[package]] name = "strum_macros" version = "0.18.0" @@ -2146,6 +2338,18 @@ dependencies = [ "syn", ] +[[package]] +name = "strum_macros" +version = "0.21.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d06aaeeee809dbc59eb4556183dd927df67db1540de5be8d3ec0b6636358a5ec" +dependencies = [ + "heck", + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "subtle" version = "2.4.1" @@ -2183,11 +2387,29 @@ checksum = "0f3ecc17269a19353b3558b313bba738b25d82993e30d62a18406a24aba4649b" dependencies = [ "heck", "pkg-config", - "strum", - "strum_macros", + "strum 0.18.0", + "strum_macros 0.18.0", "thiserror", "toml", - "version-compare", + "version-compare 0.0.10", +] + +[[package]] +name = "system-deps" +version = "3.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "480c269f870722b3b08d2f13053ce0c2ab722839f472863c3e2d61ff3a1c2fa6" +dependencies = [ + "anyhow", + "cfg-expr", + "heck", + "itertools 0.10.3", + "pkg-config", + "strum 0.21.0", + "strum_macros 0.21.1", + "thiserror", + "toml", + "version-compare 0.0.11", ] [[package]] @@ -2233,6 +2455,17 @@ dependencies = [ "syn", ] +[[package]] +name = "thread-id" +version = "4.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5fdfe0627923f7411a43ec9ec9c39c3a9b4151be313e0922042581fb6c9b717f" +dependencies = [ + "libc", + "redox_syscall", + "winapi", +] + [[package]] name = "time" version = "0.1.43" @@ -2271,6 +2504,7 @@ dependencies = [ "mio", "num_cpus", "once_cell", + "parking_lot", "pin-project-lite", "signal-hook-registry", "tokio-macros", @@ -2377,9 +2611,9 @@ dependencies = [ [[package]] name = "unicode-segmentation" -version = "1.8.0" +version = "1.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8895849a949e7845e06bd6dc1aa51731a103c42707010a5b591c0038fb73385b" +checksum = "7e8820f5d777f6224dc4be3632222971ac30164d4a258d595640799554ebfd99" [[package]] name = "unicode-width" @@ -2431,6 +2665,12 @@ version = "0.0.10" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d63556a25bae6ea31b52e640d7c41d1ab27faba4ccb600013837a3d0b3994ca1" +[[package]] +name = "version-compare" +version = "0.0.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1c18c859eead79d8b95d09e4678566e8d70105c4e7b251f707a03df32442661b" + [[package]] name = "version_check" version = "0.9.3" diff --git a/playback/Cargo.toml b/playback/Cargo.toml index 4e8d19c6..7126e3da 100644 --- a/playback/Cargo.toml +++ b/playback/Cargo.toml @@ -21,9 +21,10 @@ version = "0.3.1" futures-executor = "0.3" futures-util = { version = "0.3", default_features = false, features = ["alloc"] } log = "0.4" +parking_lot = { version = "0.11", features = ["deadlock_detection"] } byteorder = "1.4" shell-words = "1.0.0" -tokio = { version = "1", features = ["sync"] } +tokio = { version = "1", features = ["sync", "parking_lot"] } zerocopy = { version = "0.3" } thiserror = { version = "1" } @@ -34,8 +35,9 @@ libpulse-binding = { version = "2", optional = true, default-features = f libpulse-simple-binding = { version = "2", optional = true, default-features = false } jack = { version = "0.7", optional = true } sdl2 = { version = "0.34.3", optional = true } -gstreamer = { version = "0.16", optional = true } -gstreamer-app = { version = "0.16", optional = true } +gstreamer = { version = "0.17", optional = true } +gstreamer-app = { version = "0.17", optional = true } +gstreamer-audio = { version = "0.17", optional = true } glib = { version = "0.10", optional = true } # Rodio dependencies @@ -58,4 +60,4 @@ jackaudio-backend = ["jack"] rodio-backend = ["rodio", "cpal"] rodiojack-backend = ["rodio", "cpal/jack"] sdl-backend = ["sdl2"] -gstreamer-backend = ["gstreamer", "gstreamer-app", "glib"] +gstreamer-backend = ["gstreamer", "gstreamer-app", "gstreamer-audio", "glib"] diff --git a/playback/src/audio_backend/gstreamer.rs b/playback/src/audio_backend/gstreamer.rs index 8b957577..0a98846e 100644 --- a/playback/src/audio_backend/gstreamer.rs +++ b/playback/src/audio_backend/gstreamer.rs @@ -1,23 +1,28 @@ -use super::{Open, Sink, SinkAsBytes, SinkResult}; -use crate::config::AudioFormat; -use crate::convert::Converter; -use crate::decoder::AudioPacket; -use crate::{NUM_CHANNELS, SAMPLE_RATE}; +use gstreamer::{ + event::{FlushStart, FlushStop}, + prelude::*, + State, +}; use gstreamer as gst; use gstreamer_app as gst_app; +use gstreamer_audio as gst_audio; -use gst::prelude::*; -use zerocopy::AsBytes; +use parking_lot::Mutex; +use std::sync::Arc; -use std::sync::mpsc::{sync_channel, SyncSender}; -use std::thread; +use super::{Open, Sink, SinkAsBytes, SinkError, SinkResult}; + +use crate::{ + config::AudioFormat, convert::Converter, decoder::AudioPacket, NUM_CHANNELS, SAMPLE_RATE, +}; -#[allow(dead_code)] pub struct GstreamerSink { - tx: SyncSender>, + appsrc: gst_app::AppSrc, + bufferpool: gst::BufferPool, pipeline: gst::Pipeline, format: AudioFormat, + async_error: Arc>>, } impl Open for GstreamerSink { @@ -25,117 +30,166 @@ impl Open for GstreamerSink { info!("Using GStreamer sink with format: {:?}", format); gst::init().expect("failed to init GStreamer!"); - // GStreamer calls S24 and S24_3 different from the rest of the world let gst_format = match format { - AudioFormat::S24 => "S24_32".to_string(), - AudioFormat::S24_3 => "S24".to_string(), - _ => format!("{:?}", format), + AudioFormat::F64 => gst_audio::AUDIO_FORMAT_F64, + AudioFormat::F32 => gst_audio::AUDIO_FORMAT_F32, + AudioFormat::S32 => gst_audio::AUDIO_FORMAT_S32, + AudioFormat::S24 => gst_audio::AUDIO_FORMAT_S2432, + AudioFormat::S24_3 => gst_audio::AUDIO_FORMAT_S24, + AudioFormat::S16 => gst_audio::AUDIO_FORMAT_S16, }; + + let gst_info = gst_audio::AudioInfo::builder(gst_format, SAMPLE_RATE, NUM_CHANNELS as u32) + .build() + .expect("Failed to create GStreamer audio format"); + let gst_caps = gst_info.to_caps().expect("Failed to create GStreamer caps"); + let sample_size = format.size(); - let gst_bytes = 2048 * sample_size; + let gst_bytes = NUM_CHANNELS as usize * 2048 * sample_size; - #[cfg(target_endian = "little")] - const ENDIANNESS: &str = "LE"; - #[cfg(target_endian = "big")] - const ENDIANNESS: &str = "BE"; - - let pipeline_str_preamble = format!( - "appsrc caps=\"audio/x-raw,format={}{},layout=interleaved,channels={},rate={}\" block=true max-bytes={} name=appsrc0 ", - gst_format, ENDIANNESS, NUM_CHANNELS, SAMPLE_RATE, gst_bytes - ); - // no need to dither twice; use librespot dithering instead - let pipeline_str_rest = r#" ! audioconvert dithering=none ! autoaudiosink"#; - let pipeline_str: String = match device { - Some(x) => format!("{}{}", pipeline_str_preamble, x), - None => format!("{}{}", pipeline_str_preamble, pipeline_str_rest), - }; - info!("Pipeline: {}", pipeline_str); - - gst::init().unwrap(); - let pipelinee = gst::parse_launch(&*pipeline_str).expect("Couldn't launch pipeline; likely a GStreamer issue or an error in the pipeline string you specified in the 'device' argument to librespot."); - let pipeline = pipelinee - .dynamic_cast::() - .expect("couldn't cast pipeline element at runtime!"); - let bus = pipeline.get_bus().expect("couldn't get bus from pipeline"); - let mainloop = glib::MainLoop::new(None, false); - let appsrce: gst::Element = pipeline - .get_by_name("appsrc0") - .expect("couldn't get appsrc from pipeline"); - let appsrc: gst_app::AppSrc = appsrce - .dynamic_cast::() + let pipeline = gst::Pipeline::new(None); + let appsrc = gst::ElementFactory::make("appsrc", None) + .expect("Failed to create GStreamer appsrc element") + .downcast::() .expect("couldn't cast AppSrc element at runtime!"); + appsrc.set_caps(Some(&gst_caps)); + appsrc.set_max_bytes(gst_bytes as u64); + appsrc.set_block(true); + + let sink = match device { + None => { + // no need to dither twice; use librespot dithering instead + gst::parse_bin_from_description( + "audioconvert dithering=none ! audioresample ! autoaudiosink", + true, + ) + .expect("Failed to create default GStreamer sink") + } + Some(ref x) => gst::parse_bin_from_description(x, true) + .expect("Failed to create custom GStreamer sink"), + }; + pipeline + .add(&appsrc) + .expect("Failed to add GStreamer appsrc to pipeline"); + pipeline + .add(&sink) + .expect("Failed to add GStreamer sink to pipeline"); + appsrc + .link(&sink) + .expect("Failed to link GStreamer source to sink"); + + let bus = pipeline.bus().expect("couldn't get bus from pipeline"); + let bufferpool = gst::BufferPool::new(); - let appsrc_caps = appsrc.get_caps().expect("couldn't get appsrc caps"); - let mut conf = bufferpool.get_config(); - conf.set_params(Some(&appsrc_caps), 4096 * sample_size as u32, 0, 0); + + let mut conf = bufferpool.config(); + conf.set_params(Some(&gst_caps), gst_bytes as u32, 0, 0); bufferpool .set_config(conf) .expect("couldn't configure the buffer pool"); - bufferpool - .set_active(true) - .expect("couldn't activate buffer pool"); - let (tx, rx) = sync_channel::>(64 * sample_size); - thread::spawn(move || { - for data in rx { - let buffer = bufferpool.acquire_buffer(None); - if let Ok(mut buffer) = buffer { - let mutbuf = buffer.make_mut(); - mutbuf.set_size(data.len()); - mutbuf - .copy_from_slice(0, data.as_bytes()) - .expect("Failed to copy from slice"); - let _eat = appsrc.push_buffer(buffer); + let async_error = Arc::new(Mutex::new(None)); + let async_error_clone = async_error.clone(); + + bus.set_sync_handler(move |_bus, msg| { + match msg.view() { + gst::MessageView::Eos(_) => { + println!("gst signaled end of stream"); + + let mut async_error_storage = async_error_clone.lock(); + *async_error_storage = Some(String::from("gst signaled end of stream")); } + gst::MessageView::Error(err) => { + println!( + "Error from {:?}: {} ({:?})", + err.src().map(|s| s.path_string()), + err.error(), + err.debug() + ); + + let mut async_error_storage = async_error_clone.lock(); + *async_error_storage = Some(format!( + "Error from {:?}: {} ({:?})", + err.src().map(|s| s.path_string()), + err.error(), + err.debug() + )); + } + _ => (), } - }); - thread::spawn(move || { - let thread_mainloop = mainloop; - let watch_mainloop = thread_mainloop.clone(); - bus.add_watch(move |_, msg| { - match msg.view() { - gst::MessageView::Eos(..) => watch_mainloop.quit(), - gst::MessageView::Error(err) => { - println!( - "Error from {:?}: {} ({:?})", - err.get_src().map(|s| s.get_path_string()), - err.get_error(), - err.get_debug() - ); - watch_mainloop.quit(); - } - _ => (), - }; - - glib::Continue(true) - }) - .expect("failed to add bus watch"); - thread_mainloop.run(); + gst::BusSyncReply::Drop }); pipeline - .set_state(gst::State::Playing) - .expect("unable to set the pipeline to the `Playing` state"); + .set_state(State::Ready) + .expect("unable to set the pipeline to the `Ready` state"); Self { - tx, + appsrc, + bufferpool, pipeline, format, + async_error, } } } impl Sink for GstreamerSink { + fn start(&mut self) -> SinkResult<()> { + *self.async_error.lock() = None; + self.appsrc.send_event(FlushStop::new(true)); + self.bufferpool + .set_active(true) + .map_err(|e| SinkError::OnWrite(e.to_string()))?; + self.pipeline + .set_state(State::Playing) + .map_err(|e| SinkError::OnWrite(e.to_string()))?; + Ok(()) + } + + fn stop(&mut self) -> SinkResult<()> { + *self.async_error.lock() = None; + self.appsrc.send_event(FlushStart::new()); + self.pipeline + .set_state(State::Paused) + .map_err(|e| SinkError::OnWrite(e.to_string()))?; + self.bufferpool + .set_active(false) + .map_err(|e| SinkError::OnWrite(e.to_string()))?; + Ok(()) + } + sink_as_bytes!(); } +impl Drop for GstreamerSink { + fn drop(&mut self) { + let _ = self.pipeline.set_state(State::Null); + } +} + impl SinkAsBytes for GstreamerSink { fn write_bytes(&mut self, data: &[u8]) -> SinkResult<()> { - // Copy expensively (in to_vec()) to avoid thread synchronization - self.tx - .send(data.to_vec()) - .expect("tx send failed in write function"); + if let Some(async_error) = &*self.async_error.lock() { + return Err(SinkError::OnWrite(async_error.to_string())); + } + + let mut buffer = self + .bufferpool + .acquire_buffer(None) + .map_err(|e| SinkError::OnWrite(e.to_string()))?; + + let mutbuf = buffer.make_mut(); + mutbuf.set_size(data.len()); + mutbuf + .copy_from_slice(0, data) + .map_err(|e| SinkError::OnWrite(e.to_string()))?; + + self.appsrc + .push_buffer(buffer) + .map_err(|e| SinkError::OnWrite(e.to_string()))?; + Ok(()) } } From cf25c2aa36e19ffe05927654c7b45a8fb9e01521 Mon Sep 17 00:00:00 2001 From: Roderick van Domburg Date: Sat, 21 May 2022 21:06:29 +0200 Subject: [PATCH 19/39] Fix CI on ARM --- .github/workflows/test.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index ab92d984..db6388eb 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -196,4 +196,4 @@ jobs: - name: Install cross run: cargo install cross || true - name: Build - run: cross build --locked --target ${{ matrix.target }} --no-default-features + run: cross build --target ${{ matrix.target }} --no-default-features From 2a3e248bba3a490ca27d7e1741e3f3a86827690a Mon Sep 17 00:00:00 2001 From: Roderick van Domburg Date: Sat, 21 May 2022 21:36:56 +0200 Subject: [PATCH 20/39] Fix clippy lints --- core/build.rs | 19 +++++++--------- discovery/Cargo.toml | 1 - discovery/src/lib.rs | 40 ++++++++++++++------------------- playback/src/mixer/alsamixer.rs | 2 +- playback/src/mixer/mappings.rs | 4 ++-- playback/src/mixer/softmixer.rs | 2 +- src/main.rs | 2 +- 7 files changed, 30 insertions(+), 40 deletions(-) diff --git a/core/build.rs b/core/build.rs index dd16cc0f..e4aa1187 100644 --- a/core/build.rs +++ b/core/build.rs @@ -8,17 +8,14 @@ fn main() { flags.toggle(ConstantsFlags::REBUILD_ON_HEAD_CHANGE); generate_cargo_keys(ConstantsFlags::all()).expect("Unable to generate the cargo keys!"); - let build_id: String; - match env::var("SOURCE_DATE_EPOCH") { - Ok(val) => build_id = val, - Err(_) => { - build_id = rand::thread_rng() - .sample_iter(Alphanumeric) - .take(8) - .map(char::from) - .collect() - } - } + let build_id = match env::var("SOURCE_DATE_EPOCH") { + Ok(val) => val, + Err(_) => rand::thread_rng() + .sample_iter(Alphanumeric) + .take(8) + .map(char::from) + .collect(), + }; println!("cargo:rustc-env=LIBRESPOT_BUILD_ID={}", build_id); } diff --git a/discovery/Cargo.toml b/discovery/Cargo.toml index 4dccdc1e..aebaf4df 100644 --- a/discovery/Cargo.toml +++ b/discovery/Cargo.toml @@ -10,7 +10,6 @@ edition = "2018" [dependencies] aes-ctr = "0.6" base64 = "0.13" -cfg-if = "1.0" form_urlencoded = "1.0" futures-core = "0.3" hmac = "0.11" diff --git a/discovery/src/lib.rs b/discovery/src/lib.rs index b2e65586..ca403b16 100644 --- a/discovery/src/lib.rs +++ b/discovery/src/lib.rs @@ -16,7 +16,6 @@ use std::io; use std::pin::Pin; use std::task::{Context, Poll}; -use cfg_if::cfg_if; use futures_core::Stream; use librespot_core as core; use thiserror::Error; @@ -100,29 +99,24 @@ impl Builder { let name = self.server_config.name.clone().into_owned(); let server = DiscoveryServer::new(self.server_config, &mut port)?; - let svc; + #[cfg(feature = "with-dns-sd")] + let svc = dns_sd::DNSService::register( + Some(name.as_ref()), + "_spotify-connect._tcp", + None, + None, + port, + &["VERSION=1.0", "CPath=/"], + ) + .map_err(|e| Error::DnsSdError(io::Error::new(io::ErrorKind::Unsupported, e)))?; - cfg_if! { - if #[cfg(feature = "with-dns-sd")] { - svc = dns_sd::DNSService::register( - Some(name.as_ref()), - "_spotify-connect._tcp", - None, - None, - port, - &["VERSION=1.0", "CPath=/"], - ).map_err(|e| Error::DnsSdError(io::Error::new(io::ErrorKind::Unsupported, e)))?; - - } else { - let responder = libmdns::Responder::spawn(&tokio::runtime::Handle::current())?; - svc = responder.register( - "_spotify-connect._tcp".to_owned(), - name, - port, - &["VERSION=1.0", "CPath=/"], - ) - } - }; + #[cfg(not(feature = "with-dns-sd"))] + let svc = libmdns::Responder::spawn(&tokio::runtime::Handle::current())?.register( + "_spotify-connect._tcp".to_owned(), + name, + port, + &["VERSION=1.0", "CPath=/"], + ); Ok(Discovery { server, _svc: svc }) } diff --git a/playback/src/mixer/alsamixer.rs b/playback/src/mixer/alsamixer.rs index c04e6ee8..f03af958 100644 --- a/playback/src/mixer/alsamixer.rs +++ b/playback/src/mixer/alsamixer.rs @@ -191,7 +191,7 @@ impl Mixer for AlsaMixer { mapped_volume = LogMapping::linear_to_mapped(mapped_volume, self.db_range); } - self.config.volume_ctrl.from_mapped(mapped_volume) + self.config.volume_ctrl.to_unmapped(mapped_volume) } fn set_volume(&self, volume: u16) { diff --git a/playback/src/mixer/mappings.rs b/playback/src/mixer/mappings.rs index 04cef439..548d0648 100644 --- a/playback/src/mixer/mappings.rs +++ b/playback/src/mixer/mappings.rs @@ -3,7 +3,7 @@ use crate::player::db_to_ratio; pub trait MappedCtrl { fn to_mapped(&self, volume: u16) -> f64; - fn from_mapped(&self, mapped_volume: f64) -> u16; + fn to_unmapped(&self, mapped_volume: f64) -> u16; fn db_range(&self) -> f64; fn set_db_range(&mut self, new_db_range: f64); @@ -49,7 +49,7 @@ impl MappedCtrl for VolumeCtrl { mapped_volume } - fn from_mapped(&self, mapped_volume: f64) -> u16 { + fn to_unmapped(&self, mapped_volume: f64) -> u16 { // More than just an optimization, this ensures that zero mapped volume // is unmapped to non-negative real numbers (otherwise the log and cubic // equations would respectively return -inf and -1/9.) diff --git a/playback/src/mixer/softmixer.rs b/playback/src/mixer/softmixer.rs index 93da5fec..db72659d 100644 --- a/playback/src/mixer/softmixer.rs +++ b/playback/src/mixer/softmixer.rs @@ -26,7 +26,7 @@ impl Mixer for SoftMixer { fn volume(&self) -> u16 { let mapped_volume = f64::from_bits(self.volume.load(Ordering::Relaxed)); - self.volume_ctrl.from_mapped(mapped_volume) + self.volume_ctrl.to_unmapped(mapped_volume) } fn set_volume(&self, volume: u16) { diff --git a/src/main.rs b/src/main.rs index 55df381d..9a1427bc 100644 --- a/src/main.rs +++ b/src/main.rs @@ -586,7 +586,7 @@ fn get_setup() -> Setup { let stripped_env_key = |k: &str| { k.trim_start_matches("LIBRESPOT_") - .replace("_", "-") + .replace('_', "-") .to_lowercase() }; From b08502c801f5dabc03f1b3bc72873b286f4baab1 Mon Sep 17 00:00:00 2001 From: Roderick van Domburg Date: Sat, 21 May 2022 21:51:37 +0200 Subject: [PATCH 21/39] Update crates --- Cargo.lock | 775 +++++++++++++++++++++++++------------------- playback/Cargo.toml | 2 +- 2 files changed, 435 insertions(+), 342 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 10738efd..e3da3392 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -93,9 +93,9 @@ dependencies = [ [[package]] name = "anyhow" -version = "1.0.44" +version = "1.0.57" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "61604a8f862e1d5c3229fdd78f8b02c68dcf73a4c4b05fd636d12240aaa242c1" +checksum = "08f9b8508dccb7687a1d6c4ce66b2b0ecef467c94667de27d8d7fe1f8d2a9cdc" [[package]] name = "array-init" @@ -105,9 +105,9 @@ checksum = "6945cc5422176fc5e602e590c2878d2c2acd9a4fe20a4baa7c28022521698ec6" [[package]] name = "async-trait" -version = "0.1.51" +version = "0.1.53" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "44318e776df68115a881de9a8fd1b9e53368d7a4a5ce4cc48517da3393233a5e" +checksum = "ed6aa3524a2dfcf9fe180c51eae2b58738348d819517ceadf95789c51fff7600" dependencies = [ "proc-macro2", "quote", @@ -127,15 +127,15 @@ dependencies = [ [[package]] name = "autocfg" -version = "1.0.1" +version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cdb031dd78e28731d87d56cc8ffef4a8f36ca26c38fe2de700543e627f8a464a" +checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" [[package]] name = "backtrace" -version = "0.3.64" +version = "0.3.65" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5e121dee8023ce33ab248d9ce1493df03c3b38a659b240096fcbd7048ff9c31f" +checksum = "11a17d453482a265fd5f8479f2a3f405566e6ca627837aaddb85af8b1ab8ef61" dependencies = [ "addr2line", "cc", @@ -154,9 +154,9 @@ checksum = "904dfeac50f3cdaba28fc6f57fdcddb75f49ed61346676a78c4ffe55877802fd" [[package]] name = "bindgen" -version = "0.56.0" +version = "0.59.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2da379dbebc0b76ef63ca68d8fc6e71c0f13e59432e0987e508c1820e6ab5239" +checksum = "2bd2a9a458e8f4304c52c43ebb0cfbd520289f8379a52e329a38afda99bf8eb8" dependencies = [ "bitflags", "cexpr", @@ -187,10 +187,19 @@ dependencies = [ ] [[package]] -name = "bumpalo" -version = "3.8.0" +name = "block-buffer" +version = "0.10.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f1e260c3a9040a7c19a12468758f4c16f31a81a1fe087482be9570ec864bb6c" +checksum = "0bf7fe51849ea569fd452f37822f606a5cabb684dc918707a0193fd4664ff324" +dependencies = [ + "generic-array", +] + +[[package]] +name = "bumpalo" +version = "3.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a4a45a46ab1f2412e53d3a0ade76ffad2025804294569aae387231a0cd6e0899" [[package]] name = "byteorder" @@ -206,9 +215,9 @@ checksum = "c4872d67bab6358e59559027aa3b9157c53d9358c51423c17554809a8858e0f8" [[package]] name = "cc" -version = "1.0.71" +version = "1.0.73" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "79c2681d6594606957bbb8631c4b90a7fcaaa72cdb714743a437b156d6a7eedd" +checksum = "2fff2a6927b3bb87f9595d67196a70493f627687a71d87a0d692242c33f58c11" dependencies = [ "jobserver", ] @@ -221,9 +230,9 @@ checksum = "6d43a04d8753f35258c91f8ec639f792891f748a1edbd759cf1dcea3382ad83c" [[package]] name = "cexpr" -version = "0.4.0" +version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f4aedb84272dbe89af497cf81375129abda4fc0a9e7c5d317498c15cc30c0d27" +checksum = "6fac387a98bb7c37292057cffc56d62ecb629900026402633ae9160df93a8766" dependencies = [ "nom", ] @@ -258,7 +267,7 @@ dependencies = [ "libc", "num-integer", "num-traits", - "time", + "time 0.1.43", "winapi", ] @@ -273,13 +282,13 @@ dependencies = [ [[package]] name = "clang-sys" -version = "1.2.2" +version = "1.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "10612c0ec0e0a1ff0e97980647cb058a6e7aedb913d01d009c406b8b7d0b26ee" +checksum = "bf6b561dcf059c85bbe388e0a7b0a1469acb3934cc0cfa148613a830629e3049" dependencies = [ "glob", "libc", - "libloading 0.7.1", + "libloading 0.7.3", ] [[package]] @@ -295,9 +304,9 @@ dependencies = [ [[package]] name = "combine" -version = "4.6.1" +version = "4.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a909e4d93292cd8e9c42e189f61681eff9d67b6541f96b8a1a737f23737bd001" +checksum = "2a604e93b79d1808327a6fca85a6f2d69de66461e7620f5a4cbf5fb4d1d7c948" dependencies = [ "bytes", "memchr", @@ -321,9 +330,9 @@ dependencies = [ [[package]] name = "coreaudio-sys" -version = "0.2.8" +version = "0.2.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2b7e3347be6a09b46aba228d6608386739fb70beff4f61e07422da87b0bb31fa" +checksum = "3dff444d80630d7073077d38d40b4501fd518bd2b922c2a55edcc8b0f7be57e6" dependencies = [ "bindgen", ] @@ -344,10 +353,10 @@ dependencies = [ "libc", "mach", "ndk 0.3.0", - "ndk-glue 0.3.0", + "ndk-glue", "nix", "oboe", - "parking_lot", + "parking_lot 0.11.2", "stdweb", "thiserror", "web-sys", @@ -356,13 +365,23 @@ dependencies = [ [[package]] name = "cpufeatures" -version = "0.2.1" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "95059428f66df56b63431fdb4e1947ed2190586af5c5a8a8b71122bdf5a7f469" +checksum = "59a6001667ab124aebae2a495118e11d30984c3a653e99d86d58971708cf5e4b" dependencies = [ "libc", ] +[[package]] +name = "crypto-common" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "57952ca27b5e3606ff4dd79b0020231aaf9d6aa76dc05fd30137538c50bd3ce8" +dependencies = [ + "generic-array", + "typenum", +] + [[package]] name = "crypto-mac" version = "0.11.1" @@ -417,17 +436,6 @@ dependencies = [ "syn", ] -[[package]] -name = "derivative" -version = "2.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fcc3dd5e9e9c0b295d6e1e4d811fb6f157d5ffd784b8d202fc62eac8035a770b" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - [[package]] name = "digest" version = "0.9.0" @@ -437,6 +445,16 @@ dependencies = [ "generic-array", ] +[[package]] +name = "digest" +version = "0.10.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f2fb860ca6fafa5552fb6d0e816a69c8e49f0908bf524e30a90d97c85892d506" +dependencies = [ + "block-buffer 0.10.2", + "crypto-common", +] + [[package]] name = "dns-sd" version = "0.1.3" @@ -466,6 +484,15 @@ dependencies = [ "termcolor", ] +[[package]] +name = "fastrand" +version = "1.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3fcf0cee53519c866c09b5de1f6c56ff9d647101f81c1964fa632e148896cdf" +dependencies = [ + "instant", +] + [[package]] name = "fixedbitset" version = "0.2.0" @@ -490,9 +517,9 @@ dependencies = [ [[package]] name = "futures" -version = "0.3.17" +version = "0.3.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a12aa0eb539080d55c3f2d45a67c3b58b6b0773c1a3ca2dfec66d58c97fd66ca" +checksum = "f73fe65f54d1e12b726f517d3e2135ca3125a437b6d998caf1962961f7172d9e" dependencies = [ "futures-channel", "futures-core", @@ -505,9 +532,9 @@ dependencies = [ [[package]] name = "futures-channel" -version = "0.3.17" +version = "0.3.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5da6ba8c3bb3c165d3c7319fc1cc8304facf1fb8db99c5de877183c08a273888" +checksum = "c3083ce4b914124575708913bca19bfe887522d6e2e6d0952943f5eac4a74010" dependencies = [ "futures-core", "futures-sink", @@ -515,15 +542,15 @@ dependencies = [ [[package]] name = "futures-core" -version = "0.3.17" +version = "0.3.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "88d1c26957f23603395cd326b0ffe64124b818f4449552f960d815cfba83a53d" +checksum = "0c09fd04b7e4073ac7156a9539b57a484a8ea920f79c7c675d05d289ab6110d3" [[package]] name = "futures-executor" -version = "0.3.17" +version = "0.3.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "45025be030969d763025784f7f355043dc6bc74093e4ecc5000ca4dc50d8745c" +checksum = "9420b90cfa29e327d0429f19be13e7ddb68fa1cccb09d65e5706b8c7a749b8a6" dependencies = [ "futures-core", "futures-task", @@ -532,18 +559,16 @@ dependencies = [ [[package]] name = "futures-io" -version = "0.3.17" +version = "0.3.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "522de2a0fe3e380f1bc577ba0474108faf3f6b18321dbf60b3b9c39a75073377" +checksum = "fc4045962a5a5e935ee2fdedaa4e08284547402885ab326734432bed5d12966b" [[package]] name = "futures-macro" -version = "0.3.17" +version = "0.3.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "18e4a4b95cea4b4ccbcf1c5675ca7c4ee4e9e75eb79944d07defde18068f79bb" +checksum = "33c1e13800337f4d4d7a316bf45a567dbcb6ffe087f16424852d97e97a91f512" dependencies = [ - "autocfg", - "proc-macro-hack", "proc-macro2", "quote", "syn", @@ -551,23 +576,22 @@ dependencies = [ [[package]] name = "futures-sink" -version = "0.3.17" +version = "0.3.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "36ea153c13024fe480590b3e3d4cad89a0cfacecc24577b68f86c6ced9c2bc11" +checksum = "21163e139fa306126e6eedaf49ecdb4588f939600f0b1e770f4205ee4b7fa868" [[package]] name = "futures-task" -version = "0.3.17" +version = "0.3.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1d3d00f4eddb73e498a54394f228cd55853bdf059259e8e7bc6e69d408892e99" +checksum = "57c66a976bf5909d801bbef33416c41372779507e7a6b3a5e25e4749c58f776a" [[package]] name = "futures-util" -version = "0.3.17" +version = "0.3.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "36568465210a3a6ee45e1f165136d68671471a501e632e9a98d96872222b5481" +checksum = "d8b7abd5d659d9b90c8cba917f6ec750a74e2dc23902ef9cd4cc8c8b22e6036a" dependencies = [ - "autocfg", "futures-channel", "futures-core", "futures-io", @@ -577,16 +601,14 @@ dependencies = [ "memchr", "pin-project-lite", "pin-utils", - "proc-macro-hack", - "proc-macro-nested", "slab", ] [[package]] name = "generic-array" -version = "0.14.4" +version = "0.14.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "501466ecc8a30d1d3b7fc9229b122b2ce8ed6e9d9223f1138d4babb253e51817" +checksum = "fd48d33ec7f05fbfa152300fdad764757cbded343c1aa1cff2fbaf4134851803" dependencies = [ "typenum", "version_check", @@ -603,13 +625,13 @@ dependencies = [ [[package]] name = "getrandom" -version = "0.2.3" +version = "0.2.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7fcd999463524c52659517fe2cea98493cfe485d10565e7b0fb07dbba7ad2753" +checksum = "9be70c98951c83b8d2f8f60d7065fa6d5146873094452a1008da8c2f1e4205ad" dependencies = [ "cfg-if 1.0.0", "libc", - "wasi", + "wasi 0.10.2+wasi-snapshot-preview1", ] [[package]] @@ -680,7 +702,7 @@ checksum = "2aad66361f66796bfc73f530c51ef123970eb895ffba991a234fcf7bea89e518" dependencies = [ "anyhow", "heck", - "proc-macro-crate 1.1.0", + "proc-macro-crate 1.1.3", "proc-macro-error", "proc-macro2", "quote", @@ -866,9 +888,9 @@ checksum = "ab5ef0d4909ef3724cc8cce6ccc8572c5c817592e9285f5464f8e86f8bd3726e" [[package]] name = "headers" -version = "0.3.5" +version = "0.3.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a4c4eb0471fcb85846d8b0690695ef354f9afb11cb03cac2e1d7c9253351afb0" +checksum = "4cff78e5788be1e0ab65b04d306b2ed5092c815ec97ec70f4ebd5aee158aa55d" dependencies = [ "base64", "bitflags", @@ -877,7 +899,7 @@ dependencies = [ "http", "httpdate", "mime", - "sha-1", + "sha-1 0.10.0", ] [[package]] @@ -920,7 +942,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2a2a2320eb7ec0ebe8da8f744d7812d9fc4cb4d09344ac01898dbcb6a20ae69b" dependencies = [ "crypto-mac", - "digest", + "digest 0.9.0", ] [[package]] @@ -936,9 +958,9 @@ dependencies = [ [[package]] name = "http" -version = "0.2.5" +version = "0.2.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1323096b05d41827dadeaee54c9981958c0f94e670bc94ed80037d1a7b8b186b" +checksum = "ff8670570af52249509a86f5e3e18a08c60b177071826898fde8997cf5f6bfbb" dependencies = [ "bytes", "fnv", @@ -947,9 +969,9 @@ dependencies = [ [[package]] name = "http-body" -version = "0.4.4" +version = "0.4.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1ff4f84919677303da5f147645dbea6b1881f368d03ac84e1dc09031ebd7b2c6" +checksum = "d5f38f16d184e36f2408a55281cd658ecbd3ca05cce6d6510a176eca393e26d1" dependencies = [ "bytes", "http", @@ -958,15 +980,15 @@ dependencies = [ [[package]] name = "httparse" -version = "1.5.1" +version = "1.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "acd94fdbe1d4ff688b67b04eee2e17bd50995534a61539e45adfefb45e5e5503" +checksum = "496ce29bb5a52785b44e0f7ca2847ae0bb839c9bd28f69acac9b99d461c0c04c" [[package]] name = "httpdate" -version = "1.0.1" +version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6456b8a6c8f33fee7d958fcd1b60d55b11940a79e63ae87013e6d22e26034440" +checksum = "c4a1e36c821dbe04574f602848a19f742f4fb3c98d40449f11bcad18d6b17421" [[package]] name = "humantime" @@ -976,9 +998,9 @@ checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4" [[package]] name = "hyper" -version = "0.14.14" +version = "0.14.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2b91bb1f221b6ea1f1e4371216b70f40748774c2fb5971b450c07773fb92d26b" +checksum = "b26ae0a80afebe130861d90abf98e3814a4f28a4c6ffeb5ab8ebb2be311e0ef2" dependencies = [ "bytes", "futures-channel", @@ -1031,30 +1053,19 @@ dependencies = [ [[package]] name = "if-addrs" -version = "0.6.6" +version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c9a83ec4af652890ac713ffd8dc859e650420a5ef47f7b9be29b6664ab50fbc8" +checksum = "cbc0fa01ffc752e9dbc72818cdb072cd028b86be5e09dd04c5a643704fe101a9" dependencies = [ - "if-addrs-sys", "libc", "winapi", ] -[[package]] -name = "if-addrs-sys" -version = "0.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "de74b9dd780476e837e5eb5ab7c88b49ed304126e412030a0adba99c8efe79ea" -dependencies = [ - "cc", - "libc", -] - [[package]] name = "indexmap" -version = "1.7.0" +version = "1.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bc633605454125dec4b66843673f01c7df2b89479b32e0ed634e43a91cff62a5" +checksum = "0f647032dfaa1f8b6dc29bd3edb7bbef4861b8b8007ebb118d6db284fd59f6ee" dependencies = [ "autocfg", "hashbrown", @@ -1089,31 +1100,33 @@ dependencies = [ [[package]] name = "itoa" -version = "0.4.8" +version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b71991ff56294aa922b450139ee08b3bfc70982c6b2c7562771375cf73542dd4" +checksum = "112c678d4050afce233f4f2852bb2eb519230b3cf12f33585275537d7e41578d" [[package]] name = "jack" -version = "0.7.2" +version = "0.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "39722b9795ae57c6967da99b1ab009fe72897fcbc59be59508c7c520327d9e34" +checksum = "d79b205ea723e478eb31a91dcdda100912c69cc32992eb7ba26ec0bbae7bebe4" dependencies = [ "bitflags", "jack-sys", "lazy_static", "libc", + "log", ] [[package]] name = "jack-sys" -version = "0.2.2" +version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "57983f0d72dfecf2b719ed39bc9cacd85194e1a94cb3f9146009eff9856fef41" +checksum = "7b91f2d2d10bc2bab38f4dfa4bc77123a988828af39dd3f30dd9db14d44f2cc1" dependencies = [ "lazy_static", "libc", "libloading 0.6.7", + "pkg-config", ] [[package]] @@ -1147,9 +1160,9 @@ dependencies = [ [[package]] name = "js-sys" -version = "0.3.55" +version = "0.3.57" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7cc9ffccd38c451a86bf13657df244e9c3f37493cce8e5e21e940963777acc84" +checksum = "671a26f820db17c2a2750743f1dd03bafd15b98c9f30c7c2628c024c05d73397" dependencies = [ "wasm-bindgen", ] @@ -1179,9 +1192,9 @@ dependencies = [ [[package]] name = "libc" -version = "0.2.105" +version = "0.2.126" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "869d572136620d55835903746bcb5cdc54cb2851fd0aeec53220b4bb65ef3013" +checksum = "349d5a591cd28b49e1d1037471617a32ddcda5731b99419008085f72d5a53836" [[package]] name = "libloading" @@ -1195,9 +1208,9 @@ dependencies = [ [[package]] name = "libloading" -version = "0.7.1" +version = "0.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c0cf036d15402bea3c5d4de17b3fce76b3e4a56ebc1f577be0e7a72f7c607cf0" +checksum = "efbc0f03f9a775e9f6aed295c6a1ba2253c5757a9e03d55c6caa46a681abcddd" dependencies = [ "cfg-if 1.0.0", "winapi", @@ -1205,15 +1218,15 @@ dependencies = [ [[package]] name = "libm" -version = "0.2.1" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c7d73b3f436185384286bd8098d17ec07c9a7d2388a6599f824d8502b529702a" +checksum = "33a33a362ce288760ec6a508b94caaec573ae7d3bbbd91b87aa0bad4456839db" [[package]] name = "libmdns" -version = "0.6.2" +version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fac185a4d02e873c6d1ead59d674651f8ae5ec23ffe1637bee8de80665562a6a" +checksum = "d6fb7fd715150e59e9a74049d2b50e862c3959c139b95eea132a66ddae20c3d9" dependencies = [ "byteorder", "futures-util", @@ -1229,9 +1242,9 @@ dependencies = [ [[package]] name = "libpulse-binding" -version = "2.25.0" +version = "2.26.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "86835d7763ded6bc16b6c0061ec60214da7550dfcd4ef93745f6f0096129676a" +checksum = "17be42160017e0ae993c03bfdab4ecb6f82ce3f8d515bd8da8fdf18d10703663" dependencies = [ "bitflags", "libc", @@ -1243,9 +1256,9 @@ dependencies = [ [[package]] name = "libpulse-simple-binding" -version = "2.24.1" +version = "2.25.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d6a22538257c4d522bea6089d6478507f5d2589ea32150e20740aaaaaba44590" +checksum = "7cbf1a1dfd69a48cb60906399fa1d17f1b75029ef51c0789597be792dfd0bcd5" dependencies = [ "libpulse-binding", "libpulse-simple-sys", @@ -1254,9 +1267,9 @@ dependencies = [ [[package]] name = "libpulse-simple-sys" -version = "1.19.1" +version = "1.19.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b8b0fcb9665401cc7c156c337c8edc7eb4e797b9d3ae1667e1e9e17b29e0c7c" +checksum = "7c73f96f9ca34809692c4760cfe421225860aa000de50edab68a16221fd27cc1" dependencies = [ "libpulse-sys", "pkg-config", @@ -1264,9 +1277,9 @@ dependencies = [ [[package]] name = "libpulse-sys" -version = "1.19.2" +version = "1.19.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f12950b69c1b66233a900414befde36c8d4ea49deec1e1f34e4cd2f586e00c7d" +checksum = "991e6bd0efe2a36e6534e136e7996925e4c1a8e35b7807fe533f2beffff27c30" dependencies = [ "libc", "num-derive", @@ -1294,7 +1307,7 @@ dependencies = [ "librespot-protocol", "log", "rpassword", - "sha-1", + "sha-1 0.9.8", "thiserror", "tokio", "url", @@ -1362,7 +1375,7 @@ dependencies = [ "rand", "serde", "serde_json", - "sha-1", + "sha-1 0.9.8", "shannon", "thiserror", "tokio", @@ -1379,7 +1392,6 @@ version = "0.3.1" dependencies = [ "aes-ctr", "base64", - "cfg-if 1.0.0", "dns-sd", "form_urlencoded", "futures", @@ -1392,7 +1404,7 @@ dependencies = [ "log", "rand", "serde_json", - "sha-1", + "sha-1 0.9.8", "simple_logger", "thiserror", "tokio", @@ -1432,7 +1444,7 @@ dependencies = [ "librespot-metadata", "log", "ogg", - "parking_lot", + "parking_lot 0.11.2", "portaudio-rs", "rand", "rand_distr", @@ -1455,18 +1467,19 @@ dependencies = [ [[package]] name = "lock_api" -version = "0.4.5" +version = "0.4.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "712a4d093c9976e24e7dbca41db895dabcbac38eb5f4045393d17a95bdfb1109" +checksum = "327fa5b6a6940e4699ec49a9beae1ea4845c6bab9314e4f84ac68742139d8c53" dependencies = [ + "autocfg", "scopeguard", ] [[package]] name = "log" -version = "0.4.14" +version = "0.4.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "51b9bbe6c47d51fc3e1a9b945965946b4c44142ab8792c50835a980d362c2710" +checksum = "abb12e687cfb44aa40f41fc3978ef76448f9b6038cad6aef4259d3c095a2382e" dependencies = [ "cfg-if 1.0.0", ] @@ -1494,9 +1507,9 @@ checksum = "a3e378b66a060d48947b590737b30a1be76706c8dd7b8ba0f2fe3989c68a853f" [[package]] name = "memchr" -version = "2.4.1" +version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "308cc39be01b73d0d18f82a0e7b2a3df85245f84af96fdddc5d202d27e47b86a" +checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d" [[package]] name = "mime" @@ -1505,35 +1518,30 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2a60c7ce501c71e03a9c9c0d35b861413ae925bd979cc7a4e30d060069aaac8d" [[package]] -name = "miniz_oxide" -version = "0.4.4" +name = "minimal-lexical" +version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a92518e98c078586bc6c934028adcca4c92a53d6a958196de835170a01d84e4b" +checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" + +[[package]] +name = "miniz_oxide" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d2b29bd4bc3f33391105ebee3589c19197c4271e3e5a9ec9bfe8127eeff8f082" dependencies = [ "adler", - "autocfg", ] [[package]] name = "mio" -version = "0.7.14" +version = "0.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8067b404fe97c70829f082dec8bcf4f71225d7eaea1d8645349cb76fa06205cc" +checksum = "713d550d9b44d89174e066b7a6217ae06234c10cb47819a88290d2b353c31799" dependencies = [ "libc", "log", - "miow", - "ntapi", - "winapi", -] - -[[package]] -name = "miow" -version = "0.3.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b9f1c5b025cda876f66ef43a113f91ebc9f4ccef34843000e0adf6ebbab84e21" -dependencies = [ - "winapi", + "wasi 0.11.0+wasi-snapshot-preview1", + "windows-sys", ] [[package]] @@ -1558,24 +1566,30 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8794322172319b972f528bf90c6b467be0079f1fa82780ffb431088e741a73ab" dependencies = [ "jni-sys", - "ndk-sys", + "ndk-sys 0.2.2", "num_enum", "thiserror", ] [[package]] name = "ndk" -version = "0.4.0" +version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d64d6af06fde0e527b1ba5c7b79a6cc89cfc46325b0b2887dffe8f70197e0c3c" +checksum = "2032c77e030ddee34a6787a64166008da93f6a352b629261d0fee232b8742dd4" dependencies = [ "bitflags", "jni-sys", - "ndk-sys", + "ndk-sys 0.3.0", "num_enum", "thiserror", ] +[[package]] +name = "ndk-context" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "27b02d87554356db9e9a873add8782d4ea6e3e58ea071a9adb9a2e8ddb884a8b" + [[package]] name = "ndk-glue" version = "0.3.0" @@ -1587,21 +1601,7 @@ dependencies = [ "log", "ndk 0.3.0", "ndk-macro", - "ndk-sys", -] - -[[package]] -name = "ndk-glue" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d3e9e94628f24e7a3cb5b96a2dc5683acd9230bf11991c2a1677b87695138420" -dependencies = [ - "lazy_static", - "libc", - "log", - "ndk 0.4.0", - "ndk-macro", - "ndk-sys", + "ndk-sys 0.2.2", ] [[package]] @@ -1619,9 +1619,18 @@ dependencies = [ [[package]] name = "ndk-sys" -version = "0.2.1" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c44922cb3dbb1c70b5e5f443d63b64363a898564d739ba5198e3a9138442868d" +checksum = "e1bcdd74c20ad5d95aacd60ef9ba40fdf77f767051040541df557b7a9b2a2121" + +[[package]] +name = "ndk-sys" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6e5a6ae77c8ee183dcbbba6150e2e6b9f3f4196a7666c02a715a95692ec1fa97" +dependencies = [ + "jni-sys", +] [[package]] name = "nix" @@ -1637,28 +1646,19 @@ dependencies = [ [[package]] name = "nom" -version = "5.1.2" +version = "7.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ffb4262d26ed83a1c0a33a38fe2bb15797329c85770da05e6b828ddb782627af" +checksum = "a8903e5a29a317527874d0402f867152a3d21c908bb0b933e416c65e301d4c36" dependencies = [ "memchr", - "version_check", -] - -[[package]] -name = "ntapi" -version = "0.3.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3f6bb902e437b6d86e03cce10a7e2af662292c5dfef23b65899ea3ac9354ad44" -dependencies = [ - "winapi", + "minimal-lexical", ] [[package]] name = "num-bigint" -version = "0.4.2" +version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "74e768dff5fb39a41b3bcd30bb25cf989706c90d028d1ad71971987aa309d535" +checksum = "f93ab6289c7b344a8a9f60f88d80aa20032336fe78da341afc91c8a2341fc75f" dependencies = [ "autocfg", "num-integer", @@ -1679,9 +1679,9 @@ dependencies = [ [[package]] name = "num-integer" -version = "0.1.44" +version = "0.1.45" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d2cc698a63b549a70bc047073d2949cce27cd1c7b0a4a862d08a8031bc2801db" +checksum = "225d3389fb3509a24c93f5c29eb6bde2586b98d9f016636dff58d7c6f7569cd9" dependencies = [ "autocfg", "num-traits", @@ -1700,9 +1700,9 @@ dependencies = [ [[package]] name = "num-traits" -version = "0.2.14" +version = "0.2.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9a64b1ec5cda2586e284722486d802acf1f7dbdc623e2bfc57e65ca1cd099290" +checksum = "578ede34cf02f8924ab9447f50c28075b4d3e5b269972345e7e0372b38c6cdcd" dependencies = [ "autocfg", "libm", @@ -1710,9 +1710,9 @@ dependencies = [ [[package]] name = "num_cpus" -version = "1.13.0" +version = "1.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "05499f3756671c15885fee9034446956fff3f243d6077b91e5767df161f766b3" +checksum = "19e64526ebdee182341572e50e9ad03965aa510cd94427a4549448f285e957a1" dependencies = [ "hermit-abi", "libc", @@ -1720,44 +1720,52 @@ dependencies = [ [[package]] name = "num_enum" -version = "0.5.4" +version = "0.5.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3f9bd055fb730c4f8f4f57d45d35cd6b3f0980535b056dc7ff119cee6a66ed6f" +checksum = "cf5395665662ef45796a4ff5486c5d41d29e0c09640af4c5f17fd94ee2c119c9" dependencies = [ - "derivative", "num_enum_derive", ] [[package]] name = "num_enum_derive" -version = "0.5.4" +version = "0.5.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "486ea01961c4a818096de679a8b740b26d9033146ac5291b1c98557658f8cdd9" +checksum = "3b0498641e53dd6ac1a4f22547548caa6864cc4933784319cd1775271c5a46ce" dependencies = [ - "proc-macro-crate 1.1.0", + "proc-macro-crate 1.1.3", "proc-macro2", "quote", "syn", ] [[package]] -name = "object" -version = "0.27.1" +name = "num_threads" +version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "67ac1d3f9a1d3616fd9a60c8d74296f22406a238b6a72f5cc1e6f314df4ffbf9" +checksum = "2819ce041d2ee131036f4fc9d6ae7ae125a3a40e97ba64d04fe799ad9dabbb44" +dependencies = [ + "libc", +] + +[[package]] +name = "object" +version = "0.28.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e42c982f2d955fac81dd7e1d0e1426a7d702acd9c98d19ab01083a6a0328c424" dependencies = [ "memchr", ] [[package]] name = "oboe" -version = "0.4.4" +version = "0.4.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e15e22bc67e047fe342a32ecba55f555e3be6166b04dd157cd0f803dfa9f48e1" +checksum = "27f63c358b4fa0fbcfefd7c8be5cfc39c08ce2389f5325687e7762a48d30a5c1" dependencies = [ "jni", - "ndk 0.4.0", - "ndk-glue 0.4.0", + "ndk 0.6.0", + "ndk-context", "num-derive", "num-traits", "oboe-sys", @@ -1765,9 +1773,9 @@ dependencies = [ [[package]] name = "oboe-sys" -version = "0.4.4" +version = "0.4.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "338142ae5ab0aaedc8275aa8f67f460e43ae0fca76a695a742d56da0a269eadc" +checksum = "3370abb7372ed744232c12954d920d1a40f1c4686de9e79e800021ef492294bd" dependencies = [ "cc", ] @@ -1783,9 +1791,9 @@ dependencies = [ [[package]] name = "once_cell" -version = "1.8.0" +version = "1.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "692fcb63b64b1758029e0a96ee63e049ce8c5948587f2f7208df04625e5f6b56" +checksum = "7b10983b38c53aebdf33f542c6275b0f58a238129d00c4ae0e6fb59738d783ca" [[package]] name = "opaque-debug" @@ -1801,7 +1809,17 @@ checksum = "7d17b78036a60663b797adeaee46f5c9dfebb86948d1255007a1d6be0271ff99" dependencies = [ "instant", "lock_api", - "parking_lot_core", + "parking_lot_core 0.8.5", +] + +[[package]] +name = "parking_lot" +version = "0.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87f5ec2493a61ac0506c0f4199f99070cbe83857b0337006a30f3e6719b8ef58" +dependencies = [ + "lock_api", + "parking_lot_core 0.9.3", ] [[package]] @@ -1822,10 +1840,23 @@ dependencies = [ ] [[package]] -name = "paste" -version = "1.0.5" +name = "parking_lot_core" +version = "0.9.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "acbf547ad0c65e31259204bd90935776d1c693cec2f4ff7abb7a1bbbd40dfe58" +checksum = "09a279cbf25cb0757810394fbc1e359949b59e348145c643a939a525692e6929" +dependencies = [ + "cfg-if 1.0.0", + "libc", + "redox_syscall", + "smallvec", + "windows-sys", +] + +[[package]] +name = "paste" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c520e05135d6e763148b6426a837e239041653ba7becd2e538c076c738025fc" [[package]] name = "pbkdf2" @@ -1861,9 +1892,9 @@ dependencies = [ [[package]] name = "pin-project-lite" -version = "0.2.7" +version = "0.2.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8d31d11c69a6b52a174b42bdc0c30e5e11670f90788b2c471c31c1d17d449443" +checksum = "e0a7ae3ac2f1173085d398531c705756c94a4c56843785df85a60c1a0afac116" [[package]] name = "pin-utils" @@ -1873,9 +1904,9 @@ checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" [[package]] name = "pkg-config" -version = "0.3.22" +version = "0.3.25" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "12295df4f294471248581bc09bef3c38a5e46f1e36d6a37353621a0c6c357e1f" +checksum = "1df8c4ec4b0627e53bdf214615ad287367e482558cf84b109250b37464dc03ae" [[package]] name = "portaudio-rs" @@ -1900,9 +1931,9 @@ dependencies = [ [[package]] name = "ppv-lite86" -version = "0.2.15" +version = "0.2.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed0cfbc8191465bed66e1718596ee0b0b35d5ee1f41c5df2189d0fe8bde535ba" +checksum = "eb9f9e6e233e5c4a35559a617bf40a4ec447db2e84c20b55a6f83167b7e57872" [[package]] name = "pretty-hex" @@ -1912,9 +1943,9 @@ checksum = "bc5c99d529f0d30937f6f4b8a86d988047327bb88d04d2c4afc356de74722131" [[package]] name = "priority-queue" -version = "1.2.0" +version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cf40e51ccefb72d42720609e1d3c518de8b5800d723a09358d4a6d6245e1f8ca" +checksum = "00ba480ac08d3cfc40dea10fd466fd2c14dee3ea6fc7873bc4079eda2727caf0" dependencies = [ "autocfg", "indexmap", @@ -1931,9 +1962,9 @@ dependencies = [ [[package]] name = "proc-macro-crate" -version = "1.1.0" +version = "1.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1ebace6889caf889b4d3f76becee12e90353f2b8c7d875534a71e5742f8f6f83" +checksum = "e17d47ce914bf4de440332250b0edd23ce48c005f59fab39d3335866b114f11a" dependencies = [ "thiserror", "toml", @@ -1963,47 +1994,35 @@ dependencies = [ "version_check", ] -[[package]] -name = "proc-macro-hack" -version = "0.5.19" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dbf0c48bc1d91375ae5c3cd81e3722dff1abcf81a30960240640d223f59fe0e5" - -[[package]] -name = "proc-macro-nested" -version = "0.1.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bc881b2c22681370c6a780e47af9840ef841837bc98118431d4e1868bd0c1086" - [[package]] name = "proc-macro2" -version = "1.0.31" +version = "1.0.39" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b581350bde2d774a19c6f30346796806b8f42b5fd3458c5f9a8623337fb27897" +checksum = "c54b25569025b7fc9651de43004ae593a75ad88543b17178aa5e1b9c4f15f56f" dependencies = [ - "unicode-xid", + "unicode-ident", ] [[package]] name = "protobuf" -version = "2.25.2" +version = "2.27.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "47c327e191621a2158159df97cdbc2e7074bb4e940275e35abf38eb3d2595754" +checksum = "cf7e6d18738ecd0902d30d1ad232c9125985a3422929b16c65517b38adc14f96" [[package]] name = "protobuf-codegen" -version = "2.25.2" +version = "2.27.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3df8c98c08bd4d6653c2dbae00bd68c1d1d82a360265a5b0bbc73d48c63cb853" +checksum = "aec1632b7c8f2e620343439a7dfd1f3c47b18906c4be58982079911482b5d707" dependencies = [ "protobuf", ] [[package]] name = "protobuf-codegen-pure" -version = "2.25.2" +version = "2.27.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "394a73e2a819405364df8d30042c0f1174737a763e0170497ec9d36f8a2ea8f7" +checksum = "9f8122fdb18e55190c796b088a16bdb70cd7acdcd48f7a8b796b58c62e532cc6" dependencies = [ "protobuf", "protobuf-codegen", @@ -2011,23 +2030,22 @@ dependencies = [ [[package]] name = "quote" -version = "1.0.10" +version = "1.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38bc8cc6a5f2e3655e0899c1b848643b2562f853f114bfec7be120678e3ace05" +checksum = "a1feb54ed693b93a84e14094943b84b7c4eae204c512b7ccb95ab0c66d278ad1" dependencies = [ "proc-macro2", ] [[package]] name = "rand" -version = "0.8.4" +version = "0.8.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2e7573632e6454cf6b99d7aac4ccca54be06da05aca2ef7423d22d27d4d4bcd8" +checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" dependencies = [ "libc", "rand_chacha", "rand_core", - "rand_hc", ] [[package]] @@ -2051,37 +2069,28 @@ dependencies = [ [[package]] name = "rand_distr" -version = "0.4.2" +version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "964d548f8e7d12e102ef183a0de7e98180c9f8729f555897a857b96e48122d2f" +checksum = "32cb0b9bc82b0a0876c2dd994a7e7a2683d3e7390ca40e6886785ef0c7e3ee31" dependencies = [ "num-traits", "rand", ] -[[package]] -name = "rand_hc" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d51e9f596de227fda2ea6c84607f5558e196eeaf43c986b724ba4fb8fdf497e7" -dependencies = [ - "rand_core", -] - [[package]] name = "redox_syscall" -version = "0.2.10" +version = "0.2.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8383f39639269cde97d255a32bdb68c047337295414940c68bdd30c2e13203ff" +checksum = "62f25bc4c7e55e0b0b7a1d43fb893f4fa1361d0abe38b9ce4f323c2adfe6ef42" dependencies = [ "bitflags", ] [[package]] name = "regex" -version = "1.5.4" +version = "1.5.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d07a8629359eb56f1e2fb1652bb04212c072a87ba68546a04065d525673ac461" +checksum = "d83f127d94bdbcda4c8cc2e50f6f84f4b611f69c902699ca385a39c3a75f9ff1" dependencies = [ "aho-corasick", "memchr", @@ -2090,9 +2099,9 @@ dependencies = [ [[package]] name = "regex-syntax" -version = "0.6.25" +version = "0.6.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f497285884f3fcff424ffc933e56d7cbca511def0c9831a7f9b5f6153e3cc89b" +checksum = "49b3de9ec5dc0a3417da371aab17d729997c15010e7fd24ff707773a33bddb64" [[package]] name = "remove_dir_all" @@ -2145,9 +2154,9 @@ dependencies = [ [[package]] name = "ryu" -version = "1.0.5" +version = "1.0.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "71d301d4193d031abdd79ff7e3dd721168a9572ef3fe51a1517aba235bd8f86e" +checksum = "f3f6f92acf49d1b98f7a81226834412ada05458b7364277387724a237f062695" [[package]] name = "same-file" @@ -2189,24 +2198,24 @@ dependencies = [ [[package]] name = "semver" -version = "1.0.4" +version = "1.0.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "568a8e6258aa33c13358f81fd834adb854c6f7c9468520910a9b1e8fac068012" +checksum = "8cb243bdfdb5936c8dc3c45762a19d12ab4550cdc753bc247637d4ec35a040fd" [[package]] name = "serde" -version = "1.0.130" +version = "1.0.137" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f12d06de37cf59146fbdecab66aa99f9fe4f78722e3607577a5375d66bd0c913" +checksum = "61ea8d54c77f8315140a05f4c7237403bf38b72704d031543aa1d16abbf517d1" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.130" +version = "1.0.137" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d7bc1a1ab1961464eae040d96713baa5a724a8152c1222492465b54322ec508b" +checksum = "1f26faba0c3959972377d3b2d306ee9f71faee9714294e41bb777f83f88578be" dependencies = [ "proc-macro2", "quote", @@ -2215,9 +2224,9 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.68" +version = "1.0.81" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0f690853975602e1bfe1ccbf50504d67174e3bcf340f23b5ea9992e0587a52d8" +checksum = "9b7ce2b32a1aed03c558dc61a5cd328f15aff2dbc17daad8fb8af04d2100e15c" dependencies = [ "itoa", "ryu", @@ -2230,13 +2239,24 @@ version = "0.9.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "99cd6713db3cf16b6c84e06321e049a9b9f699826e16096d23bbcc44d15d51a6" dependencies = [ - "block-buffer", + "block-buffer 0.9.0", "cfg-if 1.0.0", "cpufeatures", - "digest", + "digest 0.9.0", "opaque-debug", ] +[[package]] +name = "sha-1" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "028f48d513f9678cda28f6e4064755b3fbb2af6acd672f2c209b62323f7aea0f" +dependencies = [ + "cfg-if 1.0.0", + "cpufeatures", + "digest 0.10.3", +] + [[package]] name = "shannon" version = "0.2.0" @@ -2248,15 +2268,15 @@ dependencies = [ [[package]] name = "shell-words" -version = "1.0.0" +version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b6fa3938c99da4914afedd13bf3d79bcb6c277d1b2c398d23257a304d9e1b074" +checksum = "24188a676b6ae68c3b2cb3a01be17fbf7240ce009799bb56d5b1409051e78fde" [[package]] name = "shlex" -version = "0.1.1" +version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7fdf1b9db47230893d76faad238fd6097fd6d6a9245cd7a4d90dbd639536bbd2" +checksum = "43b2853a4d09f215c24cc5489c992ce46052d359b5109343cbafbf26bc62f8a3" [[package]] name = "signal-hook-registry" @@ -2269,22 +2289,22 @@ dependencies = [ [[package]] name = "simple_logger" -version = "1.13.0" +version = "1.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b7de33c687404ec3045d4a0d437580455257c0436f858d702f244e7d652f9f07" +checksum = "45b60258a35dc3cb8a16890b8fd6723349bfa458d7960e25e633f1b1c19d7b5e" dependencies = [ "atty", - "chrono", "colored", "log", + "time 0.3.9", "winapi", ] [[package]] name = "slab" -version = "0.4.5" +version = "0.4.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9def91fd1e018fe007022791f865d0ccc9b3a0d5001e01aabb8b40e46000afb5" +checksum = "eb703cfe953bccee95685111adeedb76fabe4e97549a58d16f03ea7b9367bb32" [[package]] name = "smallvec" @@ -2294,9 +2314,9 @@ checksum = "f2dd574626839106c320a323308629dcb1acfc96e32a8cba364ddc61ac23ee83" [[package]] name = "socket2" -version = "0.4.2" +version = "0.4.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5dc90fe6c7be1a323296982db1836d1ea9e47b6839496dde9a541bc496df3516" +checksum = "66d72b759436ae32898a2af0a14218dbf55efde3feeb170eb623637db85ee1e0" dependencies = [ "libc", "winapi", @@ -2358,13 +2378,13 @@ checksum = "6bdef32e8150c2a081110b42772ffe7d7c9032b606bc226c8260fd97e0976601" [[package]] name = "syn" -version = "1.0.80" +version = "1.0.95" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d010a1623fbd906d51d650a9916aaefc05ffa0e4053ff7fe601167f3e715d194" +checksum = "fbaf6116ab8924f39d52792136fb74fd60a80194cf1b1c6ffa6453eef1c3f942" dependencies = [ "proc-macro2", "quote", - "unicode-xid", + "unicode-ident", ] [[package]] @@ -2414,13 +2434,13 @@ dependencies = [ [[package]] name = "tempfile" -version = "3.2.0" +version = "3.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dac1c663cfc93810f88aed9b8941d48cabf856a1b111c29a40439018d870eb22" +checksum = "5cdb1ef4eaeeaddc8fbd371e5017057064af0911902ef36b39801f67cc6d79e4" dependencies = [ "cfg-if 1.0.0", + "fastrand", "libc", - "rand", "redox_syscall", "remove_dir_all", "winapi", @@ -2428,27 +2448,27 @@ dependencies = [ [[package]] name = "termcolor" -version = "1.1.2" +version = "1.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2dfed899f0eb03f32ee8c6a0aabdb8a7949659e3466561fc0adf54e26d88c5f4" +checksum = "bab24d30b911b2376f3a13cc2cd443142f0c81dda04c118693e35b3835757755" dependencies = [ "winapi-util", ] [[package]] name = "thiserror" -version = "1.0.30" +version = "1.0.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "854babe52e4df1653706b98fcfc05843010039b406875930a70e4d9644e5c417" +checksum = "bd829fe32373d27f76265620b5309d0340cb8550f523c1dda251d6298069069a" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.30" +version = "1.0.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aa32fd3f627f367fe16f893e2597ae3c05020f8bba2666a4e6ea73d377e5714b" +checksum = "0396bc89e626244658bef819e22d0cc459e795a5ebe878e6ec336d1674a8d79a" dependencies = [ "proc-macro2", "quote", @@ -2477,10 +2497,28 @@ dependencies = [ ] [[package]] -name = "tinyvec" -version = "1.5.0" +name = "time" +version = "0.3.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f83b2a3d4d9091d0abd7eba4dc2710b1718583bd4d8992e2190720ea38f391f7" +checksum = "c2702e08a7a860f005826c6815dcac101b19b5eb330c27fe4a5928fec1d20ddd" +dependencies = [ + "itoa", + "libc", + "num_threads", + "time-macros", +] + +[[package]] +name = "time-macros" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42657b1a6f4d817cda8e7a0ace261fe0cc946cf3a80314390b22cc61ae080792" + +[[package]] +name = "tinyvec" +version = "1.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87cc5ceb3875bb20c2890005a4e226a4651264a5c75edb2421b52861a0a0cb50" dependencies = [ "tinyvec_macros", ] @@ -2493,29 +2531,29 @@ checksum = "cda74da7e1a664f795bb1f8a87ec406fb89a02522cf6e50620d016add6dbbf5c" [[package]] name = "tokio" -version = "1.12.0" +version = "1.18.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c2c2416fdedca8443ae44b4527de1ea633af61d8f7169ffa6e72c5b53d24efcc" +checksum = "4903bf0427cf68dddd5aa6a93220756f8be0c34fcfa9f5e6191e103e15a31395" dependencies = [ - "autocfg", "bytes", "libc", "memchr", "mio", "num_cpus", "once_cell", - "parking_lot", + "parking_lot 0.12.0", "pin-project-lite", "signal-hook-registry", + "socket2", "tokio-macros", "winapi", ] [[package]] name = "tokio-macros" -version = "1.5.0" +version = "1.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b2dd85aeaba7b68df939bd357c6afb36c87951be9e80bf9c859f2fc3e9fca0fd" +checksum = "b557f72f448c511a979e2564e55d74e6c4432fc96ff4f6241bc6bded342643b7" dependencies = [ "proc-macro2", "quote", @@ -2524,9 +2562,9 @@ dependencies = [ [[package]] name = "tokio-stream" -version = "0.1.7" +version = "0.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7b2f3f698253f03119ac0102beaa64f67a67e08074d03a22d18784104543727f" +checksum = "50145484efff8818b5ccd256697f36863f587da82cf8b409c53adf1e840798e3" dependencies = [ "futures-core", "pin-project-lite", @@ -2535,9 +2573,9 @@ dependencies = [ [[package]] name = "tokio-util" -version = "0.6.8" +version = "0.6.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "08d3725d3efa29485e87311c5b699de63cde14b00ed4d256b8318aa30ca452cd" +checksum = "36943ee01a6d67977dd3f84a5a1d2efeb4ada3a1ae771cadfaa535d9d9fc6507" dependencies = [ "bytes", "futures-core", @@ -2549,9 +2587,9 @@ dependencies = [ [[package]] name = "toml" -version = "0.5.8" +version = "0.5.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a31142970826733df8241ef35dc040ef98c679ab14d7c3e54d827099b3acecaa" +checksum = "8d82e1a7758622a465f8cee077614c73484dac5b836c02ff6a40d5d1010324d7" dependencies = [ "serde", ] @@ -2564,9 +2602,9 @@ checksum = "360dfd1d6d30e05fda32ace2c8c70e9c0a9da713275777f5a4dbb8a1893930c6" [[package]] name = "tracing" -version = "0.1.29" +version = "0.1.34" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "375a639232caf30edfc78e8d89b2d4c375515393e7af7e16f01cd96917fb2105" +checksum = "5d0ecdcb44a79f0fe9844f0c4f33a342cbcbb5117de8001e6ba0dc2351327d09" dependencies = [ "cfg-if 1.0.0", "pin-project-lite", @@ -2575,9 +2613,9 @@ dependencies = [ [[package]] name = "tracing-core" -version = "0.1.21" +version = "0.1.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1f4ed65637b8390770814083d20756f87bfa2c21bf2f110babdc5438351746e4" +checksum = "f54c8ca710e81886d498c2fd3331b56c93aa248d49de2222ad2742247c60072f" dependencies = [ "lazy_static", ] @@ -2590,15 +2628,21 @@ checksum = "59547bce71d9c38b83d9c0e92b6066c4253371f15005def0c30d9657f50c7642" [[package]] name = "typenum" -version = "1.14.0" +version = "1.15.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b63708a265f51345575b27fe43f9500ad611579e764c79edbc2037b1121959ec" +checksum = "dcf81ac59edc17cc8697ff311e8f5ef2d99fcbd9817b34cec66f90b6c3dfd987" [[package]] name = "unicode-bidi" -version = "0.3.7" +version = "0.3.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1a01404663e3db436ed2746d9fefef640d868edae3cceb81c3b8d5732fda678f" +checksum = "099b7128301d285f79ddd55b9a83d5e6b9e97c92e0ea0daebee7263e932de992" + +[[package]] +name = "unicode-ident" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d22af068fba1eb5edcb4aea19d382b2a3deb4c8f9d475c589b6ada9e0fd493ee" [[package]] name = "unicode-normalization" @@ -2623,9 +2667,9 @@ checksum = "3ed742d4ea2bd1176e236172c8429aaf54486e7ac098db29ffe6529e0ce50973" [[package]] name = "unicode-xid" -version = "0.2.2" +version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ccb82d61f80a663efe1f787a51b16b5a51e3314d6ac365b08639f52387b33f3" +checksum = "957e51f3646910546462e67d5f7599b9e4fb8acdd304b087a6494730f9eebf04" [[package]] name = "url" @@ -2673,9 +2717,9 @@ checksum = "1c18c859eead79d8b95d09e4678566e8d70105c4e7b251f707a03df32442661b" [[package]] name = "version_check" -version = "0.9.3" +version = "0.9.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5fecdca9a5291cc2b8dcf7dc02453fee791a280f3743cb0905f8822ae463b3fe" +checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" [[package]] name = "walkdir" @@ -2705,10 +2749,16 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fd6fbd9a79829dd1ad0cc20627bf1ed606756a7f77edff7b66b7064f9cb327c6" [[package]] -name = "wasm-bindgen" -version = "0.2.78" +name = "wasi" +version = "0.11.0+wasi-snapshot-preview1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "632f73e236b219150ea279196e54e610f5dbafa5d61786303d4da54f84e47fce" +checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" + +[[package]] +name = "wasm-bindgen" +version = "0.2.80" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "27370197c907c55e3f1a9fbe26f44e937fe6451368324e009cba39e139dc08ad" dependencies = [ "cfg-if 1.0.0", "wasm-bindgen-macro", @@ -2716,9 +2766,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-backend" -version = "0.2.78" +version = "0.2.80" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a317bf8f9fba2476b4b2c85ef4c4af8ff39c3c7f0cdfeed4f82c34a880aa837b" +checksum = "53e04185bfa3a779273da532f5025e33398409573f348985af9a1cbf3774d3f4" dependencies = [ "bumpalo", "lazy_static", @@ -2731,9 +2781,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro" -version = "0.2.78" +version = "0.2.80" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d56146e7c495528bf6587663bea13a8eb588d39b36b679d83972e1a2dbbdacf9" +checksum = "17cae7ff784d7e83a2fe7611cfe766ecf034111b49deb850a3dc7699c08251f5" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -2741,9 +2791,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.78" +version = "0.2.80" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7803e0eea25835f8abdc585cd3021b3deb11543c6fe226dcd30b228857c5c5ab" +checksum = "99ec0dc7a4756fffc231aab1b9f2f578d23cd391390ab27f952ae0c9b3ece20b" dependencies = [ "proc-macro2", "quote", @@ -2754,15 +2804,15 @@ dependencies = [ [[package]] name = "wasm-bindgen-shared" -version = "0.2.78" +version = "0.2.80" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0237232789cf037d5480773fe568aac745bfe2afbc11a863e97901780a6b47cc" +checksum = "d554b7f530dee5964d9a9468d95c1f8b8acae4f282807e7d27d4b03099a46744" [[package]] name = "web-sys" -version = "0.3.55" +version = "0.3.57" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38eb105f1c59d9eaa6b5cdc92b859d85b926e82cb2e0945cd0c9259faa6fe9fb" +checksum = "7b17e741662c70c8bd24ac5c5b18de314a2c26c32bf8346ee1e6f53de919c283" dependencies = [ "js-sys", "wasm-bindgen", @@ -2799,6 +2849,49 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" +[[package]] +name = "windows-sys" +version = "0.36.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ea04155a16a59f9eab786fe12a4a450e75cdb175f9e0d80da1e17db09f55b8d2" +dependencies = [ + "windows_aarch64_msvc", + "windows_i686_gnu", + "windows_i686_msvc", + "windows_x86_64_gnu", + "windows_x86_64_msvc", +] + +[[package]] +name = "windows_aarch64_msvc" +version = "0.36.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9bb8c3fd39ade2d67e9874ac4f3db21f0d710bee00fe7cab16949ec184eeaa47" + +[[package]] +name = "windows_i686_gnu" +version = "0.36.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "180e6ccf01daf4c426b846dfc66db1fc518f074baa793aa7d9b9aaeffad6a3b6" + +[[package]] +name = "windows_i686_msvc" +version = "0.36.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2e7917148b2812d1eeafaeb22a97e4813dfa60a3f8f78ebe204bcc88f12f024" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.36.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4dcd171b8776c41b97521e5da127a2d86ad280114807d0b2ab1e462bc764d9e1" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.36.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c811ca4a8c853ef420abd8592ba53ddbbac90410fab6903b3e79972a631f7680" + [[package]] name = "zerocopy" version = "0.3.0" diff --git a/playback/Cargo.toml b/playback/Cargo.toml index 7126e3da..516bd8af 100644 --- a/playback/Cargo.toml +++ b/playback/Cargo.toml @@ -42,7 +42,7 @@ glib = { version = "0.10", optional = true } # Rodio dependencies rodio = { version = "0.14", optional = true, default-features = false } -cpal = { version = "0.13", optional = true } +cpal = { version = "<0.13.5", optional = true } # Decoder lewton = "0.10" From 310b3cca81cf976288691d7c2b4493090119ec68 Mon Sep 17 00:00:00 2001 From: Roderick van Domburg Date: Sat, 21 May 2022 22:14:18 +0200 Subject: [PATCH 22/39] Prepare for 0.4.0 release --- CHANGELOG.md | 58 +++++++++++++++++++++++++--------------------------- 1 file changed, 28 insertions(+), 30 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 13e7594d..c0489ade 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,46 +5,44 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html) since v0.2.0. -## [Unreleased] +## [0.4.0] - 2022-05-21 ### Changed -- [main] Enforce reasonable ranges for option values (breaking). -- [main] Don't evaluate options that would otherwise have no effect. -- [playback] `alsa`: Improve `--device ?` functionality for the alsa backend. -- [contrib] Hardened security of the systemd service units -- [main] Verbose logging mode (`-v`, `--verbose`) now logs all parsed environment variables and command line arguments (credentials are redacted). -- [playback] `Sink`: `write()` now receives ownership of the packet (breaking). -- [playback] `pipe`: create file if it doesn't already exist +- [chore] The MSRV is now 1.53 +- [contrib] Hardened security of the `systemd` service units +- [core] `Session`: `connect()` now returns the long-term credentials +- [core] `Session`: `connect()` now accepts a flag if the credentails should be stored via the cache +- [main] Different option descriptions and error messages based on what backends are enabled at build time - [playback] More robust dynamic limiter for very wide dynamic range (breaking) -- [core] `Session`: `connect()` now returns the long-term credentials. -- [core] `Session`: `connect()` now accespt a flag if the credentails should be stored via the cache. -- [chore] The MSRV is now 1.53. +- [playback] `alsa`: improve `--device ?` output for the Alsa backend - [playback] `gstreamer`: create own context, set correct states and use sync handler +- [playback] `pipe`: create file if it doesn't already exist +- [playback] `Sink`: `write()` now receives ownership of the packet (breaking) ### Added -- [cache] Add `disable-credential-cache` flag (breaking). -- [main] Use different option descriptions and error messages based on what backends are enabled at build time. -- [main] Add a `-q`, `--quiet` option that changes the logging level to warn. -- [main] Add a short name for every flag and option. -- [main] Add the ability to parse environment variables. -- [playback] `pulseaudio`: set the PulseAudio name to match librespot's device name via `PULSE_PROP_application.name` environment variable (user set env var value takes precedence). (breaking) -- [playback] `pulseaudio`: set icon to `audio-x-generic` so we get an icon instead of a placeholder via `PULSE_PROP_application.icon_name` environment variable (user set env var value takes precedence). (breaking) -- [playback] `pulseaudio`: set values to: `PULSE_PROP_application.version`, `PULSE_PROP_application.process.binary`, `PULSE_PROP_stream.description`, `PULSE_PROP_media.software` and `PULSE_PROP_media.role` environment variables (user set env var values take precedence). (breaking) +- [main] Enforce reasonable ranges for option values (breaking) +- [main] Add the ability to parse environment variables +- [main] Log now emits warning when trying to use options that would otherwise have no effect +- [main] Verbose logging now logs all parsed environment variables and command line arguments (credentials are redacted) +- [main] Add a `-q`, `--quiet` option that changes the logging level to WARN +- [main] Add `disable-credential-cache` flag (breaking) +- [main] Add a short name for every flag and option +- [playback] `pulseaudio`: set the PulseAudio name to match librespot's device name via `PULSE_PROP_application.name` environment variable (user set env var value takes precedence) (breaking) +- [playback] `pulseaudio`: set icon to `audio-x-generic` so we get an icon instead of a placeholder via `PULSE_PROP_application.icon_name` environment variable (user set env var value takes precedence) (breaking) +- [playback] `pulseaudio`: set values to: `PULSE_PROP_application.version`, `PULSE_PROP_application.process.binary`, `PULSE_PROP_stream.description`, `PULSE_PROP_media.software` and `PULSE_PROP_media.role` environment variables (user set env var values take precedence) (breaking) ### Fixed -- [main] Prevent hang when discovery is disabled and there are no credentials or when bad credentials are given. -- [main] Don't panic when parsing options. Instead list valid values and exit. -- [main] `--alsa-mixer-device` and `--alsa-mixer-index` now fallback to the card and index specified in `--device`. +- [connect] Don't panic when activating shuffle without previous interaction - [core] Removed unsafe code (breaking) -- [playback] Adhere to ReplayGain spec when calculating gain normalisation factor. -- [playback] `alsa`: Use `--volume-range` overrides for softvol controls -- [connect] Don't panic when activating shuffle without previous interaction. -- [main] Fix crash when built with Avahi support but Avahi is locally unavailable. +- [main] Fix crash when built with Avahi support but Avahi is locally unavailable +- [main] Prevent hang when discovery is disabled and there are no credentials or when bad credentials are given +- [main] Don't panic when parsing options, instead list valid values and exit +- [main] `--alsa-mixer-device` and `--alsa-mixer-index` now fallback to the card and index specified in `--device`. +- [playback] Adhere to ReplayGain spec when calculating gain normalisation factor +- [playback] `alsa`: make `--volume-range` overrides apply to Alsa softvol controls ### Removed -- [playback] `alsamixer`: previously deprecated option `mixer-card` has been removed. -- [playback] `alsamixer`: previously deprecated option `mixer-name` has been removed. -- [playback] `alsamixer`: previously deprecated option `mixer-index` has been removed. +- [playback] `alsamixer`: previously deprecated options `mixer-card`, `mixer-name` and `mixer-index` have been removed ## [0.3.1] - 2021-10-24 @@ -119,7 +117,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [0.1.0] - 2019-11-06 -[unreleased]: https://github.com/librespot-org/librespot/compare/v0.3.1..HEAD +[0.4.0]: https://github.com/librespot-org/librespot/compare/v0.3.1..v0.4.0 [0.3.1]: https://github.com/librespot-org/librespot/compare/v0.3.0..v0.3.1 [0.3.0]: https://github.com/librespot-org/librespot/compare/v0.2.0..v0.3.0 [0.2.0]: https://github.com/librespot-org/librespot/compare/v0.1.6..v0.2.0 From dff19377fa5e3ca7e89b8bfb0bae278143e38251 Mon Sep 17 00:00:00 2001 From: Roderick van Domburg Date: Sat, 21 May 2022 22:31:15 +0200 Subject: [PATCH 23/39] Update version numbers to 0.4.0 --- Cargo.toml | 16 ++++++++-------- audio/Cargo.toml | 4 ++-- connect/Cargo.toml | 10 +++++----- core/Cargo.toml | 4 ++-- discovery/Cargo.toml | 4 ++-- metadata/Cargo.toml | 6 +++--- playback/Cargo.toml | 8 ++++---- protocol/Cargo.toml | 2 +- 8 files changed, 27 insertions(+), 27 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 8429ba2e..cc4c029e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "librespot" -version = "0.3.1" +version = "0.4.0" authors = ["Librespot Org"] license = "MIT" description = "An open source client library for Spotify, with support for Spotify Connect" @@ -22,31 +22,31 @@ doc = false [dependencies.librespot-audio] path = "audio" -version = "0.3.1" +version = "0.4.0" [dependencies.librespot-connect] path = "connect" -version = "0.3.1" +version = "0.4.0" [dependencies.librespot-core] path = "core" -version = "0.3.1" +version = "0.4.0" [dependencies.librespot-discovery] path = "discovery" -version = "0.3.1" +version = "0.4.0" [dependencies.librespot-metadata] path = "metadata" -version = "0.3.1" +version = "0.4.0" [dependencies.librespot-playback] path = "playback" -version = "0.3.1" +version = "0.4.0" [dependencies.librespot-protocol] path = "protocol" -version = "0.3.1" +version = "0.4.0" [dependencies] base64 = "0.13" diff --git a/audio/Cargo.toml b/audio/Cargo.toml index 77855e62..e60c1f40 100644 --- a/audio/Cargo.toml +++ b/audio/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "librespot-audio" -version = "0.3.1" +version = "0.4.0" authors = ["Paul Lietar "] description="The audio fetching and processing logic for librespot" license="MIT" @@ -8,7 +8,7 @@ edition = "2018" [dependencies.librespot-core] path = "../core" -version = "0.3.1" +version = "0.4.0" [dependencies] aes-ctr = "0.6" diff --git a/connect/Cargo.toml b/connect/Cargo.toml index 4daf89f4..c69df940 100644 --- a/connect/Cargo.toml +++ b/connect/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "librespot-connect" -version = "0.3.1" +version = "0.4.0" authors = ["Paul Lietar "] description = "The discovery and Spotify Connect logic for librespot" license = "MIT" @@ -20,19 +20,19 @@ tokio-stream = "0.1.1" [dependencies.librespot-core] path = "../core" -version = "0.3.1" +version = "0.4.0" [dependencies.librespot-playback] path = "../playback" -version = "0.3.1" +version = "0.4.0" [dependencies.librespot-protocol] path = "../protocol" -version = "0.3.1" +version = "0.4.0" [dependencies.librespot-discovery] path = "../discovery" -version = "0.3.1" +version = "0.4.0" [features] with-dns-sd = ["librespot-discovery/with-dns-sd"] diff --git a/core/Cargo.toml b/core/Cargo.toml index 2494a19a..bc3eba86 100644 --- a/core/Cargo.toml +++ b/core/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "librespot-core" -version = "0.3.1" +version = "0.4.0" authors = ["Paul Lietar "] build = "build.rs" description = "The core functionality provided by librespot" @@ -10,7 +10,7 @@ edition = "2018" [dependencies.librespot-protocol] path = "../protocol" -version = "0.3.1" +version = "0.4.0" [dependencies] aes = "0.6" diff --git a/discovery/Cargo.toml b/discovery/Cargo.toml index aebaf4df..beb094fb 100644 --- a/discovery/Cargo.toml +++ b/discovery/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "librespot-discovery" -version = "0.3.1" +version = "0.4.0" authors = ["Paul Lietar "] description = "The discovery logic for librespot" license = "MIT" @@ -27,7 +27,7 @@ dns-sd = { version = "0.1.3", optional = true } [dependencies.librespot-core] path = "../core" default_features = false -version = "0.3.1" +version = "0.4.0" [dev-dependencies] futures = "0.3" diff --git a/metadata/Cargo.toml b/metadata/Cargo.toml index 8eb7be8c..11992fa2 100644 --- a/metadata/Cargo.toml +++ b/metadata/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "librespot-metadata" -version = "0.3.1" +version = "0.4.0" authors = ["Paul Lietar "] description = "The metadata logic for librespot" license = "MIT" @@ -15,7 +15,7 @@ log = "0.4" [dependencies.librespot-core] path = "../core" -version = "0.3.1" +version = "0.4.0" [dependencies.librespot-protocol] path = "../protocol" -version = "0.3.1" +version = "0.4.0" diff --git a/playback/Cargo.toml b/playback/Cargo.toml index 516bd8af..42294107 100644 --- a/playback/Cargo.toml +++ b/playback/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "librespot-playback" -version = "0.3.1" +version = "0.4.0" authors = ["Sasha Hilton "] description = "The audio playback logic for librespot" license = "MIT" @@ -9,13 +9,13 @@ edition = "2018" [dependencies.librespot-audio] path = "../audio" -version = "0.3.1" +version = "0.4.0" [dependencies.librespot-core] path = "../core" -version = "0.3.1" +version = "0.4.0" [dependencies.librespot-metadata] path = "../metadata" -version = "0.3.1" +version = "0.4.0" [dependencies] futures-executor = "0.3" diff --git a/protocol/Cargo.toml b/protocol/Cargo.toml index 38f76371..005c2073 100644 --- a/protocol/Cargo.toml +++ b/protocol/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "librespot-protocol" -version = "0.3.1" +version = "0.4.0" authors = ["Paul Liétar "] build = "build.rs" description = "The protobuf logic for communicating with Spotify servers" From 8ad5a78bf6b85bd11879ef2781111b9980948131 Mon Sep 17 00:00:00 2001 From: Roderick van Domburg Date: Sat, 21 May 2022 22:51:30 +0200 Subject: [PATCH 24/39] Add repository URL --- audio/Cargo.toml | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/audio/Cargo.toml b/audio/Cargo.toml index e60c1f40..1c89c81b 100644 --- a/audio/Cargo.toml +++ b/audio/Cargo.toml @@ -2,8 +2,9 @@ name = "librespot-audio" version = "0.4.0" authors = ["Paul Lietar "] -description="The audio fetching and processing logic for librespot" -license="MIT" +description = "The audio fetching logic for librespot" +license = "MIT" +repository = "https://github.com/librespot-org/librespot" edition = "2018" [dependencies.librespot-core] From d596b16e5a1114f276d0e9325242f4891962f8a5 Mon Sep 17 00:00:00 2001 From: Roderick van Domburg Date: Sat, 21 May 2022 22:52:06 +0200 Subject: [PATCH 25/39] Expand publishing documentation --- PUBLISHING.md | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/PUBLISHING.md b/PUBLISHING.md index ceab506c..e38cd6d8 100644 --- a/PUBLISHING.md +++ b/PUBLISHING.md @@ -2,7 +2,17 @@ ## How To -The bash script in the root of the project, named `publish.sh` can be used to publish a new version of librespot and it's corresponding crates. the command should be used as follows: `./publish 0.1.0` from the project root, substituting the new version number that you wish to publish. *Note the lack of a v prefix on the version number. This is important, do not add one.* The v prefix is added where appropriate by the script. +Read through this paragraph in its entirety before running anything. + +The Bash script in the root of the project, named `publish.sh` can be used to publish a new version of librespot and it's corresponding crates. the command should be used as follows from the project root: `./publish 0.1.0` from the project root, substituting the new version number that you wish to publish. *Note the lack of a v prefix on the version number. This is important, do not add one.* The v prefix is added where appropriate by the script. + +Make sure that you are are starting from a clean working directory for both `dev` and `master`, completely up to date with remote and all local changes either committed and pushed or stashed. + +You will want to perform a dry run first: `./publish --dry-run 0.1.0`. Please make note of any errors or warnings. In particular, you may need to explicitly inform Git which remote you want to track for the `master` branch like so: `git --track origin/master` (or whatever you have called the `librespot-org` remote `master` branch). + +Depending on your system the script may fail to publish the main `librespot` crate after having published all the `librespot-xyz` sub-crates. If so then make sure the working directory is committed and pushed (watch `Cargo.toml`) and then run `cargo publish` manually after `publish.sh` finished. + +To publish the crates your GitHub account needs to be authorized on `crates.io` by `librespot-org`. ## What the script does From 5568c70cd1f1f704c1c65b92f3c5bba886233877 Mon Sep 17 00:00:00 2001 From: Roderick van Domburg Date: Sat, 21 May 2022 22:52:39 +0200 Subject: [PATCH 26/39] Prepare for new developments --- CHANGELOG.md | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index c0489ade..a50f6c45 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,16 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html) since v0.2.0. +## [Unreleased] + +### Changed + +### Added + +### Fixed + +### Removed + ## [0.4.0] - 2022-05-21 ### Changed @@ -117,6 +127,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [0.1.0] - 2019-11-06 +[unreleased]: https://github.com/librespot-org/librespot/compare/v0.4.0..HEAD [0.4.0]: https://github.com/librespot-org/librespot/compare/v0.3.1..v0.4.0 [0.3.1]: https://github.com/librespot-org/librespot/compare/v0.3.0..v0.3.1 [0.3.0]: https://github.com/librespot-org/librespot/compare/v0.2.0..v0.3.0 From c03d3ad1026e52291661a1912b2a122a26e59f7f Mon Sep 17 00:00:00 2001 From: JasonLG1979 Date: Mon, 23 May 2022 08:00:35 -0500 Subject: [PATCH 27/39] Bump deps This bumps deps that don't need major code refactoring or MSRV bumps. --- Cargo.lock | 92 +++++++++++++++++++++++++------------------- Cargo.toml | 4 +- core/Cargo.toml | 8 ++-- core/src/config.rs | 2 +- discovery/Cargo.toml | 2 +- playback/Cargo.toml | 4 +- src/main.rs | 2 +- 7 files changed, 64 insertions(+), 50 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index e3da3392..488fb209 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -293,9 +293,9 @@ dependencies = [ [[package]] name = "colored" -version = "1.9.3" +version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f4ffc801dacf156c5854b9df4f425a626539c3a6ef7893cc0c5084a23f0b6c59" +checksum = "b3616f750b84d8f0de8a58bda93e08e2a81ad3f523089b05f1dffecab48c6cbd" dependencies = [ "atty", "lazy_static", @@ -473,9 +473,9 @@ checksum = "e78d4f1cc4ae33bbfc157ed5d5a5ef3bc29227303d595861deb238fcec4e9457" [[package]] name = "env_logger" -version = "0.8.4" +version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a19187fea3ac7e84da7dacf48de0c45d63c6a76f9490dae389aead16c243fce3" +checksum = "0b2cf0344971ee6c64c31be0d530793fba457d322dfec2810c453d0ef228f9c3" dependencies = [ "atty", "humantime", @@ -495,9 +495,9 @@ dependencies = [ [[package]] name = "fixedbitset" -version = "0.2.0" +version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "37ab347416e802de484e4d03c7316c48f1ecb56574dfd4a46a80f173ce1de04d" +checksum = "279fb028e20b3c4c320317955b77c5e0c9701f05a1d309905d6fc702cdc5053e" [[package]] name = "fnv" @@ -1063,9 +1063,9 @@ dependencies = [ [[package]] name = "indexmap" -version = "1.8.1" +version = "1.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0f647032dfaa1f8b6dc29bd3edb7bbef4861b8b8007ebb118d6db284fd59f6ee" +checksum = "bc633605454125dec4b66843673f01c7df2b89479b32e0ed634e43a91cff62a5" dependencies = [ "autocfg", "hashbrown", @@ -1290,7 +1290,7 @@ dependencies = [ [[package]] name = "librespot" -version = "0.3.1" +version = "0.4.0" dependencies = [ "base64", "env_logger", @@ -1315,7 +1315,7 @@ dependencies = [ [[package]] name = "librespot-audio" -version = "0.3.1" +version = "0.4.0" dependencies = [ "aes-ctr", "byteorder", @@ -1329,7 +1329,7 @@ dependencies = [ [[package]] name = "librespot-connect" -version = "0.3.1" +version = "0.4.0" dependencies = [ "form_urlencoded", "futures-util", @@ -1348,7 +1348,7 @@ dependencies = [ [[package]] name = "librespot-core" -version = "0.3.1" +version = "0.4.0" dependencies = [ "aes", "base64", @@ -1388,7 +1388,7 @@ dependencies = [ [[package]] name = "librespot-discovery" -version = "0.3.1" +version = "0.4.0" dependencies = [ "aes-ctr", "base64", @@ -1412,7 +1412,7 @@ dependencies = [ [[package]] name = "librespot-metadata" -version = "0.3.1" +version = "0.4.0" dependencies = [ "async-trait", "byteorder", @@ -1424,7 +1424,7 @@ dependencies = [ [[package]] name = "librespot-playback" -version = "0.3.1" +version = "0.4.0" dependencies = [ "alsa", "byteorder", @@ -1444,7 +1444,7 @@ dependencies = [ "librespot-metadata", "log", "ogg", - "parking_lot 0.11.2", + "parking_lot 0.12.0", "portaudio-rs", "rand", "rand_distr", @@ -1458,7 +1458,7 @@ dependencies = [ [[package]] name = "librespot-protocol" -version = "0.3.1" +version = "0.4.0" dependencies = [ "glob", "protobuf", @@ -1791,9 +1791,9 @@ dependencies = [ [[package]] name = "once_cell" -version = "1.11.0" +version = "1.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7b10983b38c53aebdf33f542c6275b0f58a238129d00c4ae0e6fb59738d783ca" +checksum = "7709cef83f0c1f58f666e746a08b21e0085f7440fa6a29cc194d68aac97a4225" [[package]] name = "opaque-debug" @@ -1828,14 +1828,11 @@ version = "0.8.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d76e8e1493bcac0d2766c42737f34458f1c8c50c0d23bcb24ea953affb273216" dependencies = [ - "backtrace", "cfg-if 1.0.0", "instant", "libc", - "petgraph", "redox_syscall", "smallvec", - "thread-id", "winapi", ] @@ -1845,10 +1842,13 @@ version = "0.9.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "09a279cbf25cb0757810394fbc1e359949b59e348145c643a939a525692e6929" dependencies = [ + "backtrace", "cfg-if 1.0.0", "libc", + "petgraph", "redox_syscall", "smallvec", + "thread-id", "windows-sys", ] @@ -1882,9 +1882,9 @@ checksum = "d4fd5641d01c8f18a23da7b6fe29298ff4b55afcccdf78973b24cf3175fee32e" [[package]] name = "petgraph" -version = "0.5.1" +version = "0.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "467d164a6de56270bd7c4d070df81d07beace25012d5103ced4e9ff08d6afdb7" +checksum = "51b305cc4569dd4e8765bab46261f67ef5d4d11a4b6e745100ee5dad8948b46c" dependencies = [ "fixedbitset", "indexmap", @@ -1943,9 +1943,9 @@ checksum = "bc5c99d529f0d30937f6f4b8a86d988047327bb88d04d2c4afc356de74722131" [[package]] name = "priority-queue" -version = "1.2.1" +version = "1.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "00ba480ac08d3cfc40dea10fd466fd2c14dee3ea6fc7873bc4079eda2727caf0" +checksum = "de9cde7493f5f5d2d163b174be9f9a72d756b79b0f6ed85654128d238c347c1e" dependencies = [ "autocfg", "indexmap", @@ -2123,11 +2123,13 @@ dependencies = [ [[package]] name = "rpassword" -version = "5.0.1" +version = "6.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ffc936cf8a7ea60c58f030fd36a612a48f440610214dc54bc36431f9ea0c3efb" +checksum = "2bf099a1888612545b683d2661a1940089f6c2e5a8e38979b2159da876bfd956" dependencies = [ "libc", + "serde", + "serde_json", "winapi", ] @@ -2289,9 +2291,9 @@ dependencies = [ [[package]] name = "simple_logger" -version = "1.16.0" +version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "45b60258a35dc3cb8a16890b8fd6723349bfa458d7960e25e633f1b1c19d7b5e" +checksum = "c75a9723083573ace81ad0cdfc50b858aa3c366c48636edb4109d73122a0c0ea" dependencies = [ "atty", "colored", @@ -2573,16 +2575,16 @@ dependencies = [ [[package]] name = "tokio-util" -version = "0.6.10" +version = "0.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "36943ee01a6d67977dd3f84a5a1d2efeb4ada3a1ae771cadfaa535d9d9fc6507" +checksum = "f988a1a1adc2fb21f9c12aa96441da33a1728193ae0b95d2be22dbd17fcb4e5c" dependencies = [ "bytes", "futures-core", "futures-sink", - "log", "pin-project-lite", "tokio", + "tracing", ] [[package]] @@ -2608,9 +2610,21 @@ checksum = "5d0ecdcb44a79f0fe9844f0c4f33a342cbcbb5117de8001e6ba0dc2351327d09" dependencies = [ "cfg-if 1.0.0", "pin-project-lite", + "tracing-attributes", "tracing-core", ] +[[package]] +name = "tracing-attributes" +version = "0.1.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cc6b8ad3567499f98a1db7a752b07a7c8c7c7c34c332ec00effb2b0027974b7c" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "tracing-core" version = "0.1.26" @@ -2685,9 +2699,9 @@ dependencies = [ [[package]] name = "uuid" -version = "0.8.2" +version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bc5cf98d8186244414c848017f0e2676b3fcb46807f6668a97dfe67359a3c4b7" +checksum = "8cfcd319456c4d6ea10087ed423473267e1a071f3bc0aa89f80d60997843c6f0" dependencies = [ "getrandom", ] @@ -2894,9 +2908,9 @@ checksum = "c811ca4a8c853ef420abd8592ba53ddbbac90410fab6903b3e79972a631f7680" [[package]] name = "zerocopy" -version = "0.3.0" +version = "0.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6580539ad917b7c026220c4b3f2c08d52ce54d6ce0dc491e66002e35388fab46" +checksum = "332f188cc1bcf1fe1064b8c58d150f497e697f49774aa846f2dc949d9a25f236" dependencies = [ "byteorder", "zerocopy-derive", @@ -2904,9 +2918,9 @@ dependencies = [ [[package]] name = "zerocopy-derive" -version = "0.2.0" +version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d498dbd1fd7beb83c86709ae1c33ca50942889473473d287d56ce4770a18edfb" +checksum = "a0fbc82b82efe24da867ee52e015e58178684bd9dd64c34e66bdf21da2582a9f" dependencies = [ "proc-macro2", "syn", diff --git a/Cargo.toml b/Cargo.toml index cc4c029e..0f966ba6 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -50,13 +50,13 @@ version = "0.4.0" [dependencies] base64 = "0.13" -env_logger = {version = "0.8", default-features = false, features = ["termcolor","humantime","atty"]} +env_logger = {version = "0.9", default-features = false, features = ["termcolor","humantime","atty"]} futures-util = { version = "0.3", default_features = false } getopts = "0.2.21" hex = "0.4" hyper = "0.14" log = "0.4" -rpassword = "5.0" +rpassword = "6.0" thiserror = "1.0" tokio = { version = "1", features = ["rt", "rt-multi-thread", "macros", "signal", "sync", "process"] } url = "2.2" diff --git a/core/Cargo.toml b/core/Cargo.toml index bc3eba86..8ebcbf6a 100644 --- a/core/Cargo.toml +++ b/core/Cargo.toml @@ -31,7 +31,7 @@ num-integer = "0.1" num-traits = "0.2" once_cell = "1.5.2" pbkdf2 = { version = "0.8", default-features = false, features = ["hmac"] } -priority-queue = "1.1" +priority-queue = "1.2" protobuf = "2.14.0" rand = "0.8" serde = { version = "1.0", features = ["derive"] } @@ -41,14 +41,14 @@ shannon = "0.2.0" thiserror = "1.0.7" tokio = { version = "1.0", features = ["io-util", "net", "rt", "sync"] } tokio-stream = "0.1.1" -tokio-util = { version = "0.6", features = ["codec"] } +tokio-util = { version = "0.7", features = ["codec"] } url = "2.1" -uuid = { version = "0.8", default-features = false, features = ["v4"] } +uuid = { version = "1.0", default-features = false, features = ["v4"] } [build-dependencies] rand = "0.8" vergen = "3.0.4" [dev-dependencies] -env_logger = "0.8" +env_logger = "0.9" tokio = {version = "1.0", features = ["macros"] } diff --git a/core/src/config.rs b/core/src/config.rs index b8c448c2..8ead5654 100644 --- a/core/src/config.rs +++ b/core/src/config.rs @@ -12,7 +12,7 @@ pub struct SessionConfig { impl Default for SessionConfig { fn default() -> SessionConfig { - let device_id = uuid::Uuid::new_v4().to_hyphenated().to_string(); + let device_id = uuid::Uuid::new_v4().as_hyphenated().to_string(); SessionConfig { user_agent: crate::version::VERSION_STRING.to_string(), device_id, diff --git a/discovery/Cargo.toml b/discovery/Cargo.toml index beb094fb..4810c6ea 100644 --- a/discovery/Cargo.toml +++ b/discovery/Cargo.toml @@ -32,7 +32,7 @@ version = "0.4.0" [dev-dependencies] futures = "0.3" hex = "0.4" -simple_logger = "1.11" +simple_logger = "2.1" tokio = { version = "1.0", features = ["macros", "rt"] } [features] diff --git a/playback/Cargo.toml b/playback/Cargo.toml index 42294107..63e7f27f 100644 --- a/playback/Cargo.toml +++ b/playback/Cargo.toml @@ -21,11 +21,11 @@ version = "0.4.0" futures-executor = "0.3" futures-util = { version = "0.3", default_features = false, features = ["alloc"] } log = "0.4" -parking_lot = { version = "0.11", features = ["deadlock_detection"] } +parking_lot = { version = "0.12", features = ["deadlock_detection"] } byteorder = "1.4" shell-words = "1.0.0" tokio = { version = "1", features = ["sync", "parking_lot"] } -zerocopy = { version = "0.3" } +zerocopy = { version = "0.6" } thiserror = { version = "1" } # Backends diff --git a/src/main.rs b/src/main.rs index 9a1427bc..5e4b0bb5 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1053,7 +1053,7 @@ fn get_setup() -> Setup { Some(creds) if username == creds.username => Some(creds), _ => { let prompt = &format!("Password for {}: ", username); - match rpassword::prompt_password_stderr(prompt) { + match rpassword::prompt_password(prompt) { Ok(password) => { if !password.is_empty() { Some(Credentials::with_password(username, password)) From 0b7508a2bfe9e7fb52f313b48b7e202ada23100b Mon Sep 17 00:00:00 2001 From: JasonLG1979 Date: Mon, 23 May 2022 13:14:43 -0500 Subject: [PATCH 28/39] Update deps round 2 --- Cargo.lock | 461 ++++++++++------------------- playback/Cargo.toml | 18 +- playback/src/audio_backend/alsa.rs | 5 +- playback/src/audio_backend/sdl.rs | 9 +- 4 files changed, 177 insertions(+), 316 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 488fb209..39b34a77 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -71,9 +71,9 @@ dependencies = [ [[package]] name = "alsa" -version = "0.5.0" +version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "75c4da790adcb2ce5e758c064b4f3ec17a30349f9961d3e5e6c9688b052a9e18" +checksum = "5915f52fe2cf65e83924d037b6c5290b7cee097c6b5c8700746e6168a343fd6b" dependencies = [ "alsa-sys", "bitflags", @@ -139,7 +139,7 @@ checksum = "11a17d453482a265fd5f8479f2a3f405566e6ca627837aaddb85af8b1ab8ef61" dependencies = [ "addr2line", "cc", - "cfg-if 1.0.0", + "cfg-if", "libc", "miniz_oxide", "object", @@ -239,19 +239,13 @@ dependencies = [ [[package]] name = "cfg-expr" -version = "0.8.1" +version = "0.10.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b412e83326147c2bb881f8b40edfbf9905b9b8abaebd0e47ca190ba62fda8f0e" +checksum = "0aacacf4d96c24b2ad6eb8ee6df040e4f27b0d0b39a5710c30091baa830485db" dependencies = [ "smallvec", ] -[[package]] -name = "cfg-if" -version = "0.1.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822" - [[package]] name = "cfg-if" version = "1.0.0" @@ -339,20 +333,20 @@ dependencies = [ [[package]] name = "cpal" -version = "0.13.4" +version = "0.13.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "98f45f0a21f617cd2c788889ef710b63f075c949259593ea09c826f1e47a2418" +checksum = "74117836a5124f3629e4b474eed03e479abaf98988b4bb317e29f08cfe0e4116" dependencies = [ "alsa", "core-foundation-sys", "coreaudio-rs", - "jack", + "jack 0.8.3", "jni", "js-sys", "lazy_static", "libc", "mach", - "ndk 0.3.0", + "ndk", "ndk-glue", "nix", "oboe", @@ -403,9 +397,9 @@ dependencies = [ [[package]] name = "darling" -version = "0.10.2" +version = "0.13.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0d706e75d87e35569db781a9b5e2416cff1236a47ed380831f959382ccd5f858" +checksum = "a01d95850c592940db9b8194bc39f4bc0e89dee5c4265e4b1807c34a9aba453c" dependencies = [ "darling_core", "darling_macro", @@ -413,9 +407,9 @@ dependencies = [ [[package]] name = "darling_core" -version = "0.10.2" +version = "0.13.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f0c960ae2da4de88a91b2d920c2a7233b400bc33cb28453a2987822d8392519b" +checksum = "859d65a907b6852c9361e3185c862aae7fafd2887876799fa55f5f99dc40d610" dependencies = [ "fnv", "ident_case", @@ -427,9 +421,9 @@ dependencies = [ [[package]] name = "darling_macro" -version = "0.10.2" +version = "0.13.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d9b5a2f4ac4969822c62224815d069952656cadc7084fdca9751e6d959189b72" +checksum = "9c972679f83bdf9c42bd905396b6c3588a843a17f0f16dfcfa3e2c5d57441835" dependencies = [ "darling_core", "quote", @@ -465,12 +459,6 @@ dependencies = [ "pkg-config", ] -[[package]] -name = "either" -version = "1.6.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e78d4f1cc4ae33bbfc157ed5d5a5ef3bc29227303d595861deb238fcec4e9457" - [[package]] name = "env_logger" version = "0.9.0" @@ -629,7 +617,7 @@ version = "0.2.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9be70c98951c83b8d2f8f60d7065fa6d5146873094452a1008da8c2f1e4205ad" dependencies = [ - "cfg-if 1.0.0", + "cfg-if", "libc", "wasi 0.10.2+wasi-snapshot-preview1", ] @@ -642,67 +630,33 @@ checksum = "78cc372d058dcf6d5ecd98510e7fbc9e5aec4d21de70f65fea8fecebcd881bd4" [[package]] name = "glib" -version = "0.10.3" +version = "0.15.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0c685013b7515e668f1b57a165b009d4d28cb139a8a989bbd699c10dad29d0c5" +checksum = "bd124026a2fa8c33a3d17a3fe59c103f2d9fa5bd92c19e029e037736729abeab" dependencies = [ "bitflags", "futures-channel", "futures-core", "futures-executor", "futures-task", - "futures-util", - "glib-macros 0.10.1", - "glib-sys 0.10.1", - "gobject-sys 0.10.0", - "libc", - "once_cell", -] - -[[package]] -name = "glib" -version = "0.14.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7c515f1e62bf151ef6635f528d05b02c11506de986e43b34a5c920ef0b3796a4" -dependencies = [ - "bitflags", - "futures-channel", - "futures-core", - "futures-executor", - "futures-task", - "glib-macros 0.14.1", - "glib-sys 0.14.0", - "gobject-sys 0.14.0", + "glib-macros", + "glib-sys", + "gobject-sys", "libc", "once_cell", "smallvec", + "thiserror", ] [[package]] name = "glib-macros" -version = "0.10.1" +version = "0.15.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "41486a26d1366a8032b160b59065a59fb528530a46a49f627e7048fb8c064039" +checksum = "25a68131a662b04931e71891fb14aaf65ee4b44d08e8abc10f49e77418c86c64" dependencies = [ "anyhow", "heck", - "itertools 0.9.0", - "proc-macro-crate 0.1.5", - "proc-macro-error", - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "glib-macros" -version = "0.14.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2aad66361f66796bfc73f530c51ef123970eb895ffba991a234fcf7bea89e518" -dependencies = [ - "anyhow", - "heck", - "proc-macro-crate 1.1.3", + "proc-macro-crate", "proc-macro-error", "proc-macro2", "quote", @@ -711,22 +665,12 @@ dependencies = [ [[package]] name = "glib-sys" -version = "0.10.1" +version = "0.15.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c7e9b997a66e9a23d073f2b1abb4dbfc3925e0b8952f67efd8d9b6e168e4cdc1" +checksum = "ef4b192f8e65e9cf76cbf4ea71fa8e3be4a0e18ffe3d68b8da6836974cc5bad4" dependencies = [ "libc", - "system-deps 1.3.2", -] - -[[package]] -name = "glib-sys" -version = "0.14.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1c1d60554a212445e2a858e42a0e48cece1bd57b311a19a9468f70376cf554ae" -dependencies = [ - "libc", - "system-deps 3.2.0", + "system-deps", ] [[package]] @@ -737,44 +681,34 @@ checksum = "9b919933a397b79c37e33b77bb2aa3dc8eb6e165ad809e58ff75bc7db2e34574" [[package]] name = "gobject-sys" -version = "0.10.0" +version = "0.15.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "952133b60c318a62bf82ee75b93acc7e84028a093e06b9e27981c2b6fe68218c" +checksum = "0d57ce44246becd17153bd035ab4d32cfee096a657fc01f2231c9278378d1e0a" dependencies = [ - "glib-sys 0.10.1", + "glib-sys", "libc", - "system-deps 1.3.2", -] - -[[package]] -name = "gobject-sys" -version = "0.14.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aa92cae29759dae34ab5921d73fff5ad54b3d794ab842c117e36cafc7994c3f5" -dependencies = [ - "glib-sys 0.14.0", - "libc", - "system-deps 3.2.0", + "system-deps", ] [[package]] name = "gstreamer" -version = "0.17.4" +version = "0.18.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c6a255f142048ba2c4a4dce39106db1965abe355d23f4b5335edea43a553faa4" +checksum = "d66363bacf5e4f6eb281564adc2902e44c52ae5c45082423e7439e9012b75456" dependencies = [ "bitflags", - "cfg-if 1.0.0", + "cfg-if", "futures-channel", "futures-core", "futures-util", - "glib 0.14.8", + "glib", "gstreamer-sys", "libc", "muldiv", "num-integer", "num-rational", "once_cell", + "option-operations", "paste", "pretty-hex", "thiserror", @@ -782,14 +716,14 @@ dependencies = [ [[package]] name = "gstreamer-app" -version = "0.17.2" +version = "0.18.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f73b8d33b1bbe9f22d0cf56661a1d2a2c9a0e099ea10e5f1f347be5038f5c043" +checksum = "664adf6abc6546c1ad54492a067dcbc605032c9c789ce8f6f78cb9ddeef4b684" dependencies = [ "bitflags", "futures-core", "futures-sink", - "glib 0.14.8", + "glib", "gstreamer", "gstreamer-app-sys", "gstreamer-base", @@ -799,27 +733,27 @@ dependencies = [ [[package]] name = "gstreamer-app-sys" -version = "0.17.0" +version = "0.18.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "41865cfb8a5ddfa1161734a0d068dcd4689da852be0910b40484206408cfeafa" +checksum = "c3b401f21d731b3e5de802487f25507fabd34de2dd007d582f440fb1c66a4fbb" dependencies = [ - "glib-sys 0.14.0", + "glib-sys", "gstreamer-base-sys", "gstreamer-sys", "libc", - "system-deps 3.2.0", + "system-deps", ] [[package]] name = "gstreamer-audio" -version = "0.17.2" +version = "0.18.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "420b6bcb1759231f01172751da094e7afa5cd9edf40bee7475f5bc86df433c57" +checksum = "9ceb43e669be4c33c38b273fd4ca0511c0a7748987835233c529fc3c805c807e" dependencies = [ "array-init", "bitflags", - "cfg-if 1.0.0", - "glib 0.14.8", + "cfg-if", + "glib", "gstreamer", "gstreamer-audio-sys", "gstreamer-base", @@ -829,27 +763,27 @@ dependencies = [ [[package]] name = "gstreamer-audio-sys" -version = "0.17.0" +version = "0.18.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d066ddfd05f63836f35ac4a5830d5bb2f7f3d6c33c870e9b15c667d20f65d7f6" +checksum = "a34258fb53c558c0f41dad194037cbeaabf49d347570df11b8bd1c4897cf7d7c" dependencies = [ - "glib-sys 0.14.0", - "gobject-sys 0.14.0", + "glib-sys", + "gobject-sys", "gstreamer-base-sys", "gstreamer-sys", "libc", - "system-deps 3.2.0", + "system-deps", ] [[package]] name = "gstreamer-base" -version = "0.17.2" +version = "0.18.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2c0c1d8c62eb5d08fb80173609f2eea71d385393363146e4e78107facbd67715" +checksum = "224f35f36582407caf58ded74854526beeecc23d0cf64b8d1c3e00584ed6863f" dependencies = [ "bitflags", - "cfg-if 1.0.0", - "glib 0.14.8", + "cfg-if", + "glib", "gstreamer", "gstreamer-base-sys", "libc", @@ -857,27 +791,27 @@ dependencies = [ [[package]] name = "gstreamer-base-sys" -version = "0.17.0" +version = "0.18.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "28169a7b58edb93ad8ac766f0fa12dcd36a2af4257a97ee10194c7103baf3e27" +checksum = "a083493c3c340e71fa7c66eebda016e9fafc03eb1b4804cf9b2bad61994b078e" dependencies = [ - "glib-sys 0.14.0", - "gobject-sys 0.14.0", + "glib-sys", + "gobject-sys", "gstreamer-sys", "libc", - "system-deps 3.2.0", + "system-deps", ] [[package]] name = "gstreamer-sys" -version = "0.17.3" +version = "0.18.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a81704feeb3e8599913bdd1e738455c2991a01ff4a1780cb62200993e454cc3e" +checksum = "e3517a65d3c2e6f8905b456eba5d53bda158d664863aef960b44f651cb7d33e2" dependencies = [ - "glib-sys 0.14.0", - "gobject-sys 0.14.0", + "glib-sys", + "gobject-sys", "libc", - "system-deps 3.2.0", + "system-deps", ] [[package]] @@ -913,12 +847,9 @@ dependencies = [ [[package]] name = "heck" -version = "0.3.3" +version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6d621efb26863f0e9924c6ac577e8275e5e6b77455db64ffa6c65c904e9e132c" -dependencies = [ - "unicode-segmentation", -] +checksum = "2540771e65fc8cb83cd6e8a237f70c319bd5c29f78ed1084ba5d50eeac86f7f9" [[package]] name = "hermit-abi" @@ -1077,25 +1008,7 @@ version = "0.1.12" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7a5bbe824c507c5da5956355e86a746d82e0e1464f65d862cc5e71da70e94b2c" dependencies = [ - "cfg-if 1.0.0", -] - -[[package]] -name = "itertools" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "284f18f85651fe11e8a991b2adb42cb078325c996ed026d994719efcfca1d54b" -dependencies = [ - "either", -] - -[[package]] -name = "itertools" -version = "0.10.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a9a9d19fa1e79b6215ff29b9d6880b706147f16e9b1dbb1e4e5947b5b02bc5e3" -dependencies = [ - "either", + "cfg-if", ] [[package]] @@ -1106,12 +1019,25 @@ checksum = "112c678d4050afce233f4f2852bb2eb519230b3cf12f33585275537d7e41578d" [[package]] name = "jack" -version = "0.7.3" +version = "0.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d79b205ea723e478eb31a91dcdda100912c69cc32992eb7ba26ec0bbae7bebe4" +checksum = "b3902a02287c3dcad784edd1ecc5f487774b63a5fe77dd9842ea9a993d0a4a23" dependencies = [ "bitflags", - "jack-sys", + "jack-sys 0.2.2", + "lazy_static", + "libc", + "log", +] + +[[package]] +name = "jack" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ce722655a29b13bb98ec7e8ba9dc65d670b9b37c7b1c09775c7f7516811c5a36" +dependencies = [ + "bitflags", + "jack-sys 0.4.0", "lazy_static", "libc", "log", @@ -1119,13 +1045,25 @@ dependencies = [ [[package]] name = "jack-sys" -version = "0.2.3" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7b91f2d2d10bc2bab38f4dfa4bc77123a988828af39dd3f30dd9db14d44f2cc1" +checksum = "57983f0d72dfecf2b719ed39bc9cacd85194e1a94cb3f9146009eff9856fef41" dependencies = [ "lazy_static", "libc", "libloading 0.6.7", +] + +[[package]] +name = "jack-sys" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e9d70559ff166d148ccb750ddd77702af760718f3a752c731add168c22c16a9f" +dependencies = [ + "bitflags", + "lazy_static", + "libc", + "libloading 0.7.3", "pkg-config", ] @@ -1202,7 +1140,7 @@ version = "0.6.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "351a32417a12d5f7e82c368a66781e307834dae04c6ce0cd4456d52989229883" dependencies = [ - "cfg-if 1.0.0", + "cfg-if", "winapi", ] @@ -1212,7 +1150,7 @@ version = "0.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "efbc0f03f9a775e9f6aed295c6a1ba2253c5757a9e03d55c6caa46a681abcddd" dependencies = [ - "cfg-if 1.0.0", + "cfg-if", "winapi", ] @@ -1431,11 +1369,11 @@ dependencies = [ "cpal", "futures-executor", "futures-util", - "glib 0.10.3", + "glib", "gstreamer", "gstreamer-app", "gstreamer-audio", - "jack", + "jack 0.10.0", "lewton", "libpulse-binding", "libpulse-simple-binding", @@ -1481,7 +1419,7 @@ version = "0.4.17" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "abb12e687cfb44aa40f41fc3978ef76448f9b6038cad6aef4259d3c095a2382e" dependencies = [ - "cfg-if 1.0.0", + "cfg-if", ] [[package]] @@ -1511,6 +1449,15 @@ version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d" +[[package]] +name = "memoffset" +version = "0.6.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5aa361d4faea93603064a027415f07bd8e1d5c88c9fbf68bf56a285428fd79ce" +dependencies = [ + "autocfg", +] + [[package]] name = "mime" version = "0.3.16" @@ -1559,18 +1506,6 @@ dependencies = [ "serde", ] -[[package]] -name = "ndk" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8794322172319b972f528bf90c6b467be0079f1fa82780ffb431088e741a73ab" -dependencies = [ - "jni-sys", - "ndk-sys 0.2.2", - "num_enum", - "thiserror", -] - [[package]] name = "ndk" version = "0.6.0" @@ -1579,7 +1514,7 @@ checksum = "2032c77e030ddee34a6787a64166008da93f6a352b629261d0fee232b8742dd4" dependencies = [ "bitflags", "jni-sys", - "ndk-sys 0.3.0", + "ndk-sys", "num_enum", "thiserror", ] @@ -1592,37 +1527,32 @@ checksum = "27b02d87554356db9e9a873add8782d4ea6e3e58ea071a9adb9a2e8ddb884a8b" [[package]] name = "ndk-glue" -version = "0.3.0" +version = "0.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c5caf0c24d51ac1c905c27d4eda4fa0635bbe0de596b8f79235e0b17a4d29385" +checksum = "0d0c4a7b83860226e6b4183edac21851f05d5a51756e97a1144b7f5a6b63e65f" dependencies = [ "lazy_static", "libc", "log", - "ndk 0.3.0", + "ndk", + "ndk-context", "ndk-macro", - "ndk-sys 0.2.2", + "ndk-sys", ] [[package]] name = "ndk-macro" -version = "0.2.0" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "05d1c6307dc424d0f65b9b06e94f88248e6305726b14729fd67a5e47b2dc481d" +checksum = "0df7ac00c4672f9d5aece54ee3347520b7e20f158656c7db2e6de01902eb7a6c" dependencies = [ "darling", - "proc-macro-crate 0.1.5", + "proc-macro-crate", "proc-macro2", "quote", "syn", ] -[[package]] -name = "ndk-sys" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e1bcdd74c20ad5d95aacd60ef9ba40fdf77f767051040541df557b7a9b2a2121" - [[package]] name = "ndk-sys" version = "0.3.0" @@ -1634,14 +1564,15 @@ dependencies = [ [[package]] name = "nix" -version = "0.20.0" +version = "0.23.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fa9b4819da1bc61c0ea48b63b7bc8604064dd43013e7cc325df098d49cd7c18a" +checksum = "9f866317acbd3a240710c63f065ffb1e4fd466259045ccb504130b7f668f35c6" dependencies = [ "bitflags", "cc", - "cfg-if 1.0.0", + "cfg-if", "libc", + "memoffset", ] [[package]] @@ -1733,7 +1664,7 @@ version = "0.5.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3b0498641e53dd6ac1a4f22547548caa6864cc4933784319cd1775271c5a46ce" dependencies = [ - "proc-macro-crate 1.1.3", + "proc-macro-crate", "proc-macro2", "quote", "syn", @@ -1764,7 +1695,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "27f63c358b4fa0fbcfefd7c8be5cfc39c08ce2389f5325687e7762a48d30a5c1" dependencies = [ "jni", - "ndk 0.6.0", + "ndk", "ndk-context", "num-derive", "num-traits", @@ -1801,6 +1732,15 @@ version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "624a8340c38c1b80fd549087862da4ba43e08858af025b236e509b6649fc13d5" +[[package]] +name = "option-operations" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "95d6113415f41b268f1195907427519769e40ee6f28cbb053795098a2c16f447" +dependencies = [ + "paste", +] + [[package]] name = "parking_lot" version = "0.11.2" @@ -1828,7 +1768,7 @@ version = "0.8.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d76e8e1493bcac0d2766c42737f34458f1c8c50c0d23bcb24ea953affb273216" dependencies = [ - "cfg-if 1.0.0", + "cfg-if", "instant", "libc", "redox_syscall", @@ -1843,7 +1783,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "09a279cbf25cb0757810394fbc1e359949b59e348145c643a939a525692e6929" dependencies = [ "backtrace", - "cfg-if 1.0.0", + "cfg-if", "libc", "petgraph", "redox_syscall", @@ -1937,9 +1877,9 @@ checksum = "eb9f9e6e233e5c4a35559a617bf40a4ec447db2e84c20b55a6f83167b7e57872" [[package]] name = "pretty-hex" -version = "0.2.1" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bc5c99d529f0d30937f6f4b8a86d988047327bb88d04d2c4afc356de74722131" +checksum = "c6fa0831dd7cc608c38a5e323422a0077678fa5744aa2be4ad91c4ece8eec8d5" [[package]] name = "priority-queue" @@ -1951,15 +1891,6 @@ dependencies = [ "indexmap", ] -[[package]] -name = "proc-macro-crate" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1d6ea3c4595b96363c13943497db34af4460fb474a95c43f4446ad341b8c9785" -dependencies = [ - "toml", -] - [[package]] name = "proc-macro-crate" version = "1.1.3" @@ -2114,9 +2045,9 @@ dependencies = [ [[package]] name = "rodio" -version = "0.14.0" +version = "0.15.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4d98f5e557b61525057e2bc142c8cd7f0e70d75dc32852309bec440e6e046bf9" +checksum = "ec0939e9f626e6c6f1989adb6226a039c855ca483053f0ee7c98b90e41cf731e" dependencies = [ "cpal", ] @@ -2177,9 +2108,9 @@ checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" [[package]] name = "sdl2" -version = "0.34.5" +version = "0.35.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "deecbc3fa9460acff5a1e563e05cb5f31bba0aa0c214bb49a43db8159176d54b" +checksum = "f7959277b623f1fb9e04aea73686c3ca52f01b2145f8ea16f4ff30d8b7623b1a" dependencies = [ "bitflags", "lazy_static", @@ -2189,13 +2120,13 @@ dependencies = [ [[package]] name = "sdl2-sys" -version = "0.34.5" +version = "0.35.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "41a29aa21f175b5a41a6e26da572d5e5d1ee5660d35f9f9d0913e8a802098f74" +checksum = "e3586be2cf6c0a8099a79a12b4084357aa9b3e0b0d7980e3b67aaf7a9d55f9f0" dependencies = [ - "cfg-if 0.1.10", + "cfg-if", "libc", - "version-compare 0.0.10", + "version-compare", ] [[package]] @@ -2242,7 +2173,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "99cd6713db3cf16b6c84e06321e049a9b9f699826e16096d23bbcc44d15d51a6" dependencies = [ "block-buffer 0.9.0", - "cfg-if 1.0.0", + "cfg-if", "cpufeatures", "digest 0.9.0", "opaque-debug", @@ -2254,7 +2185,7 @@ version = "0.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "028f48d513f9678cda28f6e4064755b3fbb2af6acd672f2c209b62323f7aea0f" dependencies = [ - "cfg-if 1.0.0", + "cfg-if", "cpufeatures", "digest 0.10.3", ] @@ -2332,45 +2263,9 @@ checksum = "ef5430c8e36b713e13b48a9f709cc21e046723fe44ce34587b73a830203b533e" [[package]] name = "strsim" -version = "0.9.3" +version = "0.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6446ced80d6c486436db5c078dde11a9f73d42b57fb273121e160b84f63d894c" - -[[package]] -name = "strum" -version = "0.18.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "57bd81eb48f4c437cadc685403cad539345bf703d78e63707418431cecd4522b" - -[[package]] -name = "strum" -version = "0.21.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aaf86bbcfd1fa9670b7a129f64fc0c9fcbbfe4f1bc4210e9e98fe71ffc12cde2" - -[[package]] -name = "strum_macros" -version = "0.18.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87c85aa3f8ea653bfd3ddf25f7ee357ee4d204731f6aa9ad04002306f6e2774c" -dependencies = [ - "heck", - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "strum_macros" -version = "0.21.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d06aaeeee809dbc59eb4556183dd927df67db1540de5be8d3ec0b6636358a5ec" -dependencies = [ - "heck", - "proc-macro2", - "quote", - "syn", -] +checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623" [[package]] name = "subtle" @@ -2403,35 +2298,15 @@ dependencies = [ [[package]] name = "system-deps" -version = "1.3.2" +version = "6.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0f3ecc17269a19353b3558b313bba738b25d82993e30d62a18406a24aba4649b" +checksum = "a1a45a1c4c9015217e12347f2a411b57ce2c4fc543913b14b6fe40483328e709" dependencies = [ - "heck", - "pkg-config", - "strum 0.18.0", - "strum_macros 0.18.0", - "thiserror", - "toml", - "version-compare 0.0.10", -] - -[[package]] -name = "system-deps" -version = "3.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "480c269f870722b3b08d2f13053ce0c2ab722839f472863c3e2d61ff3a1c2fa6" -dependencies = [ - "anyhow", "cfg-expr", "heck", - "itertools 0.10.3", "pkg-config", - "strum 0.21.0", - "strum_macros 0.21.1", - "thiserror", "toml", - "version-compare 0.0.11", + "version-compare", ] [[package]] @@ -2440,7 +2315,7 @@ version = "3.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5cdb1ef4eaeeaddc8fbd371e5017057064af0911902ef36b39801f67cc6d79e4" dependencies = [ - "cfg-if 1.0.0", + "cfg-if", "fastrand", "libc", "redox_syscall", @@ -2608,7 +2483,7 @@ version = "0.1.34" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5d0ecdcb44a79f0fe9844f0c4f33a342cbcbb5117de8001e6ba0dc2351327d09" dependencies = [ - "cfg-if 1.0.0", + "cfg-if", "pin-project-lite", "tracing-attributes", "tracing-core", @@ -2667,12 +2542,6 @@ dependencies = [ "tinyvec", ] -[[package]] -name = "unicode-segmentation" -version = "1.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7e8820f5d777f6224dc4be3632222971ac30164d4a258d595640799554ebfd99" - [[package]] name = "unicode-width" version = "0.1.9" @@ -2719,15 +2588,9 @@ dependencies = [ [[package]] name = "version-compare" -version = "0.0.10" +version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d63556a25bae6ea31b52e640d7c41d1ab27faba4ccb600013837a3d0b3994ca1" - -[[package]] -name = "version-compare" -version = "0.0.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1c18c859eead79d8b95d09e4678566e8d70105c4e7b251f707a03df32442661b" +checksum = "fe88247b92c1df6b6de80ddc290f3976dbdf2f5f5d3fd049a9fb598c6dd5ca73" [[package]] name = "version_check" @@ -2774,7 +2637,7 @@ version = "0.2.80" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "27370197c907c55e3f1a9fbe26f44e937fe6451368324e009cba39e139dc08ad" dependencies = [ - "cfg-if 1.0.0", + "cfg-if", "wasm-bindgen-macro", ] diff --git a/playback/Cargo.toml b/playback/Cargo.toml index 63e7f27f..723b3e95 100644 --- a/playback/Cargo.toml +++ b/playback/Cargo.toml @@ -29,20 +29,20 @@ zerocopy = { version = "0.6" } thiserror = { version = "1" } # Backends -alsa = { version = "0.5", optional = true } +alsa = { version = "0.6", optional = true } portaudio-rs = { version = "0.3", optional = true } libpulse-binding = { version = "2", optional = true, default-features = false } libpulse-simple-binding = { version = "2", optional = true, default-features = false } -jack = { version = "0.7", optional = true } -sdl2 = { version = "0.34.3", optional = true } -gstreamer = { version = "0.17", optional = true } -gstreamer-app = { version = "0.17", optional = true } -gstreamer-audio = { version = "0.17", optional = true } -glib = { version = "0.10", optional = true } +jack = { version = "0.10", optional = true } +sdl2 = { version = "0.35", optional = true } +gstreamer = { version = "0.18", optional = true } +gstreamer-app = { version = "0.18", optional = true } +gstreamer-audio = { version = "0.18", optional = true } +glib = { version = "0.15", optional = true } # Rodio dependencies -rodio = { version = "0.14", optional = true, default-features = false } -cpal = { version = "<0.13.5", optional = true } +rodio = { version = "0.15", optional = true, default-features = false } +cpal = { version = "0.13", optional = true } # Decoder lewton = "0.10" diff --git a/playback/src/audio_backend/alsa.rs b/playback/src/audio_backend/alsa.rs index 16aa420d..20e73618 100644 --- a/playback/src/audio_backend/alsa.rs +++ b/playback/src/audio_backend/alsa.rs @@ -90,11 +90,8 @@ impl From for Format { F32 => Format::float(), S32 => Format::s32(), S24 => Format::s24(), + S24_3 => Format::s24_3(), S16 => Format::s16(), - #[cfg(target_endian = "little")] - S24_3 => Format::S243LE, - #[cfg(target_endian = "big")] - S24_3 => Format::S243BE, } } } diff --git a/playback/src/audio_backend/sdl.rs b/playback/src/audio_backend/sdl.rs index 1c9794a2..9ee78e94 100644 --- a/playback/src/audio_backend/sdl.rs +++ b/playback/src/audio_backend/sdl.rs @@ -99,19 +99,20 @@ impl Sink for SdlSink { Self::F32(queue) => { let samples_f32: &[f32] = &converter.f64_to_f32(samples); drain_sink!(queue, AudioFormat::F32.size()); - queue.queue(samples_f32) + queue.queue_audio(samples_f32) } Self::S32(queue) => { let samples_s32: &[i32] = &converter.f64_to_s32(samples); drain_sink!(queue, AudioFormat::S32.size()); - queue.queue(samples_s32) + queue.queue_audio(samples_s32) } Self::S16(queue) => { let samples_s16: &[i16] = &converter.f64_to_s16(samples); drain_sink!(queue, AudioFormat::S16.size()); - queue.queue(samples_s16) + queue.queue_audio(samples_s16) } - }; + } + .map_err(SinkError::OnWrite)?; Ok(()) } } From a433f2b9118b289a8489171a641bfdda620d6d19 Mon Sep 17 00:00:00 2001 From: Jason Gray Date: Mon, 23 May 2022 13:40:00 -0500 Subject: [PATCH 29/39] update MSRV --- .github/workflows/test.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index db6388eb..e1243ce7 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -64,7 +64,7 @@ jobs: matrix: os: [ubuntu-latest] toolchain: - - 1.53 # MSRV (Minimum supported rust version) + - 1.56 # MSRV (Minimum supported rust version) - stable - beta experimental: [false] From 79b92bbe7a8a4ddd0737018263df19b23eb799ad Mon Sep 17 00:00:00 2001 From: JasonLG1979 Date: Mon, 23 May 2022 13:42:38 -0500 Subject: [PATCH 30/39] Update changelog and such --- CHANGELOG.md | 1 + COMPILING.md | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index a50f6c45..b1b4491f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] ### Changed +- [chore] The MSRV is now 1.56 ### Added diff --git a/COMPILING.md b/COMPILING.md index a76d9a36..2b0a1350 100644 --- a/COMPILING.md +++ b/COMPILING.md @@ -7,7 +7,7 @@ In order to compile librespot, you will first need to set up a suitable Rust bui ### Install Rust The easiest, and recommended way to get Rust is to use [rustup](https://rustup.rs). Once that’s installed, Rust's standard tools should be set up and ready to use. -*Note: The current minimum required Rust version at the time of writing is 1.53, you can find the current minimum version specified in the `.github/workflow/test.yml` file.* +*Note: The current minimum required Rust version at the time of writing is 1.56, you can find the current minimum version specified in the `.github/workflow/test.yml` file.* #### Additional Rust tools - `rustfmt` To ensure a consistent codebase, we utilise [`rustfmt`](https://github.com/rust-lang/rustfmt) and [`clippy`](https://github.com/rust-lang/rust-clippy), which are installed by default with `rustup` these days, else they can be installed manually with: From 15aea747fdb6fe97f01dbb02656adbf3fdd6dbd1 Mon Sep 17 00:00:00 2001 From: Roderick van Domburg Date: Mon, 23 May 2022 21:42:13 +0200 Subject: [PATCH 31/39] Fix updating lockfile --- publish.sh | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/publish.sh b/publish.sh index fb4a475a..cf51212f 100755 --- a/publish.sh +++ b/publish.sh @@ -27,14 +27,17 @@ function updateVersion { do if [ "$CRATE" = "librespot" ] then - CRATE='' + CRATE_DIR='' + else + CRATE_DIR=$CRATE fi - crate_path="$WORKINGDIR/$CRATE/Cargo.toml" + crate_path="$WORKINGDIR/$CRATE_DIR/Cargo.toml" crate_path=${crate_path//\/\///} sed -i '' "s/^version.*/version = \"$1\"/g" "$crate_path" echo "Path is $crate_path" if [ "$CRATE" = "librespot" ] then + echo "Updating lockfile" if [ "$DRY_RUN" = 'true' ] ; then cargo update --dry-run git add . && git commit --dry-run -a -m "Update Cargo.lock" From 88e64bd8843d812cb60f2d07de3f4d218f5c3b8c Mon Sep 17 00:00:00 2001 From: Roderick van Domburg Date: Mon, 23 May 2022 21:43:16 +0200 Subject: [PATCH 32/39] Update Cargo.lock --- Cargo.lock | 16 ++++++++-------- Cargo.toml | 16 ++++++++-------- audio/Cargo.toml | 4 ++-- connect/Cargo.toml | 10 +++++----- core/Cargo.toml | 4 ++-- discovery/Cargo.toml | 4 ++-- metadata/Cargo.toml | 6 +++--- playback/Cargo.toml | 8 ++++---- protocol/Cargo.toml | 2 +- 9 files changed, 35 insertions(+), 35 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 39b34a77..44417d29 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1228,7 +1228,7 @@ dependencies = [ [[package]] name = "librespot" -version = "0.4.0" +version = "0.4.1" dependencies = [ "base64", "env_logger", @@ -1253,7 +1253,7 @@ dependencies = [ [[package]] name = "librespot-audio" -version = "0.4.0" +version = "0.4.1" dependencies = [ "aes-ctr", "byteorder", @@ -1267,7 +1267,7 @@ dependencies = [ [[package]] name = "librespot-connect" -version = "0.4.0" +version = "0.4.1" dependencies = [ "form_urlencoded", "futures-util", @@ -1286,7 +1286,7 @@ dependencies = [ [[package]] name = "librespot-core" -version = "0.4.0" +version = "0.4.1" dependencies = [ "aes", "base64", @@ -1326,7 +1326,7 @@ dependencies = [ [[package]] name = "librespot-discovery" -version = "0.4.0" +version = "0.4.1" dependencies = [ "aes-ctr", "base64", @@ -1350,7 +1350,7 @@ dependencies = [ [[package]] name = "librespot-metadata" -version = "0.4.0" +version = "0.4.1" dependencies = [ "async-trait", "byteorder", @@ -1362,7 +1362,7 @@ dependencies = [ [[package]] name = "librespot-playback" -version = "0.4.0" +version = "0.4.1" dependencies = [ "alsa", "byteorder", @@ -1396,7 +1396,7 @@ dependencies = [ [[package]] name = "librespot-protocol" -version = "0.4.0" +version = "0.4.1" dependencies = [ "glob", "protobuf", diff --git a/Cargo.toml b/Cargo.toml index 0f966ba6..b958a619 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "librespot" -version = "0.4.0" +version = "0.4.1" authors = ["Librespot Org"] license = "MIT" description = "An open source client library for Spotify, with support for Spotify Connect" @@ -22,31 +22,31 @@ doc = false [dependencies.librespot-audio] path = "audio" -version = "0.4.0" +version = "0.4.1" [dependencies.librespot-connect] path = "connect" -version = "0.4.0" +version = "0.4.1" [dependencies.librespot-core] path = "core" -version = "0.4.0" +version = "0.4.1" [dependencies.librespot-discovery] path = "discovery" -version = "0.4.0" +version = "0.4.1" [dependencies.librespot-metadata] path = "metadata" -version = "0.4.0" +version = "0.4.1" [dependencies.librespot-playback] path = "playback" -version = "0.4.0" +version = "0.4.1" [dependencies.librespot-protocol] path = "protocol" -version = "0.4.0" +version = "0.4.1" [dependencies] base64 = "0.13" diff --git a/audio/Cargo.toml b/audio/Cargo.toml index 1c89c81b..a4d54a07 100644 --- a/audio/Cargo.toml +++ b/audio/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "librespot-audio" -version = "0.4.0" +version = "0.4.1" authors = ["Paul Lietar "] description = "The audio fetching logic for librespot" license = "MIT" @@ -9,7 +9,7 @@ edition = "2018" [dependencies.librespot-core] path = "../core" -version = "0.4.0" +version = "0.4.1" [dependencies] aes-ctr = "0.6" diff --git a/connect/Cargo.toml b/connect/Cargo.toml index c69df940..a6393754 100644 --- a/connect/Cargo.toml +++ b/connect/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "librespot-connect" -version = "0.4.0" +version = "0.4.1" authors = ["Paul Lietar "] description = "The discovery and Spotify Connect logic for librespot" license = "MIT" @@ -20,19 +20,19 @@ tokio-stream = "0.1.1" [dependencies.librespot-core] path = "../core" -version = "0.4.0" +version = "0.4.1" [dependencies.librespot-playback] path = "../playback" -version = "0.4.0" +version = "0.4.1" [dependencies.librespot-protocol] path = "../protocol" -version = "0.4.0" +version = "0.4.1" [dependencies.librespot-discovery] path = "../discovery" -version = "0.4.0" +version = "0.4.1" [features] with-dns-sd = ["librespot-discovery/with-dns-sd"] diff --git a/core/Cargo.toml b/core/Cargo.toml index 8ebcbf6a..23ff91e8 100644 --- a/core/Cargo.toml +++ b/core/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "librespot-core" -version = "0.4.0" +version = "0.4.1" authors = ["Paul Lietar "] build = "build.rs" description = "The core functionality provided by librespot" @@ -10,7 +10,7 @@ edition = "2018" [dependencies.librespot-protocol] path = "../protocol" -version = "0.4.0" +version = "0.4.1" [dependencies] aes = "0.6" diff --git a/discovery/Cargo.toml b/discovery/Cargo.toml index 4810c6ea..1f57f61c 100644 --- a/discovery/Cargo.toml +++ b/discovery/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "librespot-discovery" -version = "0.4.0" +version = "0.4.1" authors = ["Paul Lietar "] description = "The discovery logic for librespot" license = "MIT" @@ -27,7 +27,7 @@ dns-sd = { version = "0.1.3", optional = true } [dependencies.librespot-core] path = "../core" default_features = false -version = "0.4.0" +version = "0.4.1" [dev-dependencies] futures = "0.3" diff --git a/metadata/Cargo.toml b/metadata/Cargo.toml index 11992fa2..bbc9805c 100644 --- a/metadata/Cargo.toml +++ b/metadata/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "librespot-metadata" -version = "0.4.0" +version = "0.4.1" authors = ["Paul Lietar "] description = "The metadata logic for librespot" license = "MIT" @@ -15,7 +15,7 @@ log = "0.4" [dependencies.librespot-core] path = "../core" -version = "0.4.0" +version = "0.4.1" [dependencies.librespot-protocol] path = "../protocol" -version = "0.4.0" +version = "0.4.1" diff --git a/playback/Cargo.toml b/playback/Cargo.toml index 723b3e95..cc4f0470 100644 --- a/playback/Cargo.toml +++ b/playback/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "librespot-playback" -version = "0.4.0" +version = "0.4.1" authors = ["Sasha Hilton "] description = "The audio playback logic for librespot" license = "MIT" @@ -9,13 +9,13 @@ edition = "2018" [dependencies.librespot-audio] path = "../audio" -version = "0.4.0" +version = "0.4.1" [dependencies.librespot-core] path = "../core" -version = "0.4.0" +version = "0.4.1" [dependencies.librespot-metadata] path = "../metadata" -version = "0.4.0" +version = "0.4.1" [dependencies] futures-executor = "0.3" diff --git a/protocol/Cargo.toml b/protocol/Cargo.toml index 005c2073..52a83342 100644 --- a/protocol/Cargo.toml +++ b/protocol/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "librespot-protocol" -version = "0.4.0" +version = "0.4.1" authors = ["Paul Liétar "] build = "build.rs" description = "The protobuf logic for communicating with Spotify servers" From fc1e74574a2c1537a7a25292e9354b341c0a91cb Mon Sep 17 00:00:00 2001 From: Roderick van Domburg Date: Mon, 23 May 2022 22:21:56 +0200 Subject: [PATCH 33/39] Update changelog --- CHANGELOG.md | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index b1b4491f..4e975209 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,7 +8,6 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] ### Changed -- [chore] The MSRV is now 1.56 ### Added @@ -16,6 +15,14 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Removed +## [0.4.1] - 2022-05-23 + +### Changed +- [chore] The MSRV is now 1.56 + +### Fixed +- [playback] Fixed dependency issues when installing from crate + ## [0.4.0] - 2022-05-21 ### Changed @@ -128,7 +135,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [0.1.0] - 2019-11-06 -[unreleased]: https://github.com/librespot-org/librespot/compare/v0.4.0..HEAD +[unreleased]: https://github.com/librespot-org/librespot/compare/v0.4.1..HEAD +[0.4.1]: https://github.com/librespot-org/librespot/compare/v0.4.0..v0.4.1 [0.4.0]: https://github.com/librespot-org/librespot/compare/v0.3.1..v0.4.0 [0.3.1]: https://github.com/librespot-org/librespot/compare/v0.3.0..v0.3.1 [0.3.0]: https://github.com/librespot-org/librespot/compare/v0.2.0..v0.3.0 From e4deb5ddcdf8ec6683c1441ae0fb956bce8eae5a Mon Sep 17 00:00:00 2001 From: JasonLG1979 Date: Sat, 28 May 2022 09:08:50 -0500 Subject: [PATCH 34/39] Fix fixed volume with hardware mixer. fixes https://github.com/librespot-org/librespot/issues/1008 --- CHANGELOG.md | 1 + playback/src/mixer/alsamixer.rs | 32 +++++++++++++++++++++----------- 2 files changed, 22 insertions(+), 11 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4e975209..24885534 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,6 +12,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Added ### Fixed +- [playback] `alsamixer`: make `--volume-ctrl fixed` work as expected when combined with `--mixer alsa` ### Removed diff --git a/playback/src/mixer/alsamixer.rs b/playback/src/mixer/alsamixer.rs index f03af958..a930d168 100644 --- a/playback/src/mixer/alsamixer.rs +++ b/playback/src/mixer/alsamixer.rs @@ -104,23 +104,33 @@ impl Mixer for AlsaMixer { let min_db = min_millibel.to_db() as f64; let max_db = max_millibel.to_db() as f64; - let mut db_range = f64::abs(max_db - min_db); + let reported_db_range = f64::abs(max_db - min_db); // Synchronize the volume control dB range with the mixer control, // unless it was already set with a command line option. - if !config.volume_ctrl.range_ok() { - if db_range > 100.0 { - debug!("Alsa mixer reported dB range > 100, which is suspect"); - warn!("Please manually set `--volume-range` if this is incorrect"); - } - config.volume_ctrl.set_db_range(db_range); - } else { + let db_range = if config.volume_ctrl.range_ok() { let db_range_override = config.volume_ctrl.db_range(); + if db_range_override.is_normal() { + db_range_override + } else { + reported_db_range + } + } else { + config.volume_ctrl.set_db_range(reported_db_range); + reported_db_range + }; + + if reported_db_range == db_range { + debug!("Alsa dB volume range was reported as {}", reported_db_range); + if reported_db_range > 100.0 { + debug!("Alsa mixer reported dB range > 100, which is suspect"); + debug!("Please manually set `--volume-range` if this is incorrect"); + } + } else { debug!( - "Alsa dB volume range was detected as {} but overridden as {}", - db_range, db_range_override + "Alsa dB volume range was reported as {} but overridden to {}", + reported_db_range, db_range ); - db_range = db_range_override; } // For hardware controls with a small range (24 dB or less), From 5a10a963ff2fcddc8ddd1fa8ff8a11793415953b Mon Sep 17 00:00:00 2001 From: JasonLG1979 Date: Sat, 18 Jun 2022 09:08:04 -0500 Subject: [PATCH 35/39] Minor alsa backend tweaks Silence a clippy warning and we don't need `std::cmp::min` when `usize` already has `min`. --- playback/src/audio_backend/alsa.rs | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/playback/src/audio_backend/alsa.rs b/playback/src/audio_backend/alsa.rs index 20e73618..e8d9ee05 100644 --- a/playback/src/audio_backend/alsa.rs +++ b/playback/src/audio_backend/alsa.rs @@ -6,7 +6,6 @@ use crate::{NUM_CHANNELS, SAMPLE_RATE}; use alsa::device_name::HintIter; use alsa::pcm::{Access, Format, Frames, HwParams, PCM}; use alsa::{Direction, ValueOr}; -use std::cmp::min; use std::process::exit; use thiserror::Error; @@ -141,7 +140,7 @@ fn list_compatible_devices() -> SinkResult<()> { println!( "\tDescription:\n\n\t\t{}\n", - a.desc.unwrap_or_default().replace("\n", "\n\t\t") + a.desc.unwrap_or_default().replace('\n', "\n\t\t") ); println!( @@ -467,7 +466,7 @@ impl SinkAsBytes for AlsaSink { loop { let data_left = data_len - start_index; let space_left = capacity - self.period_buffer.len(); - let data_to_buffer = min(data_left, space_left); + let data_to_buffer = data_left.min(space_left); let end_index = start_index + data_to_buffer; self.period_buffer From 0d4367fca23971dc8d790eae52e8f41044278bf4 Mon Sep 17 00:00:00 2001 From: JasonLG1979 Date: Mon, 20 Jun 2022 15:55:06 -0500 Subject: [PATCH 36/39] Improve the subprocess backend Better error handling. Move the checking of the shell command to start so a proper error can be thrown if it's None. Use write instead of write_all for finer grained error handling and the ability to attempt a restart on write errors. Use try_wait to skip flushing and killing the process if it's already dead. Stop the player on shutdown to *mostly* prevent write errors from spamming the logs during shutdown. Previously Ctrl+c always resulted in a write error. --- connect/src/spirc.rs | 1 + playback/src/audio_backend/subprocess.rs | 197 ++++++++++++++++++----- 2 files changed, 158 insertions(+), 40 deletions(-) diff --git a/connect/src/spirc.rs b/connect/src/spirc.rs index b574ff52..698ca46a 100644 --- a/connect/src/spirc.rs +++ b/connect/src/spirc.rs @@ -478,6 +478,7 @@ impl SpircTask { } SpircCommand::Shutdown => { CommandSender::new(self, MessageType::kMessageTypeGoodbye).send(); + self.player.stop(); self.shutdown = true; if let Some(rx) = self.commands.as_mut() { rx.close() diff --git a/playback/src/audio_backend/subprocess.rs b/playback/src/audio_backend/subprocess.rs index 63fc5d88..6ce545da 100644 --- a/playback/src/audio_backend/subprocess.rs +++ b/playback/src/audio_backend/subprocess.rs @@ -4,30 +4,75 @@ use crate::convert::Converter; use crate::decoder::AudioPacket; use shell_words::split; -use std::io::Write; +use std::io::{ErrorKind, Write}; use std::process::{exit, Child, Command, Stdio}; +use thiserror::Error; + +#[derive(Debug, Error)] +enum SubprocessError { + #[error(" {0}")] + OnWrite(std::io::Error), + + #[error(" Command {command} Can Not be Executed, {e}")] + SpawnFailure { command: String, e: std::io::Error }, + + #[error(" Failed to Parse Command args for {command}, {e}")] + InvalidArgs { + command: String, + e: shell_words::ParseError, + }, + + #[error(" Failed to Flush the Subprocess, {0}")] + FlushFailure(std::io::Error), + + #[error(" Failed to Kill the Subprocess, {0}")] + KillFailure(std::io::Error), + + #[error(" Failed to Wait for the Subprocess to Exit, {0}")] + WaitFailure(std::io::Error), + + #[error(" The Subprocess is no longer able to accept Bytes")] + WriteZero, + + #[error(" Missing Required Shell Command")] + MissingCommand, + + #[error(" The Subprocess is None")] + NoChild, + + #[error(" The Subprocess's stdin is None")] + NoStdin, +} + +impl From for SinkError { + fn from(e: SubprocessError) -> SinkError { + use SubprocessError::*; + let es = e.to_string(); + match e { + FlushFailure(_) | KillFailure(_) | WaitFailure(_) | OnWrite(_) | WriteZero => { + SinkError::OnWrite(es) + } + SpawnFailure { .. } => SinkError::ConnectionRefused(es), + MissingCommand | InvalidArgs { .. } => SinkError::InvalidParams(es), + NoChild | NoStdin => SinkError::NotConnected(es), + } + } +} pub struct SubprocessSink { - shell_command: String, + shell_command: Option, child: Option, format: AudioFormat, } impl Open for SubprocessSink { fn open(shell_command: Option, format: AudioFormat) -> Self { - let shell_command = match shell_command.as_deref() { - Some("?") => { - info!("Usage: --backend subprocess --device {{shell_command}}"); - exit(0); - } - Some(cmd) => cmd.to_owned(), - None => { - error!("subprocess sink requires specifying a shell command"); - exit(1); - } - }; + if let Some("?") = shell_command.as_deref() { + println!("\nUsage:\n\nOutput to a Subprocess:\n\n\t--backend subprocess --device {{shell_command}}\n"); + exit(0); + } - info!("Using subprocess sink with format: {:?}", format); + info!("Using SubprocessSink with format: {:?}", format); Self { shell_command, @@ -39,26 +84,53 @@ impl Open for SubprocessSink { impl Sink for SubprocessSink { fn start(&mut self) -> SinkResult<()> { - let args = split(&self.shell_command).unwrap(); - let child = Command::new(&args[0]) - .args(&args[1..]) - .stdin(Stdio::piped()) - .spawn() - .map_err(|e| SinkError::ConnectionRefused(e.to_string()))?; - self.child = Some(child); + self.child.get_or_insert({ + match self.shell_command.as_deref() { + Some(command) => { + let args = split(command).map_err(|e| SubprocessError::InvalidArgs { + command: command.to_string(), + e, + })?; + + Command::new(&args[0]) + .args(&args[1..]) + .stdin(Stdio::piped()) + .spawn() + .map_err(|e| SubprocessError::SpawnFailure { + command: command.to_string(), + e, + })? + } + None => return Err(SubprocessError::MissingCommand.into()), + } + }); + Ok(()) } fn stop(&mut self) -> SinkResult<()> { - if let Some(child) = &mut self.child.take() { - child - .kill() - .map_err(|e| SinkError::OnWrite(e.to_string()))?; - child - .wait() - .map_err(|e| SinkError::OnWrite(e.to_string()))?; + let child = &mut self.child.take().ok_or(SubprocessError::NoChild)?; + + match child.try_wait() { + // The process has already exited + // nothing to do. + Ok(Some(_)) => Ok(()), + Ok(_) => { + // The process Must DIE!!! + child + .stdin + .take() + .ok_or(SubprocessError::NoStdin)? + .flush() + .map_err(SubprocessError::FlushFailure)?; + + child.kill().map_err(SubprocessError::KillFailure)?; + child.wait().map_err(SubprocessError::WaitFailure)?; + + Ok(()) + } + Err(e) => Err(SubprocessError::WaitFailure(e).into()), } - Ok(()) } sink_as_bytes!(); @@ -66,22 +138,67 @@ impl Sink for SubprocessSink { impl SinkAsBytes for SubprocessSink { fn write_bytes(&mut self, data: &[u8]) -> SinkResult<()> { - if let Some(child) = &mut self.child { - let child_stdin = child + // We get one attempted restart per write. + // We don't want to get stuck in a restart loop. + let mut restarted = false; + let mut start_index = 0; + let data_len = data.len(); + let mut end_index = data_len; + + loop { + match self + .child + .as_ref() + .ok_or(SubprocessError::NoChild)? .stdin - .as_mut() - .ok_or_else(|| SinkError::NotConnected("Child is None".to_string()))?; - child_stdin - .write_all(data) - .map_err(|e| SinkError::OnWrite(e.to_string()))?; - child_stdin - .flush() - .map_err(|e| SinkError::OnWrite(e.to_string()))?; + .as_ref() + .ok_or(SubprocessError::NoStdin)? + .write(&data[start_index..end_index]) + { + Ok(0) => { + // Potentially fatal. + // As per the docs a return value of 0 + // means we shouldn't try to write to the + // process anymore so let's try a restart + // if we haven't already. + self.try_restart(SubprocessError::WriteZero, &mut restarted)?; + + continue; + } + Ok(bytes_written) => { + // What we want, a successful write. + start_index = data_len.min(start_index + bytes_written); + end_index = data_len.min(start_index + bytes_written); + + if end_index == data_len { + break Ok(()); + } + } + // Non-fatal, retry the write. + Err(ref e) if e.kind() == ErrorKind::Interrupted => continue, + Err(e) => { + // Very possibly fatal, + // but let's try a restart anyway if we haven't already. + self.try_restart(SubprocessError::OnWrite(e), &mut restarted)?; + + continue; + } + } } - Ok(()) } } impl SubprocessSink { pub const NAME: &'static str = "subprocess"; + + fn try_restart(&mut self, e: SubprocessError, restarted: &mut bool) -> SinkResult<()> { + // If the restart fails throw the original error back. + if !*restarted && self.stop().is_ok() && self.start().is_ok() { + *restarted = true; + + Ok(()) + } else { + Err(e.into()) + } + } } From 0db17973a152657990c3fd5d695bf531edcd2b0f Mon Sep 17 00:00:00 2001 From: JasonLG1979 Date: Sat, 25 Jun 2022 00:17:36 -0500 Subject: [PATCH 37/39] Fix --opt=value line argument logging Fixes https://github.com/librespot-org/librespot/issues/1011 --- src/main.rs | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/src/main.rs b/src/main.rs index 5e4b0bb5..0c542f6f 100644 --- a/src/main.rs +++ b/src/main.rs @@ -658,7 +658,15 @@ fn get_setup() -> Setup { trace!("Command line argument(s):"); for (index, key) in args.iter().enumerate() { - let opt = key.trim_start_matches('-'); + let opt = { + let key = key.trim_start_matches('-'); + + if let Some((s, _)) = key.split_once('=') { + s + } else { + key + } + }; if index > 0 && key.starts_with('-') @@ -668,13 +676,13 @@ fn get_setup() -> Setup { { if matches!(opt, PASSWORD | PASSWORD_SHORT | USERNAME | USERNAME_SHORT) { // Don't log creds. - trace!("\t\t{} \"XXXXXXXX\"", key); + trace!("\t\t{} \"XXXXXXXX\"", opt); } else { let value = matches.opt_str(opt).unwrap_or_else(|| "".to_string()); if value.is_empty() { - trace!("\t\t{}", key); + trace!("\t\t{}", opt); } else { - trace!("\t\t{} \"{}\"", key, value); + trace!("\t\t{} \"{}\"", opt, value); } } } From 2532687cc62501c238b61a0c19666b8308262abc Mon Sep 17 00:00:00 2001 From: JasonLG1979 Date: Thu, 30 Jun 2022 21:57:23 -0500 Subject: [PATCH 38/39] Improve pipe backend * Implement stop * Better error handling --- playback/src/audio_backend/pipe.rs | 84 ++++++++++++++++++++---------- 1 file changed, 57 insertions(+), 27 deletions(-) diff --git a/playback/src/audio_backend/pipe.rs b/playback/src/audio_backend/pipe.rs index 682f8124..e0e8a77c 100644 --- a/playback/src/audio_backend/pipe.rs +++ b/playback/src/audio_backend/pipe.rs @@ -2,9 +2,38 @@ use super::{Open, Sink, SinkAsBytes, SinkError, SinkResult}; use crate::config::AudioFormat; use crate::convert::Converter; use crate::decoder::AudioPacket; + use std::fs::OpenOptions; use std::io::{self, Write}; use std::process::exit; +use thiserror::Error; + +#[derive(Debug, Error)] +enum StdoutError { + #[error(" {0}")] + OnWrite(std::io::Error), + + #[error(" File Path {file} Can Not be Opened and/or Created, {e}")] + OpenFailure { file: String, e: std::io::Error }, + + #[error(" Failed to Flush the Output Stream, {0}")] + FlushFailure(std::io::Error), + + #[error(" The Output Stream is None")] + NoOutput, +} + +impl From for SinkError { + fn from(e: StdoutError) -> SinkError { + use StdoutError::*; + let es = e.to_string(); + match e { + FlushFailure(_) | OnWrite(_) => SinkError::OnWrite(es), + OpenFailure { .. } => SinkError::ConnectionRefused(es), + NoOutput => SinkError::NotConnected(es), + } + } +} pub struct StdoutSink { output: Option>, @@ -15,13 +44,12 @@ pub struct StdoutSink { impl Open for StdoutSink { fn open(file: Option, format: AudioFormat) -> Self { if let Some("?") = file.as_deref() { - info!("Usage:"); - println!(" Output to stdout: --backend pipe"); - println!(" Output to file: --backend pipe --device {{filename}}"); + println!("\nUsage:\n\nOutput to stdout:\n\n\t--backend pipe\n\nOutput to file:\n\n\t--backend pipe --device {{filename}}\n"); exit(0); } - info!("Using pipe sink with format: {:?}", format); + info!("Using StdoutSink (pipe) with format: {:?}", format); + Self { output: None, file, @@ -32,21 +60,31 @@ impl Open for StdoutSink { impl Sink for StdoutSink { fn start(&mut self) -> SinkResult<()> { - if self.output.is_none() { - let output: Box = match self.file.as_deref() { - Some(file) => { - let open_op = OpenOptions::new() + self.output.get_or_insert({ + match self.file.as_deref() { + Some(file) => Box::new( + OpenOptions::new() .write(true) .create(true) .open(file) - .map_err(|e| SinkError::ConnectionRefused(e.to_string()))?; - Box::new(open_op) - } + .map_err(|e| StdoutError::OpenFailure { + file: file.to_string(), + e, + })?, + ), None => Box::new(io::stdout()), - }; + } + }); - self.output = Some(output); - } + Ok(()) + } + + fn stop(&mut self) -> SinkResult<()> { + self.output + .take() + .ok_or(StdoutError::NoOutput)? + .flush() + .map_err(StdoutError::FlushFailure)?; Ok(()) } @@ -56,19 +94,11 @@ impl Sink for StdoutSink { impl SinkAsBytes for StdoutSink { fn write_bytes(&mut self, data: &[u8]) -> SinkResult<()> { - match self.output.as_deref_mut() { - Some(output) => { - output - .write_all(data) - .map_err(|e| SinkError::OnWrite(e.to_string()))?; - output - .flush() - .map_err(|e| SinkError::OnWrite(e.to_string()))?; - } - None => { - return Err(SinkError::NotConnected("Output is None".to_string())); - } - } + self.output + .as_deref_mut() + .ok_or(StdoutError::NoOutput)? + .write_all(data) + .map_err(StdoutError::OnWrite)?; Ok(()) } From 582fdebadd4c1c5196911ae84773508c197ed8d6 Mon Sep 17 00:00:00 2001 From: JasonLG1979 Date: Wed, 20 Jul 2022 20:27:45 -0500 Subject: [PATCH 39/39] Update Changelog This should update the changelog for my last 3 PR's. --- CHANGELOG.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 24885534..e4ba4628 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,11 +8,15 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] ### Changed +- [playback] `subprocess`: Better error handling +- [playback] `pipe`: Better error handling ### Added +- [playback] `pipe`: Implement stop ### Fixed - [playback] `alsamixer`: make `--volume-ctrl fixed` work as expected when combined with `--mixer alsa` +- [main] fix `--opt=value` line argument logging ### Removed