libvlcjni.c 21.4 KB
Newer Older
Rafaël Carré's avatar
Rafaël Carré committed
1
2
3
/*****************************************************************************
 * libvlcjni.c
 *****************************************************************************
Edward Wang's avatar
Edward Wang committed
4
 * Copyright © 2010-2013 VLC authors and VideoLAN
Rafaël Carré's avatar
Rafaël Carré committed
5
 *
Jean-Baptiste Kempf's avatar
Jean-Baptiste Kempf committed
6
7
8
 * This program is free software; you can redistribute it and/or modify it
 * under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation; either version 2.1 of the License, or
Rafaël Carré's avatar
Rafaël Carré committed
9
10
11
12
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
Jean-Baptiste Kempf's avatar
Jean-Baptiste Kempf committed
13
14
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU Lesser General Public License for more details.
Rafaël Carré's avatar
Rafaël Carré committed
15
 *
Jean-Baptiste Kempf's avatar
Jean-Baptiste Kempf committed
16
17
18
 * You should have received a copy of the GNU Lesser General Public License
 * along with this program; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
Rafaël Carré's avatar
Rafaël Carré committed
19
20
 *****************************************************************************/

21
22
#include <dirent.h>
#include <errno.h>
23
#include <string.h>
24
#include <pthread.h>
25
#include <sys/stat.h>
26
#include <sys/types.h>
27
#include <unistd.h>
28

29
#include <vlc/vlc.h>
30
31
#include <vlc_common.h>
#include <vlc_url.h>
32

33
#include <jni.h>
34

35
#include <android/api-level.h>
36

37
#include "libvlcjni.h"
ivoire's avatar
ivoire committed
38
#include "aout.h"
39
#include "utils.h"
40
41

#define LOG_TAG "VLC/JNI/main"
42
43
#include "log.h"

44
libvlc_media_t *new_media(jlong instance, JNIEnv *env, jobject thiz, jstring fileLocation, bool noOmx, bool noVideo)
45
{
Ludovic Fauvet's avatar
Ludovic Fauvet committed
46
    libvlc_instance_t *libvlc = (libvlc_instance_t*)(intptr_t)instance;
47
    jboolean isCopy;
48
49
50
    const char *psz_location = (*env)->GetStringUTFChars(env, fileLocation, &isCopy);
    libvlc_media_t *p_md = libvlc_media_new_location(libvlc, psz_location);
    (*env)->ReleaseStringUTFChars(env, fileLocation, psz_location);
51
52
53
    if (!p_md)
        return NULL;

54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
    if (!noOmx) {
        jclass cls = (*env)->GetObjectClass(env, thiz);
        jmethodID methodId = (*env)->GetMethodID(env, cls, "useIOMX", "()Z");
        if ((*env)->CallBooleanMethod(env, thiz, methodId)) {
            /*
             * Set higher caching values if using iomx decoding, since some omx
             * decoders have a very high latency, and if the preroll data isn't
             * enough to make the decoder output a frame, the playback timing gets
             * started too soon, and every decoded frame appears to be too late.
             * On Nexus One, the decoder latency seems to be 25 input packets
             * for 320x170 H.264, a few packets less on higher resolutions.
             * On Nexus S, the decoder latency seems to be about 7 packets.
             */
            libvlc_media_add_option(p_md, ":file-caching=1500");
            libvlc_media_add_option(p_md, ":network-caching=1500");
69
            libvlc_media_add_option(p_md, ":codec=mediacodec,iomx,all");
70
        }
71
72
        if (noVideo)
            libvlc_media_add_option(p_md, ":no-video");
73
    }
74
    return p_md;
75
76
}

77
78
79
80
81
82
83
// Get the current media list being followed
libvlc_media_list_t* getMediaList(JNIEnv *env, jobject thiz) {
    jclass clazz = (*env)->GetObjectClass(env, thiz);
    jfieldID fieldMP = (*env)->GetFieldID(env, clazz,
                                          "mMediaList", "Lorg/videolan/libvlc/MediaList;");
    jobject javaML = (*env)->GetObjectField(env, thiz, fieldMP);
    return getMediaListFromJava(env, javaML);
84
85
}

86
libvlc_media_player_t *getMediaPlayer(JNIEnv *env, jobject thiz)
87
{
Ludovic Fauvet's avatar
Ludovic Fauvet committed
88
    return (libvlc_media_player_t*)(intptr_t)getLong(env, thiz, "mInternalMediaPlayerInstance");
89
90
}

