From ec886e6f82a36a871fa4085657f57f7ebc7c6419 Mon Sep 17 00:00:00 2001 From: higumachan Date: Sat, 13 Aug 2022 18:01:28 +0900 Subject: [PATCH 01/15] Merge branch 'master' into refactor/f64_to_duration higumachan 2 minutes ago --- Cargo.lock | 11 +++ core/Cargo.toml | 1 + core/src/avm1/activation.rs | 5 +- core/src/avm1/globals/sound.rs | 2 +- core/src/avm2/activation.rs | 5 +- core/src/avm2/globals/flash/media/sound.rs | 4 +- core/src/backend/audio.rs | 63 ++++++++------ core/src/backend/audio/mixer.rs | 20 ++--- core/src/context.rs | 4 +- core/src/display_object/interactive.rs | 6 +- core/src/duration.rs | 99 ++++++++++++++++++++++ core/src/lib.rs | 1 + core/src/loader.rs | 2 +- core/src/player.rs | 55 ++++++------ core/src/timer.rs | 37 ++++---- desktop/src/audio.rs | 1 + desktop/src/main.rs | 9 +- scanner/src/execute.rs | 7 +- scanner/src/file_results.rs | 5 +- scanner/src/scan.rs | 2 +- tests/tests/regression_tests.rs | 10 +-- web/src/audio.rs | 7 +- web/src/lib.rs | 5 +- 23 files changed, 249 insertions(+), 112 deletions(-) create mode 100644 core/src/duration.rs diff --git a/Cargo.lock b/Cargo.lock index 90210eaf9ef06..b83caa57f4d41 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2932,6 +2932,16 @@ dependencies = [ "vcpkg", ] +[[package]] +name = "ordered-float" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "96bcbab4bfea7a59c2c0fe47211a1ac4e3e96bea6eb446d704f310bc5c732ae2" +dependencies = [ + "num-traits", + "serde", +] + [[package]] name = "os_str_bytes" version = "6.4.1" @@ -3403,6 +3413,7 @@ dependencies = [ "nellymoser-rs", "num-derive", "num-traits", + "ordered-float", "percent-encoding", "quick-xml", "rand", diff --git a/core/Cargo.toml b/core/Cargo.toml index ae921119647d2..378455578c994 100644 --- a/core/Cargo.toml +++ b/core/Cargo.toml @@ -46,6 +46,7 @@ enumset = "1.0.12" static_assertions = "1.1.0" rustversion = "1.0.9" bytemuck = "1.12.1" +ordered-float = { version = "3.0.0", features = ["serde"] } [target.'cfg(not(target_family = "wasm"))'.dependencies.futures] version = "0.3.25" diff --git a/core/src/avm1/activation.rs b/core/src/avm1/activation.rs index fdb8ae434fc16..38bb12ebf871f 100644 --- a/core/src/avm1/activation.rs +++ b/core/src/avm1/activation.rs @@ -9,6 +9,7 @@ use crate::avm1::{fscommand, globals, scope, ArrayObject, ScriptObject, Value}; use crate::backend::navigator::{NavigationMethod, Request}; use crate::context::UpdateContext; use crate::display_object::{DisplayObject, MovieClip, TDisplayObject, TDisplayObjectContainer}; +use crate::duration::RuffleDuration; use crate::ecma_conversions::f64_to_wrapping_u32; use crate::string::{AvmString, WStr, WString}; use crate::tag_utils::SwfSlice; @@ -434,7 +435,9 @@ impl<'a, 'gc, 'gc_context> Activation<'a, 'gc, 'gc_context> { *self.context.actions_since_timeout_check += 1; if *self.context.actions_since_timeout_check >= 2000 { *self.context.actions_since_timeout_check = 0; - if self.context.update_start.elapsed() >= self.context.max_execution_duration { + if RuffleDuration::from(self.context.update_start.elapsed()) + >= self.context.max_execution_duration + { return Err(Error::ExecutionTimeout); } } diff --git a/core/src/avm1/globals/sound.rs b/core/src/avm1/globals/sound.rs index 48944dc413f0b..bdee7826d2773 100644 --- a/core/src/avm1/globals/sound.rs +++ b/core/src/avm1/globals/sound.rs @@ -93,7 +93,7 @@ fn attach_sound<'gc>( .context .audio .get_sound_duration(*sound) - .map(|d| d.round() as u32), + .map(|d| d.as_millis().round() as u32), ); sound_object.set_position(activation.context.gc_context, 0); } else { diff --git a/core/src/avm2/activation.rs b/core/src/avm2/activation.rs index 40b43fb72d8cc..ce669e4bfe011 100644 --- a/core/src/avm2/activation.rs +++ b/core/src/avm2/activation.rs @@ -17,6 +17,7 @@ use crate::avm2::Namespace; use crate::avm2::QName; use crate::avm2::{value, Avm2, Error}; use crate::context::UpdateContext; +use crate::duration::RuffleDuration; use crate::string::{AvmString, WStr, WString}; use crate::swf::extensions::ReadSwfExt; use gc_arena::{Gc, GcCell}; @@ -946,7 +947,9 @@ impl<'a, 'gc, 'gc_context> Activation<'a, 'gc, 'gc_context> { self.actions_since_timeout_check += 1; if self.actions_since_timeout_check >= 2000 { self.actions_since_timeout_check = 0; - if self.context.update_start.elapsed() >= self.context.max_execution_duration { + if RuffleDuration::from(self.context.update_start.elapsed()) + >= self.context.max_execution_duration + { return Err( "A script in this movie has taken too long to execute and has been terminated." .into(), diff --git a/core/src/avm2/globals/flash/media/sound.rs b/core/src/avm2/globals/flash/media/sound.rs index 20e178473eaef..b248656c58b09 100644 --- a/core/src/avm2/globals/flash/media/sound.rs +++ b/core/src/avm2/globals/flash/media/sound.rs @@ -104,7 +104,7 @@ pub fn length<'gc>( ) -> Result, Error<'gc>> { if let Some(sound) = this.and_then(|this| this.as_sound()) { if let Some(duration) = activation.context.audio.get_sound_duration(sound) { - return Ok((duration).into()); + return Ok(duration.as_millis().into()); } } @@ -131,7 +131,7 @@ pub fn play<'gc>( let sound_transform = args.get(2).cloned().unwrap_or(Value::Null).as_object(); if let Some(duration) = activation.context.audio.get_sound_duration(sound) { - if position > duration { + if position > duration.as_millis() as f64 { return Ok(Value::Null); } } diff --git a/core/src/backend/audio.rs b/core/src/backend/audio.rs index 6e95402338526..3681cf9d11a83 100644 --- a/core/src/backend/audio.rs +++ b/core/src/backend/audio.rs @@ -1,3 +1,4 @@ +use crate::duration::RuffleDuration; use crate::{ avm1::SoundObject, avm2::SoundChannelObject, @@ -27,7 +28,6 @@ mod decoders { pub enum Error {} } -use instant::Duration; use thiserror::Error; pub type SoundHandle = Index; @@ -78,11 +78,11 @@ pub trait AudioBackend: Downcast { /// Get the position of a sound instance in milliseconds. /// Returns `None` if ther sound is not/no longer playing - fn get_sound_position(&self, instance: SoundInstanceHandle) -> Option; + fn get_sound_position(&self, instance: SoundInstanceHandle) -> Option; /// Get the duration of a sound in milliseconds. /// Returns `None` if sound is not registered. - fn get_sound_duration(&self, sound: SoundHandle) -> Option; + fn get_sound_duration(&self, sound: SoundHandle) -> Option; /// Get the size of the data stored within a given sound. /// @@ -118,7 +118,7 @@ pub trait AudioBackend: Downcast { /// value is unknown. /// /// This determines the time threshold for syncing embedded audio streams to the animation. - fn position_resolution(&self) -> Option { + fn position_resolution(&self) -> Option { None } @@ -137,7 +137,7 @@ impl_downcast!(AudioBackend); /// Information about a sound provided to `NullAudioBackend`. struct NullSound { /// The duration of the sound in milliseconds. - duration: f64, + duration: RuffleDuration, /// The compressed size of the sound data, excluding MP3 latency seek data. size: u32, @@ -175,7 +175,7 @@ impl AudioBackend for NullAudioBackend { // AS duration does not subtract `skip_sample_frames`. let num_sample_frames: f64 = sound.num_samples.into(); let sample_rate: f64 = sound.format.sample_rate.into(); - let duration = num_sample_frames * 1000.0 / sample_rate; + let duration = RuffleDuration::from_millis(num_sample_frames * 1000.0 / sample_rate); Ok(self.sounds.insert(NullSound { duration, @@ -187,7 +187,7 @@ impl AudioBackend for NullAudioBackend { fn register_mp3(&mut self, _data: &[u8]) -> Result { Ok(self.sounds.insert(NullSound { size: 0, - duration: 0.0, + duration: RuffleDuration::zero(), format: swf::SoundFormat { compression: swf::AudioCompression::Mp3, sample_rate: 44100, @@ -218,10 +218,10 @@ impl AudioBackend for NullAudioBackend { fn stop_sound(&mut self, _sound: SoundInstanceHandle) {} fn stop_all_sounds(&mut self) {} - fn get_sound_position(&self, _instance: SoundInstanceHandle) -> Option { - Some(0.0) + fn get_sound_position(&self, _instance: SoundInstanceHandle) -> Option { + Some(RuffleDuration::zero()) } - fn get_sound_duration(&self, sound: SoundHandle) -> Option { + fn get_sound_duration(&self, sound: SoundHandle) -> Option { if let Some(sound) = self.sounds.get(sound) { Some(sound.duration) } else { @@ -292,13 +292,18 @@ impl<'gc> AudioManager<'gc> { /// The default timeline stream buffer time in seconds. pub const DEFAULT_STREAM_BUFFER_TIME: i32 = 5; + /// The audio sycning threshold in seconds. + /// + /// The player will adjust animation speed to stay within this many seconds of the audio track. + pub const STREAM_SYNC_THRESHOLD: f64 = 1.0 / 60.0; + /// The threshold in seconds where an audio stream is considered too out-of-sync and will be stopped. - pub const STREAM_RESTART_THRESHOLD: f64 = 1.0; + pub const STREAM_RESTART_THRESHOLD: RuffleDuration = RuffleDuration::one_sec(); /// The minimum audio sycning threshold in seconds. /// /// The player will adjust animation speed to stay within this many seconds of the audio track. - pub const STREAM_DEFAULT_SYNC_THRESHOLD: f64 = 0.2; + pub const STREAM_DEFAULT_SYNC_THRESHOLD_SECONDS: f64 = 0.2; pub fn new() -> Self { Self { @@ -322,9 +327,9 @@ impl<'gc> AudioManager<'gc> { if let Some(pos) = audio.get_sound_position(sound.instance) { // Sounds still playing; update position. if let Some(avm1_object) = sound.avm1_object { - avm1_object.set_position(gc_context, pos.round() as u32); + avm1_object.set_position(gc_context, pos.as_millis().round() as u32); } else if let Some(avm2_object) = sound.avm2_object { - avm2_object.set_position(gc_context, pos); + avm2_object.set_position(gc_context, pos.as_millis()); } true } else { @@ -334,7 +339,7 @@ impl<'gc> AudioManager<'gc> { .and_then(|sound| audio.get_sound_duration(sound)) .unwrap_or_default(); if let Some(object) = sound.avm1_object { - object.set_position(gc_context, duration.round() as u32); + object.set_position(gc_context, duration.as_millis().round() as u32); // Fire soundComplete event. action_queue.queue_action( @@ -349,7 +354,7 @@ impl<'gc> AudioManager<'gc> { } if let Some(object) = sound.avm2_object { - object.set_position(gc_context, duration); + object.set_position(gc_context, duration.as_millis() as f64); //TODO: AVM2 events are usually not queued, but we can't //hold the update context in the audio manager yet. @@ -496,7 +501,11 @@ impl<'gc> AudioManager<'gc> { } /// Returns the difference in seconds between the primary audio stream's time and the player's time. - pub fn audio_skew_time(&mut self, audio: &mut dyn AudioBackend, offset_ms: f64) -> f64 { + pub fn audio_skew_time( + &mut self, + audio: &mut dyn AudioBackend, + offset: RuffleDuration, + ) -> RuffleDuration { // Consider the first playing "stream" sound to be the primary audio track. // Needs research: It's not clear how Flash handles the case of multiple stream sounds. let (i, skew) = self @@ -513,19 +522,19 @@ impl<'gc> AudioManager<'gc> { // Calculate the difference in time between the owning movie clip and its audio track. // If the difference is beyond some threshold, inform the player to adjust playback speed. - let timeline_pos = f64::from(clip.current_frame().saturating_sub(start_frame)) - / frame_rate - + offset_ms / 1000.0; - - Some((i, stream_pos / 1000.0 - timeline_pos)) + let timeline_pos = RuffleDuration::from_secs( + f64::from(clip.current_frame().saturating_sub(start_frame)) / frame_rate, + ) + offset.into(); + Some((i, RuffleDuration::from(stream_pos) - timeline_pos)) }) .unwrap_or_default(); // Calculate the syncing threshold based on the audio backend's frequency in updating sound position. let sync_threshold = audio .position_resolution() - .map(|duration| duration.as_secs_f64()) - .unwrap_or(Self::STREAM_DEFAULT_SYNC_THRESHOLD); + .unwrap_or(RuffleDuration::from_secs( + Self::STREAM_DEFAULT_SYNC_THRESHOLD_SECONDS, + )); if skew.abs() >= Self::STREAM_RESTART_THRESHOLD { // Way out of sync, let's stop the entire stream. @@ -533,13 +542,13 @@ impl<'gc> AudioManager<'gc> { let instance = &self.sounds[i]; audio.stop_sound(instance.instance); self.sounds.swap_remove(i); - 0.0 - } else if skew.abs() >= sync_threshold { + RuffleDuration::zero() + } else if skew.abs() < sync_threshold { // Slightly out of sync, adjust player speed to compensate. skew } else { // More or less in sync, no adjustment. - 0.0 + RuffleDuration::zero() } } diff --git a/core/src/backend/audio/mixer.rs b/core/src/backend/audio/mixer.rs index d517b545cce6d..fb0865f189fe4 100644 --- a/core/src/backend/audio/mixer.rs +++ b/core/src/backend/audio/mixer.rs @@ -1,6 +1,7 @@ use super::decoders::{self, AdpcmDecoder, Decoder, PcmDecoder, SeekableDecoder}; use super::{SoundHandle, SoundInstanceHandle, SoundTransform}; use crate::backend::audio::{DecodeError, RegisterError}; +use crate::duration::RuffleDuration; use crate::tag_utils::SwfSlice; use generational_arena::Arena; use std::io::Cursor; @@ -591,13 +592,13 @@ impl AudioMixer { /// Returns the position of a playing sound in milliseconds. /// ////// Returns `None` if the sound is no longer playing. - pub fn get_sound_position(&self, instance: SoundInstanceHandle) -> Option { + pub fn get_sound_position(&self, instance: SoundInstanceHandle) -> Option { let sound_instances = self.sound_instances.lock().unwrap(); sound_instances.get(instance).map(|instance| { // Get the current sample position from the underlying audio source. let num_sample_frames: f64 = instance.stream.source_position().into(); let sample_rate: f64 = instance.stream.source_sample_rate().into(); - num_sample_frames * 1000.0 / sample_rate + RuffleDuration::from_millis(num_sample_frames * 1000.0 / sample_rate) }) } @@ -609,16 +610,13 @@ impl AudioMixer { /// Returns the duration of a registered sound in milliseconds. /// /// Returns `None` if the sound is not registered or invalid. - pub fn get_sound_duration(&self, sound: SoundHandle) -> Option { - if let Some(sound) = self.sounds.get(sound) { + pub fn get_sound_duration(&self, sound: SoundHandle) -> Option { + self.sounds.get(sound).map(|sound| { // AS duration does not subtract `skip_sample_frames`. let num_sample_frames: f64 = sound.num_sample_frames.into(); let sample_rate: f64 = sound.format.sample_rate.into(); - let ms = num_sample_frames * 1000.0 / sample_rate; - Some(ms) - } else { - None - } + RuffleDuration::from_millis(num_sample_frames * 1000.0 / sample_rate) + }) } pub fn get_sound_size(&self, sound: SoundHandle) -> Option { @@ -1044,12 +1042,12 @@ macro_rules! impl_audio_mixer_backend { } #[inline] - fn get_sound_position(&self, instance: SoundInstanceHandle) -> Option { + fn get_sound_position(&self, instance: SoundInstanceHandle) -> Option { self.$mixer.get_sound_position(instance) } #[inline] - fn get_sound_duration(&self, sound: SoundHandle) -> Option { + fn get_sound_duration(&self, sound: SoundHandle) -> Option { self.$mixer.get_sound_duration(sound) } diff --git a/core/src/context.rs b/core/src/context.rs index c44a9e3b6be16..d05ce719d42d5 100644 --- a/core/src/context.rs +++ b/core/src/context.rs @@ -13,6 +13,7 @@ use crate::backend::{ }; use crate::context_menu::ContextMenuState; use crate::display_object::{EditText, InteractiveObject, MovieClip, SoundTransform, Stage}; +use crate::duration::RuffleDuration; use crate::external::ExternalInterface; use crate::focus_tracker::FocusTracker; use crate::frame_lifecycle::FramePhase; @@ -32,7 +33,6 @@ use ruffle_render::transform::TransformStack; use ruffle_video::backend::VideoBackend; use std::collections::{HashMap, VecDeque}; use std::sync::{Arc, Mutex, Weak}; -use std::time::Duration; /// `UpdateContext` holds shared data that is used by the various subsystems of Ruffle. /// `Player` creates this when it begins a tick and passes it through the call stack to @@ -158,7 +158,7 @@ pub struct UpdateContext<'a, 'gc, 'gc_context> { /// The maximum amount of time that can be called before a `Error::ExecutionTimeout` /// is raised. This defaults to 15 seconds but can be changed. - pub max_execution_duration: Duration, + pub max_execution_duration: RuffleDuration, /// A tracker for the current keyboard focused element pub focus_tracker: FocusTracker<'gc>, diff --git a/core/src/display_object/interactive.rs b/core/src/display_object/interactive.rs index 283e0f1b55256..d19d82fb7cd2f 100644 --- a/core/src/display_object/interactive.rs +++ b/core/src/display_object/interactive.rs @@ -13,6 +13,7 @@ use crate::display_object::stage::Stage; use crate::display_object::{ DisplayObject, DisplayObjectBase, TDisplayObject, TDisplayObjectContainer, }; +use crate::duration::RuffleDuration; use crate::events::{ClipEvent, ClipEventResult}; use bitflags::bitflags; use gc_arena::{Collect, MutationContext}; @@ -20,7 +21,6 @@ use instant::Instant; use ruffle_macros::enum_trait_object; use std::cell::{Ref, RefMut}; use std::fmt::Debug; -use std::time::Duration; use swf::Twips; /// Find the lowest common ancestor between the display objects in `from` and @@ -265,7 +265,9 @@ pub trait TInteractiveObject<'gc>: .flags .contains(InteractiveObjectFlags::DOUBLE_CLICK_ENABLED) && last_click - .map(|lc| this_click - lc < Duration::from_secs(1)) + .map(|lc| { + RuffleDuration::from(this_click - lc) < RuffleDuration::from_secs(1.0) + }) .unwrap_or(false); drop(read); diff --git a/core/src/duration.rs b/core/src/duration.rs new file mode 100644 index 0000000000000..d2f9365fb0c3e --- /dev/null +++ b/core/src/duration.rs @@ -0,0 +1,99 @@ +use num_traits::Zero; +use ordered_float::OrderedFloat; +use serde::{Deserialize, Serialize}; +use std::ops::{Add, AddAssign, Sub, SubAssign}; +use std::time::Duration; + +/// Duration f64 nanosec +#[derive(Debug, Copy, Clone, Ord, PartialOrd, Eq, PartialEq, Default, Serialize, Deserialize)] +pub struct RuffleDuration(OrderedFloat); + +impl RuffleDuration { + pub fn from_secs(secs: f64) -> Self { + Self::from_nanos(secs * 1_000_000_000.0) + } + + pub fn from_millis(millis: f64) -> Self { + Self::from_nanos(millis * 1_000_000.0) + } + + pub fn from_micros(micros: f64) -> Self { + Self::from_nanos(micros * 1_000.0) + } + + pub const fn from_nanos(nanosecs: f64) -> Self { + Self(OrderedFloat(nanosecs)) + } + + pub fn as_secs(&self) -> f64 { + self.0.into_inner() / 1_000_000_000.0 + } + + pub fn as_millis(self) -> f64 { + self.0.into_inner() / 1_000_000.0 + } + + pub fn as_micros(&self) -> f64 { + self.0.into_inner() / 1_000.0 + } + + pub fn as_nanos(&self) -> f64 { + self.0.into_inner() + } + + pub fn zero() -> Self { + Self(OrderedFloat::zero()) + } + + pub fn abs(&self) -> RuffleDuration { + Self(OrderedFloat(self.0.abs())) + } + + pub const fn one_sec() -> Self { + Self(OrderedFloat(1.0)) + } + + pub fn is_zero(&self) -> bool { + self.0.is_zero() + } +} + +impl Add for RuffleDuration { + type Output = Self; + + fn add(self, other: Self) -> Self { + Self(self.0 + other.0) + } +} + +impl AddAssign for RuffleDuration { + fn add_assign(&mut self, other: RuffleDuration) { + self.0 += other.0; + } +} + +impl Sub for RuffleDuration { + type Output = Self; + + fn sub(self, other: Self) -> Self { + Self(self.0 - other.0) + } +} + +impl SubAssign for RuffleDuration { + fn sub_assign(&mut self, rhs: Self) { + self.0 -= rhs.0; + } +} + +impl From for RuffleDuration { + fn from(d: std::time::Duration) -> Self { + Self::from_nanos(d.as_nanos() as f64) + } +} + +impl Into for RuffleDuration { + fn into(self) -> Duration { + Duration::from_nanos(self.as_nanos() as u64) + } +} diff --git a/core/src/lib.rs b/core/src/lib.rs index d260ca09c1b82..db14f8d4a35fa 100644 --- a/core/src/lib.rs +++ b/core/src/lib.rs @@ -44,6 +44,7 @@ mod xml; pub mod backend; pub mod config; +pub mod duration; pub mod external; pub use context_menu::ContextMenuItem; diff --git a/core/src/loader.rs b/core/src/loader.rs index bab6e4aada202..8036757021af3 100644 --- a/core/src/loader.rs +++ b/core/src/loader.rs @@ -1162,7 +1162,7 @@ impl<'gc> Loader<'gc> { let duration = uc .audio .get_sound_duration(handle) - .map(|d| d.round() as u32); + .map(|d| d.as_millis().round() as u32); sound_object.set_duration(uc.gc_context, duration); Ok(()) }) diff --git a/core/src/player.rs b/core/src/player.rs index 4d1bb879edd95..3ce058cb80e91 100644 --- a/core/src/player.rs +++ b/core/src/player.rs @@ -25,6 +25,7 @@ use crate::display_object::{ EditText, InteractiveObject, MovieClip, Stage, StageAlign, StageDisplayState, StageQuality, StageScaleMode, TInteractiveObject, WindowMode, }; +use crate::duration::RuffleDuration; use crate::events::{ButtonKeyCode, ClipEvent, ClipEventResult, KeyCode, MouseButton, PlayerEvent}; use crate::external::Value as ExternalValue; use crate::external::{ExternalInterface, ExternalInterfaceProvider}; @@ -54,7 +55,6 @@ use std::ops::DerefMut; use std::rc::{Rc, Weak as RcWeak}; use std::str::FromStr; use std::sync::{Arc, Mutex, Weak}; -use std::time::Duration; /// The newest known Flash Player version, serves as a default to /// `player_version`. @@ -241,7 +241,7 @@ pub struct Player { /// Gained by passage of time between host frames, spent by executing SWF frames. /// This is how we support custom SWF framerates /// and compensate for small lags by "catching up" (up to MAX_FRAMES_PER_TICK). - frame_accumulator: f64, + frame_accumulator: RuffleDuration, recent_run_frame_timings: VecDeque, /// Faked time passage for fooling hand-written busy-loop FPS limiters. @@ -261,14 +261,14 @@ pub struct Player { instance_counter: i32, /// Time remaining until the next timer will fire. - time_til_next_timer: Option, + time_til_next_timer: Option, /// The instant at which the SWF was launched. start_time: Instant, /// The maximum amount of time that can be called before a `Error::ExecutionTimeout` /// is raised. This defaults to 15 seconds but can be changed. - max_execution_duration: Duration, + max_execution_duration: RuffleDuration, /// Self-reference to ourselves. /// @@ -451,7 +451,7 @@ impl Player { } } - pub fn tick(&mut self, dt: f64) { + pub fn tick(&mut self, dt: RuffleDuration) { // Don't run until preloading is complete. // TODO: Eventually we want to stream content similar to the Flash player. if !self.audio.is_loading_complete() { @@ -461,7 +461,7 @@ impl Player { if self.is_playing() { self.frame_accumulator += dt; let frame_rate = self.frame_rate; - let frame_time = 1000.0 / frame_rate; + let frame_time = RuffleDuration::from_millis(1000.0 / frame_rate); let max_frames_per_tick = self.max_frames_per_tick(); let mut frame = 0; @@ -480,7 +480,7 @@ impl Player { // Then we need to actually pass this time, by decreasing frame_accumulator // to delay the future frame. if self.time_offset > 0 { - self.frame_accumulator -= self.time_offset as f64; + self.frame_accumulator -= RuffleDuration::from_millis(self.time_offset.into()); } } @@ -496,35 +496,36 @@ impl Player { // Sanity: If we had too many frames to tick, just reset the accumulator // to prevent running at turbo speed. if self.frame_accumulator >= frame_time { - self.frame_accumulator = 0.0; + self.frame_accumulator = RuffleDuration::zero(); } // Adjust playback speed for next frame to stay in sync with timeline audio tracks ("stream" sounds). let cur_frame_offset = self.frame_accumulator; - self.frame_accumulator += self.mutate_with_update_context(|context| { + + let add = self.mutate_with_update_context(|context| { context .audio_manager .audio_skew_time(context.audio, cur_frame_offset) - * 1000.0 }); + self.frame_accumulator += add; self.update_timers(dt); self.audio.tick(); } } - pub fn time_til_next_timer(&self) -> Option { + pub fn time_til_next_timer(&self) -> Option { self.time_til_next_timer } /// Returns the approximate duration of time until the next frame is due to run. /// This is only an approximation to be used for sleep durations. - pub fn time_til_next_frame(&self) -> std::time::Duration { - let frame_time = 1000.0 / self.frame_rate; - let mut dt = if self.frame_accumulator <= 0.0 { + pub fn time_til_next_frame(&self) -> RuffleDuration { + let frame_time = RuffleDuration::from_millis(1000.0 / self.frame_rate); + let mut dt = if self.frame_accumulator <= RuffleDuration::zero() { frame_time } else if self.frame_accumulator >= frame_time { - 0.0 + RuffleDuration::zero() } else { frame_time - self.frame_accumulator }; @@ -533,9 +534,9 @@ impl Player { dt = dt.min(time_til_next_timer) } - dt = dt.max(0.0); + dt = dt.max(RuffleDuration::zero()); - std::time::Duration::from_micros(dt as u64 * 1000) + dt } pub fn is_playing(&self) -> bool { @@ -1407,7 +1408,7 @@ impl Player { } pub fn run_frame(&mut self) { - let frame_time = Duration::from_nanos((750_000_000.0 / self.frame_rate) as u64); + let frame_time = std::time::Duration::from_nanos((750_000_000.0 / self.frame_rate) as u64); let (mut execution_limit, may_execute_while_streaming) = match self.load_behavior { LoadBehavior::Streaming => ( ExecutionLimit::with_max_ops_and_time(10000, frame_time), @@ -1808,7 +1809,7 @@ impl Player { /// Update all AVM-based timers (such as created via setInterval). /// Returns the approximate amount of time until the next timer tick. - pub fn update_timers(&mut self, dt: f64) { + pub fn update_timers(&mut self, dt: RuffleDuration) { self.time_til_next_timer = self.mutate_with_update_context(|context| Timers::update_timers(context, dt)); } @@ -1847,11 +1848,11 @@ impl Player { &self.log } - pub fn max_execution_duration(&self) -> Duration { + pub fn max_execution_duration(&self) -> RuffleDuration { self.max_execution_duration } - pub fn set_max_execution_duration(&mut self, max_execution_duration: Duration) { + pub fn set_max_execution_duration(&mut self, max_execution_duration: RuffleDuration) { self.max_execution_duration = max_execution_duration } @@ -1879,7 +1880,7 @@ pub struct PlayerBuilder { autoplay: bool, fullscreen: bool, letterbox: Letterbox, - max_execution_duration: Duration, + max_execution_duration: RuffleDuration, viewport_width: u32, viewport_height: u32, viewport_scale_factor: f64, @@ -1910,10 +1911,10 @@ impl PlayerBuilder { fullscreen: false, // Disable script timeout in debug builds by default. letterbox: Letterbox::Fullscreen, - max_execution_duration: Duration::from_secs(if cfg!(debug_assertions) { - u64::MAX + max_execution_duration: RuffleDuration::from_secs(if cfg!(debug_assertions) { + f64::MAX } else { - 15 + 15.0 }), viewport_width: 550, viewport_height: 400, @@ -1996,7 +1997,7 @@ impl PlayerBuilder { /// Sets the maximum execution time of ActionScript code. #[inline] - pub fn with_max_execution_duration(mut self, duration: Duration) -> Self { + pub fn with_max_execution_duration(mut self, duration: RuffleDuration) -> Self { self.max_execution_duration = duration; self } @@ -2091,7 +2092,7 @@ impl PlayerBuilder { // Timing frame_rate, frame_phase: Default::default(), - frame_accumulator: 0.0, + frame_accumulator: RuffleDuration::zero(), recent_run_frame_timings: VecDeque::with_capacity(10), start_time: Instant::now(), time_offset: 0, diff --git a/core/src/timer.rs b/core/src/timer.rs index a0e53e23472f1..d7e2214e8a2f6 100644 --- a/core/src/timer.rs +++ b/core/src/timer.rs @@ -11,9 +11,11 @@ use crate::avm1::{ use crate::avm2::object::TObject; use crate::avm2::{Activation as Avm2Activation, Object as Avm2Object, Value as Avm2Value}; use crate::context::UpdateContext; +use crate::duration::RuffleDuration; use crate::string::AvmString; use gc_arena::Collect; use std::collections::{binary_heap::PeekMut, BinaryHeap}; +use std::ops::{Add, AddAssign, Sub}; /// Manages the collection of timers. pub struct Timers<'gc> { @@ -24,16 +26,17 @@ pub struct Timers<'gc> { timer_counter: i32, /// The current global time. - cur_time: u64, + cur_time: RuffleDuration, } impl<'gc> Timers<'gc> { /// Ticks all timers and runs necessary callbacks. - pub fn update_timers(context: &mut UpdateContext<'_, 'gc, '_>, dt: f64) -> Option { - context.timers.cur_time = context - .timers - .cur_time - .wrapping_add((dt * Self::TIMER_SCALE) as u64); + pub fn update_timers( + context: &mut UpdateContext<'_, 'gc, '_>, + dt: RuffleDuration, + ) -> Option { + context.timers.cur_time.add_assign(dt); + let num_timers = context.timers.num_timers(); if num_timers == 0 { @@ -56,7 +59,7 @@ impl<'gc> Timers<'gc> { .context .timers .peek() - .map(|timer| timer.tick_time) + .map(|timer| RuffleDuration::from_micros(timer.tick_time as f64)) .unwrap_or(cur_time) < cur_time { @@ -73,8 +76,11 @@ impl<'gc> Timers<'gc> { // SANITY: Only allow so many ticks per timer per update. if tick_count > Self::MAX_TICKS { // Reset our time to a little bit before the nearest timer. - let next_time = activation.context.timers.peek_mut().unwrap().tick_time; - activation.context.timers.cur_time = next_time.wrapping_sub(100); + let next_time = RuffleDuration::from_micros( + activation.context.timers.peek_mut().unwrap().tick_time as f64, + ); + activation.context.timers.cur_time = + next_time.add(RuffleDuration::from_millis(100.0)); break; } @@ -156,7 +162,7 @@ impl<'gc> Timers<'gc> { .context .timers .peek() - .map(|timer| (timer.tick_time.wrapping_sub(cur_time)) as f64 / Self::TIMER_SCALE) + .map(|timer| (RuffleDuration::from_micros(timer.tick_time as f64).sub(cur_time))) } /// The minimum interval we allow for timers. @@ -165,15 +171,12 @@ impl<'gc> Timers<'gc> { /// The maximum timer ticks per call to `update_ticks`, for sanity. const MAX_TICKS: i32 = 10; - /// The scale of the timers (microseconds). - const TIMER_SCALE: f64 = 1000.0; - /// Creates a new `Timers` collection. pub fn new() -> Self { Self { timers: Default::default(), timer_counter: 0, - cur_time: 0, + cur_time: RuffleDuration::zero(), } } @@ -190,15 +193,15 @@ impl<'gc> Timers<'gc> { is_timeout: bool, ) -> i32 { // SANITY: Set a minimum interval so we don't spam too much. - let interval = interval.max(Self::MIN_INTERVAL) as u64 * (Self::TIMER_SCALE as u64); + let interval = RuffleDuration::from_millis(interval.max(Self::MIN_INTERVAL) as f64); self.timer_counter = self.timer_counter.wrapping_add(1); let id = self.timer_counter; let timer = Timer { id, callback, - tick_time: self.cur_time + interval, - interval, + tick_time: (self.cur_time + interval).as_micros() as u64, + interval: interval.as_micros() as u64, is_timeout, is_alive: std::cell::Cell::new(true), }; diff --git a/desktop/src/audio.rs b/desktop/src/audio.rs index e3ccf34bb42a5..8d48381c6c72f 100644 --- a/desktop/src/audio.rs +++ b/desktop/src/audio.rs @@ -4,6 +4,7 @@ use ruffle_core::backend::audio::{ swf, AudioBackend, AudioMixer, DecodeError, RegisterError, SoundHandle, SoundInstanceHandle, SoundTransform, }; +use ruffle_core::duration::RuffleDuration; use ruffle_core::impl_audio_mixer_backend; pub struct CpalAudioBackend { diff --git a/desktop/src/main.rs b/desktop/src/main.rs index 5dad8ba3729e6..84d891aa98f18 100644 --- a/desktop/src/main.rs +++ b/desktop/src/main.rs @@ -19,6 +19,7 @@ use anyhow::{anyhow, Context, Error}; use clap::Parser; use isahc::{config::RedirectPolicy, prelude::*, HttpClient}; use rfd::FileDialog; +use ruffle_core::duration::RuffleDuration; use ruffle_core::{ config::Letterbox, events::KeyCode, tag_utils::SwfMovie, LoadBehavior, Player, PlayerBuilder, PlayerEvent, StageDisplayState, StaticCallstack, ViewportDimensions, @@ -368,12 +369,12 @@ impl App { // Core loop winit::event::Event::MainEventsCleared if loaded => { let new_time = Instant::now(); - let dt = new_time.duration_since(time).as_micros(); - if dt > 0 { + let dt = RuffleDuration::from(new_time.duration_since(time)); + if !dt.is_zero() { time = new_time; let mut player_lock = self.player.lock().unwrap(); - player_lock.tick(dt as f64 / 1000.0); - next_frame_time = new_time + player_lock.time_til_next_frame(); + player_lock.tick(dt); + next_frame_time = new_time + player_lock.time_til_next_frame().into(); if player_lock.needs_render() { self.window.request_redraw(); } diff --git a/scanner/src/execute.rs b/scanner/src/execute.rs index a6dcfdfd065bc..b6211923298a3 100644 --- a/scanner/src/execute.rs +++ b/scanner/src/execute.rs @@ -4,6 +4,7 @@ use crate::cli_options::ExecuteReportOpt; use crate::file_results::{AvmType, FileResults, Step}; use crate::logging::{ScanLogBackend, ThreadLocalScanLogger, LOCAL_LOGGER}; use ruffle_core::backend::navigator::{NullExecutor, NullNavigatorBackend}; +use ruffle_core::duration::RuffleDuration; use ruffle_core::limits::ExecutionLimit; use ruffle_core::swf::{decompress_swf, parse_swf}; use ruffle_core::tag_utils::SwfMovie; @@ -18,11 +19,11 @@ fn execute_swf(file: &Path) { let base_path = file.parent().unwrap(); let executor = NullExecutor::new(); let movie = SwfMovie::from_path(file, None).unwrap(); - let frame_time = 1000.0 / movie.frame_rate().to_f64(); + let frame_time = RuffleDuration::from_millis(1000.0 / movie.frame_rate().to_f64()); let player = PlayerBuilder::new() .with_log(ScanLogBackend::new()) .with_navigator(NullNavigatorBackend::with_base_path(base_path, &executor)) - .with_max_execution_duration(Duration::from_secs(300)) + .with_max_execution_duration(RuffleDuration::from_secs(300.0)) .with_movie(movie) .build(); @@ -40,7 +41,7 @@ fn checkpoint( ) -> Result<(), std::io::Error> { let has_error = file_result.error.is_some(); - file_result.testing_time = start.elapsed().as_millis(); + file_result.testing_time = start.elapsed().into(); writer.serialize(file_result).unwrap(); if has_error { diff --git a/scanner/src/file_results.rs b/scanner/src/file_results.rs index 71224df8b4321..60048579e42c1 100644 --- a/scanner/src/file_results.rs +++ b/scanner/src/file_results.rs @@ -2,6 +2,7 @@ //! //! The `FileResults` type in this module is used to report results of a scan. +use ruffle_core::duration::RuffleDuration; use serde::de::{Error as DesError, Unexpected, Visitor}; use serde::ser::Error as SerError; use serde::{Deserialize, Deserializer, Serialize, Serializer}; @@ -77,7 +78,7 @@ pub struct FileResults { /// How long testing took to complete #[serde(rename = "Test Duration")] - pub testing_time: u128, + pub testing_time: RuffleDuration, /// The compressed length of the SWF file. #[serde(rename = "Compressed Length")] @@ -140,7 +141,7 @@ impl FileResults { name: name.to_string(), hash: vec![], progress: Step::Start, - testing_time: 0, + testing_time: RuffleDuration::zero(), compressed_len: None, uncompressed_len: None, error: None, diff --git a/scanner/src/scan.rs b/scanner/src/scan.rs index 73ce82ad1e0f7..f27cff9be01e0 100644 --- a/scanner/src/scan.rs +++ b/scanner/src/scan.rs @@ -105,7 +105,7 @@ pub fn scan_file>(exec_path: P, file: &DirEntry, name: &str) -> Err(e) => file_results.error = Some(e.to_string()), } - file_results.testing_time = start.elapsed().as_millis(); + file_results.testing_time = start.elapsed().into(); file_results } diff --git a/tests/tests/regression_tests.rs b/tests/tests/regression_tests.rs index 89ab27c4aab09..6ce7d6d34b6d6 100644 --- a/tests/tests/regression_tests.rs +++ b/tests/tests/regression_tests.rs @@ -18,6 +18,7 @@ use ruffle_core::tag_utils::SwfMovie; use ruffle_core::{Player, PlayerBuilder, PlayerEvent, ViewportDimensions}; use ruffle_input_format::{AutomatedEvent, InputInjector, MouseButton as InputMouseButton}; +use ruffle_core::duration::RuffleDuration; #[cfg(feature = "imgtests")] use ruffle_render_wgpu::backend::WgpuRenderBackend; #[cfg(feature = "imgtests")] @@ -1139,7 +1140,7 @@ fn timeout_avm1() -> Result<(), Error> { player .lock() .unwrap() - .set_max_execution_duration(Duration::from_secs(5)); + .set_max_execution_duration(RuffleDuration::from_secs(5.0)); Ok(()) }, |_| Ok(()), @@ -1385,8 +1386,7 @@ fn run_swf( let base_path = Path::new(swf_path).parent().unwrap(); let mut executor = NullExecutor::new(); let movie = SwfMovie::from_path(swf_path, None)?; - let frame_time = 1000.0 / movie.frame_rate().to_f64(); - let frame_time_duration = Duration::from_millis(frame_time as u64); + let frame_time = RuffleDuration::from_millis(1000.0 / movie.frame_rate().to_f64()); let trace_output = Rc::new(RefCell::new(Vec::new())); #[allow(unused_mut)] @@ -1420,7 +1420,7 @@ fn run_swf( let player = builder .with_log(TestLogBackend::new(trace_output.clone())) .with_navigator(NullNavigatorBackend::with_base_path(base_path, &executor)) - .with_max_execution_duration(Duration::from_secs(300)) + .with_max_execution_duration(RuffleDuration::from_secs(300.0)) .with_viewport_dimensions( movie.width().to_pixels() as u32, movie.height().to_pixels() as u32, @@ -1446,7 +1446,7 @@ fn run_swf( // with timer execution (timers will see an elapsed time of *at least* // the requested timer interval). if frame_time_sleep { - std::thread::sleep(frame_time_duration); + std::thread::sleep(Duration::from_nanos(frame_time.as_nanos() as u64)); } while !player diff --git a/web/src/audio.rs b/web/src/audio.rs index 68891773e3bf9..4ae5bd3121f22 100644 --- a/web/src/audio.rs +++ b/web/src/audio.rs @@ -2,6 +2,7 @@ use ruffle_core::backend::audio::{ swf, AudioBackend, AudioMixer, AudioMixerProxy, DecodeError, RegisterError, SoundHandle, SoundInstanceHandle, SoundTransform, }; +use ruffle_core::duration::RuffleDuration; use ruffle_core::impl_audio_mixer_backend; use ruffle_web_common::JsResult; use std::sync::{Arc, RwLock}; @@ -15,7 +16,7 @@ pub struct WebAudioBackend { context: AudioContext, buffers: Vec>>, time: Arc>, - position_resolution: Duration, + position_resolution: RuffleDuration, } impl WebAudioBackend { @@ -29,7 +30,7 @@ impl WebAudioBackend { mixer: AudioMixer::new(2, sample_rate as u32), buffers: Vec::with_capacity(2), time: Arc::new(RwLock::new(0.0)), - position_resolution: Duration::from_secs_f64( + position_resolution: RuffleDuration::from_secs( f64::from(Self::BUFFER_SIZE) / f64::from(sample_rate), ), }; @@ -62,7 +63,7 @@ impl AudioBackend for WebAudioBackend { let _ = self.context.suspend(); } - fn position_resolution(&self) -> Option { + fn position_resolution(&self) -> Option { Some(self.position_resolution) } } diff --git a/web/src/lib.rs b/web/src/lib.rs index a4a46bf78d1d7..a29bb4fefed2e 100644 --- a/web/src/lib.rs +++ b/web/src/lib.rs @@ -9,6 +9,7 @@ use generational_arena::{Arena, Index}; use js_sys::{Array, Function, JsString, Object, Promise, Uint8Array}; use ruffle_core::config::Letterbox; use ruffle_core::context::UpdateContext; +use ruffle_core::duration::RuffleDuration; use ruffle_core::events::{KeyCode, MouseButton, MouseWheelDelta}; use ruffle_core::external::{ ExternalInterfaceMethod, ExternalInterfaceProvider, Value as ExternalValue, Value, @@ -150,7 +151,7 @@ struct Config { log_level: log::Level, #[serde(rename = "maxExecutionDuration")] - max_execution_duration: Duration, + max_execution_duration: RuffleDuration, } /// Metadata about the playing SWF file to be passed back to JavaScript. @@ -985,7 +986,7 @@ impl Ruffle { }); } - core.tick(dt); + core.tick(RuffleDuration::from_millis(dt)); // Render if the core signals a new frame, or if we resized. if core.needs_render() || new_dimensions.is_some() { From 24fec7ee1b18a72a1607a0def3989ea6d9e8091b Mon Sep 17 00:00:00 2001 From: higumachan Date: Sat, 13 Aug 2022 18:27:38 +0900 Subject: [PATCH 02/15] fix comments --- core/src/avm2/object/soundchannel_object.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/core/src/avm2/object/soundchannel_object.rs b/core/src/avm2/object/soundchannel_object.rs index 981c0242cea89..e986eb4d76f4d 100644 --- a/core/src/avm2/object/soundchannel_object.rs +++ b/core/src/avm2/object/soundchannel_object.rs @@ -74,12 +74,12 @@ impl<'gc> SoundChannelObject<'gc> { self.0.read().sound } - /// Return the position of the playing sound in seconds. + /// Return the position of the playing sound in milliseconds. pub fn position(self) -> f64 { self.0.read().position } - /// Set the position of the playing sound in seconds. + /// Set the position of the playing sound in milliseconds. pub fn set_position(self, mc: MutationContext<'gc, '_>, value: f64) { self.0.write(mc).position = value; } From 18955efaf9e39b4425502aa154bc648c842dfbfa Mon Sep 17 00:00:00 2001 From: higumachan Date: Sat, 2 Jul 2022 01:20:10 +0900 Subject: [PATCH 03/15] To confirm, I changed the Duration of SOUND from MILLI SECOND to Duration. At that time, the regression test with a duration of sub nano second was dropped. --- Cargo.lock | 6 ++++ Cargo.toml | 1 + core/Cargo.toml | 1 + core/src/avm1/globals/sound.rs | 3 +- core/src/avm2/globals/flash/media/sound.rs | 3 +- core/src/backend/audio.rs | 13 +++++---- core/src/backend/audio/mixer.rs | 8 +++-- desktop/src/audio.rs | 1 + duration_helper/Cargo.toml | 8 +++++ duration_helper/src/lib.rs | 34 ++++++++++++++++++++++ web/Cargo.toml | 1 + web/src/audio.rs | 1 + 12 files changed, 69 insertions(+), 11 deletions(-) create mode 100644 duration_helper/Cargo.toml create mode 100644 duration_helper/src/lib.rs diff --git a/Cargo.lock b/Cargo.lock index b83caa57f4d41..fc987704cf275 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1229,6 +1229,10 @@ version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9ea835d29036a4087793836fa931b08837ad5e957da9e23886b29586fb9b6650" +[[package]] +name = "duration_helper" +version = "0.1.0" + [[package]] name = "dwrote" version = "0.11.0" @@ -3397,6 +3401,7 @@ dependencies = [ "chrono", "dasp", "downcast-rs", + "duration_helper", "encoding_rs", "enumset", "flash-lso", @@ -3608,6 +3613,7 @@ dependencies = [ "chrono", "console_error_panic_hook", "console_log", + "duration_helper", "generational-arena", "getrandom", "js-sys", diff --git a/Cargo.toml b/Cargo.toml index e75a6b73049ef..611843bbad6af 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -19,6 +19,7 @@ members = [ "video", "video/software", + "duration_helper", "tests", "tests/input-format", diff --git a/core/Cargo.toml b/core/Cargo.toml index 378455578c994..1b245daf1b16f 100644 --- a/core/Cargo.toml +++ b/core/Cargo.toml @@ -47,6 +47,7 @@ static_assertions = "1.1.0" rustversion = "1.0.9" bytemuck = "1.12.1" ordered-float = { version = "3.0.0", features = ["serde"] } +duration_helper = { path = "../duration_helper" } [target.'cfg(not(target_family = "wasm"))'.dependencies.futures] version = "0.3.25" diff --git a/core/src/avm1/globals/sound.rs b/core/src/avm1/globals/sound.rs index bdee7826d2773..d95ad6169d389 100644 --- a/core/src/avm1/globals/sound.rs +++ b/core/src/avm1/globals/sound.rs @@ -9,6 +9,7 @@ use crate::avm_warn; use crate::backend::navigator::Request; use crate::character::Character; use crate::display_object::{SoundTransform, TDisplayObject}; +use duration_helper::into_f64_millis; use gc_arena::MutationContext; const PROTO_DECLS: &[Declaration] = declare_properties! { @@ -93,7 +94,7 @@ fn attach_sound<'gc>( .context .audio .get_sound_duration(*sound) - .map(|d| d.as_millis().round() as u32), + .map(|d| into_f64_millis(d).round() as u32), ); sound_object.set_position(activation.context.gc_context, 0); } else { diff --git a/core/src/avm2/globals/flash/media/sound.rs b/core/src/avm2/globals/flash/media/sound.rs index b248656c58b09..d33cd758d7f92 100644 --- a/core/src/avm2/globals/flash/media/sound.rs +++ b/core/src/avm2/globals/flash/media/sound.rs @@ -12,6 +12,7 @@ use crate::avm2::QName; use crate::backend::navigator::Request; use crate::character::Character; use crate::display_object::SoundTransform; +use duration_helper::into_f64_millis; use gc_arena::{GcCell, MutationContext}; use swf::{SoundEvent, SoundInfo}; @@ -104,7 +105,7 @@ pub fn length<'gc>( ) -> Result, Error<'gc>> { if let Some(sound) = this.and_then(|this| this.as_sound()) { if let Some(duration) = activation.context.audio.get_sound_duration(sound) { - return Ok(duration.as_millis().into()); + return Ok((into_f64_millis(duration)).into()); } } diff --git a/core/src/backend/audio.rs b/core/src/backend/audio.rs index 3681cf9d11a83..543ad436b5ec6 100644 --- a/core/src/backend/audio.rs +++ b/core/src/backend/audio.rs @@ -1,12 +1,13 @@ -use crate::duration::RuffleDuration; use crate::{ avm1::SoundObject, avm2::SoundChannelObject, display_object::{self, DisplayObject, MovieClip, TDisplayObject}, }; use downcast_rs::Downcast; +use duration_helper::from_f64_millis; use gc_arena::Collect; use generational_arena::{Arena, Index}; +use std::time::Duration; #[cfg(feature = "audio")] pub mod decoders; @@ -82,7 +83,7 @@ pub trait AudioBackend: Downcast { /// Get the duration of a sound in milliseconds. /// Returns `None` if sound is not registered. - fn get_sound_duration(&self, sound: SoundHandle) -> Option; + fn get_sound_duration(&self, sound: SoundHandle) -> Option; /// Get the size of the data stored within a given sound. /// @@ -137,7 +138,7 @@ impl_downcast!(AudioBackend); /// Information about a sound provided to `NullAudioBackend`. struct NullSound { /// The duration of the sound in milliseconds. - duration: RuffleDuration, + duration: Duration, /// The compressed size of the sound data, excluding MP3 latency seek data. size: u32, @@ -175,7 +176,7 @@ impl AudioBackend for NullAudioBackend { // AS duration does not subtract `skip_sample_frames`. let num_sample_frames: f64 = sound.num_samples.into(); let sample_rate: f64 = sound.format.sample_rate.into(); - let duration = RuffleDuration::from_millis(num_sample_frames * 1000.0 / sample_rate); + let duration = from_f64_millis(num_sample_frames * 1000.0 / sample_rate); Ok(self.sounds.insert(NullSound { duration, @@ -221,7 +222,7 @@ impl AudioBackend for NullAudioBackend { fn get_sound_position(&self, _instance: SoundInstanceHandle) -> Option { Some(RuffleDuration::zero()) } - fn get_sound_duration(&self, sound: SoundHandle) -> Option { + fn get_sound_duration(&self, sound: SoundHandle) -> Option { if let Some(sound) = self.sounds.get(sound) { Some(sound.duration) } else { @@ -339,7 +340,7 @@ impl<'gc> AudioManager<'gc> { .and_then(|sound| audio.get_sound_duration(sound)) .unwrap_or_default(); if let Some(object) = sound.avm1_object { - object.set_position(gc_context, duration.as_millis().round() as u32); + object.set_position(gc_context, duration.as_millis() as u32); // Fire soundComplete event. action_queue.queue_action( diff --git a/core/src/backend/audio/mixer.rs b/core/src/backend/audio/mixer.rs index fb0865f189fe4..bacacaaa8aab9 100644 --- a/core/src/backend/audio/mixer.rs +++ b/core/src/backend/audio/mixer.rs @@ -3,9 +3,11 @@ use super::{SoundHandle, SoundInstanceHandle, SoundTransform}; use crate::backend::audio::{DecodeError, RegisterError}; use crate::duration::RuffleDuration; use crate::tag_utils::SwfSlice; +use duration_helper::from_f64_millis; use generational_arena::Arena; use std::io::Cursor; use std::sync::{Arc, Mutex, RwLock}; +use std::time::Duration; use swf::AudioCompression; /// Holds the last 2048 output audio frames. Frames can be written to it one by @@ -610,12 +612,12 @@ impl AudioMixer { /// Returns the duration of a registered sound in milliseconds. /// /// Returns `None` if the sound is not registered or invalid. - pub fn get_sound_duration(&self, sound: SoundHandle) -> Option { + pub fn get_sound_duration(&self, sound: SoundHandle) -> Option { self.sounds.get(sound).map(|sound| { // AS duration does not subtract `skip_sample_frames`. let num_sample_frames: f64 = sound.num_sample_frames.into(); let sample_rate: f64 = sound.format.sample_rate.into(); - RuffleDuration::from_millis(num_sample_frames * 1000.0 / sample_rate) + from_f64_millis(num_sample_frames * 1000.0 / sample_rate) }) } @@ -1047,7 +1049,7 @@ macro_rules! impl_audio_mixer_backend { } #[inline] - fn get_sound_duration(&self, sound: SoundHandle) -> Option { + fn get_sound_duration(&self, sound: SoundHandle) -> Option { self.$mixer.get_sound_duration(sound) } diff --git a/desktop/src/audio.rs b/desktop/src/audio.rs index 8d48381c6c72f..8fd3066af2ed3 100644 --- a/desktop/src/audio.rs +++ b/desktop/src/audio.rs @@ -6,6 +6,7 @@ use ruffle_core::backend::audio::{ }; use ruffle_core::duration::RuffleDuration; use ruffle_core::impl_audio_mixer_backend; +use std::time::Duration; pub struct CpalAudioBackend { #[allow(dead_code)] diff --git a/duration_helper/Cargo.toml b/duration_helper/Cargo.toml new file mode 100644 index 0000000000000..e09b7c4f27514 --- /dev/null +++ b/duration_helper/Cargo.toml @@ -0,0 +1,8 @@ +[package] +name = "duration_helper" +version = "0.1.0" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] diff --git a/duration_helper/src/lib.rs b/duration_helper/src/lib.rs new file mode 100644 index 0000000000000..e9da1b8e5cb5c --- /dev/null +++ b/duration_helper/src/lib.rs @@ -0,0 +1,34 @@ +use std::time::Duration; + +pub fn from_f64_millis(millis: f64) -> Duration { + Duration::from_nanos((millis * 1_000_000.0) as u64) +} + +pub fn into_f64_millis(duration: Duration) -> f64 { + duration.as_nanos() as f64 / 1_000_000.0 +} + +#[cfg(test)] +mod tests { + use std::time::Duration; + + #[test] + fn test_from_f64_millis_standard_case() { + assert_eq!(super::from_f64_millis(1.0), Duration::from_millis(1)); + } + + #[test] + fn test_from_f64_sub_millis_case() { + assert_eq!(super::from_f64_millis(1.5), Duration::from_micros(1500)); + } + + #[test] + fn test_into_f64_millis_standard_case() { + assert_eq!(super::into_f64_millis(Duration::from_millis(1)), 1.0); + } + + #[test] + fn test_into_f64_sub_millis_case() { + assert_eq!(super::into_f64_millis(Duration::from_micros(1500)), 1.5); + } +} diff --git a/web/Cargo.toml b/web/Cargo.toml index d7da5786780d2..27b2c2cdb5bcf 100644 --- a/web/Cargo.toml +++ b/web/Cargo.toml @@ -46,6 +46,7 @@ getrandom = { version = "0.2", features = ["js"] } serde = { version = "1.0.147", features = ["derive"] } thiserror = "1.0" base64 = "0.13.1" +duration_helper = { path = "../duration_helper" } [dependencies.ruffle_core] path = "../core" diff --git a/web/src/audio.rs b/web/src/audio.rs index 4ae5bd3121f22..533a985f06214 100644 --- a/web/src/audio.rs +++ b/web/src/audio.rs @@ -1,3 +1,4 @@ +use duration_helper::from_f64_millis; use ruffle_core::backend::audio::{ swf, AudioBackend, AudioMixer, AudioMixerProxy, DecodeError, RegisterError, SoundHandle, SoundInstanceHandle, SoundTransform, From fed9f74c7b460ebad881b811e7a25e2eaa4c8e44 Mon Sep 17 00:00:00 2001 From: higumachan Date: Sat, 2 Jul 2022 01:27:24 +0900 Subject: [PATCH 04/15] use round --- core/src/backend/audio.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/core/src/backend/audio.rs b/core/src/backend/audio.rs index 543ad436b5ec6..0c724c4a94934 100644 --- a/core/src/backend/audio.rs +++ b/core/src/backend/audio.rs @@ -7,7 +7,7 @@ use downcast_rs::Downcast; use duration_helper::from_f64_millis; use gc_arena::Collect; use generational_arena::{Arena, Index}; -use std::time::Duration; +use duration_helper::{from_f64_millis, into_f64_millis}; #[cfg(feature = "audio")] pub mod decoders; @@ -340,7 +340,7 @@ impl<'gc> AudioManager<'gc> { .and_then(|sound| audio.get_sound_duration(sound)) .unwrap_or_default(); if let Some(object) = sound.avm1_object { - object.set_position(gc_context, duration.as_millis() as u32); + object.set_position(gc_context, into_f64_millis(duration).round() as u32); // Fire soundComplete event. action_queue.queue_action( From 9d9a8633bcee43a6de33a4fcab6565710de46082 Mon Sep 17 00:00:00 2001 From: higumachan Date: Sun, 3 Jul 2022 22:20:18 +0900 Subject: [PATCH 05/15] replace other place f64 durations --- Cargo.lock | 29 +++++- core/src/avm1/globals/sound.rs | 1 + core/src/backend/audio.rs | 29 +++--- core/src/backend/audio/mixer.rs | 6 +- core/src/player.rs | 31 +++--- core/src/timer.rs | 25 ++--- desktop/src/main.rs | 4 +- duration_helper/Cargo.toml | 1 + duration_helper/src/lib.rs | 171 ++++++++++++++++++++++++++++++++ scanner/Cargo.toml | 1 + scanner/src/execute.rs | 3 +- tests/Cargo.toml | 1 + tests/tests/regression_tests.rs | 3 +- web/src/lib.rs | 3 +- 14 files changed, 252 insertions(+), 56 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index fc987704cf275..e0ecaf7ebbcbd 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -450,6 +450,7 @@ dependencies = [ "js-sys", "num-integer", "num-traits", + "time 0.1.45", "wasm-bindgen", "winapi", ] @@ -1232,6 +1233,9 @@ checksum = "9ea835d29036a4087793836fa931b08837ad5e957da9e23886b29586fb9b6650" [[package]] name = "duration_helper" version = "0.1.0" +dependencies = [ + "chrono", +] [[package]] name = "dwrote" @@ -1761,7 +1765,7 @@ dependencies = [ "cfg-if 1.0.0", "js-sys", "libc", - "wasi", + "wasi 0.11.0+wasi-snapshot-preview1", "wasm-bindgen", ] @@ -2531,7 +2535,7 @@ checksum = "e5d732bc30207a6423068df043e3d02e0735b155ad7ce1a6f76fe2baa5b158de" dependencies = [ "libc", "log", - "wasi", + "wasi 0.11.0+wasi-snapshot-preview1", "windows-sys 0.42.0", ] @@ -3566,6 +3570,7 @@ dependencies = [ "clap", "crossbeam-channel", "csv", + "duration_helper", "indicatif", "log", "path-slash", @@ -3948,7 +3953,7 @@ dependencies = [ "num-bigint", "num-traits", "thiserror", - "time", + "time 0.3.17", ] [[package]] @@ -4252,6 +4257,7 @@ name = "tests" version = "0.1.0" dependencies = [ "approx", + "duration_helper", "env_logger", "futures", "image", @@ -4302,6 +4308,17 @@ dependencies = [ "weezl", ] +[[package]] +name = "time" +version = "0.1.45" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1b797afad3f312d1c66a56d11d0316f916356d11bd158fbc6ca6389ff6bf805a" +dependencies = [ + "libc", + "wasi 0.10.0+wasi-snapshot-preview1", + "winapi", +] + [[package]] name = "time" version = "0.3.17" @@ -4554,6 +4571,12 @@ dependencies = [ "winapi-util", ] +[[package]] +name = "wasi" +version = "0.10.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a143597ca7c7793eff794def352d41792a93c481eb1042423ff7ff72ba2c31f" + [[package]] name = "wasi" version = "0.11.0+wasi-snapshot-preview1" diff --git a/core/src/avm1/globals/sound.rs b/core/src/avm1/globals/sound.rs index d95ad6169d389..e5e7869334829 100644 --- a/core/src/avm1/globals/sound.rs +++ b/core/src/avm1/globals/sound.rs @@ -11,6 +11,7 @@ use crate::character::Character; use crate::display_object::{SoundTransform, TDisplayObject}; use duration_helper::into_f64_millis; use gc_arena::MutationContext; +use std::time::Duration; const PROTO_DECLS: &[Declaration] = declare_properties! { "attachSound" => method(attach_sound; DONT_ENUM | DONT_DELETE | READ_ONLY); diff --git a/core/src/backend/audio.rs b/core/src/backend/audio.rs index 0c724c4a94934..da3a6f90dec1c 100644 --- a/core/src/backend/audio.rs +++ b/core/src/backend/audio.rs @@ -7,7 +7,8 @@ use downcast_rs::Downcast; use duration_helper::from_f64_millis; use gc_arena::Collect; use generational_arena::{Arena, Index}; -use duration_helper::{from_f64_millis, into_f64_millis}; +use num_traits::real::Real; +use duration_helper::{from_f64_millis, from_f64_seconds, into_f64_millis, into_f64_seconds, SignedDuration}; #[cfg(feature = "audio")] pub mod decoders; @@ -79,7 +80,7 @@ pub trait AudioBackend: Downcast { /// Get the position of a sound instance in milliseconds. /// Returns `None` if ther sound is not/no longer playing - fn get_sound_position(&self, instance: SoundInstanceHandle) -> Option; + fn get_sound_position(&self, instance: SoundInstanceHandle) -> Option; /// Get the duration of a sound in milliseconds. /// Returns `None` if sound is not registered. @@ -219,8 +220,8 @@ impl AudioBackend for NullAudioBackend { fn stop_sound(&mut self, _sound: SoundInstanceHandle) {} fn stop_all_sounds(&mut self) {} - fn get_sound_position(&self, _instance: SoundInstanceHandle) -> Option { - Some(RuffleDuration::zero()) + fn get_sound_position(&self, _instance: SoundInstanceHandle) -> Option { + Some(Duration::from_secs(0)) } fn get_sound_duration(&self, sound: SoundHandle) -> Option { if let Some(sound) = self.sounds.get(sound) { @@ -299,7 +300,7 @@ impl<'gc> AudioManager<'gc> { pub const STREAM_SYNC_THRESHOLD: f64 = 1.0 / 60.0; /// The threshold in seconds where an audio stream is considered too out-of-sync and will be stopped. - pub const STREAM_RESTART_THRESHOLD: RuffleDuration = RuffleDuration::one_sec(); + pub const STREAM_RESTART_THRESHOLD: Duration = Duration::from_secs(1); /// The minimum audio sycning threshold in seconds. /// @@ -328,9 +329,9 @@ impl<'gc> AudioManager<'gc> { if let Some(pos) = audio.get_sound_position(sound.instance) { // Sounds still playing; update position. if let Some(avm1_object) = sound.avm1_object { - avm1_object.set_position(gc_context, pos.as_millis().round() as u32); + avm1_object.set_position(gc_context, into_f64_millis(pos).round() as u32); } else if let Some(avm2_object) = sound.avm2_object { - avm2_object.set_position(gc_context, pos.as_millis()); + avm2_object.set_position(gc_context, into_f64_millis(pos)); } true } else { @@ -502,11 +503,7 @@ impl<'gc> AudioManager<'gc> { } /// Returns the difference in seconds between the primary audio stream's time and the player's time. - pub fn audio_skew_time( - &mut self, - audio: &mut dyn AudioBackend, - offset: RuffleDuration, - ) -> RuffleDuration { + pub fn audio_skew_time(&mut self, audio: &mut dyn AudioBackend, offset: Duration) -> SignedDuration { // Consider the first playing "stream" sound to be the primary audio track. // Needs research: It's not clear how Flash handles the case of multiple stream sounds. let (i, skew) = self @@ -523,10 +520,10 @@ impl<'gc> AudioManager<'gc> { // Calculate the difference in time between the owning movie clip and its audio track. // If the difference is beyond some threshold, inform the player to adjust playback speed. - let timeline_pos = RuffleDuration::from_secs( + let timeline_pos = SignedDuration::from_f64_secs( f64::from(clip.current_frame().saturating_sub(start_frame)) / frame_rate, ) + offset.into(); - Some((i, RuffleDuration::from(stream_pos) - timeline_pos)) + Some((i, SignedDuration::from(stream_pos) - timeline_pos)) }) .unwrap_or_default(); @@ -543,13 +540,13 @@ impl<'gc> AudioManager<'gc> { let instance = &self.sounds[i]; audio.stop_sound(instance.instance); self.sounds.swap_remove(i); - RuffleDuration::zero() + SignedDuration::from_secs(0) } else if skew.abs() < sync_threshold { // Slightly out of sync, adjust player speed to compensate. skew } else { // More or less in sync, no adjustment. - RuffleDuration::zero() + SignedDuration::from_secs(0) } } diff --git a/core/src/backend/audio/mixer.rs b/core/src/backend/audio/mixer.rs index bacacaaa8aab9..6e759b2e7b6c7 100644 --- a/core/src/backend/audio/mixer.rs +++ b/core/src/backend/audio/mixer.rs @@ -594,13 +594,13 @@ impl AudioMixer { /// Returns the position of a playing sound in milliseconds. /// ////// Returns `None` if the sound is no longer playing. - pub fn get_sound_position(&self, instance: SoundInstanceHandle) -> Option { + pub fn get_sound_position(&self, instance: SoundInstanceHandle) -> Option { let sound_instances = self.sound_instances.lock().unwrap(); sound_instances.get(instance).map(|instance| { // Get the current sample position from the underlying audio source. let num_sample_frames: f64 = instance.stream.source_position().into(); let sample_rate: f64 = instance.stream.source_sample_rate().into(); - RuffleDuration::from_millis(num_sample_frames * 1000.0 / sample_rate) + from_f64_millis(num_sample_frames * 1000.0 / sample_rate) }) } @@ -1044,7 +1044,7 @@ macro_rules! impl_audio_mixer_backend { } #[inline] - fn get_sound_position(&self, instance: SoundInstanceHandle) -> Option { + fn get_sound_position(&self, instance: SoundInstanceHandle) -> Option { self.$mixer.get_sound_position(instance) } diff --git a/core/src/player.rs b/core/src/player.rs index 3ce058cb80e91..2a6632174b026 100644 --- a/core/src/player.rs +++ b/core/src/player.rs @@ -55,6 +55,8 @@ use std::ops::DerefMut; use std::rc::{Rc, Weak as RcWeak}; use std::str::FromStr; use std::sync::{Arc, Mutex, Weak}; +use std::time::Duration; +use duration_helper::{duration_add_assign_signed_duration, from_f64_millis}; /// The newest known Flash Player version, serves as a default to /// `player_version`. @@ -241,7 +243,7 @@ pub struct Player { /// Gained by passage of time between host frames, spent by executing SWF frames. /// This is how we support custom SWF framerates /// and compensate for small lags by "catching up" (up to MAX_FRAMES_PER_TICK). - frame_accumulator: RuffleDuration, + frame_accumulator: Duration, recent_run_frame_timings: VecDeque, /// Faked time passage for fooling hand-written busy-loop FPS limiters. @@ -261,7 +263,7 @@ pub struct Player { instance_counter: i32, /// Time remaining until the next timer will fire. - time_til_next_timer: Option, + time_til_next_timer: Option, /// The instant at which the SWF was launched. start_time: Instant, @@ -451,7 +453,7 @@ impl Player { } } - pub fn tick(&mut self, dt: RuffleDuration) { + pub fn tick(&mut self, dt: Duration) { // Don't run until preloading is complete. // TODO: Eventually we want to stream content similar to the Flash player. if !self.audio.is_loading_complete() { @@ -461,7 +463,7 @@ impl Player { if self.is_playing() { self.frame_accumulator += dt; let frame_rate = self.frame_rate; - let frame_time = RuffleDuration::from_millis(1000.0 / frame_rate); + let frame_time = from_f64_millis(1000.0 / frame_rate); let max_frames_per_tick = self.max_frames_per_tick(); let mut frame = 0; @@ -480,7 +482,7 @@ impl Player { // Then we need to actually pass this time, by decreasing frame_accumulator // to delay the future frame. if self.time_offset > 0 { - self.frame_accumulator -= RuffleDuration::from_millis(self.time_offset.into()); + self.frame_accumulator -= Duration::from_millis(self.time_offset.into()); } } @@ -496,7 +498,7 @@ impl Player { // Sanity: If we had too many frames to tick, just reset the accumulator // to prevent running at turbo speed. if self.frame_accumulator >= frame_time { - self.frame_accumulator = RuffleDuration::zero(); + self.frame_accumulator = Duration::from_nanos(0); } // Adjust playback speed for next frame to stay in sync with timeline audio tracks ("stream" sounds). @@ -506,8 +508,9 @@ impl Player { context .audio_manager .audio_skew_time(context.audio, cur_frame_offset) + }); - self.frame_accumulator += add; + duration_add_assign_signed_duration(&mut self.frame_accumulator, add); self.update_timers(dt); self.audio.tick(); @@ -520,12 +523,12 @@ impl Player { /// Returns the approximate duration of time until the next frame is due to run. /// This is only an approximation to be used for sleep durations. - pub fn time_til_next_frame(&self) -> RuffleDuration { - let frame_time = RuffleDuration::from_millis(1000.0 / self.frame_rate); - let mut dt = if self.frame_accumulator <= RuffleDuration::zero() { + pub fn time_til_next_frame(&self) -> std::time::Duration { + let frame_time = from_f64_millis(1000.0 / self.frame_rate); + let mut dt = if self.frame_accumulator <= Duration::from_secs(0) { frame_time } else if self.frame_accumulator >= frame_time { - RuffleDuration::zero() + Duration::from_secs(0) } else { frame_time - self.frame_accumulator }; @@ -534,7 +537,7 @@ impl Player { dt = dt.min(time_til_next_timer) } - dt = dt.max(RuffleDuration::zero()); + dt = dt.max(Duration::from_millis(0)); dt } @@ -1809,7 +1812,7 @@ impl Player { /// Update all AVM-based timers (such as created via setInterval). /// Returns the approximate amount of time until the next timer tick. - pub fn update_timers(&mut self, dt: RuffleDuration) { + pub fn update_timers(&mut self, dt: Duration) { self.time_til_next_timer = self.mutate_with_update_context(|context| Timers::update_timers(context, dt)); } @@ -2092,7 +2095,7 @@ impl PlayerBuilder { // Timing frame_rate, frame_phase: Default::default(), - frame_accumulator: RuffleDuration::zero(), + frame_accumulator: Duration::from_secs(0), recent_run_frame_timings: VecDeque::with_capacity(10), start_time: Instant::now(), time_offset: 0, diff --git a/core/src/timer.rs b/core/src/timer.rs index d7e2214e8a2f6..e58e04c93ebc8 100644 --- a/core/src/timer.rs +++ b/core/src/timer.rs @@ -16,6 +16,7 @@ use crate::string::AvmString; use gc_arena::Collect; use std::collections::{binary_heap::PeekMut, BinaryHeap}; use std::ops::{Add, AddAssign, Sub}; +use std::time::Duration; /// Manages the collection of timers. pub struct Timers<'gc> { @@ -26,15 +27,12 @@ pub struct Timers<'gc> { timer_counter: i32, /// The current global time. - cur_time: RuffleDuration, + cur_time: Duration, } impl<'gc> Timers<'gc> { /// Ticks all timers and runs necessary callbacks. - pub fn update_timers( - context: &mut UpdateContext<'_, 'gc, '_>, - dt: RuffleDuration, - ) -> Option { + pub fn update_timers(context: &mut UpdateContext<'_, 'gc, '_>, dt: Duration) -> Option { context.timers.cur_time.add_assign(dt); let num_timers = context.timers.num_timers(); @@ -59,7 +57,7 @@ impl<'gc> Timers<'gc> { .context .timers .peek() - .map(|timer| RuffleDuration::from_micros(timer.tick_time as f64)) + .map(|timer| Duration::from_micros(timer.tick_time)) .unwrap_or(cur_time) < cur_time { @@ -76,11 +74,8 @@ impl<'gc> Timers<'gc> { // SANITY: Only allow so many ticks per timer per update. if tick_count > Self::MAX_TICKS { // Reset our time to a little bit before the nearest timer. - let next_time = RuffleDuration::from_micros( - activation.context.timers.peek_mut().unwrap().tick_time as f64, - ); - activation.context.timers.cur_time = - next_time.add(RuffleDuration::from_millis(100.0)); + let next_time = Duration::from_micros(activation.context.timers.peek_mut().unwrap().tick_time); + activation.context.timers.cur_time = next_time.add(Duration::from_millis(100)); break; } @@ -153,7 +148,7 @@ impl<'gc> Timers<'gc> { activation.context.timers.pop(); } else { // Reset setInterval timers. `peek_mut` re-sorts the timer in the priority queue. - timer.tick_time = timer.tick_time.wrapping_add(timer.interval); + timer.tick_time = timer.tick_time.add(timer.interval); } } @@ -162,7 +157,7 @@ impl<'gc> Timers<'gc> { .context .timers .peek() - .map(|timer| (RuffleDuration::from_micros(timer.tick_time as f64).sub(cur_time))) + .map(|timer| (Duration::from_micros(timer.tick_time).sub(cur_time))) } /// The minimum interval we allow for timers. @@ -176,7 +171,7 @@ impl<'gc> Timers<'gc> { Self { timers: Default::default(), timer_counter: 0, - cur_time: RuffleDuration::zero(), + cur_time: Duration::from_secs(0), } } @@ -193,7 +188,7 @@ impl<'gc> Timers<'gc> { is_timeout: bool, ) -> i32 { // SANITY: Set a minimum interval so we don't spam too much. - let interval = RuffleDuration::from_millis(interval.max(Self::MIN_INTERVAL) as f64); + let interval = Duration::from_millis(interval.max(Self::MIN_INTERVAL) as u64); self.timer_counter = self.timer_counter.wrapping_add(1); let id = self.timer_counter; diff --git a/desktop/src/main.rs b/desktop/src/main.rs index 84d891aa98f18..3429729b27550 100644 --- a/desktop/src/main.rs +++ b/desktop/src/main.rs @@ -369,12 +369,12 @@ impl App { // Core loop winit::event::Event::MainEventsCleared if loaded => { let new_time = Instant::now(); - let dt = RuffleDuration::from(new_time.duration_since(time)); + let dt = new_time.duration_since(time); if !dt.is_zero() { time = new_time; let mut player_lock = self.player.lock().unwrap(); player_lock.tick(dt); - next_frame_time = new_time + player_lock.time_til_next_frame().into(); + next_frame_time = new_time + player_lock.time_til_next_frame(); if player_lock.needs_render() { self.window.request_redraw(); } diff --git a/duration_helper/Cargo.toml b/duration_helper/Cargo.toml index e09b7c4f27514..842a33d965b3c 100644 --- a/duration_helper/Cargo.toml +++ b/duration_helper/Cargo.toml @@ -6,3 +6,4 @@ edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] +chrono = "0.4" diff --git a/duration_helper/src/lib.rs b/duration_helper/src/lib.rs index e9da1b8e5cb5c..9fd3767e7d94f 100644 --- a/duration_helper/src/lib.rs +++ b/duration_helper/src/lib.rs @@ -1,5 +1,136 @@ +use std::ops::{Add, Neg, Sub}; use std::time::Duration; +pub enum Sign { + Positive, + Negative, +} + +pub struct SignedDuration { + sign: Sign, + duration: Duration, +} + +impl SignedDuration { + pub fn new(sign: Sign, duration: Duration) -> Self { + SignedDuration { sign, duration } + } + + pub fn from_secs(secs: i64) -> Self { + SignedDuration::new( + if secs < 0 { Sign::Negative } else { Sign::Positive }, + Duration::from_secs(secs.abs() as u64), + ) + } + + pub fn from_f64_secs(secs: f64) -> Self { + SignedDuration::new( + if secs < 0.0 { Sign::Negative } else { Sign::Positive }, + Duration::from_nanos((secs.abs() * 1_000_000_000.0) as u64), + ) + } + + pub fn from_nanos(nanosecs: i64) -> Self { + SignedDuration::new( + if nanosecs < 0 { Sign::Negative } else { Sign::Positive }, + Duration::from_nanos(nanosecs.abs() as u64), + ) + } + + pub fn zero() -> Self { + SignedDuration::new(Sign::Positive, Duration::from_secs(0)) + } + + pub fn abs(&self) -> Duration { + self.duration.clone() + } +} + +impl Default for SignedDuration { + fn default() -> Self { + SignedDuration::zero() + } +} + +impl From for SignedDuration { + fn from(duration: Duration) -> Self { + Self { sign: Sign::Positive, duration } + } +} + +impl Neg for SignedDuration { + type Output = Self; + + fn neg(self) -> Self { + Self { + sign: match self.sign { + Sign::Positive => Sign::Negative, + Sign::Negative => Sign::Positive, + }, + duration: self.duration, + } + } +} + + +impl Add for SignedDuration { + type Output = Self; + + fn add(self, other: Self) -> Self { + match (self.sign, other.sign) { + (Sign::Positive, Sign::Positive) => Self { + sign: Sign::Positive, + duration: self.duration + other.duration, + }, + (Sign::Positive, Sign::Negative) => { + if self.duration >= other.duration { + Self { + sign: Sign::Positive, + duration: self.duration - other.duration, + } + } else { + Self { + sign: Sign::Negative, + duration: other.duration - self.duration, + } + } + }, + (Sign::Negative, Sign::Positive) => { + if other.duration >= self.duration { + Self { + sign: Sign::Positive, + duration: other.duration - self.duration, + } + } else { + Self { + sign: Sign::Negative, + duration: self.duration - other.duration, + } + } + }, + (Sign::Negative, Sign::Negative) => Self { + sign: Sign::Negative, + duration: self.duration + other.duration, + }, + } + } +} + +impl Sub for SignedDuration { + type Output = Self; + + fn sub(self, other: Self) -> Self { + self.add(other.neg()) + } +} + +pub fn duration_add_assign_signed_duration(duration: &mut Duration, other: SignedDuration) { + match other.sign { + Sign::Positive => *duration += other.duration, + Sign::Negative => *duration -= other.duration, + } +} + pub fn from_f64_millis(millis: f64) -> Duration { Duration::from_nanos((millis * 1_000_000.0) as u64) } @@ -8,6 +139,14 @@ pub fn into_f64_millis(duration: Duration) -> f64 { duration.as_nanos() as f64 / 1_000_000.0 } +pub fn from_f64_seconds(secs: f64) -> Duration { + Duration::from_nanos((secs * 1_000_000_000.0) as u64) +} + +pub fn into_f64_seconds(duration: Duration) -> f64 { + duration.as_nanos() as f64 / 1_000_000_000.0 +} + #[cfg(test)] mod tests { use std::time::Duration; @@ -31,4 +170,36 @@ mod tests { fn test_into_f64_sub_millis_case() { assert_eq!(super::into_f64_millis(Duration::from_micros(1500)), 1.5); } + + #[test] + fn test_from_f64_seconds_standard_case() { + assert_eq!( + super::from_f64_seconds(1.0), + Duration::from_secs(1) + ); + } + + #[test] + fn test_from_f64_sub_seconds_case() { + assert_eq!( + super::from_f64_seconds(1.5), + Duration::from_millis(1500) + ); + } + + #[test] + fn test_into_f64_seconds_standard_case() { + assert_eq!( + super::into_f64_seconds(Duration::from_secs(1)), + 1.0 + ); + } + + #[test] + fn test_into_f64_sub_seconds_case() { + assert_eq!( + super::into_f64_seconds(Duration::from_millis(1500)), + 1.5 + ); + } } diff --git a/scanner/Cargo.toml b/scanner/Cargo.toml index a7e200190db6c..0f60641419727 100644 --- a/scanner/Cargo.toml +++ b/scanner/Cargo.toml @@ -18,3 +18,4 @@ swf = { path = "../swf" } rayon = "1.6.0" crossbeam-channel = "0.5" sha2 = "0.10.6" +duration_helper = { path = "../duration_helper" } diff --git a/scanner/src/execute.rs b/scanner/src/execute.rs index b6211923298a3..a318de92e4d42 100644 --- a/scanner/src/execute.rs +++ b/scanner/src/execute.rs @@ -14,12 +14,13 @@ use std::io::{stdout, Write}; use std::panic::catch_unwind; use std::path::Path; use std::time::{Duration, Instant}; +use duration_helper::from_f64_millis; fn execute_swf(file: &Path) { let base_path = file.parent().unwrap(); let executor = NullExecutor::new(); let movie = SwfMovie::from_path(file, None).unwrap(); - let frame_time = RuffleDuration::from_millis(1000.0 / movie.frame_rate().to_f64()); + let frame_time = from_f64_millis(1000.0 / movie.frame_rate().to_f64()); let player = PlayerBuilder::new() .with_log(ScanLogBackend::new()) .with_navigator(NullNavigatorBackend::with_base_path(base_path, &executor)) diff --git a/tests/Cargo.toml b/tests/Cargo.toml index 967fd01046ab0..4966d24d89629 100644 --- a/tests/Cargo.toml +++ b/tests/Cargo.toml @@ -11,6 +11,7 @@ ruffle_render_wgpu = { path = "../render/wgpu", optional = true } ruffle_input_format = { path = "input-format" } image = "0.24.5" regex = "1.7.0" +duration_helper = { path = "../duration_helper"} [features] # Enable running image comparison tests. This is off by default, diff --git a/tests/tests/regression_tests.rs b/tests/tests/regression_tests.rs index 6ce7d6d34b6d6..3c4a590ab3f0a 100644 --- a/tests/tests/regression_tests.rs +++ b/tests/tests/regression_tests.rs @@ -29,6 +29,7 @@ use std::path::Path; use std::rc::Rc; use std::sync::{Arc, Mutex}; use std::time::Duration; +use duration_helper::from_f64_millis; const RUN_IMG_TESTS: bool = cfg!(feature = "imgtests"); @@ -1386,7 +1387,7 @@ fn run_swf( let base_path = Path::new(swf_path).parent().unwrap(); let mut executor = NullExecutor::new(); let movie = SwfMovie::from_path(swf_path, None)?; - let frame_time = RuffleDuration::from_millis(1000.0 / movie.frame_rate().to_f64()); + let frame_time = from_f64_millis(1000.0 / movie.frame_rate().to_f64()); let trace_output = Rc::new(RefCell::new(Vec::new())); #[allow(unused_mut)] diff --git a/web/src/lib.rs b/web/src/lib.rs index a29bb4fefed2e..8b58b7dc9c72a 100644 --- a/web/src/lib.rs +++ b/web/src/lib.rs @@ -29,6 +29,7 @@ use web_sys::{ AddEventListenerOptions, Element, Event, EventTarget, HtmlCanvasElement, HtmlElement, KeyboardEvent, PointerEvent, WheelEvent, Window, }; +use duration_helper::from_f64_millis; static RUFFLE_GLOBAL_PANIC: Once = Once::new(); @@ -986,7 +987,7 @@ impl Ruffle { }); } - core.tick(RuffleDuration::from_millis(dt)); + core.tick(from_f64_millis(dt)); // Render if the core signals a new frame, or if we resized. if core.needs_render() || new_dimensions.is_some() { From 36a708451cfeeac30cb09abdb781dee9cea4efa0 Mon Sep 17 00:00:00 2001 From: higumachan Date: Fri, 29 Jul 2022 00:05:32 +0900 Subject: [PATCH 06/15] implement RuffleDuration base f64 --- Cargo.lock | 15 +- Cargo.toml | 2 - core/Cargo.toml | 1 - core/src/avm1/activation.rs | 1 + core/src/avm1/globals/sound.rs | 3 +- core/src/avm2/activation.rs | 1 + core/src/avm2/globals/flash/media/sound.rs | 3 +- core/src/backend/audio.rs | 34 ++-- core/src/backend/audio/mixer.rs | 14 +- core/src/lib.rs | 1 + core/src/player.rs | 31 ++-- core/src/timer.rs | 18 +- desktop/src/audio.rs | 1 - desktop/src/main.rs | 5 +- duration_helper/Cargo.toml | 9 - duration_helper/src/lib.rs | 205 --------------------- scanner/Cargo.toml | 1 - scanner/src/execute.rs | 4 +- tests/Cargo.toml | 1 - tests/tests/regression_tests.rs | 4 +- web/Cargo.toml | 1 - web/src/lib.rs | 4 +- 22 files changed, 64 insertions(+), 295 deletions(-) delete mode 100644 duration_helper/Cargo.toml delete mode 100644 duration_helper/src/lib.rs diff --git a/Cargo.lock b/Cargo.lock index e0ecaf7ebbcbd..8b7d72724a5b9 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1231,15 +1231,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9ea835d29036a4087793836fa931b08837ad5e957da9e23886b29586fb9b6650" [[package]] -name = "duration_helper" -version = "0.1.0" -dependencies = [ - "chrono", -] - -[[package]] -name = "dwrote" -version = "0.11.0" +name = "either" +version = "1.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "439a1c2ba5611ad3ed731280541d36d2e9c4ac5e7fb818a27b604bdc5a6aa65b" dependencies = [ @@ -3405,7 +3398,6 @@ dependencies = [ "chrono", "dasp", "downcast-rs", - "duration_helper", "encoding_rs", "enumset", "flash-lso", @@ -3570,7 +3562,6 @@ dependencies = [ "clap", "crossbeam-channel", "csv", - "duration_helper", "indicatif", "log", "path-slash", @@ -3618,7 +3609,6 @@ dependencies = [ "chrono", "console_error_panic_hook", "console_log", - "duration_helper", "generational-arena", "getrandom", "js-sys", @@ -4257,7 +4247,6 @@ name = "tests" version = "0.1.0" dependencies = [ "approx", - "duration_helper", "env_logger", "futures", "image", diff --git a/Cargo.toml b/Cargo.toml index 611843bbad6af..c6dd0dc65b53b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -19,9 +19,7 @@ members = [ "video", "video/software", - "duration_helper", - "tests", "tests/input-format", ] resolver = "2" diff --git a/core/Cargo.toml b/core/Cargo.toml index 1b245daf1b16f..378455578c994 100644 --- a/core/Cargo.toml +++ b/core/Cargo.toml @@ -47,7 +47,6 @@ static_assertions = "1.1.0" rustversion = "1.0.9" bytemuck = "1.12.1" ordered-float = { version = "3.0.0", features = ["serde"] } -duration_helper = { path = "../duration_helper" } [target.'cfg(not(target_family = "wasm"))'.dependencies.futures] version = "0.3.25" diff --git a/core/src/avm1/activation.rs b/core/src/avm1/activation.rs index 38bb12ebf871f..1f9a325354334 100644 --- a/core/src/avm1/activation.rs +++ b/core/src/avm1/activation.rs @@ -28,6 +28,7 @@ use swf::avm1::read::Reader; use swf::avm1::types::*; use swf::Twips; use url::form_urlencoded; +use crate::duration::RuffleDuration; macro_rules! avm_debug { ($avm: expr, $($arg:tt)*) => ( diff --git a/core/src/avm1/globals/sound.rs b/core/src/avm1/globals/sound.rs index e5e7869334829..2ef02cce0be8f 100644 --- a/core/src/avm1/globals/sound.rs +++ b/core/src/avm1/globals/sound.rs @@ -9,7 +9,6 @@ use crate::avm_warn; use crate::backend::navigator::Request; use crate::character::Character; use crate::display_object::{SoundTransform, TDisplayObject}; -use duration_helper::into_f64_millis; use gc_arena::MutationContext; use std::time::Duration; @@ -95,7 +94,7 @@ fn attach_sound<'gc>( .context .audio .get_sound_duration(*sound) - .map(|d| into_f64_millis(d).round() as u32), + .map(|d| d.as_millis().round() as u32), ); sound_object.set_position(activation.context.gc_context, 0); } else { diff --git a/core/src/avm2/activation.rs b/core/src/avm2/activation.rs index ce669e4bfe011..cf92c460e5d3d 100644 --- a/core/src/avm2/activation.rs +++ b/core/src/avm2/activation.rs @@ -29,6 +29,7 @@ use swf::avm2::types::{ Class as AbcClass, Exception, Index, Method as AbcMethod, MethodFlags as AbcMethodFlags, Multiname as AbcMultiname, Namespace as AbcNamespace, Op, }; +use crate::duration::RuffleDuration; /// Represents a particular register set. /// diff --git a/core/src/avm2/globals/flash/media/sound.rs b/core/src/avm2/globals/flash/media/sound.rs index d33cd758d7f92..b248656c58b09 100644 --- a/core/src/avm2/globals/flash/media/sound.rs +++ b/core/src/avm2/globals/flash/media/sound.rs @@ -12,7 +12,6 @@ use crate::avm2::QName; use crate::backend::navigator::Request; use crate::character::Character; use crate::display_object::SoundTransform; -use duration_helper::into_f64_millis; use gc_arena::{GcCell, MutationContext}; use swf::{SoundEvent, SoundInfo}; @@ -105,7 +104,7 @@ pub fn length<'gc>( ) -> Result, Error<'gc>> { if let Some(sound) = this.and_then(|this| this.as_sound()) { if let Some(duration) = activation.context.audio.get_sound_duration(sound) { - return Ok((into_f64_millis(duration)).into()); + return Ok(duration.as_millis().into()); } } diff --git a/core/src/backend/audio.rs b/core/src/backend/audio.rs index da3a6f90dec1c..1df994a63193e 100644 --- a/core/src/backend/audio.rs +++ b/core/src/backend/audio.rs @@ -1,3 +1,4 @@ +use crate::duration::RuffleDuration; use crate::{ avm1::SoundObject, avm2::SoundChannelObject, @@ -8,7 +9,6 @@ use duration_helper::from_f64_millis; use gc_arena::Collect; use generational_arena::{Arena, Index}; use num_traits::real::Real; -use duration_helper::{from_f64_millis, from_f64_seconds, into_f64_millis, into_f64_seconds, SignedDuration}; #[cfg(feature = "audio")] pub mod decoders; @@ -80,11 +80,11 @@ pub trait AudioBackend: Downcast { /// Get the position of a sound instance in milliseconds. /// Returns `None` if ther sound is not/no longer playing - fn get_sound_position(&self, instance: SoundInstanceHandle) -> Option; + fn get_sound_position(&self, instance: SoundInstanceHandle) -> Option; /// Get the duration of a sound in milliseconds. /// Returns `None` if sound is not registered. - fn get_sound_duration(&self, sound: SoundHandle) -> Option; + fn get_sound_duration(&self, sound: SoundHandle) -> Option; /// Get the size of the data stored within a given sound. /// @@ -139,7 +139,7 @@ impl_downcast!(AudioBackend); /// Information about a sound provided to `NullAudioBackend`. struct NullSound { /// The duration of the sound in milliseconds. - duration: Duration, + duration: RuffleDuration, /// The compressed size of the sound data, excluding MP3 latency seek data. size: u32, @@ -177,7 +177,7 @@ impl AudioBackend for NullAudioBackend { // AS duration does not subtract `skip_sample_frames`. let num_sample_frames: f64 = sound.num_samples.into(); let sample_rate: f64 = sound.format.sample_rate.into(); - let duration = from_f64_millis(num_sample_frames * 1000.0 / sample_rate); + let duration = RuffleDuration::from_millis(num_sample_frames * 1000.0 / sample_rate); Ok(self.sounds.insert(NullSound { duration, @@ -220,10 +220,10 @@ impl AudioBackend for NullAudioBackend { fn stop_sound(&mut self, _sound: SoundInstanceHandle) {} fn stop_all_sounds(&mut self) {} - fn get_sound_position(&self, _instance: SoundInstanceHandle) -> Option { - Some(Duration::from_secs(0)) + fn get_sound_position(&self, _instance: SoundInstanceHandle) -> Option { + Some(RuffleDuration::zero()) } - fn get_sound_duration(&self, sound: SoundHandle) -> Option { + fn get_sound_duration(&self, sound: SoundHandle) -> Option { if let Some(sound) = self.sounds.get(sound) { Some(sound.duration) } else { @@ -300,7 +300,7 @@ impl<'gc> AudioManager<'gc> { pub const STREAM_SYNC_THRESHOLD: f64 = 1.0 / 60.0; /// The threshold in seconds where an audio stream is considered too out-of-sync and will be stopped. - pub const STREAM_RESTART_THRESHOLD: Duration = Duration::from_secs(1); + pub const STREAM_RESTART_THRESHOLD: RuffleDuration = RuffleDuration::one_sec(); /// The minimum audio sycning threshold in seconds. /// @@ -329,9 +329,9 @@ impl<'gc> AudioManager<'gc> { if let Some(pos) = audio.get_sound_position(sound.instance) { // Sounds still playing; update position. if let Some(avm1_object) = sound.avm1_object { - avm1_object.set_position(gc_context, into_f64_millis(pos).round() as u32); + avm1_object.set_position(gc_context, pos.as_millis().round() as u32); } else if let Some(avm2_object) = sound.avm2_object { - avm2_object.set_position(gc_context, into_f64_millis(pos)); + avm2_object.set_position(gc_context, pos.as_millis()); } true } else { @@ -341,7 +341,7 @@ impl<'gc> AudioManager<'gc> { .and_then(|sound| audio.get_sound_duration(sound)) .unwrap_or_default(); if let Some(object) = sound.avm1_object { - object.set_position(gc_context, into_f64_millis(duration).round() as u32); + object.set_position(gc_context, duration.as_millis().round() as u32); // Fire soundComplete event. action_queue.queue_action( @@ -503,7 +503,7 @@ impl<'gc> AudioManager<'gc> { } /// Returns the difference in seconds between the primary audio stream's time and the player's time. - pub fn audio_skew_time(&mut self, audio: &mut dyn AudioBackend, offset: Duration) -> SignedDuration { + pub fn audio_skew_time(&mut self, audio: &mut dyn AudioBackend, offset: RuffleDuration) -> RuffleDuration { // Consider the first playing "stream" sound to be the primary audio track. // Needs research: It's not clear how Flash handles the case of multiple stream sounds. let (i, skew) = self @@ -520,10 +520,10 @@ impl<'gc> AudioManager<'gc> { // Calculate the difference in time between the owning movie clip and its audio track. // If the difference is beyond some threshold, inform the player to adjust playback speed. - let timeline_pos = SignedDuration::from_f64_secs( + let timeline_pos = RuffleDuration::from_secs( f64::from(clip.current_frame().saturating_sub(start_frame)) / frame_rate, ) + offset.into(); - Some((i, SignedDuration::from(stream_pos) - timeline_pos)) + Some((i, RuffleDuration::from(stream_pos) - timeline_pos)) }) .unwrap_or_default(); @@ -540,13 +540,13 @@ impl<'gc> AudioManager<'gc> { let instance = &self.sounds[i]; audio.stop_sound(instance.instance); self.sounds.swap_remove(i); - SignedDuration::from_secs(0) + RuffleDuration::zero() } else if skew.abs() < sync_threshold { // Slightly out of sync, adjust player speed to compensate. skew } else { // More or less in sync, no adjustment. - SignedDuration::from_secs(0) + RuffleDuration::zero() } } diff --git a/core/src/backend/audio/mixer.rs b/core/src/backend/audio/mixer.rs index 6e759b2e7b6c7..b73d6200a7849 100644 --- a/core/src/backend/audio/mixer.rs +++ b/core/src/backend/audio/mixer.rs @@ -7,7 +7,7 @@ use duration_helper::from_f64_millis; use generational_arena::Arena; use std::io::Cursor; use std::sync::{Arc, Mutex, RwLock}; -use std::time::Duration; +use crate::duration::RuffleDuration; use swf::AudioCompression; /// Holds the last 2048 output audio frames. Frames can be written to it one by @@ -594,13 +594,13 @@ impl AudioMixer { /// Returns the position of a playing sound in milliseconds. /// ////// Returns `None` if the sound is no longer playing. - pub fn get_sound_position(&self, instance: SoundInstanceHandle) -> Option { + pub fn get_sound_position(&self, instance: SoundInstanceHandle) -> Option { let sound_instances = self.sound_instances.lock().unwrap(); sound_instances.get(instance).map(|instance| { // Get the current sample position from the underlying audio source. let num_sample_frames: f64 = instance.stream.source_position().into(); let sample_rate: f64 = instance.stream.source_sample_rate().into(); - from_f64_millis(num_sample_frames * 1000.0 / sample_rate) + RuffleDuration::from_millis(num_sample_frames * 1000.0 / sample_rate) }) } @@ -612,12 +612,12 @@ impl AudioMixer { /// Returns the duration of a registered sound in milliseconds. /// /// Returns `None` if the sound is not registered or invalid. - pub fn get_sound_duration(&self, sound: SoundHandle) -> Option { + pub fn get_sound_duration(&self, sound: SoundHandle) -> Option { self.sounds.get(sound).map(|sound| { // AS duration does not subtract `skip_sample_frames`. let num_sample_frames: f64 = sound.num_sample_frames.into(); let sample_rate: f64 = sound.format.sample_rate.into(); - from_f64_millis(num_sample_frames * 1000.0 / sample_rate) + RuffleDuration::from_millis(num_sample_frames * 1000.0 / sample_rate) }) } @@ -1044,12 +1044,12 @@ macro_rules! impl_audio_mixer_backend { } #[inline] - fn get_sound_position(&self, instance: SoundInstanceHandle) -> Option { + fn get_sound_position(&self, instance: SoundInstanceHandle) -> Option { self.$mixer.get_sound_position(instance) } #[inline] - fn get_sound_duration(&self, sound: SoundHandle) -> Option { + fn get_sound_duration(&self, sound: SoundHandle) -> Option { self.$mixer.get_sound_duration(sound) } diff --git a/core/src/lib.rs b/core/src/lib.rs index db14f8d4a35fa..1068622cca4f3 100644 --- a/core/src/lib.rs +++ b/core/src/lib.rs @@ -46,6 +46,7 @@ pub mod backend; pub mod config; pub mod duration; pub mod external; +pub mod duration; pub use context_menu::ContextMenuItem; pub use events::PlayerEvent; diff --git a/core/src/player.rs b/core/src/player.rs index 2a6632174b026..34609c79b03b9 100644 --- a/core/src/player.rs +++ b/core/src/player.rs @@ -55,8 +55,7 @@ use std::ops::DerefMut; use std::rc::{Rc, Weak as RcWeak}; use std::str::FromStr; use std::sync::{Arc, Mutex, Weak}; -use std::time::Duration; -use duration_helper::{duration_add_assign_signed_duration, from_f64_millis}; +use crate::duration::RuffleDuration; /// The newest known Flash Player version, serves as a default to /// `player_version`. @@ -243,7 +242,7 @@ pub struct Player { /// Gained by passage of time between host frames, spent by executing SWF frames. /// This is how we support custom SWF framerates /// and compensate for small lags by "catching up" (up to MAX_FRAMES_PER_TICK). - frame_accumulator: Duration, + frame_accumulator: RuffleDuration, recent_run_frame_timings: VecDeque, /// Faked time passage for fooling hand-written busy-loop FPS limiters. @@ -263,7 +262,7 @@ pub struct Player { instance_counter: i32, /// Time remaining until the next timer will fire. - time_til_next_timer: Option, + time_til_next_timer: Option, /// The instant at which the SWF was launched. start_time: Instant, @@ -453,7 +452,7 @@ impl Player { } } - pub fn tick(&mut self, dt: Duration) { + pub fn tick(&mut self, dt: RuffleDuration) { // Don't run until preloading is complete. // TODO: Eventually we want to stream content similar to the Flash player. if !self.audio.is_loading_complete() { @@ -463,7 +462,7 @@ impl Player { if self.is_playing() { self.frame_accumulator += dt; let frame_rate = self.frame_rate; - let frame_time = from_f64_millis(1000.0 / frame_rate); + let frame_time = RuffleDuration::from_millis(1000.0 / frame_rate); let max_frames_per_tick = self.max_frames_per_tick(); let mut frame = 0; @@ -482,7 +481,7 @@ impl Player { // Then we need to actually pass this time, by decreasing frame_accumulator // to delay the future frame. if self.time_offset > 0 { - self.frame_accumulator -= Duration::from_millis(self.time_offset.into()); + self.frame_accumulator -= RuffleDuration::from_millis(self.time_offset.into()); } } @@ -498,7 +497,7 @@ impl Player { // Sanity: If we had too many frames to tick, just reset the accumulator // to prevent running at turbo speed. if self.frame_accumulator >= frame_time { - self.frame_accumulator = Duration::from_nanos(0); + self.frame_accumulator = RuffleDuration::zero(); } // Adjust playback speed for next frame to stay in sync with timeline audio tracks ("stream" sounds). @@ -510,7 +509,7 @@ impl Player { .audio_skew_time(context.audio, cur_frame_offset) }); - duration_add_assign_signed_duration(&mut self.frame_accumulator, add); + self.frame_accumulator += add; self.update_timers(dt); self.audio.tick(); @@ -523,12 +522,12 @@ impl Player { /// Returns the approximate duration of time until the next frame is due to run. /// This is only an approximation to be used for sleep durations. - pub fn time_til_next_frame(&self) -> std::time::Duration { - let frame_time = from_f64_millis(1000.0 / self.frame_rate); - let mut dt = if self.frame_accumulator <= Duration::from_secs(0) { + pub fn time_til_next_frame(&self) -> RuffleDuration { + let frame_time = RuffleDuration::from_millis(1000.0 / self.frame_rate); + let mut dt = if self.frame_accumulator <= RuffleDuration::zero() { frame_time } else if self.frame_accumulator >= frame_time { - Duration::from_secs(0) + RuffleDuration::zero() } else { frame_time - self.frame_accumulator }; @@ -537,7 +536,7 @@ impl Player { dt = dt.min(time_til_next_timer) } - dt = dt.max(Duration::from_millis(0)); + dt = dt.max(RuffleDuration::zero()); dt } @@ -1812,7 +1811,7 @@ impl Player { /// Update all AVM-based timers (such as created via setInterval). /// Returns the approximate amount of time until the next timer tick. - pub fn update_timers(&mut self, dt: Duration) { + pub fn update_timers(&mut self, dt: RuffleDuration) { self.time_til_next_timer = self.mutate_with_update_context(|context| Timers::update_timers(context, dt)); } @@ -2095,7 +2094,7 @@ impl PlayerBuilder { // Timing frame_rate, frame_phase: Default::default(), - frame_accumulator: Duration::from_secs(0), + frame_accumulator: RuffleDuration::zero(), recent_run_frame_timings: VecDeque::with_capacity(10), start_time: Instant::now(), time_offset: 0, diff --git a/core/src/timer.rs b/core/src/timer.rs index e58e04c93ebc8..8da3ae685ffa0 100644 --- a/core/src/timer.rs +++ b/core/src/timer.rs @@ -16,7 +16,7 @@ use crate::string::AvmString; use gc_arena::Collect; use std::collections::{binary_heap::PeekMut, BinaryHeap}; use std::ops::{Add, AddAssign, Sub}; -use std::time::Duration; +use crate::duration::RuffleDuration; /// Manages the collection of timers. pub struct Timers<'gc> { @@ -27,12 +27,12 @@ pub struct Timers<'gc> { timer_counter: i32, /// The current global time. - cur_time: Duration, + cur_time: RuffleDuration, } impl<'gc> Timers<'gc> { /// Ticks all timers and runs necessary callbacks. - pub fn update_timers(context: &mut UpdateContext<'_, 'gc, '_>, dt: Duration) -> Option { + pub fn update_timers(context: &mut UpdateContext<'_, 'gc, '_>, dt: RuffleDuration) -> Option { context.timers.cur_time.add_assign(dt); let num_timers = context.timers.num_timers(); @@ -57,7 +57,7 @@ impl<'gc> Timers<'gc> { .context .timers .peek() - .map(|timer| Duration::from_micros(timer.tick_time)) + .map(|timer| RuffleDuration::from_micros(timer.tick_time as f64)) .unwrap_or(cur_time) < cur_time { @@ -74,8 +74,8 @@ impl<'gc> Timers<'gc> { // SANITY: Only allow so many ticks per timer per update. if tick_count > Self::MAX_TICKS { // Reset our time to a little bit before the nearest timer. - let next_time = Duration::from_micros(activation.context.timers.peek_mut().unwrap().tick_time); - activation.context.timers.cur_time = next_time.add(Duration::from_millis(100)); + let next_time = RuffleDuration::from_micros(activation.context.timers.peek_mut().unwrap().tick_time as f64); + activation.context.timers.cur_time = next_time.add(RuffleDuration::from_millis(100.0)); break; } @@ -157,7 +157,7 @@ impl<'gc> Timers<'gc> { .context .timers .peek() - .map(|timer| (Duration::from_micros(timer.tick_time).sub(cur_time))) + .map(|timer| (RuffleDuration::from_micros(timer.tick_time as f64).sub(cur_time))) } /// The minimum interval we allow for timers. @@ -171,7 +171,7 @@ impl<'gc> Timers<'gc> { Self { timers: Default::default(), timer_counter: 0, - cur_time: Duration::from_secs(0), + cur_time: RuffleDuration::zero(), } } @@ -188,7 +188,7 @@ impl<'gc> Timers<'gc> { is_timeout: bool, ) -> i32 { // SANITY: Set a minimum interval so we don't spam too much. - let interval = Duration::from_millis(interval.max(Self::MIN_INTERVAL) as u64); + let interval = RuffleDuration::from_millis(interval.max(Self::MIN_INTERVAL) as f64); self.timer_counter = self.timer_counter.wrapping_add(1); let id = self.timer_counter; diff --git a/desktop/src/audio.rs b/desktop/src/audio.rs index 8fd3066af2ed3..8d48381c6c72f 100644 --- a/desktop/src/audio.rs +++ b/desktop/src/audio.rs @@ -6,7 +6,6 @@ use ruffle_core::backend::audio::{ }; use ruffle_core::duration::RuffleDuration; use ruffle_core::impl_audio_mixer_backend; -use std::time::Duration; pub struct CpalAudioBackend { #[allow(dead_code)] diff --git a/desktop/src/main.rs b/desktop/src/main.rs index 3429729b27550..6077ce48680c5 100644 --- a/desktop/src/main.rs +++ b/desktop/src/main.rs @@ -40,6 +40,7 @@ use winit::event::{ }; use winit::event_loop::{ControlFlow, EventLoop, EventLoopBuilder}; use winit::window::{Fullscreen, Icon, Window, WindowBuilder}; +use ruffle_core::duration::RuffleDuration; thread_local! { static CALLSTACK: RefCell> = RefCell::default(); @@ -369,12 +370,12 @@ impl App { // Core loop winit::event::Event::MainEventsCleared if loaded => { let new_time = Instant::now(); - let dt = new_time.duration_since(time); + let dt = RuffleDuration::from(new_time.duration_since(time)); if !dt.is_zero() { time = new_time; let mut player_lock = self.player.lock().unwrap(); player_lock.tick(dt); - next_frame_time = new_time + player_lock.time_til_next_frame(); + next_frame_time = new_time + player_lock.time_til_next_frame().into(); if player_lock.needs_render() { self.window.request_redraw(); } diff --git a/duration_helper/Cargo.toml b/duration_helper/Cargo.toml deleted file mode 100644 index 842a33d965b3c..0000000000000 --- a/duration_helper/Cargo.toml +++ /dev/null @@ -1,9 +0,0 @@ -[package] -name = "duration_helper" -version = "0.1.0" -edition = "2021" - -# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html - -[dependencies] -chrono = "0.4" diff --git a/duration_helper/src/lib.rs b/duration_helper/src/lib.rs deleted file mode 100644 index 9fd3767e7d94f..0000000000000 --- a/duration_helper/src/lib.rs +++ /dev/null @@ -1,205 +0,0 @@ -use std::ops::{Add, Neg, Sub}; -use std::time::Duration; - -pub enum Sign { - Positive, - Negative, -} - -pub struct SignedDuration { - sign: Sign, - duration: Duration, -} - -impl SignedDuration { - pub fn new(sign: Sign, duration: Duration) -> Self { - SignedDuration { sign, duration } - } - - pub fn from_secs(secs: i64) -> Self { - SignedDuration::new( - if secs < 0 { Sign::Negative } else { Sign::Positive }, - Duration::from_secs(secs.abs() as u64), - ) - } - - pub fn from_f64_secs(secs: f64) -> Self { - SignedDuration::new( - if secs < 0.0 { Sign::Negative } else { Sign::Positive }, - Duration::from_nanos((secs.abs() * 1_000_000_000.0) as u64), - ) - } - - pub fn from_nanos(nanosecs: i64) -> Self { - SignedDuration::new( - if nanosecs < 0 { Sign::Negative } else { Sign::Positive }, - Duration::from_nanos(nanosecs.abs() as u64), - ) - } - - pub fn zero() -> Self { - SignedDuration::new(Sign::Positive, Duration::from_secs(0)) - } - - pub fn abs(&self) -> Duration { - self.duration.clone() - } -} - -impl Default for SignedDuration { - fn default() -> Self { - SignedDuration::zero() - } -} - -impl From for SignedDuration { - fn from(duration: Duration) -> Self { - Self { sign: Sign::Positive, duration } - } -} - -impl Neg for SignedDuration { - type Output = Self; - - fn neg(self) -> Self { - Self { - sign: match self.sign { - Sign::Positive => Sign::Negative, - Sign::Negative => Sign::Positive, - }, - duration: self.duration, - } - } -} - - -impl Add for SignedDuration { - type Output = Self; - - fn add(self, other: Self) -> Self { - match (self.sign, other.sign) { - (Sign::Positive, Sign::Positive) => Self { - sign: Sign::Positive, - duration: self.duration + other.duration, - }, - (Sign::Positive, Sign::Negative) => { - if self.duration >= other.duration { - Self { - sign: Sign::Positive, - duration: self.duration - other.duration, - } - } else { - Self { - sign: Sign::Negative, - duration: other.duration - self.duration, - } - } - }, - (Sign::Negative, Sign::Positive) => { - if other.duration >= self.duration { - Self { - sign: Sign::Positive, - duration: other.duration - self.duration, - } - } else { - Self { - sign: Sign::Negative, - duration: self.duration - other.duration, - } - } - }, - (Sign::Negative, Sign::Negative) => Self { - sign: Sign::Negative, - duration: self.duration + other.duration, - }, - } - } -} - -impl Sub for SignedDuration { - type Output = Self; - - fn sub(self, other: Self) -> Self { - self.add(other.neg()) - } -} - -pub fn duration_add_assign_signed_duration(duration: &mut Duration, other: SignedDuration) { - match other.sign { - Sign::Positive => *duration += other.duration, - Sign::Negative => *duration -= other.duration, - } -} - -pub fn from_f64_millis(millis: f64) -> Duration { - Duration::from_nanos((millis * 1_000_000.0) as u64) -} - -pub fn into_f64_millis(duration: Duration) -> f64 { - duration.as_nanos() as f64 / 1_000_000.0 -} - -pub fn from_f64_seconds(secs: f64) -> Duration { - Duration::from_nanos((secs * 1_000_000_000.0) as u64) -} - -pub fn into_f64_seconds(duration: Duration) -> f64 { - duration.as_nanos() as f64 / 1_000_000_000.0 -} - -#[cfg(test)] -mod tests { - use std::time::Duration; - - #[test] - fn test_from_f64_millis_standard_case() { - assert_eq!(super::from_f64_millis(1.0), Duration::from_millis(1)); - } - - #[test] - fn test_from_f64_sub_millis_case() { - assert_eq!(super::from_f64_millis(1.5), Duration::from_micros(1500)); - } - - #[test] - fn test_into_f64_millis_standard_case() { - assert_eq!(super::into_f64_millis(Duration::from_millis(1)), 1.0); - } - - #[test] - fn test_into_f64_sub_millis_case() { - assert_eq!(super::into_f64_millis(Duration::from_micros(1500)), 1.5); - } - - #[test] - fn test_from_f64_seconds_standard_case() { - assert_eq!( - super::from_f64_seconds(1.0), - Duration::from_secs(1) - ); - } - - #[test] - fn test_from_f64_sub_seconds_case() { - assert_eq!( - super::from_f64_seconds(1.5), - Duration::from_millis(1500) - ); - } - - #[test] - fn test_into_f64_seconds_standard_case() { - assert_eq!( - super::into_f64_seconds(Duration::from_secs(1)), - 1.0 - ); - } - - #[test] - fn test_into_f64_sub_seconds_case() { - assert_eq!( - super::into_f64_seconds(Duration::from_millis(1500)), - 1.5 - ); - } -} diff --git a/scanner/Cargo.toml b/scanner/Cargo.toml index 0f60641419727..a7e200190db6c 100644 --- a/scanner/Cargo.toml +++ b/scanner/Cargo.toml @@ -18,4 +18,3 @@ swf = { path = "../swf" } rayon = "1.6.0" crossbeam-channel = "0.5" sha2 = "0.10.6" -duration_helper = { path = "../duration_helper" } diff --git a/scanner/src/execute.rs b/scanner/src/execute.rs index a318de92e4d42..900c355d4f04a 100644 --- a/scanner/src/execute.rs +++ b/scanner/src/execute.rs @@ -14,13 +14,13 @@ use std::io::{stdout, Write}; use std::panic::catch_unwind; use std::path::Path; use std::time::{Duration, Instant}; -use duration_helper::from_f64_millis; +use ruffle_core::duration::RuffleDuration; fn execute_swf(file: &Path) { let base_path = file.parent().unwrap(); let executor = NullExecutor::new(); let movie = SwfMovie::from_path(file, None).unwrap(); - let frame_time = from_f64_millis(1000.0 / movie.frame_rate().to_f64()); + let frame_time = RuffleDuration::from_millis(1000.0 / movie.frame_rate().to_f64()); let player = PlayerBuilder::new() .with_log(ScanLogBackend::new()) .with_navigator(NullNavigatorBackend::with_base_path(base_path, &executor)) diff --git a/tests/Cargo.toml b/tests/Cargo.toml index 4966d24d89629..967fd01046ab0 100644 --- a/tests/Cargo.toml +++ b/tests/Cargo.toml @@ -11,7 +11,6 @@ ruffle_render_wgpu = { path = "../render/wgpu", optional = true } ruffle_input_format = { path = "input-format" } image = "0.24.5" regex = "1.7.0" -duration_helper = { path = "../duration_helper"} [features] # Enable running image comparison tests. This is off by default, diff --git a/tests/tests/regression_tests.rs b/tests/tests/regression_tests.rs index 3c4a590ab3f0a..50f1e5b96a74b 100644 --- a/tests/tests/regression_tests.rs +++ b/tests/tests/regression_tests.rs @@ -29,7 +29,7 @@ use std::path::Path; use std::rc::Rc; use std::sync::{Arc, Mutex}; use std::time::Duration; -use duration_helper::from_f64_millis; +use ruffle_core::duration::RuffleDuration; const RUN_IMG_TESTS: bool = cfg!(feature = "imgtests"); @@ -1387,7 +1387,7 @@ fn run_swf( let base_path = Path::new(swf_path).parent().unwrap(); let mut executor = NullExecutor::new(); let movie = SwfMovie::from_path(swf_path, None)?; - let frame_time = from_f64_millis(1000.0 / movie.frame_rate().to_f64()); + let frame_time = RuffleDuration::from_millis(1000.0 / movie.frame_rate().to_f64()); let trace_output = Rc::new(RefCell::new(Vec::new())); #[allow(unused_mut)] diff --git a/web/Cargo.toml b/web/Cargo.toml index 27b2c2cdb5bcf..d7da5786780d2 100644 --- a/web/Cargo.toml +++ b/web/Cargo.toml @@ -46,7 +46,6 @@ getrandom = { version = "0.2", features = ["js"] } serde = { version = "1.0.147", features = ["derive"] } thiserror = "1.0" base64 = "0.13.1" -duration_helper = { path = "../duration_helper" } [dependencies.ruffle_core] path = "../core" diff --git a/web/src/lib.rs b/web/src/lib.rs index 8b58b7dc9c72a..81108106d99fc 100644 --- a/web/src/lib.rs +++ b/web/src/lib.rs @@ -29,7 +29,7 @@ use web_sys::{ AddEventListenerOptions, Element, Event, EventTarget, HtmlCanvasElement, HtmlElement, KeyboardEvent, PointerEvent, WheelEvent, Window, }; -use duration_helper::from_f64_millis; +use ruffle_core::duration::RuffleDuration; static RUFFLE_GLOBAL_PANIC: Once = Once::new(); @@ -987,7 +987,7 @@ impl Ruffle { }); } - core.tick(from_f64_millis(dt)); + core.tick(RuffleDuration::from_millis(dt)); // Render if the core signals a new frame, or if we resized. if core.needs_render() || new_dimensions.is_some() { From 5c3074b9490c45972a1fc63991efe146cd862f10 Mon Sep 17 00:00:00 2001 From: higumachan Date: Fri, 29 Jul 2022 00:13:09 +0900 Subject: [PATCH 07/15] Avoid using std::time::Duration as much as possible --- core/src/avm1/globals/sound.rs | 1 - core/src/display_object/interactive.rs | 1 + scanner/src/file_results.rs | 1 + tests/tests/regression_tests.rs | 1 - 4 files changed, 2 insertions(+), 2 deletions(-) diff --git a/core/src/avm1/globals/sound.rs b/core/src/avm1/globals/sound.rs index 2ef02cce0be8f..bdee7826d2773 100644 --- a/core/src/avm1/globals/sound.rs +++ b/core/src/avm1/globals/sound.rs @@ -10,7 +10,6 @@ use crate::backend::navigator::Request; use crate::character::Character; use crate::display_object::{SoundTransform, TDisplayObject}; use gc_arena::MutationContext; -use std::time::Duration; const PROTO_DECLS: &[Declaration] = declare_properties! { "attachSound" => method(attach_sound; DONT_ENUM | DONT_DELETE | READ_ONLY); diff --git a/core/src/display_object/interactive.rs b/core/src/display_object/interactive.rs index d19d82fb7cd2f..60602cb96943b 100644 --- a/core/src/display_object/interactive.rs +++ b/core/src/display_object/interactive.rs @@ -22,6 +22,7 @@ use ruffle_macros::enum_trait_object; use std::cell::{Ref, RefMut}; use std::fmt::Debug; use swf::Twips; +use crate::duration::RuffleDuration; /// Find the lowest common ancestor between the display objects in `from` and /// `to`. diff --git a/scanner/src/file_results.rs b/scanner/src/file_results.rs index 60048579e42c1..08daebac4f9b0 100644 --- a/scanner/src/file_results.rs +++ b/scanner/src/file_results.rs @@ -8,6 +8,7 @@ use serde::ser::Error as SerError; use serde::{Deserialize, Deserializer, Serialize, Serializer}; use std::fmt; use std::fmt::Write; +use ruffle_core::duration::RuffleDuration; #[derive(Serialize, Deserialize, Debug, Clone)] pub enum AvmType { diff --git a/tests/tests/regression_tests.rs b/tests/tests/regression_tests.rs index 50f1e5b96a74b..f2659b09c4ba6 100644 --- a/tests/tests/regression_tests.rs +++ b/tests/tests/regression_tests.rs @@ -28,7 +28,6 @@ use std::collections::BTreeMap; use std::path::Path; use std::rc::Rc; use std::sync::{Arc, Mutex}; -use std::time::Duration; use ruffle_core::duration::RuffleDuration; const RUN_IMG_TESTS: bool = cfg!(feature = "imgtests"); From baf4a79bd2d2b361e8d16d801b980e9cc44a984a Mon Sep 17 00:00:00 2001 From: higumachan Date: Sat, 13 Aug 2022 18:37:58 +0900 Subject: [PATCH 08/15] fix clippy --- core/src/backend/audio.rs | 19 ++++++++++--------- core/src/duration.rs | 5 +++-- scanner/src/execute.rs | 5 ++--- web/src/audio.rs | 1 - web/src/lib.rs | 2 -- 5 files changed, 15 insertions(+), 17 deletions(-) diff --git a/core/src/backend/audio.rs b/core/src/backend/audio.rs index 1df994a63193e..c7fdb5b50ce78 100644 --- a/core/src/backend/audio.rs +++ b/core/src/backend/audio.rs @@ -8,7 +8,6 @@ use downcast_rs::Downcast; use duration_helper::from_f64_millis; use gc_arena::Collect; use generational_arena::{Arena, Index}; -use num_traits::real::Real; #[cfg(feature = "audio")] pub mod decoders; @@ -503,7 +502,11 @@ impl<'gc> AudioManager<'gc> { } /// Returns the difference in seconds between the primary audio stream's time and the player's time. - pub fn audio_skew_time(&mut self, audio: &mut dyn AudioBackend, offset: RuffleDuration) -> RuffleDuration { + pub fn audio_skew_time( + &mut self, + audio: &mut dyn AudioBackend, + offset: RuffleDuration, + ) -> RuffleDuration { // Consider the first playing "stream" sound to be the primary audio track. // Needs research: It's not clear how Flash handles the case of multiple stream sounds. let (i, skew) = self @@ -522,17 +525,15 @@ impl<'gc> AudioManager<'gc> { // If the difference is beyond some threshold, inform the player to adjust playback speed. let timeline_pos = RuffleDuration::from_secs( f64::from(clip.current_frame().saturating_sub(start_frame)) / frame_rate, - ) + offset.into(); - Some((i, RuffleDuration::from(stream_pos) - timeline_pos)) + ) + offset; + Some((i, stream_pos - timeline_pos)) }) .unwrap_or_default(); // Calculate the syncing threshold based on the audio backend's frequency in updating sound position. - let sync_threshold = audio - .position_resolution() - .unwrap_or(RuffleDuration::from_secs( - Self::STREAM_DEFAULT_SYNC_THRESHOLD_SECONDS, - )); + let sync_threshold = audio.position_resolution().unwrap_or_else(|| { + RuffleDuration::from_secs(Self::STREAM_DEFAULT_SYNC_THRESHOLD_SECONDS) + }); if skew.abs() >= Self::STREAM_RESTART_THRESHOLD { // Way out of sync, let's stop the entire stream. diff --git a/core/src/duration.rs b/core/src/duration.rs index d2f9365fb0c3e..389b8f0cad6a7 100644 --- a/core/src/duration.rs +++ b/core/src/duration.rs @@ -86,13 +86,14 @@ impl SubAssign for RuffleDuration { } } -impl From for RuffleDuration { +impl From for RuffleDuration { fn from(d: std::time::Duration) -> Self { Self::from_nanos(d.as_nanos() as f64) } } -impl Into for RuffleDuration { +#[allow(clippy::from_over_into)] +impl Into for RuffleDuration { fn into(self) -> Duration { Duration::from_nanos(self.as_nanos() as u64) } diff --git a/scanner/src/execute.rs b/scanner/src/execute.rs index 900c355d4f04a..cfacba84c6140 100644 --- a/scanner/src/execute.rs +++ b/scanner/src/execute.rs @@ -13,14 +13,13 @@ use sha2::{Digest, Sha256}; use std::io::{stdout, Write}; use std::panic::catch_unwind; use std::path::Path; -use std::time::{Duration, Instant}; -use ruffle_core::duration::RuffleDuration; +use std::time::Instant; fn execute_swf(file: &Path) { let base_path = file.parent().unwrap(); let executor = NullExecutor::new(); let movie = SwfMovie::from_path(file, None).unwrap(); - let frame_time = RuffleDuration::from_millis(1000.0 / movie.frame_rate().to_f64()); + let frame_time = RuffleDuration::from_millis(1000.0 / movie.frame_rate().to_f64()); let player = PlayerBuilder::new() .with_log(ScanLogBackend::new()) .with_navigator(NullNavigatorBackend::with_base_path(base_path, &executor)) diff --git a/web/src/audio.rs b/web/src/audio.rs index 533a985f06214..a7eed0a8476d8 100644 --- a/web/src/audio.rs +++ b/web/src/audio.rs @@ -7,7 +7,6 @@ use ruffle_core::duration::RuffleDuration; use ruffle_core::impl_audio_mixer_backend; use ruffle_web_common::JsResult; use std::sync::{Arc, RwLock}; -use std::time::Duration; use wasm_bindgen::{closure::Closure, prelude::*, JsCast}; use web_sys::AudioContext; diff --git a/web/src/lib.rs b/web/src/lib.rs index 81108106d99fc..606fee23ad28d 100644 --- a/web/src/lib.rs +++ b/web/src/lib.rs @@ -22,14 +22,12 @@ use serde::{Deserialize, Serialize}; use std::collections::BTreeMap; use std::sync::Once; use std::sync::{Arc, Mutex}; -use std::time::Duration; use std::{cell::RefCell, error::Error, num::NonZeroI32}; use wasm_bindgen::{prelude::*, JsCast, JsValue}; use web_sys::{ AddEventListenerOptions, Element, Event, EventTarget, HtmlCanvasElement, HtmlElement, KeyboardEvent, PointerEvent, WheelEvent, Window, }; -use ruffle_core::duration::RuffleDuration; static RUFFLE_GLOBAL_PANIC: Once = Once::new(); From a2e3bbf785a253240ce5a1b046059ac62fc73541 Mon Sep 17 00:00:00 2001 From: higumachan Date: Sun, 14 Aug 2022 13:42:11 +0900 Subject: [PATCH 09/15] cargo fmt --- core/src/avm1/activation.rs | 1 - core/src/avm2/activation.rs | 1 - core/src/display_object/interactive.rs | 1 - core/src/lib.rs | 1 - core/src/player.rs | 2 -- core/src/timer.rs | 13 +++++++++---- desktop/src/main.rs | 1 - scanner/src/file_results.rs | 1 - tests/tests/regression_tests.rs | 3 ++- 9 files changed, 11 insertions(+), 13 deletions(-) diff --git a/core/src/avm1/activation.rs b/core/src/avm1/activation.rs index 1f9a325354334..38bb12ebf871f 100644 --- a/core/src/avm1/activation.rs +++ b/core/src/avm1/activation.rs @@ -28,7 +28,6 @@ use swf::avm1::read::Reader; use swf::avm1::types::*; use swf::Twips; use url::form_urlencoded; -use crate::duration::RuffleDuration; macro_rules! avm_debug { ($avm: expr, $($arg:tt)*) => ( diff --git a/core/src/avm2/activation.rs b/core/src/avm2/activation.rs index cf92c460e5d3d..ce669e4bfe011 100644 --- a/core/src/avm2/activation.rs +++ b/core/src/avm2/activation.rs @@ -29,7 +29,6 @@ use swf::avm2::types::{ Class as AbcClass, Exception, Index, Method as AbcMethod, MethodFlags as AbcMethodFlags, Multiname as AbcMultiname, Namespace as AbcNamespace, Op, }; -use crate::duration::RuffleDuration; /// Represents a particular register set. /// diff --git a/core/src/display_object/interactive.rs b/core/src/display_object/interactive.rs index 60602cb96943b..d19d82fb7cd2f 100644 --- a/core/src/display_object/interactive.rs +++ b/core/src/display_object/interactive.rs @@ -22,7 +22,6 @@ use ruffle_macros::enum_trait_object; use std::cell::{Ref, RefMut}; use std::fmt::Debug; use swf::Twips; -use crate::duration::RuffleDuration; /// Find the lowest common ancestor between the display objects in `from` and /// `to`. diff --git a/core/src/lib.rs b/core/src/lib.rs index 1068622cca4f3..db14f8d4a35fa 100644 --- a/core/src/lib.rs +++ b/core/src/lib.rs @@ -46,7 +46,6 @@ pub mod backend; pub mod config; pub mod duration; pub mod external; -pub mod duration; pub use context_menu::ContextMenuItem; pub use events::PlayerEvent; diff --git a/core/src/player.rs b/core/src/player.rs index 34609c79b03b9..3ce058cb80e91 100644 --- a/core/src/player.rs +++ b/core/src/player.rs @@ -55,7 +55,6 @@ use std::ops::DerefMut; use std::rc::{Rc, Weak as RcWeak}; use std::str::FromStr; use std::sync::{Arc, Mutex, Weak}; -use crate::duration::RuffleDuration; /// The newest known Flash Player version, serves as a default to /// `player_version`. @@ -507,7 +506,6 @@ impl Player { context .audio_manager .audio_skew_time(context.audio, cur_frame_offset) - }); self.frame_accumulator += add; diff --git a/core/src/timer.rs b/core/src/timer.rs index 8da3ae685ffa0..433416d5a509b 100644 --- a/core/src/timer.rs +++ b/core/src/timer.rs @@ -16,7 +16,6 @@ use crate::string::AvmString; use gc_arena::Collect; use std::collections::{binary_heap::PeekMut, BinaryHeap}; use std::ops::{Add, AddAssign, Sub}; -use crate::duration::RuffleDuration; /// Manages the collection of timers. pub struct Timers<'gc> { @@ -32,7 +31,10 @@ pub struct Timers<'gc> { impl<'gc> Timers<'gc> { /// Ticks all timers and runs necessary callbacks. - pub fn update_timers(context: &mut UpdateContext<'_, 'gc, '_>, dt: RuffleDuration) -> Option { + pub fn update_timers( + context: &mut UpdateContext<'_, 'gc, '_>, + dt: RuffleDuration, + ) -> Option { context.timers.cur_time.add_assign(dt); let num_timers = context.timers.num_timers(); @@ -74,8 +76,11 @@ impl<'gc> Timers<'gc> { // SANITY: Only allow so many ticks per timer per update. if tick_count > Self::MAX_TICKS { // Reset our time to a little bit before the nearest timer. - let next_time = RuffleDuration::from_micros(activation.context.timers.peek_mut().unwrap().tick_time as f64); - activation.context.timers.cur_time = next_time.add(RuffleDuration::from_millis(100.0)); + let next_time = RuffleDuration::from_micros( + activation.context.timers.peek_mut().unwrap().tick_time as f64, + ); + activation.context.timers.cur_time = + next_time.add(RuffleDuration::from_millis(100.0)); break; } diff --git a/desktop/src/main.rs b/desktop/src/main.rs index 6077ce48680c5..84d891aa98f18 100644 --- a/desktop/src/main.rs +++ b/desktop/src/main.rs @@ -40,7 +40,6 @@ use winit::event::{ }; use winit::event_loop::{ControlFlow, EventLoop, EventLoopBuilder}; use winit::window::{Fullscreen, Icon, Window, WindowBuilder}; -use ruffle_core::duration::RuffleDuration; thread_local! { static CALLSTACK: RefCell> = RefCell::default(); diff --git a/scanner/src/file_results.rs b/scanner/src/file_results.rs index 08daebac4f9b0..60048579e42c1 100644 --- a/scanner/src/file_results.rs +++ b/scanner/src/file_results.rs @@ -8,7 +8,6 @@ use serde::ser::Error as SerError; use serde::{Deserialize, Deserializer, Serialize, Serializer}; use std::fmt; use std::fmt::Write; -use ruffle_core::duration::RuffleDuration; #[derive(Serialize, Deserialize, Debug, Clone)] pub enum AvmType { diff --git a/tests/tests/regression_tests.rs b/tests/tests/regression_tests.rs index f2659b09c4ba6..de81142431f41 100644 --- a/tests/tests/regression_tests.rs +++ b/tests/tests/regression_tests.rs @@ -10,6 +10,7 @@ use ruffle_core::backend::{ storage::{MemoryStorageBackend, StorageBackend}, }; use ruffle_core::context::UpdateContext; +use ruffle_core::duration::RuffleDuration; use ruffle_core::events::MouseButton as RuffleMouseButton; use ruffle_core::external::Value as ExternalValue; use ruffle_core::external::{ExternalInterfaceMethod, ExternalInterfaceProvider}; @@ -28,7 +29,7 @@ use std::collections::BTreeMap; use std::path::Path; use std::rc::Rc; use std::sync::{Arc, Mutex}; -use ruffle_core::duration::RuffleDuration; +use std::time::Duration; const RUN_IMG_TESTS: bool = cfg!(feature = "imgtests"); From 1ca43faad96d06020c66d1e81ecf328cec51e981 Mon Sep 17 00:00:00 2001 From: higumachan Date: Fri, 2 Sep 2022 19:30:40 +0900 Subject: [PATCH 10/15] rename RuffleDuration -> Duration --- core/src/avm1/activation.rs | 4 +-- core/src/avm2/activation.rs | 4 +-- core/src/backend/audio.rs | 38 +++++++++++------------ core/src/backend/audio/mixer.rs | 14 ++++----- core/src/context.rs | 4 +-- core/src/display_object/interactive.rs | 6 ++-- core/src/duration.rs | 28 ++++++++--------- core/src/player.rs | 42 +++++++++++++------------- core/src/timer.rs | 21 ++++++------- desktop/src/audio.rs | 2 +- desktop/src/main.rs | 4 +-- scanner/src/execute.rs | 6 ++-- scanner/src/file_results.rs | 6 ++-- tests/tests/regression_tests.rs | 12 ++++---- web/src/audio.rs | 8 ++--- web/src/lib.rs | 6 ++-- 16 files changed, 99 insertions(+), 106 deletions(-) diff --git a/core/src/avm1/activation.rs b/core/src/avm1/activation.rs index 38bb12ebf871f..839f36fd02cf0 100644 --- a/core/src/avm1/activation.rs +++ b/core/src/avm1/activation.rs @@ -9,7 +9,7 @@ use crate::avm1::{fscommand, globals, scope, ArrayObject, ScriptObject, Value}; use crate::backend::navigator::{NavigationMethod, Request}; use crate::context::UpdateContext; use crate::display_object::{DisplayObject, MovieClip, TDisplayObject, TDisplayObjectContainer}; -use crate::duration::RuffleDuration; +use crate::duration::Duration; use crate::ecma_conversions::f64_to_wrapping_u32; use crate::string::{AvmString, WStr, WString}; use crate::tag_utils::SwfSlice; @@ -435,7 +435,7 @@ impl<'a, 'gc, 'gc_context> Activation<'a, 'gc, 'gc_context> { *self.context.actions_since_timeout_check += 1; if *self.context.actions_since_timeout_check >= 2000 { *self.context.actions_since_timeout_check = 0; - if RuffleDuration::from(self.context.update_start.elapsed()) + if Duration::from(self.context.update_start.elapsed()) >= self.context.max_execution_duration { return Err(Error::ExecutionTimeout); diff --git a/core/src/avm2/activation.rs b/core/src/avm2/activation.rs index ce669e4bfe011..8cb71eeee4ec2 100644 --- a/core/src/avm2/activation.rs +++ b/core/src/avm2/activation.rs @@ -17,7 +17,7 @@ use crate::avm2::Namespace; use crate::avm2::QName; use crate::avm2::{value, Avm2, Error}; use crate::context::UpdateContext; -use crate::duration::RuffleDuration; +use crate::duration::Duration; use crate::string::{AvmString, WStr, WString}; use crate::swf::extensions::ReadSwfExt; use gc_arena::{Gc, GcCell}; @@ -947,7 +947,7 @@ impl<'a, 'gc, 'gc_context> Activation<'a, 'gc, 'gc_context> { self.actions_since_timeout_check += 1; if self.actions_since_timeout_check >= 2000 { self.actions_since_timeout_check = 0; - if RuffleDuration::from(self.context.update_start.elapsed()) + if Duration::from(self.context.update_start.elapsed()) >= self.context.max_execution_duration { return Err( diff --git a/core/src/backend/audio.rs b/core/src/backend/audio.rs index c7fdb5b50ce78..5041b9ce36e84 100644 --- a/core/src/backend/audio.rs +++ b/core/src/backend/audio.rs @@ -1,4 +1,4 @@ -use crate::duration::RuffleDuration; +use crate::duration::Duration; use crate::{ avm1::SoundObject, avm2::SoundChannelObject, @@ -79,11 +79,11 @@ pub trait AudioBackend: Downcast { /// Get the position of a sound instance in milliseconds. /// Returns `None` if ther sound is not/no longer playing - fn get_sound_position(&self, instance: SoundInstanceHandle) -> Option; + fn get_sound_position(&self, instance: SoundInstanceHandle) -> Option; /// Get the duration of a sound in milliseconds. /// Returns `None` if sound is not registered. - fn get_sound_duration(&self, sound: SoundHandle) -> Option; + fn get_sound_duration(&self, sound: SoundHandle) -> Option; /// Get the size of the data stored within a given sound. /// @@ -119,7 +119,7 @@ pub trait AudioBackend: Downcast { /// value is unknown. /// /// This determines the time threshold for syncing embedded audio streams to the animation. - fn position_resolution(&self) -> Option { + fn position_resolution(&self) -> Option { None } @@ -138,7 +138,7 @@ impl_downcast!(AudioBackend); /// Information about a sound provided to `NullAudioBackend`. struct NullSound { /// The duration of the sound in milliseconds. - duration: RuffleDuration, + duration: Duration, /// The compressed size of the sound data, excluding MP3 latency seek data. size: u32, @@ -176,7 +176,7 @@ impl AudioBackend for NullAudioBackend { // AS duration does not subtract `skip_sample_frames`. let num_sample_frames: f64 = sound.num_samples.into(); let sample_rate: f64 = sound.format.sample_rate.into(); - let duration = RuffleDuration::from_millis(num_sample_frames * 1000.0 / sample_rate); + let duration = Duration::from_millis(num_sample_frames * 1000.0 / sample_rate); Ok(self.sounds.insert(NullSound { duration, @@ -219,10 +219,10 @@ impl AudioBackend for NullAudioBackend { fn stop_sound(&mut self, _sound: SoundInstanceHandle) {} fn stop_all_sounds(&mut self) {} - fn get_sound_position(&self, _instance: SoundInstanceHandle) -> Option { - Some(RuffleDuration::zero()) + fn get_sound_position(&self, _instance: SoundInstanceHandle) -> Option { + Some(Duration::zero()) } - fn get_sound_duration(&self, sound: SoundHandle) -> Option { + fn get_sound_duration(&self, sound: SoundHandle) -> Option { if let Some(sound) = self.sounds.get(sound) { Some(sound.duration) } else { @@ -299,7 +299,7 @@ impl<'gc> AudioManager<'gc> { pub const STREAM_SYNC_THRESHOLD: f64 = 1.0 / 60.0; /// The threshold in seconds where an audio stream is considered too out-of-sync and will be stopped. - pub const STREAM_RESTART_THRESHOLD: RuffleDuration = RuffleDuration::one_sec(); + pub const STREAM_RESTART_THRESHOLD: Duration = Duration::one_sec(); /// The minimum audio sycning threshold in seconds. /// @@ -502,11 +502,7 @@ impl<'gc> AudioManager<'gc> { } /// Returns the difference in seconds between the primary audio stream's time and the player's time. - pub fn audio_skew_time( - &mut self, - audio: &mut dyn AudioBackend, - offset: RuffleDuration, - ) -> RuffleDuration { + pub fn audio_skew_time(&mut self, audio: &mut dyn AudioBackend, offset: Duration) -> Duration { // Consider the first playing "stream" sound to be the primary audio track. // Needs research: It's not clear how Flash handles the case of multiple stream sounds. let (i, skew) = self @@ -523,7 +519,7 @@ impl<'gc> AudioManager<'gc> { // Calculate the difference in time between the owning movie clip and its audio track. // If the difference is beyond some threshold, inform the player to adjust playback speed. - let timeline_pos = RuffleDuration::from_secs( + let timeline_pos = Duration::from_secs( f64::from(clip.current_frame().saturating_sub(start_frame)) / frame_rate, ) + offset; Some((i, stream_pos - timeline_pos)) @@ -531,9 +527,9 @@ impl<'gc> AudioManager<'gc> { .unwrap_or_default(); // Calculate the syncing threshold based on the audio backend's frequency in updating sound position. - let sync_threshold = audio.position_resolution().unwrap_or_else(|| { - RuffleDuration::from_secs(Self::STREAM_DEFAULT_SYNC_THRESHOLD_SECONDS) - }); + let sync_threshold = audio + .position_resolution() + .unwrap_or_else(|| Duration::from_secs(Self::STREAM_DEFAULT_SYNC_THRESHOLD_SECONDS)); if skew.abs() >= Self::STREAM_RESTART_THRESHOLD { // Way out of sync, let's stop the entire stream. @@ -541,13 +537,13 @@ impl<'gc> AudioManager<'gc> { let instance = &self.sounds[i]; audio.stop_sound(instance.instance); self.sounds.swap_remove(i); - RuffleDuration::zero() + Duration::zero() } else if skew.abs() < sync_threshold { // Slightly out of sync, adjust player speed to compensate. skew } else { // More or less in sync, no adjustment. - RuffleDuration::zero() + Duration::zero() } } diff --git a/core/src/backend/audio/mixer.rs b/core/src/backend/audio/mixer.rs index b73d6200a7849..6dac3da1a9115 100644 --- a/core/src/backend/audio/mixer.rs +++ b/core/src/backend/audio/mixer.rs @@ -1,7 +1,7 @@ use super::decoders::{self, AdpcmDecoder, Decoder, PcmDecoder, SeekableDecoder}; use super::{SoundHandle, SoundInstanceHandle, SoundTransform}; use crate::backend::audio::{DecodeError, RegisterError}; -use crate::duration::RuffleDuration; +use crate::duration::Duration; use crate::tag_utils::SwfSlice; use duration_helper::from_f64_millis; use generational_arena::Arena; @@ -594,13 +594,13 @@ impl AudioMixer { /// Returns the position of a playing sound in milliseconds. /// ////// Returns `None` if the sound is no longer playing. - pub fn get_sound_position(&self, instance: SoundInstanceHandle) -> Option { + pub fn get_sound_position(&self, instance: SoundInstanceHandle) -> Option { let sound_instances = self.sound_instances.lock().unwrap(); sound_instances.get(instance).map(|instance| { // Get the current sample position from the underlying audio source. let num_sample_frames: f64 = instance.stream.source_position().into(); let sample_rate: f64 = instance.stream.source_sample_rate().into(); - RuffleDuration::from_millis(num_sample_frames * 1000.0 / sample_rate) + Duration::from_millis(num_sample_frames * 1000.0 / sample_rate) }) } @@ -612,12 +612,12 @@ impl AudioMixer { /// Returns the duration of a registered sound in milliseconds. /// /// Returns `None` if the sound is not registered or invalid. - pub fn get_sound_duration(&self, sound: SoundHandle) -> Option { + pub fn get_sound_duration(&self, sound: SoundHandle) -> Option { self.sounds.get(sound).map(|sound| { // AS duration does not subtract `skip_sample_frames`. let num_sample_frames: f64 = sound.num_sample_frames.into(); let sample_rate: f64 = sound.format.sample_rate.into(); - RuffleDuration::from_millis(num_sample_frames * 1000.0 / sample_rate) + Duration::from_millis(num_sample_frames * 1000.0 / sample_rate) }) } @@ -1044,12 +1044,12 @@ macro_rules! impl_audio_mixer_backend { } #[inline] - fn get_sound_position(&self, instance: SoundInstanceHandle) -> Option { + fn get_sound_position(&self, instance: SoundInstanceHandle) -> Option { self.$mixer.get_sound_position(instance) } #[inline] - fn get_sound_duration(&self, sound: SoundHandle) -> Option { + fn get_sound_duration(&self, sound: SoundHandle) -> Option { self.$mixer.get_sound_duration(sound) } diff --git a/core/src/context.rs b/core/src/context.rs index d05ce719d42d5..e1f12b00e3b63 100644 --- a/core/src/context.rs +++ b/core/src/context.rs @@ -13,7 +13,7 @@ use crate::backend::{ }; use crate::context_menu::ContextMenuState; use crate::display_object::{EditText, InteractiveObject, MovieClip, SoundTransform, Stage}; -use crate::duration::RuffleDuration; +use crate::duration::Duration; use crate::external::ExternalInterface; use crate::focus_tracker::FocusTracker; use crate::frame_lifecycle::FramePhase; @@ -158,7 +158,7 @@ pub struct UpdateContext<'a, 'gc, 'gc_context> { /// The maximum amount of time that can be called before a `Error::ExecutionTimeout` /// is raised. This defaults to 15 seconds but can be changed. - pub max_execution_duration: RuffleDuration, + pub max_execution_duration: Duration, /// A tracker for the current keyboard focused element pub focus_tracker: FocusTracker<'gc>, diff --git a/core/src/display_object/interactive.rs b/core/src/display_object/interactive.rs index d19d82fb7cd2f..fe308a39ba462 100644 --- a/core/src/display_object/interactive.rs +++ b/core/src/display_object/interactive.rs @@ -13,7 +13,7 @@ use crate::display_object::stage::Stage; use crate::display_object::{ DisplayObject, DisplayObjectBase, TDisplayObject, TDisplayObjectContainer, }; -use crate::duration::RuffleDuration; +use crate::duration::Duration; use crate::events::{ClipEvent, ClipEventResult}; use bitflags::bitflags; use gc_arena::{Collect, MutationContext}; @@ -265,9 +265,7 @@ pub trait TInteractiveObject<'gc>: .flags .contains(InteractiveObjectFlags::DOUBLE_CLICK_ENABLED) && last_click - .map(|lc| { - RuffleDuration::from(this_click - lc) < RuffleDuration::from_secs(1.0) - }) + .map(|lc| Duration::from(this_click - lc) < Duration::from_secs(1.0)) .unwrap_or(false); drop(read); diff --git a/core/src/duration.rs b/core/src/duration.rs index 389b8f0cad6a7..fd9a05576e9ae 100644 --- a/core/src/duration.rs +++ b/core/src/duration.rs @@ -2,13 +2,13 @@ use num_traits::Zero; use ordered_float::OrderedFloat; use serde::{Deserialize, Serialize}; use std::ops::{Add, AddAssign, Sub, SubAssign}; -use std::time::Duration; +use std::time::Duration as StdDuration; /// Duration f64 nanosec #[derive(Debug, Copy, Clone, Ord, PartialOrd, Eq, PartialEq, Default, Serialize, Deserialize)] -pub struct RuffleDuration(OrderedFloat); +pub struct Duration(OrderedFloat); -impl RuffleDuration { +impl Duration { pub fn from_secs(secs: f64) -> Self { Self::from_nanos(secs * 1_000_000_000.0) } @@ -45,7 +45,7 @@ impl RuffleDuration { Self(OrderedFloat::zero()) } - pub fn abs(&self) -> RuffleDuration { + pub fn abs(&self) -> Duration { Self(OrderedFloat(self.0.abs())) } @@ -58,7 +58,7 @@ impl RuffleDuration { } } -impl Add for RuffleDuration { +impl Add for Duration { type Output = Self; fn add(self, other: Self) -> Self { @@ -66,13 +66,13 @@ impl Add for RuffleDuration { } } -impl AddAssign for RuffleDuration { - fn add_assign(&mut self, other: RuffleDuration) { +impl AddAssign for Duration { + fn add_assign(&mut self, other: Duration) { self.0 += other.0; } } -impl Sub for RuffleDuration { +impl Sub for Duration { type Output = Self; fn sub(self, other: Self) -> Self { @@ -80,21 +80,21 @@ impl Sub for RuffleDuration { } } -impl SubAssign for RuffleDuration { +impl SubAssign for Duration { fn sub_assign(&mut self, rhs: Self) { self.0 -= rhs.0; } } -impl From for RuffleDuration { - fn from(d: std::time::Duration) -> Self { +impl From for Duration { + fn from(d: StdDuration) -> Self { Self::from_nanos(d.as_nanos() as f64) } } #[allow(clippy::from_over_into)] -impl Into for RuffleDuration { - fn into(self) -> Duration { - Duration::from_nanos(self.as_nanos() as u64) +impl Into for Duration { + fn into(self) -> StdDuration { + StdDuration::from_nanos(self.as_nanos() as u64) } } diff --git a/core/src/player.rs b/core/src/player.rs index 3ce058cb80e91..f2c78a006022e 100644 --- a/core/src/player.rs +++ b/core/src/player.rs @@ -25,7 +25,7 @@ use crate::display_object::{ EditText, InteractiveObject, MovieClip, Stage, StageAlign, StageDisplayState, StageQuality, StageScaleMode, TInteractiveObject, WindowMode, }; -use crate::duration::RuffleDuration; +use crate::duration::Duration; use crate::events::{ButtonKeyCode, ClipEvent, ClipEventResult, KeyCode, MouseButton, PlayerEvent}; use crate::external::Value as ExternalValue; use crate::external::{ExternalInterface, ExternalInterfaceProvider}; @@ -241,7 +241,7 @@ pub struct Player { /// Gained by passage of time between host frames, spent by executing SWF frames. /// This is how we support custom SWF framerates /// and compensate for small lags by "catching up" (up to MAX_FRAMES_PER_TICK). - frame_accumulator: RuffleDuration, + frame_accumulator: Duration, recent_run_frame_timings: VecDeque, /// Faked time passage for fooling hand-written busy-loop FPS limiters. @@ -261,14 +261,14 @@ pub struct Player { instance_counter: i32, /// Time remaining until the next timer will fire. - time_til_next_timer: Option, + time_til_next_timer: Option, /// The instant at which the SWF was launched. start_time: Instant, /// The maximum amount of time that can be called before a `Error::ExecutionTimeout` /// is raised. This defaults to 15 seconds but can be changed. - max_execution_duration: RuffleDuration, + max_execution_duration: Duration, /// Self-reference to ourselves. /// @@ -451,7 +451,7 @@ impl Player { } } - pub fn tick(&mut self, dt: RuffleDuration) { + pub fn tick(&mut self, dt: Duration) { // Don't run until preloading is complete. // TODO: Eventually we want to stream content similar to the Flash player. if !self.audio.is_loading_complete() { @@ -461,7 +461,7 @@ impl Player { if self.is_playing() { self.frame_accumulator += dt; let frame_rate = self.frame_rate; - let frame_time = RuffleDuration::from_millis(1000.0 / frame_rate); + let frame_time = Duration::from_millis(1000.0 / frame_rate); let max_frames_per_tick = self.max_frames_per_tick(); let mut frame = 0; @@ -480,7 +480,7 @@ impl Player { // Then we need to actually pass this time, by decreasing frame_accumulator // to delay the future frame. if self.time_offset > 0 { - self.frame_accumulator -= RuffleDuration::from_millis(self.time_offset.into()); + self.frame_accumulator -= Duration::from_millis(self.time_offset.into()); } } @@ -496,7 +496,7 @@ impl Player { // Sanity: If we had too many frames to tick, just reset the accumulator // to prevent running at turbo speed. if self.frame_accumulator >= frame_time { - self.frame_accumulator = RuffleDuration::zero(); + self.frame_accumulator = Duration::zero(); } // Adjust playback speed for next frame to stay in sync with timeline audio tracks ("stream" sounds). @@ -514,18 +514,18 @@ impl Player { } } - pub fn time_til_next_timer(&self) -> Option { + pub fn time_til_next_timer(&self) -> Option { self.time_til_next_timer } /// Returns the approximate duration of time until the next frame is due to run. /// This is only an approximation to be used for sleep durations. - pub fn time_til_next_frame(&self) -> RuffleDuration { - let frame_time = RuffleDuration::from_millis(1000.0 / self.frame_rate); - let mut dt = if self.frame_accumulator <= RuffleDuration::zero() { + pub fn time_til_next_frame(&self) -> Duration { + let frame_time = Duration::from_millis(1000.0 / self.frame_rate); + let mut dt = if self.frame_accumulator <= Duration::zero() { frame_time } else if self.frame_accumulator >= frame_time { - RuffleDuration::zero() + Duration::zero() } else { frame_time - self.frame_accumulator }; @@ -534,7 +534,7 @@ impl Player { dt = dt.min(time_til_next_timer) } - dt = dt.max(RuffleDuration::zero()); + dt = dt.max(Duration::zero()); dt } @@ -1809,7 +1809,7 @@ impl Player { /// Update all AVM-based timers (such as created via setInterval). /// Returns the approximate amount of time until the next timer tick. - pub fn update_timers(&mut self, dt: RuffleDuration) { + pub fn update_timers(&mut self, dt: Duration) { self.time_til_next_timer = self.mutate_with_update_context(|context| Timers::update_timers(context, dt)); } @@ -1848,11 +1848,11 @@ impl Player { &self.log } - pub fn max_execution_duration(&self) -> RuffleDuration { + pub fn max_execution_duration(&self) -> Duration { self.max_execution_duration } - pub fn set_max_execution_duration(&mut self, max_execution_duration: RuffleDuration) { + pub fn set_max_execution_duration(&mut self, max_execution_duration: Duration) { self.max_execution_duration = max_execution_duration } @@ -1880,7 +1880,7 @@ pub struct PlayerBuilder { autoplay: bool, fullscreen: bool, letterbox: Letterbox, - max_execution_duration: RuffleDuration, + max_execution_duration: Duration, viewport_width: u32, viewport_height: u32, viewport_scale_factor: f64, @@ -1911,7 +1911,7 @@ impl PlayerBuilder { fullscreen: false, // Disable script timeout in debug builds by default. letterbox: Letterbox::Fullscreen, - max_execution_duration: RuffleDuration::from_secs(if cfg!(debug_assertions) { + max_execution_duration: Duration::from_secs(if cfg!(debug_assertions) { f64::MAX } else { 15.0 @@ -1997,7 +1997,7 @@ impl PlayerBuilder { /// Sets the maximum execution time of ActionScript code. #[inline] - pub fn with_max_execution_duration(mut self, duration: RuffleDuration) -> Self { + pub fn with_max_execution_duration(mut self, duration: Duration) -> Self { self.max_execution_duration = duration; self } @@ -2092,7 +2092,7 @@ impl PlayerBuilder { // Timing frame_rate, frame_phase: Default::default(), - frame_accumulator: RuffleDuration::zero(), + frame_accumulator: Duration::zero(), recent_run_frame_timings: VecDeque::with_capacity(10), start_time: Instant::now(), time_offset: 0, diff --git a/core/src/timer.rs b/core/src/timer.rs index 433416d5a509b..e5f7e8021126d 100644 --- a/core/src/timer.rs +++ b/core/src/timer.rs @@ -11,7 +11,7 @@ use crate::avm1::{ use crate::avm2::object::TObject; use crate::avm2::{Activation as Avm2Activation, Object as Avm2Object, Value as Avm2Value}; use crate::context::UpdateContext; -use crate::duration::RuffleDuration; +use crate::duration::Duration; use crate::string::AvmString; use gc_arena::Collect; use std::collections::{binary_heap::PeekMut, BinaryHeap}; @@ -26,15 +26,15 @@ pub struct Timers<'gc> { timer_counter: i32, /// The current global time. - cur_time: RuffleDuration, + cur_time: Duration, } impl<'gc> Timers<'gc> { /// Ticks all timers and runs necessary callbacks. pub fn update_timers( context: &mut UpdateContext<'_, 'gc, '_>, - dt: RuffleDuration, - ) -> Option { + dt: Duration, + ) -> Option { context.timers.cur_time.add_assign(dt); let num_timers = context.timers.num_timers(); @@ -59,7 +59,7 @@ impl<'gc> Timers<'gc> { .context .timers .peek() - .map(|timer| RuffleDuration::from_micros(timer.tick_time as f64)) + .map(|timer| Duration::from_micros(timer.tick_time as f64)) .unwrap_or(cur_time) < cur_time { @@ -76,11 +76,10 @@ impl<'gc> Timers<'gc> { // SANITY: Only allow so many ticks per timer per update. if tick_count > Self::MAX_TICKS { // Reset our time to a little bit before the nearest timer. - let next_time = RuffleDuration::from_micros( + let next_time = Duration::from_micros( activation.context.timers.peek_mut().unwrap().tick_time as f64, ); - activation.context.timers.cur_time = - next_time.add(RuffleDuration::from_millis(100.0)); + activation.context.timers.cur_time = next_time.add(Duration::from_millis(100.0)); break; } @@ -162,7 +161,7 @@ impl<'gc> Timers<'gc> { .context .timers .peek() - .map(|timer| (RuffleDuration::from_micros(timer.tick_time as f64).sub(cur_time))) + .map(|timer| (Duration::from_micros(timer.tick_time as f64).sub(cur_time))) } /// The minimum interval we allow for timers. @@ -176,7 +175,7 @@ impl<'gc> Timers<'gc> { Self { timers: Default::default(), timer_counter: 0, - cur_time: RuffleDuration::zero(), + cur_time: Duration::zero(), } } @@ -193,7 +192,7 @@ impl<'gc> Timers<'gc> { is_timeout: bool, ) -> i32 { // SANITY: Set a minimum interval so we don't spam too much. - let interval = RuffleDuration::from_millis(interval.max(Self::MIN_INTERVAL) as f64); + let interval = Duration::from_millis(interval.max(Self::MIN_INTERVAL) as f64); self.timer_counter = self.timer_counter.wrapping_add(1); let id = self.timer_counter; diff --git a/desktop/src/audio.rs b/desktop/src/audio.rs index 8d48381c6c72f..b0395cafdf4ba 100644 --- a/desktop/src/audio.rs +++ b/desktop/src/audio.rs @@ -4,7 +4,7 @@ use ruffle_core::backend::audio::{ swf, AudioBackend, AudioMixer, DecodeError, RegisterError, SoundHandle, SoundInstanceHandle, SoundTransform, }; -use ruffle_core::duration::RuffleDuration; +use ruffle_core::duration::Duration; use ruffle_core::impl_audio_mixer_backend; pub struct CpalAudioBackend { diff --git a/desktop/src/main.rs b/desktop/src/main.rs index 84d891aa98f18..571394fd500fb 100644 --- a/desktop/src/main.rs +++ b/desktop/src/main.rs @@ -19,7 +19,7 @@ use anyhow::{anyhow, Context, Error}; use clap::Parser; use isahc::{config::RedirectPolicy, prelude::*, HttpClient}; use rfd::FileDialog; -use ruffle_core::duration::RuffleDuration; +use ruffle_core::duration::Duration; use ruffle_core::{ config::Letterbox, events::KeyCode, tag_utils::SwfMovie, LoadBehavior, Player, PlayerBuilder, PlayerEvent, StageDisplayState, StaticCallstack, ViewportDimensions, @@ -369,7 +369,7 @@ impl App { // Core loop winit::event::Event::MainEventsCleared if loaded => { let new_time = Instant::now(); - let dt = RuffleDuration::from(new_time.duration_since(time)); + let dt = Duration::from(new_time.duration_since(time)); if !dt.is_zero() { time = new_time; let mut player_lock = self.player.lock().unwrap(); diff --git a/scanner/src/execute.rs b/scanner/src/execute.rs index cfacba84c6140..cb7c0fe7aa134 100644 --- a/scanner/src/execute.rs +++ b/scanner/src/execute.rs @@ -4,7 +4,7 @@ use crate::cli_options::ExecuteReportOpt; use crate::file_results::{AvmType, FileResults, Step}; use crate::logging::{ScanLogBackend, ThreadLocalScanLogger, LOCAL_LOGGER}; use ruffle_core::backend::navigator::{NullExecutor, NullNavigatorBackend}; -use ruffle_core::duration::RuffleDuration; +use ruffle_core::duration::Duration; use ruffle_core::limits::ExecutionLimit; use ruffle_core::swf::{decompress_swf, parse_swf}; use ruffle_core::tag_utils::SwfMovie; @@ -19,11 +19,11 @@ fn execute_swf(file: &Path) { let base_path = file.parent().unwrap(); let executor = NullExecutor::new(); let movie = SwfMovie::from_path(file, None).unwrap(); - let frame_time = RuffleDuration::from_millis(1000.0 / movie.frame_rate().to_f64()); + let frame_time = Duration::from_millis(1000.0 / movie.frame_rate().to_f64()); let player = PlayerBuilder::new() .with_log(ScanLogBackend::new()) .with_navigator(NullNavigatorBackend::with_base_path(base_path, &executor)) - .with_max_execution_duration(RuffleDuration::from_secs(300.0)) + .with_max_execution_duration(Duration::from_secs(300.0)) .with_movie(movie) .build(); diff --git a/scanner/src/file_results.rs b/scanner/src/file_results.rs index 60048579e42c1..4b946133ecbd9 100644 --- a/scanner/src/file_results.rs +++ b/scanner/src/file_results.rs @@ -2,7 +2,7 @@ //! //! The `FileResults` type in this module is used to report results of a scan. -use ruffle_core::duration::RuffleDuration; +use ruffle_core::duration::Duration; use serde::de::{Error as DesError, Unexpected, Visitor}; use serde::ser::Error as SerError; use serde::{Deserialize, Deserializer, Serialize, Serializer}; @@ -78,7 +78,7 @@ pub struct FileResults { /// How long testing took to complete #[serde(rename = "Test Duration")] - pub testing_time: RuffleDuration, + pub testing_time: Duration, /// The compressed length of the SWF file. #[serde(rename = "Compressed Length")] @@ -141,7 +141,7 @@ impl FileResults { name: name.to_string(), hash: vec![], progress: Step::Start, - testing_time: RuffleDuration::zero(), + testing_time: Duration::zero(), compressed_len: None, uncompressed_len: None, error: None, diff --git a/tests/tests/regression_tests.rs b/tests/tests/regression_tests.rs index de81142431f41..a08fe60d505e5 100644 --- a/tests/tests/regression_tests.rs +++ b/tests/tests/regression_tests.rs @@ -10,7 +10,7 @@ use ruffle_core::backend::{ storage::{MemoryStorageBackend, StorageBackend}, }; use ruffle_core::context::UpdateContext; -use ruffle_core::duration::RuffleDuration; +use ruffle_core::duration::Duration; use ruffle_core::events::MouseButton as RuffleMouseButton; use ruffle_core::external::Value as ExternalValue; use ruffle_core::external::{ExternalInterfaceMethod, ExternalInterfaceProvider}; @@ -29,7 +29,7 @@ use std::collections::BTreeMap; use std::path::Path; use std::rc::Rc; use std::sync::{Arc, Mutex}; -use std::time::Duration; +use std::time::Duration as StdDuration; const RUN_IMG_TESTS: bool = cfg!(feature = "imgtests"); @@ -1141,7 +1141,7 @@ fn timeout_avm1() -> Result<(), Error> { player .lock() .unwrap() - .set_max_execution_duration(RuffleDuration::from_secs(5.0)); + .set_max_execution_duration(Duration::from_secs(5.0)); Ok(()) }, |_| Ok(()), @@ -1387,7 +1387,7 @@ fn run_swf( let base_path = Path::new(swf_path).parent().unwrap(); let mut executor = NullExecutor::new(); let movie = SwfMovie::from_path(swf_path, None)?; - let frame_time = RuffleDuration::from_millis(1000.0 / movie.frame_rate().to_f64()); + let frame_time = Duration::from_millis(1000.0 / movie.frame_rate().to_f64()); let trace_output = Rc::new(RefCell::new(Vec::new())); #[allow(unused_mut)] @@ -1421,7 +1421,7 @@ fn run_swf( let player = builder .with_log(TestLogBackend::new(trace_output.clone())) .with_navigator(NullNavigatorBackend::with_base_path(base_path, &executor)) - .with_max_execution_duration(RuffleDuration::from_secs(300.0)) + .with_max_execution_duration(Duration::from_secs(300.0)) .with_viewport_dimensions( movie.width().to_pixels() as u32, movie.height().to_pixels() as u32, @@ -1447,7 +1447,7 @@ fn run_swf( // with timer execution (timers will see an elapsed time of *at least* // the requested timer interval). if frame_time_sleep { - std::thread::sleep(Duration::from_nanos(frame_time.as_nanos() as u64)); + std::thread::sleep(StdDuration::from_nanos(frame_time.as_nanos() as u64)); } while !player diff --git a/web/src/audio.rs b/web/src/audio.rs index a7eed0a8476d8..242beee46d2e3 100644 --- a/web/src/audio.rs +++ b/web/src/audio.rs @@ -3,7 +3,7 @@ use ruffle_core::backend::audio::{ swf, AudioBackend, AudioMixer, AudioMixerProxy, DecodeError, RegisterError, SoundHandle, SoundInstanceHandle, SoundTransform, }; -use ruffle_core::duration::RuffleDuration; +use ruffle_core::duration::Duration; use ruffle_core::impl_audio_mixer_backend; use ruffle_web_common::JsResult; use std::sync::{Arc, RwLock}; @@ -16,7 +16,7 @@ pub struct WebAudioBackend { context: AudioContext, buffers: Vec>>, time: Arc>, - position_resolution: RuffleDuration, + position_resolution: Duration, } impl WebAudioBackend { @@ -30,7 +30,7 @@ impl WebAudioBackend { mixer: AudioMixer::new(2, sample_rate as u32), buffers: Vec::with_capacity(2), time: Arc::new(RwLock::new(0.0)), - position_resolution: RuffleDuration::from_secs( + position_resolution: Duration::from_secs( f64::from(Self::BUFFER_SIZE) / f64::from(sample_rate), ), }; @@ -63,7 +63,7 @@ impl AudioBackend for WebAudioBackend { let _ = self.context.suspend(); } - fn position_resolution(&self) -> Option { + fn position_resolution(&self) -> Option { Some(self.position_resolution) } } diff --git a/web/src/lib.rs b/web/src/lib.rs index 606fee23ad28d..e8f8ee1a11b8a 100644 --- a/web/src/lib.rs +++ b/web/src/lib.rs @@ -9,7 +9,7 @@ use generational_arena::{Arena, Index}; use js_sys::{Array, Function, JsString, Object, Promise, Uint8Array}; use ruffle_core::config::Letterbox; use ruffle_core::context::UpdateContext; -use ruffle_core::duration::RuffleDuration; +use ruffle_core::duration::Duration; use ruffle_core::events::{KeyCode, MouseButton, MouseWheelDelta}; use ruffle_core::external::{ ExternalInterfaceMethod, ExternalInterfaceProvider, Value as ExternalValue, Value, @@ -150,7 +150,7 @@ struct Config { log_level: log::Level, #[serde(rename = "maxExecutionDuration")] - max_execution_duration: RuffleDuration, + max_execution_duration: Duration, } /// Metadata about the playing SWF file to be passed back to JavaScript. @@ -985,7 +985,7 @@ impl Ruffle { }); } - core.tick(RuffleDuration::from_millis(dt)); + core.tick(Duration::from_millis(dt)); // Render if the core signals a new frame, or if we resized. if core.needs_render() || new_dimensions.is_some() { From db26389cf287f5b6baf1951ba879bdf2fc142495 Mon Sep 17 00:00:00 2001 From: higumachan Date: Fri, 2 Sep 2022 19:43:48 +0900 Subject: [PATCH 11/15] remove ordered_float dependencies --- Cargo.lock | 11 ----------- core/Cargo.toml | 1 - core/src/backend/audio.rs | 8 ++++---- core/src/duration.rs | 34 ++++++++++++++++++---------------- core/src/player.rs | 12 ++++++------ core/src/timer.rs | 2 +- scanner/src/file_results.rs | 2 +- 7 files changed, 30 insertions(+), 40 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 8b7d72724a5b9..5141ee1444c86 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2933,16 +2933,6 @@ dependencies = [ "vcpkg", ] -[[package]] -name = "ordered-float" -version = "3.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "96bcbab4bfea7a59c2c0fe47211a1ac4e3e96bea6eb446d704f310bc5c732ae2" -dependencies = [ - "num-traits", - "serde", -] - [[package]] name = "os_str_bytes" version = "6.4.1" @@ -3414,7 +3404,6 @@ dependencies = [ "nellymoser-rs", "num-derive", "num-traits", - "ordered-float", "percent-encoding", "quick-xml", "rand", diff --git a/core/Cargo.toml b/core/Cargo.toml index 378455578c994..ae921119647d2 100644 --- a/core/Cargo.toml +++ b/core/Cargo.toml @@ -46,7 +46,6 @@ enumset = "1.0.12" static_assertions = "1.1.0" rustversion = "1.0.9" bytemuck = "1.12.1" -ordered-float = { version = "3.0.0", features = ["serde"] } [target.'cfg(not(target_family = "wasm"))'.dependencies.futures] version = "0.3.25" diff --git a/core/src/backend/audio.rs b/core/src/backend/audio.rs index 5041b9ce36e84..9f39795076261 100644 --- a/core/src/backend/audio.rs +++ b/core/src/backend/audio.rs @@ -220,7 +220,7 @@ impl AudioBackend for NullAudioBackend { fn stop_all_sounds(&mut self) {} fn get_sound_position(&self, _instance: SoundInstanceHandle) -> Option { - Some(Duration::zero()) + Some(Duration::ZERO) } fn get_sound_duration(&self, sound: SoundHandle) -> Option { if let Some(sound) = self.sounds.get(sound) { @@ -299,7 +299,7 @@ impl<'gc> AudioManager<'gc> { pub const STREAM_SYNC_THRESHOLD: f64 = 1.0 / 60.0; /// The threshold in seconds where an audio stream is considered too out-of-sync and will be stopped. - pub const STREAM_RESTART_THRESHOLD: Duration = Duration::one_sec(); + pub const STREAM_RESTART_THRESHOLD: Duration = Duration::ONE_SECOND; /// The minimum audio sycning threshold in seconds. /// @@ -537,13 +537,13 @@ impl<'gc> AudioManager<'gc> { let instance = &self.sounds[i]; audio.stop_sound(instance.instance); self.sounds.swap_remove(i); - Duration::zero() + Duration::ZERO } else if skew.abs() < sync_threshold { // Slightly out of sync, adjust player speed to compensate. skew } else { // More or less in sync, no adjustment. - Duration::zero() + Duration::ZERO } } diff --git a/core/src/duration.rs b/core/src/duration.rs index fd9a05576e9ae..85256345e0750 100644 --- a/core/src/duration.rs +++ b/core/src/duration.rs @@ -1,14 +1,16 @@ use num_traits::Zero; -use ordered_float::OrderedFloat; use serde::{Deserialize, Serialize}; use std::ops::{Add, AddAssign, Sub, SubAssign}; use std::time::Duration as StdDuration; /// Duration f64 nanosec -#[derive(Debug, Copy, Clone, Ord, PartialOrd, Eq, PartialEq, Default, Serialize, Deserialize)] -pub struct Duration(OrderedFloat); +#[derive(Debug, Copy, Clone, PartialOrd, PartialEq, Default, Serialize, Deserialize)] +pub struct Duration(f64); impl Duration { + pub const ZERO: Self = Self(0.0); + pub const ONE_SECOND: Self = Self(1.0); + pub fn from_secs(secs: f64) -> Self { Self::from_nanos(secs * 1_000_000_000.0) } @@ -22,39 +24,39 @@ impl Duration { } pub const fn from_nanos(nanosecs: f64) -> Self { - Self(OrderedFloat(nanosecs)) + Self(nanosecs) } pub fn as_secs(&self) -> f64 { - self.0.into_inner() / 1_000_000_000.0 + self.0 / 1_000_000_000.0 } pub fn as_millis(self) -> f64 { - self.0.into_inner() / 1_000_000.0 + self.0 / 1_000_000.0 } pub fn as_micros(&self) -> f64 { - self.0.into_inner() / 1_000.0 + self.0 / 1_000.0 } pub fn as_nanos(&self) -> f64 { - self.0.into_inner() + self.0 } - pub fn zero() -> Self { - Self(OrderedFloat::zero()) + pub fn abs(&self) -> Duration { + Self(self.0.abs()) } - pub fn abs(&self) -> Duration { - Self(OrderedFloat(self.0.abs())) + pub fn is_zero(&self) -> bool { + self.0.is_zero() } - pub const fn one_sec() -> Self { - Self(OrderedFloat(1.0)) + pub fn min(&self, other: &Self) -> Self { + Self(self.0.min(other.0)) } - pub fn is_zero(&self) -> bool { - self.0.is_zero() + pub fn max(&self, other: &Self) -> Self { + Self(self.0.max(other.0)) } } diff --git a/core/src/player.rs b/core/src/player.rs index f2c78a006022e..e4b0ffe1e5d4c 100644 --- a/core/src/player.rs +++ b/core/src/player.rs @@ -496,7 +496,7 @@ impl Player { // Sanity: If we had too many frames to tick, just reset the accumulator // to prevent running at turbo speed. if self.frame_accumulator >= frame_time { - self.frame_accumulator = Duration::zero(); + self.frame_accumulator = Duration::ZERO; } // Adjust playback speed for next frame to stay in sync with timeline audio tracks ("stream" sounds). @@ -522,19 +522,19 @@ impl Player { /// This is only an approximation to be used for sleep durations. pub fn time_til_next_frame(&self) -> Duration { let frame_time = Duration::from_millis(1000.0 / self.frame_rate); - let mut dt = if self.frame_accumulator <= Duration::zero() { + let mut dt = if self.frame_accumulator <= Duration::ZERO { frame_time } else if self.frame_accumulator >= frame_time { - Duration::zero() + Duration::ZERO } else { frame_time - self.frame_accumulator }; if let Some(time_til_next_timer) = self.time_til_next_timer { - dt = dt.min(time_til_next_timer) + dt = dt.min(&time_til_next_timer) } - dt = dt.max(Duration::zero()); + dt = dt.max(&Duration::ZERO); dt } @@ -2092,7 +2092,7 @@ impl PlayerBuilder { // Timing frame_rate, frame_phase: Default::default(), - frame_accumulator: Duration::zero(), + frame_accumulator: Duration::ZERO, recent_run_frame_timings: VecDeque::with_capacity(10), start_time: Instant::now(), time_offset: 0, diff --git a/core/src/timer.rs b/core/src/timer.rs index e5f7e8021126d..ce1973dffae29 100644 --- a/core/src/timer.rs +++ b/core/src/timer.rs @@ -175,7 +175,7 @@ impl<'gc> Timers<'gc> { Self { timers: Default::default(), timer_counter: 0, - cur_time: Duration::zero(), + cur_time: Duration::ZERO, } } diff --git a/scanner/src/file_results.rs b/scanner/src/file_results.rs index 4b946133ecbd9..c1e001b6bdb7b 100644 --- a/scanner/src/file_results.rs +++ b/scanner/src/file_results.rs @@ -141,7 +141,7 @@ impl FileResults { name: name.to_string(), hash: vec![], progress: Step::Start, - testing_time: Duration::zero(), + testing_time: Duration::ZERO, compressed_len: None, uncompressed_len: None, error: None, From 7e59e60ef7cb7393bc84368b5274152c3af6632b Mon Sep 17 00:00:00 2001 From: higumachan Date: Sun, 4 Sep 2022 23:55:59 +0900 Subject: [PATCH 12/15] use += --- core/src/timer.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/core/src/timer.rs b/core/src/timer.rs index ce1973dffae29..1e6f598b6281d 100644 --- a/core/src/timer.rs +++ b/core/src/timer.rs @@ -15,7 +15,7 @@ use crate::duration::Duration; use crate::string::AvmString; use gc_arena::Collect; use std::collections::{binary_heap::PeekMut, BinaryHeap}; -use std::ops::{Add, AddAssign, Sub}; +use std::ops::{Add, Sub}; /// Manages the collection of timers. pub struct Timers<'gc> { @@ -35,7 +35,7 @@ impl<'gc> Timers<'gc> { context: &mut UpdateContext<'_, 'gc, '_>, dt: Duration, ) -> Option { - context.timers.cur_time.add_assign(dt); + context.timers.cur_time += dt; let num_timers = context.timers.num_timers(); From 5b2872566152e453bdfa0efbcb1b4c7461426939 Mon Sep 17 00:00:00 2001 From: higumachan Date: Mon, 26 Sep 2022 22:30:55 +0900 Subject: [PATCH 13/15] fix review point --- tests/tests/regression_tests.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/tests/regression_tests.rs b/tests/tests/regression_tests.rs index a08fe60d505e5..ee1f86a974ea3 100644 --- a/tests/tests/regression_tests.rs +++ b/tests/tests/regression_tests.rs @@ -1387,7 +1387,7 @@ fn run_swf( let base_path = Path::new(swf_path).parent().unwrap(); let mut executor = NullExecutor::new(); let movie = SwfMovie::from_path(swf_path, None)?; - let frame_time = Duration::from_millis(1000.0 / movie.frame_rate().to_f64()); + let frame_time = Duration::from_secs(1.0 / movie.frame_rate().to_f64()); let trace_output = Rc::new(RefCell::new(Vec::new())); #[allow(unused_mut)] @@ -1447,7 +1447,7 @@ fn run_swf( // with timer execution (timers will see an elapsed time of *at least* // the requested timer interval). if frame_time_sleep { - std::thread::sleep(StdDuration::from_nanos(frame_time.as_nanos() as u64)); + std::thread::sleep(frame_time.into()); } while !player From a98f3e2eb740f1c723d88e3770c2da526522691a Mon Sep 17 00:00:00 2001 From: David Wendt Date: Tue, 29 Nov 2022 22:44:24 -0500 Subject: [PATCH 14/15] chore: Fix the lockfile and a few source files that got screwed up in the mismerge --- Cargo.lock | 100 ++------------------------------ core/src/backend/audio.rs | 3 +- core/src/backend/audio/mixer.rs | 2 - core/src/limits.rs | 2 +- core/src/loader.rs | 2 +- tests/tests/regression_tests.rs | 1 - web/src/audio.rs | 1 - 7 files changed, 8 insertions(+), 103 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 5141ee1444c86..c2effec50e99b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -31,15 +31,6 @@ dependencies = [ "version_check", ] -[[package]] -name = "aho-corasick" -version = "0.7.20" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cc936419f96fa211c1b9166887b38e5e40b19958e5b895be7c1f93adec7071ac" -dependencies = [ - "memchr", -] - [[package]] name = "aliasable" version = "0.1.3" @@ -450,7 +441,6 @@ dependencies = [ "js-sys", "num-integer", "num-traits", - "time 0.1.45", "wasm-bindgen", "winapi", ] @@ -877,16 +867,6 @@ dependencies = [ "memchr", ] -[[package]] -name = "ctor" -version = "0.1.26" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6d2301688392eb071b0bf1a37be05c469d3cc4dbbd95df672fe28ab021e6a096" -dependencies = [ - "quote", - "syn", -] - [[package]] name = "cty" version = "0.2.2" @@ -1167,12 +1147,6 @@ dependencies = [ "syn", ] -[[package]] -name = "diff" -version = "0.1.13" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "56254986775e3233ffa9c4d7d3faaf6d36a2c09d30b20687e9f88bc8bafc16c8" - [[package]] name = "digest" version = "0.10.6" @@ -1231,8 +1205,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9ea835d29036a4087793836fa931b08837ad5e957da9e23886b29586fb9b6650" [[package]] -name = "either" -version = "1.6.1" +name = "dwrote" +version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "439a1c2ba5611ad3ed731280541d36d2e9c4ac5e7fb818a27b604bdc5a6aa65b" dependencies = [ @@ -1327,10 +1301,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "85cdab6a89accf66733ad5a1693a4dcced6aeff64602b634530dd73c1f3ee9f0" dependencies = [ "humantime", - "is-terminal", "log", - "regex", - "termcolor", ] [[package]] @@ -1758,7 +1729,7 @@ dependencies = [ "cfg-if 1.0.0", "js-sys", "libc", - "wasi 0.11.0+wasi-snapshot-preview1", + "wasi", "wasm-bindgen", ] @@ -2528,7 +2499,7 @@ checksum = "e5d732bc30207a6423068df043e3d02e0735b155ad7ce1a6f76fe2baa5b158de" dependencies = [ "libc", "log", - "wasi 0.11.0+wasi-snapshot-preview1", + "wasi", "windows-sys 0.42.0", ] @@ -2962,15 +2933,6 @@ dependencies = [ "syn", ] -[[package]] -name = "output_vt100" -version = "0.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "628223faebab4e3e40667ee0b2336d34a5b960ff60ea743ddfdbcf7770bcfb66" -dependencies = [ - "winapi", -] - [[package]] name = "pango-sys" version = "0.15.10" @@ -3106,18 +3068,6 @@ version = "0.2.17" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" -[[package]] -name = "pretty_assertions" -version = "1.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a25e9bcb20aa780fd0bb16b72403a9064d6b3f22f026946029acb941a50af755" -dependencies = [ - "ctor", - "diff", - "output_vt100", - "yansi", -] - [[package]] name = "primal-check" version = "0.3.3" @@ -3303,8 +3253,6 @@ version = "1.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e076559ef8e241f2ae3479e36f97bd5741c0330689e217ad51ce2c76808b868a" dependencies = [ - "aho-corasick", - "memchr", "regex-syntax", ] @@ -3932,7 +3880,7 @@ dependencies = [ "num-bigint", "num-traits", "thiserror", - "time 0.3.17", + "time", ] [[package]] @@ -4231,21 +4179,6 @@ dependencies = [ "winapi", ] -[[package]] -name = "tests" -version = "0.1.0" -dependencies = [ - "approx", - "env_logger", - "futures", - "image", - "pretty_assertions", - "regex", - "ruffle_core", - "ruffle_input_format", - "ruffle_render_wgpu", -] - [[package]] name = "thiserror" version = "1.0.37" @@ -4286,17 +4219,6 @@ dependencies = [ "weezl", ] -[[package]] -name = "time" -version = "0.1.45" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1b797afad3f312d1c66a56d11d0316f916356d11bd158fbc6ca6389ff6bf805a" -dependencies = [ - "libc", - "wasi 0.10.0+wasi-snapshot-preview1", - "winapi", -] - [[package]] name = "time" version = "0.3.17" @@ -4549,12 +4471,6 @@ dependencies = [ "winapi-util", ] -[[package]] -name = "wasi" -version = "0.10.0+wasi-snapshot-preview1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1a143597ca7c7793eff794def352d41792a93c481eb1042423ff7ff72ba2c31f" - [[package]] name = "wasi" version = "0.11.0+wasi-snapshot-preview1" @@ -5158,9 +5074,3 @@ checksum = "56c1936c4cc7a1c9ab21a1ebb602eb942ba868cbd44a99cb7cdc5892335e1c85" dependencies = [ "linked-hash-map", ] - -[[package]] -name = "yansi" -version = "0.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09041cd90cf85f7f8b2df60c646f853b7f535ce68f85244eb6731cf89fa498ec" diff --git a/core/src/backend/audio.rs b/core/src/backend/audio.rs index 9f39795076261..c473258e95e0c 100644 --- a/core/src/backend/audio.rs +++ b/core/src/backend/audio.rs @@ -5,7 +5,6 @@ use crate::{ display_object::{self, DisplayObject, MovieClip, TDisplayObject}, }; use downcast_rs::Downcast; -use duration_helper::from_f64_millis; use gc_arena::Collect; use generational_arena::{Arena, Index}; @@ -188,7 +187,7 @@ impl AudioBackend for NullAudioBackend { fn register_mp3(&mut self, _data: &[u8]) -> Result { Ok(self.sounds.insert(NullSound { size: 0, - duration: RuffleDuration::zero(), + duration: Duration::ZERO, format: swf::SoundFormat { compression: swf::AudioCompression::Mp3, sample_rate: 44100, diff --git a/core/src/backend/audio/mixer.rs b/core/src/backend/audio/mixer.rs index 6dac3da1a9115..df411f929a18d 100644 --- a/core/src/backend/audio/mixer.rs +++ b/core/src/backend/audio/mixer.rs @@ -3,11 +3,9 @@ use super::{SoundHandle, SoundInstanceHandle, SoundTransform}; use crate::backend::audio::{DecodeError, RegisterError}; use crate::duration::Duration; use crate::tag_utils::SwfSlice; -use duration_helper::from_f64_millis; use generational_arena::Arena; use std::io::Cursor; use std::sync::{Arc, Mutex, RwLock}; -use crate::duration::RuffleDuration; use swf::AudioCompression; /// Holds the last 2048 output audio frames. Frames can be written to it one by diff --git a/core/src/limits.rs b/core/src/limits.rs index 3eee73c58df1b..e03309d8c139c 100644 --- a/core/src/limits.rs +++ b/core/src/limits.rs @@ -1,5 +1,5 @@ use crate::context::UpdateContext; -use std::time::Duration; +use crate::duration::Duration; /// Indication of how long execution is allowed to take. /// diff --git a/core/src/loader.rs b/core/src/loader.rs index 8036757021af3..3892c8251f614 100644 --- a/core/src/loader.rs +++ b/core/src/loader.rs @@ -18,6 +18,7 @@ use crate::context::{ActionQueue, ActionType, UpdateContext}; use crate::display_object::{ Bitmap, DisplayObject, TDisplayObject, TDisplayObjectContainer, TInteractiveObject, }; +use crate::duration::Duration; use crate::events::ClipEvent; use crate::frame_lifecycle::catchup_display_object_to_frame; use crate::limits::ExecutionLimit; @@ -32,7 +33,6 @@ use ruffle_render::utils::{determine_jpeg_tag_format, JpegTagFormat}; use std::fmt; use std::str::FromStr; use std::sync::{Arc, Mutex, Weak}; -use std::time::Duration; use swf::read::{extract_swz, read_compression_type}; use thiserror::Error; use url::form_urlencoded; diff --git a/tests/tests/regression_tests.rs b/tests/tests/regression_tests.rs index ee1f86a974ea3..78e4ec449b936 100644 --- a/tests/tests/regression_tests.rs +++ b/tests/tests/regression_tests.rs @@ -19,7 +19,6 @@ use ruffle_core::tag_utils::SwfMovie; use ruffle_core::{Player, PlayerBuilder, PlayerEvent, ViewportDimensions}; use ruffle_input_format::{AutomatedEvent, InputInjector, MouseButton as InputMouseButton}; -use ruffle_core::duration::RuffleDuration; #[cfg(feature = "imgtests")] use ruffle_render_wgpu::backend::WgpuRenderBackend; #[cfg(feature = "imgtests")] diff --git a/web/src/audio.rs b/web/src/audio.rs index 242beee46d2e3..9671637e7b6a1 100644 --- a/web/src/audio.rs +++ b/web/src/audio.rs @@ -1,4 +1,3 @@ -use duration_helper::from_f64_millis; use ruffle_core::backend::audio::{ swf, AudioBackend, AudioMixer, AudioMixerProxy, DecodeError, RegisterError, SoundHandle, SoundInstanceHandle, SoundTransform, From 042ee49fcc3ab6e5e4601185ab963ef82ac08e19 Mon Sep 17 00:00:00 2001 From: David Wendt Date: Tue, 29 Nov 2022 22:44:57 -0500 Subject: [PATCH 15/15] core: Fix a handful of types that were added after this PR was originally drafted --- core/src/duration.rs | 1 + core/src/limits.rs | 4 ++-- core/src/loader.rs | 5 ++++- core/src/player.rs | 2 +- 4 files changed, 8 insertions(+), 4 deletions(-) diff --git a/core/src/duration.rs b/core/src/duration.rs index 85256345e0750..364887abe5da4 100644 --- a/core/src/duration.rs +++ b/core/src/duration.rs @@ -10,6 +10,7 @@ pub struct Duration(f64); impl Duration { pub const ZERO: Self = Self(0.0); pub const ONE_SECOND: Self = Self(1.0); + pub const MAX: Self = Self(f64::MAX); pub fn from_secs(secs: f64) -> Self { Self::from_nanos(secs * 1_000_000_000.0) diff --git a/core/src/limits.rs b/core/src/limits.rs index e03309d8c139c..42ec894cc078c 100644 --- a/core/src/limits.rs +++ b/core/src/limits.rs @@ -58,7 +58,7 @@ impl ExecutionLimit { Self { current_oplimit: Some(0), max_ops_per_check: Some(0), - time_limit: Duration::from_secs(0), + time_limit: Duration::from_secs(0.0), } } @@ -80,7 +80,7 @@ impl ExecutionLimit { *oplimit = oplimit.saturating_sub(ops); if *oplimit == 0 { - if context.update_start.elapsed() >= self.time_limit { + if context.update_start.elapsed().as_nanos() as f64 >= self.time_limit.as_nanos() { return true; } diff --git a/core/src/loader.rs b/core/src/loader.rs index 3892c8251f614..5084176192c74 100644 --- a/core/src/loader.rs +++ b/core/src/loader.rs @@ -1417,7 +1417,10 @@ impl<'gc> Loader<'gc> { Loader::preload_tick( handle, uc, - &mut ExecutionLimit::with_max_ops_and_time(10000, Duration::from_millis(1)), + &mut ExecutionLimit::with_max_ops_and_time( + 10000, + Duration::from_millis(1.0), + ), )?; return Ok(()); diff --git a/core/src/player.rs b/core/src/player.rs index e4b0ffe1e5d4c..f1e274c387ef9 100644 --- a/core/src/player.rs +++ b/core/src/player.rs @@ -1408,7 +1408,7 @@ impl Player { } pub fn run_frame(&mut self) { - let frame_time = std::time::Duration::from_nanos((750_000_000.0 / self.frame_rate) as u64); + let frame_time = Duration::from_nanos(750_000_000.0 / self.frame_rate); let (mut execution_limit, may_execute_while_streaming) = match self.load_behavior { LoadBehavior::Streaming => ( ExecutionLimit::with_max_ops_and_time(10000, frame_time),