Modified OpenSL ES backend to dynamically set the bufferCount based on the current Android OS version (at runtime). My previous change to lower it from 8 to 4 did in fact give us reports that Android 4.1 playback was breaking up. Marc Salem did warn me that this was a possibility because the 4.1 timing characteristics/requirements changed drastically. So the change is to check for the current OS version and set the bufferCount to 8 if >=4.1 and 4 if below 4.1.

One tricky modification is that JNI is needed in the opensles.c backend which impacts a function pointer previously not being set and is sensitive to initialization order. This changes the logic slightly to ensure initialization is correct and not overwritten by AudioTrack initialization.

Thanks to Josh Quick for help on the JNI code to get the Android API version number.
master
Eric Wing 2012-11-12 18:34:25 -08:00 committed by Marc Salem
parent c5984e2280
commit dbef5ed4d6
3 changed files with 74 additions and 4 deletions

View File

@ -11,6 +11,13 @@ jint JNI_OnLoad(JavaVM *vm, void *reserved) {
return JNI_VERSION_1_4;
}
void JNICALL JNI_OnUnload (JavaVM *vm, void *reserved)
{
if (apportableOpenALFuncs.alc_android_set_java_vm) {
apportableOpenALFuncs.alc_android_set_java_vm(NULL);
}
}
ALC_API void ALC_APIENTRY alcSuspend(void) {
if (apportableOpenALFuncs.alc_android_suspend) {
apportableOpenALFuncs.alc_android_suspend();
@ -23,4 +30,4 @@ ALC_API void ALC_APIENTRY alcResume(void) {
}
}
#endif
#endif

View File

@ -295,7 +295,8 @@ void alc_audiotrack_init(BackendFuncs *func_list)
{
*func_list = android_funcs;
if (apportableOpenALFuncs.alc_android_suspend == NULL) {
if (apportableOpenALFuncs.alc_android_suspend == NULL
&& apportableOpenALFuncs.alc_android_set_java_vm == NULL) {
apportableOpenALFuncs.alc_android_suspend = alc_audiotrack_suspend;
apportableOpenALFuncs.alc_android_resume = alc_audiotrack_resume;
apportableOpenALFuncs.alc_android_set_java_vm = alc_audiotrack_set_java_vm;

View File

@ -34,6 +34,9 @@
#include <sched.h>
#include <sys/prctl.h>
#include <jni.h>
#define LOG_NDEBUG 0
#define LOG_TAG "OpenAL_SLES"
@ -69,6 +72,8 @@ static SLPlayItf bqPlayerPlay;
static ALCdevice *openSLESDevice = NULL;
static SLAndroidSimpleBufferQueueItf bqPlayerBufferQueue;
// JNI stuff so we can get the runtime OS version number
static JavaVM* javaVM = NULL;
static long timespecdiff(struct timespec *starttime, struct timespec *finishtime)
{
@ -80,7 +85,8 @@ static long timespecdiff(struct timespec *starttime, struct timespec *finishtime
// thread to mix and enqueue data
#define bufferSize (1024*4)
#define bufferCount 4
// Cannot be a constant because we need to tweak differently depending on OS version.
size_t bufferCount = 8;
typedef enum {
OUTPUT_BUFFER_STATE_UNKNOWN,
@ -96,7 +102,8 @@ typedef struct outputBuffer_s {
char buffer[bufferSize];
} outputBuffer_t;
static outputBuffer_t outputBuffers[bufferCount];
// Will dynamically create the number of buffers (array elements) based on OS version.
static outputBuffer_t* outputBuffers = NULL;
typedef struct {
@ -501,6 +508,56 @@ void alc_opensles_resume()
}
}
static int alc_opensles_get_android_api()
{
jclass androidVersionClass = NULL;
jfieldID androidSdkIntField = NULL;
int androidApiLevel = 0;
JNIEnv* env = NULL;
(*javaVM)->GetEnv(javaVM, (void**)&env, JNI_VERSION_1_4);
androidVersionClass = (*env)->FindClass(env, "android/os/Build$VERSION");
if (androidVersionClass)
{
androidSdkIntField = (*env)->GetStaticFieldID(env, androidVersionClass, "SDK_INT", "I");
if (androidSdkIntField != NULL)
{
androidApiLevel = (int)((*env)->GetStaticIntField(env, androidVersionClass, androidSdkIntField));
}
(*env)->DeleteLocalRef(env, androidVersionClass);
}
return androidApiLevel;
}
static void alc_opensles_set_java_vm(JavaVM *vm)
{
javaVM = vm;
if(NULL == javaVM)
{
free(outputBuffers);
outputBuffers = NULL;
}
else
{
if(NULL == outputBuffers)
{
int android_os_version = alc_opensles_get_android_api;
// If running on 4.1 (Jellybean) or later, use 8 buffers to avoid breakup/stuttering.
if(android_os_version >= 16)
{
bufferCount = 8;
}
// Else, use 4 buffers to reduce latency
else
{
bufferCount = 4;
}
outputBuffers = (outputBuffer_t*)malloc(sizeof(outputBuffer_t)*bufferCount);
}
}
}
void alc_opensles_init(BackendFuncs *func_list)
{
LOGV("alc_opensles_init");
@ -511,6 +568,11 @@ void alc_opensles_init(BackendFuncs *func_list)
}
*func_list = opensles_funcs;
// We need the JavaVM for JNI so we can detect the OS version number at runtime.
// This is because we need to use different bufferCount values for Android 4.1 vs. pre-4.1.
// This must be set before JNI_OnLoad is invoked.
apportableOpenALFuncs.alc_android_set_java_vm = alc_opensles_set_java_vm;
}
void alc_opensles_deinit(void)