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