Merge branch 'opensl'

This commit is contained in:
Themaister 2013-01-18 19:22:41 +01:00
commit 76a7b5aa60
4 changed files with 105 additions and 43 deletions

View File

@ -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 = {

View File

@ -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

View File

@ -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

View File

@ -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;