Make the OpenSL wrapper an object too, to make sure it's always initialized the same.

This commit is contained in:
Henrik Rydgård 2017-08-01 15:42:47 +02:00
parent a453dc8123
commit 3ce8680d9a
5 changed files with 121 additions and 55 deletions

View File

@ -23,7 +23,8 @@
<RootNamespace>DaSh</RootNamespace>
<Keyword>Win32Proj</Keyword>
<ProjectName>PPSSPPWindows</ProjectName>
<WindowsTargetPlatformVersion></WindowsTargetPlatformVersion>
<WindowsTargetPlatformVersion>
</WindowsTargetPlatformVersion>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
@ -295,6 +296,18 @@
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|x64'">true</ExcludedFromBuild>
</ClCompile>
<ClCompile Include="..\android\jni\native-audio-so.cpp">
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|x64'">true</ExcludedFromBuild>
</ClCompile>
<ClCompile Include="..\android\jni\native_audio.cpp">
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|x64'">true</ExcludedFromBuild>
</ClCompile>
<ClCompile Include="..\android\jni\TestRunner.cpp" />
<ClCompile Include="..\ext\glew\glew.c">
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">NotUsing</PrecompiledHeader>
@ -426,6 +439,18 @@
<ClInclude Include="..\android\jni\app-android.h" />
<ClInclude Include="..\android\jni\ArmEmitterTest.h" />
<ClInclude Include="..\android\jni\Arm64EmitterTest.h" />
<ClInclude Include="..\android\jni\native-audio-so.h">
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|x64'">true</ExcludedFromBuild>
</ClInclude>
<ClInclude Include="..\android\jni\native_audio.h">
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|x64'">true</ExcludedFromBuild>
</ClInclude>
<ClInclude Include="..\android\jni\TestRunner.h" />
<ClInclude Include="..\ios\ViewController.h" />
<ClInclude Include="..\Qt\Debugger\ctrldisasmview.h" />

View File

@ -195,6 +195,12 @@
<ClCompile Include="..\android\jni\app-android.cpp">
<Filter>Other Platforms</Filter>
</ClCompile>
<ClCompile Include="..\android\jni\native_audio.cpp">
<Filter>Other Platforms</Filter>
</ClCompile>
<ClCompile Include="..\android\jni\native-audio-so.cpp">
<Filter>Other Platforms</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="Debugger\CtrlDisAsmView.h">
@ -358,6 +364,12 @@
<ClInclude Include="..\android\jni\app-android.h">
<Filter>Other Platforms</Filter>
</ClInclude>
<ClInclude Include="..\android\jni\native_audio.h">
<Filter>Other Platforms</Filter>
</ClInclude>
<ClInclude Include="..\android\jni\native-audio-so.h">
<Filter>Other Platforms</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<None Include="icon1.ico">

View File

