avm2: Impl `Sound.length`

This also adds duration tracking for `NullAudioBackend`.
This commit is contained in:
David Wendt 2021-08-13 18:14:16 -04:00 committed by kmeisthax
parent e25fb732ea
commit d7f2f782c4
2 changed files with 38 additions and 5 deletions

View File

@ -93,6 +93,21 @@ pub fn url<'gc>(
Ok(Value::Null) Ok(Value::Null)
} }
/// Implements `Sound.length`
pub fn length<'gc>(
activation: &mut Activation<'_, 'gc, '_>,
this: Option<Object<'gc>>,
_args: &[Value<'gc>],
) -> Result<Value<'gc>, 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. /// Construct `Sound`'s class.
pub fn create_class<'gc>(mc: MutationContext<'gc, '_>) -> GcCell<'gc, Class<'gc>> { pub fn create_class<'gc>(mc: MutationContext<'gc, '_>) -> GcCell<'gc, Class<'gc>> {
let class = Class::new( 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), ("isBuffering", Some(is_buffering), None),
("isURLInaccessible", Some(is_buffering), None), ("isURLInaccessible", Some(is_buffering), None),
("url", Some(url), None), ("url", Some(url), None),
("length", Some(length), None),
]; ];
write.define_public_builtin_instance_properties(mc, PUBLIC_INSTANCE_PROPERTIES); write.define_public_builtin_instance_properties(mc, PUBLIC_INSTANCE_PROPERTIES);

View File

@ -113,9 +113,14 @@ pub trait AudioBackend: Downcast {
impl_downcast!(AudioBackend); impl_downcast!(AudioBackend);
struct NullSound {
duration: u32,
size: u32,
}
/// Audio backend that ignores all audio. /// Audio backend that ignores all audio.
pub struct NullAudioBackend { pub struct NullAudioBackend {
sounds: Arena<u32>, sounds: Arena<NullSound>,
} }
impl NullAudioBackend { impl NullAudioBackend {
@ -130,7 +135,15 @@ impl AudioBackend for NullAudioBackend {
fn play(&mut self) {} fn play(&mut self) {}
fn pause(&mut self) {} fn pause(&mut self) {}
fn register_sound(&mut self, sound: &swf::Sound) -> Result<SoundHandle, Error> { fn register_sound(&mut self, sound: &swf::Sound) -> Result<SoundHandle, Error> {
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( fn start_sound(
@ -157,12 +170,16 @@ impl AudioBackend for NullAudioBackend {
fn get_sound_position(&self, _instance: SoundInstanceHandle) -> Option<u32> { fn get_sound_position(&self, _instance: SoundInstanceHandle) -> Option<u32> {
None None
} }
fn get_sound_duration(&self, _sound: SoundHandle) -> Option<u32> { fn get_sound_duration(&self, sound: SoundHandle) -> Option<u32> {
None if let Some(sound) = self.sounds.get(sound) {
Some(sound.duration)
} else {
None
}
} }
fn get_sound_size(&self, sound: SoundHandle) -> Option<u32> { fn get_sound_size(&self, sound: SoundHandle) -> Option<u32> {
if let Some(sound) = self.sounds.get(sound) { if let Some(sound) = self.sounds.get(sound) {
Some(*sound) Some(sound.size)
} else { } else {
None None
} }