Add high latency audio support for Android.
Should fix ghetto hardware again.
This commit is contained in:
parent
3122dbf4e6
commit
16ca310f93
|
@ -98,6 +98,12 @@
|
||||||
android:summary="Enable dynamic rate control (recommended)."
|
android:summary="Enable dynamic rate control (recommended)."
|
||||||
android:title="Dynamic Rate Control"
|
android:title="Dynamic Rate Control"
|
||||||
android:dependency="audio_enable" />
|
android:dependency="audio_enable" />
|
||||||
|
<CheckBoxPreference
|
||||||
|
android:defaultValue="false"
|
||||||
|
android:key="audio_high_latency"
|
||||||
|
android:summary="Use (very) high latency audio. Necessary for older Android devices with poor audio drivers."
|
||||||
|
android:title="High latency audio"
|
||||||
|
android:dependency="audio_enable" />
|
||||||
</PreferenceCategory>
|
</PreferenceCategory>
|
||||||
</PreferenceScreen>
|
</PreferenceScreen>
|
||||||
<PreferenceScreen android:title="Input Options" >
|
<PreferenceScreen android:title="Input Options" >
|
||||||
|
|
|
@ -219,6 +219,7 @@ public class CoreSelection extends Activity implements
|
||||||
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(getBaseContext());
|
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(getBaseContext());
|
||||||
config.setBoolean("audio_rate_control", prefs.getBoolean("audio_rate_control", true));
|
config.setBoolean("audio_rate_control", prefs.getBoolean("audio_rate_control", true));
|
||||||
config.setInt("audio_out_rate", getOptimalSamplingRate());
|
config.setInt("audio_out_rate", getOptimalSamplingRate());
|
||||||
|
config.setInt("audio_latency", prefs.getBoolean("audio_high_latency", false) ? 160 : 64);
|
||||||
config.setBoolean("audio_enable", prefs.getBoolean("audio_enable", true));
|
config.setBoolean("audio_enable", prefs.getBoolean("audio_enable", true));
|
||||||
config.setBoolean("video_smooth", prefs.getBoolean("video_smooth", true));
|
config.setBoolean("video_smooth", prefs.getBoolean("video_smooth", true));
|
||||||
config.setBoolean("video_allow_rotate", prefs.getBoolean("video_allow_rotate", true));
|
config.setBoolean("video_allow_rotate", prefs.getBoolean("video_allow_rotate", true));
|
||||||
|
|
|
@ -33,13 +33,10 @@
|
||||||
|
|
||||||
#define SLPlayItf_SetPlayState(a, ...) ((*(a))->SetPlayState(a, __VA_ARGS__))
|
#define SLPlayItf_SetPlayState(a, ...) ((*(a))->SetPlayState(a, __VA_ARGS__))
|
||||||
|
|
||||||
// TODO: Are these sane?
|
|
||||||
#define BUFFER_SIZE (2 * 1024)
|
|
||||||
#define BUFFER_COUNT 16
|
|
||||||
|
|
||||||
typedef struct sl
|
typedef struct sl
|
||||||
{
|
{
|
||||||
uint8_t buffer[BUFFER_COUNT][BUFFER_SIZE];
|
uint8_t **buffer;
|
||||||
|
uint8_t *buffer_chunk;
|
||||||
unsigned buffer_index;
|
unsigned buffer_index;
|
||||||
unsigned buffer_ptr;
|
unsigned buffer_ptr;
|
||||||
volatile unsigned buffered_blocks;
|
volatile unsigned buffered_blocks;
|
||||||
|
@ -55,6 +52,7 @@ typedef struct sl
|
||||||
slock_t *lock;
|
slock_t *lock;
|
||||||
scond_t *cond;
|
scond_t *cond;
|
||||||
bool nonblock;
|
bool nonblock;
|
||||||
|
unsigned buf_size;
|
||||||
unsigned buf_count;
|
unsigned buf_count;
|
||||||
} sl_t;
|
} sl_t;
|
||||||
|
|
||||||
|
@ -93,6 +91,8 @@ static void sl_free(void *data)
|
||||||
if (sl->cond)
|
if (sl->cond)
|
||||||
scond_free(sl->cond);
|
scond_free(sl->cond);
|
||||||
|
|
||||||
|
free(sl->buffer);
|
||||||
|
free(sl->buffer_chunk);
|
||||||
free(sl);
|
free(sl);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -122,11 +122,23 @@ 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(SLEngineItf_CreateOutputMix(sl->engine, &sl->output_mix, 0, NULL, NULL));
|
||||||
GOTO_IF_FAIL(SLObjectItf_Realize(sl->output_mix, SL_BOOLEAN_FALSE));
|
GOTO_IF_FAIL(SLObjectItf_Realize(sl->output_mix, SL_BOOLEAN_FALSE));
|
||||||
|
|
||||||
|
sl->buf_size = next_pow2(32 * latency);
|
||||||
sl->buf_count = (latency * 4 * out_rate + 500) / 1000;
|
sl->buf_count = (latency * 4 * out_rate + 500) / 1000;
|
||||||
sl->buf_count = (sl->buf_count + BUFFER_SIZE / 2) / BUFFER_SIZE;
|
sl->buf_count = (sl->buf_count + sl->buf_size / 2) / sl->buf_size;
|
||||||
sl->buf_count = min(sl->buf_count, BUFFER_COUNT);
|
|
||||||
|
|
||||||
RARCH_LOG("[SLES] : Setting audio latency (buffer size: [%d]) ...\n", sl->buf_count * BUFFER_SIZE);
|
sl->buffer = (uint8_t**)calloc(sizeof(uint8_t*), sl->buf_count);
|
||||||
|
if (!sl->buffer)
|
||||||
|
goto error;
|
||||||
|
|
||||||
|
sl->buffer_chunk = (uint8_t*)calloc(sl->buf_count, sl->buf_size);
|
||||||
|
if (!sl->buffer_chunk)
|
||||||
|
goto error;
|
||||||
|
|
||||||
|
for (unsigned i = 0; i < sl->buf_count; i++)
|
||||||
|
sl->buffer[i] = sl->buffer_chunk + i * sl->buf_size;
|
||||||
|
|
||||||
|
RARCH_LOG("[SLES] : Setting audio latency: Block size = %u, Blocks = %u, Total = %u ...\n",
|
||||||
|
sl->buf_size, sl->buf_count, sl->buf_size * sl->buf_count);
|
||||||
|
|
||||||
fmt_pcm.formatType = SL_DATAFORMAT_PCM;
|
fmt_pcm.formatType = SL_DATAFORMAT_PCM;
|
||||||
fmt_pcm.numChannels = 2;
|
fmt_pcm.numChannels = 2;
|
||||||
|
@ -164,7 +176,7 @@ static void *sl_init(const char *device, unsigned rate, unsigned latency)
|
||||||
sl->buffered_blocks = sl->buf_count;
|
sl->buffered_blocks = sl->buf_count;
|
||||||
sl->buffer_index = 0;
|
sl->buffer_index = 0;
|
||||||
for (unsigned i = 0; i < sl->buf_count; i++)
|
for (unsigned i = 0; i < sl->buf_count; i++)
|
||||||
(*sl->buffer_queue)->Enqueue(sl->buffer_queue, sl->buffer[i], BUFFER_SIZE);
|
(*sl->buffer_queue)->Enqueue(sl->buffer_queue, sl->buffer[i], sl->buf_size);
|
||||||
|
|
||||||
GOTO_IF_FAIL(SLObjectItf_GetInterface(sl->buffer_queue_object, SL_IID_PLAY, &sl->player));
|
GOTO_IF_FAIL(SLObjectItf_GetInterface(sl->buffer_queue_object, SL_IID_PLAY, &sl->player));
|
||||||
GOTO_IF_FAIL(SLPlayItf_SetPlayState(sl->player, SL_PLAYSTATE_PLAYING));
|
GOTO_IF_FAIL(SLPlayItf_SetPlayState(sl->player, SL_PLAYSTATE_PLAYING));
|
||||||
|
@ -218,7 +230,7 @@ static ssize_t sl_write(void *data, const void *buf_, size_t size)
|
||||||
slock_unlock(sl->lock);
|
slock_unlock(sl->lock);
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t avail_write = min(BUFFER_SIZE - sl->buffer_ptr, size);
|
size_t avail_write = min(sl->buf_size - sl->buffer_ptr, size);
|
||||||
if (avail_write)
|
if (avail_write)
|
||||||
{
|
{
|
||||||
memcpy(sl->buffer[sl->buffer_index] + sl->buffer_ptr, buf, avail_write);
|
memcpy(sl->buffer[sl->buffer_index] + sl->buffer_ptr, buf, avail_write);
|
||||||
|
@ -228,9 +240,9 @@ static ssize_t sl_write(void *data, const void *buf_, size_t size)
|
||||||
written += avail_write;
|
written += avail_write;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (sl->buffer_ptr >= BUFFER_SIZE)
|
if (sl->buffer_ptr >= sl->buf_size)
|
||||||
{
|
{
|
||||||
SLresult res = (*sl->buffer_queue)->Enqueue(sl->buffer_queue, sl->buffer[sl->buffer_index], BUFFER_SIZE);
|
SLresult res = (*sl->buffer_queue)->Enqueue(sl->buffer_queue, sl->buffer[sl->buffer_index], sl->buf_size);
|
||||||
sl->buffer_index = (sl->buffer_index + 1) % sl->buf_count;
|
sl->buffer_index = (sl->buffer_index + 1) % sl->buf_count;
|
||||||
__sync_fetch_and_add(&sl->buffered_blocks, 1);
|
__sync_fetch_and_add(&sl->buffered_blocks, 1);
|
||||||
sl->buffer_ptr = 0;
|
sl->buffer_ptr = 0;
|
||||||
|
@ -243,22 +255,20 @@ static ssize_t sl_write(void *data, const void *buf_, size_t size)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//RARCH_LOG("Blocks: %u\n", sl->buffered_blocks);
|
|
||||||
|
|
||||||
return written;
|
return written;
|
||||||
}
|
}
|
||||||
|
|
||||||
static size_t sl_write_avail(void *data)
|
static size_t sl_write_avail(void *data)
|
||||||
{
|
{
|
||||||
sl_t *sl = (sl_t*)data;
|
sl_t *sl = (sl_t*)data;
|
||||||
size_t avail = (sl->buf_count - (int)sl->buffered_blocks - 1) * BUFFER_SIZE + (BUFFER_SIZE - (int)sl->buffer_ptr);
|
size_t avail = (sl->buf_count - (int)sl->buffered_blocks - 1) * sl->buf_size + (sl->buf_size - (int)sl->buffer_ptr);
|
||||||
return avail;
|
return avail;
|
||||||
}
|
}
|
||||||
|
|
||||||
static size_t sl_buffer_size(void *data)
|
static size_t sl_buffer_size(void *data)
|
||||||
{
|
{
|
||||||
sl_t *sl = (sl_t*)data;
|
sl_t *sl = (sl_t*)data;
|
||||||
return BUFFER_SIZE * sl->buf_count;
|
return sl->buf_size * sl->buf_count;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool sl_use_float(void *data)
|
static bool sl_use_float(void *data)
|
||||||
|
|
Loading…
Reference in New Issue