blob: 8d3a9aab80e5f597b4f89436ba0530fbb7d55449 [file] [log] [blame]
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001/*
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
Wei Jia071a8b72015-03-09 16:38:25 -070020#include "android_media_AudioTrack.h"
21
Glenn Kastenc81d31c2012-03-13 14:46:23 -070022#include <JNIHelp.h>
Jean-Michel Trivi7ca04522014-02-07 09:39:34 -080023#include <JniConstants.h>
Andreas Gampeed6b9df2014-11-20 22:02:20 -080024#include "core_jni_helpers.h"
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080025
Jean-Michel Trivi7ca04522014-02-07 09:39:34 -080026#include "ScopedBytes.h"
27
Glenn Kastenc81d31c2012-03-13 14:46:23 -070028#include <utils/Log.h>
29#include <media/AudioSystem.h>
30#include <media/AudioTrack.h>
Glenn Kasten37967d42012-11-28 14:37:36 -080031#include <audio_utils/primitives.h>
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080032
Mathias Agopian07952722009-05-19 19:08:10 -070033#include <binder/MemoryHeapBase.h>
34#include <binder/MemoryBase.h>
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080035
Glenn Kastenfe834d32014-01-08 14:49:08 -080036#include "android_media_AudioFormat.h"
Eric Laurentbc11a692014-05-16 12:19:25 -070037#include "android_media_AudioErrors.h"
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080038
39// ----------------------------------------------------------------------------
40
41using namespace android;
42
43// ----------------------------------------------------------------------------
44static const char* const kClassPathName = "android/media/AudioTrack";
Jean-Michel Trivia1d80e32014-06-18 08:18:41 -070045static const char* const kAudioAttributesClassPathName = "android/media/AudioAttributes";
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080046
Jean-Michel Trivia1d80e32014-06-18 08:18:41 -070047struct audio_track_fields_t {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080048 // these fields provide access from C++ to the...
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080049 jmethodID postNativeEventInJava; //... event post callback method
Eric Laurent83b36852009-07-28 07:49:22 -070050 jfieldID nativeTrackInJavaObj; // stores in Java the native AudioTrack object
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080051 jfieldID jniData; // stores in Java additional resources used by the native AudioTrack
Jean-Michel Trivia1d80e32014-06-18 08:18:41 -070052 jfieldID fieldStreamType; // ... mStreamType field in the AudioTrack Java object
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080053};
Jean-Michel Trivia1d80e32014-06-18 08:18:41 -070054struct audio_attributes_fields_t {
Jean-Michel Trivi701d6ff2014-07-16 07:51:22 -070055 jfieldID fieldUsage; // AudioAttributes.mUsage
56 jfieldID fieldContentType; // AudioAttributes.mContentType
57 jfieldID fieldFlags; // AudioAttributes.mFlags
58 jfieldID fieldFormattedTags;// AudioAttributes.mFormattedTags
Jean-Michel Trivia1d80e32014-06-18 08:18:41 -070059};
60static audio_track_fields_t javaAudioTrackFields;
61static audio_attributes_fields_t javaAudioAttrFields;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080062
63struct audiotrack_callback_cookie {
64 jclass audioTrack_class;
65 jobject audioTrack_ref;
Eric Laurent532bc1c2012-04-20 12:45:03 -070066 bool busy;
67 Condition cond;
68};
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080069
Glenn Kasten3d301cb2012-01-16 14:46:54 -080070// keep these values in sync with AudioTrack.java
71#define MODE_STATIC 0
72#define MODE_STREAM 1
73
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080074// ----------------------------------------------------------------------------
75class AudioTrackJniStorage {
76 public:
77 sp<MemoryHeapBase> mMemHeap;
78 sp<MemoryBase> mMemBase;
79 audiotrack_callback_cookie mCallbackData;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080080
81 AudioTrackJniStorage() {
Jean-Michel Trivi8a149682009-07-15 18:31:11 -070082 mCallbackData.audioTrack_class = 0;
83 mCallbackData.audioTrack_ref = 0;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080084 }
85
86 ~AudioTrackJniStorage() {
87 mMemBase.clear();
88 mMemHeap.clear();
89 }
90
91 bool allocSharedMem(int sizeInBytes) {
92 mMemHeap = new MemoryHeapBase(sizeInBytes, 0, "AudioTrack Heap Base");
93 if (mMemHeap->getHeapID() < 0) {
94 return false;
95 }
96 mMemBase = new MemoryBase(mMemHeap, 0, sizeInBytes);
97 return true;
98 }
99};
100
Eric Laurent532bc1c2012-04-20 12:45:03 -0700101static Mutex sLock;
102static SortedVector <audiotrack_callback_cookie *> sAudioTrackCallBackCookies;
103
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800104// ----------------------------------------------------------------------------
105#define DEFAULT_OUTPUT_SAMPLE_RATE 44100
106
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800107#define AUDIOTRACK_ERROR_SETUP_AUDIOSYSTEM -16
Glenn Kastenfb2ab9e2011-12-12 09:05:55 -0800108#define AUDIOTRACK_ERROR_SETUP_INVALIDCHANNELMASK -17
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800109#define AUDIOTRACK_ERROR_SETUP_INVALIDFORMAT -18
110#define AUDIOTRACK_ERROR_SETUP_INVALIDSTREAMTYPE -19
111#define AUDIOTRACK_ERROR_SETUP_NATIVEINITFAILED -20
112
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800113// ----------------------------------------------------------------------------
Glenn Kastene46a86f2011-06-01 15:20:35 -0700114static void audioCallback(int event, void* user, void *info) {
Eric Laurent532bc1c2012-04-20 12:45:03 -0700115
116 audiotrack_callback_cookie *callbackInfo = (audiotrack_callback_cookie *)user;
117 {
118 Mutex::Autolock l(sLock);
119 if (sAudioTrackCallBackCookies.indexOf(callbackInfo) < 0) {
120 return;
121 }
122 callbackInfo->busy = true;
123 }
124
Glenn Kasten5b1576c2013-07-18 16:58:19 -0700125 switch (event) {
126 case AudioTrack::EVENT_MARKER: {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800127 JNIEnv *env = AndroidRuntime::getJNIEnv();
Glenn Kastena667ff32013-07-22 07:36:34 -0700128 if (user != NULL && env != NULL) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800129 env->CallStaticVoidMethod(
Glenn Kasten18db49a2012-03-12 16:29:55 -0700130 callbackInfo->audioTrack_class,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800131 javaAudioTrackFields.postNativeEventInJava,
132 callbackInfo->audioTrack_ref, event, 0,0, NULL);
133 if (env->ExceptionCheck()) {
134 env->ExceptionDescribe();
135 env->ExceptionClear();
136 }
137 }
Glenn Kasten5b1576c2013-07-18 16:58:19 -0700138 } break;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800139
Glenn Kasten5b1576c2013-07-18 16:58:19 -0700140 case AudioTrack::EVENT_NEW_POS: {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800141 JNIEnv *env = AndroidRuntime::getJNIEnv();
Glenn Kastena667ff32013-07-22 07:36:34 -0700142 if (user != NULL && env != NULL) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800143 env->CallStaticVoidMethod(
Glenn Kasten18db49a2012-03-12 16:29:55 -0700144 callbackInfo->audioTrack_class,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800145 javaAudioTrackFields.postNativeEventInJava,
146 callbackInfo->audioTrack_ref, event, 0,0, NULL);
147 if (env->ExceptionCheck()) {
148 env->ExceptionDescribe();
149 env->ExceptionClear();
150 }
151 }
Glenn Kasten5b1576c2013-07-18 16:58:19 -0700152 } break;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800153 }
Glenn Kasten5b1576c2013-07-18 16:58:19 -0700154
Eric Laurent532bc1c2012-04-20 12:45:03 -0700155 {
156 Mutex::Autolock l(sLock);
157 callbackInfo->busy = false;
158 callbackInfo->cond.broadcast();
159 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800160}
161
162
163// ----------------------------------------------------------------------------
Eric Laurent532bc1c2012-04-20 12:45:03 -0700164static sp<AudioTrack> getAudioTrack(JNIEnv* env, jobject thiz)
165{
166 Mutex::Autolock l(sLock);
167 AudioTrack* const at =
Ashok Bhat075e9a12014-01-06 13:45:09 +0000168 (AudioTrack*)env->GetLongField(thiz, javaAudioTrackFields.nativeTrackInJavaObj);
Eric Laurent532bc1c2012-04-20 12:45:03 -0700169 return sp<AudioTrack>(at);
170}
171
172static sp<AudioTrack> setAudioTrack(JNIEnv* env, jobject thiz, const sp<AudioTrack>& at)
173{
174 Mutex::Autolock l(sLock);
175 sp<AudioTrack> old =
Ashok Bhat075e9a12014-01-06 13:45:09 +0000176 (AudioTrack*)env->GetLongField(thiz, javaAudioTrackFields.nativeTrackInJavaObj);
Eric Laurent532bc1c2012-04-20 12:45:03 -0700177 if (at.get()) {
Mathias Agopianb1d90c82013-03-06 17:45:42 -0800178 at->incStrong((void*)setAudioTrack);
Eric Laurent532bc1c2012-04-20 12:45:03 -0700179 }
180 if (old != 0) {
Mathias Agopianb1d90c82013-03-06 17:45:42 -0800181 old->decStrong((void*)setAudioTrack);
Eric Laurent532bc1c2012-04-20 12:45:03 -0700182 }
Ashok Bhat075e9a12014-01-06 13:45:09 +0000183 env->SetLongField(thiz, javaAudioTrackFields.nativeTrackInJavaObj, (jlong)at.get());
Eric Laurent532bc1c2012-04-20 12:45:03 -0700184 return old;
185}
Wei Jia071a8b72015-03-09 16:38:25 -0700186
187// ----------------------------------------------------------------------------
188sp<AudioTrack> android_media_AudioTrack_getAudioTrack(JNIEnv* env, jobject audioTrackObj) {
189 return getAudioTrack(env, audioTrackObj);
190}
191
Eric Laurent532bc1c2012-04-20 12:45:03 -0700192// ----------------------------------------------------------------------------
Ashok Bhat075e9a12014-01-06 13:45:09 +0000193static jint
Jean-Michel Trivieac84382014-02-04 14:50:40 -0800194android_media_AudioTrack_setup(JNIEnv *env, jobject thiz, jobject weak_this,
Jean-Michel Trivia1d80e32014-06-18 08:18:41 -0700195 jobject jaa,
196 jint sampleRateInHertz, jint javaChannelMask,
197 jint audioFormat, jint buffSizeInBytes, jint memoryMode, jintArray jSession) {
198
Steve Block71f2cf12011-10-20 11:56:00 +0100199 ALOGV("sampleRate=%d, audioFormat(from Java)=%d, channel mask=%x, buffSize=%d",
Jean-Michel Trivid9ae1c52011-07-25 12:58:14 -0700200 sampleRateInHertz, audioFormat, javaChannelMask, buffSizeInBytes);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800201
Jean-Michel Trivia1d80e32014-06-18 08:18:41 -0700202 if (jaa == 0) {
203 ALOGE("Error creating AudioTrack: invalid audio attributes");
204 return (jint) AUDIO_JAVA_ERROR;
205 }
206
Andy Hunga9470c12015-01-29 17:16:03 -0800207 // Java channel masks don't map directly to the native definition for positional
208 // channel masks: it's a shift by 2 to skip the two deprecated channel
209 // configurations "default" and "mono".
210 // Invalid channel representations are caught by !audio_is_output_channel() below.
211 audio_channel_mask_t nativeChannelMask =
212 audio_channel_mask_get_representation(javaChannelMask)
213 == AUDIO_CHANNEL_REPRESENTATION_POSITION
214 ? javaChannelMask >> 2 : javaChannelMask;
Jean-Michel Trivid9ae1c52011-07-25 12:58:14 -0700215
216 if (!audio_is_output_channel(nativeChannelMask)) {
Glenn Kasten33c437d2013-07-18 17:04:21 -0700217 ALOGE("Error creating AudioTrack: invalid channel mask %#x.", javaChannelMask);
Ashok Bhat075e9a12014-01-06 13:45:09 +0000218 return (jint) AUDIOTRACK_ERROR_SETUP_INVALIDCHANNELMASK;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800219 }
Jean-Michel Trivid9ae1c52011-07-25 12:58:14 -0700220
Eric Laurentdbf55662014-07-01 18:56:30 -0700221 uint32_t channelCount = audio_channel_count_from_out_mask(nativeChannelMask);
Glenn Kasten18db49a2012-03-12 16:29:55 -0700222
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800223 // check the format.
224 // This function was called from Java, so we compare the format against the Java constants
Glenn Kastenfe834d32014-01-08 14:49:08 -0800225 audio_format_t format = audioFormatToNative(audioFormat);
226 if (format == AUDIO_FORMAT_INVALID) {
Glenn Kasten8f81d082012-11-28 14:37:48 -0800227 ALOGE("Error creating AudioTrack: unsupported audio format %d.", audioFormat);
Ashok Bhat075e9a12014-01-06 13:45:09 +0000228 return (jint) AUDIOTRACK_ERROR_SETUP_INVALIDFORMAT;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800229 }
230
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800231 // compute the frame count
Eric Laurentff0d9f02014-06-09 17:23:02 -0700232 size_t frameCount;
233 if (audio_is_linear_pcm(format)) {
234 const size_t bytesPerSample = audio_bytes_per_sample(format);
235 frameCount = buffSizeInBytes / (channelCount * bytesPerSample);
236 } else {
237 frameCount = buffSizeInBytes;
238 }
Glenn Kasten18db49a2012-03-12 16:29:55 -0700239
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800240 jclass clazz = env->GetObjectClass(thiz);
241 if (clazz == NULL) {
Steve Block3762c312012-01-06 19:20:56 +0000242 ALOGE("Can't find %s when setting up callback.", kClassPathName);
Ashok Bhat075e9a12014-01-06 13:45:09 +0000243 return (jint) AUDIOTRACK_ERROR_SETUP_NATIVEINITFAILED;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800244 }
Eric Laurent2fb43ef2010-09-24 12:03:36 -0700245
246 if (jSession == NULL) {
Steve Block3762c312012-01-06 19:20:56 +0000247 ALOGE("Error creating AudioTrack: invalid session ID pointer");
Eric Laurentbc11a692014-05-16 12:19:25 -0700248 return (jint) AUDIO_JAVA_ERROR;
Eric Laurent619346f2010-06-21 09:27:30 -0700249 }
250
Eric Laurent2fb43ef2010-09-24 12:03:36 -0700251 jint* nSession = (jint *) env->GetPrimitiveArrayCritical(jSession, NULL);
252 if (nSession == NULL) {
Steve Block3762c312012-01-06 19:20:56 +0000253 ALOGE("Error creating AudioTrack: Error retrieving session id pointer");
Eric Laurentbc11a692014-05-16 12:19:25 -0700254 return (jint) AUDIO_JAVA_ERROR;
Eric Laurent2fb43ef2010-09-24 12:03:36 -0700255 }
256 int sessionId = nSession[0];
257 env->ReleasePrimitiveArrayCritical(jSession, nSession, 0);
258 nSession = NULL;
259
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800260 // create the native AudioTrack object
Eric Laurent532bc1c2012-04-20 12:45:03 -0700261 sp<AudioTrack> lpTrack = new AudioTrack();
Glenn Kasten18db49a2012-03-12 16:29:55 -0700262
Jean-Michel Trivia1d80e32014-06-18 08:18:41 -0700263 audio_attributes_t *paa = NULL;
264 // read the AudioAttributes values
265 paa = (audio_attributes_t *) calloc(1, sizeof(audio_attributes_t));
Jean-Michel Trivi701d6ff2014-07-16 07:51:22 -0700266 const jstring jtags =
267 (jstring) env->GetObjectField(jaa, javaAudioAttrFields.fieldFormattedTags);
Jean-Michel Trivia1d80e32014-06-18 08:18:41 -0700268 const char* tags = env->GetStringUTFChars(jtags, NULL);
269 // copying array size -1, char array for tags was calloc'd, no need to NULL-terminate it
270 strncpy(paa->tags, tags, AUDIO_ATTRIBUTES_TAGS_MAX_SIZE - 1);
271 env->ReleaseStringUTFChars(jtags, tags);
272 paa->usage = (audio_usage_t) env->GetIntField(jaa, javaAudioAttrFields.fieldUsage);
273 paa->content_type =
274 (audio_content_type_t) env->GetIntField(jaa, javaAudioAttrFields.fieldContentType);
275 paa->flags = env->GetIntField(jaa, javaAudioAttrFields.fieldFlags);
276
277 ALOGV("AudioTrack_setup for usage=%d content=%d flags=0x%#x tags=%s",
278 paa->usage, paa->content_type, paa->flags, paa->tags);
279
Eric Laurent532bc1c2012-04-20 12:45:03 -0700280 // initialize the callback information:
281 // this data will be passed with every AudioTrack callback
282 AudioTrackJniStorage* lpJniStorage = new AudioTrackJniStorage();
Eric Laurent532bc1c2012-04-20 12:45:03 -0700283 lpJniStorage->mCallbackData.audioTrack_class = (jclass)env->NewGlobalRef(clazz);
284 // we use a weak reference so the AudioTrack object can be garbage collected.
285 lpJniStorage->mCallbackData.audioTrack_ref = env->NewGlobalRef(weak_this);
286 lpJniStorage->mCallbackData.busy = false;
287
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800288 // initialize the native AudioTrack object
Jean-Michel Trivi2defed92014-05-14 18:15:59 -0700289 status_t status = NO_ERROR;
Glenn Kasten3d301cb2012-01-16 14:46:54 -0800290 switch (memoryMode) {
291 case MODE_STREAM:
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800292
Glenn Kastenc5d14242014-03-28 16:19:52 -0700293 status = lpTrack->set(
Jean-Michel Trivic8d6b6f2014-07-28 09:52:14 -0700294 AUDIO_STREAM_DEFAULT,// stream type, but more info conveyed in paa (last argument)
Jean-Michel Trivia1d80e32014-06-18 08:18:41 -0700295 sampleRateInHertz,
296 format,// word length, PCM
297 nativeChannelMask,
298 frameCount,
299 AUDIO_OUTPUT_FLAG_NONE,
300 audioCallback, &(lpJniStorage->mCallbackData),//callback, callback data (user)
301 0,// notificationFrames == 0 since not using EVENT_MORE_DATA to feed the AudioTrack
302 0,// shared mem
303 true,// thread can call Java
304 sessionId,// audio session ID
Jean-Michel Trivic8d6b6f2014-07-28 09:52:14 -0700305 AudioTrack::TRANSFER_SYNC,
Jean-Michel Trivia1d80e32014-06-18 08:18:41 -0700306 NULL, // default offloadInfo
307 -1, -1, // default uid, pid values
308 paa);
Glenn Kasten3d301cb2012-01-16 14:46:54 -0800309 break;
Glenn Kasten18db49a2012-03-12 16:29:55 -0700310
Glenn Kasten3d301cb2012-01-16 14:46:54 -0800311 case MODE_STATIC:
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800312 // AudioTrack is using shared memory
Glenn Kasten18db49a2012-03-12 16:29:55 -0700313
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800314 if (!lpJniStorage->allocSharedMem(buffSizeInBytes)) {
Steve Block3762c312012-01-06 19:20:56 +0000315 ALOGE("Error creating AudioTrack in static mode: error creating mem heap base");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800316 goto native_init_failure;
317 }
Glenn Kasten18db49a2012-03-12 16:29:55 -0700318
Glenn Kastenc5d14242014-03-28 16:19:52 -0700319 status = lpTrack->set(
Jean-Michel Trivic8d6b6f2014-07-28 09:52:14 -0700320 AUDIO_STREAM_DEFAULT,// stream type, but more info conveyed in paa (last argument)
Jean-Michel Trivia1d80e32014-06-18 08:18:41 -0700321 sampleRateInHertz,
322 format,// word length, PCM
323 nativeChannelMask,
324 frameCount,
325 AUDIO_OUTPUT_FLAG_NONE,
326 audioCallback, &(lpJniStorage->mCallbackData),//callback, callback data (user));
327 0,// notificationFrames == 0 since not using EVENT_MORE_DATA to feed the AudioTrack
328 lpJniStorage->mMemBase,// shared mem
329 true,// thread can call Java
330 sessionId,// audio session ID
Jean-Michel Trivic8d6b6f2014-07-28 09:52:14 -0700331 AudioTrack::TRANSFER_SHARED,
Jean-Michel Trivia1d80e32014-06-18 08:18:41 -0700332 NULL, // default offloadInfo
333 -1, -1, // default uid, pid values
334 paa);
Glenn Kasten3d301cb2012-01-16 14:46:54 -0800335 break;
336
337 default:
338 ALOGE("Unknown mode %d", memoryMode);
339 goto native_init_failure;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800340 }
341
Glenn Kastenc5d14242014-03-28 16:19:52 -0700342 if (status != NO_ERROR) {
343 ALOGE("Error %d initializing AudioTrack", status);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800344 goto native_init_failure;
345 }
346
Eric Laurent2fb43ef2010-09-24 12:03:36 -0700347 nSession = (jint *) env->GetPrimitiveArrayCritical(jSession, NULL);
348 if (nSession == NULL) {
Steve Block3762c312012-01-06 19:20:56 +0000349 ALOGE("Error creating AudioTrack: Error retrieving session id pointer");
Eric Laurent2fb43ef2010-09-24 12:03:36 -0700350 goto native_init_failure;
351 }
Eric Laurent619346f2010-06-21 09:27:30 -0700352 // read the audio session ID back from AudioTrack in case we create a new session
353 nSession[0] = lpTrack->getSessionId();
Eric Laurent619346f2010-06-21 09:27:30 -0700354 env->ReleasePrimitiveArrayCritical(jSession, nSession, 0);
355 nSession = NULL;
356
Eric Laurent532bc1c2012-04-20 12:45:03 -0700357 { // scope for the lock
358 Mutex::Autolock l(sLock);
359 sAudioTrackCallBackCookies.add(&lpJniStorage->mCallbackData);
360 }
Glenn Kasten18db49a2012-03-12 16:29:55 -0700361 // save our newly created C++ AudioTrack in the "nativeTrackInJavaObj" field
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800362 // of the Java object (in mNativeTrackInJavaObj)
Eric Laurent532bc1c2012-04-20 12:45:03 -0700363 setAudioTrack(env, thiz, lpTrack);
Glenn Kasten18db49a2012-03-12 16:29:55 -0700364
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800365 // save the JNI resources so we can free them later
Ashok Bhat075e9a12014-01-06 13:45:09 +0000366 //ALOGV("storing lpJniStorage: %x\n", (long)lpJniStorage);
367 env->SetLongField(thiz, javaAudioTrackFields.jniData, (jlong)lpJniStorage);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800368
Jean-Michel Trivia1d80e32014-06-18 08:18:41 -0700369 // since we had audio attributes, the stream type was derived from them during the
370 // creation of the native AudioTrack: push the same value to the Java object
371 env->SetIntField(thiz, javaAudioTrackFields.fieldStreamType, (jint) lpTrack->streamType());
372 // audio attributes were copied in AudioTrack creation
373 free(paa);
374 paa = NULL;
375
376
Eric Laurentbc11a692014-05-16 12:19:25 -0700377 return (jint) AUDIO_JAVA_SUCCESS;
Glenn Kasten18db49a2012-03-12 16:29:55 -0700378
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800379 // failures:
380native_init_failure:
Jean-Michel Trivia1d80e32014-06-18 08:18:41 -0700381 if (paa != NULL) {
382 free(paa);
383 }
Eric Laurent619346f2010-06-21 09:27:30 -0700384 if (nSession != NULL) {
385 env->ReleasePrimitiveArrayCritical(jSession, nSession, 0);
386 }
Jean-Michel Trivi8a149682009-07-15 18:31:11 -0700387 env->DeleteGlobalRef(lpJniStorage->mCallbackData.audioTrack_class);
388 env->DeleteGlobalRef(lpJniStorage->mCallbackData.audioTrack_ref);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800389 delete lpJniStorage;
Ashok Bhat075e9a12014-01-06 13:45:09 +0000390 env->SetLongField(thiz, javaAudioTrackFields.jniData, 0);
Glenn Kasten18db49a2012-03-12 16:29:55 -0700391
Ashok Bhat075e9a12014-01-06 13:45:09 +0000392 return (jint) AUDIOTRACK_ERROR_SETUP_NATIVEINITFAILED;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800393}
394
395
396// ----------------------------------------------------------------------------
397static void
398android_media_AudioTrack_start(JNIEnv *env, jobject thiz)
399{
Eric Laurent532bc1c2012-04-20 12:45:03 -0700400 sp<AudioTrack> lpTrack = getAudioTrack(env, thiz);
401 if (lpTrack == NULL) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800402 jniThrowException(env, "java/lang/IllegalStateException",
403 "Unable to retrieve AudioTrack pointer for start()");
Eric Laurent7070b362010-07-16 07:43:46 -0700404 return;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800405 }
Jean-Michel Trivi21dc0372009-05-08 16:06:34 -0700406
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800407 lpTrack->start();
408}
409
410
411// ----------------------------------------------------------------------------
412static void
413android_media_AudioTrack_stop(JNIEnv *env, jobject thiz)
414{
Eric Laurent532bc1c2012-04-20 12:45:03 -0700415 sp<AudioTrack> lpTrack = getAudioTrack(env, thiz);
416 if (lpTrack == NULL) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800417 jniThrowException(env, "java/lang/IllegalStateException",
418 "Unable to retrieve AudioTrack pointer for stop()");
Eric Laurent7070b362010-07-16 07:43:46 -0700419 return;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800420 }
421
422 lpTrack->stop();
423}
424
425
426// ----------------------------------------------------------------------------
427static void
428android_media_AudioTrack_pause(JNIEnv *env, jobject thiz)
429{
Eric Laurent532bc1c2012-04-20 12:45:03 -0700430 sp<AudioTrack> lpTrack = getAudioTrack(env, thiz);
431 if (lpTrack == NULL) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800432 jniThrowException(env, "java/lang/IllegalStateException",
433 "Unable to retrieve AudioTrack pointer for pause()");
Eric Laurent7070b362010-07-16 07:43:46 -0700434 return;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800435 }
436
437 lpTrack->pause();
438}
439
440
441// ----------------------------------------------------------------------------
442static void
443android_media_AudioTrack_flush(JNIEnv *env, jobject thiz)
444{
Eric Laurent532bc1c2012-04-20 12:45:03 -0700445 sp<AudioTrack> lpTrack = getAudioTrack(env, thiz);
446 if (lpTrack == NULL) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800447 jniThrowException(env, "java/lang/IllegalStateException",
448 "Unable to retrieve AudioTrack pointer for flush()");
Eric Laurent7070b362010-07-16 07:43:46 -0700449 return;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800450 }
451
452 lpTrack->flush();
453}
454
455// ----------------------------------------------------------------------------
456static void
457android_media_AudioTrack_set_volume(JNIEnv *env, jobject thiz, jfloat leftVol, jfloat rightVol )
458{
Eric Laurent532bc1c2012-04-20 12:45:03 -0700459 sp<AudioTrack> lpTrack = getAudioTrack(env, thiz);
460 if (lpTrack == NULL) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800461 jniThrowException(env, "java/lang/IllegalStateException",
462 "Unable to retrieve AudioTrack pointer for setVolume()");
Eric Laurent7070b362010-07-16 07:43:46 -0700463 return;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800464 }
465
466 lpTrack->setVolume(leftVol, rightVol);
467}
468
469// ----------------------------------------------------------------------------
Glenn Kasten18db49a2012-03-12 16:29:55 -0700470
Eric Laurent532bc1c2012-04-20 12:45:03 -0700471#define CALLBACK_COND_WAIT_TIMEOUT_MS 1000
Jean-Michel Trivieac84382014-02-04 14:50:40 -0800472static void android_media_AudioTrack_release(JNIEnv *env, jobject thiz) {
Eric Laurent532bc1c2012-04-20 12:45:03 -0700473 sp<AudioTrack> lpTrack = setAudioTrack(env, thiz, 0);
474 if (lpTrack == NULL) {
475 return;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800476 }
Eric Laurent532bc1c2012-04-20 12:45:03 -0700477 //ALOGV("deleting lpTrack: %x\n", (int)lpTrack);
478 lpTrack->stop();
Glenn Kasten18db49a2012-03-12 16:29:55 -0700479
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800480 // delete the JNI data
Ashok Bhat075e9a12014-01-06 13:45:09 +0000481 AudioTrackJniStorage* pJniStorage = (AudioTrackJniStorage *)env->GetLongField(
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800482 thiz, javaAudioTrackFields.jniData);
Eric Laurent532bc1c2012-04-20 12:45:03 -0700483 // reset the native resources in the Java object so any attempt to access
484 // them after a call to release fails.
Ashok Bhat075e9a12014-01-06 13:45:09 +0000485 env->SetLongField(thiz, javaAudioTrackFields.jniData, 0);
Eric Laurent532bc1c2012-04-20 12:45:03 -0700486
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800487 if (pJniStorage) {
Eric Laurent532bc1c2012-04-20 12:45:03 -0700488 Mutex::Autolock l(sLock);
489 audiotrack_callback_cookie *lpCookie = &pJniStorage->mCallbackData;
Steve Block71f2cf12011-10-20 11:56:00 +0100490 //ALOGV("deleting pJniStorage: %x\n", (int)pJniStorage);
Eric Laurent532bc1c2012-04-20 12:45:03 -0700491 while (lpCookie->busy) {
492 if (lpCookie->cond.waitRelative(sLock,
493 milliseconds(CALLBACK_COND_WAIT_TIMEOUT_MS)) !=
494 NO_ERROR) {
495 break;
496 }
497 }
498 sAudioTrackCallBackCookies.remove(lpCookie);
499 // delete global refs created in native_setup
500 env->DeleteGlobalRef(lpCookie->audioTrack_class);
501 env->DeleteGlobalRef(lpCookie->audioTrack_ref);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800502 delete pJniStorage;
503 }
504}
505
Glenn Kasten18db49a2012-03-12 16:29:55 -0700506
Eric Laurent532bc1c2012-04-20 12:45:03 -0700507// ----------------------------------------------------------------------------
Jean-Michel Trivieac84382014-02-04 14:50:40 -0800508static void android_media_AudioTrack_finalize(JNIEnv *env, jobject thiz) {
509 //ALOGV("android_media_AudioTrack_finalize jobject: %x\n", (int)thiz);
510 android_media_AudioTrack_release(env, thiz);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800511}
512
Andy Hung4aacc902015-04-14 15:01:29 -0700513// overloaded JNI array helper functions (same as in android_media_AudioRecord)
514static inline
515jbyte *envGetArrayElements(JNIEnv *env, jbyteArray array, jboolean *isCopy) {
516 return env->GetByteArrayElements(array, isCopy);
517}
518
519static inline
520void envReleaseArrayElements(JNIEnv *env, jbyteArray array, jbyte *elems, jint mode) {
521 env->ReleaseByteArrayElements(array, elems, mode);
522}
523
524static inline
525jshort *envGetArrayElements(JNIEnv *env, jshortArray array, jboolean *isCopy) {
526 return env->GetShortArrayElements(array, isCopy);
527}
528
529static inline
530void envReleaseArrayElements(JNIEnv *env, jshortArray array, jshort *elems, jint mode) {
531 env->ReleaseShortArrayElements(array, elems, mode);
532}
533
534static inline
535jfloat *envGetArrayElements(JNIEnv *env, jfloatArray array, jboolean *isCopy) {
536 return env->GetFloatArrayElements(array, isCopy);
537}
538
539static inline
540void envReleaseArrayElements(JNIEnv *env, jfloatArray array, jfloat *elems, jint mode) {
541 env->ReleaseFloatArrayElements(array, elems, mode);
542}
543
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800544// ----------------------------------------------------------------------------
Andy Hung4aacc902015-04-14 15:01:29 -0700545template <typename T>
546static jint writeToTrack(const sp<AudioTrack>& track, jint audioFormat, const T *data,
547 jint offsetInSamples, jint sizeInSamples, bool blocking) {
Jean-Michel Trivi21dc0372009-05-08 16:06:34 -0700548 // give the data to the native AudioTrack object (the data starts at the offset)
549 ssize_t written = 0;
550 // regular write() or copy the data to the AudioTrack's shared memory?
Andy Hung4aacc902015-04-14 15:01:29 -0700551 size_t sizeInBytes = sizeInSamples * sizeof(T);
Eric Laurent532bc1c2012-04-20 12:45:03 -0700552 if (track->sharedBuffer() == 0) {
Andy Hung4aacc902015-04-14 15:01:29 -0700553 written = track->write(data + offsetInSamples, sizeInBytes, blocking);
Glenn Kasten9b53db32013-07-10 14:13:39 -0700554 // for compatibility with earlier behavior of write(), return 0 in this case
555 if (written == (ssize_t) WOULD_BLOCK) {
556 written = 0;
557 }
Jean-Michel Trivi21dc0372009-05-08 16:06:34 -0700558 } else {
Andy Hung2c0e17c2015-01-12 15:07:14 -0800559 // writing to shared memory, check for capacity
560 if ((size_t)sizeInBytes > track->sharedBuffer()->size()) {
561 sizeInBytes = track->sharedBuffer()->size();
Jean-Michel Trivi21dc0372009-05-08 16:06:34 -0700562 }
Andy Hung4aacc902015-04-14 15:01:29 -0700563 memcpy(track->sharedBuffer()->pointer(), data + offsetInSamples, sizeInBytes);
Andy Hung2c0e17c2015-01-12 15:07:14 -0800564 written = sizeInBytes;
Jean-Michel Trivi21dc0372009-05-08 16:06:34 -0700565 }
Andy Hung4aacc902015-04-14 15:01:29 -0700566 if (written > 0) {
567 return written / sizeof(T);
568 }
569 // for compatibility, error codes pass through unchanged
Jean-Michel Trivi21dc0372009-05-08 16:06:34 -0700570 return written;
Jean-Michel Trivi21dc0372009-05-08 16:06:34 -0700571}
572
573// ----------------------------------------------------------------------------
Andy Hung4aacc902015-04-14 15:01:29 -0700574template <typename T>
575static jint android_media_AudioTrack_writeArray(JNIEnv *env, jobject thiz,
576 T javaAudioData,
577 jint offsetInSamples, jint sizeInSamples,
578 jint javaAudioFormat,
579 jboolean isWriteBlocking) {
580 //ALOGV("android_media_AudioTrack_writeArray(offset=%d, sizeInSamples=%d) called",
581 // offsetInSamples, sizeInSamples);
Eric Laurent532bc1c2012-04-20 12:45:03 -0700582 sp<AudioTrack> lpTrack = getAudioTrack(env, thiz);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800583 if (lpTrack == NULL) {
584 jniThrowException(env, "java/lang/IllegalStateException",
585 "Unable to retrieve AudioTrack pointer for write()");
Andy Hung4aacc902015-04-14 15:01:29 -0700586 return (jint)AUDIO_JAVA_INVALID_OPERATION;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800587 }
588
Andy Hung4aacc902015-04-14 15:01:29 -0700589 if (javaAudioData == NULL) {
590 ALOGE("NULL java array of audio data to play");
591 return (jint)AUDIO_JAVA_BAD_VALUE;
592 }
593
Eric Laurent421ddc02011-03-07 14:52:59 -0800594 // NOTE: We may use GetPrimitiveArrayCritical() when the JNI implementation changes in such
595 // a way that it becomes much more efficient. When doing so, we will have to prevent the
596 // AudioSystem callback to be called while in critical section (in case of media server
597 // process crash for instance)
Andy Hung4aacc902015-04-14 15:01:29 -0700598
599 // get the pointer for the audio data from the java array
600 auto cAudioData = envGetArrayElements(env, javaAudioData, NULL);
601 if (cAudioData == NULL) {
602 ALOGE("Error retrieving source of audio data to play");
603 return (jint)AUDIO_JAVA_BAD_VALUE; // out of memory or no data to load
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800604 }
605
Andy Hung4aacc902015-04-14 15:01:29 -0700606 jint samplesWritten = writeToTrack(lpTrack, javaAudioFormat, cAudioData,
607 offsetInSamples, sizeInSamples, isWriteBlocking == JNI_TRUE /* blocking */);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800608
Andy Hung4aacc902015-04-14 15:01:29 -0700609 envReleaseArrayElements(env, javaAudioData, cAudioData, 0);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800610
Andy Hung4aacc902015-04-14 15:01:29 -0700611 //ALOGV("write wrote %d (tried %d) samples in the native AudioTrack with offset %d",
612 // (int)samplesWritten, (int)(sizeInSamples), (int)offsetInSamples);
613 return samplesWritten;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800614}
615
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800616// ----------------------------------------------------------------------------
Jean-Michel Trivi7ca04522014-02-07 09:39:34 -0800617static jint android_media_AudioTrack_write_native_bytes(JNIEnv *env, jobject thiz,
Jean-Michel Trivi5d21f672014-03-20 17:02:31 -0700618 jbyteArray javaBytes, jint byteOffset, jint sizeInBytes,
Jean-Michel Trivi7ca04522014-02-07 09:39:34 -0800619 jint javaAudioFormat, jboolean isWriteBlocking) {
620 //ALOGV("android_media_AudioTrack_write_native_bytes(offset=%d, sizeInBytes=%d) called",
621 // offsetInBytes, sizeInBytes);
622 sp<AudioTrack> lpTrack = getAudioTrack(env, thiz);
623 if (lpTrack == NULL) {
624 jniThrowException(env, "java/lang/IllegalStateException",
625 "Unable to retrieve AudioTrack pointer for write()");
Andy Hung4aacc902015-04-14 15:01:29 -0700626 return (jint)AUDIO_JAVA_INVALID_OPERATION;
Jean-Michel Trivi7ca04522014-02-07 09:39:34 -0800627 }
628
629 ScopedBytesRO bytes(env, javaBytes);
630 if (bytes.get() == NULL) {
631 ALOGE("Error retrieving source of audio data to play, can't play");
Eric Laurentbc11a692014-05-16 12:19:25 -0700632 return (jint)AUDIO_JAVA_BAD_VALUE;
Jean-Michel Trivi7ca04522014-02-07 09:39:34 -0800633 }
634
Jean-Michel Trivi5d21f672014-03-20 17:02:31 -0700635 jint written = writeToTrack(lpTrack, javaAudioFormat, bytes.get(), byteOffset,
Jean-Michel Trivi7ca04522014-02-07 09:39:34 -0800636 sizeInBytes, isWriteBlocking == JNI_TRUE /* blocking */);
637
638 return written;
639}
640
641// ----------------------------------------------------------------------------
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800642static jint android_media_AudioTrack_get_native_frame_count(JNIEnv *env, jobject thiz) {
Eric Laurent532bc1c2012-04-20 12:45:03 -0700643 sp<AudioTrack> lpTrack = getAudioTrack(env, thiz);
644 if (lpTrack == NULL) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800645 jniThrowException(env, "java/lang/IllegalStateException",
646 "Unable to retrieve AudioTrack pointer for frameCount()");
Eric Laurentbc11a692014-05-16 12:19:25 -0700647 return (jint)AUDIO_JAVA_ERROR;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800648 }
Eric Laurent532bc1c2012-04-20 12:45:03 -0700649
650 return lpTrack->frameCount();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800651}
652
653
654// ----------------------------------------------------------------------------
Eric Laurent88e209d2009-07-07 07:10:45 -0700655static jint android_media_AudioTrack_set_playback_rate(JNIEnv *env, jobject thiz,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800656 jint sampleRateInHz) {
Eric Laurent532bc1c2012-04-20 12:45:03 -0700657 sp<AudioTrack> lpTrack = getAudioTrack(env, thiz);
658 if (lpTrack == NULL) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800659 jniThrowException(env, "java/lang/IllegalStateException",
660 "Unable to retrieve AudioTrack pointer for setSampleRate()");
Eric Laurentbc11a692014-05-16 12:19:25 -0700661 return (jint)AUDIO_JAVA_ERROR;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800662 }
Eric Laurentbc11a692014-05-16 12:19:25 -0700663 return nativeToJavaStatus(lpTrack->setSampleRate(sampleRateInHz));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800664}
665
666
667// ----------------------------------------------------------------------------
668static jint android_media_AudioTrack_get_playback_rate(JNIEnv *env, jobject thiz) {
Eric Laurent532bc1c2012-04-20 12:45:03 -0700669 sp<AudioTrack> lpTrack = getAudioTrack(env, thiz);
670 if (lpTrack == NULL) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800671 jniThrowException(env, "java/lang/IllegalStateException",
672 "Unable to retrieve AudioTrack pointer for getSampleRate()");
Eric Laurentbc11a692014-05-16 12:19:25 -0700673 return (jint)AUDIO_JAVA_ERROR;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800674 }
Eric Laurent532bc1c2012-04-20 12:45:03 -0700675 return (jint) lpTrack->getSampleRate();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800676}
677
678
679// ----------------------------------------------------------------------------
Glenn Kasten18db49a2012-03-12 16:29:55 -0700680static jint android_media_AudioTrack_set_marker_pos(JNIEnv *env, jobject thiz,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800681 jint markerPos) {
Eric Laurent532bc1c2012-04-20 12:45:03 -0700682 sp<AudioTrack> lpTrack = getAudioTrack(env, thiz);
683 if (lpTrack == NULL) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800684 jniThrowException(env, "java/lang/IllegalStateException",
685 "Unable to retrieve AudioTrack pointer for setMarkerPosition()");
Eric Laurentbc11a692014-05-16 12:19:25 -0700686 return (jint)AUDIO_JAVA_ERROR;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800687 }
Eric Laurentbc11a692014-05-16 12:19:25 -0700688 return nativeToJavaStatus( lpTrack->setMarkerPosition(markerPos) );
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800689}
690
691
692// ----------------------------------------------------------------------------
693static jint android_media_AudioTrack_get_marker_pos(JNIEnv *env, jobject thiz) {
Eric Laurent532bc1c2012-04-20 12:45:03 -0700694 sp<AudioTrack> lpTrack = getAudioTrack(env, thiz);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800695 uint32_t markerPos = 0;
Glenn Kasten18db49a2012-03-12 16:29:55 -0700696
Eric Laurent532bc1c2012-04-20 12:45:03 -0700697 if (lpTrack == NULL) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800698 jniThrowException(env, "java/lang/IllegalStateException",
699 "Unable to retrieve AudioTrack pointer for getMarkerPosition()");
Eric Laurentbc11a692014-05-16 12:19:25 -0700700 return (jint)AUDIO_JAVA_ERROR;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800701 }
Eric Laurent532bc1c2012-04-20 12:45:03 -0700702 lpTrack->getMarkerPosition(&markerPos);
703 return (jint)markerPos;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800704}
705
706
707// ----------------------------------------------------------------------------
708static jint android_media_AudioTrack_set_pos_update_period(JNIEnv *env, jobject thiz,
709 jint period) {
Eric Laurent532bc1c2012-04-20 12:45:03 -0700710 sp<AudioTrack> lpTrack = getAudioTrack(env, thiz);
711 if (lpTrack == NULL) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800712 jniThrowException(env, "java/lang/IllegalStateException",
713 "Unable to retrieve AudioTrack pointer for setPositionUpdatePeriod()");
Eric Laurentbc11a692014-05-16 12:19:25 -0700714 return (jint)AUDIO_JAVA_ERROR;
Glenn Kasten18db49a2012-03-12 16:29:55 -0700715 }
Eric Laurentbc11a692014-05-16 12:19:25 -0700716 return nativeToJavaStatus( lpTrack->setPositionUpdatePeriod(period) );
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800717}
718
719
720// ----------------------------------------------------------------------------
721static jint android_media_AudioTrack_get_pos_update_period(JNIEnv *env, jobject thiz) {
Eric Laurent532bc1c2012-04-20 12:45:03 -0700722 sp<AudioTrack> lpTrack = getAudioTrack(env, thiz);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800723 uint32_t period = 0;
Glenn Kasten18db49a2012-03-12 16:29:55 -0700724
Eric Laurent532bc1c2012-04-20 12:45:03 -0700725 if (lpTrack == NULL) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800726 jniThrowException(env, "java/lang/IllegalStateException",
727 "Unable to retrieve AudioTrack pointer for getPositionUpdatePeriod()");
Eric Laurentbc11a692014-05-16 12:19:25 -0700728 return (jint)AUDIO_JAVA_ERROR;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800729 }
Eric Laurent532bc1c2012-04-20 12:45:03 -0700730 lpTrack->getPositionUpdatePeriod(&period);
731 return (jint)period;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800732}
733
734
735// ----------------------------------------------------------------------------
Glenn Kasten18db49a2012-03-12 16:29:55 -0700736static jint android_media_AudioTrack_set_position(JNIEnv *env, jobject thiz,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800737 jint position) {
Eric Laurent532bc1c2012-04-20 12:45:03 -0700738 sp<AudioTrack> lpTrack = getAudioTrack(env, thiz);
739 if (lpTrack == NULL) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800740 jniThrowException(env, "java/lang/IllegalStateException",
741 "Unable to retrieve AudioTrack pointer for setPosition()");
Eric Laurentbc11a692014-05-16 12:19:25 -0700742 return (jint)AUDIO_JAVA_ERROR;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800743 }
Eric Laurentbc11a692014-05-16 12:19:25 -0700744 return nativeToJavaStatus( lpTrack->setPosition(position) );
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800745}
746
747
748// ----------------------------------------------------------------------------
749static jint android_media_AudioTrack_get_position(JNIEnv *env, jobject thiz) {
Eric Laurent532bc1c2012-04-20 12:45:03 -0700750 sp<AudioTrack> lpTrack = getAudioTrack(env, thiz);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800751 uint32_t position = 0;
Glenn Kasten18db49a2012-03-12 16:29:55 -0700752
Eric Laurent532bc1c2012-04-20 12:45:03 -0700753 if (lpTrack == NULL) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800754 jniThrowException(env, "java/lang/IllegalStateException",
755 "Unable to retrieve AudioTrack pointer for getPosition()");
Eric Laurentbc11a692014-05-16 12:19:25 -0700756 return (jint)AUDIO_JAVA_ERROR;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800757 }
Eric Laurent532bc1c2012-04-20 12:45:03 -0700758 lpTrack->getPosition(&position);
759 return (jint)position;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800760}
761
762
763// ----------------------------------------------------------------------------
Oliver Woodman61dcdf32013-06-26 12:43:36 +0100764static jint android_media_AudioTrack_get_latency(JNIEnv *env, jobject thiz) {
765 sp<AudioTrack> lpTrack = getAudioTrack(env, thiz);
766
767 if (lpTrack == NULL) {
768 jniThrowException(env, "java/lang/IllegalStateException",
769 "Unable to retrieve AudioTrack pointer for latency()");
Eric Laurentbc11a692014-05-16 12:19:25 -0700770 return (jint)AUDIO_JAVA_ERROR;
Oliver Woodman61dcdf32013-06-26 12:43:36 +0100771 }
772 return (jint)lpTrack->latency();
773}
774
775
776// ----------------------------------------------------------------------------
Glenn Kasten948c2e62013-09-04 13:51:29 -0700777static jint android_media_AudioTrack_get_timestamp(JNIEnv *env, jobject thiz, jlongArray jTimestamp) {
778 sp<AudioTrack> lpTrack = getAudioTrack(env, thiz);
779
780 if (lpTrack == NULL) {
781 ALOGE("Unable to retrieve AudioTrack pointer for getTimestamp()");
Eric Laurentbc11a692014-05-16 12:19:25 -0700782 return (jint)AUDIO_JAVA_ERROR;
Glenn Kasten948c2e62013-09-04 13:51:29 -0700783 }
784 AudioTimestamp timestamp;
785 status_t status = lpTrack->getTimestamp(timestamp);
786 if (status == OK) {
787 jlong* nTimestamp = (jlong *) env->GetPrimitiveArrayCritical(jTimestamp, NULL);
788 if (nTimestamp == NULL) {
789 ALOGE("Unable to get array for getTimestamp()");
Eric Laurentbc11a692014-05-16 12:19:25 -0700790 return (jint)AUDIO_JAVA_ERROR;
Glenn Kasten948c2e62013-09-04 13:51:29 -0700791 }
792 nTimestamp[0] = (jlong) timestamp.mPosition;
793 nTimestamp[1] = (jlong) ((timestamp.mTime.tv_sec * 1000000000LL) + timestamp.mTime.tv_nsec);
794 env->ReleasePrimitiveArrayCritical(jTimestamp, nTimestamp, 0);
795 }
Eric Laurentbc11a692014-05-16 12:19:25 -0700796 return (jint) nativeToJavaStatus(status);
Glenn Kasten948c2e62013-09-04 13:51:29 -0700797}
798
799
800// ----------------------------------------------------------------------------
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800801static jint android_media_AudioTrack_set_loop(JNIEnv *env, jobject thiz,
802 jint loopStart, jint loopEnd, jint loopCount) {
Eric Laurent532bc1c2012-04-20 12:45:03 -0700803 sp<AudioTrack> lpTrack = getAudioTrack(env, thiz);
804 if (lpTrack == NULL) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800805 jniThrowException(env, "java/lang/IllegalStateException",
806 "Unable to retrieve AudioTrack pointer for setLoop()");
Eric Laurentbc11a692014-05-16 12:19:25 -0700807 return (jint)AUDIO_JAVA_ERROR;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800808 }
Eric Laurentbc11a692014-05-16 12:19:25 -0700809 return nativeToJavaStatus( lpTrack->setLoop(loopStart, loopEnd, loopCount) );
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800810}
811
812
813// ----------------------------------------------------------------------------
814static jint android_media_AudioTrack_reload(JNIEnv *env, jobject thiz) {
Eric Laurent532bc1c2012-04-20 12:45:03 -0700815 sp<AudioTrack> lpTrack = getAudioTrack(env, thiz);
816 if (lpTrack == NULL) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800817 jniThrowException(env, "java/lang/IllegalStateException",
818 "Unable to retrieve AudioTrack pointer for reload()");
Eric Laurentbc11a692014-05-16 12:19:25 -0700819 return (jint)AUDIO_JAVA_ERROR;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800820 }
Eric Laurentbc11a692014-05-16 12:19:25 -0700821 return nativeToJavaStatus( lpTrack->reload() );
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800822}
823
824
825// ----------------------------------------------------------------------------
826static jint android_media_AudioTrack_get_output_sample_rate(JNIEnv *env, jobject thiz,
827 jint javaStreamType) {
Glenn Kasten85fbc872012-11-14 13:21:09 -0800828 uint32_t afSamplingRate;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800829 // convert the stream type from Java to native value
Jean-Michel Trivieac84382014-02-04 14:50:40 -0800830 // FIXME: code duplication with android_media_AudioTrack_setup()
Dima Zavin24fc2fb2011-04-19 22:30:36 -0700831 audio_stream_type_t nativeStreamType;
Glenn Kasten29a09092012-01-16 14:37:12 -0800832 switch (javaStreamType) {
833 case AUDIO_STREAM_VOICE_CALL:
834 case AUDIO_STREAM_SYSTEM:
835 case AUDIO_STREAM_RING:
836 case AUDIO_STREAM_MUSIC:
837 case AUDIO_STREAM_ALARM:
838 case AUDIO_STREAM_NOTIFICATION:
839 case AUDIO_STREAM_BLUETOOTH_SCO:
840 case AUDIO_STREAM_DTMF:
841 nativeStreamType = (audio_stream_type_t) javaStreamType;
842 break;
843 default:
Dima Zavin24fc2fb2011-04-19 22:30:36 -0700844 nativeStreamType = AUDIO_STREAM_DEFAULT;
Glenn Kasten29a09092012-01-16 14:37:12 -0800845 break;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800846 }
847
Glenn Kasten8f81d082012-11-28 14:37:48 -0800848 status_t status = AudioSystem::getOutputSamplingRate(&afSamplingRate, nativeStreamType);
849 if (status != NO_ERROR) {
850 ALOGE("Error %d in AudioSystem::getOutputSamplingRate() for stream type %d "
851 "in AudioTrack JNI", status, nativeStreamType);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800852 return DEFAULT_OUTPUT_SAMPLE_RATE;
853 } else {
854 return afSamplingRate;
855 }
856}
857
858
859// ----------------------------------------------------------------------------
860// returns the minimum required size for the successful creation of a streaming AudioTrack
861// returns -1 if there was an error querying the hardware.
862static jint android_media_AudioTrack_get_min_buff_size(JNIEnv *env, jobject thiz,
Glenn Kasten5b8fd442013-11-14 09:44:14 -0800863 jint sampleRateInHertz, jint channelCount, jint audioFormat) {
Chia-chi Yehc3308072010-08-19 17:14:36 +0800864
Glenn Kasten659a9712014-01-08 11:38:33 -0800865 size_t frameCount;
866 const status_t status = AudioTrack::getMinFrameCount(&frameCount, AUDIO_STREAM_DEFAULT,
867 sampleRateInHertz);
868 if (status != NO_ERROR) {
869 ALOGE("AudioTrack::getMinFrameCount() for sample rate %d failed with status %d",
870 sampleRateInHertz, status);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800871 return -1;
872 }
Glenn Kastenfe834d32014-01-08 14:49:08 -0800873 const audio_format_t format = audioFormatToNative(audioFormat);
Eric Laurentff0d9f02014-06-09 17:23:02 -0700874 if (audio_is_linear_pcm(format)) {
875 const size_t bytesPerSample = audio_bytes_per_sample(format);
876 return frameCount * channelCount * bytesPerSample;
877 } else {
878 return frameCount;
879 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800880}
881
Eric Laurent7070b362010-07-16 07:43:46 -0700882// ----------------------------------------------------------------------------
Glenn Kasten3009f0b2014-03-28 16:02:26 -0700883static jint
Eric Laurent7070b362010-07-16 07:43:46 -0700884android_media_AudioTrack_setAuxEffectSendLevel(JNIEnv *env, jobject thiz, jfloat level )
885{
Eric Laurent532bc1c2012-04-20 12:45:03 -0700886 sp<AudioTrack> lpTrack = getAudioTrack(env, thiz);
Eric Laurent7070b362010-07-16 07:43:46 -0700887 if (lpTrack == NULL ) {
888 jniThrowException(env, "java/lang/IllegalStateException",
889 "Unable to retrieve AudioTrack pointer for setAuxEffectSendLevel()");
Glenn Kasten3009f0b2014-03-28 16:02:26 -0700890 return -1;
Eric Laurent7070b362010-07-16 07:43:46 -0700891 }
892
Glenn Kasten3009f0b2014-03-28 16:02:26 -0700893 status_t status = lpTrack->setAuxEffectSendLevel(level);
894 if (status != NO_ERROR) {
895 ALOGE("AudioTrack::setAuxEffectSendLevel() for level %g failed with status %d",
896 level, status);
897 }
898 return (jint) status;
Eric Laurent7070b362010-07-16 07:43:46 -0700899}
900
901// ----------------------------------------------------------------------------
902static jint android_media_AudioTrack_attachAuxEffect(JNIEnv *env, jobject thiz,
903 jint effectId) {
Eric Laurent532bc1c2012-04-20 12:45:03 -0700904 sp<AudioTrack> lpTrack = getAudioTrack(env, thiz);
905 if (lpTrack == NULL) {
Eric Laurent7070b362010-07-16 07:43:46 -0700906 jniThrowException(env, "java/lang/IllegalStateException",
907 "Unable to retrieve AudioTrack pointer for attachAuxEffect()");
Eric Laurentbc11a692014-05-16 12:19:25 -0700908 return (jint)AUDIO_JAVA_ERROR;
Eric Laurent7070b362010-07-16 07:43:46 -0700909 }
Eric Laurentbc11a692014-05-16 12:19:25 -0700910 return nativeToJavaStatus( lpTrack->attachAuxEffect(effectId) );
Eric Laurent7070b362010-07-16 07:43:46 -0700911}
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800912
Paul McLean88e1d862015-04-06 16:36:51 -0700913static jboolean android_media_AudioTrack_setOutputDevice(
914 JNIEnv *env, jobject thiz, jint device_id) {
915
916 sp<AudioTrack> lpTrack = getAudioTrack(env, thiz);
917 return lpTrack->setOutputDevice(device_id) == NO_ERROR;
918}
919
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800920// ----------------------------------------------------------------------------
921// ----------------------------------------------------------------------------
922static JNINativeMethod gMethods[] = {
923 // name, signature, funcPtr
924 {"native_start", "()V", (void *)android_media_AudioTrack_start},
925 {"native_stop", "()V", (void *)android_media_AudioTrack_stop},
926 {"native_pause", "()V", (void *)android_media_AudioTrack_pause},
927 {"native_flush", "()V", (void *)android_media_AudioTrack_flush},
Jean-Michel Trivia1d80e32014-06-18 08:18:41 -0700928 {"native_setup", "(Ljava/lang/Object;Ljava/lang/Object;IIIII[I)I",
Jean-Michel Trivieac84382014-02-04 14:50:40 -0800929 (void *)android_media_AudioTrack_setup},
930 {"native_finalize", "()V", (void *)android_media_AudioTrack_finalize},
931 {"native_release", "()V", (void *)android_media_AudioTrack_release},
Andy Hung4aacc902015-04-14 15:01:29 -0700932 {"native_write_byte", "([BIIIZ)I",(void *)android_media_AudioTrack_writeArray<jbyteArray>},
Jean-Michel Trivi7ca04522014-02-07 09:39:34 -0800933 {"native_write_native_bytes",
Jean-Michel Trivi5d21f672014-03-20 17:02:31 -0700934 "(Ljava/lang/Object;IIIZ)I",
Jean-Michel Trivi7ca04522014-02-07 09:39:34 -0800935 (void *)android_media_AudioTrack_write_native_bytes},
Andy Hung4aacc902015-04-14 15:01:29 -0700936 {"native_write_short", "([SIIIZ)I",(void *)android_media_AudioTrack_writeArray<jshortArray>},
937 {"native_write_float", "([FIIIZ)I",(void *)android_media_AudioTrack_writeArray<jfloatArray>},
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800938 {"native_setVolume", "(FF)V", (void *)android_media_AudioTrack_set_volume},
939 {"native_get_native_frame_count",
940 "()I", (void *)android_media_AudioTrack_get_native_frame_count},
941 {"native_set_playback_rate",
Eric Laurent88e209d2009-07-07 07:10:45 -0700942 "(I)I", (void *)android_media_AudioTrack_set_playback_rate},
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800943 {"native_get_playback_rate",
944 "()I", (void *)android_media_AudioTrack_get_playback_rate},
945 {"native_set_marker_pos","(I)I", (void *)android_media_AudioTrack_set_marker_pos},
946 {"native_get_marker_pos","()I", (void *)android_media_AudioTrack_get_marker_pos},
947 {"native_set_pos_update_period",
948 "(I)I", (void *)android_media_AudioTrack_set_pos_update_period},
949 {"native_get_pos_update_period",
950 "()I", (void *)android_media_AudioTrack_get_pos_update_period},
951 {"native_set_position", "(I)I", (void *)android_media_AudioTrack_set_position},
952 {"native_get_position", "()I", (void *)android_media_AudioTrack_get_position},
Oliver Woodman61dcdf32013-06-26 12:43:36 +0100953 {"native_get_latency", "()I", (void *)android_media_AudioTrack_get_latency},
Glenn Kasten948c2e62013-09-04 13:51:29 -0700954 {"native_get_timestamp", "([J)I", (void *)android_media_AudioTrack_get_timestamp},
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800955 {"native_set_loop", "(III)I", (void *)android_media_AudioTrack_set_loop},
956 {"native_reload_static", "()I", (void *)android_media_AudioTrack_reload},
957 {"native_get_output_sample_rate",
958 "(I)I", (void *)android_media_AudioTrack_get_output_sample_rate},
959 {"native_get_min_buff_size",
960 "(III)I", (void *)android_media_AudioTrack_get_min_buff_size},
Eric Laurent7070b362010-07-16 07:43:46 -0700961 {"native_setAuxEffectSendLevel",
Glenn Kasten3009f0b2014-03-28 16:02:26 -0700962 "(F)I", (void *)android_media_AudioTrack_setAuxEffectSendLevel},
Eric Laurent7070b362010-07-16 07:43:46 -0700963 {"native_attachAuxEffect",
964 "(I)I", (void *)android_media_AudioTrack_attachAuxEffect},
Paul McLean88e1d862015-04-06 16:36:51 -0700965 {"native_setOutputDevice", "(I)Z",
966 (void *)android_media_AudioTrack_setOutputDevice},
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800967};
968
969
970// field names found in android/media/AudioTrack.java
971#define JAVA_POSTEVENT_CALLBACK_NAME "postEventFromNative"
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800972#define JAVA_NATIVETRACKINJAVAOBJ_FIELD_NAME "mNativeTrackInJavaObj"
973#define JAVA_JNIDATA_FIELD_NAME "mJniData"
Jean-Michel Trivia1d80e32014-06-18 08:18:41 -0700974#define JAVA_STREAMTYPE_FIELD_NAME "mStreamType"
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800975
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800976// ----------------------------------------------------------------------------
977// preconditions:
978// theClass is valid
979bool android_media_getIntConstantFromClass(JNIEnv* pEnv, jclass theClass, const char* className,
980 const char* constName, int* constVal) {
981 jfieldID javaConst = NULL;
982 javaConst = pEnv->GetStaticFieldID(theClass, constName, "I");
983 if (javaConst != NULL) {
984 *constVal = pEnv->GetStaticIntField(theClass, javaConst);
985 return true;
986 } else {
Steve Block3762c312012-01-06 19:20:56 +0000987 ALOGE("Can't find %s.%s", className, constName);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800988 return false;
989 }
990}
991
992
993// ----------------------------------------------------------------------------
994int register_android_media_AudioTrack(JNIEnv *env)
995{
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800996 javaAudioTrackFields.nativeTrackInJavaObj = NULL;
997 javaAudioTrackFields.postNativeEventInJava = NULL;
998
999 // Get the AudioTrack class
Andreas Gampeed6b9df2014-11-20 22:02:20 -08001000 jclass audioTrackClass = FindClassOrDie(env, kClassPathName);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001001
1002 // Get the postEvent method
Andreas Gampeed6b9df2014-11-20 22:02:20 -08001003 javaAudioTrackFields.postNativeEventInJava = GetStaticMethodIDOrDie(env,
1004 audioTrackClass, JAVA_POSTEVENT_CALLBACK_NAME,
1005 "(Ljava/lang/Object;IIILjava/lang/Object;)V");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001006
1007 // Get the variables fields
1008 // nativeTrackInJavaObj
Andreas Gampeed6b9df2014-11-20 22:02:20 -08001009 javaAudioTrackFields.nativeTrackInJavaObj = GetFieldIDOrDie(env,
1010 audioTrackClass, JAVA_NATIVETRACKINJAVAOBJ_FIELD_NAME, "J");
Jean-Michel Trivia1d80e32014-06-18 08:18:41 -07001011 // jniData
Andreas Gampeed6b9df2014-11-20 22:02:20 -08001012 javaAudioTrackFields.jniData = GetFieldIDOrDie(env,
1013 audioTrackClass, JAVA_JNIDATA_FIELD_NAME, "J");
Jean-Michel Trivia1d80e32014-06-18 08:18:41 -07001014 // fieldStreamType
Andreas Gampeed6b9df2014-11-20 22:02:20 -08001015 javaAudioTrackFields.fieldStreamType = GetFieldIDOrDie(env,
1016 audioTrackClass, JAVA_STREAMTYPE_FIELD_NAME, "I");
Jean-Michel Trivia1d80e32014-06-18 08:18:41 -07001017
1018 // Get the AudioAttributes class and fields
Andreas Gampeed6b9df2014-11-20 22:02:20 -08001019 jclass audioAttrClass = FindClassOrDie(env, kAudioAttributesClassPathName);
1020 javaAudioAttrFields.fieldUsage = GetFieldIDOrDie(env, audioAttrClass, "mUsage", "I");
1021 javaAudioAttrFields.fieldContentType = GetFieldIDOrDie(env,
1022 audioAttrClass, "mContentType", "I");
1023 javaAudioAttrFields.fieldFlags = GetFieldIDOrDie(env, audioAttrClass, "mFlags", "I");
1024 javaAudioAttrFields.fieldFormattedTags = GetFieldIDOrDie(env,
1025 audioAttrClass, "mFormattedTags", "Ljava/lang/String;");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001026
Andreas Gampeed6b9df2014-11-20 22:02:20 -08001027 return RegisterMethodsOrDie(env, kClassPathName, gMethods, NELEM(gMethods));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001028}
1029
1030
1031// ----------------------------------------------------------------------------