Refactor Volume control, allow for a fixed volume option (#447)

Refactored the old `--linear-volume` flag to a more generic `--volume-ctrl` flag that takes the options of `[linear, log, fixed]`. It defaults as previously to log.
This commit is contained in:
Ash 2020-07-25 09:38:08 +02:00 committed by GitHub
parent dc99cd73c0
commit f0b3b2c7e8
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 58 additions and 19 deletions

View file

@ -14,8 +14,7 @@ use crate::playback::mixer::Mixer;
use crate::playback::player::{Player, PlayerEvent, PlayerEventChannel}; use crate::playback::player::{Player, PlayerEvent, PlayerEventChannel};
use crate::protocol; use crate::protocol;
use crate::protocol::spirc::{DeviceState, Frame, MessageType, PlayStatus, State, TrackRef}; use crate::protocol::spirc::{DeviceState, Frame, MessageType, PlayStatus, State, TrackRef};
use librespot_core::config::{ConnectConfig, VolumeCtrl};
use librespot_core::config::ConnectConfig;
use librespot_core::mercury::MercuryError; use librespot_core::mercury::MercuryError;
use librespot_core::session::Session; use librespot_core::session::Session;
use librespot_core::spotify_id::{SpotifyAudioType, SpotifyId, SpotifyIdError}; use librespot_core::spotify_id::{SpotifyAudioType, SpotifyId, SpotifyIdError};
@ -80,7 +79,7 @@ pub enum SpircCommand {
} }
struct SpircTaskConfig { struct SpircTaskConfig {
linear_volume: bool, volume_ctrl: VolumeCtrl,
autoplay: bool, autoplay: bool,
} }
@ -161,7 +160,11 @@ fn initial_device_state(config: ConnectConfig) -> DeviceState {
msg.set_typ(protocol::spirc::CapabilityType::kVolumeSteps); msg.set_typ(protocol::spirc::CapabilityType::kVolumeSteps);
{ {
let repeated = msg.mut_intValue(); let repeated = msg.mut_intValue();
repeated.push(64) if let VolumeCtrl::Fixed = config.volume_ctrl {
repeated.push(0)
} else {
repeated.push(64)
}
}; };
msg msg
}; };
@ -170,7 +173,7 @@ fn initial_device_state(config: ConnectConfig) -> DeviceState {
msg.set_typ(protocol::spirc::CapabilityType::kSupportsPlaylistV2); msg.set_typ(protocol::spirc::CapabilityType::kSupportsPlaylistV2);
{ {
let repeated = msg.mut_intValue(); let repeated = msg.mut_intValue();
repeated.push(64) repeated.push(1)
}; };
msg msg
}; };
@ -230,12 +233,14 @@ fn calc_logarithmic_volume(volume: u16) -> u16 {
val val
} }
fn volume_to_mixer(volume: u16, linear_volume: bool) -> u16 { fn volume_to_mixer(volume: u16, volume_ctrl: &VolumeCtrl) -> u16 {
if linear_volume { match volume_ctrl {
debug!("linear volume: {}", volume); VolumeCtrl::Linear => {
volume debug!("linear volume: {}", volume);
} else { volume
calc_logarithmic_volume(volume) }
VolumeCtrl::Log => calc_logarithmic_volume(volume),
VolumeCtrl::Fixed => volume,
} }
} }
@ -274,9 +279,10 @@ impl Spirc {
let volume = config.volume; let volume = config.volume;
let task_config = SpircTaskConfig { let task_config = SpircTaskConfig {
linear_volume: config.linear_volume, volume_ctrl: config.volume_ctrl.to_owned(),
autoplay: config.autoplay, autoplay: config.autoplay,
}; };
let device = initial_device_state(config); let device = initial_device_state(config);
let player_events = player.get_player_event_channel(); let player_events = player.get_player_event_channel();
@ -1292,7 +1298,7 @@ impl SpircTask {
fn set_volume(&mut self, volume: u16) { fn set_volume(&mut self, volume: u16) {
self.device.set_volume(volume as u32); self.device.set_volume(volume as u32);
self.mixer self.mixer
.set_volume(volume_to_mixer(volume, self.config.linear_volume)); .set_volume(volume_to_mixer(volume, &self.config.volume_ctrl));
if let Some(cache) = self.session.cache() { if let Some(cache) = self.session.cache() {
cache.save_volume(Volume { volume }) cache.save_volume(Volume { volume })
} }

View file

@ -84,6 +84,32 @@ pub struct ConnectConfig {
pub name: String, pub name: String,
pub device_type: DeviceType, pub device_type: DeviceType,
pub volume: u16, pub volume: u16,
pub linear_volume: bool, pub volume_ctrl: VolumeCtrl,
pub autoplay: bool, pub autoplay: bool,
} }
#[derive(Clone, Debug)]
pub enum VolumeCtrl {
Linear,
Log,
Fixed,
}
impl FromStr for VolumeCtrl {
type Err = ();
fn from_str(s: &str) -> Result<Self, Self::Err> {
use self::VolumeCtrl::*;
match s.to_lowercase().as_ref() {
"linear" => Ok(Linear),
"log" => Ok(Log),
"fixed" => Ok(Fixed),
_ => Err(()),
}
}
}
impl Default for VolumeCtrl {
fn default() -> VolumeCtrl {
VolumeCtrl::Linear
}
}

View file

@ -15,7 +15,7 @@ use url::Url;
use librespot::core::authentication::{get_credentials, Credentials}; use librespot::core::authentication::{get_credentials, Credentials};
use librespot::core::cache::Cache; use librespot::core::cache::Cache;
use librespot::core::config::{ConnectConfig, DeviceType, SessionConfig}; use librespot::core::config::{ConnectConfig, DeviceType, SessionConfig, VolumeCtrl};
use librespot::core::session::Session; use librespot::core::session::Session;
use librespot::core::version; use librespot::core::version;
@ -173,10 +173,11 @@ fn setup(args: &[String]) -> Setup {
"Pregain (dB) applied by volume normalisation", "Pregain (dB) applied by volume normalisation",
"PREGAIN", "PREGAIN",
) )
.optflag( .optopt(
"", "",
"linear-volume", "volume-ctrl",
"increase volume linear instead of logarithmic.", "Volume control type - [linear, log, fixed]. Default is logarithmic",
"VOLUME_CTRL"
) )
.optflag( .optflag(
"", "",
@ -337,11 +338,17 @@ fn setup(args: &[String]) -> Setup {
.map(|device_type| DeviceType::from_str(device_type).expect("Invalid device type")) .map(|device_type| DeviceType::from_str(device_type).expect("Invalid device type"))
.unwrap_or(DeviceType::default()); .unwrap_or(DeviceType::default());
let volume_ctrl = matches
.opt_str("volume-ctrl")
.as_ref()
.map(|volume_ctrl| VolumeCtrl::from_str(volume_ctrl).expect("Invalid volume ctrl type"))
.unwrap_or(VolumeCtrl::default());
ConnectConfig { ConnectConfig {
name: name, name: name,
device_type: device_type, device_type: device_type,
volume: initial_volume, volume: initial_volume,
linear_volume: matches.opt_present("linear-volume"), volume_ctrl: volume_ctrl,
autoplay: matches.opt_present("autoplay"), autoplay: matches.opt_present("autoplay"),
} }
}; };