Rafaël Carré's avatar
Rafaël Carré committed
91
92
static void releaseMediaPlayer(JNIEnv *env, jobject thiz)
{
93
94
    libvlc_media_player_t* p_mp = getMediaPlayer(env, thiz);
    if (p_mp)
95
    {
96
97
        libvlc_media_player_stop(p_mp);
        libvlc_media_player_release(p_mp);
98
        setLong(env, thiz, "mInternalMediaPlayerInstance", 0);
99
100
101
    }
}

102
103
104
105
106
/* Pointer to the Java virtual machine
 * Note: It's okay to use a static variable for the VM pointer since there
 * can only be one instance of this shared library in a single VM
 */
JavaVM *myVm;
107

108
static jobject eventHandlerInstance = NULL;
109

110
111
/** vout lock declared in vout.c */
extern pthread_mutex_t vout_android_lock;
112

113
114
115
116
static void vlc_event_callback(const libvlc_event_t *ev, void *data)
{
    JNIEnv *env;

117
    bool isAttached = false;
118

119
    if (eventHandlerInstance == NULL)
Sébastien Toque's avatar
Sébastien Toque committed
120
        return;
121

Rafaël Carré's avatar
Rafaël Carré committed
122
123
    if ((*myVm)->GetEnv(myVm, (void**) &env, JNI_VERSION_1_2) < 0) {
        if ((*myVm)->AttachCurrentThread(myVm, &env, NULL) < 0)
124
            return;
125
        isAttached = true;
126
127
    }

128
129
130
131
132
133
134
135
136
137
    /* Creating the bundle in C allows us to subscribe to more events
     * and get better flexibility for each event. For example, we can
     * have totally different types of data for each event, instead of,
     * for example, only an integer and/or string.
     */
    jclass clsBundle = (*env)->FindClass(env, "android/os/Bundle");
    jmethodID clsCtor = (*env)->GetMethodID(env, clsBundle, "<init>", "()V" );
    jobject bundle = (*env)->NewObject(env, clsBundle, clsCtor);

    jmethodID putInt = (*env)->GetMethodID(env, clsBundle, "putInt", "(Ljava/lang/String;I)V" );
138
    jmethodID putFloat = (*env)->GetMethodID(env, clsBundle, "putFloat", "(Ljava/lang/String;F)V" );
139
140
    jmethodID putString = (*env)->GetMethodID(env, clsBundle, "putString", "(Ljava/lang/String;Ljava/lang/String;)V" );

141
142
143
144
145
    if (ev->type == libvlc_MediaPlayerPositionChanged) {
            jstring sData = (*env)->NewStringUTF(env, "data");
            (*env)->CallVoidMethod(env, bundle, putFloat, sData, ev->u.media_player_position_changed.new_position);
            (*env)->DeleteLocalRef(env, sData);
    } else if(ev->type == libvlc_MediaPlayerVout) {
146
147
148
149
        /* For determining the vout/ES track change */
        jstring sData = (*env)->NewStringUTF(env, "data");
        (*env)->CallVoidMethod(env, bundle, putInt, sData, ev->u.media_player_vout.new_count);
        (*env)->DeleteLocalRef(env, sData);
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
    } else if(ev->type == libvlc_MediaListItemAdded ||
              ev->type == libvlc_MediaListItemDeleted ) {
        jstring item_uri = (*env)->NewStringUTF(env, "item_uri");
        jstring item_index = (*env)->NewStringUTF(env, "item_index");
        char* mrl = libvlc_media_get_mrl(
            ev->type == libvlc_MediaListItemAdded ?
            ev->u.media_list_item_added.item :
            ev->u.media_list_item_deleted.item
            );
        jstring item_uri_value = (*env)->NewStringUTF(env, mrl);
        jint item_index_value;
        if(ev->type == libvlc_MediaListItemAdded)
            item_index_value = ev->u.media_list_item_added.index;
        else
            item_index_value = ev->u.media_list_item_deleted.index;

        (*env)->CallVoidMethod(env, bundle, putString, item_uri, item_uri_value);
        (*env)->CallVoidMethod(env, bundle, putInt, item_index, item_index_value);

        (*env)->DeleteLocalRef(env, item_uri);
        (*env)->DeleteLocalRef(env, item_uri_value);
        (*env)->DeleteLocalRef(env, item_index);
        free(mrl);
173
174
    }

175
    /* Get the object class */
176
    jclass cls = (*env)->GetObjectClass(env, eventHandlerInstance);
177
    if (!cls) {
178
        LOGE("EventHandler: failed to get class reference");
179
        goto end;
180
181
182
    }

    /* Find the callback ID */
183
    jmethodID methodID = (*env)->GetMethodID(env, cls, "callback", "(ILandroid/os/Bundle;)V");
184
    if (methodID) {
185
        (*env)->CallVoidMethod(env, eventHandlerInstance, methodID, ev->type, bundle);
186
    } else {
187
        LOGE("EventHandler: failed to get the callback method");
188
189
    }

190
191
192
end:
    if (isAttached)
        (*myVm)->DetachCurrentThread(myVm);
193
194
}

