From 54570fdfb499ac8b45e71249f41a21277d0f55df Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Tue, 17 Sep 2019 09:26:52 +0200 Subject: [PATCH 1/3] Android OpenSL: Fix bug where we should have enqueued two buffers on startup. I don't actually think this matters much though. Seems to make absolutely no difference on any of my devices, but you never know. --- android/jni/native-audio-so.cpp | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/android/jni/native-audio-so.cpp b/android/jni/native-audio-so.cpp index 27729ab2cddc..b2d684da0037 100644 --- a/android/jni/native-audio-so.cpp +++ b/android/jni/native-audio-so.cpp @@ -124,13 +124,16 @@ bool OpenSLContext::Init() { result = (*bqPlayerPlay)->SetPlayState(bqPlayerPlay, SL_PLAYSTATE_PLAYING); assert(SL_RESULT_SUCCESS == result); - // Render and enqueue a first buffer. (or should we just play the buffer empty?) - buffer[0] = new short[framesPerBuffer * 2]; - buffer[1] = new short[framesPerBuffer * 2]; + // Enqueue two empty buffers. + buffer[0] = new short[framesPerBuffer * 2]{}; + buffer[1] = new short[framesPerBuffer * 2]{}; curBuffer = 0; - audioCallback(buffer[curBuffer], framesPerBuffer); - + result = (*bqPlayerBufferQueue)->Enqueue(bqPlayerBufferQueue, buffer[curBuffer], sizeof(buffer[curBuffer])); + if (SL_RESULT_SUCCESS != result) { + return false; + } + curBuffer ^= 1; result = (*bqPlayerBufferQueue)->Enqueue(bqPlayerBufferQueue, buffer[curBuffer], sizeof(buffer[curBuffer])); if (SL_RESULT_SUCCESS != result) { return false; From e69b71b58f48fceeb6291daf5ae4e930875ab78e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Tue, 17 Sep 2019 23:26:42 +0200 Subject: [PATCH 2/3] Remove some legacy --- android/jni/app-android.cpp | 2 +- android/jni/native_audio.cpp | 2 +- android/jni/native_audio.h | 8 +------- 3 files changed, 3 insertions(+), 9 deletions(-) diff --git a/android/jni/app-android.cpp b/android/jni/app-android.cpp index c8049939d42e..1bebc69c87a8 100644 --- a/android/jni/app-android.cpp +++ b/android/jni/app-android.cpp @@ -506,7 +506,7 @@ extern "C" void Java_org_ppsspp_ppsspp_NativeApp_audioInit(JNIEnv *, jclass) { ILOG("NativeApp.audioInit() -- Using OpenSL audio! frames/buffer: %i optimal sr: %i actual sr: %i", optimalFramesPerBuffer, optimalSampleRate, sampleRate); if (!g_audioState) { - g_audioState = AndroidAudio_Init(&NativeMix, library_path, framesPerBuffer, sampleRate); + g_audioState = AndroidAudio_Init(&NativeMix, framesPerBuffer, sampleRate); } else { ELOG("Audio state already initialized"); } diff --git a/android/jni/native_audio.cpp b/android/jni/native_audio.cpp index 1bb027f3c615..a06159a89c4b 100644 --- a/android/jni/native_audio.cpp +++ b/android/jni/native_audio.cpp @@ -9,7 +9,7 @@ struct AndroidAudioState { int sample_rate = 0; }; -AndroidAudioState *AndroidAudio_Init(AndroidAudioCallback callback, std::string libraryDir, int optimalFramesPerBuffer, int optimalSampleRate) { +AndroidAudioState *AndroidAudio_Init(AndroidAudioCallback callback, int optimalFramesPerBuffer, int optimalSampleRate) { AndroidAudioState *state = new AndroidAudioState(); state->callback = callback; state->frames_per_buffer = optimalFramesPerBuffer ? optimalFramesPerBuffer : 256; diff --git a/android/jni/native_audio.h b/android/jni/native_audio.h index f00ae000ba2b..427f29ca3615 100644 --- a/android/jni/native_audio.h +++ b/android/jni/native_audio.h @@ -5,14 +5,8 @@ struct AndroidAudioState; -// This is the file you should include from your program. It dynamically loads -// the native_audio.so shared object and sets up the function pointers. - -// Do not call this if you have detected that the android version is below -// 2.2, as it will fail miserably. - // It's okay for optimalFramesPerBuffer and optimalSampleRate to be 0. Defaults will be used. -AndroidAudioState *AndroidAudio_Init(AndroidAudioCallback cb, std::string libraryDir, int optimalFramesPerBuffer, int optimalSampleRate); +AndroidAudioState *AndroidAudio_Init(AndroidAudioCallback cb, int optimalFramesPerBuffer, int optimalSampleRate); bool AndroidAudio_Pause(AndroidAudioState *state); bool AndroidAudio_Resume(AndroidAudioState *state); bool AndroidAudio_Shutdown(AndroidAudioState *state); From f9bf1f96bd88315f0034fe0dbb86d2f3e9f068ba Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Tue, 17 Sep 2019 23:38:50 +0200 Subject: [PATCH 3/3] Android audio: Turns out the initial queue operation queued up too little data anyway (sizeof on dynamic buffer.. sigh). Anyway like I said, none of this really seems to matter. --- android/jni/native-audio-so.cpp | 40 +++++++++++++++++---------------- android/jni/native-audio-so.h | 9 ++++++-- 2 files changed, 28 insertions(+), 21 deletions(-) diff --git a/android/jni/native-audio-so.cpp b/android/jni/native-audio-so.cpp index b2d684da0037..63a345639555 100644 --- a/android/jni/native-audio-so.cpp +++ b/android/jni/native-audio-so.cpp @@ -56,7 +56,9 @@ void OpenSLContext::BqPlayerCallback(SLAndroidSimpleBufferQueueItf bq) { ELOG("OpenSL ES: Failed to enqueue! %i %i", renderedFrames, sizeInBytes); } - curBuffer ^= 1; // Switch buffer + curBuffer += 1; // Switch buffer + if (curBuffer == NUM_BUFFERS) + curBuffer = 0; } // create the engine and output mix objects @@ -83,7 +85,7 @@ bool OpenSLContext::Init() { // The constants, such as SL_SAMPLINGRATE_44_1, are just 44100000. SLuint32 sr = (SLuint32)sampleRate * 1000; - SLDataLocator_AndroidSimpleBufferQueue loc_bufq = {SL_DATALOCATOR_ANDROIDSIMPLEBUFFERQUEUE, 2}; + SLDataLocator_AndroidSimpleBufferQueue loc_bufq = {SL_DATALOCATOR_ANDROIDSIMPLEBUFFERQUEUE, NUM_BUFFERS}; SLDataFormat_PCM format_pcm = { SL_DATAFORMAT_PCM, 2, @@ -124,21 +126,20 @@ bool OpenSLContext::Init() { result = (*bqPlayerPlay)->SetPlayState(bqPlayerPlay, SL_PLAYSTATE_PLAYING); assert(SL_RESULT_SUCCESS == result); - // Enqueue two empty buffers. - buffer[0] = new short[framesPerBuffer * 2]{}; - buffer[1] = new short[framesPerBuffer * 2]{}; - - curBuffer = 0; - result = (*bqPlayerBufferQueue)->Enqueue(bqPlayerBufferQueue, buffer[curBuffer], sizeof(buffer[curBuffer])); - if (SL_RESULT_SUCCESS != result) { - return false; + // Allocate and enqueue N empty buffers. + for (int i = 0; i < NUM_BUFFERS; i++) { + buffer[i] = new short[framesPerBuffer * 2]{}; } - curBuffer ^= 1; - result = (*bqPlayerBufferQueue)->Enqueue(bqPlayerBufferQueue, buffer[curBuffer], sizeof(buffer[curBuffer])); - if (SL_RESULT_SUCCESS != result) { - return false; + + int sizeInBytes = framesPerBuffer * 2 * sizeof(short); + for (int i = 0; i < NUM_BUFFERS; i++) { + result = (*bqPlayerBufferQueue)->Enqueue(bqPlayerBufferQueue, buffer[i], sizeInBytes); + if (SL_RESULT_SUCCESS != result) { + return false; + } } - curBuffer ^= 1; + + curBuffer = 0; return true; } @@ -177,10 +178,11 @@ OpenSLContext::~OpenSLContext() { engineObject = nullptr; engineEngine = nullptr; } - delete [] buffer[0]; - delete [] buffer[1]; - buffer[0] = nullptr; - buffer[1] = nullptr; + + for (int i = 0; i < NUM_BUFFERS; i++) { + delete[] buffer[i]; + buffer[i] = nullptr; + } ILOG("OpenSLWrap_Shutdown - finished"); } diff --git a/android/jni/native-audio-so.h b/android/jni/native-audio-so.h index 286a3338eb09..9623e5170938 100644 --- a/android/jni/native-audio-so.h +++ b/android/jni/native-audio-so.h @@ -37,10 +37,15 @@ class OpenSLContext : public AudioContext { SLAndroidSimpleBufferQueueItf bqPlayerBufferQueue = nullptr; SLVolumeItf bqPlayerVolume = nullptr; + // Should be no reason to need more than two buffers, but make it clear in the code. + enum { + NUM_BUFFERS = 2, + }; + // Double buffering. - short *buffer[2]{}; + short *buffer[NUM_BUFFERS]{}; int curBuffer = 0; static void bqPlayerCallbackWrap(SLAndroidSimpleBufferQueueItf bq, void *context); void BqPlayerCallback(SLAndroidSimpleBufferQueueItf bq); -}; \ No newline at end of file +};