From 9c13232aa31b053f15cf7791dfa7b53437d8a5d9 Mon Sep 17 00:00:00 2001 From: David Wendt Date: Fri, 17 Mar 2023 22:25:54 -0400 Subject: [PATCH] core: Add a type to hold playing streams. Calling `StreamManager::tick` advances all streams to the appropriate time. This is an unlocked timestep to support things like non-stage-FPS video and the like. --- core/src/context.rs | 5 +++++ core/src/player.rs | 13 ++++++++++- core/src/streams.rs | 54 +++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 71 insertions(+), 1 deletion(-) diff --git a/core/src/context.rs b/core/src/context.rs index 755d3b0c9..ebd7abbff 100644 --- a/core/src/context.rs +++ b/core/src/context.rs @@ -20,6 +20,7 @@ use crate::library::Library; use crate::loader::LoadManager; use crate::player::Player; use crate::prelude::*; +use crate::streams::StreamManager; use crate::stub::StubCollection; use crate::tag_utils::{SwfMovie, SwfSlice}; use crate::timer::Timers; @@ -183,6 +184,9 @@ pub struct UpdateContext<'a, 'gc> { /// /// If we are not doing frame processing, then this is `FramePhase::Enter`. pub frame_phase: &'a mut FramePhase, + + /// Manager of in-progress media streams. + pub stream_manager: &'a mut StreamManager<'gc>, } /// Convenience methods for controlling audio. @@ -347,6 +351,7 @@ impl<'a, 'gc> UpdateContext<'a, 'gc> { frame_rate: self.frame_rate, actions_since_timeout_check: self.actions_since_timeout_check, frame_phase: self.frame_phase, + stream_manager: self.stream_manager, } } diff --git a/core/src/player.rs b/core/src/player.rs index 3a40c8a30..e9cea57d2 100644 --- a/core/src/player.rs +++ b/core/src/player.rs @@ -39,6 +39,7 @@ use crate::limits::ExecutionLimit; use crate::loader::{LoadBehavior, LoadManager}; use crate::locale::get_current_date_time; use crate::prelude::*; +use crate::streams::StreamManager; use crate::string::AvmString; use crate::stub::StubCollection; use crate::tag_utils::SwfMovie; @@ -153,6 +154,9 @@ struct GcRootData<'gc> { /// Manager of active sound instances. audio_manager: AudioManager<'gc>, + + /// List of actively playing streams to decode. + stream_manager: StreamManager<'gc>, } impl<'gc> GcRootData<'gc> { @@ -176,6 +180,7 @@ impl<'gc> GcRootData<'gc> { &mut Option>, &mut ExternalInterface<'gc>, &mut AudioManager<'gc>, + &mut StreamManager<'gc>, ) { ( self.stage, @@ -192,6 +197,7 @@ impl<'gc> GcRootData<'gc> { &mut self.current_context_menu, &mut self.external_interface, &mut self.audio_manager, + &mut self.stream_manager, ) } } @@ -526,10 +532,12 @@ impl Player { }); self.update_timers(dt); + self.update(|context| { + StreamManager::tick(context, dt); + }); self.audio.tick(); } } - pub fn time_til_next_timer(&self) -> Option { self.time_til_next_timer } @@ -1731,6 +1739,7 @@ impl Player { current_context_menu, external_interface, audio_manager, + stream_manager, ) = root_data.update_context_params(); let mut update_context = UpdateContext { @@ -1777,6 +1786,7 @@ impl Player { actions_since_timeout_check: &mut self.actions_since_timeout_check, frame_phase: &mut self.frame_phase, stub_tracker: &mut self.stub_tracker, + stream_manager, }; let old_frame_rate = *update_context.frame_rate; @@ -2273,6 +2283,7 @@ impl PlayerBuilder { ), timers: Timers::new(), unbound_text_fields: Vec::new(), + stream_manager: StreamManager::new(), }, ), }, diff --git a/core/src/streams.rs b/core/src/streams.rs index 704fe4682..14d6a05ee 100644 --- a/core/src/streams.rs +++ b/core/src/streams.rs @@ -1,7 +1,61 @@ +//! NetStream implementation + +use crate::context::UpdateContext; use crate::loader::Error; use gc_arena::{Collect, GcCell, MutationContext}; +/// Manager for all media streams. +/// +/// This does *not* handle data transport; which is delegated to `LoadManager`. +/// `StreamManager` *only* handles decoding or encoding of relevant media +/// streams. +#[derive(Collect)] +#[collect(no_drop)] +pub struct StreamManager<'gc> { + /// List of actively playing streams. + /// + /// This is not the total list of all created NetStreams; only the ones + /// that have been configured to play media. + playing_streams: Vec>, +} + +impl<'gc> Default for StreamManager<'gc> { + fn default() -> Self { + Self::new() + } +} + +impl<'gc> StreamManager<'gc> { + pub fn new() -> Self { + StreamManager { + playing_streams: Vec::new(), + } + } + + /// Process all playing media streams. + /// + /// This is an unlocked timestep; the `dt` parameter indicates how many + /// milliseconds have elapsed since the last tick. This is intended to + /// support video framerates separate from the Stage frame rate. + /// + /// This does not borrow `&mut self` as we need the `UpdateContext`, too. + pub fn tick(_context: &mut UpdateContext<'gc, '_>, _dt: f64) {} +} + /// A stream representing download of some (audiovisual) data. +/// +/// `NetStream` interacts with several different parts of player +/// infrastructure: +/// +/// * `LoadManager` fills individual `NetStream` buffers with data (or, in the +/// future, empties them out for media upload) +/// * `StreamManager` processes media data in the `NetStream` buffer (in the +/// future, sending it to the audio backend or `SoundManager`) +/// * `Video` display objects linked to this `NetStream` display the latest +/// decoded frame. +/// +/// It corresponds directly to the AVM1 and AVM2 `NetStream` classes; it's API +/// is intended to be a VM-agnostic version of those. #[derive(Clone, Debug, Collect)] #[collect(require_static)] pub struct NetStream {