195
jint JNI_OnLoad(JavaVM *vm, void *reserved)
196
{
197
198
199
    // Keep a reference on the Java VM.
    myVm = vm;

200
201
    pthread_mutex_init(&vout_android_lock, NULL);

202
    LOGD("JNI interface loaded.");
203
    return JNI_VERSION_1_2;
204
205
}

206
207
208
209
void JNI_OnUnload(JavaVM* vm, void* reserved) {
    pthread_mutex_destroy(&vout_android_lock);
}

Rafaël Carré's avatar
Rafaël Carré committed
210
211
// FIXME: use atomics
static bool verbosity;
212

213
void Java_org_videolan_libvlc_LibVLC_nativeInit(JNIEnv *env, jobject thiz)
214
{
215
216
217
218
219
    //only use OpenSLES if java side says we can
    jclass cls = (*env)->GetObjectClass(env, thiz);
    jmethodID methodId = (*env)->GetMethodID(env, cls, "getAout", "()I");
    bool use_opensles = (*env)->CallIntMethod(env, thiz, methodId) == AOUT_OPENSLES;

220
221
222
    methodId = (*env)->GetMethodID(env, cls, "timeStretchingEnabled", "()Z");
    bool enable_time_stretch = (*env)->CallBooleanMethod(env, thiz, methodId);

Edward Wang's avatar
Edward Wang committed
223
224
225
    methodId = (*env)->GetMethodID(env, cls, "frameSkipEnabled", "()Z");
    bool enable_frame_skip = (*env)->CallBooleanMethod(env, thiz, methodId);

Edward Wang's avatar
Edward Wang committed
226
227
228
229
230
    methodId = (*env)->GetMethodID(env, cls, "getDeblocking", "()I");
    int deblocking = (*env)->CallIntMethod(env, thiz, methodId);
    char deblockstr[2] = "3";
    snprintf(deblockstr, 2, "%d", deblocking);
    LOGD("Using deblocking level %d", deblocking);
231

232
233
234
235
    methodId = (*env)->GetMethodID(env, cls, "getChroma", "()Ljava/lang/String;");
    jstring chroma = (*env)->CallObjectMethod(env, thiz, methodId);
    const char *chromastr = (*env)->GetStringUTFChars(env, chroma, 0);
    LOGD("Chroma set to \"%s\"", chromastr);
Edward Wang's avatar
Edward Wang committed
236

237
238
239
    methodId = (*env)->GetMethodID(env, cls, "getSubtitlesEncoding", "()Ljava/lang/String;");
    jstring subsencoding = (*env)->CallObjectMethod(env, thiz, methodId);
    const char *subsencodingstr = (*env)->GetStringUTFChars(env, subsencoding, 0);
Edward Wang's avatar
Edward Wang committed
240
    LOGD("Subtitle encoding set to \"%s\"", subsencodingstr);
241

242
243
244
    methodId = (*env)->GetMethodID(env, cls, "isVerboseMode", "()Z");
    verbosity = (*env)->CallBooleanMethod(env, thiz, methodId);

245
    /* Don't add any invalid options, otherwise it causes LibVLC to crash */
246
    const char *argv[] = {
247
        "-I", "dummy",
Jean-Baptiste Kempf's avatar
Jean-Baptiste Kempf committed
248
249
250
        "--no-osd",
        "--no-video-title-show",
        "--no-stats",
251
252
        "--no-plugins-cache",
        "--no-drop-late-frames",
253
254
255
256
        /* The VLC default is to pick the highest resolution possible
         * (i.e. 1080p). For mobile, pick a more sane default for slow
         * mobile data networks and slower hardware. */
        "--preferred-resolution", "360",
Jean-Baptiste Kempf's avatar
Jean-Baptiste Kempf committed
257
        "--avcodec-fast",
258
        "--avcodec-threads=0",
259
        "--subsdec-encoding", subsencodingstr,
260
        enable_time_stretch ? "--audio-time-stretch" : "--no-audio-time-stretch",
Edward Wang's avatar
Edward Wang committed
261
        "--avcodec-skiploopfilter", deblockstr,
Edward Wang's avatar
Edward Wang committed
262
263
        "--avcodec-skip-frame", enable_frame_skip ? "4" : "0",
        "--avcodec-skip-idct", enable_frame_skip ? "4" : "0",
264
        use_opensles ? "--aout=opensles" : "--aout=android_audiotrack",
265
        "--androidsurface-chroma", chromastr != NULL && chromastr[0] != 0 ? chromastr : "RV32",
266
    };
267
    libvlc_instance_t *instance = libvlc_new(sizeof(argv) / sizeof(*argv), argv);
268

Ludovic Fauvet's avatar
Ludovic Fauvet committed
269
    setLong(env, thiz, "mLibVlcInstance", (jlong)(intptr_t) instance);
270

271
    (*env)->ReleaseStringUTFChars(env, chroma, chromastr);
272
273
    (*env)->ReleaseStringUTFChars(env, subsencoding, subsencodingstr);

274
275
    if (!instance)
    {
276
        jclass exc = (*env)->FindClass(env, "org/videolan/libvlc/LibVlcException");
277
278
279
280
        (*env)->ThrowNew(env, exc, "Unable to instantiate LibVLC");
    }

    LOGI("LibVLC initialized: %p", instance);
281

Rafaël Carré's avatar
Rafaël Carré committed
282
    libvlc_log_set(instance, debug_log, &verbosity);
283
284
}

