Fix some REPL playback issues, including upgrading rodio to use more robust symphonia decoding

This commit is contained in:
NGnius (Graham) 2022-01-26 20:15:00 -05:00
parent 0c3f0fee9c
commit d3bb52d354
5 changed files with 35 additions and 61 deletions

5
Cargo.lock generated
View file

@ -1807,15 +1807,16 @@ dependencies = [
[[package]]
name = "rodio"
version = "0.14.0"
version = "0.15.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4d98f5e557b61525057e2bc142c8cd7f0e70d75dc32852309bec440e6e046bf9"
checksum = "ec0939e9f626e6c6f1989adb6226a039c855ca483053f0ee7c98b90e41cf731e"
dependencies = [
"claxon",
"cpal",
"hound",
"lewton",
"minimp3",
"symphonia",
]
[[package]]

View file

@ -6,7 +6,7 @@ license = "LGPL-2.1-only OR GPL-2.0-or-later"
readme = "README.md"
[dependencies]
rodio = { version = "^0.14"}
rodio = { version = "^0.15", features = ["symphonia"]}
m3u8-rs = { version = "^3.0.0" }
# local

View file

@ -1,6 +1,5 @@
use std::fs;
use std::io;
use std::path::PathBuf;
use rodio::{decoder::Decoder, OutputStream, OutputStreamHandle, Sink};
@ -40,22 +39,11 @@ impl<T: MpsTokenReader> MpsPlayer<T> {
if let Some(filename) =
music.field("filename").and_then(|x| x.to_owned().to_str())
{
let path: PathBuf = filename.into();
if let Some(ext) = path.extension().and_then(|x| x.to_str()) {
match ext {
"mp3"
| "wav"
| "flac"
| "aac"
| "ogg" => {
let file = fs::File::open(path).map_err(PlaybackError::from_err)?;
let stream = io::BufReader::new(file);
let source = Decoder::new(stream).map_err(PlaybackError::from_err)?;
self.sink.append(source);
},
_ => {}
}
}
// NOTE: Default rodio::Decoder hangs here when decoding large files, but symphonia does not
let file = fs::File::open(filename).map_err(PlaybackError::from_err)?;
let stream = io::BufReader::new(file);
let source = Decoder::new(stream).map_err(PlaybackError::from_err)?;
self.sink.append(source);
Ok(())
} else {
Err(PlaybackError::from_err(
@ -79,22 +67,11 @@ impl<T: MpsTokenReader> MpsPlayer<T> {
if let Some(filename) =
music.field("filename").and_then(|x| x.to_owned().to_str())
{
let path: PathBuf = filename.into();
if let Some(ext) = path.extension().and_then(|x| x.to_str()) {
match ext {
"mp3"
| "wav"
| "flac"
| "aac"
| "ogg" => {
let file = fs::File::open(path).map_err(PlaybackError::from_err)?;
let stream = io::BufReader::new(file);
let source = Decoder::new(stream).map_err(PlaybackError::from_err)?;
self.sink.append(source);
},
_ => {}
}
}
// NOTE: Default rodio::Decoder hangs here when decoding large files, but symphonia does not
let file = fs::File::open(filename).map_err(PlaybackError::from_err)?;
let stream = io::BufReader::new(file);
let source = Decoder::new(stream).map_err(PlaybackError::from_err)?;
self.sink.append(source);
Ok(())
} else {
Err(PlaybackError::from_err(
@ -120,24 +97,13 @@ impl<T: MpsTokenReader> MpsPlayer<T> {
if let Some(filename) =
music.field("filename").and_then(|x| x.to_owned().to_str())
{
let path: PathBuf = filename.into();
if let Some(ext) = path.extension().and_then(|x| x.to_str()) {
match ext {
"mp3"
| "wav"
| "flac"
| "aac"
| "ogg" => {
enqueued.push(music.clone());
let file = fs::File::open(path).map_err(PlaybackError::from_err)?;
let stream = io::BufReader::new(file);
let source = Decoder::new(stream).map_err(PlaybackError::from_err)?;
self.sink.append(source);
items_left -= 1;
},
_ => {}
}
}
enqueued.push(music.clone());
// NOTE: Default rodio::Decoder hangs here when decoding large files, but symphonia does not
let file = fs::File::open(filename).map_err(PlaybackError::from_err)?;
let stream = io::BufReader::new(file);
let source = Decoder::new(stream).map_err(PlaybackError::from_err)?;
self.sink.append(source);
items_left -= 1;
Ok(())
} else {
Err(PlaybackError::from_err(

View file

@ -39,7 +39,9 @@ impl<T: MpsTokenReader> MpsPlayerServer<T> {
fn enqeue_some(&mut self, count: usize) {
//println!("Enqueuing up to {} items", count);
match self.player.enqueue(count) {
Err(e) => self.event.send(PlayerAction::Exception(e)).unwrap(),
Err(e) => {
self.event.send(PlayerAction::Exception(e)).unwrap();
},
Ok(items) => {
for item in items {
// notify of new items that have been enqueued
@ -152,7 +154,7 @@ impl<T: MpsTokenReader> MpsPlayerServer<T> {
playback: Sender<PlaybackAction>,
keep_alive: bool,
) -> JoinHandle<()> {
thread::spawn(move || Self::unblocking_timer_loop(ctrl_tx, 50));
thread::spawn(move || Self::unblocking_timer_loop(ctrl_tx, 100));
thread::spawn(move || {
let player = factory();
let mut server_obj = Self::new(player, ctrl_rx, event, playback, keep_alive);

View file

@ -51,10 +51,10 @@ pub fn repl(args: CliArgs) {
match player.save_m3u8(&mut playlist_writer) {
Ok(_) => {}
Err(e) => {
eprintln!("{}", e.message());
error_prompt(e, &args);
// consume any further errors (this shouldn't actually write anything)
while let Err(e) = player.save_m3u8(&mut playlist_writer) {
eprintln!("{}", e.message());
error_prompt(e, &args);
}
}
}
@ -69,7 +69,7 @@ pub fn repl(args: CliArgs) {
if args.wait {
match ctrl.wait_for_empty() {
Ok(_) => {}
Err(e) => eprintln!("{}", e.message()),
Err(e) => error_prompt(e, &args),
}
} else {
// consume all incoming errors
@ -77,7 +77,7 @@ pub fn repl(args: CliArgs) {
while had_err {
let mut new_had_err = false;
for e in ctrl.check_ack() {
eprintln!("{}", e.message());
error_prompt(e, &args);
new_had_err = true;
}
had_err = new_had_err;
@ -127,7 +127,7 @@ fn read_loop<F: FnMut()>(args: &CliArgs, state: &mut ReplState, mut execute: F)
'\n' => {
let statement_result = std::str::from_utf8(state.statement_buf.as_slice());
if statement_result.is_ok() && statement_result.unwrap().trim().starts_with("?") {
println!("Got {}", statement_result.unwrap());
//println!("Got {}", statement_result.unwrap());
repl_commands(statement_result.unwrap().trim());
state.statement_buf.clear();
} else if state.bracket_depth == 0 && state.in_literal.is_none() {
@ -153,6 +153,11 @@ fn prompt(line: &mut usize, args: &CliArgs) {
std::io::stdout().flush().expect("Failed to flush stdout");
}
#[inline(always)]
fn error_prompt(error: mps_player::PlaybackError, args: &CliArgs) {
eprintln!("E{}{}", args.prompt, error.message());
}
fn repl_commands(command_str: &str) {
let words: Vec<&str> = command_str.split(" ").map(|s| s.trim()).collect();
match words[0] {