use serde::{Deserialize, Serialize};
pub use tarang::core;
pub use tarang::audio as media_audio;
pub use tarang::demux;
pub use tarang::video;
pub use tarang::ai as media_ai;
pub use tarang::core::TarangError;
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct MediaSource {
pub source: String,
pub state: PlaybackState,
pub volume: f32,
pub looping: bool,
#[serde(skip)]
pub position_secs: f64,
#[serde(skip)]
pub duration_secs: f64,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize, Default)]
#[non_exhaustive]
pub enum PlaybackState {
#[default]
Idle,
Playing,
Paused,
Finished,
Error,
}
impl MediaSource {
pub fn new(source: impl Into<String>) -> Self {
let source = source.into();
tracing::trace!(%source, "created media source");
Self {
source,
state: PlaybackState::Idle,
volume: 1.0,
looping: false,
position_secs: 0.0,
duration_secs: 0.0,
}
}
pub fn with_volume(mut self, volume: f32) -> Self {
self.volume = volume.clamp(0.0, 1.0);
self
}
pub fn with_looping(mut self) -> Self {
self.looping = true;
self
}
#[must_use]
#[inline]
pub fn is_playing(&self) -> bool {
self.state == PlaybackState::Playing
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn media_source_builder() {
let src = MediaSource::new("video/intro.mp4")
.with_volume(0.8)
.with_looping();
assert_eq!(src.source, "video/intro.mp4");
assert_eq!(src.volume, 0.8);
assert!(src.looping);
assert_eq!(src.state, PlaybackState::Idle);
assert!(!src.is_playing());
}
#[test]
fn media_source_default_state() {
let src = MediaSource::new("music/theme.ogg");
assert_eq!(src.state, PlaybackState::Idle);
assert_eq!(src.volume, 1.0);
assert!(!src.looping);
}
#[test]
fn media_source_volume_clamp() {
let src = MediaSource::new("test.wav").with_volume(5.0);
assert_eq!(src.volume, 1.0);
let src = MediaSource::new("test.wav").with_volume(-1.0);
assert_eq!(src.volume, 0.0);
}
#[test]
fn media_source_as_component() {
let mut world = crate::World::new();
let e = world.spawn();
world
.insert_component(e, MediaSource::new("cutscene.mp4"))
.unwrap();
assert!(world.has_component::<MediaSource>(e));
let src = world.get_component::<MediaSource>(e).unwrap();
assert_eq!(src.source, "cutscene.mp4");
}
}