いきなり起動したものの、ROMフォルダを選択するとSDLの世界に戻りますので、AUDIO初期化あたりでSIGSEGVで落ちます。
W/Qt (22339): QCommonStyle::drawComplexControl: Control 1 not handled W/Qt (22339): QCommonStyle::drawComplexControl: Control 1 not handled W/Qt (22339): QCommonStyle::drawComplexControl: Control 1 not handled D/Qt (22339): keyUp W/Qt (22339): QCommonStyle::drawComplexControl: Control 1 not handled D/Qt (22339): keyDown D/Qt (22339): keyUp D/Qt (22339): resetSoftwareKeyboard D/Qt (22339): hideSoftwareKeyboard V/SDL (22339): SDL audio: opening device
実は、AndroidのSDLは完全なNativeではなくVIDEO、AUDIO、KEYBOARDなどの入出力はJavaで実装していて、JNIでCからJavaを呼び出しています。(逆にJavaからCの呼び出しもあります)
という訳でまずは、AUDIO周りのJNIを修正していきます。
/******************************************************************************* Globals *******************************************************************************/ ///static JNIEnv* mEnv = NULL; static JNIEnv* mAudioEnv = NULL; static JavaVM* s_javaVM = NULL; (省略) // Library init extern "C" jint JNI_OnLoad(JavaVM* vm, void* reserved) { JNIEnv* env; if (vm->GetEnv(reinterpret_cast<void**>(&env), JNI_VERSION_1_4) != JNI_OK) { __android_log_print(ANDROID_LOG_INFO, "SDL", "Can't get the enviroument"); return -1; } s_javaVM = vm; // search for our class jclass clazz=env->FindClass("org/kde/necessitas/origo/QtActivity"); if (!clazz) { __android_log_print(ANDROID_LOG_INFO, "SDL", "Can't find QtActivity class"); return -1; } mActivityClass = (jclass)env->NewGlobalRef(clazz); ///} /// Called before SDL_main() to initialize JNI bindings /// extern "C" void SDL_Android_Init(JNIEnv* env, jclass cls) /// { __android_log_print(ANDROID_LOG_INFO, "SDL", "SDL_Android_Init()"); /// /// mEnv = env; /// mActivityClass = cls; /// /// midCreateGLContext = mEnv->GetStaticMethodID(mActivityClass, /// "createGLContext","(II)Z"); /// midFlipBuffers = mEnv->GetStaticMethodID(mActivityClass, /// "flipBuffers","()V"); /// midAudioInit = mEnv->GetStaticMethodID(mActivityClass, /// "audioInit", "(IZZI)Ljava/lang/Object;"); midAudioInit = env->GetStaticMethodID(mActivityClass, "audioInit", "(IZZI)Ljava/lang/Object;"); /// midAudioWriteShortBuffer = mEnv->GetStaticMethodID(mActivityClass, /// "audioWriteShortBuffer", "([S)V"); midAudioWriteShortBuffer = env->GetStaticMethodID(mActivityClass, "audioWriteShortBuffer", "([S)V"); /// midAudioWriteByteBuffer = mEnv->GetStaticMethodID(mActivityClass, /// "audioWriteByteBuffer", "([B)V"); midAudioWriteByteBuffer = env->GetStaticMethodID(mActivityClass, "audioWriteByteBuffer", "([B)V"); /// midAudioQuit = mEnv->GetStaticMethodID(mActivityClass, /// "audioQuit", "()V"); midAudioQuit = env->GetStaticMethodID(mActivityClass, "audioQuit", "()V"); /// if(!midCreateGLContext || !midFlipBuffers || !midAudioInit || /// !midAudioWriteShortBuffer || !midAudioWriteByteBuffer || !midAudioQuit) { if(!midAudioInit || !midAudioWriteShortBuffer || !midAudioWriteByteBuffer || !midAudioQuit) { __android_log_print(ANDROID_LOG_WARN, "SDL", "SDL: Couldn't locate Java callbacks, check that they're named and typed correctly"); } return JNI_VERSION_1_4; } (省略) /// extern "C" void Java_org_libsdl_app_SDLActivity_nativeRunAudioThread( extern "C" void Java_org_kde_necessitas_origo_QtActivity_nativeRunAudioThread( JNIEnv* env, jclass cls) { /* This is the audio thread, with a different environment */ mAudioEnv = env; Android_RunAudioThread(); } /******************************************************************************* Functions called by SDL into Java *******************************************************************************/ extern "C" SDL_bool Android_JNI_CreateContext(int majorVersion, int minorVersion) { /// if (mEnv->CallStaticBooleanMethod(mActivityClass, midCreateGLContext, majorVersion, minorVersion)) { /// return SDL_TRUE; /// } else { return SDL_FALSE; /// } } extern "C" void Android_JNI_SwapWindow() { /// mEnv->CallStaticVoidMethod(mActivityClass, midFlipBuffers); } extern "C" void Android_JNI_SetActivityTitle(const char *title) { /// jmethodID mid; /// /// mid = mEnv->GetStaticMethodID(mActivityClass,"setActivityTitle","(Ljava/lang/String;)V"); /// if (mid) { /// mEnv->CallStaticVoidMethod(mActivityClass, mid, mEnv->NewStringUTF(title)); /// } } (省略) extern "C" int Android_JNI_OpenAudioDevice(int sampleRate, int is16Bit, int channelCount, int desiredBufferFrames) { int audioBufferFrames; __android_log_print(ANDROID_LOG_VERBOSE, "SDL", "SDL audio: opening device"); audioBuffer16Bit = is16Bit; audioBufferStereo = channelCount > 1; /// audioBuffer = mEnv->CallStaticObjectMethod(mActivityClass, midAudioInit, sampleRate, audioBuffer16Bit, audioBufferStereo, desiredBufferFrames); JNIEnv* env; if (s_javaVM->AttachCurrentThread(&env, NULL) < 0) { __android_log_print(ANDROID_LOG_VERBOSE, "SDL", "AttachCurrentThread failed"); return 0; } audioBuffer = env->CallStaticObjectMethod(mActivityClass, midAudioInit, sampleRate, audioBuffer16Bit, audioBufferStereo, desiredBufferFrames); if (audioBuffer == NULL) { __android_log_print(ANDROID_LOG_WARN, "SDL", "SDL audio: didn't get back a good audio buffer!"); return 0; } /// audioBuffer = mEnv->NewGlobalRef(audioBuffer); audioBuffer = env->NewGlobalRef(audioBuffer); jboolean isCopy = JNI_FALSE; if (audioBuffer16Bit) { /// audioBufferPinned = mEnv->GetShortArrayElements((jshortArray)audioBuffer, &isCopy); /// audioBufferFrames = mEnv->GetArrayLength((jshortArray)audioBuffer); audioBufferPinned = env->GetShortArrayElements((jshortArray)audioBuffer, &isCopy); audioBufferFrames = env->GetArrayLength((jshortArray)audioBuffer); } else { /// audioBufferPinned = mEnv->GetByteArrayElements((jbyteArray)audioBuffer, &isCopy); /// audioBufferFrames = mEnv->GetArrayLength((jbyteArray)audioBuffer); audioBufferPinned = env->GetByteArrayElements((jbyteArray)audioBuffer, &isCopy); audioBufferFrames = env->GetArrayLength((jbyteArray)audioBuffer); } if (audioBufferStereo) { audioBufferFrames /= 2; } s_javaVM->DetachCurrentThread(); return audioBufferFrames; } (省略) extern "C" void Android_JNI_CloseAudioDevice() { JNIEnv* env; if (s_javaVM->AttachCurrentThread(&env, NULL) < 0) { __android_log_print(ANDROID_LOG_VERBOSE, "SDL", "AttachCurrentThread failed"); return; } /// mEnv->CallStaticVoidMethod(mActivityClass, midAudioQuit); env->CallStaticVoidMethod(mActivityClass, midAudioQuit); if (audioBuffer) { /// mEnv->DeleteGlobalRef(audioBuffer); env->DeleteGlobalRef(audioBuffer); audioBuffer = NULL; audioBufferPinned = NULL; } s_javaVM->DetachCurrentThread(); }
QtActivity.java
//@ANDROID-11 //QtCreator import android.app.Fragment; //QtCreator import android.view.ActionMode; //QtCreator import android.view.ActionMode.Callback; //@ANDROID-11 import android.app.*; import android.content.*; import android.view.*; import android.os.*; import android.util.Log; import android.graphics.*; import android.text.method.*; import android.text.*; import android.media.*; import android.hardware.*; import java.lang.*; (省略) /// C functions we call public static native void nativeRunAudioThread(); private static Thread mAudioThread; private static AudioTrack mAudioTrack; /* Java functions called from C */ private static Object buf; public static Object audioInit(int sampleRate, boolean is16Bit, boolean isStereo, int desiredFrames) { int channelConfig = isStereo ? AudioFormat.CHANNEL_CONFIGURATION_STEREO : AudioFormat.CHANNEL_CONFIGURATION_MONO; int audioFormat = is16Bit ? AudioFormat.ENCODING_PCM_16BIT : AudioFormat.ENCODING_PCM_8BIT; int frameSize = (isStereo ? 2 : 1) * (is16Bit ? 2 : 1); Log.v("SDL", "SDL audio: wanted " + (isStereo ? "stereo" : "mono") + " " + (is16Bit ? "16-bit" : "8-bit") + " " + ((float)sampleRate / 1000f) + "kHz, " + desiredFrames + " frames buffer"); // Let the user pick a larger buffer if they really want -- but ye // gods they probably shouldn't, the minimums are horrifyingly high // latency already desiredFrames = Math.max(desiredFrames, (AudioTrack.getMinBufferSize(sampleRate, channelConfig, audioFormat) + frameSize - 1) / frameSize); mAudioTrack = new AudioTrack(AudioManager.STREAM_MUSIC, sampleRate, channelConfig, audioFormat, desiredFrames * frameSize, AudioTrack.MODE_STREAM); audioStartThread(); Log.v("SDL", "SDL audio: got " + ((mAudioTrack.getChannelCount() >= 2) ? "stereo" : "mono") + " " + ((mAudioTrack.getAudioFormat() == AudioFormat.ENCODING_PCM_16BIT) ? "16-bit" : "8-bit") + " " + ((float)mAudioTrack.getSampleRate() / 1000f) + "kHz, " + desiredFrames + " frames buffer"); if (is16Bit) { buf = new short[desiredFrames * (isStereo ? 2 : 1)]; } else { buf = new byte[desiredFrames * (isStereo ? 2 : 1)]; } return buf; } public static void audioStartThread() { mAudioThread = new Thread(new Runnable() { public void run() { mAudioTrack.play(); nativeRunAudioThread(); } }); // I'd take REALTIME if I could get it! mAudioThread.setPriority(Thread.MAX_PRIORITY); mAudioThread.start(); } public static void audioWriteShortBuffer(short[] buffer) { for (int i = 0; i < buffer.length; ) { int result = mAudioTrack.write(buffer, i, buffer.length - i); if (result > 0) { i += result; } else if (result == 0) { try { Thread.sleep(1); } catch(InterruptedException e) { // Nom nom } } else { Log.w("SDL", "SDL audio: error return from write(short)"); return; } } } public static void audioWriteByteBuffer(byte[] buffer) { for (int i = 0; i < buffer.length; ) { int result = mAudioTrack.write(buffer, i, buffer.length - i); if (result > 0) { i += result; } else if (result == 0) { try { Thread.sleep(1); } catch(InterruptedException e) { // Nom nom } } else { Log.w("SDL", "SDL audio: error return from write(short)"); return; } } } public static void audioQuit() { if (mAudioThread != null) { try { mAudioThread.join(); } catch(Exception e) { Log.v("SDL", "Problem stopping audio thread: " + e); } mAudioThread = null; //Log.v("SDL", "Finished waiting for audio thread"); } if (mAudioTrack != null) { mAudioTrack.stop(); mAudioTrack = null; } }
SIGSEGVでは落ちなくなりましたが初期化で失敗しています。