Fix some REPL playback issues, including upgrading rodio to use more robust symphonia decoding
This commit is contained in:
parent
0c3f0fee9c
commit
d3bb52d354
5 changed files with 35 additions and 61 deletions
5
Cargo.lock
generated
5
Cargo.lock
generated
|
@ -1807,15 +1807,16 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "rodio"
|
name = "rodio"
|
||||||
version = "0.14.0"
|
version = "0.15.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "4d98f5e557b61525057e2bc142c8cd7f0e70d75dc32852309bec440e6e046bf9"
|
checksum = "ec0939e9f626e6c6f1989adb6226a039c855ca483053f0ee7c98b90e41cf731e"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"claxon",
|
"claxon",
|
||||||
"cpal",
|
"cpal",
|
||||||
"hound",
|
"hound",
|
||||||
"lewton",
|
"lewton",
|
||||||
"minimp3",
|
"minimp3",
|
||||||
|
"symphonia",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
|
|
@ -6,7 +6,7 @@ license = "LGPL-2.1-only OR GPL-2.0-or-later"
|
||||||
readme = "README.md"
|
readme = "README.md"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
rodio = { version = "^0.14"}
|
rodio = { version = "^0.15", features = ["symphonia"]}
|
||||||
m3u8-rs = { version = "^3.0.0" }
|
m3u8-rs = { version = "^3.0.0" }
|
||||||
|
|
||||||
# local
|
# local
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
use std::fs;
|
use std::fs;
|
||||||
use std::io;
|
use std::io;
|
||||||
use std::path::PathBuf;
|
|
||||||
|
|
||||||
use rodio::{decoder::Decoder, OutputStream, OutputStreamHandle, Sink};
|
use rodio::{decoder::Decoder, OutputStream, OutputStreamHandle, Sink};
|
||||||
|
|
||||||
|
@ -40,22 +39,11 @@ impl<T: MpsTokenReader> MpsPlayer<T> {
|
||||||
if let Some(filename) =
|
if let Some(filename) =
|
||||||
music.field("filename").and_then(|x| x.to_owned().to_str())
|
music.field("filename").and_then(|x| x.to_owned().to_str())
|
||||||
{
|
{
|
||||||
let path: PathBuf = filename.into();
|
// NOTE: Default rodio::Decoder hangs here when decoding large files, but symphonia does not
|
||||||
if let Some(ext) = path.extension().and_then(|x| x.to_str()) {
|
let file = fs::File::open(filename).map_err(PlaybackError::from_err)?;
|
||||||
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 stream = io::BufReader::new(file);
|
||||||
let source = Decoder::new(stream).map_err(PlaybackError::from_err)?;
|
let source = Decoder::new(stream).map_err(PlaybackError::from_err)?;
|
||||||
self.sink.append(source);
|
self.sink.append(source);
|
||||||
},
|
|
||||||
_ => {}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Ok(())
|
Ok(())
|
||||||
} else {
|
} else {
|
||||||
Err(PlaybackError::from_err(
|
Err(PlaybackError::from_err(
|
||||||
|
@ -79,22 +67,11 @@ impl<T: MpsTokenReader> MpsPlayer<T> {
|
||||||
if let Some(filename) =
|
if let Some(filename) =
|
||||||
music.field("filename").and_then(|x| x.to_owned().to_str())
|
music.field("filename").and_then(|x| x.to_owned().to_str())
|
||||||
{
|
{
|
||||||
let path: PathBuf = filename.into();
|
// NOTE: Default rodio::Decoder hangs here when decoding large files, but symphonia does not
|
||||||
if let Some(ext) = path.extension().and_then(|x| x.to_str()) {
|
let file = fs::File::open(filename).map_err(PlaybackError::from_err)?;
|
||||||
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 stream = io::BufReader::new(file);
|
||||||
let source = Decoder::new(stream).map_err(PlaybackError::from_err)?;
|
let source = Decoder::new(stream).map_err(PlaybackError::from_err)?;
|
||||||
self.sink.append(source);
|
self.sink.append(source);
|
||||||
},
|
|
||||||
_ => {}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Ok(())
|
Ok(())
|
||||||
} else {
|
} else {
|
||||||
Err(PlaybackError::from_err(
|
Err(PlaybackError::from_err(
|
||||||
|
@ -120,24 +97,13 @@ impl<T: MpsTokenReader> MpsPlayer<T> {
|
||||||
if let Some(filename) =
|
if let Some(filename) =
|
||||||
music.field("filename").and_then(|x| x.to_owned().to_str())
|
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());
|
enqueued.push(music.clone());
|
||||||
let file = fs::File::open(path).map_err(PlaybackError::from_err)?;
|
// 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 stream = io::BufReader::new(file);
|
||||||
let source = Decoder::new(stream).map_err(PlaybackError::from_err)?;
|
let source = Decoder::new(stream).map_err(PlaybackError::from_err)?;
|
||||||
self.sink.append(source);
|
self.sink.append(source);
|
||||||
items_left -= 1;
|
items_left -= 1;
|
||||||
},
|
|
||||||
_ => {}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Ok(())
|
Ok(())
|
||||||
} else {
|
} else {
|
||||||
Err(PlaybackError::from_err(
|
Err(PlaybackError::from_err(
|
||||||
|
|
|
@ -39,7 +39,9 @@ impl<T: MpsTokenReader> MpsPlayerServer<T> {
|
||||||
fn enqeue_some(&mut self, count: usize) {
|
fn enqeue_some(&mut self, count: usize) {
|
||||||
//println!("Enqueuing up to {} items", count);
|
//println!("Enqueuing up to {} items", count);
|
||||||
match self.player.enqueue(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) => {
|
Ok(items) => {
|
||||||
for item in items {
|
for item in items {
|
||||||
// notify of new items that have been enqueued
|
// notify of new items that have been enqueued
|
||||||
|
@ -152,7 +154,7 @@ impl<T: MpsTokenReader> MpsPlayerServer<T> {
|
||||||
playback: Sender<PlaybackAction>,
|
playback: Sender<PlaybackAction>,
|
||||||
keep_alive: bool,
|
keep_alive: bool,
|
||||||
) -> JoinHandle<()> {
|
) -> JoinHandle<()> {
|
||||||
thread::spawn(move || Self::unblocking_timer_loop(ctrl_tx, 50));
|
thread::spawn(move || Self::unblocking_timer_loop(ctrl_tx, 100));
|
||||||
thread::spawn(move || {
|
thread::spawn(move || {
|
||||||
let player = factory();
|
let player = factory();
|
||||||
let mut server_obj = Self::new(player, ctrl_rx, event, playback, keep_alive);
|
let mut server_obj = Self::new(player, ctrl_rx, event, playback, keep_alive);
|
||||||
|
|
15
src/repl.rs
15
src/repl.rs
|
@ -51,10 +51,10 @@ pub fn repl(args: CliArgs) {
|
||||||
match player.save_m3u8(&mut playlist_writer) {
|
match player.save_m3u8(&mut playlist_writer) {
|
||||||
Ok(_) => {}
|
Ok(_) => {}
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
eprintln!("{}", e.message());
|
error_prompt(e, &args);
|
||||||
// consume any further errors (this shouldn't actually write anything)
|
// consume any further errors (this shouldn't actually write anything)
|
||||||
while let Err(e) = player.save_m3u8(&mut playlist_writer) {
|
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 {
|
if args.wait {
|
||||||
match ctrl.wait_for_empty() {
|
match ctrl.wait_for_empty() {
|
||||||
Ok(_) => {}
|
Ok(_) => {}
|
||||||
Err(e) => eprintln!("{}", e.message()),
|
Err(e) => error_prompt(e, &args),
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// consume all incoming errors
|
// consume all incoming errors
|
||||||
|
@ -77,7 +77,7 @@ pub fn repl(args: CliArgs) {
|
||||||
while had_err {
|
while had_err {
|
||||||
let mut new_had_err = false;
|
let mut new_had_err = false;
|
||||||
for e in ctrl.check_ack() {
|
for e in ctrl.check_ack() {
|
||||||
eprintln!("{}", e.message());
|
error_prompt(e, &args);
|
||||||
new_had_err = true;
|
new_had_err = true;
|
||||||
}
|
}
|
||||||
had_err = new_had_err;
|
had_err = new_had_err;
|
||||||
|
@ -127,7 +127,7 @@ fn read_loop<F: FnMut()>(args: &CliArgs, state: &mut ReplState, mut execute: F)
|
||||||
'\n' => {
|
'\n' => {
|
||||||
let statement_result = std::str::from_utf8(state.statement_buf.as_slice());
|
let statement_result = std::str::from_utf8(state.statement_buf.as_slice());
|
||||||
if statement_result.is_ok() && statement_result.unwrap().trim().starts_with("?") {
|
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());
|
repl_commands(statement_result.unwrap().trim());
|
||||||
state.statement_buf.clear();
|
state.statement_buf.clear();
|
||||||
} else if state.bracket_depth == 0 && state.in_literal.is_none() {
|
} 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");
|
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) {
|
fn repl_commands(command_str: &str) {
|
||||||
let words: Vec<&str> = command_str.split(" ").map(|s| s.trim()).collect();
|
let words: Vec<&str> = command_str.split(" ").map(|s| s.trim()).collect();
|
||||||
match words[0] {
|
match words[0] {
|
||||||
|
|
Loading…
Reference in a new issue