285
void Java_org_videolan_libvlc_LibVLC_nativeDestroy(JNIEnv *env, jobject thiz)
286
{
287
    releaseMediaPlayer(env, thiz);
Edward Wang's avatar
Edward Wang committed
288
    jlong libVlcInstance = getLong(env, thiz, "mLibVlcInstance");
289
290
291
    if (!libVlcInstance)
        return; // Already destroyed

Ludovic Fauvet's avatar
Ludovic Fauvet committed
292
    libvlc_instance_t *instance = (libvlc_instance_t*)(intptr_t) libVlcInstance;
Rafaël Carré's avatar
Rafaël Carré committed
293
    libvlc_log_unset(instance);
294
295
    libvlc_release(instance);

Edward Wang's avatar
Edward Wang committed
296
    setLong(env, thiz, "mLibVlcInstance", 0);
297
298
}

299
void Java_org_videolan_libvlc_LibVLC_detachEventHandler(JNIEnv *env, jobject thiz)
300
{
301
302
303
    if (eventHandlerInstance != NULL) {
        (*env)->DeleteGlobalRef(env, eventHandlerInstance);
        eventHandlerInstance = NULL;
304
305
306
    }
}

307
void Java_org_videolan_libvlc_LibVLC_setEventHandler(JNIEnv *env, jobject thiz, jobject eventHandler)
308
{
309
310
311
    if (eventHandlerInstance != NULL) {
        (*env)->DeleteGlobalRef(env, eventHandlerInstance);
        eventHandlerInstance = NULL;
312
313
    }

314
    eventHandlerInstance = getEventHandlerReference(env, thiz, eventHandler);
315
316
}

