diff --git a/Makefile.common b/Makefile.common index f48484a7ae..fc4548ca24 100644 --- a/Makefile.common +++ b/Makefile.common @@ -97,6 +97,7 @@ OBJ += frontend/frontend.o \ file_ops.o \ libretro-sdk/file/file_path.o \ hash.o \ + audio_driver.o \ driver.o \ settings.o \ settings_list.o \ diff --git a/audio_driver.c b/audio_driver.c new file mode 100644 index 0000000000..30ef88cf48 --- /dev/null +++ b/audio_driver.c @@ -0,0 +1,383 @@ +/* RetroArch - A frontend for libretro. + * Copyright (C) 2010-2014 - Hans-Kristian Arntzen + * Copyright (C) 2011-2015 - Daniel De Matteis + * + * RetroArch 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 Found- + * ation, either version 3 of the License, or (at your option) any later version. + * + * RetroArch 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 RetroArch. + * If not, see . + */ + +#include +#include +#include "audio_driver.h" +#include "audio/utils.h" +#include "audio/audio_thread_wrapper.h" +#include "driver.h" +#include "general.h" +#include "retroarch.h" + +static const audio_driver_t *audio_drivers[] = { +#ifdef HAVE_ALSA + &audio_alsa, +#ifndef __QNX__ + &audio_alsathread, +#endif +#endif +#if defined(HAVE_OSS) || defined(HAVE_OSS_BSD) + &audio_oss, +#endif +#ifdef HAVE_RSOUND + &audio_rsound, +#endif +#ifdef HAVE_COREAUDIO + &audio_coreaudio, +#endif +#ifdef HAVE_AL + &audio_openal, +#endif +#ifdef HAVE_SL + &audio_opensl, +#endif +#ifdef HAVE_ROAR + &audio_roar, +#endif +#ifdef HAVE_JACK + &audio_jack, +#endif +#if defined(HAVE_SDL) || defined(HAVE_SDL2) + &audio_sdl, +#endif +#ifdef HAVE_XAUDIO + &audio_xa, +#endif +#ifdef HAVE_DSOUND + &audio_dsound, +#endif +#ifdef HAVE_PULSE + &audio_pulse, +#endif +#ifdef __CELLOS_LV2__ + &audio_ps3, +#endif +#ifdef XENON + &audio_xenon360, +#endif +#ifdef GEKKO + &audio_gx, +#endif +#ifdef EMSCRIPTEN + &audio_rwebaudio, +#endif +#ifdef PSP + &audio_psp1, +#endif + &audio_null, + NULL, +}; + +/** + * compute_audio_buffer_statistics: + * + * Computes audio buffer statistics. + * + **/ +static void compute_audio_buffer_statistics(void) +{ + unsigned i, low_water_size, high_water_size, avg, stddev; + float avg_filled, deviation; + uint64_t accum = 0, accum_var = 0; + unsigned low_water_count = 0, high_water_count = 0; + unsigned samples = min(g_extern.measure_data.buffer_free_samples_count, + AUDIO_BUFFER_FREE_SAMPLES_COUNT); + + if (samples < 3) + return; + + for (i = 1; i < samples; i++) + accum += g_extern.measure_data.buffer_free_samples[i]; + + avg = accum / (samples - 1); + + for (i = 1; i < samples; i++) + { + int diff = avg - g_extern.measure_data.buffer_free_samples[i]; + accum_var += diff * diff; + } + + stddev = (unsigned)sqrt((double)accum_var / (samples - 2)); + avg_filled = 1.0f - (float)avg / g_extern.audio_data.driver_buffer_size; + deviation = (float)stddev / g_extern.audio_data.driver_buffer_size; + + low_water_size = g_extern.audio_data.driver_buffer_size * 3 / 4; + high_water_size = g_extern.audio_data.driver_buffer_size / 4; + + for (i = 1; i < samples; i++) + { + if (g_extern.measure_data.buffer_free_samples[i] >= low_water_size) + low_water_count++; + else if (g_extern.measure_data.buffer_free_samples[i] <= high_water_size) + high_water_count++; + } + + RARCH_LOG("Average audio buffer saturation: %.2f %%, standard deviation (percentage points): %.2f %%.\n", + avg_filled * 100.0, deviation * 100.0); + RARCH_LOG("Amount of time spent close to underrun: %.2f %%. Close to blocking: %.2f %%.\n", + (100.0 * low_water_count) / (samples - 1), + (100.0 * high_water_count) / (samples - 1)); +} + +/** + * audio_driver_find_handle: + * @index : index of driver to get handle to. + * + * Returns: handle to audio driver at index. Can be NULL + * if nothing found. + **/ +const void *audio_driver_find_handle(int index) +{ + const void *drv = audio_drivers[index]; + if (!drv) + return NULL; + return drv; +} + +/** + * audio_driver_find_ident: + * @index : index of driver to get handle to. + * + * Returns: Human-readable identifier of audio driver at index. Can be NULL + * if nothing found. + **/ +const char *audio_driver_find_ident(int index) +{ + const audio_driver_t *drv = audio_drivers[index]; + if (!drv) + return NULL; + return drv->ident; +} + +/** + * config_get_audio_driver_options: + * + * Get an enumerated list of all audio driver names, separated by '|'. + * + * Returns: string listing of all audio driver names, separated by '|'. + **/ +const char* config_get_audio_driver_options(void) +{ + union string_list_elem_attr attr; + unsigned i; + char *options = NULL; + int options_len = 0; + struct string_list *options_l = string_list_new(); + + attr.i = 0; + + for (i = 0; audio_driver_find_handle(i); i++) + { + const char *opt = audio_driver_find_ident(i); + options_len += strlen(opt) + 1; + string_list_append(options_l, opt, attr); + } + + options = (char*)calloc(options_len, sizeof(char)); + + string_list_join_concat(options, options_len, options_l, "|"); + + string_list_free(options_l); + options_l = NULL; + + return options; +} + +void find_audio_driver(void) +{ + int i = find_driver_index("audio_driver", g_settings.audio.driver); + if (i >= 0) + driver.audio = audio_driver_find_handle(i); + else + { + unsigned d; + RARCH_ERR("Couldn't find any audio driver named \"%s\"\n", + g_settings.audio.driver); + RARCH_LOG_OUTPUT("Available audio drivers are:\n"); + for (d = 0; audio_driver_find_handle(d); d++) + RARCH_LOG_OUTPUT("\t%s\n", audio_driver_find_ident(d)); + RARCH_WARN("Going to default to first audio driver...\n"); + + driver.audio = audio_driver_find_handle(0); + + if (!driver.audio) + rarch_fail(1, "find_audio_driver()"); + } +} + +void uninit_audio(void) +{ + if (driver.audio_data && driver.audio) + driver.audio->free(driver.audio_data); + + free(g_extern.audio_data.conv_outsamples); + g_extern.audio_data.conv_outsamples = NULL; + g_extern.audio_data.data_ptr = 0; + + free(g_extern.audio_data.rewind_buf); + g_extern.audio_data.rewind_buf = NULL; + + if (!g_settings.audio.enable) + { + driver.audio_active = false; + return; + } + + rarch_resampler_freep(&driver.resampler, + &driver.resampler_data); + + free(g_extern.audio_data.data); + g_extern.audio_data.data = NULL; + + free(g_extern.audio_data.outsamples); + g_extern.audio_data.outsamples = NULL; + + rarch_main_command(RARCH_CMD_DSP_FILTER_DEINIT); + + compute_audio_buffer_statistics(); +} + +void init_audio(void) +{ + size_t outsamples_max, max_bufsamples = AUDIO_CHUNK_SIZE_NONBLOCKING * 2; + + audio_convert_init_simd(); + + /* Resource leaks will follow if audio is initialized twice. */ + if (driver.audio_data) + return; + + /* Accomodate rewind since at some point we might have two full buffers. */ + outsamples_max = max_bufsamples * AUDIO_MAX_RATIO * + g_settings.slowmotion_ratio; + + /* Used for recording even if audio isn't enabled. */ + rarch_assert(g_extern.audio_data.conv_outsamples = + (int16_t*)malloc(outsamples_max * sizeof(int16_t))); + + g_extern.audio_data.block_chunk_size = AUDIO_CHUNK_SIZE_BLOCKING; + g_extern.audio_data.nonblock_chunk_size = AUDIO_CHUNK_SIZE_NONBLOCKING; + g_extern.audio_data.chunk_size = + g_extern.audio_data.block_chunk_size; + + /* Needs to be able to hold full content of a full max_bufsamples + * in addition to its own. */ + rarch_assert(g_extern.audio_data.rewind_buf = (int16_t*) + malloc(max_bufsamples * sizeof(int16_t))); + g_extern.audio_data.rewind_size = max_bufsamples; + + if (!g_settings.audio.enable) + { + driver.audio_active = false; + return; + } + + find_audio_driver(); +#ifdef HAVE_THREADS + if (g_extern.system.audio_callback.callback) + { + RARCH_LOG("Starting threaded audio driver ...\n"); + if (!rarch_threaded_audio_init(&driver.audio, &driver.audio_data, + *g_settings.audio.device ? g_settings.audio.device : NULL, + g_settings.audio.out_rate, g_settings.audio.latency, + driver.audio)) + { + RARCH_ERR("Cannot open threaded audio driver ... Exiting ...\n"); + rarch_fail(1, "init_audio()"); + } + } + else +#endif + { + driver.audio_data = driver.audio->init(*g_settings.audio.device ? + g_settings.audio.device : NULL, + g_settings.audio.out_rate, g_settings.audio.latency); + } + + if (!driver.audio_data) + { + RARCH_ERR("Failed to initialize audio driver. Will continue without audio.\n"); + driver.audio_active = false; + } + + g_extern.audio_data.use_float = false; + if (driver.audio_active && driver.audio->use_float(driver.audio_data)) + g_extern.audio_data.use_float = true; + + if (!g_settings.audio.sync && driver.audio_active) + { + rarch_main_command(RARCH_CMD_AUDIO_SET_NONBLOCKING_STATE); + g_extern.audio_data.chunk_size = + g_extern.audio_data.nonblock_chunk_size; + } + + if (g_extern.audio_data.in_rate <= 0.0f) + { + /* Should never happen. */ + RARCH_WARN("Input rate is invalid (%.3f Hz). Using output rate (%u Hz).\n", + g_extern.audio_data.in_rate, g_settings.audio.out_rate); + g_extern.audio_data.in_rate = g_settings.audio.out_rate; + } + + g_extern.audio_data.orig_src_ratio = + g_extern.audio_data.src_ratio = + (double)g_settings.audio.out_rate / g_extern.audio_data.in_rate; + + if (!rarch_resampler_realloc(&driver.resampler_data, + &driver.resampler, + g_settings.audio.resampler, g_extern.audio_data.orig_src_ratio)) + { + RARCH_ERR("Failed to initialize resampler \"%s\".\n", + g_settings.audio.resampler); + driver.audio_active = false; + } + + rarch_assert(g_extern.audio_data.data = (float*) + malloc(max_bufsamples * sizeof(float))); + + g_extern.audio_data.data_ptr = 0; + + rarch_assert(g_settings.audio.out_rate < + g_extern.audio_data.in_rate * AUDIO_MAX_RATIO); + rarch_assert(g_extern.audio_data.outsamples = (float*) + malloc(outsamples_max * sizeof(float))); + + g_extern.audio_data.rate_control = false; + if (!g_extern.system.audio_callback.callback && driver.audio_active && + g_settings.audio.rate_control) + { + if (driver.audio->buffer_size && driver.audio->write_avail) + { + g_extern.audio_data.driver_buffer_size = + driver.audio->buffer_size(driver.audio_data); + g_extern.audio_data.rate_control = true; + } + else + RARCH_WARN("Audio rate control was desired, but driver does not support needed features.\n"); + } + + rarch_main_command(RARCH_CMD_DSP_FILTER_DEINIT); + + g_extern.measure_data.buffer_free_samples_count = 0; + + if (driver.audio_active && !g_extern.audio_data.mute && + g_extern.system.audio_callback.callback) + { + /* Threaded driver is initially stopped. */ + driver.audio->start(driver.audio_data); + } +} diff --git a/audio_driver.h b/audio_driver.h new file mode 100644 index 0000000000..91fc2a8139 --- /dev/null +++ b/audio_driver.h @@ -0,0 +1,117 @@ +/* RetroArch - A frontend for libretro. + * Copyright (C) 2010-2014 - Hans-Kristian Arntzen + * Copyright (C) 2011-2015 - Daniel De Matteis + * + * RetroArch 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 Found- + * ation, either version 3 of the License, or (at your option) any later version. + * + * RetroArch 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 RetroArch. + * If not, see . + */ + +#ifndef __AUDIO_DRIVER__H +#define __AUDIO_DRIVER__H + +#include +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct audio_driver +{ + void *(*init)(const char *device, unsigned rate, unsigned latency); + + ssize_t (*write)(void *data, const void *buf, size_t size); + + bool (*stop)(void *data); + + bool (*start)(void *data); + + /* Is the audio driver currently running? */ + bool (*alive)(void *data); + + /* Should we care about blocking in audio thread? Fast forwarding. */ + void (*set_nonblock_state)(void *data, bool toggle); + + void (*free)(void *data); + + /* Defines if driver will take standard floating point samples, + * or int16_t samples. */ + bool (*use_float)(void *data); + + /* Human-readable identifier. */ + const char *ident; + + /* Optional. */ + size_t (*write_avail)(void *data); + + size_t (*buffer_size)(void *data); +} audio_driver_t; + +extern audio_driver_t audio_rsound; +extern audio_driver_t audio_oss; +extern audio_driver_t audio_alsa; +extern audio_driver_t audio_alsathread; +extern audio_driver_t audio_roar; +extern audio_driver_t audio_openal; +extern audio_driver_t audio_opensl; +extern audio_driver_t audio_jack; +extern audio_driver_t audio_sdl; +extern audio_driver_t audio_xa; +extern audio_driver_t audio_pulse; +extern audio_driver_t audio_dsound; +extern audio_driver_t audio_coreaudio; +extern audio_driver_t audio_xenon360; +extern audio_driver_t audio_ps3; +extern audio_driver_t audio_gx; +extern audio_driver_t audio_psp1; +extern audio_driver_t audio_rwebaudio; +extern audio_driver_t audio_null; + +/** + * audio_driver_find_handle: + * @index : index of driver to get handle to. + * + * Returns: handle to audio driver at index. Can be NULL + * if nothing found. + **/ +const void *audio_driver_find_handle(int index); + +/** + * audio_driver_find_ident: + * @index : index of driver to get handle to. + * + * Returns: Human-readable identifier of audio driver at index. Can be NULL + * if nothing found. + **/ +const char *audio_driver_find_ident(int index); + +/** + * config_get_audio_driver_options: + * + * Get an enumerated list of all audio driver names, separated by '|'. + * + * Returns: string listing of all audio driver names, separated by '|'. + **/ +const char* config_get_audio_driver_options(void); + +void find_audio_driver(void); + +void uninit_audio(void); + +void init_audio(void); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/driver.c b/driver.c index 792e8b5d78..621029a701 100644 --- a/driver.c +++ b/driver.c @@ -14,7 +14,6 @@ * If not, see . */ - #include "driver.h" #include "general.h" #include "retroarch.h" @@ -23,9 +22,7 @@ #include #include #include "compat/posix_string.h" -#include "audio/utils.h" #include "gfx/video_thread_wrapper.h" -#include "audio/audio_thread_wrapper.h" #include "gfx/gfx_common.h" #include @@ -43,129 +40,6 @@ driver_t driver; -static const audio_driver_t *audio_drivers[] = { -#ifdef HAVE_ALSA - &audio_alsa, -#ifndef __QNX__ - &audio_alsathread, -#endif -#endif -#if defined(HAVE_OSS) || defined(HAVE_OSS_BSD) - &audio_oss, -#endif -#ifdef HAVE_RSOUND - &audio_rsound, -#endif -#ifdef HAVE_COREAUDIO - &audio_coreaudio, -#endif -#ifdef HAVE_AL - &audio_openal, -#endif -#ifdef HAVE_SL - &audio_opensl, -#endif -#ifdef HAVE_ROAR - &audio_roar, -#endif -#ifdef HAVE_JACK - &audio_jack, -#endif -#if defined(HAVE_SDL) || defined(HAVE_SDL2) - &audio_sdl, -#endif -#ifdef HAVE_XAUDIO - &audio_xa, -#endif -#ifdef HAVE_DSOUND - &audio_dsound, -#endif -#ifdef HAVE_PULSE - &audio_pulse, -#endif -#ifdef __CELLOS_LV2__ - &audio_ps3, -#endif -#ifdef XENON - &audio_xenon360, -#endif -#ifdef GEKKO - &audio_gx, -#endif -#ifdef EMSCRIPTEN - &audio_rwebaudio, -#endif -#ifdef PSP - &audio_psp1, -#endif - &audio_null, - NULL, -}; - -/** - * audio_driver_find_handle: - * @index : index of driver to get handle to. - * - * Returns: handle to audio driver at index. Can be NULL - * if nothing found. - **/ -static const void *audio_driver_find_handle(int index) -{ - const void *drv = audio_drivers[index]; - if (!drv) - return NULL; - return drv; -} - -/** - * audio_driver_find_ident: - * @index : index of driver to get handle to. - * - * Returns: Human-readable identifier of audio driver at index. Can be NULL - * if nothing found. - **/ -static const char *audio_driver_find_ident(int index) -{ - const audio_driver_t *drv = audio_drivers[index]; - if (!drv) - return NULL; - return drv->ident; -} - -/** - * config_get_audio_driver_options: - * - * Get an enumerated list of all audio driver names, separated by '|'. - * - * Returns: string listing of all audio driver names, separated by '|'. - **/ -const char* config_get_audio_driver_options(void) -{ - union string_list_elem_attr attr; - unsigned i; - char *options = NULL; - int options_len = 0; - struct string_list *options_l = string_list_new(); - - attr.i = 0; - - for (i = 0; audio_driver_find_handle(i); i++) - { - const char *opt = audio_driver_find_ident(i); - options_len += strlen(opt) + 1; - string_list_append(options_l, opt, attr); - } - - options = (char*)calloc(options_len, sizeof(char)); - - string_list_join_concat(options, options_len, options_l, "|"); - - string_list_free(options_l); - options_l = NULL; - - return options; -} - static const video_driver_t *video_drivers[] = { #ifdef HAVE_OPENGL &video_gl, @@ -824,7 +698,7 @@ static const void *find_driver_nonempty(const char *label, int i, * Returns: -1 if no driver based on @label and @drv found, otherwise * index number of the driver found in the array. **/ -static int find_driver_index(const char * label, const char *drv) +int find_driver_index(const char * label, const char *drv) { unsigned i; char str[PATH_MAX_LENGTH]; @@ -1207,30 +1081,6 @@ static void find_menu_driver(void) } #endif - -static void find_audio_driver(void) -{ - int i = find_driver_index("audio_driver", g_settings.audio.driver); - if (i >= 0) - driver.audio = audio_driver_find_handle(i); - else - { - unsigned d; - RARCH_ERR("Couldn't find any audio driver named \"%s\"\n", - g_settings.audio.driver); - RARCH_LOG_OUTPUT("Available audio drivers are:\n"); - for (d = 0; audio_driver_find_handle(d); d++) - RARCH_LOG_OUTPUT("\t%s\n", audio_driver_find_ident(d)); - RARCH_WARN("Going to default to first audio driver...\n"); - - driver.audio = audio_driver_find_handle(0); - - if (!driver.audio) - rarch_fail(1, "find_audio_driver()"); - } -} - - static void find_video_driver(void) { int i; @@ -1536,137 +1386,6 @@ static void init_menu(void) } #endif -static void init_audio(void) -{ - size_t outsamples_max, max_bufsamples = AUDIO_CHUNK_SIZE_NONBLOCKING * 2; - - audio_convert_init_simd(); - - /* Resource leaks will follow if audio is initialized twice. */ - if (driver.audio_data) - return; - - /* Accomodate rewind since at some point we might have two full buffers. */ - outsamples_max = max_bufsamples * AUDIO_MAX_RATIO * - g_settings.slowmotion_ratio; - - /* Used for recording even if audio isn't enabled. */ - rarch_assert(g_extern.audio_data.conv_outsamples = - (int16_t*)malloc(outsamples_max * sizeof(int16_t))); - - g_extern.audio_data.block_chunk_size = AUDIO_CHUNK_SIZE_BLOCKING; - g_extern.audio_data.nonblock_chunk_size = AUDIO_CHUNK_SIZE_NONBLOCKING; - g_extern.audio_data.chunk_size = - g_extern.audio_data.block_chunk_size; - - /* Needs to be able to hold full content of a full max_bufsamples - * in addition to its own. */ - rarch_assert(g_extern.audio_data.rewind_buf = (int16_t*) - malloc(max_bufsamples * sizeof(int16_t))); - g_extern.audio_data.rewind_size = max_bufsamples; - - if (!g_settings.audio.enable) - { - driver.audio_active = false; - return; - } - - find_audio_driver(); -#ifdef HAVE_THREADS - if (g_extern.system.audio_callback.callback) - { - RARCH_LOG("Starting threaded audio driver ...\n"); - if (!rarch_threaded_audio_init(&driver.audio, &driver.audio_data, - *g_settings.audio.device ? g_settings.audio.device : NULL, - g_settings.audio.out_rate, g_settings.audio.latency, - driver.audio)) - { - RARCH_ERR("Cannot open threaded audio driver ... Exiting ...\n"); - rarch_fail(1, "init_audio()"); - } - } - else -#endif - { - driver.audio_data = driver.audio->init(*g_settings.audio.device ? - g_settings.audio.device : NULL, - g_settings.audio.out_rate, g_settings.audio.latency); - } - - if (!driver.audio_data) - { - RARCH_ERR("Failed to initialize audio driver. Will continue without audio.\n"); - driver.audio_active = false; - } - - g_extern.audio_data.use_float = false; - if (driver.audio_active && driver.audio->use_float(driver.audio_data)) - g_extern.audio_data.use_float = true; - - if (!g_settings.audio.sync && driver.audio_active) - { - rarch_main_command(RARCH_CMD_AUDIO_SET_NONBLOCKING_STATE); - g_extern.audio_data.chunk_size = - g_extern.audio_data.nonblock_chunk_size; - } - - if (g_extern.audio_data.in_rate <= 0.0f) - { - /* Should never happen. */ - RARCH_WARN("Input rate is invalid (%.3f Hz). Using output rate (%u Hz).\n", - g_extern.audio_data.in_rate, g_settings.audio.out_rate); - g_extern.audio_data.in_rate = g_settings.audio.out_rate; - } - - g_extern.audio_data.orig_src_ratio = - g_extern.audio_data.src_ratio = - (double)g_settings.audio.out_rate / g_extern.audio_data.in_rate; - - if (!rarch_resampler_realloc(&driver.resampler_data, - &driver.resampler, - g_settings.audio.resampler, g_extern.audio_data.orig_src_ratio)) - { - RARCH_ERR("Failed to initialize resampler \"%s\".\n", - g_settings.audio.resampler); - driver.audio_active = false; - } - - rarch_assert(g_extern.audio_data.data = (float*) - malloc(max_bufsamples * sizeof(float))); - - g_extern.audio_data.data_ptr = 0; - - rarch_assert(g_settings.audio.out_rate < - g_extern.audio_data.in_rate * AUDIO_MAX_RATIO); - rarch_assert(g_extern.audio_data.outsamples = (float*) - malloc(outsamples_max * sizeof(float))); - - g_extern.audio_data.rate_control = false; - if (!g_extern.system.audio_callback.callback && driver.audio_active && - g_settings.audio.rate_control) - { - if (driver.audio->buffer_size && driver.audio->write_avail) - { - g_extern.audio_data.driver_buffer_size = - driver.audio->buffer_size(driver.audio_data); - g_extern.audio_data.rate_control = true; - } - else - RARCH_WARN("Audio rate control was desired, but driver does not support needed features.\n"); - } - - rarch_main_command(RARCH_CMD_DSP_FILTER_DEINIT); - - g_extern.measure_data.buffer_free_samples_count = 0; - - if (driver.audio_active && !g_extern.audio_data.mute && - g_extern.system.audio_callback.callback) - { - /* Threaded driver is initially stopped. */ - driver.audio->start(driver.audio_data); - } -} - static void deinit_pixel_converter(void) { scaler_ctx_gen_reset(&driver.scaler); @@ -2063,89 +1782,6 @@ static void compute_monitor_fps_statistics(void) } } -/** - * compute_audio_buffer_statistics: - * - * Computes audio buffer statistics. - * - **/ -static void compute_audio_buffer_statistics(void) -{ - unsigned i, low_water_size, high_water_size, avg, stddev; - float avg_filled, deviation; - uint64_t accum = 0, accum_var = 0; - unsigned low_water_count = 0, high_water_count = 0; - unsigned samples = min(g_extern.measure_data.buffer_free_samples_count, - AUDIO_BUFFER_FREE_SAMPLES_COUNT); - - if (samples < 3) - return; - - for (i = 1; i < samples; i++) - accum += g_extern.measure_data.buffer_free_samples[i]; - - avg = accum / (samples - 1); - - for (i = 1; i < samples; i++) - { - int diff = avg - g_extern.measure_data.buffer_free_samples[i]; - accum_var += diff * diff; - } - - stddev = (unsigned)sqrt((double)accum_var / (samples - 2)); - avg_filled = 1.0f - (float)avg / g_extern.audio_data.driver_buffer_size; - deviation = (float)stddev / g_extern.audio_data.driver_buffer_size; - - low_water_size = g_extern.audio_data.driver_buffer_size * 3 / 4; - high_water_size = g_extern.audio_data.driver_buffer_size / 4; - - for (i = 1; i < samples; i++) - { - if (g_extern.measure_data.buffer_free_samples[i] >= low_water_size) - low_water_count++; - else if (g_extern.measure_data.buffer_free_samples[i] <= high_water_size) - high_water_count++; - } - - RARCH_LOG("Average audio buffer saturation: %.2f %%, standard deviation (percentage points): %.2f %%.\n", - avg_filled * 100.0, deviation * 100.0); - RARCH_LOG("Amount of time spent close to underrun: %.2f %%. Close to blocking: %.2f %%.\n", - (100.0 * low_water_count) / (samples - 1), - (100.0 * high_water_count) / (samples - 1)); -} - -static void uninit_audio(void) -{ - if (driver.audio_data && driver.audio) - driver.audio->free(driver.audio_data); - - free(g_extern.audio_data.conv_outsamples); - g_extern.audio_data.conv_outsamples = NULL; - g_extern.audio_data.data_ptr = 0; - - free(g_extern.audio_data.rewind_buf); - g_extern.audio_data.rewind_buf = NULL; - - if (!g_settings.audio.enable) - { - driver.audio_active = false; - return; - } - - rarch_resampler_freep(&driver.resampler, - &driver.resampler_data); - - free(g_extern.audio_data.data); - g_extern.audio_data.data = NULL; - - free(g_extern.audio_data.outsamples); - g_extern.audio_data.outsamples = NULL; - - rarch_main_command(RARCH_CMD_DSP_FILTER_DEINIT); - - compute_audio_buffer_statistics(); -} - static void uninit_video_input(void) { rarch_main_command(RARCH_CMD_OVERLAY_DEINIT); diff --git a/driver.h b/driver.h index 930f3036a7..72a61ce679 100644 --- a/driver.h +++ b/driver.h @@ -14,7 +14,6 @@ * If not, see . */ - #ifndef __DRIVER__H #define __DRIVER__H @@ -36,6 +35,8 @@ #include "frontend/frontend_context.h" #include +#include "audio_driver.h" + #include "menu/menu_driver.h" #include "menu/backend/menu_backend.h" #include "menu/disp/menu_display.h" @@ -180,30 +181,6 @@ typedef struct video_info bool rgb32; } video_info_t; -typedef struct audio_driver -{ - void *(*init)(const char *device, unsigned rate, unsigned latency); - ssize_t (*write)(void *data, const void *buf, size_t size); - bool (*stop)(void *data); - bool (*start)(void *data); - - /* Is the audio driver currently running? */ - bool (*alive)(void *data); - - /* Should we care about blocking in audio thread? Fast forwarding. */ - void (*set_nonblock_state)(void *data, bool toggle); - void (*free)(void *data); - - /* Defines if driver will take standard floating point samples, - * or int16_t samples. */ - bool (*use_float)(void *data); - const char *ident; - - /* Optional. */ - size_t (*write_avail)(void *data); - size_t (*buffer_size)(void *data); -} audio_driver_t; - #define AXIS_NEG(x) (((uint32_t)(x) << 16) | UINT16_C(0xFFFF)) #define AXIS_POS(x) ((uint32_t)(x) | UINT32_C(0xFFFF0000)) #define AXIS_NONE UINT32_C(0xFFFFFFFF) @@ -805,26 +782,6 @@ bool driver_update_system_av_info(const struct retro_system_av_info *info); extern driver_t driver; /* Backends */ -extern audio_driver_t audio_rsound; -extern audio_driver_t audio_oss; -extern audio_driver_t audio_alsa; -extern audio_driver_t audio_alsathread; -extern audio_driver_t audio_roar; -extern audio_driver_t audio_openal; -extern audio_driver_t audio_opensl; -extern audio_driver_t audio_jack; -extern audio_driver_t audio_sdl; -extern audio_driver_t audio_xa; -extern audio_driver_t audio_pulse; -extern audio_driver_t audio_dsound; -extern audio_driver_t audio_coreaudio; -extern audio_driver_t audio_xenon360; -extern audio_driver_t audio_ps3; -extern audio_driver_t audio_gx; -extern audio_driver_t audio_psp1; -extern audio_driver_t audio_rwebaudio; -extern audio_driver_t audio_null; - extern video_driver_t video_gl; extern video_driver_t video_psp1; extern video_driver_t video_vita; @@ -886,15 +843,6 @@ const char* config_get_camera_driver_options(void); **/ const char* config_get_video_driver_options(void); -/** - * config_get_audio_driver_options: - * - * Get an enumerated list of all audio driver names, separated by '|'. - * - * Returns: string listing of all audio driver names, separated by '|'. - **/ -const char* config_get_audio_driver_options(void); - /** * config_get_osk_driver_options: * @@ -929,6 +877,18 @@ const char* config_get_location_driver_options(void); **/ const char* config_get_menu_driver_options(void); #endif + +/** + * find_driver_index: + * @label : string of driver type to be found. + * @drv : identifier of driver to be found. + * + * Find index of the driver, based on @label. + * + * Returns: -1 if no driver based on @label and @drv found, otherwise + * index number of the driver found in the array. + **/ +int find_driver_index(const char * label, const char *drv); extern camera_driver_t camera_v4l2; extern camera_driver_t camera_android; diff --git a/griffin/griffin.c b/griffin/griffin.c index a950d92a08..ff537384c5 100644 --- a/griffin/griffin.c +++ b/griffin/griffin.c @@ -496,6 +496,7 @@ AUDIO /*============================================================ DRIVERS ============================================================ */ +#include "../audio_driver.c" #include "../driver.c" /*============================================================