diff --git a/audio/audio_driver.c b/audio/audio_driver.c index 38efa39051..255dc092fe 100644 --- a/audio/audio_driver.c +++ b/audio/audio_driver.c @@ -179,6 +179,11 @@ static void *audio_driver_context_audio_data = NULL; static bool audio_suspended = false; +static void audio_mixer_play_stop_sequential_cb( + audio_mixer_sound_t *sound, unsigned reason); +static void audio_mixer_play_stop_cb( + audio_mixer_sound_t *sound, unsigned reason); + enum resampler_quality audio_driver_get_resampler_quality(void) { settings_t *settings = config_get_ptr(); @@ -1077,6 +1082,50 @@ static void audio_mixer_play_stop_cb( } } +static void audio_mixer_play_stop_sequential_cb( + audio_mixer_sound_t *sound, unsigned reason) +{ + int idx = audio_mixer_find_index(sound); + + switch (reason) + { + case AUDIO_MIXER_SOUND_FINISHED: + audio_mixer_destroy(sound); + + if (idx >= 0) + { + unsigned i = (unsigned)idx; + + if (!string_is_empty(audio_mixer_streams[i].name)) + free(audio_mixer_streams[i].name); + + audio_mixer_streams[i].name = NULL; + audio_mixer_streams[i].state = AUDIO_STREAM_STATE_NONE; + audio_mixer_streams[i].volume = 0.0f; + audio_mixer_streams[i].buf = NULL; + audio_mixer_streams[i].stop_cb = NULL; + audio_mixer_streams[i].handle = NULL; + audio_mixer_streams[i].voice = NULL; + + i++; + + for (; i < AUDIO_MIXER_MAX_STREAMS; i++) + { + if (audio_mixer_streams[i].state == AUDIO_STREAM_STATE_STOPPED) + { + audio_driver_mixer_play_stream_sequential(i); + break; + } + } + } + break; + case AUDIO_MIXER_SOUND_STOPPED: + break; + case AUDIO_MIXER_SOUND_REPEATED: + break; + } +} + bool audio_driver_mixer_get_free_stream_slot(unsigned *id) { unsigned i; @@ -1149,10 +1198,15 @@ bool audio_driver_mixer_add_stream(audio_mixer_stream_params_t *params) { case AUDIO_STREAM_STATE_PLAYING_LOOPED: looped = true; - /* fall-through */ + voice = audio_mixer_play(handle, looped, params->volume, stop_cb); + break; case AUDIO_STREAM_STATE_PLAYING: voice = audio_mixer_play(handle, looped, params->volume, stop_cb); break; + case AUDIO_STREAM_STATE_PLAYING_SEQUENTIAL: + stop_cb = audio_mixer_play_stop_sequential_cb; + voice = audio_mixer_play(handle, looped, params->volume, stop_cb); + break; default: break; } @@ -1178,7 +1232,7 @@ enum audio_mixer_state audio_driver_mixer_get_stream_state(unsigned i) return audio_mixer_streams[i].state; } -static void audio_driver_mixer_play_stream_internal(unsigned i, bool looped) +static void audio_driver_mixer_play_stream_internal(unsigned i, unsigned type) { bool set_state = false; @@ -1188,27 +1242,38 @@ static void audio_driver_mixer_play_stream_internal(unsigned i, bool looped) switch (audio_mixer_streams[i].state) { case AUDIO_STREAM_STATE_STOPPED: - audio_mixer_streams[i].voice = audio_mixer_play(audio_mixer_streams[i].handle, looped, 1.0f, audio_mixer_streams[i].stop_cb); + audio_mixer_streams[i].voice = audio_mixer_play(audio_mixer_streams[i].handle, + (type == AUDIO_STREAM_STATE_PLAYING_LOOPED) ? true : false, + 1.0f, audio_mixer_streams[i].stop_cb); set_state = true; break; case AUDIO_STREAM_STATE_PLAYING: case AUDIO_STREAM_STATE_PLAYING_LOOPED: + case AUDIO_STREAM_STATE_PLAYING_SEQUENTIAL: case AUDIO_STREAM_STATE_NONE: break; } if (set_state) - audio_mixer_streams[i].state = looped ? AUDIO_STREAM_STATE_PLAYING_LOOPED : AUDIO_STREAM_STATE_PLAYING; + audio_mixer_streams[i].state = type; } void audio_driver_mixer_play_stream(unsigned i) { - audio_driver_mixer_play_stream_internal(i, false); + audio_mixer_streams[i].stop_cb = audio_mixer_play_stop_cb; + audio_driver_mixer_play_stream_internal(i, AUDIO_STREAM_STATE_PLAYING); } void audio_driver_mixer_play_stream_looped(unsigned i) { - audio_driver_mixer_play_stream_internal(i, true); + audio_mixer_streams[i].stop_cb = audio_mixer_play_stop_cb; + audio_driver_mixer_play_stream_internal(i, AUDIO_STREAM_STATE_PLAYING_LOOPED); +} + +void audio_driver_mixer_play_stream_sequential(unsigned i) +{ + audio_mixer_streams[i].stop_cb = audio_mixer_play_stop_sequential_cb; + audio_driver_mixer_play_stream_internal(i, AUDIO_STREAM_STATE_PLAYING_SEQUENTIAL); } float audio_driver_mixer_get_stream_volume(unsigned i) @@ -1245,6 +1310,7 @@ void audio_driver_mixer_stop_stream(unsigned i) { case AUDIO_STREAM_STATE_PLAYING: case AUDIO_STREAM_STATE_PLAYING_LOOPED: + case AUDIO_STREAM_STATE_PLAYING_SEQUENTIAL: set_state = true; break; case AUDIO_STREAM_STATE_STOPPED: @@ -1274,6 +1340,7 @@ void audio_driver_mixer_remove_stream(unsigned i) { case AUDIO_STREAM_STATE_PLAYING: case AUDIO_STREAM_STATE_PLAYING_LOOPED: + case AUDIO_STREAM_STATE_PLAYING_SEQUENTIAL: audio_driver_mixer_stop_stream(i); destroy = true; break; diff --git a/audio/audio_driver.h b/audio/audio_driver.h index 95efadd41b..bf81dbff11 100644 --- a/audio/audio_driver.h +++ b/audio/audio_driver.h @@ -53,7 +53,8 @@ enum audio_mixer_state AUDIO_STREAM_STATE_NONE = 0, AUDIO_STREAM_STATE_STOPPED, AUDIO_STREAM_STATE_PLAYING, - AUDIO_STREAM_STATE_PLAYING_LOOPED + AUDIO_STREAM_STATE_PLAYING_LOOPED, + AUDIO_STREAM_STATE_PLAYING_SEQUENTIAL }; typedef struct audio_mixer_stream @@ -294,6 +295,8 @@ bool audio_driver_mixer_add_stream(audio_mixer_stream_params_t *params); void audio_driver_mixer_play_stream(unsigned i); +void audio_driver_mixer_play_stream_sequential(unsigned i); + void audio_driver_mixer_play_stream_looped(unsigned i); void audio_driver_mixer_stop_stream(unsigned i); diff --git a/menu/cbs/menu_cbs_ok.c b/menu/cbs/menu_cbs_ok.c index 1ed4abc678..37f64a7166 100644 --- a/menu/cbs/menu_cbs_ok.c +++ b/menu/cbs/menu_cbs_ok.c @@ -1780,6 +1780,7 @@ static int action_ok_mixer_stream_action_play(const char *path, break; case AUDIO_STREAM_STATE_PLAYING: case AUDIO_STREAM_STATE_PLAYING_LOOPED: + case AUDIO_STREAM_STATE_PLAYING_SEQUENTIAL: case AUDIO_STREAM_STATE_NONE: break; } @@ -1799,6 +1800,27 @@ static int action_ok_mixer_stream_action_play_looped(const char *path, break; case AUDIO_STREAM_STATE_PLAYING: case AUDIO_STREAM_STATE_PLAYING_LOOPED: + case AUDIO_STREAM_STATE_PLAYING_SEQUENTIAL: + case AUDIO_STREAM_STATE_NONE: + break; + } + return 0; +} + +static int action_ok_mixer_stream_action_play_sequential(const char *path, + const char *label, unsigned type, size_t idx, size_t entry_idx) +{ + unsigned stream_id = type - MENU_SETTINGS_AUDIO_MIXER_STREAM_ACTIONS_PLAY_SEQUENTIAL_BEGIN; + enum audio_mixer_state state = audio_driver_mixer_get_stream_state(stream_id); + + switch (state) + { + case AUDIO_STREAM_STATE_STOPPED: + audio_driver_mixer_play_stream_sequential(stream_id); + break; + case AUDIO_STREAM_STATE_PLAYING: + case AUDIO_STREAM_STATE_PLAYING_LOOPED: + case AUDIO_STREAM_STATE_PLAYING_SEQUENTIAL: case AUDIO_STREAM_STATE_NONE: break; } @@ -1815,6 +1837,7 @@ static int action_ok_mixer_stream_action_remove(const char *path, { case AUDIO_STREAM_STATE_PLAYING: case AUDIO_STREAM_STATE_PLAYING_LOOPED: + case AUDIO_STREAM_STATE_PLAYING_SEQUENTIAL: case AUDIO_STREAM_STATE_STOPPED: audio_driver_mixer_remove_stream(stream_id); break; @@ -1834,6 +1857,7 @@ static int action_ok_mixer_stream_action_stop(const char *path, { case AUDIO_STREAM_STATE_PLAYING: case AUDIO_STREAM_STATE_PLAYING_LOOPED: + case AUDIO_STREAM_STATE_PLAYING_SEQUENTIAL: audio_driver_mixer_stop_stream(stream_id); break; case AUDIO_STREAM_STATE_STOPPED: @@ -4733,6 +4757,11 @@ static int menu_cbs_init_bind_ok_compare_type(menu_file_list_cbs_t *cbs, { BIND_ACTION_OK(cbs, action_ok_mixer_stream_action_play_looped); } + else if (type >= MENU_SETTINGS_AUDIO_MIXER_STREAM_ACTIONS_PLAY_SEQUENTIAL_BEGIN + && type <= MENU_SETTINGS_AUDIO_MIXER_STREAM_ACTIONS_PLAY_SEQUENTIAL_END) + { + BIND_ACTION_OK(cbs, action_ok_mixer_stream_action_play_sequential); + } else if (type >= MENU_SETTINGS_AUDIO_MIXER_STREAM_ACTIONS_REMOVE_BEGIN && type <= MENU_SETTINGS_AUDIO_MIXER_STREAM_ACTIONS_REMOVE_END) { diff --git a/menu/cbs/menu_cbs_sublabel.c b/menu/cbs/menu_cbs_sublabel.c index 678b833f40..5b12b93593 100644 --- a/menu/cbs/menu_cbs_sublabel.c +++ b/menu/cbs/menu_cbs_sublabel.c @@ -488,6 +488,9 @@ static int action_bind_sublabel_audio_mixer_stream( case AUDIO_STREAM_STATE_PLAYING_LOOPED: strlcpy(msg, "Playing (Looped)", sizeof(msg)); break; + case AUDIO_STREAM_STATE_PLAYING_SEQUENTIAL: + strlcpy(msg, "Playing (Sequential)", sizeof(msg)); + break; } snprintf(s, len, "State : %s | Volume: %.2f dB", msg, diff --git a/menu/menu_displaylist.c b/menu/menu_displaylist.c index 940584e620..f824d1cc34 100644 --- a/menu/menu_displaylist.c +++ b/menu/menu_displaylist.c @@ -4277,19 +4277,21 @@ bool menu_displaylist_ctl(enum menu_displaylist_ctl_state type, void *data) { char lbl_play[128]; char lbl_play_looped[128]; + char lbl_play_sequential[128]; char lbl_remove[128]; char lbl_stop[128]; char lbl_volume[128]; unsigned id = info->type - MENU_SETTINGS_AUDIO_MIXER_STREAM_ACTIONS_BEGIN; lbl_remove[0] = lbl_stop[0] = lbl_play[0] = lbl_play_looped[0] = '\0'; - lbl_volume[0] = '\0'; + lbl_volume[0] = lbl_play_sequential[0] = '\0'; snprintf(lbl_volume, sizeof(lbl_volume), "mixer_stream_%d_action_volume", id); snprintf(lbl_stop, sizeof(lbl_stop), "mixer_stream_%d_action_stop", id); snprintf(lbl_remove, sizeof(lbl_remove), "mixer_stream_%d_action_remove", id); snprintf(lbl_play, sizeof(lbl_play), "mixer_stream_%d_action_play", id); snprintf(lbl_play_looped, sizeof(lbl_play_looped), "mixer_stream_%d_action_play_looped", id); + snprintf(lbl_play_sequential, sizeof(lbl_play_sequential), "mixer_stream_%d_action_play_sequential", id); menu_entries_append_enum(info->list, "Play", @@ -4303,6 +4305,12 @@ bool menu_displaylist_ctl(enum menu_displaylist_ctl_state type, void *data) MSG_UNKNOWN, (MENU_SETTINGS_AUDIO_MIXER_STREAM_ACTIONS_PLAY_LOOPED_BEGIN + id), 0, 0); + menu_entries_append_enum(info->list, + "Play (Sequential)", + lbl_play_sequential, + MSG_UNKNOWN, + (MENU_SETTINGS_AUDIO_MIXER_STREAM_ACTIONS_PLAY_SEQUENTIAL_BEGIN + id), + 0, 0); menu_entries_append_enum(info->list, "Stop", lbl_stop, diff --git a/menu/menu_driver.h b/menu/menu_driver.h index c9286ede6b..86c69d0fcd 100644 --- a/menu/menu_driver.h +++ b/menu/menu_driver.h @@ -201,6 +201,8 @@ enum menu_settings_type MENU_SETTINGS_AUDIO_MIXER_STREAM_ACTIONS_PLAY_END = MENU_SETTINGS_AUDIO_MIXER_STREAM_ACTIONS_PLAY_BEGIN + 7, MENU_SETTINGS_AUDIO_MIXER_STREAM_ACTIONS_PLAY_LOOPED_BEGIN, MENU_SETTINGS_AUDIO_MIXER_STREAM_ACTIONS_PLAY_LOOPED_END = MENU_SETTINGS_AUDIO_MIXER_STREAM_ACTIONS_PLAY_LOOPED_BEGIN + 7, + MENU_SETTINGS_AUDIO_MIXER_STREAM_ACTIONS_PLAY_SEQUENTIAL_BEGIN, + MENU_SETTINGS_AUDIO_MIXER_STREAM_ACTIONS_PLAY_SEQUENTIAL_END = MENU_SETTINGS_AUDIO_MIXER_STREAM_ACTIONS_PLAY_SEQUENTIAL_BEGIN + 7, MENU_SETTINGS_AUDIO_MIXER_STREAM_ACTIONS_VOLUME_BEGIN, MENU_SETTINGS_AUDIO_MIXER_STREAM_ACTIONS_VOLUME_END = MENU_SETTINGS_AUDIO_MIXER_STREAM_ACTIONS_VOLUME_BEGIN + 7, MENU_SETTINGS_BIND_BEGIN,