android_media_SoundPool.cpp revision 54b6cfa9a9e5b861a9930af873580d6dc20f773c
1/*
2 * Copyright (C) 2008 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#include <stdio.h>
18
19//#define LOG_NDEBUG 0
20#define LOG_TAG "SoundPool"
21
22#include <utils/Log.h>
23#include <nativehelper/jni.h>
24#include <nativehelper/JNIHelp.h>
25#include <android_runtime/AndroidRuntime.h>
26#include "SoundPool.h"
27
28using namespace android;
29
30static struct fields_t {
31    jfieldID    mNativeContext;
32    jclass      mSoundPoolClass;
33} fields;
34
35static inline SoundPool* MusterSoundPool(JNIEnv *env, jobject thiz) {
36    return (SoundPool*)env->GetIntField(thiz, fields.mNativeContext);
37}
38
39// ----------------------------------------------------------------------------
40static int
41android_media_SoundPool_load_URL(JNIEnv *env, jobject thiz, jstring path, jint priority)
42{
43    LOGV("android_media_SoundPool_load_URL");
44    SoundPool *ap = MusterSoundPool(env, thiz);
45    if (path == NULL) {
46        jniThrowException(env, "java/lang/IllegalArgumentException", NULL);
47        return 0;
48    }
49    const char* s = env->GetStringUTFChars(path, NULL);
50    int id = ap->load(s, priority);
51    env->ReleaseStringUTFChars(path, s);
52    return id;
53}
54
55static int
56android_media_SoundPool_load_FD(JNIEnv *env, jobject thiz, jobject fileDescriptor,
57        jlong offset, jlong length, jint priority)
58{
59    LOGV("android_media_SoundPool_load_FD");
60    SoundPool *ap = MusterSoundPool(env, thiz);
61    if (ap == NULL) return 0;
62    return ap->load(getParcelFileDescriptorFD(env, fileDescriptor),
63            int64_t(offset), int64_t(length), int(priority));
64}
65
66static bool
67android_media_SoundPool_unload(JNIEnv *env, jobject thiz, jint sampleID) {
68    LOGV("android_media_SoundPool_unload\n");
69    SoundPool *ap = MusterSoundPool(env, thiz);
70    if (ap == NULL) return 0;
71    return ap->unload(sampleID);
72}
73
74static int
75android_media_SoundPool_play(JNIEnv *env, jobject thiz, jint sampleID,
76        jfloat leftVolume, jfloat rightVolume, jint priority, jint loop,
77        jfloat rate)
78{
79    LOGV("android_media_SoundPool_play\n");
80    SoundPool *ap = MusterSoundPool(env, thiz);
81    if (ap == NULL) return 0;
82    return ap->play(sampleID, leftVolume, rightVolume, priority, loop, rate);
83}
84
85static void
86android_media_SoundPool_pause(JNIEnv *env, jobject thiz, jint channelID)
87{
88    LOGV("android_media_SoundPool_pause");
89    SoundPool *ap = MusterSoundPool(env, thiz);
90    if (ap == NULL) return;
91    ap->pause(channelID);
92}
93
94static void
95android_media_SoundPool_resume(JNIEnv *env, jobject thiz, jint channelID)
96{
97    LOGV("android_media_SoundPool_resume");
98    SoundPool *ap = MusterSoundPool(env, thiz);
99    if (ap == NULL) return;
100    ap->resume(channelID);
101}
102
103static void
104android_media_SoundPool_stop(JNIEnv *env, jobject thiz, jint channelID)
105{
106    LOGV("android_media_SoundPool_stop");
107    SoundPool *ap = MusterSoundPool(env, thiz);
108    if (ap == NULL) return;
109    ap->stop(channelID);
110}
111
112static void
113android_media_SoundPool_setVolume(JNIEnv *env, jobject thiz, jint channelID,
114        float leftVolume, float rightVolume)
115{
116    LOGV("android_media_SoundPool_setVolume");
117    SoundPool *ap = MusterSoundPool(env, thiz);
118    if (ap == NULL) return;
119    ap->setVolume(channelID, leftVolume, rightVolume);
120}
121
122static void
123android_media_SoundPool_setPriority(JNIEnv *env, jobject thiz, jint channelID,
124        int priority)
125{
126    LOGV("android_media_SoundPool_setPriority");
127    SoundPool *ap = MusterSoundPool(env, thiz);
128    if (ap == NULL) return;
129    ap->setPriority(channelID, priority);
130}
131
132static void
133android_media_SoundPool_setLoop(JNIEnv *env, jobject thiz, jint channelID,
134        int loop)
135{
136    LOGV("android_media_SoundPool_setLoop");
137    SoundPool *ap = MusterSoundPool(env, thiz);
138    if (ap == NULL) return;
139    ap->setLoop(channelID, loop);
140}
141
142static void
143android_media_SoundPool_setRate(JNIEnv *env, jobject thiz, jint channelID,
144        float rate)
145{
146    LOGV("android_media_SoundPool_setRate");
147    SoundPool *ap = MusterSoundPool(env, thiz);
148    if (ap == NULL) return;
149    ap->setRate(channelID, rate);
150}
151
152static void
153android_media_SoundPool_native_setup(JNIEnv *env, jobject thiz,
154        jobject weak_this, jint maxChannels, jint streamType, jint srcQuality)
155{
156    LOGV("android_media_SoundPool_native_setup");
157    SoundPool *ap = new SoundPool(weak_this, maxChannels, streamType, srcQuality);
158    if (ap == NULL) {
159        jniThrowException(env, "java/lang/RuntimeException", "Out of memory");
160        return;
161    }
162
163    // save pointer to SoundPool C++ object in opaque field in Java object
164    env->SetIntField(thiz, fields.mNativeContext, (int)ap);
165}
166
167static void
168android_media_SoundPool_release(JNIEnv *env, jobject thiz)
169{
170    LOGV("android_media_SoundPool_release");
171    SoundPool *ap = MusterSoundPool(env, thiz);
172    if (ap != NULL) {
173        env->SetIntField(thiz, fields.mNativeContext, 0);
174        delete ap;
175    }
176}
177
178// ----------------------------------------------------------------------------
179
180// Dalvik VM type signatures
181static JNINativeMethod gMethods[] = {
182    {   "_load",
183        "(Ljava/lang/String;I)I",
184        (void *)android_media_SoundPool_load_URL
185    },
186    {   "_load",
187        "(Ljava/io/FileDescriptor;JJI)I",
188        (void *)android_media_SoundPool_load_FD
189    },
190    {   "unload",
191        "(I)Z",
192        (void *)android_media_SoundPool_unload
193    },
194    {   "play",
195        "(IFFIIF)I",
196        (void *)android_media_SoundPool_play
197    },
198    {   "pause",
199        "(I)V",
200        (void *)android_media_SoundPool_pause
201    },
202    {   "resume",
203        "(I)V",
204        (void *)android_media_SoundPool_resume
205    },
206    {   "stop",
207        "(I)V",
208        (void *)android_media_SoundPool_stop
209    },
210    {   "setVolume",
211        "(IFF)V",
212        (void *)android_media_SoundPool_setVolume
213    },
214    {   "setPriority",
215        "(II)V",
216        (void *)android_media_SoundPool_setPriority
217    },
218    {   "setLoop",
219        "(II)V",
220        (void *)android_media_SoundPool_setLoop
221    },
222    {   "setRate",
223        "(IF)V",
224        (void *)android_media_SoundPool_setRate
225    },
226    {   "native_setup",
227        "(Ljava/lang/Object;III)V",
228        (void*)android_media_SoundPool_native_setup
229    },
230    {   "release",
231        "()V",
232        (void*)android_media_SoundPool_release
233    }
234};
235
236static const char* const kClassPathName = "android/media/SoundPool";
237
238jint JNI_OnLoad(JavaVM* vm, void* reserved)
239{
240    JNIEnv* env = NULL;
241    jint result = -1;
242    jclass clazz;
243
244    if (vm->GetEnv((void**) &env, JNI_VERSION_1_4) != JNI_OK) {
245        LOGE("ERROR: GetEnv failed\n");
246        goto bail;
247    }
248    assert(env != NULL);
249
250    clazz = env->FindClass(kClassPathName);
251    if (clazz == NULL) {
252        LOGE("Can't find %s", kClassPathName);
253        goto bail;
254    }
255
256    fields.mNativeContext = env->GetFieldID(clazz, "mNativeContext", "I");
257    if (fields.mNativeContext == NULL) {
258        LOGE("Can't find SoundPool.mNativeContext");
259        goto bail;
260    }
261
262    if (AndroidRuntime::registerNativeMethods(env, kClassPathName, gMethods, NELEM(gMethods)) < 0)
263        goto bail;
264
265    /* success -- return valid version number */
266    result = JNI_VERSION_1_4;
267
268bail:
269    return result;
270}
271