libvlcjni.c 21.3 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 "vout.h"
40
#include "utils.h"
41
#include "native_crash_handler.h"
42

43 44 45
#define VOUT_ANDROID_SURFACE 0
#define VOUT_OPENGLES2       1

46 47 48 49
#define HW_ACCELERATION_DISABLED 0
#define HW_ACCELERATION_DECODING 1
#define HW_ACCELERATION_FULL     2

50
#define LOG_TAG "VLC/JNI/main"
51 52
#include "log.h"

53 54 55 56 57 58
#ifdef HAVE_IOMX_DR
#define NO_IOMX_DR "--no-omxil-dr"
#else
#define NO_IOMX_DR ""
#endif

59
libvlc_media_t *new_media(jlong instance, JNIEnv *env, jobject thiz, jstring fileLocation, bool noOmx, bool noVideo)
60
{
Ludovic Fauvet's avatar
Ludovic Fauvet committed
61
    libvlc_instance_t *libvlc = (libvlc_instance_t*)(intptr_t)instance;
62
    jboolean isCopy;
63 64 65
    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);
66 67 68
    if (!p_md)
        return NULL;

69 70
    if (!noOmx) {
        jclass cls = (*env)->GetObjectClass(env, thiz);
71 72 73
        jmethodID methodId = (*env)->GetMethodID(env, cls, "getHardwareAcceleration", "()I");
        int hardwareAcceleration = (*env)->CallIntMethod(env, thiz, methodId);
        if (hardwareAcceleration == HW_ACCELERATION_DECODING || hardwareAcceleration == HW_ACCELERATION_FULL) {
74 75 76 77 78 79 80 81 82 83 84
            /*
             * 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");
85
            libvlc_media_add_option(p_md, ":codec=mediacodec,iomx,all");
86
        }
87 88
        if (noVideo)
            libvlc_media_add_option(p_md, ":no-video");
89
    }
90
    return p_md;
91 92
}

93
libvlc_media_player_t *getMediaPlayer(JNIEnv *env, jobject thiz)
94
{
Ludovic Fauvet's avatar
Ludovic Fauvet committed
95
    return (libvlc_media_player_t*)(intptr_t)getLong(env, thiz, "mInternalMediaPlayerInstance");
96 97
}

Rafaël Carré's avatar
Rafaël Carré committed
98 99
static void releaseMediaPlayer(JNIEnv *env, jobject thiz)
{
100 101
    libvlc_media_player_t* p_mp = getMediaPlayer(env, thiz);
    if (p_mp)
102
    {
103 104
        libvlc_media_player_stop(p_mp);
        libvlc_media_player_release(p_mp);
105
        setLong(env, thiz, "mInternalMediaPlayerInstance", 0);
106 107 108
    }
}

109 110 111 112 113
/* 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;
114

115
static jobject eventHandlerInstance = NULL;
116 117 118 119 120

static void vlc_event_callback(const libvlc_event_t *ev, void *data)
{
    JNIEnv *env;

121
    bool isAttached = false;
122

123
    if (eventHandlerInstance == NULL)
Sébastien Toque's avatar
Sébastien Toque committed
124
        return;
125

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

132 133 134 135 136 137 138 139 140 141
    /* 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" );
142
    jmethodID putFloat = (*env)->GetMethodID(env, clsBundle, "putFloat", "(Ljava/lang/String;F)V" );
143 144
    jmethodID putString = (*env)->GetMethodID(env, clsBundle, "putString", "(Ljava/lang/String;Ljava/lang/String;)V" );

145
    if (ev->type == libvlc_MediaPlayerPositionChanged) {
146 147 148
        jstring sData = (*env)->NewStringUTF(env, "data");
        (*env)->CallVoidMethod(env, bundle, putFloat, sData, ev->u.media_player_position_changed.new_position);
        (*env)->DeleteLocalRef(env, sData);
149 150 151 152
    } else if (ev->type == libvlc_MediaPlayerTimeChanged) {
        jstring sData = (*env)->NewStringUTF(env, "data");
        (*env)->CallVoidMethod(env, bundle, putInt, sData, (int) ev->u.media_player_time_changed.new_time);
        (*env)->DeleteLocalRef(env, sData);
153
    } else if(ev->type == libvlc_MediaPlayerVout) {
154 155 156 157
        /* 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);
158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180
    } 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);
181 182
    }

183
    /* Get the object class */
184
    jclass cls = (*env)->GetObjectClass(env, eventHandlerInstance);
185
    if (!cls) {
186
        LOGE("EventHandler: failed to get class reference");
187
        goto end;
188 189 190
    }

    /* Find the callback ID */
191
    jmethodID methodID = (*env)->GetMethodID(env, cls, "callback", "(ILandroid/os/Bundle;)V");
192
    if (methodID) {
193
        (*env)->CallVoidMethod(env, eventHandlerInstance, methodID, ev->type, bundle);
194
    } else {
195
        LOGE("EventHandler: failed to get the callback method");
196 197
    }

198
end:
Edward Wang's avatar
Edward Wang committed
199
    (*env)->DeleteLocalRef(env, bundle);
200 201
    if (isAttached)
        (*myVm)->DetachCurrentThread(myVm);
202 203
}

204
jint JNI_OnLoad(JavaVM *vm, void *reserved)
205
{
206 207 208
    // Keep a reference on the Java VM.
    myVm = vm;

209
    pthread_mutex_init(&vout_android_lock, NULL);
210
    pthread_cond_init(&vout_android_surf_attached, NULL);
211

212
    LOGD("JNI interface loaded.");
213
    return JNI_VERSION_1_2;
214 215
}

216 217
void JNI_OnUnload(JavaVM* vm, void* reserved) {
    pthread_mutex_destroy(&vout_android_lock);
218
    pthread_cond_destroy(&vout_android_surf_attached);
219 220
}

Rafaël Carré's avatar
Rafaël Carré committed
221 222
// FIXME: use atomics
static bool verbosity;
223

224
void Java_org_videolan_libvlc_LibVLC_nativeInit(JNIEnv *env, jobject thiz)
225
{
226 227 228 229 230
    //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;

231 232 233
    methodId = (*env)->GetMethodID(env, cls, "getVout", "()I");
    bool use_opengles2 = (*env)->CallIntMethod(env, thiz, methodId) == VOUT_OPENGLES2;

234 235 236
    methodId = (*env)->GetMethodID(env, cls, "timeStretchingEnabled", "()Z");
    bool enable_time_stretch = (*env)->CallBooleanMethod(env, thiz, methodId);

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

Edward Wang's avatar
Edward Wang committed
240 241
    methodId = (*env)->GetMethodID(env, cls, "getDeblocking", "()I");
    int deblocking = (*env)->CallIntMethod(env, thiz, methodId);
Rafaël Carré's avatar
Rafaël Carré committed
242 243
    char deblockstr[2];
    snprintf(deblockstr, sizeof(deblockstr), "%d", deblocking);
Edward Wang's avatar
Edward Wang committed
244
    LOGD("Using deblocking level %d", deblocking);
245

Edward Wang's avatar
Edward Wang committed
246 247
    methodId = (*env)->GetMethodID(env, cls, "getNetworkCaching", "()I");
    int networkCaching = (*env)->CallIntMethod(env, thiz, methodId);
Rafaël Carré's avatar
Rafaël Carré committed
248
    char networkCachingstr[25];
Edward Wang's avatar
Edward Wang committed
249
    if(networkCaching > 0) {
Rafaël Carré's avatar
Rafaël Carré committed
250
        snprintf(networkCachingstr, sizeof(networkCachingstr), "--network-caching=%d", networkCaching);
Edward Wang's avatar
Edward Wang committed
251 252 253
        LOGD("Using network caching of %d ms", networkCaching);
    }

254 255 256 257
    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
258

259 260 261
    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
262
    LOGD("Subtitle encoding set to \"%s\"", subsencodingstr);
263

264 265 266
    methodId = (*env)->GetMethodID(env, cls, "isVerboseMode", "()Z");
    verbosity = (*env)->CallBooleanMethod(env, thiz, methodId);

267 268
    methodId = (*env)->GetMethodID(env, cls, "getHardwareAcceleration", "()I");
    int hardwareAcceleration = (*env)->CallIntMethod(env, thiz, methodId);
269 270 271
    /* With the MediaCodec opaque mode we cannot use the OpenGL ES vout. */
    if (hardwareAcceleration == HW_ACCELERATION_FULL)
        use_opengles2 = false;
272

flx42's avatar
flx42 committed
273 274
    methodId = (*env)->GetMethodID(env, cls, "getCachePath", "()Ljava/lang/String;");
    jstring cachePath = (*env)->CallObjectMethod(env, thiz, methodId);
275 276 277 278 279
    if (cachePath) {
        const char *cache_path = (*env)->GetStringUTFChars(env, cachePath, 0);
        setenv("DVDCSS_CACHE", cache_path, 1);
        (*env)->ReleaseStringUTFChars(env, cachePath, cache_path);
    }
flx42's avatar
flx42 committed
280

281
    /* Don't add any invalid options, otherwise it causes LibVLC to crash */
282
    const char *argv[] = {
283
        /* CPU intensive plugin, setting for slow devices */
284
        enable_time_stretch ? "--audio-time-stretch" : "--no-audio-time-stretch",
285 286

        /* avcodec speed settings for slow devices */
287
        //"--avcodec-fast", // non-spec-compliant speedup tricks
Edward Wang's avatar
Edward Wang committed
288
        "--avcodec-skiploopfilter", deblockstr,
289 290
        "--avcodec-skip-frame", enable_frame_skip ? "2" : "0",
        "--avcodec-skip-idct", enable_frame_skip ? "2" : "0",
291 292 293 294

        /* Remove me when UTF-8 is enforced by law */
        "--subsdec-encoding", subsencodingstr,

295 296 297
        /* Enable statistics */
        "--stats",

298
        /* XXX: why can't the default be fine ? #7792 */
Edward Wang's avatar
Edward Wang committed
299
        (networkCaching > 0) ? networkCachingstr : "",
300 301

        /* Android audio API is a mess */
302
        use_opensles ? "--aout=opensles" : "--aout=android_audiotrack",
303 304

        /* Android video API is a mess */
305
        use_opengles2 ? "--vout=gles2" : "--vout=androidsurface",
306
        "--androidsurface-chroma", chromastr != NULL && chromastr[0] != 0 ? chromastr : "RV32",
307
        /* XXX: we can't recover from direct rendering failure */
308
        (hardwareAcceleration == HW_ACCELERATION_FULL) ? "" : "--no-mediacodec-dr",
309
        (hardwareAcceleration == HW_ACCELERATION_FULL) ? "" : NO_IOMX_DR,
310
    };
311
    libvlc_instance_t *instance = libvlc_new(sizeof(argv) / sizeof(*argv), argv);
312

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

315
    (*env)->ReleaseStringUTFChars(env, chroma, chromastr);
316 317
    (*env)->ReleaseStringUTFChars(env, subsencoding, subsencodingstr);

318 319
    if (!instance)
    {
320
        jclass exc = (*env)->FindClass(env, "org/videolan/libvlc/LibVlcException");
321 322 323 324
        (*env)->ThrowNew(env, exc, "Unable to instantiate LibVLC");
    }

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

Rafaël Carré's avatar
Rafaël Carré committed
326
    libvlc_log_set(instance, debug_log, &verbosity);
327 328

    init_native_crash_handler(env, thiz);
329 330
}

331
void Java_org_videolan_libvlc_LibVLC_nativeDestroy(JNIEnv *env, jobject thiz)
332
{
333 334
    destroy_native_crash_handler(env);

335
    releaseMediaPlayer(env, thiz);
Edward Wang's avatar
Edward Wang committed
336
    jlong libVlcInstance = getLong(env, thiz, "mLibVlcInstance");
337 338 339
    if (!libVlcInstance)
        return; // Already destroyed

Ludovic Fauvet's avatar
Ludovic Fauvet committed
340
    libvlc_instance_t *instance = (libvlc_instance_t*)(intptr_t) libVlcInstance;
Rafaël Carré's avatar
Rafaël Carré committed
341
    libvlc_log_unset(instance);
342 343
    libvlc_release(instance);

Edward Wang's avatar
Edward Wang committed
344
    setLong(env, thiz, "mLibVlcInstance", 0);
345 346
}

347
void Java_org_videolan_libvlc_LibVLC_detachEventHandler(JNIEnv *env, jobject thiz)
348
{
349 350 351
    if (eventHandlerInstance != NULL) {
        (*env)->DeleteGlobalRef(env, eventHandlerInstance);
        eventHandlerInstance = NULL;
352 353 354
    }
}

355
void Java_org_videolan_libvlc_LibVLC_setEventHandler(JNIEnv *env, jobject thiz, jobject eventHandler)
356
{
357 358 359
    if (eventHandlerInstance != NULL) {
        (*env)->DeleteGlobalRef(env, eventHandlerInstance);
        eventHandlerInstance = NULL;
360 361
    }

362
    eventHandlerInstance = getEventHandlerReference(env, thiz, eventHandler);
363 364
}

Edward Wang's avatar
Edward Wang committed
365
void Java_org_videolan_libvlc_LibVLC_playMRL(JNIEnv *env, jobject thiz, jlong instance,
366 367
                                             jstring mrl, jobjectArray mediaOptions)
{
368 369 370
    /* Release previous media player, if any */
    releaseMediaPlayer(env, thiz);

371
    /* Create a media player playing environment */
Ludovic Fauvet's avatar
Ludovic Fauvet committed
372
    libvlc_media_player_t *mp = libvlc_media_player_new((libvlc_instance_t*)(intptr_t)instance);
Rafaël Carré's avatar
Rafaël Carré committed
373
    libvlc_media_player_set_video_title_display(mp, libvlc_position_disable, 0);
374 375
    jobject myJavaLibVLC = (*env)->NewGlobalRef(env, thiz);

376 377 378 379
    //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 )
380
    {
381
        libvlc_audio_set_callbacks(mp, aout_play, aout_pause, NULL, NULL, NULL,
Sébastien Toque's avatar
Sébastien Toque committed
382 383
                                   (void*) myJavaLibVLC);
        libvlc_audio_set_format_callbacks(mp, aout_open, aout_close);
384 385
    }

386 387
    /* Connect the event manager */
    libvlc_event_manager_t *ev = libvlc_media_player_event_manager(mp);
388 389 390 391 392
    static const libvlc_event_type_t mp_events[] = {
        libvlc_MediaPlayerPlaying,
        libvlc_MediaPlayerPaused,
        libvlc_MediaPlayerEndReached,
        libvlc_MediaPlayerStopped,
393
        libvlc_MediaPlayerVout,
394
        libvlc_MediaPlayerPositionChanged,
395
        libvlc_MediaPlayerTimeChanged,
396
        libvlc_MediaPlayerEncounteredError
397
    };
398
    for(int i = 0; i < (sizeof(mp_events) / sizeof(*mp_events)); i++)
399 400
        libvlc_event_attach(ev, mp_events[i], vlc_event_callback, myVm);

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

404 405 406 407
    cls = (*env)->GetObjectClass(env, thiz);
    jmethodID methodID = (*env)->GetMethodID(env, cls, "applyEqualizer", "()V");
    (*env)->CallVoidMethod(env, thiz, methodID);

408 409 410 411
    const char* p_mrl = (*env)->GetStringUTFChars(env, mrl, 0);

    libvlc_media_t* p_md = libvlc_media_new_location((libvlc_instance_t*)(intptr_t)instance, p_mrl);
    /* media options */
412 413 414 415 416 417 418 419 420 421
    if (mediaOptions != NULL)
    {
        int stringCount = (*env)->GetArrayLength(env, mediaOptions);
        for(int i = 0; i < stringCount; i++)
        {
            jstring option = (jstring)(*env)->GetObjectArrayElement(env, mediaOptions, i);
            const char* p_st = (*env)->GetStringUTFChars(env, option, 0);
            libvlc_media_add_option(p_md, p_st); // option
            (*env)->ReleaseStringUTFChars(env, option, p_st);
        }
422
    }
423

424 425
    (*env)->ReleaseStringUTFChars(env, mrl, p_mrl);

426 427 428 429 430 431 432 433
    /* Connect the media event manager. */
    libvlc_event_manager_t *ev_media = libvlc_media_event_manager(p_md);
    static const libvlc_event_type_t mp_media_events[] = {
        libvlc_MediaParsedChanged
    };
    for(int i = 0; i < (sizeof(mp_media_events) / sizeof(*mp_media_events)); i++)
        libvlc_event_attach(ev_media, mp_media_events[i], vlc_event_callback, myVm);

434 435
    libvlc_media_player_set_media(mp, p_md);
    libvlc_media_player_play(mp);
436 437
}

438
jfloat Java_org_videolan_libvlc_LibVLC_getRate(JNIEnv *env, jobject thiz) {
Edward Wang's avatar
Edward Wang committed
439 440 441 442 443 444 445
    libvlc_media_player_t* mp = getMediaPlayer(env, thiz);
    if(mp)
        return libvlc_media_player_get_rate(mp);
    else
        return 1.00;
}

446
void Java_org_videolan_libvlc_LibVLC_setRate(JNIEnv *env, jobject thiz, jfloat rate) {
Edward Wang's avatar
Edward Wang committed
447 448 449 450 451
    libvlc_media_player_t* mp = getMediaPlayer(env, thiz);
    if(mp)
        libvlc_media_player_set_rate(mp, rate);
}

452
jboolean Java_org_videolan_libvlc_LibVLC_isPlaying(JNIEnv *env, jobject thiz)
453
{
454
    libvlc_media_player_t *mp = getMediaPlayer(env, thiz);
455
    if (mp)
456
        return !!libvlc_media_player_is_playing(mp);
457 458
    else
        return 0;
459 460
}

461
jboolean Java_org_videolan_libvlc_LibVLC_isSeekable(JNIEnv *env, jobject thiz)
462
{
463 464 465
    libvlc_media_player_t *mp = getMediaPlayer(env, thiz);
    if (mp)
        return !!libvlc_media_player_is_seekable(mp);
466
    return 0;
467 468
}

469
void Java_org_videolan_libvlc_LibVLC_play(JNIEnv *env, jobject thiz)
470
{
471
    libvlc_media_player_t *mp = getMediaPlayer(env, thiz);
472
    if (mp)
473
        libvlc_media_player_play(mp);
474 475
}

476
void Java_org_videolan_libvlc_LibVLC_pause(JNIEnv *env, jobject thiz)
477
{
478
    libvlc_media_player_t *mp = getMediaPlayer(env, thiz);
479
    if (mp)
480
        libvlc_media_player_pause(mp);
481 482
}

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

490
jint Java_org_videolan_libvlc_LibVLC_getVolume(JNIEnv *env, jobject thiz)
491
{
492 493 494
    libvlc_media_player_t *mp = getMediaPlayer(env, thiz);
    if (mp)
        return (jint) libvlc_audio_get_volume(mp);
495 496 497
    return -1;
}

498
jint Java_org_videolan_libvlc_LibVLC_setVolume(JNIEnv *env, jobject thiz, jint volume)
499
{
500 501
    libvlc_media_player_t *mp = getMediaPlayer(env, thiz);
    if (mp)
502
        //Returns 0 if the volume was set, -1 if it was out of range or error
503
        return (jint) libvlc_audio_set_volume(mp, (int) volume);
504 505 506
    return -1;
}

507
jlong Java_org_videolan_libvlc_LibVLC_getTime(JNIEnv *env, jobject thiz)
508
{
509 510 511
    libvlc_media_player_t *mp = getMediaPlayer(env, thiz);
    if (mp)
        return libvlc_media_player_get_time(mp);
512 513 514
    return -1;
}

515
void Java_org_videolan_libvlc_LibVLC_setTime(JNIEnv *env, jobject thiz, jlong time)
516
{
517 518 519
    libvlc_media_player_t *mp = getMediaPlayer(env, thiz);
    if (mp)
        libvlc_media_player_set_time(mp, time);
520 521
}

522
jfloat Java_org_videolan_libvlc_LibVLC_getPosition(JNIEnv *env, jobject thiz)
523
{
524 525 526
    libvlc_media_player_t *mp = getMediaPlayer(env, thiz);
    if (mp)
        return (jfloat) libvlc_media_player_get_position(mp);
527 528 529
    return -1;
}

530
void Java_org_videolan_libvlc_LibVLC_setPosition(JNIEnv *env, jobject thiz, jfloat pos)
531
{
532 533 534
    libvlc_media_player_t *mp = getMediaPlayer(env, thiz);
    if (mp)
        libvlc_media_player_set_position(mp, pos);
535 536
}

537
jlong Java_org_videolan_libvlc_LibVLC_getLength(JNIEnv *env, jobject thiz)
538
{
539 540 541
    libvlc_media_player_t *mp = getMediaPlayer(env, thiz);
    if (mp)
        return (jlong) libvlc_media_player_get_length(mp);
542 543 544
    return -1;
}

545
jstring Java_org_videolan_libvlc_LibVLC_version(JNIEnv* env, jobject thiz)
546
{
547 548
    return (*env)->NewStringUTF(env, libvlc_get_version());
}
549

550
jstring Java_org_videolan_libvlc_LibVLC_compiler(JNIEnv* env, jobject thiz)
551 552 553 554
{
    return (*env)->NewStringUTF(env, libvlc_get_compiler());
}

555
jstring Java_org_videolan_libvlc_LibVLC_changeset(JNIEnv* env, jobject thiz)
556 557 558
{
    return (*env)->NewStringUTF(env, libvlc_get_changeset());
}
559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581

jint Java_org_videolan_libvlc_LibVLC_getTitle(JNIEnv *env, jobject thiz)
{
    libvlc_media_player_t *mp = getMediaPlayer(env, thiz);
    if (mp)
        return libvlc_media_player_get_title(mp);
    return -1;
}

void Java_org_videolan_libvlc_LibVLC_setTitle(JNIEnv *env, jobject thiz, jint title)
{
    libvlc_media_player_t *mp = getMediaPlayer(env, thiz);
    if (mp)
        libvlc_media_player_set_title(mp, title);
}

jint Java_org_videolan_libvlc_LibVLC_getChapterCountForTitle(JNIEnv *env, jobject thiz, jint title)
{
    libvlc_media_player_t *mp = getMediaPlayer(env, thiz);
    if (mp)
        return libvlc_media_player_get_chapter_count_for_title(mp, title);
    return -1;
}
Edward Wang's avatar
Edward Wang committed
582 583 584 585 586 587 588 589

jint Java_org_videolan_libvlc_LibVLC_getTitleCount(JNIEnv *env, jobject thiz)
{
    libvlc_media_player_t *mp = getMediaPlayer(env, thiz);
    if (mp)
        return libvlc_media_player_get_title_count(mp);
    return -1;
}