From 4e359318c4d6ec8167adbb4bdf91d8956f99bafc Mon Sep 17 00:00:00 2001 From: Mahyar Koshkouei Date: Mon, 12 Feb 2018 22:35:56 +0000 Subject: [PATCH] Use audio callback The libretro frontend now controls audio, and can now therefore pause the video and audio. This requires a modified version of libmpv which is not currently upstream: https://github.com/deltabeard/mpv/commit/789aa4528e30003d0691c4d8697348d23b55bfa0 Not that all audio is currently converted to 48000Hz. Squashed commit of the following: commit ef16a4045e36cb9acd87ef2632d57f7380494781 Author: Mahyar Koshkouei Date: Mon Feb 12 22:29:52 2018 +0000 Working audio-cb Audio currently resampled to 48kHz. Signed-off-by: Mahyar Koshkouei commit 0b430219b8cae47af4f0f32611f888d51c3393b1 Author: Mahyar Koshkouei Date: Mon Feb 12 19:23:38 2018 +0000 Minor audio-cb changes for testing Signed-off-by: Mahyar Koshkouei commit 65a2ebe354066839bd8e27584684c901709a1c2b Author: Mahyar Koshkouei Date: Mon Feb 12 16:51:53 2018 +0000 WIP: use mpv audio-cb output Audio quality and timing is poor. Signed-off-by: Mahyar Koshkouei commit ce22b385461c087217542b2a4c1e0f01ea530164 Author: Mahyar Koshkouei Date: Mon Feb 12 10:22:53 2018 +0000 Remove spaces Signed-off-by: Mahyar Koshkouei Signed-off-by: Mahyar Koshkouei --- libretro.h | 1 + mpv-libretro.c | 78 ++++++++++++++++++++++++++++++++++++++------------ 2 files changed, 60 insertions(+), 19 deletions(-) diff --git a/libretro.h b/libretro.h index 7148f47..9c99c29 100644 --- a/libretro.h +++ b/libretro.h @@ -2222,6 +2222,7 @@ typedef void (RETRO_CALLCONV *retro_audio_sample_t)(int16_t left, int16_t right) * One frame is defined as a sample of left and right channels, interleaved. * I.e. int16_t buf[4] = { l, r, l, r }; would be 2 frames. * Only one of the audio callbacks must ever be used. + * Limited to a maximum of 1024 samples. */ typedef size_t (RETRO_CALLCONV *retro_audio_sample_batch_t)(const int16_t *data, size_t frames); diff --git a/mpv-libretro.c b/mpv-libretro.c index 1f7a9a9..26076b5 100644 --- a/mpv-libretro.c +++ b/mpv-libretro.c @@ -1,16 +1,16 @@ /* mpv media player libretro core * Copyright (C) 2018 Mahyar Koshkouei - * + * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. - * + * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - * + * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ @@ -56,6 +56,13 @@ static int64_t *playback_time = 0; /* filepath required globaly as mpv is reopened on context change */ static char *filepath = NULL; +static volatile int frame_queue = 0; + +void queue_new_frame(void *cb_ctx) +{ + frame_queue++; +} + static void fallback_log(enum retro_log_level level, const char *fmt, ...) { (void)level; @@ -193,7 +200,7 @@ void retro_get_system_info(struct retro_system_info *info) void retro_get_system_av_info(struct retro_system_av_info *info) { - float sampling_rate = 48000.0f; + float sampling_rate = 44100.0f; struct retro_variable var = { .key = "test_aspect" }; environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var); @@ -294,6 +301,10 @@ static void context_reset(void) goto err; } + mpv_opengl_cb_set_update_callback(mpv_gl, queue_new_frame, NULL); + + mpv_set_option_string(mpv, "ao", "audio-cb"); + if(mpv_set_option_string(mpv, "hwdec", "auto") < 0) log_cb(RETRO_LOG_ERROR, "failed to set hwdec option\n"); @@ -317,6 +328,11 @@ static void context_reset(void) usleep(10); } + /* TODO #2: Check for the highest samplerate in audio stream, and use that. + * Fall back to 48kHz otherwise. + */ + mpv_set_option_string(mpv, "audio-samplerate", "48000"); + log_cb(RETRO_LOG_INFO, "Context reset.\n"); return; @@ -381,20 +397,25 @@ void retro_reset(void) return; } -#if 0 static void audio_callback(void) { - static unsigned phase; + /* Obtain len samples to reduce lag. */ + int len = 2*1024; + static int16_t frames[512]; - for (unsigned i = 0; i < 30000 / 60; i++, phase++) + while(len > 0) { - int16_t val = 0x800 * sinf(2.0f * M_PI * phase * 300.0f / 30000.0f); - audio_cb(val, val); - } + int mpv_len = mpv_audio_callback(&frames, len > 512 ? 512*2 : len*2); + //printf("mpv cb: %d\n", mpv_len); + if(mpv_len < 1) + return; - phase %= 100; + len -= mpv_len; + + //printf("acb: %lu\n", audio_batch_cb(frames, mpv_len)); + audio_batch_cb(frames, mpv_len); + } } -#endif static void retropad_update_input(void) { @@ -414,7 +435,7 @@ static void retropad_update_input(void) /* A ternary operator is used since input_state_cb returns an int16_t, but * we only care about whether the button is on or off which is why we store * the value in a single bit for each button. - * + * * Unsure if saving the memory is worth the extra checks, costing CPU time, * but both are incredibly miniscule anyway. */ @@ -471,7 +492,7 @@ void retro_run(void) * retro_get_system_av_info() call. */ static bool updated_video_dimensions = false; - static int64_t width, height; + static int64_t width = 0, height = 0; if(updated_video_dimensions == false) { @@ -493,18 +514,37 @@ void retro_run(void) .aspect_ratio = -1, }; - environ_cb(RETRO_ENVIRONMENT_SET_SYSTEM_AV_INFO, &geometry); + struct retro_system_timing timing = { + .fps = 60.0f, + .sample_rate = 48000.0f, + }; + + struct retro_system_av_info av_info = { + .geometry = geometry, + .timing = timing, + }; + + if(width > 0 && height > 0) + environ_cb(RETRO_ENVIRONMENT_SET_SYSTEM_AV_INFO, &av_info); + updated_video_dimensions = true; } print_mpv_logs(); retropad_update_input(); - /* TODO #2: Implement an audio callback feature in to libmpv */ - /* audio_callback(); */ - mpv_opengl_cb_draw(mpv_gl, hw_render.get_current_framebuffer(), width, height); - video_cb(RETRO_HW_FRAME_BUFFER_VALID, width, height, 0); + if(frame_queue > 0) + { + mpv_opengl_cb_draw(mpv_gl, hw_render.get_current_framebuffer(), width, height); + video_cb(RETRO_HW_FRAME_BUFFER_VALID, width, height, 0); + frame_queue--; + } + else + video_cb(NULL, width, height, 0); + + /* TODO #2: Implement an audio callback feature in to libmpv */ + audio_callback(); return; }