Feature-gate passthrough decoder

This commit is contained in:
Roderick van Domburg 2022-01-25 20:46:10 +01:00
parent 3f95a45b27
commit 552d9145f4
No known key found for this signature in database
GPG key ID: A9EF5222A26F0451
5 changed files with 36 additions and 14 deletions

View file

@ -72,6 +72,8 @@ gstreamer-backend = ["librespot-playback/gstreamer-backend"]
with-dns-sd = ["librespot-core/with-dns-sd", "librespot-discovery/with-dns-sd"] with-dns-sd = ["librespot-core/with-dns-sd", "librespot-discovery/with-dns-sd"]
passthrough-decoder = ["librespot-playback/passthrough-decoder"]
default = ["rodio-backend"] default = ["rodio-backend"]
[package.metadata.deb] [package.metadata.deb]

View file

@ -46,7 +46,7 @@ cpal = { version = "0.13", optional = true }
symphonia = { version = "0.4", default-features = false, features = ["mp3", "ogg", "vorbis"] } symphonia = { version = "0.4", default-features = false, features = ["mp3", "ogg", "vorbis"] }
# Legacy Ogg container decoder for the passthrough decoder # Legacy Ogg container decoder for the passthrough decoder
ogg = "0.8" ogg = { version = "0.8", optional = true }
# Dithering # Dithering
rand = { version = "0.8", features = ["small_rng"] } rand = { version = "0.8", features = ["small_rng"] }
@ -61,3 +61,5 @@ rodio-backend = ["rodio", "cpal"]
rodiojack-backend = ["rodio", "cpal/jack"] rodiojack-backend = ["rodio", "cpal/jack"]
sdl-backend = ["sdl2"] sdl-backend = ["sdl2"]
gstreamer-backend = ["gstreamer", "gstreamer-app", "glib"] gstreamer-backend = ["gstreamer", "gstreamer-app", "glib"]
passthrough-decoder = ["ogg"]

View file

