Refactoring pmoflac - factorisation des erreurs
This commit is contained in:
@@ -20,39 +20,15 @@ use tokio::{
|
||||
|
||||
use crate::{
|
||||
common::ChannelReader,
|
||||
decoder_common::{spawn_ingest_task, spawn_writer_task, CHANNEL_CAPACITY, DUPLEX_BUFFER_SIZE},
|
||||
decoder_common::{
|
||||
spawn_ingest_task, spawn_writer_task, DecoderError, CHANNEL_CAPACITY, DUPLEX_BUFFER_SIZE,
|
||||
},
|
||||
pcm::StreamInfo,
|
||||
stream::ManagedAsyncReader,
|
||||
};
|
||||
|
||||
/// Errors that can occur while decoding AIFF data.
|
||||
#[derive(thiserror::Error, Debug, Clone)]
|
||||
pub enum AiffError {
|
||||
#[error("I/O error ({kind:?}): {message}")]
|
||||
Io {
|
||||
kind: io::ErrorKind,
|
||||
message: String,
|
||||
},
|
||||
#[error("AIFF decode error: {0}")]
|
||||
Decode(String),
|
||||
#[error("internal channel closed unexpectedly")]
|
||||
ChannelClosed,
|
||||
}
|
||||
|
||||
impl From<io::Error> for AiffError {
|
||||
fn from(err: io::Error) -> Self {
|
||||
AiffError::Io {
|
||||
kind: err.kind(),
|
||||
message: err.to_string(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<String> for AiffError {
|
||||
fn from(value: String) -> Self {
|
||||
AiffError::Decode(value)
|
||||
}
|
||||
}
|
||||
pub type AiffError = DecoderError;
|
||||
|
||||
/// Streaming reader that buffers bytes as they arrive and exposes convenience helpers.
|
||||
struct StreamingAiffReader<E>
|
||||
|
||||
@@ -23,17 +23,17 @@ pub enum DecodeAudioError {
|
||||
#[error("unknown or unsupported audio format")]
|
||||
UnknownFormat,
|
||||
#[error("FLAC decode error: {0}")]
|
||||
Flac(#[from] FlacError),
|
||||
Flac(FlacError),
|
||||
#[error("MP3 decode error: {0}")]
|
||||
Mp3(#[from] Mp3Error),
|
||||
Mp3(Mp3Error),
|
||||
#[error("Ogg/Vorbis decode error: {0}")]
|
||||
Vorbis(OggError),
|
||||
#[error("Ogg/Opus decode error: {0}")]
|
||||
Opus(OggOpusError),
|
||||
#[error("WAV decode error: {0}")]
|
||||
Wav(#[from] WavError),
|
||||
Wav(WavError),
|
||||
#[error("AIFF decode error: {0}")]
|
||||
Aiff(#[from] AiffError),
|
||||
Aiff(AiffError),
|
||||
}
|
||||
|
||||
pub async fn decode_audio_stream<R>(reader: R) -> Result<DecodedAudioStream, DecodeAudioError>
|
||||
@@ -59,11 +59,15 @@ where
|
||||
|
||||
let stream = match format {
|
||||
DetectedFormat::Flac => {
|
||||
let stream = decode_flac_stream(prefixed).await?;
|
||||
let stream = decode_flac_stream(prefixed)
|
||||
.await
|
||||
.map_err(DecodeAudioError::Flac)?;
|
||||
DecodedAudioStream::Flac(stream)
|
||||
}
|
||||
DetectedFormat::Mp3 => {
|
||||
let stream = decode_mp3_stream(prefixed).await?;
|
||||
let stream = decode_mp3_stream(prefixed)
|
||||
.await
|
||||
.map_err(DecodeAudioError::Mp3)?;
|
||||
DecodedAudioStream::Mp3(stream)
|
||||
}
|
||||
DetectedFormat::OggVorbis => {
|
||||
@@ -79,11 +83,15 @@ where
|
||||
DecodedAudioStream::OggOpus(stream)
|
||||
}
|
||||
DetectedFormat::Wav => {
|
||||
let stream = decode_wav_stream(prefixed).await?;
|
||||
let stream = decode_wav_stream(prefixed)
|
||||
.await
|
||||
.map_err(DecodeAudioError::Wav)?;
|
||||
DecodedAudioStream::Wav(stream)
|
||||
}
|
||||
DetectedFormat::Aiff => {
|
||||
let stream = decode_aiff_stream(prefixed).await?;
|
||||
let stream = decode_aiff_stream(prefixed)
|
||||
.await
|
||||
.map_err(DecodeAudioError::Aiff)?;
|
||||
DecodedAudioStream::Aiff(stream)
|
||||
}
|
||||
};
|
||||
@@ -114,16 +122,16 @@ impl DecodedAudioStream {
|
||||
|
||||
pub async fn wait(self) -> Result<(), DecodeAudioError> {
|
||||
match self {
|
||||
DecodedAudioStream::Flac(inner) => inner.wait().await.map_err(DecodeAudioError::from),
|
||||
DecodedAudioStream::Mp3(inner) => inner.wait().await.map_err(DecodeAudioError::from),
|
||||
DecodedAudioStream::Flac(inner) => inner.wait().await.map_err(DecodeAudioError::Flac),
|
||||
DecodedAudioStream::Mp3(inner) => inner.wait().await.map_err(DecodeAudioError::Mp3),
|
||||
DecodedAudioStream::OggVorbis(inner) => {
|
||||
inner.wait().await.map_err(DecodeAudioError::Vorbis)
|
||||
}
|
||||
DecodedAudioStream::OggOpus(inner) => {
|
||||
inner.wait().await.map_err(DecodeAudioError::Opus)
|
||||
}
|
||||
DecodedAudioStream::Wav(inner) => inner.wait().await.map_err(DecodeAudioError::from),
|
||||
DecodedAudioStream::Aiff(inner) => inner.wait().await.map_err(DecodeAudioError::from),
|
||||
DecodedAudioStream::Wav(inner) => inner.wait().await.map_err(DecodeAudioError::Wav),
|
||||
DecodedAudioStream::Aiff(inner) => inner.wait().await.map_err(DecodeAudioError::Aiff),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -186,12 +194,12 @@ pub enum DecodedReader {
|
||||
impl DecodedReader {
|
||||
pub async fn wait(self) -> Result<(), DecodeAudioError> {
|
||||
match self {
|
||||
DecodedReader::Flac(inner) => inner.wait().await.map_err(DecodeAudioError::from),
|
||||
DecodedReader::Mp3(inner) => inner.wait().await.map_err(DecodeAudioError::from),
|
||||
DecodedReader::Flac(inner) => inner.wait().await.map_err(DecodeAudioError::Flac),
|
||||
DecodedReader::Mp3(inner) => inner.wait().await.map_err(DecodeAudioError::Mp3),
|
||||
DecodedReader::OggVorbis(inner) => inner.wait().await.map_err(DecodeAudioError::Vorbis),
|
||||
DecodedReader::OggOpus(inner) => inner.wait().await.map_err(DecodeAudioError::Opus),
|
||||
DecodedReader::Wav(inner) => inner.wait().await.map_err(DecodeAudioError::from),
|
||||
DecodedReader::Aiff(inner) => inner.wait().await.map_err(DecodeAudioError::from),
|
||||
DecodedReader::Wav(inner) => inner.wait().await.map_err(DecodeAudioError::Wav),
|
||||
DecodedReader::Aiff(inner) => inner.wait().await.map_err(DecodeAudioError::Aiff),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,6 +12,41 @@ use tokio::{
|
||||
task::JoinHandle,
|
||||
};
|
||||
|
||||
/// Generic error type shared by the streaming decoders.
|
||||
#[derive(thiserror::Error, Debug, Clone)]
|
||||
pub enum DecoderError {
|
||||
#[error("I/O error ({kind:?}): {message}")]
|
||||
Io {
|
||||
kind: io::ErrorKind,
|
||||
message: String,
|
||||
},
|
||||
#[error("{0}")]
|
||||
Decode(String),
|
||||
#[error("internal channel closed unexpectedly")]
|
||||
ChannelClosed,
|
||||
}
|
||||
|
||||
impl From<io::Error> for DecoderError {
|
||||
fn from(err: io::Error) -> Self {
|
||||
DecoderError::Io {
|
||||
kind: err.kind(),
|
||||
message: err.to_string(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<String> for DecoderError {
|
||||
fn from(value: String) -> Self {
|
||||
DecoderError::Decode(value)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<&str> for DecoderError {
|
||||
fn from(value: &str) -> Self {
|
||||
DecoderError::Decode(value.to_owned())
|
||||
}
|
||||
}
|
||||
|
||||
/// Size of chunks when reading input data.
|
||||
///
|
||||
/// This size balances between efficient I/O operations and memory usage.
|
||||
|
||||
@@ -101,41 +101,15 @@ use tokio::{
|
||||
|
||||
use crate::{
|
||||
common::ChannelReader,
|
||||
decoder_common::{spawn_ingest_task, spawn_writer_task, CHANNEL_CAPACITY, DUPLEX_BUFFER_SIZE},
|
||||
decoder_common::{
|
||||
spawn_ingest_task, spawn_writer_task, DecoderError, CHANNEL_CAPACITY, DUPLEX_BUFFER_SIZE,
|
||||
},
|
||||
pcm::StreamInfo,
|
||||
stream::ManagedAsyncReader,
|
||||
};
|
||||
|
||||
/// Errors that can occur while decoding MP3 data.
|
||||
#[derive(thiserror::Error, Debug, Clone)]
|
||||
pub enum Mp3Error {
|
||||
#[error("I/O error ({kind:?}): {message}")]
|
||||
Io {
|
||||
kind: io::ErrorKind,
|
||||
message: String,
|
||||
},
|
||||
#[error("MP3 decode error: {0}")]
|
||||
Decode(String),
|
||||
#[error("internal channel closed unexpectedly")]
|
||||
ChannelClosed,
|
||||
#[error("{role} task failed: {details}")]
|
||||
TaskJoin { role: &'static str, details: String },
|
||||
}
|
||||
|
||||
impl From<io::Error> for Mp3Error {
|
||||
fn from(err: io::Error) -> Self {
|
||||
Mp3Error::Io {
|
||||
kind: err.kind(),
|
||||
message: err.to_string(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<String> for Mp3Error {
|
||||
fn from(msg: String) -> Self {
|
||||
Mp3Error::Decode(msg)
|
||||
}
|
||||
}
|
||||
pub type Mp3Error = DecoderError;
|
||||
|
||||
/// An async stream that decodes MP3 audio into PCM samples.
|
||||
///
|
||||
|
||||
@@ -25,7 +25,7 @@ use std::{
|
||||
io::{self, Read},
|
||||
};
|
||||
|
||||
use crate::common::ChannelReader;
|
||||
use crate::{common::ChannelReader, decoder_common::DecoderError};
|
||||
|
||||
/// Maximum number of bytes to scan when searching for Ogg sync pattern.
|
||||
///
|
||||
@@ -60,42 +60,7 @@ impl Default for OggReaderOptions {
|
||||
}
|
||||
}
|
||||
|
||||
/// Shared error type for Ogg container parsing.
|
||||
#[derive(thiserror::Error, Debug, Clone)]
|
||||
pub enum OggContainerError {
|
||||
#[error("I/O error ({kind:?}): {message}")]
|
||||
Io {
|
||||
kind: io::ErrorKind,
|
||||
message: String,
|
||||
},
|
||||
#[error("ogg container error: {0}")]
|
||||
Decode(String),
|
||||
#[error("internal channel closed unexpectedly")]
|
||||
ChannelClosed,
|
||||
#[error("{role} task failed: {details}")]
|
||||
TaskJoin { role: &'static str, details: String },
|
||||
}
|
||||
|
||||
impl From<io::Error> for OggContainerError {
|
||||
fn from(err: io::Error) -> Self {
|
||||
OggContainerError::Io {
|
||||
kind: err.kind(),
|
||||
message: err.to_string(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<String> for OggContainerError {
|
||||
fn from(value: String) -> Self {
|
||||
OggContainerError::Decode(value)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<&str> for OggContainerError {
|
||||
fn from(value: &str) -> Self {
|
||||
OggContainerError::Decode(value.into())
|
||||
}
|
||||
}
|
||||
pub type OggContainerError = DecoderError;
|
||||
|
||||
/// Streaming Ogg packet reader that assembles packets from Ogg pages.
|
||||
///
|
||||
|
||||
@@ -18,39 +18,15 @@ use tokio::{
|
||||
|
||||
use crate::{
|
||||
common::ChannelReader,
|
||||
decoder_common::{spawn_ingest_task, spawn_writer_task, CHANNEL_CAPACITY, DUPLEX_BUFFER_SIZE},
|
||||
decoder_common::{
|
||||
spawn_ingest_task, spawn_writer_task, DecoderError, CHANNEL_CAPACITY, DUPLEX_BUFFER_SIZE,
|
||||
},
|
||||
pcm::StreamInfo,
|
||||
stream::ManagedAsyncReader,
|
||||
};
|
||||
|
||||
/// Errors that can occur while decoding WAV data.
|
||||
#[derive(thiserror::Error, Debug, Clone)]
|
||||
pub enum WavError {
|
||||
#[error("I/O error ({kind:?}): {message}")]
|
||||
Io {
|
||||
kind: io::ErrorKind,
|
||||
message: String,
|
||||
},
|
||||
#[error("WAV decode error: {0}")]
|
||||
Decode(String),
|
||||
#[error("internal channel closed unexpectedly")]
|
||||
ChannelClosed,
|
||||
}
|
||||
|
||||
impl From<io::Error> for WavError {
|
||||
fn from(err: io::Error) -> Self {
|
||||
WavError::Io {
|
||||
kind: err.kind(),
|
||||
message: err.to_string(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<String> for WavError {
|
||||
fn from(value: String) -> Self {
|
||||
WavError::Decode(value)
|
||||
}
|
||||
}
|
||||
pub type WavError = DecoderError;
|
||||
|
||||
/// Streaming WAV reader state.
|
||||
struct StreamingWavReader<E>
|
||||
|
||||
Reference in New Issue
Block a user