mirror of
https://github.com/libretro/RetroArch
synced 2025-02-01 09:32:58 +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.
|
* 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 */
|
/* VFS functionality */
|
||||||
|
|
||||||
/* File paths:
|
/* File paths:
|
||||||
@ -2224,6 +2233,30 @@ struct retro_frame_time_callback
|
|||||||
retro_usec_t reference;
|
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.
|
/* 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.
|
* 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 */
|
gfx_display_t dispgfx; /* ptr alignment */
|
||||||
input_keyboard_press_t keyboard_press_cb; /* ptr alignment */
|
input_keyboard_press_t keyboard_press_cb; /* ptr alignment */
|
||||||
struct retro_frame_time_callback runloop_frame_time; /* 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 */
|
retro_input_state_t input_state_callback_original; /* ptr alignment */
|
||||||
struct retro_audio_callback audio_callback; /* ptr alignment */
|
struct retro_audio_callback audio_callback; /* ptr alignment */
|
||||||
retro_keyboard_event_t runloop_key_event; /* 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;
|
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:
|
case RETRO_ENVIRONMENT_GET_RUMBLE_INTERFACE:
|
||||||
{
|
{
|
||||||
struct retro_rumble_interface *iface =
|
struct retro_rumble_interface *iface =
|
||||||
@ -20880,6 +20896,8 @@ static void uninit_libretro_symbols(
|
|||||||
retroarch_deinit_core_options(p_rarch);
|
retroarch_deinit_core_options(p_rarch);
|
||||||
retroarch_system_info_free(p_rarch);
|
retroarch_system_info_free(p_rarch);
|
||||||
retroarch_frame_time_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->camera_driver_active = false;
|
||||||
p_rarch->location_driver_active = false;
|
p_rarch->location_driver_active = false;
|
||||||
|
|
||||||
@ -38049,6 +38067,8 @@ bool rarch_ctl(enum rarch_ctl_state state, void *data)
|
|||||||
#endif
|
#endif
|
||||||
p_rarch->runloop_autosave = false;
|
p_rarch->runloop_autosave = false;
|
||||||
retroarch_frame_time_free(p_rarch);
|
retroarch_frame_time_free(p_rarch);
|
||||||
|
memset(&p_rarch->runloop_audio_buffer_status, 0,
|
||||||
|
sizeof(struct retro_audio_buffer_status_callback));
|
||||||
break;
|
break;
|
||||||
case RARCH_CTL_IS_IDLE:
|
case RARCH_CTL_IS_IDLE:
|
||||||
return p_rarch->runloop_idle;
|
return p_rarch->runloop_idle;
|
||||||
@ -40079,6 +40099,45 @@ int runloop_iterate(void)
|
|||||||
p_rarch->runloop_frame_time.callback(delta);
|
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,
|
switch ((enum runloop_state)runloop_check_state(p_rarch,
|
||||||
settings, current_time))
|
settings, current_time))
|
||||||
{
|
{
|
||||||
|
Loading…
x
Reference in New Issue
Block a user