mirror of
https://github.com/librespot-org/librespot.git
synced 2024-12-18 17:11:53 +00:00
Put CommonSampleRates to some use and clean up backend imports
This commit is contained in:
parent
242e68a98c
commit
25425dab5c
10 changed files with 123 additions and 72 deletions
|
@ -1,11 +1,18 @@
|
||||||
use super::{Open, Sink, SinkAsBytes, SinkError, SinkResult};
|
use super::{Open, Sink, SinkAsBytes, SinkError, SinkResult};
|
||||||
use crate::config::{AudioFormat, SampleRate};
|
|
||||||
use crate::convert::Converter;
|
use crate::{
|
||||||
use crate::decoder::AudioPacket;
|
config::{AudioFormat, SampleRate},
|
||||||
use crate::{CommonSampleRates, NUM_CHANNELS, SAMPLE_RATE as DECODER_SAMPLE_RATE};
|
convert::Converter,
|
||||||
use alsa::device_name::HintIter;
|
decoder::AudioPacket,
|
||||||
use alsa::pcm::{Access, Format, Frames, HwParams, PCM};
|
CommonSampleRates, NUM_CHANNELS, SAMPLE_RATE as DECODER_SAMPLE_RATE,
|
||||||
use alsa::{Direction, ValueOr};
|
};
|
||||||
|
|
||||||
|
use alsa::{
|
||||||
|
device_name::HintIter,
|
||||||
|
pcm::{Access, Format, Frames, HwParams, PCM},
|
||||||
|
Direction, ValueOr,
|
||||||
|
};
|
||||||
|
|
||||||
use std::process::exit;
|
use std::process::exit;
|
||||||
use thiserror::Error;
|
use thiserror::Error;
|
||||||
|
|
||||||
|
@ -204,7 +211,12 @@ impl Open for AlsaSink {
|
||||||
|
|
||||||
let latency_scale_factor = DECODER_SAMPLE_RATE as f64 / sample_rate as f64;
|
let latency_scale_factor = DECODER_SAMPLE_RATE as f64 / sample_rate as f64;
|
||||||
|
|
||||||
info!("Using AlsaSink with format: {format:?}, sample rate: {sample_rate}");
|
info!(
|
||||||
|
"Using AlsaSink with format: {format:?}, sample rate: {}",
|
||||||
|
CommonSampleRates::try_from(sample_rate)
|
||||||
|
.unwrap_or_default()
|
||||||
|
.to_string()
|
||||||
|
);
|
||||||
|
|
||||||
Self {
|
Self {
|
||||||
pcm: None,
|
pcm: None,
|
||||||
|
|
|
@ -13,7 +13,9 @@ use std::sync::Arc;
|
||||||
|
|
||||||
use super::{Open, Sink, SinkAsBytes, SinkError, SinkResult};
|
use super::{Open, Sink, SinkAsBytes, SinkError, SinkResult};
|
||||||
|
|
||||||
use crate::{config::AudioFormat, convert::Converter, decoder::AudioPacket, NUM_CHANNELS};
|
use crate::{
|
||||||
|
config::AudioFormat, convert::Converter, decoder::AudioPacket, CommonSampleRates, NUM_CHANNELS,
|
||||||
|
};
|
||||||
|
|
||||||
pub struct GstreamerSink {
|
pub struct GstreamerSink {
|
||||||
appsrc: gst_app::AppSrc,
|
appsrc: gst_app::AppSrc,
|
||||||
|
@ -25,7 +27,13 @@ pub struct GstreamerSink {
|
||||||
|
|
||||||
impl Open for GstreamerSink {
|
impl Open for GstreamerSink {
|
||||||
fn open(device: Option<String>, format: AudioFormat, sample_rate: u32) -> Self {
|
fn open(device: Option<String>, format: AudioFormat, sample_rate: u32) -> Self {
|
||||||
info!("Using GStreamer sink with format: {format:?}, sample rate: {sample_rate}");
|
info!(
|
||||||
|
"Using GstreamerSink with format: {format:?}, sample rate: {}",
|
||||||
|
CommonSampleRates::try_from(sample_rate)
|
||||||
|
.unwrap_or_default()
|
||||||
|
.to_string()
|
||||||
|
);
|
||||||
|
|
||||||
gst::init().expect("failed to init GStreamer!");
|
gst::init().expect("failed to init GStreamer!");
|
||||||
|
|
||||||
let gst_format = match format {
|
let gst_format = match format {
|
||||||
|
|
|
@ -1,11 +1,13 @@
|
||||||
use super::{Open, Sink, SinkError, SinkResult};
|
use super::{Open, Sink, SinkError, SinkResult};
|
||||||
use crate::config::AudioFormat;
|
|
||||||
use crate::convert::Converter;
|
use crate::{
|
||||||
use crate::decoder::AudioPacket;
|
config::AudioFormat, convert::Converter, decoder::AudioPacket, CommonSampleRates, NUM_CHANNELS,
|
||||||
use crate::NUM_CHANNELS;
|
};
|
||||||
|
|
||||||
use jack::{
|
use jack::{
|
||||||
AsyncClient, AudioOut, Client, ClientOptions, Control, Port, ProcessHandler, ProcessScope,
|
AsyncClient, AudioOut, Client, ClientOptions, Control, Port, ProcessHandler, ProcessScope,
|
||||||
};
|
};
|
||||||
|
|
||||||
use std::sync::mpsc::{sync_channel, Receiver, SyncSender};
|
use std::sync::mpsc::{sync_channel, Receiver, SyncSender};
|
||||||
|
|
||||||
pub struct JackSink {
|
pub struct JackSink {
|
||||||
|
@ -42,9 +44,12 @@ impl Open for JackSink {
|
||||||
if format != AudioFormat::F32 {
|
if format != AudioFormat::F32 {
|
||||||
warn!("JACK currently does not support {format:?} output");
|
warn!("JACK currently does not support {format:?} output");
|
||||||
}
|
}
|
||||||
|
|
||||||
info!(
|
info!(
|
||||||
"Using JACK sink with format {:?}, sample rate: {sample_rate}",
|
"Using JackSink with format: {format:?}, sample rate: {}",
|
||||||
AudioFormat::F32
|
CommonSampleRates::try_from(sample_rate)
|
||||||
|
.unwrap_or_default()
|
||||||
|
.to_string()
|
||||||
);
|
);
|
||||||
|
|
||||||
let client_name = client_name.unwrap_or_else(|| "librespot".to_string());
|
let client_name = client_name.unwrap_or_else(|| "librespot".to_string());
|
||||||
|
|
|
@ -1,11 +1,12 @@
|
||||||
use super::{Open, Sink, SinkAsBytes, SinkError, SinkResult};
|
use super::{Open, Sink, SinkAsBytes, SinkError, SinkResult};
|
||||||
use crate::config::AudioFormat;
|
use crate::{config::AudioFormat, convert::Converter, decoder::AudioPacket, CommonSampleRates};
|
||||||
use crate::convert::Converter;
|
|
||||||
use crate::decoder::AudioPacket;
|
use std::{
|
||||||
|
fs::OpenOptions,
|
||||||
|
io::{self, Write},
|
||||||
|
process::exit,
|
||||||
|
};
|
||||||
|
|
||||||
use std::fs::OpenOptions;
|
|
||||||
use std::io::{self, Write};
|
|
||||||
use std::process::exit;
|
|
||||||
use thiserror::Error;
|
use thiserror::Error;
|
||||||
|
|
||||||
#[derive(Debug, Error)]
|
#[derive(Debug, Error)]
|
||||||
|
@ -48,7 +49,12 @@ impl Open for StdoutSink {
|
||||||
exit(0);
|
exit(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
info!("Using StdoutSink (pipe) with format: {format:?}, sample rate: {sample_rate}");
|
info!(
|
||||||
|
"Using StdoutSink with format: {format:?}, sample rate: {}",
|
||||||
|
CommonSampleRates::try_from(sample_rate)
|
||||||
|
.unwrap_or_default()
|
||||||
|
.to_string()
|
||||||
|
);
|
||||||
|
|
||||||
Self {
|
Self {
|
||||||
output: None,
|
output: None,
|
||||||
|
|
|
@ -1,12 +1,15 @@
|
||||||
use super::{Open, Sink, SinkError, SinkResult};
|
use super::{Open, Sink, SinkError, SinkResult};
|
||||||
use crate::config::AudioFormat;
|
|
||||||
use crate::convert::Converter;
|
use crate::{
|
||||||
use crate::decoder::AudioPacket;
|
config::AudioFormat, convert::Converter, decoder::AudioPacket, CommonSampleRates, NUM_CHANNELS,
|
||||||
use crate::NUM_CHANNELS;
|
};
|
||||||
use portaudio_rs::device::{get_default_output_index, DeviceIndex, DeviceInfo};
|
|
||||||
use portaudio_rs::stream::*;
|
use portaudio_rs::{
|
||||||
use std::process::exit;
|
device::{get_default_output_index, DeviceIndex, DeviceInfo},
|
||||||
use std::time::Duration;
|
stream::*,
|
||||||
|
};
|
||||||
|
|
||||||
|
use std::{process::exit, time::Duration};
|
||||||
|
|
||||||
pub enum PortAudioSink<'a> {
|
pub enum PortAudioSink<'a> {
|
||||||
F32(
|
F32(
|
||||||
|
@ -55,7 +58,12 @@ fn find_output(device: &str) -> Option<DeviceIndex> {
|
||||||
|
|
||||||
impl<'a> Open for PortAudioSink<'a> {
|
impl<'a> Open for PortAudioSink<'a> {
|
||||||
fn open(device: Option<String>, format: AudioFormat, sample_rate: u32) -> PortAudioSink<'a> {
|
fn open(device: Option<String>, format: AudioFormat, sample_rate: u32) -> PortAudioSink<'a> {
|
||||||
info!("Using PortAudio sink with format: {format:?}, sample rate: {sample_rate}");
|
info!(
|
||||||
|
"Using PortAudioSink with format: {format:?}, sample rate: {}",
|
||||||
|
CommonSampleRates::try_from(sample_rate)
|
||||||
|
.unwrap_or_default()
|
||||||
|
.to_string()
|
||||||
|
);
|
||||||
|
|
||||||
portaudio_rs::initialize().unwrap();
|
portaudio_rs::initialize().unwrap();
|
||||||
|
|
||||||
|
|
|
@ -1,8 +1,10 @@
|
||||||
use super::{Open, Sink, SinkAsBytes, SinkError, SinkResult};
|
use super::{Open, Sink, SinkAsBytes, SinkError, SinkResult};
|
||||||
use crate::config::AudioFormat;
|
|
||||||
use crate::convert::Converter;
|
use crate::{
|
||||||
use crate::decoder::AudioPacket;
|
config::AudioFormat, convert::Converter, decoder::AudioPacket, CommonSampleRates, NUM_CHANNELS,
|
||||||
use crate::{NUM_CHANNELS, SAMPLE_RATE as DECODER_SAMPLE_RATE};
|
SAMPLE_RATE as DECODER_SAMPLE_RATE,
|
||||||
|
};
|
||||||
|
|
||||||
use libpulse_binding::{self as pulse, error::PAErr, stream::Direction};
|
use libpulse_binding::{self as pulse, error::PAErr, stream::Direction};
|
||||||
use libpulse_simple_binding::Simple;
|
use libpulse_simple_binding::Simple;
|
||||||
use std::env;
|
use std::env;
|
||||||
|
@ -76,7 +78,12 @@ impl Open for PulseAudioSink {
|
||||||
format
|
format
|
||||||
};
|
};
|
||||||
|
|
||||||
info!("Using PulseAudioSink with format: {format:?}, sample rate: {sample_rate}");
|
info!(
|
||||||
|
"Using PulseAudioSink with format: {format:?}, sample rate: {}",
|
||||||
|
CommonSampleRates::try_from(sample_rate)
|
||||||
|
.unwrap_or_default()
|
||||||
|
.to_string()
|
||||||
|
);
|
||||||
|
|
||||||
let sample_spec = pulse::sample::Spec {
|
let sample_spec = pulse::sample::Spec {
|
||||||
format: format.into(),
|
format: format.into(),
|
||||||
|
|
|
@ -1,15 +1,13 @@
|
||||||
use std::process::exit;
|
use std::{process::exit, thread, time::Duration};
|
||||||
use std::thread;
|
|
||||||
use std::time::Duration;
|
|
||||||
|
|
||||||
use cpal::traits::{DeviceTrait, HostTrait};
|
use cpal::traits::{DeviceTrait, HostTrait};
|
||||||
use thiserror::Error;
|
use thiserror::Error;
|
||||||
|
|
||||||
use super::{Sink, SinkError, SinkResult};
|
use super::{Sink, SinkError, SinkResult};
|
||||||
use crate::config::AudioFormat;
|
|
||||||
use crate::convert::Converter;
|
use crate::{
|
||||||
use crate::decoder::AudioPacket;
|
config::AudioFormat, convert::Converter, decoder::AudioPacket, CommonSampleRates, NUM_CHANNELS,
|
||||||
use crate::NUM_CHANNELS;
|
};
|
||||||
|
|
||||||
#[cfg(all(
|
#[cfg(all(
|
||||||
feature = "rodiojack-backend",
|
feature = "rodiojack-backend",
|
||||||
|
@ -176,15 +174,18 @@ pub fn open(
|
||||||
format: AudioFormat,
|
format: AudioFormat,
|
||||||
sample_rate: u32,
|
sample_rate: u32,
|
||||||
) -> RodioSink {
|
) -> RodioSink {
|
||||||
info!(
|
|
||||||
"Using Rodio sink with format {format:?} and cpal host: {}",
|
|
||||||
host.id().name()
|
|
||||||
);
|
|
||||||
|
|
||||||
if format != AudioFormat::S16 && format != AudioFormat::F32 {
|
if format != AudioFormat::S16 && format != AudioFormat::F32 {
|
||||||
unimplemented!("Rodio currently only supports F32 and S16 formats");
|
unimplemented!("Rodio currently only supports F32 and S16 formats");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
info!(
|
||||||
|
"Using RodioSink with format: {format:?}, sample rate: {}, and cpal host: {}",
|
||||||
|
CommonSampleRates::try_from(sample_rate)
|
||||||
|
.unwrap_or_default()
|
||||||
|
.to_string(),
|
||||||
|
host.id().name(),
|
||||||
|
);
|
||||||
|
|
||||||
let (sink, stream) = create_sink(&host, device).unwrap();
|
let (sink, stream) = create_sink(&host, device).unwrap();
|
||||||
|
|
||||||
debug!("Rodio sink was created");
|
debug!("Rodio sink was created");
|
||||||
|
|
|
@ -1,11 +1,12 @@
|
||||||
use super::{Open, Sink, SinkError, SinkResult};
|
use super::{Open, Sink, SinkError, SinkResult};
|
||||||
use crate::config::AudioFormat;
|
|
||||||
use crate::convert::Converter;
|
use crate::{
|
||||||
use crate::decoder::AudioPacket;
|
config::AudioFormat, convert::Converter, decoder::AudioPacket, CommonSampleRates, NUM_CHANNELS,
|
||||||
use crate::{NUM_CHANNELS, SAMPLE_RATE};
|
SAMPLE_RATE,
|
||||||
|
};
|
||||||
|
|
||||||
use sdl2::audio::{AudioQueue, AudioSpecDesired};
|
use sdl2::audio::{AudioQueue, AudioSpecDesired};
|
||||||
use std::thread;
|
use std::{thread, time::Duration};
|
||||||
use std::time::Duration;
|
|
||||||
|
|
||||||
pub enum SdlSink {
|
pub enum SdlSink {
|
||||||
F32(AudioQueue<f32>),
|
F32(AudioQueue<f32>),
|
||||||
|
@ -15,7 +16,12 @@ pub enum SdlSink {
|
||||||
|
|
||||||
impl Open for SdlSink {
|
impl Open for SdlSink {
|
||||||
fn open(device: Option<String>, format: AudioFormat, sample_rate: u32) -> Self {
|
fn open(device: Option<String>, format: AudioFormat, sample_rate: u32) -> Self {
|
||||||
info!("Using SDL sink with format: {format:?}, sample rate: {sample_rate}");
|
info!(
|
||||||
|
"Using SdlSink with format: {format:?}, sample rate: {}",
|
||||||
|
CommonSampleRates::try_from(sample_rate)
|
||||||
|
.unwrap_or_default()
|
||||||
|
.to_string()
|
||||||
|
);
|
||||||
|
|
||||||
if device.is_some() {
|
if device.is_some() {
|
||||||
warn!("SDL sink does not support specifying a device name");
|
warn!("SDL sink does not support specifying a device name");
|
||||||
|
|
|
@ -1,11 +1,13 @@
|
||||||
use super::{Open, Sink, SinkAsBytes, SinkError, SinkResult};
|
use super::{Open, Sink, SinkAsBytes, SinkError, SinkResult};
|
||||||
use crate::config::AudioFormat;
|
|
||||||
use crate::convert::Converter;
|
|
||||||
use crate::decoder::AudioPacket;
|
|
||||||
use shell_words::split;
|
|
||||||
|
|
||||||
use std::io::{ErrorKind, Write};
|
use crate::{config::AudioFormat, convert::Converter, decoder::AudioPacket, CommonSampleRates};
|
||||||
use std::process::{exit, Child, Command, Stdio};
|
|
||||||
|
use std::{
|
||||||
|
io::{ErrorKind, Write},
|
||||||
|
process::{exit, Child, Command, Stdio},
|
||||||
|
};
|
||||||
|
|
||||||
|
use shell_words::split;
|
||||||
use thiserror::Error;
|
use thiserror::Error;
|
||||||
|
|
||||||
#[derive(Debug, Error)]
|
#[derive(Debug, Error)]
|
||||||
|
@ -72,7 +74,12 @@ impl Open for SubprocessSink {
|
||||||
exit(0);
|
exit(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
info!("Using SubprocessSink with format: {format:?}, sample rate: {sample_rate}");
|
info!(
|
||||||
|
"Using SubprocessSink with format: {format:?}, sample rate: {}",
|
||||||
|
CommonSampleRates::try_from(sample_rate)
|
||||||
|
.unwrap_or_default()
|
||||||
|
.to_string()
|
||||||
|
);
|
||||||
|
|
||||||
Self {
|
Self {
|
||||||
shell_command,
|
shell_command,
|
||||||
|
|
|
@ -28,13 +28,6 @@ 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 PAGES_PER_MS: f64 = SAMPLE_RATE as f64 / 1000.0;
|
||||||
pub const MS_PER_PAGE: f64 = 1000.0 / SAMPLE_RATE as f64;
|
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 {
|
pub fn db_to_ratio(db: f64) -> f64 {
|
||||||
f64::powf(10.0, db / DB_VOLTAGE_RATIO)
|
f64::powf(10.0, db / DB_VOLTAGE_RATIO)
|
||||||
}
|
}
|
||||||
|
@ -43,8 +36,6 @@ pub fn ratio_to_db(ratio: f64) -> f64 {
|
||||||
ratio.log10() * DB_VOLTAGE_RATIO
|
ratio.log10() * DB_VOLTAGE_RATIO
|
||||||
}
|
}
|
||||||
|
|
||||||
// not used by all backends
|
|
||||||
#[allow(dead_code)]
|
|
||||||
#[derive(Copy, Clone, Debug, Default)]
|
#[derive(Copy, Clone, Debug, Default)]
|
||||||
pub enum CommonSampleRates {
|
pub enum CommonSampleRates {
|
||||||
#[default]
|
#[default]
|
||||||
|
|
Loading…
Reference in a new issue