audio: Add AudioBackend::stop_sound

This commit is contained in:
Mike Welsh 2020-01-01 19:33:21 -08:00
parent 63dd92259b
commit d0142f1d67
4 changed files with 65 additions and 11 deletions

View File

@ -11,6 +11,7 @@ pub mod swf {
pub type AudioStreamHandle = Index;
pub type SoundHandle = Index;
pub type SoundInstanceHandle = Index;
type Error = Box<dyn std::error::Error>;
@ -35,7 +36,9 @@ pub trait AudioBackend {
/// Starts playing a sound instance that is not tied to a MovieClip timeline.
/// In Flash, this is known as an "Event" sound.
fn start_sound(&mut self, sound: SoundHandle, settings: &swf::SoundInfo);
fn start_sound(&mut self, sound: SoundHandle, settings: &swf::SoundInfo)
-> SoundInstanceHandle;
fn start_stream(
&mut self,
clip_id: crate::prelude::CharacterId,
@ -44,6 +47,10 @@ pub trait AudioBackend {
handle: &swf::SoundStreamHead,
) -> AudioStreamHandle;
/// Stops a playing sound instance.
/// No-op if the sound is not playing.
fn stop_sound(&mut self, sound: SoundInstanceHandle);
/// Stops a playing stream souund.
/// Should be called whenever a MovieClip timeline stops playing or seeks to a new frame.
fn stop_stream(&mut self, stream: AudioStreamHandle);
@ -100,7 +107,11 @@ impl<T: AudioBackend + ?Sized> AudioBackend for Box<T> {
fn preload_sound_stream_end(&mut self, clip_id: swf::CharacterId) {
self.deref_mut().preload_sound_stream_end(clip_id)
}
fn start_sound(&mut self, sound: SoundHandle, settings: &swf::SoundInfo) {
fn start_sound(
&mut self,
sound: SoundHandle,
settings: &swf::SoundInfo,
) -> SoundInstanceHandle {
self.deref_mut().start_sound(sound, settings)
}
fn start_stream(
@ -114,6 +125,10 @@ impl<T: AudioBackend + ?Sized> AudioBackend for Box<T> {
.start_stream(clip_id, clip_frame, clip_data, handle)
}
fn stop_sound(&mut self, sound: SoundInstanceHandle) {
self.deref_mut().stop_sound(sound)
}
fn stop_stream(&mut self, stream: AudioStreamHandle) {
self.deref_mut().stop_stream(stream)
}
@ -156,7 +171,13 @@ impl AudioBackend for NullAudioBackend {
Ok(self.sounds.insert(()))
}
fn start_sound(&mut self, _sound: SoundHandle, _sound_info: &swf::SoundInfo) {}
fn start_sound(
&mut self,
_sound: SoundHandle,
_sound_info: &swf::SoundInfo,
) -> SoundInstanceHandle {
SoundInstanceHandle::from_raw_parts(0, 0)
}
fn start_stream(
&mut self,
@ -167,6 +188,9 @@ impl AudioBackend for NullAudioBackend {
) -> AudioStreamHandle {
self.streams.insert(())
}
fn stop_sound(&mut self, _sound: SoundInstanceHandle) {}
fn stop_stream(&mut self, stream: AudioStreamHandle) {
self.streams.remove(stream);
}

View File

@ -1684,7 +1684,9 @@ impl<'gc, 'a> MovieClipData<'gc> {
// The sound event type is controlled by the "Sync" setting in the Flash IDE.
match start_sound.sound_info.event {
// "Event" sounds always play, independent of the timeline.
SoundEvent::Event => context.audio.start_sound(handle, &start_sound.sound_info),
SoundEvent::Event => {
context.audio.start_sound(handle, &start_sound.sound_info);
}
// "Start" sounds only play if an instance of the same sound is not already playing.
SoundEvent::Start => {

View File

@ -3,7 +3,9 @@ use generational_arena::Arena;
use ruffle_core::backend::audio::decoders::{
self, AdpcmDecoder, Mp3Decoder, PcmDecoder, SeekableDecoder,
};
use ruffle_core::backend::audio::{swf, AudioBackend, AudioStreamHandle, SoundHandle};
use ruffle_core::backend::audio::{
swf, AudioBackend, AudioStreamHandle, SoundHandle, SoundInstanceHandle,
};
use ruffle_core::tag_utils::SwfSlice;
use std::io::Cursor;
use std::sync::{Arc, Mutex};
@ -351,7 +353,11 @@ impl AudioBackend for CpalAudioBackend {
sound_instances.remove(stream);
}
fn start_sound(&mut self, sound_handle: SoundHandle, settings: &swf::SoundInfo) {
fn start_sound(
&mut self,
sound_handle: SoundHandle,
settings: &swf::SoundInfo,
) -> SoundInstanceHandle {
let sound = &self.sounds[sound_handle];
let data = Cursor::new(VecAsRef(Arc::clone(&sound.data)));
// Create a signal that decodes and resamples the sound.
@ -375,7 +381,12 @@ impl AudioBackend for CpalAudioBackend {
clip_id: None,
signal,
active: true,
});
})
}
fn stop_sound(&mut self, sound: SoundInstanceHandle) {
let mut sound_instances = self.sound_instances.lock().unwrap();
sound_instances.remove(sound);
}
fn stop_all_sounds(&mut self) {

View File

@ -3,7 +3,9 @@ use fnv::FnvHashMap;
use generational_arena::Arena;
use ruffle_core::backend::audio::decoders::{AdpcmDecoder, Mp3Decoder};
use ruffle_core::backend::audio::swf::{self, AudioCompression};
use ruffle_core::backend::audio::{AudioBackend, AudioStreamHandle, SoundHandle};
use ruffle_core::backend::audio::{
AudioBackend, AudioStreamHandle, SoundHandle, SoundInstanceHandle,
};
use std::cell::{Cell, RefCell};
use std::rc::Rc;
use wasm_bindgen::{closure::Closure, prelude::*, JsCast};
@ -129,7 +131,7 @@ impl WebAudioBackend {
&mut self,
handle: SoundHandle,
settings: Option<&swf::SoundInfo>,
) -> SoundHandle {
) -> SoundInstanceHandle {
let sound = self.sounds.get(handle).unwrap();
match &sound.source {
SoundSource::AudioBuffer(audio_buffer) => {
@ -640,8 +642,12 @@ impl AudioBackend for WebAudioBackend {
}
}
fn start_sound(&mut self, sound: SoundHandle, sound_info: &swf::SoundInfo) {
self.start_sound_internal(sound, Some(sound_info));
fn start_sound(
&mut self,
sound: SoundHandle,
sound_info: &swf::SoundInfo,
) -> SoundInstanceHandle {
self.start_sound_internal(sound, Some(sound_info))
}
fn start_stream(
@ -691,6 +697,17 @@ impl AudioBackend for WebAudioBackend {
}
}
fn stop_sound(&mut self, sound: SoundInstanceHandle) {
SOUND_INSTANCES.with(|instances| {
let mut instances = instances.borrow_mut();
if let Some(mut instance) = instances.remove(sound) {
if let SoundInstanceType::AudioBuffer(ref mut node) = instance.instance_type {
let _ = node.disconnect();
}
}
})
}
fn stop_stream(&mut self, stream: AudioStreamHandle) {
SOUND_INSTANCES.with(|instances| {
let mut instances = instances.borrow_mut();