audio: keep the device running behind the menu instead of stopping it

Opening the menu with the core paused used to stop the audio driver
and closing it started the driver again, unless menu sounds were on,
in which case audio stayed up and the runloop fed the device a frame
of silence per menu frame for the sounds to mix into. That second
model is the only one now. Sound in the menu is ordinary - menu
sounds, the mixer, animated thumbnails with audio - and every one of
those wants a running stream; stopping and starting the device around
the toggle also cost a driver-dependent restart on every menu visit
for nothing, and left the device in a state that is not the one it
plays in.

The menu toggle and CMD_EVENT_MENU_PAUSE_LIBRETRO no longer touch
audio at all; only the microphone is stopped and started. The runloop
feeds silence whenever the core is not running behind the menu,
regardless of the menu-sound setting, so the stream never starves and
rate control keeps its footing across the toggle.

CMD_EVENT_AUDIO_STOP and CMD_EVENT_AUDIO_START lose the gate that
made them consult the menu's pause and sound settings. That gate
existed for the menu toggle, and it also disabled the commands for
callers that mean them: the 3DS sleep and wake hooks stopped stopping
audio whenever pause-on-menu was off.

Closes #12892. The issue asked for the 3DS and Vita to be tested with
the device left running behind the menu; that has not been done here.
This commit is contained in:
libretroadmin committed 2026-08-29 23:24:20 +02:00
1 parent e711b2097a
commit d428b0afca
3 files changed
+28 -79

No files matched your search

