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