Voice Rework -- Events, Track Queues (#806)
This implements a proof-of-concept for an improved audio frontend. The largest change is the introduction of events and event handling: both by time elapsed and by track events, such as ending or looping. Following on from this, the library now includes a basic, event-driven track queue system (which people seem to ask for unusually often). A new sample, `examples/13_voice_events`, demonstrates both the `TrackQueue` system and some basic events via the `~queue` and `~play_fade` commands. Locks are removed from around the control of `Audio` objects, which should allow the backend to be moved to a more granular futures-based backend solution in a cleaner way.
This commit is contained in:
99
src/input/codec/mod.rs
Normal file
99
src/input/codec/mod.rs
Normal file
@@ -0,0 +1,99 @@
|
||||
//! Decoding schemes for input audio bytestreams.
|
||||
|
||||
mod opus;
|
||||
|
||||
pub use self::opus::OpusDecoderState;
|
||||
|
||||
use super::*;
|
||||
use std::{fmt::Debug, mem};
|
||||
|
||||
/// State used to decode input bytes of an [`Input`].
|
||||
///
|
||||
/// [`Input`]: ../struct.Input.html
|
||||
#[non_exhaustive]
|
||||
#[derive(Clone, Debug)]
|
||||
pub enum Codec {
|
||||
/// The inner bytestream is encoded using the Opus codec, to be decoded
|
||||
/// using the given state.
|
||||
///
|
||||
/// Must be combined with a non-[`Raw`] container.
|
||||
///
|
||||
/// [`Raw`]: ../enum.Container.html#variant.Raw
|
||||
Opus(OpusDecoderState),
|
||||
/// The inner bytestream is encoded using raw `i16` samples.
|
||||
///
|
||||
/// Must be combined with a [`Raw`] container.
|
||||
///
|
||||
/// [`Raw`]: ../enum.Container.html#variant.Raw
|
||||
Pcm,
|
||||
/// The inner bytestream is encoded using raw `f32` samples.
|
||||
///
|
||||
/// Must be combined with a [`Raw`] container.
|
||||
///
|
||||
/// [`Raw`]: ../enum.Container.html#variant.Raw
|
||||
FloatPcm,
|
||||
}
|
||||
|
||||
impl From<&Codec> for CodecType {
|
||||
fn from(f: &Codec) -> Self {
|
||||
use Codec::*;
|
||||
|
||||
match f {
|
||||
Opus(_) => Self::Opus,
|
||||
Pcm => Self::Pcm,
|
||||
FloatPcm => Self::FloatPcm,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Type of data being passed into an [`Input`].
|
||||
///
|
||||
/// [`Input`]: ../struct.Input.html
|
||||
#[non_exhaustive]
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
pub enum CodecType {
|
||||
/// The inner bytestream is encoded using the Opus codec.
|
||||
///
|
||||
/// Must be combined with a non-[`Raw`] container.
|
||||
///
|
||||
/// [`Raw`]: ../enum.Container.html#variant.Raw
|
||||
Opus,
|
||||
/// The inner bytestream is encoded using raw `i16` samples.
|
||||
///
|
||||
/// Must be combined with a [`Raw`] container.
|
||||
///
|
||||
/// [`Raw`]: ../enum.Container.html#variant.Raw
|
||||
Pcm,
|
||||
/// The inner bytestream is encoded using raw `f32` samples.
|
||||
///
|
||||
/// Must be combined with a [`Raw`] container.
|
||||
///
|
||||
/// [`Raw`]: ../enum.Container.html#variant.Raw
|
||||
FloatPcm,
|
||||
}
|
||||
|
||||
impl CodecType {
|
||||
/// Returns the length of a single output sample, in bytes.
|
||||
pub fn sample_len(&self) -> usize {
|
||||
use CodecType::*;
|
||||
|
||||
match self {
|
||||
Opus | FloatPcm => mem::size_of::<f32>(),
|
||||
Pcm => mem::size_of::<i16>(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFrom<CodecType> for Codec {
|
||||
type Error = Error;
|
||||
|
||||
fn try_from(f: CodecType) -> Result<Self> {
|
||||
use CodecType::*;
|
||||
|
||||
match f {
|
||||
Opus => Ok(Codec::Opus(OpusDecoderState::new()?)),
|
||||
Pcm => Ok(Codec::Pcm),
|
||||
FloatPcm => Ok(Codec::FloatPcm),
|
||||
}
|
||||
}
|
||||
}
|
||||
43
src/input/codec/opus.rs
Normal file
43
src/input/codec/opus.rs
Normal file
@@ -0,0 +1,43 @@
|
||||
use crate::constants::*;
|
||||
use audiopus::{coder::Decoder as OpusDecoder, Channels, Error as OpusError};
|
||||
use parking_lot::Mutex;
|
||||
use std::sync::Arc;
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
/// Inner state
|
||||
pub struct OpusDecoderState {
|
||||
/// Inner decoder used to convert opus frames into a stream of samples.
|
||||
pub decoder: Arc<Mutex<OpusDecoder>>,
|
||||
/// Controls whether this source allows direct Opus frame passthrough.
|
||||
/// Defaults to `true`.
|
||||
///
|
||||
/// Enabling this flag is a promise from the programmer to the audio core
|
||||
/// that the source has been encoded at 48kHz, using 20ms long frames.
|
||||
/// If you cannot guarantee this, disable this flag (or else risk nasal demons)
|
||||
/// and bizarre audio behaviour.
|
||||
pub allow_passthrough: bool,
|
||||
pub(crate) current_frame: Vec<f32>,
|
||||
pub(crate) frame_pos: usize,
|
||||
pub(crate) should_reset: bool,
|
||||
}
|
||||
|
||||
impl OpusDecoderState {
|
||||
/// Creates a new decoder, having stereo output at 48kHz.
|
||||
pub fn new() -> Result<Self, OpusError> {
|
||||
Ok(Self::from_decoder(OpusDecoder::new(
|
||||
SAMPLE_RATE,
|
||||
Channels::Stereo,
|
||||
)?))
|
||||
}
|
||||
|
||||
/// Creates a new decoder pre-configured by the user.
|
||||
pub fn from_decoder(decoder: OpusDecoder) -> Self {
|
||||
Self {
|
||||
decoder: Arc::new(Mutex::new(decoder)),
|
||||
allow_passthrough: true,
|
||||
current_frame: Vec::with_capacity(STEREO_FRAME_SIZE),
|
||||
frame_pos: 0,
|
||||
should_reset: false,
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user