+9 -13
View File
@@ -6575,8 +6575,9 @@ void menu_driver_toggle(
* struct is NULL
*/
video_driver_t *current_video = (video_driver_t*)curr_video_data;
#ifdef HAVE_MICROPHONE
bool menu_pause_libretro = false;
bool audio_enable_menu = false;
#endif
runloop_state_t *runloop_st = runloop_state_get_ptr();
struct menu_state *menu_st = &menu_driver_state;
bool runloop_shutdown_initiated = (runloop_st->flags &
@@ -6592,14 +6593,13 @@ void menu_driver_toggle(
if (settings)
{
#ifdef HAVE_MICROPHONE
#ifdef HAVE_NETWORKING
menu_pause_libretro = settings->bools.menu_pause_libretro
&& netplay_driver_ctl(RARCH_NETPLAY_CTL_ALLOW_PAUSE, NULL);
#else
menu_pause_libretro = settings->bools.menu_pause_libretro;
#endif
#ifdef HAVE_AUDIOMIXER
audio_enable_menu = settings->bools.audio_enable_menu;
#endif
#ifdef HAVE_OVERLAY
input_overlay_hide_in_menu = settings->bools.input_overlay_hide_in_menu;
@@ -6670,14 +6670,14 @@ void menu_driver_toggle(
/* Stop all rumbling before entering the menu. */
command_event(CMD_EVENT_RUMBLE_STOP, NULL);
if (menu_pause_libretro)
{
if (!audio_enable_menu)
command_event(CMD_EVENT_AUDIO_STOP, NULL);
/* Audio keeps running behind the menu: the runloop feeds the
* device silence while the core is paused, and menu sounds, the
* mixer and thumbnail video playback all mix into that stream.
* Only the microphone is stopped. */
#ifdef HAVE_MICROPHONE
if (menu_pause_libretro)
command_event(CMD_EVENT_MICROPHONE_STOP, NULL);
#endif
}
/* Override keyboard callback to redirect to menu instead.
* We'll use this later for something ... */
@@ -6702,14 +6702,10 @@ void menu_driver_toggle(
if (!runloop_shutdown_initiated)
driver_set_nonblock_state();
if (menu_pause_libretro)
{
if (!audio_enable_menu)
command_event(CMD_EVENT_AUDIO_START, NULL);
#ifdef HAVE_MICROPHONE
if (menu_pause_libretro)
command_event(CMD_EVENT_MICROPHONE_START, NULL);
#endif
}
/* Restore libretro keyboard callback. */
if (key_event && frontend_key_event)
+11 -53
View File
@@ -4332,53 +4332,17 @@ bool command_event(enum event_command cmd, void *data)
}
#endif
break;
/* Plain stop and start. These used to be gated on the menu's
* pause and menu-sound settings because the menu toggle issued
* them; it no longer does, and the gate also disabled them for
* the callers that mean it, such as the 3DS sleep and wake hooks. */
case CMD_EVENT_AUDIO_STOP:
{
bool menu_pause_libretro = false;
bool audio_enable_menu = false;
#if defined(HAVE_AUDIOMIXER) && defined(HAVE_MENU)
audio_enable_menu = settings->bools.audio_enable_menu
&& menu_st->flags & MENU_ST_FLAG_ALIVE;
#endif
#ifdef HAVE_NETWORKING
menu_pause_libretro = settings->bools.menu_pause_libretro
&& netplay_driver_ctl(RARCH_NETPLAY_CTL_ALLOW_PAUSE, NULL)
&& !netplay_driver_ctl(RARCH_NETPLAY_CTL_USE_CORE_PACKET_INTERFACE, NULL);
#else
menu_pause_libretro = settings->bools.menu_pause_libretro;
#endif
if (audio_enable_menu || !menu_pause_libretro)
return false;
if (!audio_driver_stop())
return false;
}
if (!audio_driver_stop())
return false;
break;
case CMD_EVENT_AUDIO_START:
{
bool menu_pause_libretro = false;
bool audio_enable_menu = false;
#if defined(HAVE_AUDIOMIXER) && defined(HAVE_MENU)
audio_enable_menu = settings->bools.audio_enable_menu
&& menu_st->flags & MENU_ST_FLAG_ALIVE;
#endif
#ifdef HAVE_NETWORKING
menu_pause_libretro = settings->bools.menu_pause_libretro
&& netplay_driver_ctl(RARCH_NETPLAY_CTL_ALLOW_PAUSE, NULL)
&& !netplay_driver_ctl(RARCH_NETPLAY_CTL_USE_CORE_PACKET_INTERFACE, NULL);
#else
menu_pause_libretro = settings->bools.menu_pause_libretro;
#endif
if (audio_enable_menu && !menu_pause_libretro)
return false;
if (!audio_driver_start(runloop_st->flags & RUNLOOP_FLAG_SHUTDOWN_INITIATED))
return false;
}
if (!audio_driver_start(runloop_st->flags & RUNLOOP_FLAG_SHUTDOWN_INITIATED))
return false;
break;
#ifdef HAVE_MICROPHONE
case CMD_EVENT_MICROPHONE_STOP:
@@ -5305,20 +5269,14 @@ bool command_event(enum event_command cmd, void *data)
bool menu_pause_libretro = settings->bools.menu_pause_libretro;
#endif
/* Audio is not stopped or started around the menu any more;
* see the menu toggle. */
#ifdef HAVE_MICROPHONE
if (menu_pause_libretro)
{
command_event(CMD_EVENT_AUDIO_STOP, NULL);
#ifdef HAVE_MICROPHONE
command_event(CMD_EVENT_MICROPHONE_STOP, NULL);
#endif
}
else
{
command_event(CMD_EVENT_AUDIO_START, NULL);
#ifdef HAVE_MICROPHONE
command_event(CMD_EVENT_MICROPHONE_START, NULL);
#endif
}
}
#endif
break;
+8 -13
View File
@@ -6995,19 +6995,14 @@ static enum runloop_state_enum runloop_check_state(
menu->state = 0;
}
/* Pump the menu audio path when menu sounds are enabled, or when a
* mixer stream is active (e.g. animated thumbnail preview audio) --
* the mixer is only advanced by audio_driver_flush(), which in the
* menu is driven from here. Without this, thumbnail audio would be
* silent whenever menu sounds are disabled. */
if ( !libretro_running
#ifdef HAVE_AUDIOMIXER
&& ( settings->bools.audio_enable_menu
|| audio_driver_mixer_get_streams_playing() > 0)
#else
&& settings->bools.audio_enable_menu
#endif
)
/* Feed the audio device one frame of silence while the core is
* not running behind the menu, so the stream never starves or
* stops: the device stays in the same state it is in during
* play, rate control keeps its footing, and menu sounds, the
* mixer and thumbnail video playback mix into this stream
* through audio_driver_flush(), which in the menu is driven only
* from here. */
if (!libretro_running)
audio_driver_menu_sample();
}