NiklasEi/bevy_kira_audio

Stopping a Queued instance

chungwong opened this issue · 0 comments

Currently a Quened instance handle cannot be stopped.

This is an example of the scenario using the main branch with commit [63d4f82] instead of v0.10.

trait Channel = Sync + Send + Resource;

pub(crate) struct ChannelState<T> {
    pub(crate) handle: Option<Handle<AudioSource>>,
    pub(crate) instance_handle: Option<InstanceHandle>,
    _marker: PhantomData<T>,
}

impl<T> Default for ChannelState<T> {
    fn default() -> Self {
        Self {
            handle: None,
            instance_handle: None,
            _marker: PhantomData,
        }
    }
}

#[derive(Component, Debug, Default, Clone)]
pub(crate) struct MusicChannel;

pub struct AudioPlugin;

impl Plugin for AudioPlugin {
    fn build(&self, app: &mut App) {
        app.add_plugin(KiraAudioPlugin)
            .insert_resource(ChannelState::<MusicChannel>::default())
            .add_audio_channel::<MusicChannel>()
            .add_enter_system(GameState::MainMenu, play_menu_music)
            .add_enter_system(GameState::InGame, play_game_music)
            .add_system(play_channel::<MusicChannel>)
            .add_system(print_status::<MusicChannel>)
            ;
    }
}

fn print_status<T: Channel>(
    audio: Res<AudioChannel<T>>,
    channel_state: Res<ChannelState<T>>,
    ) {
    if let Some(instance_handle) = &channel_state.instance_handle {
        let state = audio.state(instance_handle.clone());
        println!("Loop audio {:?} {:?}", state, instance_handle);
    }
}

#[allow(clippy::only_used_in_recursion)]
fn play_menu_music(
    mut channel_state: ResMut<ChannelState<MusicChannel>>,
    asset_server: Res<AssetServer>,
    audio: Res<AudioChannel<MusicChannel>>,
) {
    dbg!("play main menu music");
    channel_state.handle = Some(asset_server.load("music/TownTheme.mp3"));
}

#[allow(clippy::only_used_in_recursion)]
fn play_game_music(
    mut channel_state: ResMut<ChannelState<MusicChannel>>,
    asset_server: Res<AssetServer>,
    audio: Res<AudioChannel<MusicChannel>>,
) {
    audio.stop();
    dbg!("play another music");
}

fn play_channel<T: Channel>(
    mut channel_state: ResMut<ChannelState<T>>,
    audio: Res<AudioChannel<T>>,
) {
    if let ChannelState {
        handle: Some(handle),
        ..
    } = &*channel_state
    {
        channel_state.instance_handle = Some(audio.play(handle.clone()));
        channel_state.handle = None;
    }
}
  1. At first, MusicChannel is added.
  2. At game state MainMenu, play_menu_music is to load the mp3 file, it took seconds to load it and it is in the state of Queued
  3. While the instance is still Queued, the game state changed to InGame and there is a new music to be played by play_game_music.
  4. Even though audio.stop() is issued, the instance won't be stopped.
  5. Once the instance is ready, it will play in InGame.

So although there is audio.stop() when the channel is switched over to the new one, now both MainMenu music and the InGame music play together.