From f438e2032f610331b937b6998d646ba662ea1327 Mon Sep 17 00:00:00 2001 From: Mike Welsh Date: Mon, 5 Sep 2022 23:38:07 -0700 Subject: [PATCH] avm1: Add is_streaming flag to Sound `Sound.loadSound` with `isStreaming` of true causes any previously playing audio on the same object to be stopped. --- core/src/avm1/globals/sound.rs | 15 +++++++++++++++ core/src/avm1/object/sound_object.rs | 14 ++++++++++++++ 2 files changed, 29 insertions(+) diff --git a/core/src/avm1/globals/sound.rs b/core/src/avm1/globals/sound.rs index 069526f7f..17b120e2e 100644 --- a/core/src/avm1/globals/sound.rs +++ b/core/src/avm1/globals/sound.rs @@ -86,6 +86,7 @@ fn attach_sound<'gc>( .character_by_export_name(name) { sound_object.set_sound(activation.context.gc_context, Some(*sound)); + sound_object.set_is_streaming(activation.context.gc_context, false); sound_object.set_duration( activation.context.gc_context, activation @@ -251,6 +252,14 @@ fn load_sound<'gc>( .get(1) .unwrap_or(&Value::Undefined) .as_bool(activation.swf_version()); + if is_streaming { + // Streaming MP3s can only have a single active instance. + // (Previous `attachSound` instances will continue to play.) + if let Some(sound_instance) = sound.sound_instance() { + activation.context.stop_sound(sound_instance); + } + } + sound.set_is_streaming(activation.context.gc_context, is_streaming); let future = activation.context.load_manager.load_sound_avm1( activation.context.player.clone(), sound, @@ -384,6 +393,12 @@ pub fn start<'gc>( use swf::{SoundEvent, SoundInfo}; if let Some(sound_object) = this.as_sound_object() { if let Some(sound) = sound_object.sound() { + if sound_object.is_streaming() { + // Streaming MP3s can only have a single active instance. + if let Some(sound_instance) = sound_object.sound_instance() { + activation.context.stop_sound(sound_instance); + } + } let sound_instance = activation.context.start_sound( sound, &SoundInfo { diff --git a/core/src/avm1/object/sound_object.rs b/core/src/avm1/object/sound_object.rs index ee0cb92ec..2e6e1d6b7 100644 --- a/core/src/avm1/object/sound_object.rs +++ b/core/src/avm1/object/sound_object.rs @@ -37,6 +37,11 @@ pub struct SoundObjectData<'gc> { /// Duration of the currently attached sound in milliseconds. duration: Option, + + /// Whether this sound is an external streaming MP3. + /// This will be true if `Sound.loadSound` was called with `isStreaming` of `true`. + /// A streaming sound can only have a single active instance. + is_streaming: bool, } impl fmt::Debug for SoundObject<'_> { @@ -64,6 +69,7 @@ impl<'gc> SoundObject<'gc> { owner: None, position: 0, duration: None, + is_streaming: false, }, )) } @@ -115,6 +121,14 @@ impl<'gc> SoundObject<'gc> { pub fn set_position(self, gc_context: MutationContext<'gc, '_>, position: u32) { self.0.write(gc_context).position = position; } + + pub fn is_streaming(self) -> bool { + self.0.read().is_streaming + } + + pub fn set_is_streaming(self, gc_context: MutationContext<'gc, '_>, is_streaming: bool) { + self.0.write(gc_context).is_streaming = is_streaming; + } } impl<'gc> TObject<'gc> for SoundObject<'gc> {