Skip to content

Commit

Permalink
feat: option for audio format
Browse files Browse the repository at this point in the history
  • Loading branch information
Mathias Millet authored and eladyn committed Mar 22, 2023
1 parent 9932391 commit 62bee6d
Show file tree
Hide file tree
Showing 4 changed files with 79 additions and 5 deletions.
6 changes: 6 additions & 0 deletions docs/src/config/File.md
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,12 @@ backend = "alsa" # use portaudio for macOS [homebrew]
# list of valid devices, run `aplay -L`,
device = "alsa_audio_device" # omit for macOS

# The PCM sample format to use. Possible values
# are F32, S32, S24, S24_3, S16.
# Change this value if you encounter errors like
# "Alsa error PCM open ALSA function 'snd_pcm_hw_params_set_format' failed with error 'EINVAL: Invalid argument'"
audio_format = "S16"

# The alsa control device. By default this is the same
# name as the `device` field.
control = "alsa_audio_device" # omit for macOS
Expand Down
71 changes: 69 additions & 2 deletions src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,9 @@ use gethostname::gethostname;
use librespot_core::{
cache::Cache, config::DeviceType as LSDeviceType, config::SessionConfig, version,
};
use librespot_playback::config::{Bitrate as LSBitrate, PlayerConfig};
use librespot_playback::config::{
AudioFormat as LSAudioFormat, Bitrate as LSBitrate, PlayerConfig,
};
use log::{error, info, warn};
use serde::{de::Error, de::Unexpected, Deserialize, Deserializer};
use sha1::{Digest, Sha1};
Expand Down Expand Up @@ -266,6 +268,57 @@ impl ToString for DBusType {
}
}

/// LibreSpot supported audio formats
static AUDIO_FORMAT_VALUES: &[&str] = &["F32", "S32", "S24", "S24_3", "S16"];

#[derive(Clone, Copy, Debug, Deserialize, PartialEq, StructOpt)]
pub enum AudioFormat {
F32,
S32,
S24,
S24_3,
S16,
}

impl FromStr for AudioFormat {
type Err = ParseError;

fn from_str(s: &str) -> Result<Self, Self::Err> {
match s {
"F32" => Ok(AudioFormat::F32),
"S32" => Ok(AudioFormat::S32),
"S24" => Ok(AudioFormat::S24),
"S24_3" => Ok(AudioFormat::S24_3),
"S16" => Ok(AudioFormat::S16),
_ => unreachable!(),
}
}
}

impl ToString for AudioFormat {
fn to_string(&self) -> String {
match self {
AudioFormat::F32 => "F32".to_string(),
AudioFormat::S32 => "S32".to_string(),
AudioFormat::S24 => "S24".to_string(),
AudioFormat::S24_3 => "S24_3".to_string(),
AudioFormat::S16 => "S16".to_string(),
}
}
}

impl From<AudioFormat> for LSAudioFormat {
fn from(audio_format: AudioFormat) -> Self {
match audio_format {
AudioFormat::F32 => LSAudioFormat::F32,
AudioFormat::S32 => LSAudioFormat::S32,
AudioFormat::S24 => LSAudioFormat::S24,
AudioFormat::S24_3 => LSAudioFormat::S24_3,
AudioFormat::S16 => LSAudioFormat::S16,
}
}
}

#[derive(Debug, Default, StructOpt)]
#[structopt(
about = "A Spotify daemon",
Expand Down Expand Up @@ -404,6 +457,10 @@ pub struct SharedConfigValues {
#[structopt(long, short = "B", possible_values = &BITRATE_VALUES, value_name = "number")]
bitrate: Option<Bitrate>,

/// The audio format of the streamed audio data
#[structopt(long, possible_values = &AUDIO_FORMAT_VALUES, value_name = "string")]
audio_format: Option<AudioFormat>,

/// Initial volume between 0 and 100
#[structopt(long, value_name = "initial_volume")]
initial_volume: Option<String>,
Expand Down Expand Up @@ -511,6 +568,7 @@ impl fmt::Debug for SharedConfigValues {
.field("mixer", &self.mixer)
.field("device_name", &self.device_name)
.field("bitrate", &self.bitrate)
.field("audio_format", &self.audio_format)
.field("initial_volume", &self.initial_volume)
.field("volume_normalisation", &self.volume_normalisation)
.field("normalisation_pregain", &self.normalisation_pregain)
Expand Down Expand Up @@ -583,7 +641,8 @@ impl SharedConfigValues {
device_type,
use_mpris,
max_cache_size,
dbus_type
dbus_type,
audio_format
);

// Handles boolean merging.
Expand Down Expand Up @@ -622,6 +681,7 @@ pub(crate) struct SpotifydConfig {
pub(crate) cache: Option<Cache>,
pub(crate) backend: Option<String>,
pub(crate) audio_device: Option<String>,
pub(crate) audio_format: LSAudioFormat,
#[allow(unused)]
pub(crate) control_device: Option<String>,
#[allow(unused)]
Expand Down Expand Up @@ -660,6 +720,12 @@ pub(crate) fn get_internal_config(config: CliConfig) -> SpotifydConfig {
.unwrap_or(Bitrate::Bitrate160)
.into();

let audio_format: LSAudioFormat = config
.shared_config
.audio_format
.unwrap_or(AudioFormat::S16)
.into();

let backend = config
.shared_config
.backend
Expand Down Expand Up @@ -776,6 +842,7 @@ pub(crate) fn get_internal_config(config: CliConfig) -> SpotifydConfig {
cache,
backend: Some(backend),
audio_device: config.shared_config.device,
audio_format,
control_device: config.shared_config.control,
mixer: config.shared_config.mixer,
volume_controller,
Expand Down
6 changes: 3 additions & 3 deletions src/main_loop.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ pub struct AudioSetup {
pub mixer: Box<dyn FnMut() -> Box<dyn Mixer>>,
pub backend: fn(Option<String>, AudioFormat) -> Box<dyn Sink>,
pub audio_device: Option<String>,
pub audio_format: AudioFormat,
}

pub struct SpotifydState {
Expand Down Expand Up @@ -122,13 +123,12 @@ impl MainLoop {
let audio_filter = mixer.get_audio_filter();
let backend = self.audio_setup.backend;
let audio_device = self.audio_setup.audio_device.clone();
let audio_format = self.audio_setup.audio_format;
let (player, mut event_channel) = Player::new(
self.player_config.clone(),
session.clone(),
audio_filter,
// TODO: dunno how to work with AudioFormat yet, maybe dig further if this
// doesn't work for all configurations
move || (backend)(audio_device, AudioFormat::default()),
move || (backend)(audio_device, audio_format),
);

let (spirc, spirc_task) = Spirc::new(
Expand Down
1 change: 1 addition & 0 deletions src/setup.rs
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,7 @@ pub(crate) fn initial_state(config: config::SpotifydConfig) -> main_loop::MainLo
mixer,
backend,
audio_device: config.audio_device,
audio_format: config.audio_format,
},
spotifyd_state: main_loop::SpotifydState {
cache,
Expand Down

0 comments on commit 62bee6d

Please sign in to comment.