317
318
static void create_player_and_play(JNIEnv* env, jobject thiz,
                                   jlong instance, int position) {
319
320
321
    /* Release previous media player, if any */
    releaseMediaPlayer(env, thiz);

322
323
    libvlc_media_list_t* p_mlist = getMediaList(env, thiz);

324
    /* Create a media player playing environment */
Ludovic Fauvet's avatar
Ludovic Fauvet committed
325
    libvlc_media_player_t *mp = libvlc_media_player_new((libvlc_instance_t*)(intptr_t)instance);
326

327
328
    jobject myJavaLibVLC = (*env)->NewGlobalRef(env, thiz);

329
330
331
332
    //if AOUT_AUDIOTRACK_JAVA, we use amem
    jclass cls = (*env)->GetObjectClass(env, thiz);
    jmethodID methodId = (*env)->GetMethodID(env, cls, "getAout", "()I");
    if ( (*env)->CallIntMethod(env, thiz, methodId) == AOUT_AUDIOTRACK_JAVA )
333
    {
334
        libvlc_audio_set_callbacks(mp, aout_play, aout_pause, NULL, NULL, NULL,
Sébastien Toque's avatar
Sébastien Toque committed
335
336
                                   (void*) myJavaLibVLC);
        libvlc_audio_set_format_callbacks(mp, aout_open, aout_close);
337
338
    }

339
340
    /* Connect the event manager */
    libvlc_event_manager_t *ev = libvlc_media_player_event_manager(mp);
341
342
343
344
345
    static const libvlc_event_type_t mp_events[] = {
        libvlc_MediaPlayerPlaying,
        libvlc_MediaPlayerPaused,
        libvlc_MediaPlayerEndReached,
        libvlc_MediaPlayerStopped,
346
        libvlc_MediaPlayerVout,
347
348
        libvlc_MediaPlayerPositionChanged,
        libvlc_MediaPlayerEncounteredError
349
    };
350
    for(int i = 0; i < (sizeof(mp_events) / sizeof(*mp_events)); i++)
351
352
        libvlc_event_attach(ev, mp_events[i], vlc_event_callback, myVm);

353

354
    /* Keep a pointer to this media player */
Ludovic Fauvet's avatar
Ludovic Fauvet committed
355
    setLong(env, thiz, "mInternalMediaPlayerInstance", (jlong)(intptr_t)mp);
356

357
358
359
360
361
362
    setInt(env, thiz, "mInternalMediaPlayerIndex", (jint)position);
    libvlc_media_list_lock(p_mlist);
    libvlc_media_t* p_md = libvlc_media_list_item_at_index(p_mlist, position);
    libvlc_media_list_unlock(p_mlist);
    libvlc_media_player_set_media(mp, p_md);
    libvlc_media_player_play(mp);
363
364
}

365
jint Java_org_videolan_libvlc_LibVLC_expandMedia(JNIEnv *env, jobject thiz)
Edward Wang's avatar
Edward Wang committed
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
{
    int current_position = getInt(env, thiz, "mInternalMediaPlayerIndex");
    libvlc_media_list_t* p_mlist = getMediaList(env, thiz);
    libvlc_media_list_lock(p_mlist);
    libvlc_media_t* p_md = libvlc_media_list_item_at_index(p_mlist, current_position);
    libvlc_media_list_unlock(p_mlist);
    libvlc_media_list_t* p_subitems = libvlc_media_subitems(p_md);
    libvlc_media_release(p_md);
    if(p_subitems) {
        // Expand any subitems if needed
        int subitem_count = libvlc_media_list_count(p_subitems);
        if(subitem_count > 0) {
            LOGD("Found %d subitems, expanding", subitem_count);
            libvlc_media_list_lock(p_mlist);
            for(int i = subitem_count - 1; i >= 0; i--) {
                libvlc_media_list_insert_media(p_mlist, libvlc_media_list_item_at_index(p_subitems, i), current_position+1);
            }
            libvlc_media_list_remove_index(p_mlist, current_position);
            libvlc_media_list_unlock(p_mlist);
        }
        libvlc_media_list_release(p_subitems);
        if(subitem_count > 0) {
            create_player_and_play(env, thiz,
                getLong(env, thiz, "mLibVlcInstance"), current_position);
390
            return (jint)current_position;
Edward Wang's avatar
Edward Wang committed
391
        } else
392
            return -1;
Edward Wang's avatar
Edward Wang committed
393
    } else {
394
        return -1;
Edward Wang's avatar
Edward Wang committed
395
396
397
    }
}

