Skip to content

Commit

Permalink
Merge pull request #12333 from hrydgard/android-opensl-init-fix
Browse files Browse the repository at this point in the history
Android OpenSL initial queue fix
  • Loading branch information
hrydgard authored Sep 17, 2019
2 parents e723594 + f9bf1f9 commit 07a5adc
Show file tree
Hide file tree
Showing 5 changed files with 31 additions and 27 deletions.
2 changes: 1 addition & 1 deletion android/jni/app-android.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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");
}
Expand Down
37 changes: 21 additions & 16 deletions android/jni/native-audio-so.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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,
Expand Down Expand Up @@ -124,18 +126,20 @@ 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];

curBuffer = 0;
audioCallback(buffer[curBuffer], framesPerBuffer);
// Allocate and enqueue N empty buffers.
for (int i = 0; i < NUM_BUFFERS; i++) {
buffer[i] = new short[framesPerBuffer * 2]{};
}

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

Expand Down Expand Up @@ -174,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");
}

9 changes: 7 additions & 2 deletions android/jni/native-audio-so.h
Original file line number Diff line number Diff line change
Expand Up @@ -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);
};
};
2 changes: 1 addition & 1 deletion android/jni/native_audio.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
8 changes: 1 addition & 7 deletions android/jni/native_audio.h
Original file line number Diff line number Diff line change
Expand Up @@ -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);

0 comments on commit 07a5adc

Please sign in to comment.