diff --git a/connect/src/spirc.rs b/connect/src/spirc.rs index e6d46788..cec19ea1 100644 --- a/connect/src/spirc.rs +++ b/connect/src/spirc.rs @@ -874,6 +874,7 @@ impl SpircTask { } match update.typ() { + MessageType::kMessageTypeHello => self.notify(Some(ident)), MessageType::kMessageTypeLoad => { self.handle_load(update.state.get_or_default())?; self.notify(None) diff --git a/playback/src/audio_backend/alsa.rs b/playback/src/audio_backend/alsa.rs index e5c311c7..285d70e2 100644 --- a/playback/src/audio_backend/alsa.rs +++ b/playback/src/audio_backend/alsa.rs @@ -1,8 +1,8 @@ use super::{Open, Sink, SinkAsBytes, SinkError, SinkResult}; -use crate::config::AudioFormat; +use crate::config::{AudioFormat, SampleRate}; use crate::convert::Converter; use crate::decoder::AudioPacket; -use crate::{NUM_CHANNELS, SAMPLE_RATE as DECODER_SAMPLE_RATE}; +use crate::{COMMON_SAMPLE_RATES, NUM_CHANNELS, SAMPLE_RATE as DECODER_SAMPLE_RATE}; use alsa::device_name::HintIter; use alsa::pcm::{Access, Format, Frames, HwParams, PCM}; use alsa::{Direction, ValueOr}; @@ -12,22 +12,6 @@ use thiserror::Error; const OPTIMAL_NUM_PERIODS: Frames = 5; const MIN_NUM_PERIODS: Frames = 2; -const COMMON_SAMPLE_RATES: [u32; 14] = [ - 8000, 11025, 16000, 22050, 44100, 48000, 88200, 96000, 176400, 192000, 352800, 384000, 705600, - 768000, -]; - -const SUPPORTED_SAMPLE_RATES: [u32; 4] = [44100, 48000, 88200, 96000]; - -const FORMATS: [AudioFormat; 6] = [ - AudioFormat::S16, - AudioFormat::S24, - AudioFormat::S24_3, - AudioFormat::S32, - AudioFormat::F32, - AudioFormat::F64, -]; - #[derive(Debug, Error)] enum AlsaError { #[error("<AlsaSink> Device {device} Unsupported Format {alsa_format} ({format:?}), {e}, Supported Format(s): {supported_formats:?}")] @@ -134,25 +118,22 @@ fn list_compatible_devices() -> SinkResult<()> { { let mut supported_formats_and_samplerates = String::new(); - for format in FORMATS.iter() { + for format in AudioFormat::default().into_iter() { let hwp = hwp.clone(); - if hwp.set_format((*format).into()).is_ok() { - let sample_rates: Vec<String> = SUPPORTED_SAMPLE_RATES - .iter() + if hwp.set_format(format.into()).is_ok() { + let sample_rates: Vec<String> = SampleRate::default() + .into_iter() .filter_map(|sample_rate| { let hwp = hwp.clone(); if hwp - .set_rate(*sample_rate, ValueOr::Nearest) + .set_rate( + sample_rate.as_u32(), + ValueOr::Nearest, + ) .is_ok() { - match *sample_rate { - 44100 => Some("44.1kHz".to_string()), - 48000 => Some("48kHz".to_string()), - 88200 => Some("88.2kHz".to_string()), - 96000 => Some("96kHz".to_string()), - _ => None, - } + Some(sample_rate.to_string()) } else { None } @@ -161,7 +142,7 @@ fn list_compatible_devices() -> SinkResult<()> { if !sample_rates.is_empty() { let format_and_sample_rates = - if *format == AudioFormat::S24_3 { + if format == AudioFormat::S24_3 { format!( "\n\t\tFormat: {format:?} Sample Rate(s): {}", sample_rates.join(", ") @@ -379,10 +360,10 @@ impl AlsaSink { let alsa_format = self.format.into(); hwp.set_format(alsa_format).map_err(|e| { - let supported_formats = FORMATS - .iter() + let supported_formats = AudioFormat::default() + .into_iter() .filter_map(|f| { - if hwp.test_format((*f).into()).is_ok() { + if hwp.test_format(f.into()).is_ok() { Some(format!("{f:?}")) } else { None diff --git a/playback/src/config.rs b/playback/src/config.rs index e50e5262..ca17837a 100644 --- a/playback/src/config.rs +++ b/playback/src/config.rs @@ -151,6 +151,17 @@ pub enum SampleRate { Hz96000, } +impl IntoIterator for SampleRate { + type Item = SampleRate; + type IntoIter = std::vec::IntoIter<Self::Item>; + + fn into_iter(self) -> Self::IntoIter { + use SampleRate::*; + + vec![Hz44100, Hz48000, Hz88200, Hz96000].into_iter() + } +} + impl FromStr for SampleRate { type Err = (); @@ -302,6 +313,17 @@ pub enum AudioFormat { S16, } +impl IntoIterator for AudioFormat { + type Item = AudioFormat; + type IntoIter = std::vec::IntoIter<Self::Item>; + + fn into_iter(self) -> Self::IntoIter { + use AudioFormat::*; + + vec![F64, F32, S32, S24, S24_3, S16].into_iter() + } +} + impl FromStr for AudioFormat { type Err = (); fn from_str(s: &str) -> Result<Self, Self::Err> { diff --git a/playback/src/lib.rs b/playback/src/lib.rs index e56b2cae..6797d6db 100644 --- a/playback/src/lib.rs +++ b/playback/src/lib.rs @@ -25,6 +25,13 @@ pub const SAMPLES_PER_SECOND: u32 = SAMPLE_RATE * NUM_CHANNELS as u32; pub const PAGES_PER_MS: f64 = SAMPLE_RATE as f64 / 1000.0; pub const MS_PER_PAGE: f64 = 1000.0 / SAMPLE_RATE as f64; +// not used by all backends +#[allow(dead_code)] +const COMMON_SAMPLE_RATES: [u32; 14] = [ + 8000, 11025, 16000, 22050, 44100, 48000, 88200, 96000, 176400, 192000, 352800, 384000, 705600, + 768000, +]; + pub fn db_to_ratio(db: f64) -> f64 { f64::powf(10.0, db / DB_VOLTAGE_RATIO) } diff --git a/playback/src/player.rs b/playback/src/player.rs index 5d166221..e522de1e 100644 --- a/playback/src/player.rs +++ b/playback/src/player.rs @@ -324,7 +324,7 @@ impl Player { { let (cmd_tx, cmd_rx) = mpsc::unbounded_channel(); - let player_id = PLAYER_COUNTER.fetch_add(1, Ordering::AcqRel); + let player_id = PLAYER_COUNTER.fetch_add(1, Ordering::SeqCst); let thread_name = format!("player:{}", player_id); @@ -1954,7 +1954,7 @@ impl PlayerInternal { // The player increments the player id when it gets it... let thread_name = format!( "loader:{}:{}", - PLAYER_COUNTER.load(Ordering::Relaxed).saturating_sub(1), + PLAYER_COUNTER.load(Ordering::SeqCst).saturating_sub(1), spotify_id.to_uri().unwrap_or_default() ); diff --git a/playback/src/resampler.rs b/playback/src/resampler.rs index 3dfd3f3c..b921df2f 100644 --- a/playback/src/resampler.rs +++ b/playback/src/resampler.rs @@ -368,7 +368,7 @@ impl StereoInterleavedResampler { debug!("Interpolation Quality: {interpolation_quality}"); // The player increments the player id when it gets it... - let player_id = PLAYER_COUNTER.load(Ordering::Relaxed).saturating_sub(1); + let player_id = PLAYER_COUNTER.load(Ordering::SeqCst).saturating_sub(1); let left_thread_name = format!("resampler:{player_id}:left"); let right_thread_name = format!("resampler:{player_id}:right"); diff --git a/src/player_event_handler.rs b/src/player_event_handler.rs index 4fe2a271..0c16a053 100644 --- a/src/player_event_handler.rs +++ b/src/player_event_handler.rs @@ -1,6 +1,11 @@ use log::{debug, error, warn}; -use std::{collections::HashMap, process::exit, process::Command, sync::atomic::Ordering, thread}; +use std::{ + collections::HashMap, + process::{exit, Command}, + sync::atomic::Ordering, + thread, +}; use librespot::{ metadata::audio::UniqueFields, @@ -18,7 +23,7 @@ impl EventHandler { // The player increments the player id when it gets it... let thread_name = format!( "event-handler:{}", - PLAYER_COUNTER.load(Ordering::Relaxed).saturating_sub(1) + PLAYER_COUNTER.load(Ordering::SeqCst).saturating_sub(1) ); let builder = thread::Builder::new().name(thread_name.clone());