398
jint Java_org_videolan_libvlc_LibVLC_readMedia(JNIEnv *env, jobject thiz,
399
400
401
402
403
404
405
                                            jlong instance, jstring mrl, jboolean novideo)
{
    /* Create a new item */
    libvlc_media_t *m = new_media(instance, env, thiz, mrl, false, novideo);
    if (!m)
    {
        LOGE("readMedia: Could not create the media!");
406
        return -1;
407
408
409
410
411
    }

    libvlc_media_list_t* p_mlist = getMediaList(env, thiz);

    libvlc_media_list_lock(p_mlist);
412
413
414
415
    if(libvlc_media_list_add_media(p_mlist, m) != 0) {
        LOGE("readMedia: Could not add to the media list!");
        libvlc_media_list_unlock(p_mlist);
        libvlc_media_release(m);
416
        return -1;
417
    }
418
419
420
421
422
423
424
    int position = libvlc_media_list_index_of_item(p_mlist, m);
    libvlc_media_list_unlock(p_mlist);

    /* No need to keep the media now */
    libvlc_media_release(m);

    create_player_and_play(env, thiz, instance, position);
425
426

    return position;
427
428
}

429
void Java_org_videolan_libvlc_LibVLC_playIndex(JNIEnv *env, jobject thiz,
430
431
432
433
                                            jlong instance, int position) {
    create_player_and_play(env, thiz, instance, position);
}

434
void Java_org_videolan_libvlc_LibVLC_getMediaListItems(
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
                JNIEnv *env, jobject thiz, jobject arrayList) {
    jclass arrayClass = (*env)->FindClass(env, "java/util/ArrayList");
    jmethodID methodID = (*env)->GetMethodID(env, arrayClass, "add", "(Ljava/lang/Object;)Z");
    jstring str;

    libvlc_media_list_t* p_mlist = getMediaList(env, thiz);
    libvlc_media_list_lock( p_mlist );
    for(int i = 0; i < libvlc_media_list_count( p_mlist ); i++) {
        char* mrl = libvlc_media_get_mrl( libvlc_media_list_item_at_index( p_mlist, i ) );
        str = (*env)->NewStringUTF(env, mrl);
        (*env)->CallBooleanMethod(env, arrayList, methodID, str);
        (*env)->DeleteLocalRef(env, str);
        free(mrl);
    }
    libvlc_media_list_unlock( p_mlist );
}

452
jfloat Java_org_videolan_libvlc_LibVLC_getRate(JNIEnv *env, jobject thiz) {
Edward Wang's avatar
Edward Wang committed
453
454
455
456
457
458
459
    libvlc_media_player_t* mp = getMediaPlayer(env, thiz);
    if(mp)
        return libvlc_media_player_get_rate(mp);
    else
        return 1.00;
}

460
void Java_org_videolan_libvlc_LibVLC_setRate(JNIEnv *env, jobject thiz, jfloat rate) {
Edward Wang's avatar
Edward Wang committed
461
462
463
464
465
    libvlc_media_player_t* mp = getMediaPlayer(env, thiz);
    if(mp)
        libvlc_media_player_set_rate(mp, rate);
}

466
jboolean Java_org_videolan_libvlc_LibVLC_isPlaying(JNIEnv *env, jobject thiz)
467
{
468
    libvlc_media_player_t *mp = getMediaPlayer(env, thiz);
469
    if (mp)
470
        return !!libvlc_media_player_is_playing(mp);
471
472
    else
        return 0;
473
474
}

475
jboolean Java_org_videolan_libvlc_LibVLC_isSeekable(JNIEnv *env, jobject thiz)
476
{
477
478
479
    libvlc_media_player_t *mp = getMediaPlayer(env, thiz);
    if (mp)
        return !!libvlc_media_player_is_seekable(mp);
480
    return 0;
481
482
}

483
void Java_org_videolan_libvlc_LibVLC_play(JNIEnv *env, jobject thiz)
484
{
485
    libvlc_media_player_t *mp = getMediaPlayer(env, thiz);
486
    if (mp)
487
        libvlc_media_player_play(mp);
488
489
}

490
void Java_org_videolan_libvlc_LibVLC_pause(JNIEnv *env, jobject thiz)
491
{
492
    libvlc_media_player_t *mp = getMediaPlayer(env, thiz);
493
    if (mp)
494
        libvlc_media_player_pause(mp);
495
496
}

497
void Java_org_videolan_libvlc_LibVLC_stop(JNIEnv *env, jobject thiz)
498
{
499
    libvlc_media_player_t *mp = getMediaPlayer(env, thiz);
500
    if (mp)
501
        libvlc_media_player_stop(mp);
502
503
}

