use std::any::Any;
use std::fmt;
use std::future::Future;
use std::path::PathBuf;
use std::pin::Pin;
use std::sync::Arc;
use std::time::{Duration, Instant};
use crate::{CompositionLayer, Cue, Size};
pub trait Players {
fn open(&self, url: &str) -> Box<dyn MediaPlayer>;
}
pub trait MediaPlayer {
fn play(&self);
fn pause(&self);
fn seek(&self, position: Duration, tolerance: SeekTolerance);
fn set_rate(&self, rate: f64);
fn set_volume(&self, volume: f64);
fn set_muted(&self, muted: bool);
fn set_looping(&self, looping: bool);
fn state(&self) -> PlayerState;
fn position(&self) -> Duration;
fn changed(&self) -> MediaChangeFuture;
fn set_video_output(&self, output: Option<VideoOutput>);
fn select_audio_track(&self, id: &str);
fn select_text_track(&self, id: Option<&str>);
fn metadata(&self) -> MediaMetadata;
fn cues(&self) -> Vec<Cue>;
}
#[derive(Clone)]
pub enum VideoOutput {
Layer(Arc<dyn CompositionLayer>),
Frames(Arc<dyn VideoFrameReader>),
}
#[derive(Clone, Debug, PartialEq)]
pub struct PlayerState {
pub status: PlayerStatus,
pub activity: PlayerActivity,
pub seeking: Option<Duration>,
pub rate: f64,
pub volume: f64,
pub muted: bool,
pub duration: Option<Duration>,
pub loaded: Vec<TimeRange>,
pub seekable: Vec<TimeRange>,
pub size: Option<Size>,
pub tracks: Vec<MediaTrack>,
}
impl PlayerState {
pub fn loading() -> PlayerState {
PlayerState {
status: PlayerStatus::Loading,
activity: PlayerActivity::Paused(Some(PauseReason::Requested)),
seeking: None,
rate: 1.0,
volume: 1.0,
muted: false,
duration: None,
loaded: Vec::new(),
seekable: Vec::new(),
size: None,
tracks: Vec::new(),
}
}
pub fn failed(error: PlayerError) -> PlayerState {
PlayerState {
status: PlayerStatus::Failed(error),
activity: PlayerActivity::Paused(None),
..PlayerState::loading()
}
}
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub enum PlayerStatus {
Loading,
Ready,
Failed(PlayerError),
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum PlayerActivity {
Paused(Option<PauseReason>),
Waiting(Option<WaitReason>),
Playing,
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum PauseReason {
Requested,
End,
Interrupted,
OutputRemoved,
Backgrounded,
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum WaitReason {
Data,
EvaluatingData,
HeldBySystem,
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct PlayerError {
pub kind: PlayerErrorKind,
pub message: String,
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum PlayerErrorKind {
Network,
Decode,
Unsupported,
Protected,
Refused,
Other,
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub struct TimeRange {
pub start: Duration,
pub end: Duration,
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub struct SeekTolerance {
pub before: Duration,
pub after: Duration,
}
impl SeekTolerance {
pub const EXACT: SeekTolerance = SeekTolerance {
before: Duration::ZERO,
after: Duration::ZERO,
};
pub const ANY: SeekTolerance = SeekTolerance {
before: Duration::MAX,
after: Duration::MAX,
};
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct MediaTrack {
pub id: String,
pub kind: MediaTrackKind,
pub language: String,
pub label: String,
pub selected: bool,
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum MediaTrackKind {
Audio,
Video,
Text,
}
#[derive(Clone, Debug, Default, PartialEq, Eq)]
pub struct MediaMetadata {
pub title: Option<String>,
pub artist: Option<String>,
pub album: Option<String>,
pub artwork: Option<EncodedImage>,
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct EncodedImage {
pub mime_type: String,
pub data: Arc<[u8]>,
}
pub trait Cameras {
fn cameras(&self) -> CameraListFuture;
fn changed(&self) -> MediaChangeFuture;
fn open(&self, camera: &Camera) -> CameraOpenFuture;
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct Camera {
pub id: CameraId,
pub name: String,
pub facing: CameraFacing,
}
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
pub struct CameraId(pub String);
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum CameraFacing {
Front,
Back,
External,
}
pub trait CameraDevice {
fn formats(&self) -> Vec<CameraFormat>;
fn start(&self, format: &CameraFormat, outputs: CameraOutputs) -> CameraStartFuture;
}
#[derive(Clone, Debug, PartialEq)]
pub struct CameraFormat {
pub size: Size,
pub min_frame_rate: f64,
pub max_frame_rate: f64,
pub photo_sizes: Vec<Size>,
}
#[derive(Clone, Default)]
pub struct CameraOutputs {
pub preview: Option<Arc<dyn CompositionLayer>>,
pub frames: Option<Arc<dyn VideoFrameReader>>,
pub photos: Option<Size>,
pub movies: Option<MovieOptions>,
}
impl CameraOutputs {
pub fn new() -> CameraOutputs {
CameraOutputs::default()
}
pub fn preview(mut self, layer: Arc<dyn CompositionLayer>) -> CameraOutputs {
self.preview = Some(layer);
self
}
pub fn frames(mut self, reader: Arc<dyn VideoFrameReader>) -> CameraOutputs {
self.frames = Some(reader);
self
}
pub fn photos(mut self, size: Size) -> CameraOutputs {
self.photos = Some(size);
self
}
pub fn movies(mut self, options: MovieOptions) -> CameraOutputs {
self.movies = Some(options);
self
}
}
pub trait CaptureSession {
fn format(&self) -> CameraFormat;
fn state(&self) -> CaptureState;
fn changed(&self) -> MediaChangeFuture;
fn take_photo(&self) -> PhotoFuture;
fn start_recording(&self, path: PathBuf) -> RecordingFuture;
fn stop_recording(&self);
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub enum CaptureState {
Running,
Interrupted(Option<CameraInterruption>),
Ended(CameraError),
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum CameraInterruption {
InUseByAnotherApp,
Background,
SystemPressure,
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub enum CameraError {
NotAllowed,
InUse,
Unplugged,
Failed(String),
}
impl fmt::Display for CameraError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
CameraError::NotAllowed => f.write_str("the app may not use the camera"),
CameraError::InUse => f.write_str("another app has the camera"),
CameraError::Unplugged => f.write_str("the camera is no longer attached"),
CameraError::Failed(reason) => write!(f, "the camera failed: {reason}"),
}
}
}
impl std::error::Error for CameraError {}
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct Photo {
pub bytes: Vec<u8>,
pub mime_type: String,
}
#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
pub struct MovieOptions {
pub sound: bool,
}
pub trait VideoFrameReaders {
fn make_reader(&self) -> Arc<dyn VideoFrameReader>;
}
pub trait VideoFrameReader: Any + Send + Sync {
fn frame_for(&self, display_time: Instant) -> Option<Arc<dyn VideoFrame>>;
}
pub trait VideoFrame: Any + Send + Sync {
fn width(&self) -> u32;
fn height(&self) -> u32;
fn texture(&self, device: &wgpu::Device) -> Option<wgpu::Texture>;
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub enum MediaError {
NotRunning,
Failed(String),
}
impl fmt::Display for MediaError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
MediaError::NotRunning => f.write_str("the camera session does not run"),
MediaError::Failed(reason) => write!(f, "the camera failed: {reason}"),
}
}
}
impl std::error::Error for MediaError {}
pub type MediaChangeFuture = Pin<Box<dyn Future<Output = ()>>>;
pub type CameraListFuture = Pin<Box<dyn Future<Output = Vec<Camera>>>>;
pub type CameraOpenFuture =
Pin<Box<dyn Future<Output = Result<Box<dyn CameraDevice>, CameraError>>>>;
pub type CameraStartFuture =
Pin<Box<dyn Future<Output = Result<Box<dyn CaptureSession>, CameraError>>>>;
pub type PhotoFuture = Pin<Box<dyn Future<Output = Result<Photo, MediaError>>>>;
pub type RecordingFuture = Pin<Box<dyn Future<Output = Result<(), MediaError>>>>;