mirror of
https://github.com/CTCaer/RetroArch.git
synced 2025-01-03 16:48:40 +00:00
Merge branch 'opensl'
This commit is contained in:
commit
76a7b5aa60
@ -16,7 +16,6 @@
|
||||
|
||||
#include "../driver.h"
|
||||
#include "../general.h"
|
||||
#include "../fifo_buffer.h"
|
||||
#include "../thread.h"
|
||||
|
||||
#include <SLES/OpenSLES.h>
|
||||
@ -35,20 +34,24 @@
|
||||
#define SLPlayItf_SetPlayState(a, ...) ((*(a))->SetPlayState(a, __VA_ARGS__))
|
||||
|
||||
// TODO: Are these sane?
|
||||
#define BUFFER_SIZE 4096
|
||||
#define BUFFER_SIZE 8192
|
||||
#define BUFFER_COUNT 4
|
||||
|
||||
typedef struct sl
|
||||
{
|
||||
uint8_t buffer[BUFFER_SIZE];
|
||||
uint8_t buffer[BUFFER_COUNT][BUFFER_SIZE];
|
||||
unsigned buffer_index;
|
||||
unsigned buffer_ptr;
|
||||
volatile unsigned buffered_blocks;
|
||||
|
||||
SLObjectItf engine_object;
|
||||
SLEngineItf engine;
|
||||
|
||||
SLObjectItf output_mix;
|
||||
SLObjectItf buffer_queue_object;
|
||||
SLAndroidSimpleBufferQueueItf buffer_queue;
|
||||
SLPlayItf player;
|
||||
|
||||
fifo_buffer_t *fifo;
|
||||
slock_t *lock;
|
||||
scond_t *cond;
|
||||
bool nonblock;
|
||||
@ -60,15 +63,9 @@ static void opensl_callback(SLAndroidSimpleBufferQueueItf bq, void *ctx)
|
||||
sl_t *sl = (sl_t*)ctx;
|
||||
|
||||
slock_lock(sl->lock);
|
||||
size_t read_avail = fifo_read_avail(sl->fifo);
|
||||
if (read_avail > BUFFER_SIZE)
|
||||
read_avail = BUFFER_SIZE;
|
||||
fifo_read(sl->fifo, sl->buffer, read_avail);
|
||||
sl->buffered_blocks--;
|
||||
slock_unlock(sl->lock);
|
||||
|
||||
memset(sl->buffer + read_avail, 0, BUFFER_SIZE - read_avail);
|
||||
(*bq)->Enqueue(bq, sl->buffer, BUFFER_SIZE);
|
||||
|
||||
scond_signal(sl->cond);
|
||||
}
|
||||
|
||||
@ -95,8 +92,6 @@ static void sl_free(void *data)
|
||||
if (sl->engine_object)
|
||||
SLObjectItf_Destroy(sl->engine_object);
|
||||
|
||||
if (sl->fifo)
|
||||
fifo_free(sl->fifo);
|
||||
if (sl->lock)
|
||||
slock_free(sl->lock);
|
||||
if (sl->cond)
|
||||
@ -119,8 +114,6 @@ static void *sl_init(const char *device, unsigned rate, unsigned latency)
|
||||
SLInterfaceID id = SL_IID_ANDROIDSIMPLEBUFFERQUEUE;
|
||||
SLboolean req = SL_BOOLEAN_TRUE;
|
||||
|
||||
SLAndroidSimpleBufferQueueItf buffer_queue = NULL;
|
||||
|
||||
SLresult res = 0;
|
||||
sl_t *sl = (sl_t*)calloc(1, sizeof(sl_t));
|
||||
if (!sl)
|
||||
@ -132,7 +125,7 @@ static void *sl_init(const char *device, unsigned rate, unsigned latency)
|
||||
GOTO_IF_FAIL(SLEngineItf_CreateOutputMix(sl->engine, &sl->output_mix, 0, NULL, NULL));
|
||||
GOTO_IF_FAIL(SLObjectItf_Realize(sl->output_mix, SL_BOOLEAN_FALSE));
|
||||
|
||||
sl->buf_count = 8;
|
||||
sl->buf_count = BUFFER_COUNT;
|
||||
|
||||
RARCH_LOG("[SLES] : Setting audio latency (buffer size: [%d])..\n", sl->buf_count * BUFFER_SIZE);
|
||||
|
||||
@ -161,21 +154,22 @@ static void *sl_init(const char *device, unsigned rate, unsigned latency)
|
||||
GOTO_IF_FAIL(SLObjectItf_Realize(sl->buffer_queue_object, SL_BOOLEAN_FALSE));
|
||||
|
||||
GOTO_IF_FAIL(SLObjectItf_GetInterface(sl->buffer_queue_object, SL_IID_BUFFERQUEUE,
|
||||
&buffer_queue));
|
||||
&sl->buffer_queue));
|
||||
|
||||
sl->cond = scond_new();
|
||||
sl->lock = slock_new();
|
||||
sl->fifo = fifo_new(BUFFER_SIZE * sl->buf_count);
|
||||
|
||||
(*buffer_queue)->RegisterCallback(buffer_queue, opensl_callback, sl);
|
||||
(*buffer_queue)->Enqueue(buffer_queue, sl->buffer, BUFFER_SIZE);
|
||||
(*sl->buffer_queue)->RegisterCallback(sl->buffer_queue, opensl_callback, sl);
|
||||
|
||||
// Enqueue a bit to get stuff rolling.
|
||||
sl->buffered_blocks = BUFFER_COUNT;
|
||||
sl->buffer_index = 0;
|
||||
for (unsigned i = 0; i < BUFFER_COUNT; i++)
|
||||
(*sl->buffer_queue)->Enqueue(sl->buffer_queue, sl->buffer[i], BUFFER_SIZE);
|
||||
|
||||
GOTO_IF_FAIL(SLObjectItf_GetInterface(sl->buffer_queue_object, SL_IID_PLAY, &sl->player));
|
||||
GOTO_IF_FAIL(SLPlayItf_SetPlayState(sl->player, SL_PLAYSTATE_PLAYING));
|
||||
|
||||
g_settings.audio.rate_control_delta = 0.006;
|
||||
g_settings.audio.rate_control = true;
|
||||
|
||||
return sl;
|
||||
|
||||
error:
|
||||
@ -213,31 +207,44 @@ static ssize_t sl_write(void *data, const void *buf_, size_t size)
|
||||
while (size)
|
||||
{
|
||||
slock_lock(sl->lock);
|
||||
|
||||
size_t write_avail = fifo_write_avail(sl->fifo);
|
||||
if (write_avail > size)
|
||||
write_avail = size;
|
||||
|
||||
if (write_avail)
|
||||
if (sl->nonblock)
|
||||
{
|
||||
fifo_write(sl->fifo, buf, write_avail);
|
||||
slock_unlock(sl->lock);
|
||||
written += write_avail;
|
||||
size -= write_avail;
|
||||
buf += write_avail;
|
||||
}
|
||||
else if (!sl->nonblock)
|
||||
{
|
||||
scond_wait(sl->cond, sl->lock);
|
||||
slock_unlock(sl->lock);
|
||||
if (sl->buffered_blocks == BUFFER_COUNT)
|
||||
{
|
||||
slock_unlock(sl->lock);
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
while (sl->buffered_blocks == BUFFER_COUNT)
|
||||
scond_wait(sl->cond, sl->lock);
|
||||
}
|
||||
slock_unlock(sl->lock);
|
||||
|
||||
size_t avail_write = min(BUFFER_SIZE - sl->buffer_ptr, size);
|
||||
if (avail_write)
|
||||
{
|
||||
memcpy(sl->buffer[sl->buffer_index] + sl->buffer_ptr, buf, avail_write);
|
||||
sl->buffer_ptr += avail_write;
|
||||
buf += avail_write;
|
||||
size -= avail_write;
|
||||
written += avail_write;
|
||||
}
|
||||
|
||||
if (sl->buffer_ptr >= BUFFER_SIZE)
|
||||
{
|
||||
slock_lock(sl->lock);
|
||||
(*sl->buffer_queue)->Enqueue(sl->buffer_queue, sl->buffer[sl->buffer_index], BUFFER_SIZE);
|
||||
sl->buffer_index = (sl->buffer_index + 1) & (BUFFER_COUNT - 1);
|
||||
sl->buffered_blocks++;
|
||||
slock_unlock(sl->lock);
|
||||
break;
|
||||
sl->buffer_ptr = 0;
|
||||
}
|
||||
}
|
||||
|
||||
//RARCH_LOG("Blocks: %u\n", sl->buffered_blocks);
|
||||
|
||||
return written;
|
||||
}
|
||||
|
||||
@ -245,15 +252,15 @@ static size_t sl_write_avail(void *data)
|
||||
{
|
||||
sl_t *sl = (sl_t*)data;
|
||||
slock_lock(sl->lock);
|
||||
size_t avail = fifo_write_avail(sl->fifo);
|
||||
size_t avail = (BUFFER_COUNT - (int)sl->buffered_blocks - 1) * BUFFER_SIZE + (BUFFER_SIZE - (int)sl->buffer_ptr);
|
||||
slock_unlock(sl->lock);
|
||||
return avail;
|
||||
}
|
||||
|
||||
static size_t sl_buffer_size(void *data)
|
||||
{
|
||||
sl_t *sl = (sl_t*)data;
|
||||
return BUFFER_SIZE * sl->buf_count;
|
||||
(void)data;
|
||||
return BUFFER_SIZE * BUFFER_COUNT;
|
||||
}
|
||||
|
||||
const audio_driver_t audio_opensl = {
|
||||
|
48
driver.c
48
driver.c
@ -434,6 +434,52 @@ void init_audio(void)
|
||||
#ifdef HAVE_DYLIB
|
||||
init_dsp_plugin();
|
||||
#endif
|
||||
|
||||
g_extern.audio_data.buffer_free_samples_count = 0;
|
||||
}
|
||||
|
||||
static void compute_audio_buffer_statistics(void)
|
||||
{
|
||||
unsigned samples = min(g_extern.audio_data.buffer_free_samples_count, AUDIO_BUFFER_FREE_SAMPLES_COUNT);
|
||||
if (!samples)
|
||||
return;
|
||||
|
||||
uint64_t accum = 0;
|
||||
for (unsigned i = 0; i < samples; i++)
|
||||
accum += g_extern.audio_data.buffer_free_samples[i];
|
||||
|
||||
int avg = accum / samples;
|
||||
|
||||
uint64_t accum_var = 0;
|
||||
for (unsigned i = 0; i < samples; i++)
|
||||
{
|
||||
int diff = avg - g_extern.audio_data.buffer_free_samples[i];
|
||||
accum_var += diff * diff;
|
||||
}
|
||||
|
||||
unsigned stddev = (unsigned)sqrtf((float)accum_var / samples);
|
||||
|
||||
float avg_filled = 1.0f - (float)avg / g_extern.audio_data.driver_buffer_size;
|
||||
float deviation = (float)stddev / g_extern.audio_data.driver_buffer_size;
|
||||
|
||||
unsigned low_water_size = g_extern.audio_data.driver_buffer_size * 3 / 4;
|
||||
unsigned high_water_size = g_extern.audio_data.driver_buffer_size / 4;
|
||||
|
||||
unsigned low_water_count = 0;
|
||||
unsigned high_water_count = 0;
|
||||
for (unsigned i = 0; i < samples; i++)
|
||||
{
|
||||
if (g_extern.audio_data.buffer_free_samples[i] >= low_water_size)
|
||||
low_water_count++;
|
||||
else if (g_extern.audio_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,
|
||||
(100.0 * high_water_count) / samples);
|
||||
}
|
||||
|
||||
void uninit_audio(void)
|
||||
@ -466,6 +512,8 @@ void uninit_audio(void)
|
||||
#ifdef HAVE_DYLIB
|
||||
deinit_dsp_plugin();
|
||||
#endif
|
||||
|
||||
compute_audio_buffer_statistics();
|
||||
}
|
||||
|
||||
#ifdef HAVE_DYLIB
|
||||
|
@ -401,6 +401,10 @@ struct global
|
||||
|
||||
float volume_db;
|
||||
float volume_gain;
|
||||
|
||||
#define AUDIO_BUFFER_FREE_SAMPLES_COUNT (8 * 1024)
|
||||
unsigned buffer_free_samples[AUDIO_BUFFER_FREE_SAMPLES_COUNT];
|
||||
uint64_t buffer_free_samples_count;
|
||||
} audio_data;
|
||||
|
||||
struct
|
||||
|
@ -182,6 +182,9 @@ static void readjust_audio_input_rate(void)
|
||||
//RARCH_LOG_OUTPUT("Audio buffer is %u%% full\n",
|
||||
// (unsigned)(100 - (avail * 100) / g_extern.audio_data.driver_buffer_size));
|
||||
|
||||
unsigned write_index = (g_extern.audio_data.buffer_free_samples_count++) & (AUDIO_BUFFER_FREE_SAMPLES_COUNT - 1);
|
||||
g_extern.audio_data.buffer_free_samples[write_index] = avail;
|
||||
|
||||
int half_size = g_extern.audio_data.driver_buffer_size / 2;
|
||||
int delta_mid = avail - half_size;
|
||||
double direction = (double)delta_mid / half_size;
|
||||
|
Loading…
Reference in New Issue
Block a user