diff --git a/core/src/avm2/globals/flash/media/sound.rs b/core/src/avm2/globals/flash/media/sound.rs index 2a64c57ca..cbec5ec61 100644 --- a/core/src/avm2/globals/flash/media/sound.rs +++ b/core/src/avm2/globals/flash/media/sound.rs @@ -93,6 +93,21 @@ pub fn url<'gc>( Ok(Value::Null) } +/// Implements `Sound.length` +pub fn length<'gc>( + activation: &mut Activation<'_, 'gc, '_>, + this: Option>, + _args: &[Value<'gc>], +) -> Result, Error> { + 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()); + } + } + + Ok(Value::Undefined) +} + /// Construct `Sound`'s class. pub fn create_class<'gc>(mc: MutationContext<'gc, '_>) -> GcCell<'gc, Class<'gc>> { let class = Class::new( @@ -118,6 +133,7 @@ pub fn create_class<'gc>(mc: MutationContext<'gc, '_>) -> GcCell<'gc, Class<'gc> ("isBuffering", Some(is_buffering), None), ("isURLInaccessible", Some(is_buffering), None), ("url", Some(url), None), + ("length", Some(length), None), ]; write.define_public_builtin_instance_properties(mc, PUBLIC_INSTANCE_PROPERTIES); diff --git a/core/src/backend/audio.rs b/core/src/backend/audio.rs index fa1036964..a559604c5 100644 --- a/core/src/backend/audio.rs +++ b/core/src/backend/audio.rs @@ -113,9 +113,14 @@ pub trait AudioBackend: Downcast { impl_downcast!(AudioBackend); +struct NullSound { + duration: u32, + size: u32, +} + /// Audio backend that ignores all audio. pub struct NullAudioBackend { - sounds: Arena, + sounds: Arena, } impl NullAudioBackend { @@ -130,7 +135,15 @@ impl AudioBackend for NullAudioBackend { fn play(&mut self) {} fn pause(&mut self) {} fn register_sound(&mut self, sound: &swf::Sound) -> Result { - Ok(self.sounds.insert(sound.data.len() as u32)) + // 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 ms = (num_sample_frames * 1000.0 / sample_rate).round(); + + Ok(self.sounds.insert(NullSound { + duration: ms as u32, + size: sound.data.len() as u32, + })) } fn start_sound( @@ -157,12 +170,16 @@ impl AudioBackend for NullAudioBackend { fn get_sound_position(&self, _instance: SoundInstanceHandle) -> Option { None } - fn get_sound_duration(&self, _sound: SoundHandle) -> Option { - None + fn get_sound_duration(&self, sound: SoundHandle) -> Option { + if let Some(sound) = self.sounds.get(sound) { + Some(sound.duration) + } else { + None + } } fn get_sound_size(&self, sound: SoundHandle) -> Option { if let Some(sound) = self.sounds.get(sound) { - Some(*sound) + Some(sound.size) } else { None }