libvlcjni.c 21.5 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
libvlc_media_list_t *getMediaList(JNIEnv *env, jobject thiz)
78
{
Ludovic Fauvet's avatar
Ludovic Fauvet committed
79
    return (libvlc_media_list_t*)(intptr_t)getLong(env, thiz, "mMediaListInstance");
80
81
}

82
libvlc_media_player_t *getMediaPlayer(JNIEnv *env, jobject thiz)
83
{
Ludovic Fauvet's avatar
Ludovic Fauvet committed
84
    return (libvlc_media_player_t*)(intptr_t)getLong(env, thiz, "mInternalMediaPlayerInstance");
85
86
}

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

98
99
100
101
102
/* 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;
103

104
static jobject eventHandlerInstance = NULL;
105

106
107
/** vout lock declared in vout.c */
extern pthread_mutex_t vout_android_lock;
108

109
110
111
112
static void vlc_event_callback(const libvlc_event_t *ev, void *data)
{
    JNIEnv *env;

113
    bool isAttached = false;
114

115
    if (eventHandlerInstance == NULL)
Sébastien Toque's avatar
Sébastien Toque committed
116
        return;
117

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

124
125
126
127
128
129
130
131
132
133
    /* 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" );
134
    jmethodID putFloat = (*env)->GetMethodID(env, clsBundle, "putFloat", "(Ljava/lang/String;F)V" );
135
136
    jmethodID putString = (*env)->GetMethodID(env, clsBundle, "putString", "(Ljava/lang/String;Ljava/lang/String;)V" );

137
138
139
140
141
    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) {
142
143
144
145
        /* 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);
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
    } 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);
169
170
    }

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

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

186
187
188
end:
    if (isAttached)
        (*myVm)->DetachCurrentThread(myVm);
189
190
}

191
jint JNI_OnLoad(JavaVM *vm, void *reserved)
192
{
193
194
195
    // Keep a reference on the Java VM.
    myVm = vm;

196
197
    pthread_mutex_init(&vout_android_lock, NULL);

198
    LOGD("JNI interface loaded.");
199
    return JNI_VERSION_1_2;
200
201
}

202
203
204
205
void JNI_OnUnload(JavaVM* vm, void* reserved) {
    pthread_mutex_destroy(&vout_android_lock);
}

Rafaël Carré's avatar
Rafaël Carré committed
206
207
// FIXME: use atomics
static bool verbosity;
208

209
void Java_org_videolan_libvlc_LibVLC_nativeInit(JNIEnv *env, jobject thiz)
210
{
211
212
213
214
215
    //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;

216
217
218
    methodId = (*env)->GetMethodID(env, cls, "timeStretchingEnabled", "()Z");
    bool enable_time_stretch = (*env)->CallBooleanMethod(env, thiz, methodId);

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

Edward Wang's avatar
Edward Wang committed
222
223
224
225
226
    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);
227

228
229
230
231
    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
232

233
234
235
    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
236
    LOGD("Subtitle encoding set to \"%s\"", subsencodingstr);
237

238
239
240
    methodId = (*env)->GetMethodID(env, cls, "isVerboseMode", "()Z");
    verbosity = (*env)->CallBooleanMethod(env, thiz, methodId);

241
    /* Don't add any invalid options, otherwise it causes LibVLC to crash */
242
    const char *argv[] = {
243
        "-I", "dummy",
Jean-Baptiste Kempf's avatar
Jean-Baptiste Kempf committed
244
245
246
        "--no-osd",
        "--no-video-title-show",
        "--no-stats",
247
248
        "--no-plugins-cache",
        "--no-drop-late-frames",
249
250
251
252
        /* 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
253
        "--avcodec-fast",
254
        "--avcodec-threads=0",
255
        "--subsdec-encoding", subsencodingstr,
256
        enable_time_stretch ? "--audio-time-stretch" : "--no-audio-time-stretch",
Edward Wang's avatar
Edward Wang committed
257
        "--avcodec-skiploopfilter", deblockstr,
Edward Wang's avatar
Edward Wang committed
258
259
        "--avcodec-skip-frame", enable_frame_skip ? "4" : "0",
        "--avcodec-skip-idct", enable_frame_skip ? "4" : "0",
260
        use_opensles ? "--aout=opensles" : "--aout=android_audiotrack",
261
        "--androidsurface-chroma", chromastr != NULL && chromastr[0] != 0 ? chromastr : "RV32",
262
    };
263
    libvlc_instance_t *instance = libvlc_new(sizeof(argv) / sizeof(*argv), argv);
264

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

267
    (*env)->ReleaseStringUTFChars(env, chroma, chromastr);
268
269
    (*env)->ReleaseStringUTFChars(env, subsencoding, subsencodingstr);

270
271
    if (!instance)
    {
272
        jclass exc = (*env)->FindClass(env, "org/videolan/libvlc/LibVlcException");
273
274
275
276
        (*env)->ThrowNew(env, exc, "Unable to instantiate LibVLC");
    }

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

Rafaël Carré's avatar
Rafaël Carré committed
278
279
    libvlc_log_set(instance, debug_log, &verbosity);

280
281
282
283
284
285
286
287
    /* Connect the event manager */
    libvlc_event_manager_t *ev = libvlc_media_list_event_manager(pointer);
    static const libvlc_event_type_t mp_events[] = {
        libvlc_MediaListItemAdded,
        libvlc_MediaListItemDeleted,
    };
    for(int i = 0; i < (sizeof(mp_events) / sizeof(*mp_events)); i++)
        libvlc_event_attach(ev, mp_events[i], vlc_event_callback, myVm);
288
289
}

290
void Java_org_videolan_libvlc_LibVLC_nativeDestroy(JNIEnv *env, jobject thiz)
291
{
292
    releaseMediaPlayer(env, thiz);
Edward Wang's avatar
Edward Wang committed
293
    jlong libVlcInstance = getLong(env, thiz, "mLibVlcInstance");
294
295
296
    if (!libVlcInstance)
        return; // Already destroyed

Ludovic Fauvet's avatar
Ludovic Fauvet committed
297
    libvlc_instance_t *instance = (libvlc_instance_t*)(intptr_t) libVlcInstance;
Rafaël Carré's avatar
Rafaël Carré committed
298
    libvlc_log_unset(instance);
299
300
    libvlc_release(instance);

Edward Wang's avatar
Edward Wang committed
301
    setLong(env, thiz, "mLibVlcInstance", 0);
302
303
}

304
void Java_org_videolan_libvlc_LibVLC_detachEventHandler(JNIEnv *env, jobject thiz)
305
{
306
307
308
    if (eventHandlerInstance != NULL) {
        (*env)->DeleteGlobalRef(env, eventHandlerInstance);
        eventHandlerInstance = NULL;
309
310
311
    }
}

312
void Java_org_videolan_libvlc_LibVLC_setEventHandler(JNIEnv *env, jobject thiz, jobject eventHandler)
313
{
314
315
316
    if (eventHandlerInstance != NULL) {
        (*env)->DeleteGlobalRef(env, eventHandlerInstance);
        eventHandlerInstance = NULL;
317
318
    }

319
    eventHandlerInstance = getEventHandlerReference(env, thiz, eventHandler);
320
321
}

322
323
static void create_player_and_play(JNIEnv* env, jobject thiz,
                                   jlong instance, int position) {
324
325
326
    /* Release previous media player, if any */
    releaseMediaPlayer(env, thiz);

327
328
    libvlc_media_list_t* p_mlist = getMediaList(env, thiz);

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

332
333
    jobject myJavaLibVLC = (*env)->NewGlobalRef(env, thiz);

334
335
336
337
    //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 )
338
    {
339
        libvlc_audio_set_callbacks(mp, aout_play, aout_pause, NULL, NULL, NULL,
Sébastien Toque's avatar
Sébastien Toque committed
340
341
                                   (void*) myJavaLibVLC);
        libvlc_audio_set_format_callbacks(mp, aout_open, aout_close);
342
343
    }

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

358

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

362
363
364
365
366
367
    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);
368
369
}

