Start work on using OpenSL conditionally (to still support Android 2.2)

This commit is contained in:
Henrik Rydgard
2012-07-07 22:58:27 +02:00
parent aaa15177e0
commit 3e05162dc0
7 changed files with 278 additions and 6 deletions
+16 -3
View File
@@ -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());
}
+200
View File
@@ -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;
}
}
+8
View File
@@ -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)();
+34
View File
@@ -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;
}
+12
View File
@@ -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);
}