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//#define LOG_NDEBUG 0 17 18#define LOG_TAG "AudioTrack-JNI" 19 20#include "android_media_AudioTrack.h" 21 22#include <JNIHelp.h> 23#include <JniConstants.h> 24#include "core_jni_helpers.h" 25 26#include "ScopedBytes.h" 27 28#include <utils/Log.h> 29#include <media/AudioSystem.h> 30#include <media/AudioTrack.h> 31#include <audio_utils/primitives.h> 32 33#include <binder/MemoryHeapBase.h> 34#include <binder/MemoryBase.h> 35 36#include "android_media_AudioFormat.h" 37#include "android_media_AudioErrors.h" 38#include "android_media_PlaybackParams.h" 39#include "android_media_DeviceCallback.h" 40 41// ---------------------------------------------------------------------------- 42 43using namespace android; 44 45// ---------------------------------------------------------------------------- 46static const char* const kClassPathName = "android/media/AudioTrack"; 47static const char* const kAudioAttributesClassPathName = "android/media/AudioAttributes"; 48 49struct audio_track_fields_t { 50 // these fields provide access from C++ to the... 51 jmethodID postNativeEventInJava; //... event post callback method 52 jfieldID nativeTrackInJavaObj; // stores in Java the native AudioTrack object 53 jfieldID jniData; // stores in Java additional resources used by the native AudioTrack 54 jfieldID fieldStreamType; // ... mStreamType field in the AudioTrack Java object 55}; 56struct audio_attributes_fields_t { 57 jfieldID fieldUsage; // AudioAttributes.mUsage 58 jfieldID fieldContentType; // AudioAttributes.mContentType 59 jfieldID fieldFlags; // AudioAttributes.mFlags 60 jfieldID fieldFormattedTags;// AudioAttributes.mFormattedTags 61}; 62static audio_track_fields_t javaAudioTrackFields; 63static audio_attributes_fields_t javaAudioAttrFields; 64static PlaybackParams::fields_t gPlaybackParamsFields; 65 66struct audiotrack_callback_cookie { 67 jclass audioTrack_class; 68 jobject audioTrack_ref; 69 bool busy; 70 Condition cond; 71}; 72 73// keep these values in sync with AudioTrack.java 74#define MODE_STATIC 0 75#define MODE_STREAM 1 76 77// ---------------------------------------------------------------------------- 78class AudioTrackJniStorage { 79 public: 80 sp<MemoryHeapBase> mMemHeap; 81 sp<MemoryBase> mMemBase; 82 audiotrack_callback_cookie mCallbackData; 83 sp<JNIDeviceCallback> mDeviceCallback; 84 85 AudioTrackJniStorage() { 86 mCallbackData.audioTrack_class = 0; 87 mCallbackData.audioTrack_ref = 0; 88 } 89 90 ~AudioTrackJniStorage() { 91 mMemBase.clear(); 92 mMemHeap.clear(); 93 } 94 95 bool allocSharedMem(int sizeInBytes) { 96 mMemHeap = new MemoryHeapBase(sizeInBytes, 0, "AudioTrack Heap Base"); 97 if (mMemHeap->getHeapID() < 0) { 98 return false; 99 } 100 mMemBase = new MemoryBase(mMemHeap, 0, sizeInBytes); 101 return true; 102 } 103}; 104 105static Mutex sLock; 106static SortedVector <audiotrack_callback_cookie *> sAudioTrackCallBackCookies; 107 108// ---------------------------------------------------------------------------- 109#define DEFAULT_OUTPUT_SAMPLE_RATE 44100 110 111#define AUDIOTRACK_ERROR_SETUP_AUDIOSYSTEM -16 112#define AUDIOTRACK_ERROR_SETUP_INVALIDCHANNELMASK -17 113#define AUDIOTRACK_ERROR_SETUP_INVALIDFORMAT -18 114#define AUDIOTRACK_ERROR_SETUP_INVALIDSTREAMTYPE -19 115#define AUDIOTRACK_ERROR_SETUP_NATIVEINITFAILED -20 116 117// ---------------------------------------------------------------------------- 118static void audioCallback(int event, void* user, void *info) { 119 120 audiotrack_callback_cookie *callbackInfo = (audiotrack_callback_cookie *)user; 121 { 122 Mutex::Autolock l(sLock); 123 if (sAudioTrackCallBackCookies.indexOf(callbackInfo) < 0) { 124 return; 125 } 126 callbackInfo->busy = true; 127 } 128 129 switch (event) { 130 case AudioTrack::EVENT_MARKER: { 131 JNIEnv *env = AndroidRuntime::getJNIEnv(); 132 if (user != NULL && env != NULL) { 133 env->CallStaticVoidMethod( 134 callbackInfo->audioTrack_class, 135 javaAudioTrackFields.postNativeEventInJava, 136 callbackInfo->audioTrack_ref, event, 0,0, NULL); 137 if (env->ExceptionCheck()) { 138 env->ExceptionDescribe(); 139 env->ExceptionClear(); 140 } 141 } 142 } break; 143 144 case AudioTrack::EVENT_NEW_POS: { 145 JNIEnv *env = AndroidRuntime::getJNIEnv(); 146 if (user != NULL && env != NULL) { 147 env->CallStaticVoidMethod( 148 callbackInfo->audioTrack_class, 149 javaAudioTrackFields.postNativeEventInJava, 150 callbackInfo->audioTrack_ref, event, 0,0, NULL); 151 if (env->ExceptionCheck()) { 152 env->ExceptionDescribe(); 153 env->ExceptionClear(); 154 } 155 } 156 } break; 157 } 158 159 { 160 Mutex::Autolock l(sLock); 161 callbackInfo->busy = false; 162 callbackInfo->cond.broadcast(); 163 } 164} 165 166 167// ---------------------------------------------------------------------------- 168static sp<AudioTrack> getAudioTrack(JNIEnv* env, jobject thiz) 169{ 170 Mutex::Autolock l(sLock); 171 AudioTrack* const at = 172 (AudioTrack*)env->GetLongField(thiz, javaAudioTrackFields.nativeTrackInJavaObj); 173 return sp<AudioTrack>(at); 174} 175 176static sp<AudioTrack> setAudioTrack(JNIEnv* env, jobject thiz, const sp<AudioTrack>& at) 177{ 178 Mutex::Autolock l(sLock); 179 sp<AudioTrack> old = 180 (AudioTrack*)env->GetLongField(thiz, javaAudioTrackFields.nativeTrackInJavaObj); 181 if (at.get()) { 182 at->incStrong((void*)setAudioTrack); 183 } 184 if (old != 0) { 185 old->decStrong((void*)setAudioTrack); 186 } 187 env->SetLongField(thiz, javaAudioTrackFields.nativeTrackInJavaObj, (jlong)at.get()); 188 return old; 189} 190 191// ---------------------------------------------------------------------------- 192sp<AudioTrack> android_media_AudioTrack_getAudioTrack(JNIEnv* env, jobject audioTrackObj) { 193 return getAudioTrack(env, audioTrackObj); 194} 195 196// This function converts Java channel masks to a native channel mask. 197// validity should be checked with audio_is_output_channel(). 198static inline audio_channel_mask_t nativeChannelMaskFromJavaChannelMasks( 199 jint channelPositionMask, jint channelIndexMask) 200{ 201 if (channelIndexMask != 0) { // channel index mask takes priority 202 // To convert to a native channel mask, the Java channel index mask 203 // requires adding the index representation. 204 return audio_channel_mask_from_representation_and_bits( 205 AUDIO_CHANNEL_REPRESENTATION_INDEX, 206 channelIndexMask); 207 } 208 // To convert to a native channel mask, the Java channel position mask 209 // requires a shift by 2 to skip the two deprecated channel 210 // configurations "default" and "mono". 211 return (audio_channel_mask_t)(channelPositionMask >> 2); 212} 213 214// ---------------------------------------------------------------------------- 215static jint 216android_media_AudioTrack_setup(JNIEnv *env, jobject thiz, jobject weak_this, 217 jobject jaa, 218 jint sampleRateInHertz, jint channelPositionMask, jint channelIndexMask, 219 jint audioFormat, jint buffSizeInBytes, jint memoryMode, jintArray jSession) { 220 221 ALOGV("sampleRate=%d, channel mask=%x, index mask=%x, audioFormat(Java)=%d, buffSize=%d", 222 sampleRateInHertz, channelPositionMask, channelIndexMask, audioFormat, buffSizeInBytes); 223 224 if (jaa == 0) { 225 ALOGE("Error creating AudioTrack: invalid audio attributes"); 226 return (jint) AUDIO_JAVA_ERROR; 227 } 228 229 // Invalid channel representations are caught by !audio_is_output_channel() below. 230 audio_channel_mask_t nativeChannelMask = nativeChannelMaskFromJavaChannelMasks( 231 channelPositionMask, channelIndexMask); 232 if (!audio_is_output_channel(nativeChannelMask)) { 233 ALOGE("Error creating AudioTrack: invalid native channel mask %#x.", nativeChannelMask); 234 return (jint) AUDIOTRACK_ERROR_SETUP_INVALIDCHANNELMASK; 235 } 236 237 uint32_t channelCount = audio_channel_count_from_out_mask(nativeChannelMask); 238 239 // check the format. 240 // This function was called from Java, so we compare the format against the Java constants 241 audio_format_t format = audioFormatToNative(audioFormat); 242 if (format == AUDIO_FORMAT_INVALID) { 243 ALOGE("Error creating AudioTrack: unsupported audio format %d.", audioFormat); 244 return (jint) AUDIOTRACK_ERROR_SETUP_INVALIDFORMAT; 245 } 246 247 // compute the frame count 248 size_t frameCount; 249 if (audio_is_linear_pcm(format)) { 250 const size_t bytesPerSample = audio_bytes_per_sample(format); 251 frameCount = buffSizeInBytes / (channelCount * bytesPerSample); 252 } else { 253 frameCount = buffSizeInBytes; 254 } 255 256 jclass clazz = env->GetObjectClass(thiz); 257 if (clazz == NULL) { 258 ALOGE("Can't find %s when setting up callback.", kClassPathName); 259 return (jint) AUDIOTRACK_ERROR_SETUP_NATIVEINITFAILED; 260 } 261 262 if (jSession == NULL) { 263 ALOGE("Error creating AudioTrack: invalid session ID pointer"); 264 return (jint) AUDIO_JAVA_ERROR; 265 } 266 267 jint* nSession = (jint *) env->GetPrimitiveArrayCritical(jSession, NULL); 268 if (nSession == NULL) { 269 ALOGE("Error creating AudioTrack: Error retrieving session id pointer"); 270 return (jint) AUDIO_JAVA_ERROR; 271 } 272 int sessionId = nSession[0]; 273 env->ReleasePrimitiveArrayCritical(jSession, nSession, 0); 274 nSession = NULL; 275 276 // create the native AudioTrack object 277 sp<AudioTrack> lpTrack = new AudioTrack(); 278 279 audio_attributes_t *paa = NULL; 280 // read the AudioAttributes values 281 paa = (audio_attributes_t *) calloc(1, sizeof(audio_attributes_t)); 282 const jstring jtags = 283 (jstring) env->GetObjectField(jaa, javaAudioAttrFields.fieldFormattedTags); 284 const char* tags = env->GetStringUTFChars(jtags, NULL); 285 // copying array size -1, char array for tags was calloc'd, no need to NULL-terminate it 286 strncpy(paa->tags, tags, AUDIO_ATTRIBUTES_TAGS_MAX_SIZE - 1); 287 env->ReleaseStringUTFChars(jtags, tags); 288 paa->usage = (audio_usage_t) env->GetIntField(jaa, javaAudioAttrFields.fieldUsage); 289 paa->content_type = 290 (audio_content_type_t) env->GetIntField(jaa, javaAudioAttrFields.fieldContentType); 291 paa->flags = env->GetIntField(jaa, javaAudioAttrFields.fieldFlags); 292 293 ALOGV("AudioTrack_setup for usage=%d content=%d flags=0x%#x tags=%s", 294 paa->usage, paa->content_type, paa->flags, paa->tags); 295 296 // initialize the callback information: 297 // this data will be passed with every AudioTrack callback 298 AudioTrackJniStorage* lpJniStorage = new AudioTrackJniStorage(); 299 lpJniStorage->mCallbackData.audioTrack_class = (jclass)env->NewGlobalRef(clazz); 300 // we use a weak reference so the AudioTrack object can be garbage collected. 301 lpJniStorage->mCallbackData.audioTrack_ref = env->NewGlobalRef(weak_this); 302 lpJniStorage->mCallbackData.busy = false; 303 304 // initialize the native AudioTrack object 305 status_t status = NO_ERROR; 306 switch (memoryMode) { 307 case MODE_STREAM: 308 309 status = lpTrack->set( 310 AUDIO_STREAM_DEFAULT,// stream type, but more info conveyed in paa (last argument) 311 sampleRateInHertz, 312 format,// word length, PCM 313 nativeChannelMask, 314 frameCount, 315 AUDIO_OUTPUT_FLAG_NONE, 316 audioCallback, &(lpJniStorage->mCallbackData),//callback, callback data (user) 317 0,// notificationFrames == 0 since not using EVENT_MORE_DATA to feed the AudioTrack 318 0,// shared mem 319 true,// thread can call Java 320 sessionId,// audio session ID 321 AudioTrack::TRANSFER_SYNC, 322 NULL, // default offloadInfo 323 -1, -1, // default uid, pid values 324 paa); 325 break; 326 327 case MODE_STATIC: 328 // AudioTrack is using shared memory 329 330 if (!lpJniStorage->allocSharedMem(buffSizeInBytes)) { 331 ALOGE("Error creating AudioTrack in static mode: error creating mem heap base"); 332 goto native_init_failure; 333 } 334 335 status = lpTrack->set( 336 AUDIO_STREAM_DEFAULT,// stream type, but more info conveyed in paa (last argument) 337 sampleRateInHertz, 338 format,// word length, PCM 339 nativeChannelMask, 340 frameCount, 341 AUDIO_OUTPUT_FLAG_NONE, 342 audioCallback, &(lpJniStorage->mCallbackData),//callback, callback data (user)); 343 0,// notificationFrames == 0 since not using EVENT_MORE_DATA to feed the AudioTrack 344 lpJniStorage->mMemBase,// shared mem 345 true,// thread can call Java 346 sessionId,// audio session ID 347 AudioTrack::TRANSFER_SHARED, 348 NULL, // default offloadInfo 349 -1, -1, // default uid, pid values 350 paa); 351 break; 352 353 default: 354 ALOGE("Unknown mode %d", memoryMode); 355 goto native_init_failure; 356 } 357 358 if (status != NO_ERROR) { 359 ALOGE("Error %d initializing AudioTrack", status); 360 goto native_init_failure; 361 } 362 363 nSession = (jint *) env->GetPrimitiveArrayCritical(jSession, NULL); 364 if (nSession == NULL) { 365 ALOGE("Error creating AudioTrack: Error retrieving session id pointer"); 366 goto native_init_failure; 367 } 368 // read the audio session ID back from AudioTrack in case we create a new session 369 nSession[0] = lpTrack->getSessionId(); 370 env->ReleasePrimitiveArrayCritical(jSession, nSession, 0); 371 nSession = NULL; 372 373 { // scope for the lock 374 Mutex::Autolock l(sLock); 375 sAudioTrackCallBackCookies.add(&lpJniStorage->mCallbackData); 376 } 377 // save our newly created C++ AudioTrack in the "nativeTrackInJavaObj" field 378 // of the Java object (in mNativeTrackInJavaObj) 379 setAudioTrack(env, thiz, lpTrack); 380 381 // save the JNI resources so we can free them later 382 //ALOGV("storing lpJniStorage: %x\n", (long)lpJniStorage); 383 env->SetLongField(thiz, javaAudioTrackFields.jniData, (jlong)lpJniStorage); 384 385 // since we had audio attributes, the stream type was derived from them during the 386 // creation of the native AudioTrack: push the same value to the Java object 387 env->SetIntField(thiz, javaAudioTrackFields.fieldStreamType, (jint) lpTrack->streamType()); 388 // audio attributes were copied in AudioTrack creation 389 free(paa); 390 paa = NULL; 391 392 393 return (jint) AUDIO_JAVA_SUCCESS; 394 395 // failures: 396native_init_failure: 397 if (paa != NULL) { 398 free(paa); 399 } 400 if (nSession != NULL) { 401 env->ReleasePrimitiveArrayCritical(jSession, nSession, 0); 402 } 403 env->DeleteGlobalRef(lpJniStorage->mCallbackData.audioTrack_class); 404 env->DeleteGlobalRef(lpJniStorage->mCallbackData.audioTrack_ref); 405 delete lpJniStorage; 406 env->SetLongField(thiz, javaAudioTrackFields.jniData, 0); 407 408 // lpTrack goes out of scope, so reference count drops to zero 409 return (jint) AUDIOTRACK_ERROR_SETUP_NATIVEINITFAILED; 410} 411 412 413// ---------------------------------------------------------------------------- 414static void 415android_media_AudioTrack_start(JNIEnv *env, jobject thiz) 416{ 417 sp<AudioTrack> lpTrack = getAudioTrack(env, thiz); 418 if (lpTrack == NULL) { 419 jniThrowException(env, "java/lang/IllegalStateException", 420 "Unable to retrieve AudioTrack pointer for start()"); 421 return; 422 } 423 424 lpTrack->start(); 425} 426 427 428// ---------------------------------------------------------------------------- 429static void 430android_media_AudioTrack_stop(JNIEnv *env, jobject thiz) 431{ 432 sp<AudioTrack> lpTrack = getAudioTrack(env, thiz); 433 if (lpTrack == NULL) { 434 jniThrowException(env, "java/lang/IllegalStateException", 435 "Unable to retrieve AudioTrack pointer for stop()"); 436 return; 437 } 438 439 lpTrack->stop(); 440} 441 442 443// ---------------------------------------------------------------------------- 444static void 445android_media_AudioTrack_pause(JNIEnv *env, jobject thiz) 446{ 447 sp<AudioTrack> lpTrack = getAudioTrack(env, thiz); 448 if (lpTrack == NULL) { 449 jniThrowException(env, "java/lang/IllegalStateException", 450 "Unable to retrieve AudioTrack pointer for pause()"); 451 return; 452 } 453 454 lpTrack->pause(); 455} 456 457 458// ---------------------------------------------------------------------------- 459static void 460android_media_AudioTrack_flush(JNIEnv *env, jobject thiz) 461{ 462 sp<AudioTrack> lpTrack = getAudioTrack(env, thiz); 463 if (lpTrack == NULL) { 464 jniThrowException(env, "java/lang/IllegalStateException", 465 "Unable to retrieve AudioTrack pointer for flush()"); 466 return; 467 } 468 469 lpTrack->flush(); 470} 471 472// ---------------------------------------------------------------------------- 473static void 474android_media_AudioTrack_set_volume(JNIEnv *env, jobject thiz, jfloat leftVol, jfloat rightVol ) 475{ 476 sp<AudioTrack> lpTrack = getAudioTrack(env, thiz); 477 if (lpTrack == NULL) { 478 jniThrowException(env, "java/lang/IllegalStateException", 479 "Unable to retrieve AudioTrack pointer for setVolume()"); 480 return; 481 } 482 483 lpTrack->setVolume(leftVol, rightVol); 484} 485 486// ---------------------------------------------------------------------------- 487 488#define CALLBACK_COND_WAIT_TIMEOUT_MS 1000 489static void android_media_AudioTrack_release(JNIEnv *env, jobject thiz) { 490 sp<AudioTrack> lpTrack = setAudioTrack(env, thiz, 0); 491 if (lpTrack == NULL) { 492 return; 493 } 494 //ALOGV("deleting lpTrack: %x\n", (int)lpTrack); 495 lpTrack->stop(); 496 497 // delete the JNI data 498 AudioTrackJniStorage* pJniStorage = (AudioTrackJniStorage *)env->GetLongField( 499 thiz, javaAudioTrackFields.jniData); 500 // reset the native resources in the Java object so any attempt to access 501 // them after a call to release fails. 502 env->SetLongField(thiz, javaAudioTrackFields.jniData, 0); 503 504 if (pJniStorage) { 505 Mutex::Autolock l(sLock); 506 audiotrack_callback_cookie *lpCookie = &pJniStorage->mCallbackData; 507 //ALOGV("deleting pJniStorage: %x\n", (int)pJniStorage); 508 while (lpCookie->busy) { 509 if (lpCookie->cond.waitRelative(sLock, 510 milliseconds(CALLBACK_COND_WAIT_TIMEOUT_MS)) != 511 NO_ERROR) { 512 break; 513 } 514 } 515 sAudioTrackCallBackCookies.remove(lpCookie); 516 // delete global refs created in native_setup 517 env->DeleteGlobalRef(lpCookie->audioTrack_class); 518 env->DeleteGlobalRef(lpCookie->audioTrack_ref); 519 delete pJniStorage; 520 } 521} 522 523 524// ---------------------------------------------------------------------------- 525static void android_media_AudioTrack_finalize(JNIEnv *env, jobject thiz) { 526 //ALOGV("android_media_AudioTrack_finalize jobject: %x\n", (int)thiz); 527 android_media_AudioTrack_release(env, thiz); 528} 529 530// overloaded JNI array helper functions (same as in android_media_AudioRecord) 531static inline 532jbyte *envGetArrayElements(JNIEnv *env, jbyteArray array, jboolean *isCopy) { 533 return env->GetByteArrayElements(array, isCopy); 534} 535 536static inline 537void envReleaseArrayElements(JNIEnv *env, jbyteArray array, jbyte *elems, jint mode) { 538 env->ReleaseByteArrayElements(array, elems, mode); 539} 540 541static inline 542jshort *envGetArrayElements(JNIEnv *env, jshortArray array, jboolean *isCopy) { 543 return env->GetShortArrayElements(array, isCopy); 544} 545 546static inline 547void envReleaseArrayElements(JNIEnv *env, jshortArray array, jshort *elems, jint mode) { 548 env->ReleaseShortArrayElements(array, elems, mode); 549} 550 551static inline 552jfloat *envGetArrayElements(JNIEnv *env, jfloatArray array, jboolean *isCopy) { 553 return env->GetFloatArrayElements(array, isCopy); 554} 555 556static inline 557void envReleaseArrayElements(JNIEnv *env, jfloatArray array, jfloat *elems, jint mode) { 558 env->ReleaseFloatArrayElements(array, elems, mode); 559} 560 561// ---------------------------------------------------------------------------- 562template <typename T> 563static jint writeToTrack(const sp<AudioTrack>& track, jint audioFormat, const T *data, 564 jint offsetInSamples, jint sizeInSamples, bool blocking) { 565 // give the data to the native AudioTrack object (the data starts at the offset) 566 ssize_t written = 0; 567 // regular write() or copy the data to the AudioTrack's shared memory? 568 size_t sizeInBytes = sizeInSamples * sizeof(T); 569 if (track->sharedBuffer() == 0) { 570 written = track->write(data + offsetInSamples, sizeInBytes, blocking); 571 // for compatibility with earlier behavior of write(), return 0 in this case 572 if (written == (ssize_t) WOULD_BLOCK) { 573 written = 0; 574 } 575 } else { 576 // writing to shared memory, check for capacity 577 if ((size_t)sizeInBytes > track->sharedBuffer()->size()) { 578 sizeInBytes = track->sharedBuffer()->size(); 579 } 580 memcpy(track->sharedBuffer()->pointer(), data + offsetInSamples, sizeInBytes); 581 written = sizeInBytes; 582 } 583 if (written > 0) { 584 return written / sizeof(T); 585 } 586 // for compatibility, error codes pass through unchanged 587 return written; 588} 589 590// ---------------------------------------------------------------------------- 591template <typename T> 592static jint android_media_AudioTrack_writeArray(JNIEnv *env, jobject thiz, 593 T javaAudioData, 594 jint offsetInSamples, jint sizeInSamples, 595 jint javaAudioFormat, 596 jboolean isWriteBlocking) { 597 //ALOGV("android_media_AudioTrack_writeArray(offset=%d, sizeInSamples=%d) called", 598 // offsetInSamples, sizeInSamples); 599 sp<AudioTrack> lpTrack = getAudioTrack(env, thiz); 600 if (lpTrack == NULL) { 601 jniThrowException(env, "java/lang/IllegalStateException", 602 "Unable to retrieve AudioTrack pointer for write()"); 603 return (jint)AUDIO_JAVA_INVALID_OPERATION; 604 } 605 606 if (javaAudioData == NULL) { 607 ALOGE("NULL java array of audio data to play"); 608 return (jint)AUDIO_JAVA_BAD_VALUE; 609 } 610 611 // NOTE: We may use GetPrimitiveArrayCritical() when the JNI implementation changes in such 612 // a way that it becomes much more efficient. When doing so, we will have to prevent the 613 // AudioSystem callback to be called while in critical section (in case of media server 614 // process crash for instance) 615 616 // get the pointer for the audio data from the java array 617 auto cAudioData = envGetArrayElements(env, javaAudioData, NULL); 618 if (cAudioData == NULL) { 619 ALOGE("Error retrieving source of audio data to play"); 620 return (jint)AUDIO_JAVA_BAD_VALUE; // out of memory or no data to load 621 } 622 623 jint samplesWritten = writeToTrack(lpTrack, javaAudioFormat, cAudioData, 624 offsetInSamples, sizeInSamples, isWriteBlocking == JNI_TRUE /* blocking */); 625 626 envReleaseArrayElements(env, javaAudioData, cAudioData, 0); 627 628 //ALOGV("write wrote %d (tried %d) samples in the native AudioTrack with offset %d", 629 // (int)samplesWritten, (int)(sizeInSamples), (int)offsetInSamples); 630 return samplesWritten; 631} 632 633// ---------------------------------------------------------------------------- 634static jint android_media_AudioTrack_write_native_bytes(JNIEnv *env, jobject thiz, 635 jbyteArray javaBytes, jint byteOffset, jint sizeInBytes, 636 jint javaAudioFormat, jboolean isWriteBlocking) { 637 //ALOGV("android_media_AudioTrack_write_native_bytes(offset=%d, sizeInBytes=%d) called", 638 // offsetInBytes, sizeInBytes); 639 sp<AudioTrack> lpTrack = getAudioTrack(env, thiz); 640 if (lpTrack == NULL) { 641 jniThrowException(env, "java/lang/IllegalStateException", 642 "Unable to retrieve AudioTrack pointer for write()"); 643 return (jint)AUDIO_JAVA_INVALID_OPERATION; 644 } 645 646 ScopedBytesRO bytes(env, javaBytes); 647 if (bytes.get() == NULL) { 648 ALOGE("Error retrieving source of audio data to play, can't play"); 649 return (jint)AUDIO_JAVA_BAD_VALUE; 650 } 651 652 jint written = writeToTrack(lpTrack, javaAudioFormat, bytes.get(), byteOffset, 653 sizeInBytes, isWriteBlocking == JNI_TRUE /* blocking */); 654 655 return written; 656} 657 658// ---------------------------------------------------------------------------- 659static jint android_media_AudioTrack_get_native_frame_count(JNIEnv *env, jobject thiz) { 660 sp<AudioTrack> lpTrack = getAudioTrack(env, thiz); 661 if (lpTrack == NULL) { 662 jniThrowException(env, "java/lang/IllegalStateException", 663 "Unable to retrieve AudioTrack pointer for frameCount()"); 664 return (jint)AUDIO_JAVA_ERROR; 665 } 666 667 return lpTrack->frameCount(); 668} 669 670 671// ---------------------------------------------------------------------------- 672static jint android_media_AudioTrack_set_playback_rate(JNIEnv *env, jobject thiz, 673 jint sampleRateInHz) { 674 sp<AudioTrack> lpTrack = getAudioTrack(env, thiz); 675 if (lpTrack == NULL) { 676 jniThrowException(env, "java/lang/IllegalStateException", 677 "Unable to retrieve AudioTrack pointer for setSampleRate()"); 678 return (jint)AUDIO_JAVA_ERROR; 679 } 680 return nativeToJavaStatus(lpTrack->setSampleRate(sampleRateInHz)); 681} 682 683 684// ---------------------------------------------------------------------------- 685static jint android_media_AudioTrack_get_playback_rate(JNIEnv *env, jobject thiz) { 686 sp<AudioTrack> lpTrack = getAudioTrack(env, thiz); 687 if (lpTrack == NULL) { 688 jniThrowException(env, "java/lang/IllegalStateException", 689 "Unable to retrieve AudioTrack pointer for getSampleRate()"); 690 return (jint)AUDIO_JAVA_ERROR; 691 } 692 return (jint) lpTrack->getSampleRate(); 693} 694 695 696// ---------------------------------------------------------------------------- 697static void android_media_AudioTrack_set_playback_params(JNIEnv *env, jobject thiz, 698 jobject params) { 699 sp<AudioTrack> lpTrack = getAudioTrack(env, thiz); 700 if (lpTrack == NULL) { 701 jniThrowException(env, "java/lang/IllegalStateException", 702 "AudioTrack not initialized"); 703 return; 704 } 705 706 PlaybackParams pbp; 707 pbp.fillFromJobject(env, gPlaybackParamsFields, params); 708 709 ALOGV("setPlaybackParams: %d:%f %d:%f %d:%u %d:%u", 710 pbp.speedSet, pbp.audioRate.mSpeed, 711 pbp.pitchSet, pbp.audioRate.mPitch, 712 pbp.audioFallbackModeSet, pbp.audioRate.mFallbackMode, 713 pbp.audioStretchModeSet, pbp.audioRate.mStretchMode); 714 715 // to simulate partially set params, we do a read-modify-write. 716 // TODO: pass in the valid set mask into AudioTrack. 717 AudioPlaybackRate rate = lpTrack->getPlaybackRate(); 718 bool updatedRate = false; 719 if (pbp.speedSet) { 720 rate.mSpeed = pbp.audioRate.mSpeed; 721 updatedRate = true; 722 } 723 if (pbp.pitchSet) { 724 rate.mPitch = pbp.audioRate.mPitch; 725 updatedRate = true; 726 } 727 if (pbp.audioFallbackModeSet) { 728 rate.mFallbackMode = pbp.audioRate.mFallbackMode; 729 updatedRate = true; 730 } 731 if (pbp.audioStretchModeSet) { 732 rate.mStretchMode = pbp.audioRate.mStretchMode; 733 updatedRate = true; 734 } 735 if (updatedRate) { 736 if (lpTrack->setPlaybackRate(rate) != OK) { 737 jniThrowException(env, "java/lang/IllegalArgumentException", 738 "arguments out of range"); 739 } 740 } 741} 742 743 744// ---------------------------------------------------------------------------- 745static jobject android_media_AudioTrack_get_playback_params(JNIEnv *env, jobject thiz, 746 jobject params) { 747 sp<AudioTrack> lpTrack = getAudioTrack(env, thiz); 748 if (lpTrack == NULL) { 749 jniThrowException(env, "java/lang/IllegalStateException", 750 "AudioTrack not initialized"); 751 return NULL; 752 } 753 754 PlaybackParams pbs; 755 pbs.audioRate = lpTrack->getPlaybackRate(); 756 pbs.speedSet = true; 757 pbs.pitchSet = true; 758 pbs.audioFallbackModeSet = true; 759 pbs.audioStretchModeSet = true; 760 return pbs.asJobject(env, gPlaybackParamsFields); 761} 762 763 764// ---------------------------------------------------------------------------- 765static jint android_media_AudioTrack_set_marker_pos(JNIEnv *env, jobject thiz, 766 jint markerPos) { 767 sp<AudioTrack> lpTrack = getAudioTrack(env, thiz); 768 if (lpTrack == NULL) { 769 jniThrowException(env, "java/lang/IllegalStateException", 770 "Unable to retrieve AudioTrack pointer for setMarkerPosition()"); 771 return (jint)AUDIO_JAVA_ERROR; 772 } 773 return nativeToJavaStatus( lpTrack->setMarkerPosition(markerPos) ); 774} 775 776 777// ---------------------------------------------------------------------------- 778static jint android_media_AudioTrack_get_marker_pos(JNIEnv *env, jobject thiz) { 779 sp<AudioTrack> lpTrack = getAudioTrack(env, thiz); 780 uint32_t markerPos = 0; 781 782 if (lpTrack == NULL) { 783 jniThrowException(env, "java/lang/IllegalStateException", 784 "Unable to retrieve AudioTrack pointer for getMarkerPosition()"); 785 return (jint)AUDIO_JAVA_ERROR; 786 } 787 lpTrack->getMarkerPosition(&markerPos); 788 return (jint)markerPos; 789} 790 791 792// ---------------------------------------------------------------------------- 793static jint android_media_AudioTrack_set_pos_update_period(JNIEnv *env, jobject thiz, 794 jint period) { 795 sp<AudioTrack> lpTrack = getAudioTrack(env, thiz); 796 if (lpTrack == NULL) { 797 jniThrowException(env, "java/lang/IllegalStateException", 798 "Unable to retrieve AudioTrack pointer for setPositionUpdatePeriod()"); 799 return (jint)AUDIO_JAVA_ERROR; 800 } 801 return nativeToJavaStatus( lpTrack->setPositionUpdatePeriod(period) ); 802} 803 804 805// ---------------------------------------------------------------------------- 806static jint android_media_AudioTrack_get_pos_update_period(JNIEnv *env, jobject thiz) { 807 sp<AudioTrack> lpTrack = getAudioTrack(env, thiz); 808 uint32_t period = 0; 809 810 if (lpTrack == NULL) { 811 jniThrowException(env, "java/lang/IllegalStateException", 812 "Unable to retrieve AudioTrack pointer for getPositionUpdatePeriod()"); 813 return (jint)AUDIO_JAVA_ERROR; 814 } 815 lpTrack->getPositionUpdatePeriod(&period); 816 return (jint)period; 817} 818 819 820// ---------------------------------------------------------------------------- 821static jint android_media_AudioTrack_set_position(JNIEnv *env, jobject thiz, 822 jint position) { 823 sp<AudioTrack> lpTrack = getAudioTrack(env, thiz); 824 if (lpTrack == NULL) { 825 jniThrowException(env, "java/lang/IllegalStateException", 826 "Unable to retrieve AudioTrack pointer for setPosition()"); 827 return (jint)AUDIO_JAVA_ERROR; 828 } 829 return nativeToJavaStatus( lpTrack->setPosition(position) ); 830} 831 832 833// ---------------------------------------------------------------------------- 834static jint android_media_AudioTrack_get_position(JNIEnv *env, jobject thiz) { 835 sp<AudioTrack> lpTrack = getAudioTrack(env, thiz); 836 uint32_t position = 0; 837 838 if (lpTrack == NULL) { 839 jniThrowException(env, "java/lang/IllegalStateException", 840 "Unable to retrieve AudioTrack pointer for getPosition()"); 841 return (jint)AUDIO_JAVA_ERROR; 842 } 843 lpTrack->getPosition(&position); 844 return (jint)position; 845} 846 847 848// ---------------------------------------------------------------------------- 849static jint android_media_AudioTrack_get_latency(JNIEnv *env, jobject thiz) { 850 sp<AudioTrack> lpTrack = getAudioTrack(env, thiz); 851 852 if (lpTrack == NULL) { 853 jniThrowException(env, "java/lang/IllegalStateException", 854 "Unable to retrieve AudioTrack pointer for latency()"); 855 return (jint)AUDIO_JAVA_ERROR; 856 } 857 return (jint)lpTrack->latency(); 858} 859 860 861// ---------------------------------------------------------------------------- 862static jint android_media_AudioTrack_get_timestamp(JNIEnv *env, jobject thiz, jlongArray jTimestamp) { 863 sp<AudioTrack> lpTrack = getAudioTrack(env, thiz); 864 865 if (lpTrack == NULL) { 866 ALOGE("Unable to retrieve AudioTrack pointer for getTimestamp()"); 867 return (jint)AUDIO_JAVA_ERROR; 868 } 869 AudioTimestamp timestamp; 870 status_t status = lpTrack->getTimestamp(timestamp); 871 if (status == OK) { 872 jlong* nTimestamp = (jlong *) env->GetPrimitiveArrayCritical(jTimestamp, NULL); 873 if (nTimestamp == NULL) { 874 ALOGE("Unable to get array for getTimestamp()"); 875 return (jint)AUDIO_JAVA_ERROR; 876 } 877 nTimestamp[0] = (jlong) timestamp.mPosition; 878 nTimestamp[1] = (jlong) ((timestamp.mTime.tv_sec * 1000000000LL) + timestamp.mTime.tv_nsec); 879 env->ReleasePrimitiveArrayCritical(jTimestamp, nTimestamp, 0); 880 } 881 return (jint) nativeToJavaStatus(status); 882} 883 884 885// ---------------------------------------------------------------------------- 886static jint android_media_AudioTrack_set_loop(JNIEnv *env, jobject thiz, 887 jint loopStart, jint loopEnd, jint loopCount) { 888 sp<AudioTrack> lpTrack = getAudioTrack(env, thiz); 889 if (lpTrack == NULL) { 890 jniThrowException(env, "java/lang/IllegalStateException", 891 "Unable to retrieve AudioTrack pointer for setLoop()"); 892 return (jint)AUDIO_JAVA_ERROR; 893 } 894 return nativeToJavaStatus( lpTrack->setLoop(loopStart, loopEnd, loopCount) ); 895} 896 897 898// ---------------------------------------------------------------------------- 899static jint android_media_AudioTrack_reload(JNIEnv *env, jobject thiz) { 900 sp<AudioTrack> lpTrack = getAudioTrack(env, thiz); 901 if (lpTrack == NULL) { 902 jniThrowException(env, "java/lang/IllegalStateException", 903 "Unable to retrieve AudioTrack pointer for reload()"); 904 return (jint)AUDIO_JAVA_ERROR; 905 } 906 return nativeToJavaStatus( lpTrack->reload() ); 907} 908 909 910// ---------------------------------------------------------------------------- 911static jint android_media_AudioTrack_get_output_sample_rate(JNIEnv *env, jobject thiz, 912 jint javaStreamType) { 913 uint32_t afSamplingRate; 914 // convert the stream type from Java to native value 915 // FIXME: code duplication with android_media_AudioTrack_setup() 916 audio_stream_type_t nativeStreamType; 917 switch (javaStreamType) { 918 case AUDIO_STREAM_VOICE_CALL: 919 case AUDIO_STREAM_SYSTEM: 920 case AUDIO_STREAM_RING: 921 case AUDIO_STREAM_MUSIC: 922 case AUDIO_STREAM_ALARM: 923 case AUDIO_STREAM_NOTIFICATION: 924 case AUDIO_STREAM_BLUETOOTH_SCO: 925 case AUDIO_STREAM_DTMF: 926 nativeStreamType = (audio_stream_type_t) javaStreamType; 927 break; 928 default: 929 nativeStreamType = AUDIO_STREAM_DEFAULT; 930 break; 931 } 932 933 status_t status = AudioSystem::getOutputSamplingRate(&afSamplingRate, nativeStreamType); 934 if (status != NO_ERROR) { 935 ALOGE("Error %d in AudioSystem::getOutputSamplingRate() for stream type %d " 936 "in AudioTrack JNI", status, nativeStreamType); 937 return DEFAULT_OUTPUT_SAMPLE_RATE; 938 } else { 939 return afSamplingRate; 940 } 941} 942 943 944// ---------------------------------------------------------------------------- 945// returns the minimum required size for the successful creation of a streaming AudioTrack 946// returns -1 if there was an error querying the hardware. 947static jint android_media_AudioTrack_get_min_buff_size(JNIEnv *env, jobject thiz, 948 jint sampleRateInHertz, jint channelCount, jint audioFormat) { 949 950 size_t frameCount; 951 const status_t status = AudioTrack::getMinFrameCount(&frameCount, AUDIO_STREAM_DEFAULT, 952 sampleRateInHertz); 953 if (status != NO_ERROR) { 954 ALOGE("AudioTrack::getMinFrameCount() for sample rate %d failed with status %d", 955 sampleRateInHertz, status); 956 return -1; 957 } 958 const audio_format_t format = audioFormatToNative(audioFormat); 959 if (audio_is_linear_pcm(format)) { 960 const size_t bytesPerSample = audio_bytes_per_sample(format); 961 return frameCount * channelCount * bytesPerSample; 962 } else { 963 return frameCount; 964 } 965} 966 967// ---------------------------------------------------------------------------- 968static jint 969android_media_AudioTrack_setAuxEffectSendLevel(JNIEnv *env, jobject thiz, jfloat level ) 970{ 971 sp<AudioTrack> lpTrack = getAudioTrack(env, thiz); 972 if (lpTrack == NULL ) { 973 jniThrowException(env, "java/lang/IllegalStateException", 974 "Unable to retrieve AudioTrack pointer for setAuxEffectSendLevel()"); 975 return -1; 976 } 977 978 status_t status = lpTrack->setAuxEffectSendLevel(level); 979 if (status != NO_ERROR) { 980 ALOGE("AudioTrack::setAuxEffectSendLevel() for level %g failed with status %d", 981 level, status); 982 } 983 return (jint) status; 984} 985 986// ---------------------------------------------------------------------------- 987static jint android_media_AudioTrack_attachAuxEffect(JNIEnv *env, jobject thiz, 988 jint effectId) { 989 sp<AudioTrack> lpTrack = getAudioTrack(env, thiz); 990 if (lpTrack == NULL) { 991 jniThrowException(env, "java/lang/IllegalStateException", 992 "Unable to retrieve AudioTrack pointer for attachAuxEffect()"); 993 return (jint)AUDIO_JAVA_ERROR; 994 } 995 return nativeToJavaStatus( lpTrack->attachAuxEffect(effectId) ); 996} 997 998static jboolean android_media_AudioTrack_setOutputDevice( 999 JNIEnv *env, jobject thiz, jint device_id) { 1000 1001 sp<AudioTrack> lpTrack = getAudioTrack(env, thiz); 1002 if (lpTrack == 0) { 1003 return false; 1004 } 1005 return lpTrack->setOutputDevice(device_id) == NO_ERROR; 1006} 1007 1008static jint android_media_AudioTrack_getRoutedDeviceId( 1009 JNIEnv *env, jobject thiz) { 1010 1011 sp<AudioTrack> lpTrack = getAudioTrack(env, thiz); 1012 if (lpTrack == NULL) { 1013 return 0; 1014 } 1015 return (jint)lpTrack->getRoutedDeviceId(); 1016} 1017 1018static void android_media_AudioTrack_enableDeviceCallback( 1019 JNIEnv *env, jobject thiz) { 1020 1021 sp<AudioTrack> lpTrack = getAudioTrack(env, thiz); 1022 if (lpTrack == NULL) { 1023 return; 1024 } 1025 AudioTrackJniStorage* pJniStorage = (AudioTrackJniStorage *)env->GetLongField( 1026 thiz, javaAudioTrackFields.jniData); 1027 if (pJniStorage == NULL || pJniStorage->mDeviceCallback != 0) { 1028 return; 1029 } 1030 pJniStorage->mDeviceCallback = 1031 new JNIDeviceCallback(env, thiz, pJniStorage->mCallbackData.audioTrack_ref, 1032 javaAudioTrackFields.postNativeEventInJava); 1033 lpTrack->addAudioDeviceCallback(pJniStorage->mDeviceCallback); 1034} 1035 1036static void android_media_AudioTrack_disableDeviceCallback( 1037 JNIEnv *env, jobject thiz) { 1038 1039 sp<AudioTrack> lpTrack = getAudioTrack(env, thiz); 1040 if (lpTrack == NULL) { 1041 return; 1042 } 1043 AudioTrackJniStorage* pJniStorage = (AudioTrackJniStorage *)env->GetLongField( 1044 thiz, javaAudioTrackFields.jniData); 1045 if (pJniStorage == NULL || pJniStorage->mDeviceCallback == 0) { 1046 return; 1047 } 1048 lpTrack->removeAudioDeviceCallback(pJniStorage->mDeviceCallback); 1049 pJniStorage->mDeviceCallback.clear(); 1050} 1051 1052 1053// ---------------------------------------------------------------------------- 1054// ---------------------------------------------------------------------------- 1055static JNINativeMethod gMethods[] = { 1056 // name, signature, funcPtr 1057 {"native_start", "()V", (void *)android_media_AudioTrack_start}, 1058 {"native_stop", "()V", (void *)android_media_AudioTrack_stop}, 1059 {"native_pause", "()V", (void *)android_media_AudioTrack_pause}, 1060 {"native_flush", "()V", (void *)android_media_AudioTrack_flush}, 1061 {"native_setup", "(Ljava/lang/Object;Ljava/lang/Object;IIIIII[I)I", 1062 (void *)android_media_AudioTrack_setup}, 1063 {"native_finalize", "()V", (void *)android_media_AudioTrack_finalize}, 1064 {"native_release", "()V", (void *)android_media_AudioTrack_release}, 1065 {"native_write_byte", "([BIIIZ)I",(void *)android_media_AudioTrack_writeArray<jbyteArray>}, 1066 {"native_write_native_bytes", 1067 "(Ljava/lang/Object;IIIZ)I", 1068 (void *)android_media_AudioTrack_write_native_bytes}, 1069 {"native_write_short", "([SIIIZ)I",(void *)android_media_AudioTrack_writeArray<jshortArray>}, 1070 {"native_write_float", "([FIIIZ)I",(void *)android_media_AudioTrack_writeArray<jfloatArray>}, 1071 {"native_setVolume", "(FF)V", (void *)android_media_AudioTrack_set_volume}, 1072 {"native_get_native_frame_count", 1073 "()I", (void *)android_media_AudioTrack_get_native_frame_count}, 1074 {"native_set_playback_rate", 1075 "(I)I", (void *)android_media_AudioTrack_set_playback_rate}, 1076 {"native_get_playback_rate", 1077 "()I", (void *)android_media_AudioTrack_get_playback_rate}, 1078 {"native_set_playback_params", 1079 "(Landroid/media/PlaybackParams;)V", 1080 (void *)android_media_AudioTrack_set_playback_params}, 1081 {"native_get_playback_params", 1082 "()Landroid/media/PlaybackParams;", 1083 (void *)android_media_AudioTrack_get_playback_params}, 1084 {"native_set_marker_pos","(I)I", (void *)android_media_AudioTrack_set_marker_pos}, 1085 {"native_get_marker_pos","()I", (void *)android_media_AudioTrack_get_marker_pos}, 1086 {"native_set_pos_update_period", 1087 "(I)I", (void *)android_media_AudioTrack_set_pos_update_period}, 1088 {"native_get_pos_update_period", 1089 "()I", (void *)android_media_AudioTrack_get_pos_update_period}, 1090 {"native_set_position", "(I)I", (void *)android_media_AudioTrack_set_position}, 1091 {"native_get_position", "()I", (void *)android_media_AudioTrack_get_position}, 1092 {"native_get_latency", "()I", (void *)android_media_AudioTrack_get_latency}, 1093 {"native_get_timestamp", "([J)I", (void *)android_media_AudioTrack_get_timestamp}, 1094 {"native_set_loop", "(III)I", (void *)android_media_AudioTrack_set_loop}, 1095 {"native_reload_static", "()I", (void *)android_media_AudioTrack_reload}, 1096 {"native_get_output_sample_rate", 1097 "(I)I", (void *)android_media_AudioTrack_get_output_sample_rate}, 1098 {"native_get_min_buff_size", 1099 "(III)I", (void *)android_media_AudioTrack_get_min_buff_size}, 1100 {"native_setAuxEffectSendLevel", 1101 "(F)I", (void *)android_media_AudioTrack_setAuxEffectSendLevel}, 1102 {"native_attachAuxEffect", 1103 "(I)I", (void *)android_media_AudioTrack_attachAuxEffect}, 1104 {"native_setOutputDevice", "(I)Z", 1105 (void *)android_media_AudioTrack_setOutputDevice}, 1106 {"native_getRoutedDeviceId", "()I", (void *)android_media_AudioTrack_getRoutedDeviceId}, 1107 {"native_enableDeviceCallback", "()V", (void *)android_media_AudioTrack_enableDeviceCallback}, 1108 {"native_disableDeviceCallback", "()V", (void *)android_media_AudioTrack_disableDeviceCallback}, 1109}; 1110 1111 1112// field names found in android/media/AudioTrack.java 1113#define JAVA_POSTEVENT_CALLBACK_NAME "postEventFromNative" 1114#define JAVA_NATIVETRACKINJAVAOBJ_FIELD_NAME "mNativeTrackInJavaObj" 1115#define JAVA_JNIDATA_FIELD_NAME "mJniData" 1116#define JAVA_STREAMTYPE_FIELD_NAME "mStreamType" 1117 1118// ---------------------------------------------------------------------------- 1119// preconditions: 1120// theClass is valid 1121bool android_media_getIntConstantFromClass(JNIEnv* pEnv, jclass theClass, const char* className, 1122 const char* constName, int* constVal) { 1123 jfieldID javaConst = NULL; 1124 javaConst = pEnv->GetStaticFieldID(theClass, constName, "I"); 1125 if (javaConst != NULL) { 1126 *constVal = pEnv->GetStaticIntField(theClass, javaConst); 1127 return true; 1128 } else { 1129 ALOGE("Can't find %s.%s", className, constName); 1130 return false; 1131 } 1132} 1133 1134 1135// ---------------------------------------------------------------------------- 1136int register_android_media_AudioTrack(JNIEnv *env) 1137{ 1138 javaAudioTrackFields.nativeTrackInJavaObj = NULL; 1139 javaAudioTrackFields.postNativeEventInJava = NULL; 1140 1141 // Get the AudioTrack class 1142 jclass audioTrackClass = FindClassOrDie(env, kClassPathName); 1143 1144 // Get the postEvent method 1145 javaAudioTrackFields.postNativeEventInJava = GetStaticMethodIDOrDie(env, 1146 audioTrackClass, JAVA_POSTEVENT_CALLBACK_NAME, 1147 "(Ljava/lang/Object;IIILjava/lang/Object;)V"); 1148 1149 // Get the variables fields 1150 // nativeTrackInJavaObj 1151 javaAudioTrackFields.nativeTrackInJavaObj = GetFieldIDOrDie(env, 1152 audioTrackClass, JAVA_NATIVETRACKINJAVAOBJ_FIELD_NAME, "J"); 1153 // jniData 1154 javaAudioTrackFields.jniData = GetFieldIDOrDie(env, 1155 audioTrackClass, JAVA_JNIDATA_FIELD_NAME, "J"); 1156 // fieldStreamType 1157 javaAudioTrackFields.fieldStreamType = GetFieldIDOrDie(env, 1158 audioTrackClass, JAVA_STREAMTYPE_FIELD_NAME, "I"); 1159 1160 env->DeleteLocalRef(audioTrackClass); 1161 1162 // Get the AudioAttributes class and fields 1163 jclass audioAttrClass = FindClassOrDie(env, kAudioAttributesClassPathName); 1164 javaAudioAttrFields.fieldUsage = GetFieldIDOrDie(env, audioAttrClass, "mUsage", "I"); 1165 javaAudioAttrFields.fieldContentType = GetFieldIDOrDie(env, 1166 audioAttrClass, "mContentType", "I"); 1167 javaAudioAttrFields.fieldFlags = GetFieldIDOrDie(env, audioAttrClass, "mFlags", "I"); 1168 javaAudioAttrFields.fieldFormattedTags = GetFieldIDOrDie(env, 1169 audioAttrClass, "mFormattedTags", "Ljava/lang/String;"); 1170 1171 env->DeleteLocalRef(audioAttrClass); 1172 1173 // initialize PlaybackParams field info 1174 gPlaybackParamsFields.init(env); 1175 1176 return RegisterMethodsOrDie(env, kClassPathName, gMethods, NELEM(gMethods)); 1177} 1178 1179 1180// ---------------------------------------------------------------------------- 1181