370
jint Java_org_videolan_libvlc_LibVLC_expandMedia(JNIEnv *env, jobject thiz)
Edward Wang's avatar
Edward Wang committed
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
{
    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);
395
            return (jint)current_position;
Edward Wang's avatar
Edward Wang committed
396
        } else
397
            return -1;
Edward Wang's avatar
Edward Wang committed
398
    } else {
399
        return -1;
Edward Wang's avatar
Edward Wang committed
400
401
402
    }
}

403
jint Java_org_videolan_libvlc_LibVLC_readMedia(JNIEnv *env, jobject thiz,
404
405
406
407
408
409
410
                                            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!");
411
        return -1;
412
413
414
415
416
    }

    libvlc_media_list_t* p_mlist = getMediaList(env, thiz);

    libvlc_media_list_lock(p_mlist);
417
418
419
420
    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);
421
        return -1;
422
    }
423
424
425
426
427
428
429
    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);
430
431

    return position;
432
433
}

434
void Java_org_videolan_libvlc_LibVLC_playIndex(JNIEnv *env, jobject thiz,
435
436
437
438
                                            jlong instance, int position) {
    create_player_and_play(env, thiz, instance, position);
}

439
void Java_org_videolan_libvlc_LibVLC_getMediaListItems(
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
                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 );
}