@ -13,34 +13,32 @@
#include "../base/logging.h"
#include "native-audio-so.h"
// This is kinda ugly, but for simplicity I've left these as globals just like in the sample,
// as there's not really any use case for this where we have multiple audio devices yet.
AudioContext::AudioContext(AndroidAudioCallback cb, int _FramesPerBuffer, int _SampleRate)
: audioCallback(cb), framesPerBuffer(_FramesPerBuffer), sampleRate(_SampleRate) {
if (framesPerBuffer == 0)
framesPerBuffer = 256;
if (framesPerBuffer < 32)
framesPerBuffer = 32;
if (framesPerBuffer > 4096)
framesPerBuffer = 4096;
// engine interfaces
static SLObjectItf engineObject;
static SLEngineItf engineEngine;
static SLObjectItf outputMixObject;
// buffer queue player interfaces
static SLObjectItf bqPlayerObject = NULL;
static SLPlayItf bqPlayerPlay;
static SLAndroidSimpleBufferQueueItf bqPlayerBufferQueue;
static SLMuteSoloItf bqPlayerMuteSolo;
static SLVolumeItf bqPlayerVolume;
// Double buffering.
static short *buffer[2];
static int curBuffer = 0;
static int framesPerBuffer;
int sampleRate;
static AndroidAudioCallback audioCallback;
sampleRate = _SampleRate;
if (sampleRate != 44100 && sampleRate != 48000) {
ELOG("Invalid sample rate %i - choosing 44100", sampleRate);
sampleRate = 44100;
}
}
// This callback handler is called every time a buffer finishes playing.
// The documentation available is very unclear about how to best manage buffers.
// I've chosen to this approach: Instantly enqueue a buffer that was rendered to the last time,
// and then render the next. Hopefully it's okay to spend time in this callback after having enqueued.
static void bqPlayerCallback(SLAndroidSimpleBufferQueueItf bq, void *context) {
void OpenSLContext::bqPlayerCallbackWrap(SLAndroidSimpleBufferQueueItf bq, void *context) {
OpenSLContext *ctx = (OpenSLContext *)context;
ctx->BqPlayerCallback(bq);
}
void OpenSLContext::BqPlayerCallback(SLAndroidSimpleBufferQueueItf bq) {
if (bq != bqPlayerBufferQueue) {
ELOG("Wrong bq!");
return;
@ -66,22 +64,10 @@ static void bqPlayerCallback(SLAndroidSimpleBufferQueueItf bq, void *context) {
}
// create the engine and output mix objects
bool OpenSLWrap_Init(AndroidAudioCallback cb, int _FramesPerBuffer, int _SampleRate) {
audioCallback = cb;
framesPerBuffer = _FramesPerBuffer;
if (framesPerBuffer == 0)
framesPerBuffer = 256;
if (framesPerBuffer < 32)
framesPerBuffer = 32;
if (framesPerBuffer > 4096)
framesPerBuffer = 4096;
sampleRate = _SampleRate;
if (sampleRate != 44100 && sampleRate != 48000) {
ELOG("Invalid sample rate %i - choosing 44100", sampleRate);
sampleRate = 44100;
}
OpenSLContext::OpenSLContext(AndroidAudioCallback cb, int _FramesPerBuffer, int _SampleRate)
: AudioContext(cb, _FramesPerBuffer, _SampleRate) {}
bool OpenSLContext::Init() {
SLresult result;
// create engine
result = slCreateEngine(&engineObject, 0, NULL, 0, NULL, NULL);
@ -137,7 +123,7 @@ bool OpenSLWrap_Init(AndroidAudioCallback cb, int _FramesPerBuffer, int _SampleR
result = (*bqPlayerObject)->GetInterface(bqPlayerObject, SL_IID_BUFFERQUEUE,
&bqPlayerBufferQueue);
assert(SL_RESULT_SUCCESS == result);
result = (*bqPlayerBufferQueue)->RegisterCallback(bqPlayerBufferQueue, bqPlayerCallback, NULL);
result = (*bqPlayerBufferQueue)->RegisterCallback(bqPlayerBufferQueue, &bqPlayerCallbackWrap, this);
assert(SL_RESULT_SUCCESS == result);
result = (*bqPlayerObject)->GetInterface(bqPlayerObject, SL_IID_VOLUME, &bqPlayerVolume);
assert(SL_RESULT_SUCCESS == result);
@ -160,7 +146,7 @@ bool OpenSLWrap_Init(AndroidAudioCallback cb, int _FramesPerBuffer, int _SampleR
}
// shut down the native audio system
void OpenSLWrap_Shutdown() {
OpenSLContext::~OpenSLContext() {
if (bqPlayerPlay) {
ILOG("OpenSLWrap_Shutdown - stopping playback");
SLresult result;

View File

@ -1,6 +1,47 @@
#pragma once
#include <SLES/OpenSLES.h>
#include <SLES/OpenSLES_Android.h>
typedef int (*AndroidAudioCallback)(short *buffer, int num_samples);
bool OpenSLWrap_Init(AndroidAudioCallback cb, int _FramesPerBuffer, int _SampleRate);
void OpenSLWrap_Shutdown();
class AudioContext {
public:
AudioContext(AndroidAudioCallback cb, int _FramesPerBuffer, int _SampleRate);
virtual bool Init() { return false; }
virtual ~AudioContext() {}
protected:
AndroidAudioCallback audioCallback;
int framesPerBuffer;
int sampleRate;
};
class OpenSLContext : public AudioContext {
public:
OpenSLContext(AndroidAudioCallback cb, int framesPerBuffer, int sampleRate);
bool Init() override;
~OpenSLContext();
private:
// engine interfaces
SLObjectItf engineObject = nullptr;
SLEngineItf engineEngine = nullptr;
SLObjectItf outputMixObject = nullptr;
// buffer queue player interfaces
SLObjectItf bqPlayerObject = nullptr;
SLPlayItf bqPlayerPlay = nullptr;
SLAndroidSimpleBufferQueueItf bqPlayerBufferQueue = nullptr;
SLMuteSoloItf bqPlayerMuteSolo = nullptr;
SLVolumeItf bqPlayerVolume = nullptr;
// Double buffering.
short *buffer[2]{};
int curBuffer = 0;
static void bqPlayerCallbackWrap(SLAndroidSimpleBufferQueueItf bq, void *context);
void BqPlayerCallback(SLAndroidSimpleBufferQueueItf bq);
};

View File

@ -3,17 +3,15 @@
#include "android/jni/native-audio-so.h"
struct AndroidAudioState {
void *so;
AndroidAudioCallback callback;
bool playing;
int frames_per_buffer;
int sample_rate;
AudioContext *ctx = nullptr;
AndroidAudioCallback callback = nullptr;
int frames_per_buffer = 0;
int sample_rate = 0;
};
AndroidAudioState *AndroidAudio_Init(AndroidAudioCallback callback, std::string libraryDir, int optimalFramesPerBuffer, int optimalSampleRate) {
AndroidAudioState *state = new AndroidAudioState();
state->callback = callback;
state->playing = false;
state->frames_per_buffer = optimalFramesPerBuffer ? optimalFramesPerBuffer : 256;
state->sample_rate = optimalSampleRate ? optimalSampleRate : 44100;
return state;
@ -24,11 +22,15 @@ bool AndroidAudio_Resume(AndroidAudioState *state) {
ELOG("Audio was shutdown, cannot resume!");
return false;
}
if (!state->playing) {
if (!state->ctx) {
ILOG("Calling OpenSLWrap_Init_T...");
bool init_retval = OpenSLWrap_Init(state->callback, state->frames_per_buffer, state->sample_rate);
state->ctx = new OpenSLContext(state->callback, state->frames_per_buffer, state->sample_rate);
ILOG("Returned from OpenSLWrap_Init_T");
state->playing = true;
bool init_retval = state->ctx->Init();
if (!init_retval) {
delete state->ctx;
state->ctx = nullptr;
}
return init_retval;
}
return false;
@ -39,11 +41,11 @@ bool AndroidAudio_Pause(AndroidAudioState *state) {
ELOG("Audio was shutdown, cannot pause!");
return false;
}
if (state->playing) {
if (state->ctx) {
ILOG("Calling OpenSLWrap_Shutdown_T...");
OpenSLWrap_Shutdown();
delete state->ctx;
state->ctx = nullptr;
ILOG("Returned from OpenSLWrap_Shutdown_T ...");
state->playing = false;
return true;
}
return false;
@ -54,7 +56,7 @@ bool AndroidAudio_Shutdown(AndroidAudioState *state) {
ELOG("Audio already shutdown!");
return false;
}
if (state->playing) {
if (state->ctx) {
ELOG("Should not shut down when playing! Something is wrong!");
return false;
}