504
void Java_org_videolan_libvlc_LibVLC_previous(JNIEnv *env, jobject thiz)
Edward Wang's avatar
Edward Wang committed
505
{
506
507
508
509
510
511
512
    int current_position = getInt(env, thiz, "mInternalMediaPlayerIndex");

    if(current_position-1 >= 0) {
        setInt(env, thiz, "mInternalMediaPlayerIndex", (jint)(current_position-1));
        create_player_and_play(env, thiz,
             getLong(env, thiz, "mLibVlcInstance"), current_position-1);
    }
Edward Wang's avatar
Edward Wang committed
513
514
}

515
void Java_org_videolan_libvlc_LibVLC_next(JNIEnv *env, jobject thiz)
Edward Wang's avatar
Edward Wang committed
516
{
517
518
519
520
521
522
523
524
    libvlc_media_list_t* p_mlist = getMediaList(env, thiz);
    int current_position = getInt(env, thiz, "mInternalMediaPlayerIndex");

    if(current_position+1 < libvlc_media_list_count(p_mlist)) {
        setInt(env, thiz, "mInternalMediaPlayerIndex", (jint)(current_position+1));
        create_player_and_play(env, thiz,
             getLong(env, thiz, "mLibVlcInstance"), current_position+1);
    }
Edward Wang's avatar
Edward Wang committed
525
526
}

527
jint Java_org_videolan_libvlc_LibVLC_getVolume(JNIEnv *env, jobject thiz)
528
{
529
530
531
    libvlc_media_player_t *mp = getMediaPlayer(env, thiz);
    if (mp)
        return (jint) libvlc_audio_get_volume(mp);
532
533
534
    return -1;
}

535
jint Java_org_videolan_libvlc_LibVLC_setVolume(JNIEnv *env, jobject thiz, jint volume)
536
{
537
538
    libvlc_media_player_t *mp = getMediaPlayer(env, thiz);
    if (mp)
539
        //Returns 0 if the volume was set, -1 if it was out of range or error
540
        return (jint) libvlc_audio_set_volume(mp, (int) volume);
541
542
543
    return -1;
}

544
jlong Java_org_videolan_libvlc_LibVLC_getTime(JNIEnv *env, jobject thiz)
545
{
546
547
548
    libvlc_media_player_t *mp = getMediaPlayer(env, thiz);
    if (mp)
        return libvlc_media_player_get_time(mp);
549
550
551
    return -1;
}

552
void Java_org_videolan_libvlc_LibVLC_setTime(JNIEnv *env, jobject thiz, jlong time)
553
{
554
555
556
    libvlc_media_player_t *mp = getMediaPlayer(env, thiz);
    if (mp)
        libvlc_media_player_set_time(mp, time);
557
558
}

559
jfloat Java_org_videolan_libvlc_LibVLC_getPosition(JNIEnv *env, jobject thiz)
560
{
561
562
563
    libvlc_media_player_t *mp = getMediaPlayer(env, thiz);
    if (mp)
        return (jfloat) libvlc_media_player_get_position(mp);
564
565
566
    return -1;
}

567
void Java_org_videolan_libvlc_LibVLC_setPosition(JNIEnv *env, jobject thiz, jfloat pos)
568
{
569
570
571
    libvlc_media_player_t *mp = getMediaPlayer(env, thiz);
    if (mp)
        libvlc_media_player_set_position(mp, pos);
572
573
}

574
jlong Java_org_videolan_libvlc_LibVLC_getLength(JNIEnv *env, jobject thiz)
575
{
576
577
578
    libvlc_media_player_t *mp = getMediaPlayer(env, thiz);
    if (mp)
        return (jlong) libvlc_media_player_get_length(mp);
579
580
581
    return -1;
}

582
jstring Java_org_videolan_libvlc_LibVLC_version(JNIEnv* env, jobject thiz)
583
{
584
585
    return (*env)->NewStringUTF(env, libvlc_get_version());
}
586

587
jstring Java_org_videolan_libvlc_LibVLC_compiler(JNIEnv* env, jobject thiz)
588
589
590
591
{
    return (*env)->NewStringUTF(env, libvlc_get_compiler());
}

592
jstring Java_org_videolan_libvlc_LibVLC_changeset(JNIEnv* env, jobject thiz)
593
594
595
{
    return (*env)->NewStringUTF(env, libvlc_get_changeset());
}