From 47badd61e02e9d65b9e71e5bc04265c739faf58e Mon Sep 17 00:00:00 2001 From: Roderick van Domburg Date: Sat, 27 Nov 2021 14:26:13 +0100 Subject: [PATCH] Update tokio and fix build --- Cargo.lock | 24 ++-- playback/Cargo.toml | 2 +- playback/src/decoder/symphonia_decoder.rs | 136 ++++++++++++++++++++++ 3 files changed, 149 insertions(+), 13 deletions(-) create mode 100644 playback/src/decoder/symphonia_decoder.rs diff --git a/Cargo.lock b/Cargo.lock index 7eddf8df..57e50c03 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1808,18 +1808,18 @@ dependencies = [ [[package]] name = "pin-project" -version = "1.0.7" +version = "1.0.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c7509cc106041c40a4518d2af7a61530e1eed0e6285296a3d8c5472806ccc4a4" +checksum = "576bc800220cc65dac09e99e97b08b358cfab6e17078de8dc5fee223bd2d0c08" dependencies = [ "pin-project-internal", ] [[package]] name = "pin-project-internal" -version = "1.0.7" +version = "1.0.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "48c950132583b500556b1efd71d45b319029f2b71518d979fcc208e16b42426f" +checksum = "6e8fe8163d14ce7f0cdac2e040116f22eac817edabff0be91e8aff7e9accf389" dependencies = [ "proc-macro2", "quote", @@ -2498,9 +2498,9 @@ checksum = "cda74da7e1a664f795bb1f8a87ec406fb89a02522cf6e50620d016add6dbbf5c" [[package]] name = "tokio" -version = "1.6.0" +version = "1.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bd3076b5c8cc18138b8f8814895c11eb4de37114a5d127bafdc5e55798ceef37" +checksum = "70e992e41e0d2fb9f755b37446f20900f64446ef54874f40a60c78f021ac6144" dependencies = [ "autocfg", "bytes", @@ -2517,9 +2517,9 @@ dependencies = [ [[package]] name = "tokio-macros" -version = "1.2.0" +version = "1.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c49e3df43841dafb86046472506755d8501c5615673955f6aa17181125d13c37" +checksum = "c9efc1aba077437943f7515666aa2b882dfabfbfdf89c819ea75a8d6e9eaba5e" dependencies = [ "proc-macro2", "quote", @@ -2539,9 +2539,9 @@ dependencies = [ [[package]] name = "tokio-stream" -version = "0.1.6" +version = "0.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f8864d706fdb3cc0843a49647ac892720dac98a6eeb818b77190592cf4994066" +checksum = "50145484efff8818b5ccd256697f36863f587da82cf8b409c53adf1e840798e3" dependencies = [ "futures-core", "pin-project-lite", @@ -2567,9 +2567,9 @@ dependencies = [ [[package]] name = "tokio-util" -version = "0.6.7" +version = "0.6.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1caa0b0c8d94a049db56b5acf8cba99dc0623aab1b26d5b5f5e2d945846b3592" +checksum = "9e99e1983e5d376cd8eb4b66604d2e99e79f5bd988c3055891dcd8c9e2604cc0" dependencies = [ "bytes", "futures-core", diff --git a/playback/Cargo.toml b/playback/Cargo.toml index 0bed793c..96b3649a 100644 --- a/playback/Cargo.toml +++ b/playback/Cargo.toml @@ -23,7 +23,7 @@ futures-util = { version = "0.3", default_features = false, features = ["alloc"] log = "0.4" byteorder = "1.4" shell-words = "1.0.0" -tokio = { version = "1", features = ["sync"] } +tokio = { version = "1", features = ["rt", "rt-multi-thread", "sync"] } zerocopy = { version = "0.3" } # Backends diff --git a/playback/src/decoder/symphonia_decoder.rs b/playback/src/decoder/symphonia_decoder.rs new file mode 100644 index 00000000..309c495d --- /dev/null +++ b/playback/src/decoder/symphonia_decoder.rs @@ -0,0 +1,136 @@ +use super::{AudioDecoder, AudioPacket, DecoderError, DecoderResult}; + +use crate::audio::AudioFile; + +use symphonia::core::audio::{AudioBufferRef, Channels}; +use symphonia::core::codecs::Decoder; +use symphonia::core::errors::Error as SymphoniaError; +use symphonia::core::formats::{FormatReader, SeekMode, SeekTo}; +use symphonia::core::io::{MediaSource, MediaSourceStream}; +use symphonia::core::units::TimeStamp; +use symphonia::default::{codecs::VorbisDecoder, formats::OggReader}; + +use std::io::{Read, Seek, SeekFrom}; + +impl MediaSource for FileWithConstSize +where + R: Read + Seek + Send, +{ + fn is_seekable(&self) -> bool { + true + } + + fn byte_len(&self) -> Option { + Some(self.len()) + } +} + +pub struct FileWithConstSize { + stream: T, + len: u64, +} + +impl FileWithConstSize { + pub fn len(&self) -> u64 { + self.len + } + + pub fn is_empty(&self) -> bool { + self.len() == 0 + } +} + +impl FileWithConstSize +where + T: Seek, +{ + pub fn new(mut stream: T) -> Self { + stream.seek(SeekFrom::End(0)).unwrap(); + let len = stream.stream_position().unwrap(); + stream.seek(SeekFrom::Start(0)).unwrap(); + Self { stream, len } + } +} + +impl Read for FileWithConstSize +where + T: Read, +{ + fn read(&mut self, buf: &mut [u8]) -> std::io::Result { + self.stream.read(buf) + } +} + +impl Seek for FileWithConstSize +where + T: Seek, +{ + fn seek(&mut self, pos: SeekFrom) -> std::io::Result { + self.stream.seek(pos) + } +} + +pub struct SymphoniaDecoder { + track_id: u32, + decoder: Box, + format: Box, + position: TimeStamp, +} + +impl SymphoniaDecoder { + pub fn new(input: R) -> DecoderResult + where + R: Read + Seek, + { + let mss_opts = Default::default(); + let mss = MediaSourceStream::new(Box::new(FileWithConstSize::new(input)), mss_opts); + + let format_opts = Default::default(); + let format = OggReader::try_new(mss, &format_opts).map_err(|e| DecoderError::SymphoniaDecoder(e.to_string()))?; + + let track = format.default_track().unwrap(); + let decoder_opts = Default::default(); + let decoder = VorbisDecoder::try_new(&track.codec_params, &decoder_opts)?; + + Ok(Self { + track_id: track.id, + decoder: Box::new(decoder), + format: Box::new(format), + position: 0, + }) + } +} + +impl AudioDecoder for SymphoniaDecoder { + fn seek(&mut self, absgp: u64) -> DecoderResult<()> { + let seeked_to = self.format.seek( + SeekMode::Accurate, + SeekTo::Time { + time: absgp, // TODO : move to Duration + track_id: Some(self.track_id), + }, + )?; + self.position = seeked_to.actual_ts; + // TODO : Ok(self.position) + Ok(()) + } + + fn next_packet(&mut self) -> DecoderResult> { + let packet = match self.format.next_packet() { + Ok(packet) => packet, + Err(e) => { + log::error!("format error: {}", err); + return Err(DecoderError::SymphoniaDecoder(e.to_string())), + } + }; + match self.decoder.decode(&packet) { + Ok(audio_buf) => { + self.position += packet.frames() as TimeStamp; + Ok(Some(packet)) + } + // TODO: Handle non-fatal decoding errors and retry. + Err(e) => + return Err(DecoderError::SymphoniaDecoder(e.to_string())), + } + } +}