457
jfloat Java_org_videolan_libvlc_LibVLC_getRate(JNIEnv *env, jobject thiz) {
Edward Wang's avatar
Edward Wang committed
458
459
460
461
462
463
464
    libvlc_media_player_t* mp = getMediaPlayer(env, thiz);
    if(mp)
        return libvlc_media_player_get_rate(mp);
    else
        return 1.00;
}

465
void Java_org_videolan_libvlc_LibVLC_setRate(JNIEnv *env, jobject thiz, jfloat rate) {
Edward Wang's avatar
Edward Wang committed
466
467
468
469
470
    libvlc_media_player_t* mp = getMediaPlayer(env, thiz);
    if(mp)
        libvlc_media_player_set_rate(mp, rate);
}

471
jboolean Java_org_videolan_libvlc_LibVLC_isPlaying(JNIEnv *env, jobject thiz)
472
{
473
    libvlc_media_player_t *mp = getMediaPlayer(env, thiz);
474
    if (mp)
475
        return !!libvlc_media_player_is_playing(mp);
476
477
    else
        return 0;
478
479
}

480
jboolean Java_org_videolan_libvlc_LibVLC_isSeekable(JNIEnv *env, jobject thiz)
481
{
482
483
484
    libvlc_media_player_t *mp = getMediaPlayer(env, thiz);
    if (mp)
        return !!libvlc_media_player_is_seekable(mp);
485
    return 0;
486
487
}

488
void Java_org_videolan_libvlc_LibVLC_play(JNIEnv *env, jobject thiz)
489
{
490
    libvlc_media_player_t *mp = getMediaPlayer(env, thiz);
491
    if (mp)
492
        libvlc_media_player_play(mp);
493
494
}

495
void Java_org_videolan_libvlc_LibVLC_pause(JNIEnv *env, jobject thiz)
496
{
497
    libvlc_media_player_t *mp = getMediaPlayer(env, thiz);
498
    if (mp)
499
        libvlc_media_player_pause(mp);
500
501
}

502
void Java_org_videolan_libvlc_LibVLC_stop(JNIEnv *env, jobject thiz)
503
{
504
    libvlc_media_player_t *mp = getMediaPlayer(env, thiz);
505
    if (mp)
506
        libvlc_media_player_stop(mp);
507
508
}

509
void Java_org_videolan_libvlc_LibVLC_previous(JNIEnv *env, jobject thiz)
Edward Wang's avatar
Edward Wang committed
510
{
511
512
513
514
515
516
517
    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
518
519
}

520
void Java_org_videolan_libvlc_LibVLC_next(JNIEnv *env, jobject thiz)
Edward Wang's avatar
Edward Wang committed
521
{
522
523
524
525
526
527
528
529
    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
530
531
}

532
jint Java_org_videolan_libvlc_LibVLC_getVolume(JNIEnv *env, jobject thiz)
533
{
534
535
536
    libvlc_media_player_t *mp = getMediaPlayer(env, thiz);
    if (mp)
        return (jint) libvlc_audio_get_volume(mp);
537
538
539
    return -1;
}

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

549
jlong Java_org_videolan_libvlc_LibVLC_getTime(JNIEnv *env, jobject thiz)
550
{
551
552
553
    libvlc_media_player_t *mp = getMediaPlayer(env, thiz);
    if (mp)
        return libvlc_media_player_get_time(mp);
554
555
556
    return -1;
}

557
void Java_org_videolan_libvlc_LibVLC_setTime(JNIEnv *env, jobject thiz, jlong time)
558
{
559
560
561
    libvlc_media_player_t *mp = getMediaPlayer(env, thiz);
    if (mp)
        libvlc_media_player_set_time(mp, time);
562
563
}

564
jfloat Java_org_videolan_libvlc_LibVLC_getPosition(JNIEnv *env, jobject thiz)
565
{
566
567
568
    libvlc_media_player_t *mp = getMediaPlayer(env, thiz);
    if (mp)
        return (jfloat) libvlc_media_player_get_position(mp);
569
570
571
    return -1;
}

572
void Java_org_videolan_libvlc_LibVLC_setPosition(JNIEnv *env, jobject thiz, jfloat pos)
573
{
574
575
576
    libvlc_media_player_t *mp = getMediaPlayer(env, thiz);
    if (mp)
        libvlc_media_player_set_position(mp, pos);
577
578
}

579
jlong Java_org_videolan_libvlc_LibVLC_getLength(JNIEnv *env, jobject thiz)
580
{
581
582
583
    libvlc_media_player_t *mp = getMediaPlayer(env, thiz);
    if (mp)
        return (jlong) libvlc_media_player_get_length(mp);
584
585
586
    return -1;
}

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

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

597
jstring Java_org_videolan_libvlc_LibVLC_changeset(JNIEnv* env, jobject thiz)
598
599
600
{
    return (*env)->NewStringUTF(env, libvlc_get_changeset());
}