Implemented support for custom decoders
parent
6d673b5d9c
commit
7204270277
|
|
@ -6,7 +6,10 @@ use std::{
|
||||||
|
|
||||||
use crate::CliArgs;
|
use crate::CliArgs;
|
||||||
|
|
||||||
use self::{app::App, request_queue::request_queue_cleaner};
|
use self::{
|
||||||
|
app::{App, AppOptions},
|
||||||
|
request_queue::request_queue_cleaner,
|
||||||
|
};
|
||||||
|
|
||||||
pub mod app;
|
pub mod app;
|
||||||
pub mod crossterm;
|
pub mod crossterm;
|
||||||
|
|
@ -16,9 +19,13 @@ pub mod ui;
|
||||||
pub fn run(args: CliArgs) -> Result<(), Box<dyn Error>> {
|
pub fn run(args: CliArgs) -> Result<(), Box<dyn Error>> {
|
||||||
let message_queue = Arc::new(Mutex::new(vec![]));
|
let message_queue = Arc::new(Mutex::new(vec![]));
|
||||||
let server_state = Arc::new(Mutex::new(None));
|
let server_state = Arc::new(Mutex::new(None));
|
||||||
let app = App {
|
let options = AppOptions {
|
||||||
title: "rmp - Rust Music Player".into(),
|
title: "rmp - Rust Music Player".into(),
|
||||||
enhanced_graphics: args.enhanced_graphics,
|
enhanced_graphics: args.enhanced_graphics,
|
||||||
|
sync_state: args.sync_state,
|
||||||
|
};
|
||||||
|
let app = App {
|
||||||
|
options,
|
||||||
should_quit: false,
|
should_quit: false,
|
||||||
state: server_state.clone(),
|
state: server_state.clone(),
|
||||||
message_queue: message_queue.clone(),
|
message_queue: message_queue.clone(),
|
||||||
|
|
|
||||||
|
|
@ -9,19 +9,23 @@ use rmp::{
|
||||||
};
|
};
|
||||||
|
|
||||||
pub struct App {
|
pub struct App {
|
||||||
pub title: String,
|
pub options: AppOptions,
|
||||||
pub should_quit: bool,
|
pub should_quit: bool,
|
||||||
pub enhanced_graphics: bool,
|
|
||||||
pub message_queue: Arc<Mutex<Vec<Message>>>,
|
pub message_queue: Arc<Mutex<Vec<Message>>>,
|
||||||
pub state: Arc<Mutex<Option<ServerState>>>,
|
pub state: Arc<Mutex<Option<ServerState>>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub struct AppOptions {
|
||||||
|
pub title: String,
|
||||||
|
pub sync_state: bool,
|
||||||
|
pub enhanced_graphics: bool,
|
||||||
|
}
|
||||||
|
|
||||||
impl App {
|
impl App {
|
||||||
pub fn new(title: &str, enhanced_graphics: bool) -> Self {
|
pub fn new(options: AppOptions) -> Self {
|
||||||
Self {
|
Self {
|
||||||
title: title.to_string(),
|
options,
|
||||||
should_quit: false,
|
should_quit: false,
|
||||||
enhanced_graphics,
|
|
||||||
message_queue: Arc::new(Mutex::new(vec![])),
|
message_queue: Arc::new(Mutex::new(vec![])),
|
||||||
state: Arc::new(Mutex::new(None)),
|
state: Arc::new(Mutex::new(None)),
|
||||||
}
|
}
|
||||||
|
|
@ -85,6 +89,8 @@ impl App {
|
||||||
pub fn on_tab(&mut self) {}
|
pub fn on_tab(&mut self) {}
|
||||||
|
|
||||||
pub fn on_tick(&mut self, _duration: Duration) {
|
pub fn on_tick(&mut self, _duration: Duration) {
|
||||||
self.push_message(Message::new(MessageType::StateFetch, None));
|
if self.options.sync_state {
|
||||||
|
self.push_message(Message::new(MessageType::StateFetch, None));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -38,6 +38,10 @@ pub struct CliArgs {
|
||||||
#[argh(option, default = "100")]
|
#[argh(option, default = "100")]
|
||||||
message_rate: u64,
|
message_rate: u64,
|
||||||
|
|
||||||
|
/// should client automatically sync the server state? (used mainly for debugging)
|
||||||
|
#[argh(option, default = "true")]
|
||||||
|
sync_state: bool,
|
||||||
|
|
||||||
/// whether unicode symbols are used to improve the overall look of the app
|
/// whether unicode symbols are used to improve the overall look of the app
|
||||||
#[argh(option, default = "true")]
|
#[argh(option, default = "true")]
|
||||||
enhanced_graphics: bool,
|
enhanced_graphics: bool,
|
||||||
|
|
|
||||||
|
|
@ -16,6 +16,7 @@ use crate::CliArgs;
|
||||||
use self::playback::{playback_manager, Playback};
|
use self::playback::{playback_manager, Playback};
|
||||||
|
|
||||||
pub mod audio_backend;
|
pub mod audio_backend;
|
||||||
|
pub mod decoder;
|
||||||
pub mod playback;
|
pub mod playback;
|
||||||
|
|
||||||
pub struct Server {
|
pub struct Server {
|
||||||
|
|
@ -188,5 +189,5 @@ fn route_request(request: &Message, server: &mut Server) -> Result<Message, Stri
|
||||||
}
|
}
|
||||||
_ => return Ok(Message::new(MessageType::NotImplementedAck, None)),
|
_ => return Ok(Message::new(MessageType::NotImplementedAck, None)),
|
||||||
}
|
}
|
||||||
return Message::state_response(&server.state);
|
Message::state_response(&server.state)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,96 @@
|
||||||
|
// Implement decoders missing from rodio.
|
||||||
|
// At the moment this means opus, mod and xm.
|
||||||
|
|
||||||
|
use std::io::{Read, Seek};
|
||||||
|
|
||||||
|
pub mod opus;
|
||||||
|
|
||||||
|
pub enum SourceImpl<R>
|
||||||
|
where
|
||||||
|
R: Read + Seek,
|
||||||
|
{
|
||||||
|
Rodio(rodio::Decoder<R>),
|
||||||
|
// Custom(Decoder<R>),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<R> Iterator for SourceImpl<R>
|
||||||
|
where
|
||||||
|
R: Read + Seek,
|
||||||
|
{
|
||||||
|
type Item = i16;
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn next(&mut self) -> Option<Self::Item> {
|
||||||
|
match self {
|
||||||
|
Self::Rodio(source) => source.next(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<R> rodio::Source for SourceImpl<R>
|
||||||
|
where
|
||||||
|
R: Read + Seek,
|
||||||
|
{
|
||||||
|
#[inline]
|
||||||
|
fn current_frame_len(&self) -> Option<usize> {
|
||||||
|
match self {
|
||||||
|
Self::Rodio(source) => source.current_frame_len(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn channels(&self) -> u16 {
|
||||||
|
match self {
|
||||||
|
Self::Rodio(source) => source.channels(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn sample_rate(&self) -> u32 {
|
||||||
|
match self {
|
||||||
|
Self::Rodio(source) => source.sample_rate(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn total_duration(&self) -> Option<std::time::Duration> {
|
||||||
|
match self {
|
||||||
|
Self::Rodio(source) => source.total_duration(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub enum Decoder<R>
|
||||||
|
where
|
||||||
|
R: Read + Seek,
|
||||||
|
{
|
||||||
|
Opus(opus::OpusDecoder<R>),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<R> Decoder<R>
|
||||||
|
where
|
||||||
|
R: Read + Seek,
|
||||||
|
{
|
||||||
|
pub fn new(data: R) -> Result<SourceImpl<R>, ()>
|
||||||
|
where
|
||||||
|
R: Read + Seek + Send + Sync + 'static,
|
||||||
|
{
|
||||||
|
match rodio::Decoder::new(data) {
|
||||||
|
Ok(source) => return Ok(SourceImpl::Rodio(source)),
|
||||||
|
Err(err) => {
|
||||||
|
eprintln!(
|
||||||
|
"Rodio decode error:\n\terror: {err:?}\n\tcontinuing with custom decoder"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// match Decoder::new(data) {
|
||||||
|
// Ok(source) => return Ok(SourceImpl::Custom(source)),
|
||||||
|
// Err(err) => {
|
||||||
|
// eprintln!("Custom decode error:\n\terror: {err:?}\n\tPlayback failed");
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
Err(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,12 @@
|
||||||
|
use std::{
|
||||||
|
io::{Read, Seek},
|
||||||
|
marker::PhantomData,
|
||||||
|
};
|
||||||
|
|
||||||
|
/// Not implemented
|
||||||
|
pub struct OpusDecoder<R>
|
||||||
|
where
|
||||||
|
R: Read + Seek,
|
||||||
|
{
|
||||||
|
_data: PhantomData<R>,
|
||||||
|
}
|
||||||
|
|
@ -5,9 +5,9 @@ use std::{
|
||||||
sync::{Arc, Mutex},
|
sync::{Arc, Mutex},
|
||||||
};
|
};
|
||||||
|
|
||||||
use rodio::{Decoder, OutputStream, Sink};
|
use rodio::{OutputStream, Sink};
|
||||||
|
|
||||||
use super::Server;
|
use super::{decoder::Decoder, Server};
|
||||||
|
|
||||||
// HACK: hard-coded path to track
|
// HACK: hard-coded path to track
|
||||||
static TRACK: &str = "";
|
static TRACK: &str = "";
|
||||||
|
|
@ -49,10 +49,7 @@ pub fn playback_manager(server: Arc<Mutex<Server>>) {
|
||||||
let file = BufReader::new(File::open(&track).unwrap());
|
let file = BufReader::new(File::open(&track).unwrap());
|
||||||
let source = match Decoder::new(file) {
|
let source = match Decoder::new(file) {
|
||||||
Ok(source) => source,
|
Ok(source) => source,
|
||||||
Err(err) => {
|
Err(_) => continue,
|
||||||
eprintln!("Decode error:\n\ttrack: {track:?}\n\tinfo: {err:?}");
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
sink.clear();
|
sink.clear();
|
||||||
sink.append(source);
|
sink.append(source);
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue