using ytLive.Services.Audio; namespace ytLive.Services; /// /// TASK 21: a media file decoder exposed to . /// Mirrors IScreenCaptureSource/ICameraFrameSource so the manager /// (and tests) treat a local video file like any other frame source: start/stop /// and a per-frame event consumers coalesce. /// public interface IMediaFrameSource : IDisposable { string Key { get; } /// When true, the decoder restarts from the beginning on natural EOF /// instead of raising (used for BRB/starting-soon loops). bool Looping { get; set; } /// Raised (on a worker thread) for each decoded frame. event Action? FrameAvailable; /// Raised (on a worker thread) per chunk of the file's own soundtrack /// (48 kHz stereo float). The manager applies the layer's level/mute and hands it /// to the mixer; a source with no audio simply never raises it. event Action? AudioAvailable; /// Raised when the file finishes decoding (natural EOF) — not raised /// while is true. event Action? Completed; Task StartAsync(CancellationToken cancellationToken = default); Task StopAsync(); }