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:
Kyle Simpson
2020-10-29 20:25:20 +00:00
committed by Alex M. M
commit 7e4392ae68
76 changed files with 8756 additions and 0 deletions

99
src/input/codec/mod.rs Normal file
View 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
View 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,
}
}
}