mirror of
https://github.com/hrydgard/ppsspp.git
synced 2026-07-11 01:25:07 +02:00
Start work on using OpenSL conditionally (to still support Android 2.2)
This commit is contained in:
+16
-3
@@ -21,6 +21,7 @@
|
||||
#include "input/input_state.h"
|
||||
#include "audio/mixer.h"
|
||||
#include "math/math_util.h"
|
||||
#include "android/native_audio.h"
|
||||
|
||||
#define coord_xres 480
|
||||
#define coord_yres 800
|
||||
@@ -81,6 +82,7 @@ InputState input_state;
|
||||
|
||||
static bool renderer_inited = false;
|
||||
static bool first_lost = true;
|
||||
static bool use_native_audio = false;
|
||||
|
||||
extern "C" jboolean Java_com_turboviking_libnative_NativeApp_isLandscape(JNIEnv *env, jclass) {
|
||||
std::string app_name, app_nice_name;
|
||||
@@ -91,13 +93,13 @@ extern "C" jboolean Java_com_turboviking_libnative_NativeApp_isLandscape(JNIEnv
|
||||
|
||||
extern "C" void Java_com_turboviking_libnative_NativeApp_init
|
||||
(JNIEnv *env, jclass, jint xxres, jint yyres, jstring apkpath,
|
||||
jstring dataDir, jstring externalDir, jstring jinstallID) {
|
||||
jstring dataDir, jstring externalDir, jstring jinstallID, jboolean juseNativeAudio) {
|
||||
jniEnvUI = env;
|
||||
pixel_xres = xxres;
|
||||
pixel_yres = yyres;
|
||||
g_xres = xxres;
|
||||
g_yres = yyres;
|
||||
|
||||
use_native_audio = juseNativeAudio;
|
||||
if (g_xres < g_yres)
|
||||
{
|
||||
// Portrait - let's force the imaginary resolution we want
|
||||
@@ -124,7 +126,8 @@ extern "C" void Java_com_turboviking_libnative_NativeApp_init
|
||||
str = env->GetStringUTFChars(jinstallID, &isCopy);
|
||||
std::string installID = std::string(str);
|
||||
|
||||
std::string app_name, app_nice_name;
|
||||
std::string app_name;
|
||||
std::string app_nice_name;
|
||||
bool landscape;
|
||||
|
||||
NativeGetAppInfo(&app_name, &app_nice_name, &landscape);
|
||||
@@ -275,3 +278,13 @@ extern "C" void JNICALL Java_com_turboviking_libnative_NativeApp_accelerometer
|
||||
input_state.acc.y = y;
|
||||
input_state.acc.z = z;
|
||||
}
|
||||
|
||||
extern "C" void Java_com_turboviking_libnative_NativeApp_sendMessage
|
||||
(JNIEnv *env, jclass, jstring message, jstring param) {
|
||||
jboolean isCopy;
|
||||
std::string msg(env->GetStringUTFChars(message, &isCopy));
|
||||
std::string prm(env->GetStringUTFChars(param, &isCopy));
|
||||
ILOG("Message received: %s %s", msg.c_str(), prm.c_str());
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,200 @@
|
||||
/*
|
||||
* Copyright (C) 2010 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
*/
|
||||
|
||||
/* This is a JNI example where we use native methods to play sounds
|
||||
* using OpenSL ES. See the corresponding Java source file located at:
|
||||
*
|
||||
* src/com/example/nativeaudio/NativeAudio/NativeAudio.java
|
||||
*/
|
||||
|
||||
#include <assert.h>
|
||||
#include <string.h>
|
||||
|
||||
// for __android_log_print(ANDROID_LOG_INFO, "YourApp", "formatted message");
|
||||
// #include <android/log.h>
|
||||
|
||||
// for native audio
|
||||
#include <SLES/OpenSLES.h>
|
||||
#include <SLES/OpenSLES_Android.h>
|
||||
|
||||
// engine interfaces
|
||||
static SLObjectItf engineObject = NULL;
|
||||
static SLEngineItf engineEngine;
|
||||
|
||||
// output mix interfaces
|
||||
static SLObjectItf outputMixObject = NULL;
|
||||
static SLEnvironmentalReverbItf outputMixEnvironmentalReverb = NULL;
|
||||
|
||||
// buffer queue player interfaces
|
||||
static SLObjectItf bqPlayerObject = NULL;
|
||||
static SLPlayItf bqPlayerPlay;
|
||||
static SLAndroidSimpleBufferQueueItf bqPlayerBufferQueue;
|
||||
static SLMuteSoloItf bqPlayerMuteSolo;
|
||||
static SLVolumeItf bqPlayerVolume;
|
||||
|
||||
// synthesized sawtooth clip
|
||||
#define SAWTOOTH_FRAMES 8000
|
||||
static short sawtoothBuffer[SAWTOOTH_FRAMES];
|
||||
|
||||
// pointer and size of the next player buffer to enqueue, and number of remaining buffers
|
||||
static short *nextBuffer;
|
||||
static unsigned nextSize;
|
||||
|
||||
// synthesize a mono sawtooth wave and place it into a buffer (called automatically on load)
|
||||
__attribute__((constructor)) static void onDlOpen(void)
|
||||
{
|
||||
unsigned int i;
|
||||
for (i = 0; i < SAWTOOTH_FRAMES; ++i) {
|
||||
sawtoothBuffer[i] = 32768 - ((i % 100) * 660);
|
||||
}
|
||||
}
|
||||
|
||||
// this callback handler is called every time a buffer finishes playing
|
||||
void bqPlayerCallback(SLAndroidSimpleBufferQueueItf bq, void *context)
|
||||
{
|
||||
assert(bq == bqPlayerBufferQueue);
|
||||
assert(NULL == context);
|
||||
|
||||
|
||||
nextBuffer = sawtoothBuffer;
|
||||
nextSize = sizeof(sawtoothBuffer);
|
||||
SLresult result;
|
||||
// enqueue another buffer
|
||||
result = (*bqPlayerBufferQueue)->Enqueue(bqPlayerBufferQueue, nextBuffer, nextSize);
|
||||
// the most likely other result is SL_RESULT_BUFFER_INSUFFICIENT,
|
||||
// which for this code example would indicate a programming error
|
||||
assert(SL_RESULT_SUCCESS == result);
|
||||
}
|
||||
|
||||
// create the engine and output mix objects
|
||||
extern "C" bool OpenSLWrap_Init()
|
||||
{
|
||||
SLresult result;
|
||||
|
||||
// create engine
|
||||
result = slCreateEngine(&engineObject, 0, NULL, 0, NULL, NULL);
|
||||
assert(SL_RESULT_SUCCESS == result);
|
||||
|
||||
// realize the engine
|
||||
result = (*engineObject)->Realize(engineObject, SL_BOOLEAN_FALSE);
|
||||
assert(SL_RESULT_SUCCESS == result);
|
||||
|
||||
// get the engine interface, which is needed in order to create other objects
|
||||
result = (*engineObject)->GetInterface(engineObject, SL_IID_ENGINE, &engineEngine);
|
||||
assert(SL_RESULT_SUCCESS == result);
|
||||
|
||||
// create output mix, with environmental reverb specified as a non-required interface
|
||||
const SLInterfaceID ids1[1] = {SL_IID_ENVIRONMENTALREVERB};
|
||||
const SLboolean req1[1] = {SL_BOOLEAN_FALSE};
|
||||
result = (*engineEngine)->CreateOutputMix(engineEngine, &outputMixObject, 1, ids1, req1);
|
||||
assert(SL_RESULT_SUCCESS == result);
|
||||
|
||||
// realize the output mix
|
||||
result = (*outputMixObject)->Realize(outputMixObject, SL_BOOLEAN_FALSE);
|
||||
assert(SL_RESULT_SUCCESS == result);
|
||||
|
||||
// create buffer queue audio player
|
||||
// ================================
|
||||
|
||||
// configure audio source
|
||||
SLDataLocator_AndroidSimpleBufferQueue loc_bufq = {SL_DATALOCATOR_ANDROIDSIMPLEBUFFERQUEUE, 2};
|
||||
|
||||
// TODO: This is all wrong.
|
||||
SLDataFormat_PCM format_pcm = {
|
||||
SL_DATAFORMAT_PCM,
|
||||
1,
|
||||
SL_SAMPLINGRATE_8,
|
||||
SL_PCMSAMPLEFORMAT_FIXED_16,
|
||||
SL_PCMSAMPLEFORMAT_FIXED_16,
|
||||
SL_SPEAKER_FRONT_CENTER,
|
||||
SL_BYTEORDER_LITTLEENDIAN};
|
||||
|
||||
SLDataSource audioSrc = {&loc_bufq, &format_pcm};
|
||||
|
||||
// configure audio sink
|
||||
SLDataLocator_OutputMix loc_outmix = {SL_DATALOCATOR_OUTPUTMIX, outputMixObject};
|
||||
SLDataSink audioSnk = {&loc_outmix, NULL};
|
||||
|
||||
// create audio player
|
||||
const SLInterfaceID ids[3] = {SL_IID_BUFFERQUEUE, SL_IID_VOLUME};
|
||||
const SLboolean req[3] = {SL_BOOLEAN_TRUE, SL_BOOLEAN_TRUE};
|
||||
result = (*engineEngine)->CreateAudioPlayer(engineEngine, &bqPlayerObject, &audioSrc, &audioSnk,
|
||||
3, ids, req);
|
||||
assert(SL_RESULT_SUCCESS == result);
|
||||
|
||||
// realize the player
|
||||
result = (*bqPlayerObject)->Realize(bqPlayerObject, SL_BOOLEAN_FALSE);
|
||||
assert(SL_RESULT_SUCCESS == result);
|
||||
|
||||
// get the play interface
|
||||
result = (*bqPlayerObject)->GetInterface(bqPlayerObject, SL_IID_PLAY, &bqPlayerPlay);
|
||||
assert(SL_RESULT_SUCCESS == result);
|
||||
|
||||
// get the buffer queue interface
|
||||
result = (*bqPlayerObject)->GetInterface(bqPlayerObject, SL_IID_BUFFERQUEUE,
|
||||
&bqPlayerBufferQueue);
|
||||
assert(SL_RESULT_SUCCESS == result);
|
||||
|
||||
// register callback on the buffer queue
|
||||
result = (*bqPlayerBufferQueue)->RegisterCallback(bqPlayerBufferQueue, bqPlayerCallback, NULL);
|
||||
assert(SL_RESULT_SUCCESS == result);
|
||||
|
||||
// get the volume interface
|
||||
result = (*bqPlayerObject)->GetInterface(bqPlayerObject, SL_IID_VOLUME, &bqPlayerVolume);
|
||||
assert(SL_RESULT_SUCCESS == result);
|
||||
|
||||
// set the player's state to playing
|
||||
result = (*bqPlayerPlay)->SetPlayState(bqPlayerPlay, SL_PLAYSTATE_PLAYING);
|
||||
assert(SL_RESULT_SUCCESS == result);
|
||||
|
||||
if (nextBuffer) {
|
||||
SLresult result;
|
||||
result = (*bqPlayerBufferQueue)->Enqueue(bqPlayerBufferQueue, nextBuffer, nextSize);
|
||||
if (SL_RESULT_SUCCESS != result) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// shut down the native audio system
|
||||
extern "C" void OpenSLWrap_Shutdown()
|
||||
{
|
||||
// destroy buffer queue audio player object, and invalidate all associated interfaces
|
||||
if (bqPlayerObject != NULL) {
|
||||
(*bqPlayerObject)->Destroy(bqPlayerObject);
|
||||
bqPlayerObject = NULL;
|
||||
bqPlayerPlay = NULL;
|
||||
bqPlayerBufferQueue = NULL;
|
||||
bqPlayerMuteSolo = NULL;
|
||||
bqPlayerVolume = NULL;
|
||||
}
|
||||
|
||||
// destroy output mix object, and invalidate all associated interfaces
|
||||
if (outputMixObject != NULL) {
|
||||
(*outputMixObject)->Destroy(outputMixObject);
|
||||
outputMixObject = NULL;
|
||||
outputMixEnvironmentalReverb = NULL;
|
||||
}
|
||||
|
||||
// destroy engine object, and invalidate all associated interfaces
|
||||
if (engineObject != NULL) {
|
||||
(*engineObject)->Destroy(engineObject);
|
||||
engineObject = NULL;
|
||||
engineEngine = NULL;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
#pragma once
|
||||
|
||||
// Header for dynamic loading
|
||||
|
||||
typedef void (*AndroidAudioCallback)(short *buffer, int num_samples);
|
||||
|
||||
typedef bool (*OpenSLWrap_Init_T)(AndroidAudioCallback cb);
|
||||
typedef void (*OpenSLWrap_Shutdown_T)();
|
||||
@@ -0,0 +1,34 @@
|
||||
#include <dlfcn.h>
|
||||
|
||||
#include "base/logging.h"
|
||||
#include "android/native_audio.h"
|
||||
#include "android/native-audio-so.h"
|
||||
|
||||
static void *so;
|
||||
static OpenSLWrap_Init_T init_func;
|
||||
static OpenSLWrap_Shutdown_T shutdown_func;
|
||||
|
||||
bool AndroidAudio_Init(AndroidAudioCallback cb) {
|
||||
ILOG("Loading native audio library...");
|
||||
so = dlopen("libnative_audio.so", RTLD_NOW);
|
||||
if (!so) {
|
||||
ELOG("Failed to find native audio library");
|
||||
return false;
|
||||
}
|
||||
init_func = (OpenSLWrap_Init_T)dlsym(so, "OpenSLWrap_Init");
|
||||
shutdown_func = (OpenSLWrap_Shutdown_T)dlsym(so, "OpenSLWrap_Shutdown");
|
||||
|
||||
ILOG("Calling OpenSLWrap_Init_T...");
|
||||
bool init_retval = init_func(cb);
|
||||
ILOG("Returned from OpenSLWrap_Init_T");
|
||||
return init_retval;
|
||||
}
|
||||
|
||||
|
||||
void AndroidAudio_Shutdown() {
|
||||
ILOG("Calling OpenSLWrap_Shutdown_T...");
|
||||
shutdown_func();
|
||||
ILOG("Returned from OpenSLWrap_Shutdown_T");
|
||||
dlclose(so);
|
||||
so = 0;
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
#pragma once
|
||||
|
||||
#include "native-audio-so.h"
|
||||
|
||||
// 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.
|
||||
|
||||
bool AndroidAudio_Init(AndroidAudioCallback cb);
|
||||
void AndroidAudio_Shutdown();
|
||||
@@ -86,6 +86,7 @@ public class NativeActivity extends Activity {
|
||||
private GLSurfaceView mGLSurfaceView;
|
||||
private NativeAudioPlayer audioPlayer;
|
||||
|
||||
boolean useOpenSL = false;
|
||||
|
||||
public static String runCommand;
|
||||
public static String commandParameter;
|
||||
@@ -121,7 +122,8 @@ public class NativeActivity extends Activity {
|
||||
String externalStorageDir = sdcard.getAbsolutePath();
|
||||
String dataDir = this.getFilesDir().getAbsolutePath();
|
||||
String apkFilePath = appInfo.sourceDir;
|
||||
NativeApp.init(scrWidth, scrHeight, apkFilePath, dataDir, externalStorageDir, installID);
|
||||
NativeApp.sendMessage("Message from Java", "Hot Coffee");
|
||||
NativeApp.init(scrWidth, scrHeight, apkFilePath, dataDir, externalStorageDir, installID, useOpenSL);
|
||||
|
||||
// Keep the screen bright - very annoying if it goes dark when tilting away
|
||||
Window window = this.getWindow();
|
||||
@@ -143,7 +145,8 @@ public class NativeActivity extends Activity {
|
||||
// Native OpenSL is available. Let's not use the Java player in the future.
|
||||
// TODO: code for that.
|
||||
}
|
||||
audioPlayer = new NativeAudioPlayer();
|
||||
if (!useOpenSL)
|
||||
audioPlayer = new NativeAudioPlayer();
|
||||
}
|
||||
|
||||
private boolean detectOpenGLES20() {
|
||||
|
||||
@@ -4,7 +4,7 @@ public class NativeApp {
|
||||
public static native boolean isLandscape();
|
||||
public static native void init(
|
||||
int xxres, int yyres, String apkPath,
|
||||
String dataDir, String externalDir, String installID);
|
||||
String dataDir, String externalDir, String installID, boolean useOpenSL);
|
||||
public static native void shutdown();
|
||||
|
||||
public static native void keyDown(int key);
|
||||
@@ -16,4 +16,6 @@ public class NativeApp {
|
||||
// Sensor/input data. These are asynchronous, beware!
|
||||
public static native void touch(float x, float y, int data, int pointerId);
|
||||
public static native void accelerometer(float x, float y, float z);
|
||||
|
||||
public static native void sendMessage(String msg, String arg);
|
||||
}
|
||||
Reference in New Issue
Block a user