mirror of
https://github.com/libretro/RetroArch
synced 2025-02-01 00:32:46 +00:00
Merge pull request #11451 from jdgleaver/api-audio-buffer-status
Add API extension for cores to monitor frontend audio buffer occupancy
This commit is contained in:
commit
aa04d3ccdd
@ -1335,6 +1335,15 @@ enum retro_mod
|
||||
* should be considered active.
|
||||
*/
|
||||
|
||||
#define RETRO_ENVIRONMENT_SET_AUDIO_BUFFER_STATUS_CALLBACK 62
|
||||
/* const struct retro_audio_buffer_status_callback * --
|
||||
* Lets the core know the occupancy level of the frontend
|
||||
* audio buffer. Can be used by a core to attempt frame
|
||||
* skipping in order to avoid buffer under-runs.
|
||||
* A core may pass NULL to disable buffer status reporting
|
||||
* in the frontend.
|
||||
*/
|
||||
|
||||
/* VFS functionality */
|
||||
|
||||
/* File paths:
|
||||
@ -2224,6 +2233,30 @@ struct retro_frame_time_callback
|
||||
retro_usec_t reference;
|
||||
};
|
||||
|
||||
/* Notifies a libretro core of the current occupancy
|
||||
* level of the frontend audio buffer.
|
||||
*
|
||||
* - active: 'true' if audio buffer is currently
|
||||
* in use. Will be 'false' if audio is
|
||||
* disabled in the frontend
|
||||
*
|
||||
* - occupancy: Given as a value in the range [0,100],
|
||||
* corresponding to the occupancy percentage
|
||||
* of the audio buffer
|
||||
*
|
||||
* - underrun_likely: 'true' if the frontend expects an
|
||||
* audio buffer underrun during the
|
||||
* next frame (indicates that a core
|
||||
* should attempt frame skipping)
|
||||
*
|
||||
* It will be called right before retro_run() every frame. */
|
||||
typedef void (RETRO_CALLCONV *retro_audio_buffer_status_callback_t)(
|
||||
bool active, unsigned occupancy, bool underrun_likely);
|
||||
struct retro_audio_buffer_status_callback
|
||||
{
|
||||
retro_audio_buffer_status_callback_t callback;
|
||||
};
|
||||
|
||||
/* Pass this to retro_video_refresh_t if rendering to hardware.
|
||||
* Passing NULL to retro_video_refresh_t is still a frame dupe as normal.
|
||||
* */
|
||||
|
59
retroarch.c
59
retroarch.c
@ -2156,6 +2156,7 @@ struct rarch_state
|
||||
gfx_display_t dispgfx; /* ptr alignment */
|
||||
input_keyboard_press_t keyboard_press_cb; /* ptr alignment */
|
||||
struct retro_frame_time_callback runloop_frame_time; /* ptr alignment */
|
||||
struct retro_audio_buffer_status_callback runloop_audio_buffer_status; /* ptr alignment */
|
||||
retro_input_state_t input_state_callback_original; /* ptr alignment */
|
||||
struct retro_audio_callback audio_callback; /* ptr alignment */
|
||||
retro_keyboard_event_t runloop_key_event; /* ptr alignment */
|
||||
@ -19891,6 +19892,21 @@ static bool rarch_environment_cb(unsigned cmd, void *data)
|
||||
break;
|
||||
}
|
||||
|
||||
case RETRO_ENVIRONMENT_SET_AUDIO_BUFFER_STATUS_CALLBACK:
|
||||
{
|
||||
const struct retro_audio_buffer_status_callback *info =
|
||||
(const struct retro_audio_buffer_status_callback*)data;
|
||||
|
||||
RARCH_LOG("[Environ]: SET_AUDIO_BUFFER_STATUS_CALLBACK.\n");
|
||||
|
||||
if (info)
|
||||
p_rarch->runloop_audio_buffer_status.callback = info->callback;
|
||||
else
|
||||
p_rarch->runloop_audio_buffer_status.callback = NULL;
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case RETRO_ENVIRONMENT_GET_RUMBLE_INTERFACE:
|
||||
{
|
||||
struct retro_rumble_interface *iface =
|
||||
@ -20880,6 +20896,8 @@ static void uninit_libretro_symbols(
|
||||
retroarch_deinit_core_options(p_rarch);
|
||||
retroarch_system_info_free(p_rarch);
|
||||
retroarch_frame_time_free(p_rarch);
|
||||
memset(&p_rarch->runloop_audio_buffer_status, 0,
|
||||
sizeof(struct retro_audio_buffer_status_callback));
|
||||
p_rarch->camera_driver_active = false;
|
||||
p_rarch->location_driver_active = false;
|
||||
|
||||
@ -38049,6 +38067,8 @@ bool rarch_ctl(enum rarch_ctl_state state, void *data)
|
||||
#endif
|
||||
p_rarch->runloop_autosave = false;
|
||||
retroarch_frame_time_free(p_rarch);
|
||||
memset(&p_rarch->runloop_audio_buffer_status, 0,
|
||||
sizeof(struct retro_audio_buffer_status_callback));
|
||||
break;
|
||||
case RARCH_CTL_IS_IDLE:
|
||||
return p_rarch->runloop_idle;
|
||||
@ -40079,6 +40099,45 @@ int runloop_iterate(void)
|
||||
p_rarch->runloop_frame_time.callback(delta);
|
||||
}
|
||||
|
||||
/* Update audio buffer occupancy if buffer status
|
||||
* callback is in use by the core */
|
||||
if (p_rarch->runloop_audio_buffer_status.callback)
|
||||
{
|
||||
bool audio_buf_active = false;
|
||||
unsigned audio_buf_occupancy = 0;
|
||||
bool audio_buf_underrun = false;
|
||||
|
||||
if (!(p_rarch->runloop_paused ||
|
||||
!p_rarch->audio_driver_active ||
|
||||
!p_rarch->audio_driver_output_samples_buf) &&
|
||||
p_rarch->current_audio->write_avail &&
|
||||
p_rarch->audio_driver_context_audio_data &&
|
||||
p_rarch->audio_driver_buffer_size)
|
||||
{
|
||||
size_t audio_buf_avail = p_rarch->current_audio->write_avail(
|
||||
p_rarch->audio_driver_context_audio_data);
|
||||
|
||||
audio_buf_avail = (audio_buf_avail > p_rarch->audio_driver_buffer_size) ?
|
||||
p_rarch->audio_driver_buffer_size : audio_buf_avail;
|
||||
|
||||
audio_buf_occupancy = (unsigned)(100 - (audio_buf_avail * 100) /
|
||||
p_rarch->audio_driver_buffer_size);
|
||||
|
||||
/* Elsewhere, we standardise on a 'low water mark'
|
||||
* of 25% of the total audio buffer size - use
|
||||
* the same metric here (can be made more sophisticated
|
||||
* if required - i.e. determine buffer occupancy in
|
||||
* terms of usec, and weigh this against the expected
|
||||
* frame time) */
|
||||
audio_buf_underrun = audio_buf_occupancy < 25;
|
||||
|
||||
audio_buf_active = true;
|
||||
}
|
||||
|
||||
p_rarch->runloop_audio_buffer_status.callback(
|
||||
audio_buf_active, audio_buf_occupancy, audio_buf_underrun);
|
||||
}
|
||||
|
||||
switch ((enum runloop_state)runloop_check_state(p_rarch,
|
||||
settings, current_time))
|
||||
{
|
||||
|
Loading…
x
Reference in New Issue
Block a user