mirror of
https://github.com/librespot-org/librespot.git
synced 2024-12-18 17:11:53 +00:00
Feature-gate passthrough decoder
This commit is contained in:
parent
3f95a45b27
commit
552d9145f4
5 changed files with 36 additions and 14 deletions
|
@ -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]
|
||||||
|
|
|
@ -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"]
|
||||||
|
|
|
@ -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),
|
||||||
|
|
|
@ -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!(
|
||||||
|
|
17
src/main.rs
17
src/main.rs
|
@ -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,
|
||||||
|
|
Loading…
Reference in a new issue