src/core/android/SDL_android.cpp
author Sam Lantinga <slouken@libsdl.org>
Fri, 08 Apr 2011 13:03:26 -0700
changeset 5535 96594ac5fd1a
parent 5262 b530ef003506
child 5582 1281a3f1f0a6
permissions -rw-r--r--
SDL 1.3 is now under the zlib license.
     1 /*
     2   Simple DirectMedia Layer
     3   Copyright (C) 1997-2011 Sam Lantinga <slouken@libsdl.org>
     4 
     5   This software is provided 'as-is', without any express or implied
     6   warranty.  In no event will the authors be held liable for any damages
     7   arising from the use of this software.
     8 
     9   Permission is granted to anyone to use this software for any purpose,
    10   including commercial applications, and to alter it and redistribute it
    11   freely, subject to the following restrictions:
    12 
    13   1. The origin of this software must not be misrepresented; you must not
    14      claim that you wrote the original software. If you use this software
    15      in a product, an acknowledgment in the product documentation would be
    16      appreciated but is not required.
    17   2. Altered source versions must be plainly marked as such, and must not be
    18      misrepresented as being the original software.
    19   3. This notice may not be removed or altered from any source distribution.
    20 */
    21 #include "SDL_config.h"
    22 #include "SDL_stdinc.h"
    23 
    24 #include "SDL_android.h"
    25 
    26 extern "C" {
    27 #include "../../events/SDL_events_c.h"
    28 #include "../../video/android/SDL_androidkeyboard.h"
    29 #include "../../video/android/SDL_androidtouch.h"
    30 #include "../../video/android/SDL_androidvideo.h"
    31 
    32 /* Impelemented in audio/android/SDL_androidaudio.c */
    33 extern void Android_RunAudioThread();
    34 } // C
    35 
    36 /*******************************************************************************
    37  This file links the Java side of Android with libsdl
    38 *******************************************************************************/
    39 #include <jni.h>
    40 #include <android/log.h>
    41 
    42 
    43 /*******************************************************************************
    44                                Globals
    45 *******************************************************************************/
    46 static JNIEnv* mEnv = NULL;
    47 static JNIEnv* mAudioEnv = NULL;
    48 
    49 // Main activity
    50 static jclass mActivityClass;
    51 
    52 // method signatures
    53 static jmethodID midCreateGLContext;
    54 static jmethodID midFlipBuffers;
    55 static jmethodID midAudioInit;
    56 static jmethodID midAudioWriteShortBuffer;
    57 static jmethodID midAudioWriteByteBuffer;
    58 static jmethodID midAudioQuit;
    59 
    60 // Accelerometer data storage
    61 static float fLastAccelerometer[3];
    62 
    63 
    64 /*******************************************************************************
    65                  Functions called by JNI
    66 *******************************************************************************/
    67 
    68 // Library init
    69 extern "C" jint JNI_OnLoad(JavaVM* vm, void* reserved)
    70 {
    71     return JNI_VERSION_1_4;
    72 }
    73 
    74 // Called before SDL_main() to initialize JNI bindings
    75 extern "C" void SDL_Android_Init(JNIEnv* env, jclass cls)
    76 {
    77     __android_log_print(ANDROID_LOG_INFO, "SDL", "SDL_Android_Init()");
    78 
    79     mEnv = env;
    80     mActivityClass = cls;
    81 
    82     midCreateGLContext = mEnv->GetStaticMethodID(mActivityClass,
    83                                 "createGLContext","(II)Z");
    84     midFlipBuffers = mEnv->GetStaticMethodID(mActivityClass,
    85                                 "flipBuffers","()V");
    86     midAudioInit = mEnv->GetStaticMethodID(mActivityClass, 
    87                                 "audioInit", "(IZZI)Ljava/lang/Object;");
    88     midAudioWriteShortBuffer = mEnv->GetStaticMethodID(mActivityClass,
    89                                 "audioWriteShortBuffer", "([S)V");
    90     midAudioWriteByteBuffer = mEnv->GetStaticMethodID(mActivityClass,
    91                                 "audioWriteByteBuffer", "([B)V");
    92     midAudioQuit = mEnv->GetStaticMethodID(mActivityClass,
    93                                 "audioQuit", "()V");
    94 
    95     if(!midCreateGLContext || !midFlipBuffers || !midAudioInit ||
    96        !midAudioWriteShortBuffer || !midAudioWriteByteBuffer || !midAudioQuit) {
    97         __android_log_print(ANDROID_LOG_WARN, "SDL", "SDL: Couldn't locate Java callbacks, check that they're named and typed correctly");
    98     }
    99 }
   100 
   101 // Resize
   102 extern "C" void Java_org_libsdl_app_SDLActivity_onNativeResize(
   103                                     JNIEnv* env, jclass jcls,
   104                                     jint width, jint height, jint format)
   105 {
   106     Android_SetScreenResolution(width, height, format);
   107 }
   108 
   109 // Keydown
   110 extern "C" void Java_org_libsdl_app_SDLActivity_onNativeKeyDown(
   111                                     JNIEnv* env, jclass jcls, jint keycode)
   112 {
   113     Android_OnKeyDown(keycode);
   114 }
   115 
   116 // Keyup
   117 extern "C" void Java_org_libsdl_app_SDLActivity_onNativeKeyUp(
   118                                     JNIEnv* env, jclass jcls, jint keycode)
   119 {
   120     Android_OnKeyUp(keycode);
   121 }
   122 
   123 // Touch
   124 extern "C" void Java_org_libsdl_app_SDLActivity_onNativeTouch(
   125                                     JNIEnv* env, jclass jcls,
   126                                     jint action, jfloat x, jfloat y, jfloat p)
   127 {
   128     Android_OnTouch(action, x, y, p);
   129 }
   130 
   131 // Accelerometer
   132 extern "C" void Java_org_libsdl_app_SDLActivity_onNativeAccel(
   133                                     JNIEnv* env, jclass jcls,
   134                                     jfloat x, jfloat y, jfloat z)
   135 {
   136     fLastAccelerometer[0] = x;
   137     fLastAccelerometer[1] = y;
   138     fLastAccelerometer[2] = z;   
   139 }
   140 
   141 // Quit
   142 extern "C" void Java_org_libsdl_app_SDLActivity_nativeQuit(
   143                                     JNIEnv* env, jclass cls)
   144 {    
   145     // Inject a SDL_QUIT event
   146     SDL_SendQuit();
   147 }
   148 
   149 extern "C" void Java_org_libsdl_app_SDLActivity_nativeRunAudioThread(
   150                                     JNIEnv* env, jclass cls)
   151 {
   152     /* This is the audio thread, with a different environment */
   153     mAudioEnv = env;
   154 
   155     Android_RunAudioThread();
   156 }
   157 
   158 
   159 /*******************************************************************************
   160              Functions called by SDL into Java
   161 *******************************************************************************/
   162 extern "C" SDL_bool Android_JNI_CreateContext(int majorVersion, int minorVersion)
   163 {
   164     if (mEnv->CallStaticBooleanMethod(mActivityClass, midCreateGLContext, majorVersion, minorVersion)) {
   165         return SDL_TRUE;
   166     } else {
   167         return SDL_FALSE;
   168     }
   169 }
   170 
   171 extern "C" void Android_JNI_SwapWindow()
   172 {
   173     mEnv->CallStaticVoidMethod(mActivityClass, midFlipBuffers); 
   174 }
   175 
   176 extern "C" void Android_JNI_SetActivityTitle(const char *title)
   177 {
   178     jmethodID mid;
   179 
   180     mid = mEnv->GetStaticMethodID(mActivityClass,"setActivityTitle","(Ljava/lang/String;)V");
   181     if (mid) {
   182         mEnv->CallStaticVoidMethod(mActivityClass, mid, mEnv->NewStringUTF(title));
   183     }
   184 }
   185 
   186 extern "C" void Android_JNI_GetAccelerometerValues(float values[3])
   187 {
   188     int i;
   189     for (i = 0; i < 3; ++i) {
   190         values[i] = fLastAccelerometer[i];
   191     }
   192 }
   193 
   194 //
   195 // Audio support
   196 //
   197 static jboolean audioBuffer16Bit = JNI_FALSE;
   198 static jboolean audioBufferStereo = JNI_FALSE;
   199 static jobject audioBuffer = NULL;
   200 static void* audioBufferPinned = NULL;
   201 
   202 extern "C" int Android_JNI_OpenAudioDevice(int sampleRate, int is16Bit, int channelCount, int desiredBufferFrames)
   203 {
   204     int audioBufferFrames;
   205 
   206     __android_log_print(ANDROID_LOG_VERBOSE, "SDL", "SDL audio: opening device");
   207     audioBuffer16Bit = is16Bit;
   208     audioBufferStereo = channelCount > 1;
   209 
   210     audioBuffer = mEnv->CallStaticObjectMethod(mActivityClass, midAudioInit, sampleRate, audioBuffer16Bit, audioBufferStereo, desiredBufferFrames);
   211 
   212     if (audioBuffer == NULL) {
   213         __android_log_print(ANDROID_LOG_WARN, "SDL", "SDL audio: didn't get back a good audio buffer!");
   214         return 0;
   215     }
   216     audioBuffer = mEnv->NewGlobalRef(audioBuffer);
   217 
   218     jboolean isCopy = JNI_FALSE;
   219     if (audioBuffer16Bit) {
   220         audioBufferPinned = mEnv->GetShortArrayElements((jshortArray)audioBuffer, &isCopy);
   221         audioBufferFrames = mEnv->GetArrayLength((jshortArray)audioBuffer);
   222     } else {
   223         audioBufferPinned = mEnv->GetByteArrayElements((jbyteArray)audioBuffer, &isCopy);
   224         audioBufferFrames = mEnv->GetArrayLength((jbyteArray)audioBuffer);
   225     }
   226     if (audioBufferStereo) {
   227         audioBufferFrames /= 2;
   228     }
   229 
   230     return audioBufferFrames;
   231 }
   232 
   233 extern "C" void * Android_JNI_GetAudioBuffer()
   234 {
   235     return audioBufferPinned;
   236 }
   237 
   238 extern "C" void Android_JNI_WriteAudioBuffer()
   239 {
   240     if (audioBuffer16Bit) {
   241         mAudioEnv->ReleaseShortArrayElements((jshortArray)audioBuffer, (jshort *)audioBufferPinned, JNI_COMMIT);
   242         mAudioEnv->CallStaticVoidMethod(mActivityClass, midAudioWriteShortBuffer, (jshortArray)audioBuffer);
   243     } else {
   244         mAudioEnv->ReleaseByteArrayElements((jbyteArray)audioBuffer, (jbyte *)audioBufferPinned, JNI_COMMIT);
   245         mAudioEnv->CallStaticVoidMethod(mActivityClass, midAudioWriteByteBuffer, (jbyteArray)audioBuffer);
   246     }
   247 
   248     /* JNI_COMMIT means the changes are committed to the VM but the buffer remains pinned */
   249 }
   250 
   251 extern "C" void Android_JNI_CloseAudioDevice()
   252 {
   253     mEnv->CallStaticVoidMethod(mActivityClass, midAudioQuit); 
   254 
   255     if (audioBuffer) {
   256         mEnv->DeleteGlobalRef(audioBuffer);
   257         audioBuffer = NULL;
   258         audioBufferPinned = NULL;
   259     }
   260 }
   261 
   262 /* vi: set ts=4 sw=4 expandtab: */