use std::sync::{Arc, Mutex};
pub trait HlsHandler: Send + Sync {
fn on_play(&self, url: &str, start_position: f32) -> Box<dyn HlsSession>;
}
pub trait HlsSession: Send {
fn duration(&self) -> f32;
fn position(&self) -> f32;
fn rate(&self) -> f32;
fn ready(&self) -> bool {
true
}
fn seek(&mut self, position: f32);
fn set_rate(&mut self, rate: f32);
fn stop(&mut self);
}
pub(crate) struct HlsState {
pub session: Option<Box<dyn HlsSession>>,
pub session_id: Option<String>,
}
impl HlsState {
pub fn new() -> Arc<Mutex<Self>> {
Arc::new(Mutex::new(Self {
session: None,
session_id: None,
}))
}
}
#[cfg(test)]
mod tests {
use super::*;
struct MockSession {
pos: f32,
rate: f32,
stopped: bool,
}
impl HlsSession for MockSession {
fn duration(&self) -> f32 {
120.0
}
fn position(&self) -> f32 {
self.pos
}
fn rate(&self) -> f32 {
self.rate
}
fn seek(&mut self, position: f32) {
self.pos = position;
}
fn set_rate(&mut self, rate: f32) {
self.rate = rate;
}
fn stop(&mut self) {
self.stopped = true;
self.rate = 0.0;
}
}
#[test]
fn hls_state_lifecycle() {
let state = HlsState::new();
{
let s = state.lock().unwrap();
assert!(s.session.is_none());
}
{
let mut s = state.lock().unwrap();
s.session = Some(Box::new(MockSession {
pos: 0.0,
rate: 1.0,
stopped: false,
}));
s.session_id = Some("test-123".into());
}
{
let s = state.lock().unwrap();
let session = s.session.as_ref().unwrap();
assert_eq!(session.duration(), 120.0);
assert_eq!(session.rate(), 1.0);
}
{
let mut s = state.lock().unwrap();
s.session.as_mut().unwrap().seek(60.0);
assert_eq!(s.session.as_ref().unwrap().position(), 60.0);
}
{
let mut s = state.lock().unwrap();
s.session.as_mut().unwrap().set_rate(0.0);
assert_eq!(s.session.as_ref().unwrap().rate(), 0.0);
}
{
let mut s = state.lock().unwrap();
s.session.as_mut().unwrap().stop();
assert_eq!(s.session.as_ref().unwrap().rate(), 0.0);
s.session = None;
}
let s = state.lock().unwrap();
assert!(s.session.is_none());
}
}