use std::{num::NonZeroU16, time::Duration};
use bitflags::bitflags;
use serde::{Deserialize, Serialize};
use zng_task::channel::IpcBytesCast;
use zng_txt::Txt;
use zng_unit::Factor;
use crate::api_extension::{ApiExtensionId, ApiExtensionPayload};
crate::declare_id! {
pub struct AudioDeviceId(_);
pub struct AudioId(_);
pub struct AudioOutputId(_);
pub struct AudioPlayId(_);
pub struct AudioEncodeId(_);
}
#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
#[non_exhaustive]
pub struct AudioDeviceInfo {
pub name: Txt,
pub capabilities: AudioDeviceCapability,
pub input_modes: Vec<AudioStreamMode>,
pub output_modes: Vec<AudioStreamMode>,
}
bitflags! {
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
pub struct AudioDeviceCapability: u8 {
const INPUT = 0b01;
const OUTPUT = 0b11;
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
#[non_exhaustive]
pub struct AudioStreamMode {
pub channels: NonZeroU16,
pub sample_rate: SampleRate,
pub buffer_size: BufferSize,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
pub struct SampleRate {
pub min: u32,
pub max: u32,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
#[non_exhaustive]
pub enum BufferSize {
Range {
min: u32,
max: u32,
},
Unknown,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[non_exhaustive]
pub struct AudioRequest<D> {
pub format: AudioDataFormat,
pub data: D,
pub max_decoded_len: u64,
pub tracks: AudioTracksMode,
pub parent: Option<AudioTrackMetadata>,
}
impl<D> AudioRequest<D> {
pub fn new(format: AudioDataFormat, data: D, max_decoded_len: u64) -> Self {
Self {
format,
data,
max_decoded_len,
tracks: AudioTracksMode::PRIMARY,
parent: None,
}
}
}
#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
#[non_exhaustive]
pub enum AudioDataFormat {
InterleavedF32 {
channel_count: u16,
sample_rate: u32,
total_duration: Option<Duration>,
},
FileExtension(Txt),
MimeType(Txt),
Unknown,
}
impl From<Txt> for AudioDataFormat {
fn from(ext_or_mime: Txt) -> Self {
if ext_or_mime.contains('/') {
AudioDataFormat::MimeType(ext_or_mime)
} else {
AudioDataFormat::FileExtension(ext_or_mime)
}
}
}
impl From<&str> for AudioDataFormat {
fn from(ext_or_mime: &str) -> Self {
Txt::from_str(ext_or_mime).into()
}
}
#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
#[non_exhaustive]
pub struct AudioFormat {
pub display_name: Txt,
pub media_type_suffixes: Txt,
pub file_extensions: Txt,
pub capabilities: AudioFormatCapability,
}
impl AudioFormat {
pub const fn from_static(
display_name: &'static str,
media_type_suffixes: &'static str,
file_extensions: &'static str,
capabilities: AudioFormatCapability,
) -> Self {
assert!(media_type_suffixes.is_ascii());
Self {
display_name: Txt::from_static(display_name),
media_type_suffixes: Txt::from_static(media_type_suffixes),
file_extensions: Txt::from_static(file_extensions),
capabilities,
}
}
pub fn media_type_suffixes_iter(&self) -> impl Iterator<Item = &str> {
self.media_type_suffixes.split(',').map(|e| e.trim())
}
pub fn media_types(&self) -> impl Iterator<Item = Txt> {
self.media_type_suffixes_iter().map(Txt::from_str)
}
pub fn file_extensions_iter(&self) -> impl Iterator<Item = &str> {
self.file_extensions.split(',').map(|e| e.trim())
}
pub fn matches(&self, f: &str) -> bool {
let f = f.strip_prefix('.').unwrap_or(f);
let f = f.strip_prefix("audio/").unwrap_or(f);
self.media_type_suffixes_iter().any(|e| e.eq_ignore_ascii_case(f)) || self.file_extensions_iter().any(|e| e.eq_ignore_ascii_case(f))
}
}
bitflags! {
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
pub struct AudioFormatCapability: u8 {
const ENCODE = 0b_0000_0001;
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[non_exhaustive]
pub struct AudioEncodeRequest {
pub id: AudioId,
pub format: Txt,
pub mix: AudioMix,
}
impl AudioEncodeRequest {
pub fn new(id: AudioId, format: Txt, mix: AudioMix) -> Self {
Self { id, format, mix }
}
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
#[non_exhaustive]
pub struct AudioMetadata {
pub id: AudioId,
pub channel_count: u16,
pub sample_rate: u32,
pub total_duration: Option<Duration>,
pub parent: Option<AudioTrackMetadata>,
pub extensions: Vec<(ApiExtensionId, ApiExtensionPayload)>,
}
impl AudioMetadata {
pub fn new(id: AudioId, channel_count: u16, sample_rate: u32) -> Self {
Self {
id,
channel_count,
sample_rate,
total_duration: None,
parent: None,
extensions: vec![],
}
}
}
impl Default for AudioMetadata {
fn default() -> Self {
Self {
id: AudioId::INVALID,
channel_count: Default::default(),
sample_rate: Default::default(),
total_duration: Default::default(),
parent: Default::default(),
extensions: vec![],
}
}
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
#[non_exhaustive]
pub struct AudioTrackMetadata {
pub parent: AudioId,
pub index: usize,
}
impl AudioTrackMetadata {
pub fn new(parent: AudioId, index: usize) -> Self {
Self { parent, index }
}
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
#[non_exhaustive]
pub struct AudioDecoded {
pub id: AudioId,
pub offset: usize,
pub chunk: IpcBytesCast<f32>,
pub is_full: bool,
}
impl AudioDecoded {
pub fn new(id: AudioId, chunk: IpcBytesCast<f32>) -> Self {
Self {
id,
offset: 0,
chunk,
is_full: false,
}
}
}
impl Default for AudioDecoded {
fn default() -> Self {
Self {
id: AudioId::INVALID,
offset: Default::default(),
chunk: Default::default(),
is_full: Default::default(),
}
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[non_exhaustive]
pub struct AudioOutputRequest {
pub id: AudioOutputId,
pub config: AudioOutputConfig,
}
impl AudioOutputRequest {
pub fn new(id: AudioOutputId, config: AudioOutputConfig) -> Self {
Self { id, config }
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[non_exhaustive]
pub struct AudioOutputUpdateRequest {
pub id: AudioOutputId,
pub config: AudioOutputConfig,
}
impl AudioOutputUpdateRequest {
pub fn new(id: AudioOutputId, config: AudioOutputConfig) -> Self {
Self { id, config }
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[non_exhaustive]
pub struct AudioOutputOpenData {
pub channel_count: u16,
pub sample_rate: u32,
}
impl AudioOutputOpenData {
pub fn new(channel_count: u16, sample_rate: u32) -> Self {
Self {
channel_count,
sample_rate,
}
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[non_exhaustive]
pub struct AudioOutputConfig {
pub state: AudioOutputState,
pub volume: Factor,
pub speed: Factor,
}
impl AudioOutputConfig {
pub fn new(state: AudioOutputState, volume: Factor, speed: Factor) -> Self {
Self { state, volume, speed }
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
#[non_exhaustive]
pub enum AudioOutputState {
Playing,
Paused,
Stopped,
}
impl AudioOutputState {
pub fn is_playing(&self) -> bool {
matches!(self, Self::Playing)
}
pub fn is_paused(&self) -> bool {
matches!(self, Self::Paused)
}
pub fn is_stopped(&self) -> bool {
matches!(self, Self::Stopped)
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[non_exhaustive]
pub struct AudioPlayRequest {
pub output: AudioOutputId,
pub mix: AudioMix,
}
impl AudioPlayRequest {
pub fn new(output: AudioOutputId, mix: AudioMix) -> Self {
Self { output, mix }
}
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
#[non_exhaustive]
pub struct AudioMix {
pub delay: Duration,
pub total_duration: Option<Duration>,
pub layers: Vec<AudioMixLayer>,
}
impl AudioMix {
pub fn new() -> Self {
Self {
delay: Duration::ZERO,
total_duration: None,
layers: vec![],
}
}
}
impl Default for AudioMix {
fn default() -> Self {
Self::new()
}
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
#[non_exhaustive]
pub enum AudioMixLayer {
Audio {
audio: AudioId,
skip: Duration,
take: Duration,
},
AudioMix {
mix: AudioMix,
skip: Duration,
take: Duration,
},
VolumeLinear {
start: Duration,
duration: Duration,
start_volume: Factor,
end_volume: Factor,
},
SineWave {
frequency: f32,
duration: Duration,
},
}
bitflags! {
#[derive(Copy, Debug, PartialEq, Eq, Clone, Hash, Serialize, Deserialize)]
pub struct AudioTracksMode: u8 {
const TRACKS = 0b0001;
const PRIMARY = 0;
}
}