@ -2,7 +2,9 @@ use std::ops::Deref;
use thiserror::Error; use thiserror::Error;
#[cfg(feature = "passthrough-decoder")]
mod passthrough_decoder; mod passthrough_decoder;
#[cfg(feature = "passthrough-decoder")]
pub use passthrough_decoder::PassthroughDecoder; pub use passthrough_decoder::PassthroughDecoder;
mod symphonia_decoder; mod symphonia_decoder;
@ -41,7 +43,7 @@ impl AudioPacket {
} }
} }
pub fn oggdata(&self) -> AudioPacketResult<&[u8]> { pub fn raw(&self) -> AudioPacketResult<&[u8]> {
match self { match self {
AudioPacket::Raw(d) => Ok(d), AudioPacket::Raw(d) => Ok(d),
AudioPacket::Samples(_) => Err(AudioPacketError::Samples), AudioPacket::Samples(_) => Err(AudioPacketError::Samples),

View file

@ -35,13 +35,14 @@ use crate::{
config::{Bitrate, NormalisationMethod, NormalisationType, PlayerConfig}, config::{Bitrate, NormalisationMethod, NormalisationType, PlayerConfig},
convert::Converter, convert::Converter,
core::{util::SeqGenerator, Error, Session, SpotifyId}, core::{util::SeqGenerator, Error, Session, SpotifyId},
decoder::{ decoder::{AudioDecoder, AudioPacket, AudioPacketPosition, SymphoniaDecoder},
AudioDecoder, AudioPacket, AudioPacketPosition, PassthroughDecoder, SymphoniaDecoder,
},
metadata::audio::{AudioFileFormat, AudioFiles, AudioItem}, metadata::audio::{AudioFileFormat, AudioFiles, AudioItem},
mixer::AudioFilter, mixer::AudioFilter,
}; };
#[cfg(feature = "passthrough-decoder")]
use crate::decoder::PassthroughDecoder;
use crate::SAMPLES_PER_SECOND; use crate::SAMPLES_PER_SECOND;
const PRELOAD_NEXT_TRACK_BEFORE_END_DURATION_MS: u32 = 30000; const PRELOAD_NEXT_TRACK_BEFORE_END_DURATION_MS: u32 = 30000;
@ -931,9 +932,7 @@ impl PlayerTrackLoader {
} }
}; };
let result = if self.config.passthrough { let mut symphonia_decoder = |audio_file, format| {
PassthroughDecoder::new(audio_file, format).map(|x| Box::new(x) as Decoder)
} else {
SymphoniaDecoder::new(audio_file, format).map(|mut decoder| { SymphoniaDecoder::new(audio_file, format).map(|mut decoder| {
// For formats other that Vorbis, we'll try getting normalisation data from // For formats other that Vorbis, we'll try getting normalisation data from
// ReplayGain metadata fields, if present. // ReplayGain metadata fields, if present.
@ -944,12 +943,22 @@ impl PlayerTrackLoader {
}) })
}; };
#[cfg(feature = "passthrough-decoder")]
let decoder_type = if self.config.passthrough {
PassthroughDecoder::new(audio_file, format).map(|x| Box::new(x) as Decoder)
} else {
symphonia_decoder(audio_file, format)
};
#[cfg(not(feature = "passthrough-decoder"))]
let decoder_type = symphonia_decoder(audio_file, format);
let normalisation_data = normalisation_data.unwrap_or_else(|| { let normalisation_data = normalisation_data.unwrap_or_else(|| {
warn!("Unable to get normalisation data, continuing with defaults."); warn!("Unable to get normalisation data, continuing with defaults.");
NormalisationData::default() NormalisationData::default()
}); });
let mut decoder = match result { let mut decoder = match decoder_type {
Ok(decoder) => decoder, Ok(decoder) => decoder,
Err(e) if is_cached => { Err(e) if is_cached => {
warn!( warn!(

View file

@ -227,6 +227,7 @@ fn get_setup() -> Setup {
const NORMALISATION_RELEASE: &str = "normalisation-release"; const NORMALISATION_RELEASE: &str = "normalisation-release";
const NORMALISATION_THRESHOLD: &str = "normalisation-threshold"; const NORMALISATION_THRESHOLD: &str = "normalisation-threshold";
const ONEVENT: &str = "onevent"; const ONEVENT: &str = "onevent";
#[cfg(feature = "passthrough-decoder")]
const PASSTHROUGH: &str = "passthrough"; const PASSTHROUGH: &str = "passthrough";
const PASSWORD: &str = "password"; const PASSWORD: &str = "password";
const PROXY: &str = "proxy"; const PROXY: &str = "proxy";
@ -262,6 +263,7 @@ fn get_setup() -> Setup {
const NAME_SHORT: &str = "n"; const NAME_SHORT: &str = "n";
const DISABLE_DISCOVERY_SHORT: &str = "O"; const DISABLE_DISCOVERY_SHORT: &str = "O";
const ONEVENT_SHORT: &str = "o"; const ONEVENT_SHORT: &str = "o";
#[cfg(feature = "passthrough-decoder")]
const PASSTHROUGH_SHORT: &str = "P"; const PASSTHROUGH_SHORT: &str = "P";
const PASSWORD_SHORT: &str = "p"; const PASSWORD_SHORT: &str = "p";
const EMIT_SINK_EVENTS_SHORT: &str = "Q"; const EMIT_SINK_EVENTS_SHORT: &str = "Q";
@ -371,11 +373,6 @@ fn get_setup() -> Setup {
EMIT_SINK_EVENTS, EMIT_SINK_EVENTS,
"Run PROGRAM set by `--onevent` before the sink is opened and after it is closed.", "Run PROGRAM set by `--onevent` before the sink is opened and after it is closed.",
) )
.optflag(
PASSTHROUGH_SHORT,
PASSTHROUGH,
"Pass a raw stream to the output. Only works with the pipe and subprocess backends.",
)
.optflag( .optflag(
ENABLE_VOLUME_NORMALISATION_SHORT, ENABLE_VOLUME_NORMALISATION_SHORT,
ENABLE_VOLUME_NORMALISATION, ENABLE_VOLUME_NORMALISATION,
@ -568,6 +565,13 @@ fn get_setup() -> Setup {
"PORT", "PORT",
); );
#[cfg(feature = "passthrough-decoder")]
opts.optflag(
PASSTHROUGH_SHORT,
PASSTHROUGH,
"Pass a raw stream to the output. Only works with the pipe and subprocess backends.",
);
let args: Vec<_> = std::env::args_os() let args: Vec<_> = std::env::args_os()
.filter_map(|s| match s.into_string() { .filter_map(|s| match s.into_string() {
Ok(valid) => Some(valid), Ok(valid) => Some(valid),
@ -1505,7 +1509,10 @@ fn get_setup() -> Setup {
}, },
}; };
#[cfg(feature = "passthrough-decoder")]
let passthrough = opt_present(PASSTHROUGH); let passthrough = opt_present(PASSTHROUGH);
#[cfg(not(feature = "passthrough-decoder"))]
let passthrough = false;
PlayerConfig { PlayerConfig {
bitrate, bitrate,