android_media_SoundPool_SoundPoolImpl.cpp revision 55a30c41b6c47d3afe6b13c25c64e8eec9f45e7c
1/* 2 * Copyright (C) 2008 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17#include <stdio.h> 18 19//#define LOG_NDEBUG 0 20#define LOG_TAG "SoundPool-JNI" 21 22#include <utils/Log.h> 23#include <nativehelper/jni.h> 24#include <nativehelper/JNIHelp.h> 25#include <android_runtime/AndroidRuntime.h> 26#include <media/SoundPool.h> 27 28using namespace android; 29 30static struct fields_t { 31 jfieldID mNativeContext; 32 jmethodID mPostEvent; 33 jclass mSoundPoolClass; 34} fields; 35static inline SoundPool* MusterSoundPool(JNIEnv *env, jobject thiz) { 36 return (SoundPool*)env->GetLongField(thiz, fields.mNativeContext); 37} 38static const char* const kAudioAttributesClassPathName = "android/media/AudioAttributes"; 39struct audio_attributes_fields_t { 40 jfieldID fieldUsage; // AudioAttributes.mUsage 41 jfieldID fieldContentType; // AudioAttributes.mContentType 42 jfieldID fieldFlags; // AudioAttributes.mFlags 43 jfieldID fieldFormattedTags;// AudioAttributes.mFormattedTags 44}; 45static audio_attributes_fields_t javaAudioAttrFields; 46 47// ---------------------------------------------------------------------------- 48static jint 49android_media_SoundPool_SoundPoolImpl_load_URL(JNIEnv *env, jobject thiz, jstring path, jint priority) 50{ 51 ALOGV("android_media_SoundPool_SoundPoolImpl_load_URL"); 52 SoundPool *ap = MusterSoundPool(env, thiz); 53 if (path == NULL) { 54 jniThrowException(env, "java/lang/IllegalArgumentException", NULL); 55 return 0; 56 } 57 const char* s = env->GetStringUTFChars(path, NULL); 58 int id = ap->load(s, priority); 59 env->ReleaseStringUTFChars(path, s); 60 return (jint) id; 61} 62 63static jint 64android_media_SoundPool_SoundPoolImpl_load_FD(JNIEnv *env, jobject thiz, jobject fileDescriptor, 65 jlong offset, jlong length, jint priority) 66{ 67 ALOGV("android_media_SoundPool_SoundPoolImpl_load_FD"); 68 SoundPool *ap = MusterSoundPool(env, thiz); 69 if (ap == NULL) return 0; 70 return (jint) ap->load(jniGetFDFromFileDescriptor(env, fileDescriptor), 71 int64_t(offset), int64_t(length), int(priority)); 72} 73 74static jboolean 75android_media_SoundPool_SoundPoolImpl_unload(JNIEnv *env, jobject thiz, jint sampleID) { 76 ALOGV("android_media_SoundPool_SoundPoolImpl_unload\n"); 77 SoundPool *ap = MusterSoundPool(env, thiz); 78 if (ap == NULL) return JNI_FALSE; 79 return ap->unload(sampleID) ? JNI_TRUE : JNI_FALSE; 80} 81 82static jint 83android_media_SoundPool_SoundPoolImpl_play(JNIEnv *env, jobject thiz, jint sampleID, 84 jfloat leftVolume, jfloat rightVolume, jint priority, jint loop, 85 jfloat rate) 86{ 87 ALOGV("android_media_SoundPool_SoundPoolImpl_play\n"); 88 SoundPool *ap = MusterSoundPool(env, thiz); 89 if (ap == NULL) return 0; 90 return (jint) ap->play(sampleID, leftVolume, rightVolume, priority, loop, rate); 91} 92 93static void 94android_media_SoundPool_SoundPoolImpl_pause(JNIEnv *env, jobject thiz, jint channelID) 95{ 96 ALOGV("android_media_SoundPool_SoundPoolImpl_pause"); 97 SoundPool *ap = MusterSoundPool(env, thiz); 98 if (ap == NULL) return; 99 ap->pause(channelID); 100} 101 102static void 103android_media_SoundPool_SoundPoolImpl_resume(JNIEnv *env, jobject thiz, jint channelID) 104{ 105 ALOGV("android_media_SoundPool_SoundPoolImpl_resume"); 106 SoundPool *ap = MusterSoundPool(env, thiz); 107 if (ap == NULL) return; 108 ap->resume(channelID); 109} 110 111static void 112android_media_SoundPool_SoundPoolImpl_autoPause(JNIEnv *env, jobject thiz) 113{ 114 ALOGV("android_media_SoundPool_SoundPoolImpl_autoPause"); 115 SoundPool *ap = MusterSoundPool(env, thiz); 116 if (ap == NULL) return; 117 ap->autoPause(); 118} 119 120static void 121android_media_SoundPool_SoundPoolImpl_autoResume(JNIEnv *env, jobject thiz) 122{ 123 ALOGV("android_media_SoundPool_SoundPoolImpl_autoResume"); 124 SoundPool *ap = MusterSoundPool(env, thiz); 125 if (ap == NULL) return; 126 ap->autoResume(); 127} 128 129static void 130android_media_SoundPool_SoundPoolImpl_stop(JNIEnv *env, jobject thiz, jint channelID) 131{ 132 ALOGV("android_media_SoundPool_SoundPoolImpl_stop"); 133 SoundPool *ap = MusterSoundPool(env, thiz); 134 if (ap == NULL) return; 135 ap->stop(channelID); 136} 137 138static void 139android_media_SoundPool_SoundPoolImpl_setVolume(JNIEnv *env, jobject thiz, jint channelID, 140 jfloat leftVolume, jfloat rightVolume) 141{ 142 ALOGV("android_media_SoundPool_SoundPoolImpl_setVolume"); 143 SoundPool *ap = MusterSoundPool(env, thiz); 144 if (ap == NULL) return; 145 ap->setVolume(channelID, (float) leftVolume, (float) rightVolume); 146} 147 148static void 149android_media_SoundPool_SoundPoolImpl_setPriority(JNIEnv *env, jobject thiz, jint channelID, 150 jint priority) 151{ 152 ALOGV("android_media_SoundPool_SoundPoolImpl_setPriority"); 153 SoundPool *ap = MusterSoundPool(env, thiz); 154 if (ap == NULL) return; 155 ap->setPriority(channelID, (int) priority); 156} 157 158static void 159android_media_SoundPool_SoundPoolImpl_setLoop(JNIEnv *env, jobject thiz, jint channelID, 160 int loop) 161{ 162 ALOGV("android_media_SoundPool_SoundPoolImpl_setLoop"); 163 SoundPool *ap = MusterSoundPool(env, thiz); 164 if (ap == NULL) return; 165 ap->setLoop(channelID, loop); 166} 167 168static void 169android_media_SoundPool_SoundPoolImpl_setRate(JNIEnv *env, jobject thiz, jint channelID, 170 jfloat rate) 171{ 172 ALOGV("android_media_SoundPool_SoundPoolImpl_setRate"); 173 SoundPool *ap = MusterSoundPool(env, thiz); 174 if (ap == NULL) return; 175 ap->setRate(channelID, (float) rate); 176} 177 178static void android_media_callback(SoundPoolEvent event, SoundPool* soundPool, void* user) 179{ 180 ALOGV("callback: (%d, %d, %d, %p, %p)", event.mMsg, event.mArg1, event.mArg2, soundPool, user); 181 JNIEnv *env = AndroidRuntime::getJNIEnv(); 182 env->CallStaticVoidMethod(fields.mSoundPoolClass, fields.mPostEvent, user, event.mMsg, event.mArg1, event.mArg2, NULL); 183} 184 185static jint 186android_media_SoundPool_SoundPoolImpl_native_setup(JNIEnv *env, jobject thiz, jobject weakRef, 187 jint maxChannels, jobject jaa) 188{ 189 if (jaa == 0) { 190 ALOGE("Error creating SoundPool: invalid audio attributes"); 191 return -1; 192 } 193 194 audio_attributes_t *paa = NULL; 195 // read the AudioAttributes values 196 paa = (audio_attributes_t *) calloc(1, sizeof(audio_attributes_t)); 197 const jstring jtags = 198 (jstring) env->GetObjectField(jaa, javaAudioAttrFields.fieldFormattedTags); 199 const char* tags = env->GetStringUTFChars(jtags, NULL); 200 // copying array size -1, char array for tags was calloc'd, no need to NULL-terminate it 201 strncpy(paa->tags, tags, AUDIO_ATTRIBUTES_TAGS_MAX_SIZE - 1); 202 env->ReleaseStringUTFChars(jtags, tags); 203 paa->usage = (audio_usage_t) env->GetIntField(jaa, javaAudioAttrFields.fieldUsage); 204 paa->content_type = 205 (audio_content_type_t) env->GetIntField(jaa, javaAudioAttrFields.fieldContentType); 206 paa->flags = env->GetIntField(jaa, javaAudioAttrFields.fieldFlags); 207 208 ALOGV("android_media_SoundPool_SoundPoolImpl_native_setup"); 209 SoundPool *ap = new SoundPool(maxChannels, paa); 210 if (ap == NULL) { 211 return -1; 212 } 213 214 // save pointer to SoundPool C++ object in opaque field in Java object 215 env->SetLongField(thiz, fields.mNativeContext, (jlong) ap); 216 217 // set callback with weak reference 218 jobject globalWeakRef = env->NewGlobalRef(weakRef); 219 ap->setCallback(android_media_callback, globalWeakRef); 220 221 // audio attributes were copied in SoundPool creation 222 free(paa); 223 224 return 0; 225} 226 227static void 228android_media_SoundPool_SoundPoolImpl_release(JNIEnv *env, jobject thiz) 229{ 230 ALOGV("android_media_SoundPool_SoundPoolImpl_release"); 231 SoundPool *ap = MusterSoundPool(env, thiz); 232 if (ap != NULL) { 233 234 // release weak reference 235 jobject weakRef = (jobject) ap->getUserData(); 236 if (weakRef != NULL) { 237 env->DeleteGlobalRef(weakRef); 238 } 239 240 // clear callback and native context 241 ap->setCallback(NULL, NULL); 242 env->SetLongField(thiz, fields.mNativeContext, 0); 243 delete ap; 244 } 245} 246 247// ---------------------------------------------------------------------------- 248 249// Dalvik VM type signatures 250static JNINativeMethod gMethods[] = { 251 { "_load", 252 "(Ljava/lang/String;I)I", 253 (void *)android_media_SoundPool_SoundPoolImpl_load_URL 254 }, 255 { "_load", 256 "(Ljava/io/FileDescriptor;JJI)I", 257 (void *)android_media_SoundPool_SoundPoolImpl_load_FD 258 }, 259 { "unload", 260 "(I)Z", 261 (void *)android_media_SoundPool_SoundPoolImpl_unload 262 }, 263 { "_play", 264 "(IFFIIF)I", 265 (void *)android_media_SoundPool_SoundPoolImpl_play 266 }, 267 { "pause", 268 "(I)V", 269 (void *)android_media_SoundPool_SoundPoolImpl_pause 270 }, 271 { "resume", 272 "(I)V", 273 (void *)android_media_SoundPool_SoundPoolImpl_resume 274 }, 275 { "autoPause", 276 "()V", 277 (void *)android_media_SoundPool_SoundPoolImpl_autoPause 278 }, 279 { "autoResume", 280 "()V", 281 (void *)android_media_SoundPool_SoundPoolImpl_autoResume 282 }, 283 { "stop", 284 "(I)V", 285 (void *)android_media_SoundPool_SoundPoolImpl_stop 286 }, 287 { "_setVolume", 288 "(IFF)V", 289 (void *)android_media_SoundPool_SoundPoolImpl_setVolume 290 }, 291 { "setPriority", 292 "(II)V", 293 (void *)android_media_SoundPool_SoundPoolImpl_setPriority 294 }, 295 { "setLoop", 296 "(II)V", 297 (void *)android_media_SoundPool_SoundPoolImpl_setLoop 298 }, 299 { "setRate", 300 "(IF)V", 301 (void *)android_media_SoundPool_SoundPoolImpl_setRate 302 }, 303 { "native_setup", 304 "(Ljava/lang/Object;ILjava/lang/Object;)I", 305 (void*)android_media_SoundPool_SoundPoolImpl_native_setup 306 }, 307 { "release", 308 "()V", 309 (void*)android_media_SoundPool_SoundPoolImpl_release 310 } 311}; 312 313static const char* const kClassPathName = "android/media/SoundPool$SoundPoolImpl"; 314 315jint JNI_OnLoad(JavaVM* vm, void* reserved) 316{ 317 JNIEnv* env = NULL; 318 jint result = -1; 319 jclass clazz; 320 321 if (vm->GetEnv((void**) &env, JNI_VERSION_1_4) != JNI_OK) { 322 ALOGE("ERROR: GetEnv failed\n"); 323 return result; 324 } 325 assert(env != NULL); 326 327 clazz = env->FindClass(kClassPathName); 328 if (clazz == NULL) { 329 ALOGE("Can't find %s", kClassPathName); 330 return result; 331 } 332 333 fields.mNativeContext = env->GetFieldID(clazz, "mNativeContext", "J"); 334 if (fields.mNativeContext == NULL) { 335 ALOGE("Can't find SoundPoolImpl.mNativeContext"); 336 return result; 337 } 338 339 fields.mPostEvent = env->GetStaticMethodID(clazz, "postEventFromNative", 340 "(Ljava/lang/Object;IIILjava/lang/Object;)V"); 341 if (fields.mPostEvent == NULL) { 342 ALOGE("Can't find android/media/SoundPoolImpl.postEventFromNative"); 343 return result; 344 } 345 346 // create a reference to class. Technically, we're leaking this reference 347 // since it's a static object. 348 fields.mSoundPoolClass = (jclass) env->NewGlobalRef(clazz); 349 350 if (AndroidRuntime::registerNativeMethods(env, kClassPathName, gMethods, NELEM(gMethods)) < 0) 351 return result; 352 353 // Get the AudioAttributes class and fields 354 jclass audioAttrClass = env->FindClass(kAudioAttributesClassPathName); 355 if (audioAttrClass == NULL) { 356 ALOGE("Can't find %s", kAudioAttributesClassPathName); 357 return result; 358 } 359 jclass audioAttributesClassRef = (jclass)env->NewGlobalRef(audioAttrClass); 360 javaAudioAttrFields.fieldUsage = env->GetFieldID(audioAttributesClassRef, "mUsage", "I"); 361 javaAudioAttrFields.fieldContentType 362 = env->GetFieldID(audioAttributesClassRef, "mContentType", "I"); 363 javaAudioAttrFields.fieldFlags = env->GetFieldID(audioAttributesClassRef, "mFlags", "I"); 364 javaAudioAttrFields.fieldFormattedTags = 365 env->GetFieldID(audioAttributesClassRef, "mFormattedTags", "Ljava/lang/String;"); 366 env->DeleteGlobalRef(audioAttributesClassRef); 367 if (javaAudioAttrFields.fieldUsage == NULL || javaAudioAttrFields.fieldContentType == NULL 368 || javaAudioAttrFields.fieldFlags == NULL 369 || javaAudioAttrFields.fieldFormattedTags == NULL) { 370 ALOGE("Can't initialize AudioAttributes fields"); 371 return result; 372 } 373 374 /* success -- return valid version number */ 375 return JNI_VERSION_1_4; 376} 377