libvlcjni.c 23.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
#include <assert.h>
22 23
#include <dirent.h>
#include <errno.h>
24
#include <string.h>
25
#include <pthread.h>
26
#include <sys/stat.h>
27
#include <sys/types.h>
28
#include <unistd.h>
29

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

34
#include <jni.h>
35

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

38
#include "libvlcjni.h"
ivoire's avatar
ivoire committed
39
#include "aout.h"
40
#include "vout.h"
41
#include "utils.h"
42
#include "native_crash_handler.h"
43

44 45
#define VOUT_ANDROID_SURFACE 0
#define VOUT_OPENGLES2       1
46
#define VOUT_ANDROID_WINDOW  2
47

48
#define LOG_TAG "VLC/JNI/main"
49 50
#include "log.h"

51 52
#define VLC_JNI_VERSION JNI_VERSION_1_2

53 54 55 56 57
#define THREAD_NAME "libvlcjni"
int jni_attach_thread(JNIEnv **env, const char *thread_name);
void jni_detach_thread();
int jni_get_env(JNIEnv **env);

58 59 60 61 62 63 64 65 66 67 68 69
static void add_media_options(libvlc_media_t *p_md, JNIEnv *env, jobjectArray mediaOptions)
{
    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);
    }
}

70
libvlc_media_t *new_media(JNIEnv *env, jobject thiz, jstring fileLocation, bool noOmx, bool noVideo)
71
{
72
    libvlc_instance_t *libvlc = getLibVlcInstance(env, thiz);
73
    jboolean isCopy;
74 75 76
    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);
77 78 79
    if (!p_md)
        return NULL;

80 81 82 83 84 85 86 87 88
    jclass cls = (*env)->GetObjectClass(env, thiz);
    jmethodID methodId = (*env)->GetMethodID(env, cls, "getMediaOptions", "(ZZ)[Ljava/lang/String;");
    if (methodId != NULL)
    {
        jobjectArray mediaOptions = (*env)->CallObjectMethod(env, thiz, methodId, noOmx, noVideo);
        if (mediaOptions != NULL)
        {
            add_media_options(p_md, env, mediaOptions);
            (*env)->DeleteLocalRef(env, mediaOptions);
89
        }
90
    }
91
    return p_md;
92 93
}

94 95 96 97 98
libvlc_instance_t *getLibVlcInstance(JNIEnv *env, jobject thiz)
{
    return (libvlc_instance_t*)(intptr_t)getLong(env, thiz, "mLibVlcInstance");
}

99
libvlc_media_player_t *getMediaPlayer(JNIEnv *env, jobject thiz)
100
{
Ludovic Fauvet's avatar
Ludovic Fauvet committed
101
    return (libvlc_media_player_t*)(intptr_t)getLong(env, thiz, "mInternalMediaPlayerInstance");
102 103
}

104

Rafaël Carré's avatar
Rafaël Carré committed
105 106
static void releaseMediaPlayer(JNIEnv *env, jobject thiz)
{
107 108
    libvlc_media_player_t* p_mp = getMediaPlayer(env, thiz);
    if (p_mp)
109
    {
110 111
        libvlc_media_player_stop(p_mp);
        libvlc_media_player_release(p_mp);
112
        setLong(env, thiz, "mInternalMediaPlayerInstance", 0);
113 114 115
    }
}

116 117 118 119
/* 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
 */
Thomas Guillem's avatar
Thomas Guillem committed
120
static JavaVM *myVm;
121

122
static jobject eventHandlerInstance = NULL;
123 124 125 126 127

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

128
    bool isAttached = false;
129

130
    if (eventHandlerInstance == NULL)
Sébastien Toque's avatar
Sébastien Toque committed
131
        return;
132

133 134
    if (jni_get_env(&env) < 0) {
        if (jni_attach_thread(&env, THREAD_NAME) < 0)
135
            return;
136
        isAttached = true;
137 138
    }

139 140 141 142 143 144 145 146 147 148
    /* 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" );
149
    jmethodID putLong = (*env)->GetMethodID(env, clsBundle, "putLong", "(Ljava/lang/String;J)V" );
150
    jmethodID putFloat = (*env)->GetMethodID(env, clsBundle, "putFloat", "(Ljava/lang/String;F)V" );
151 152
    jmethodID putString = (*env)->GetMethodID(env, clsBundle, "putString", "(Ljava/lang/String;Ljava/lang/String;)V" );

153
    if (ev->type == libvlc_MediaPlayerPositionChanged) {
154 155 156
        jstring sData = (*env)->NewStringUTF(env, "data");
        (*env)->CallVoidMethod(env, bundle, putFloat, sData, ev->u.media_player_position_changed.new_position);
        (*env)->DeleteLocalRef(env, sData);
157 158
    } else if (ev->type == libvlc_MediaPlayerTimeChanged) {
        jstring sData = (*env)->NewStringUTF(env, "data");
159
        (*env)->CallVoidMethod(env, bundle, putLong, sData, ev->u.media_player_time_changed.new_time);
160
        (*env)->DeleteLocalRef(env, sData);
161
    } else if(ev->type == libvlc_MediaPlayerVout) {
162 163 164 165
        /* 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);
166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188
    } 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);
189 190
    }

191
    /* Get the object class */
192
    jclass cls = (*env)->GetObjectClass(env, eventHandlerInstance);
193
    if (!cls) {
194
        LOGE("EventHandler: failed to get class reference");
195
        goto end;
196 197 198
    }

    /* Find the callback ID */
199
    jmethodID methodID = (*env)->GetMethodID(env, cls, "callback", "(ILandroid/os/Bundle;)V");
200
    if (methodID) {
201
        (*env)->CallVoidMethod(env, eventHandlerInstance, methodID, ev->type, bundle);
202
    } else {
203
        LOGE("EventHandler: failed to get the callback method");
204 205
    }

206
end:
Edward Wang's avatar
Edward Wang committed
207
    (*env)->DeleteLocalRef(env, bundle);
208
    if (isAttached)
209
        jni_detach_thread();
210 211
}

212
jint JNI_OnLoad(JavaVM *vm, void *reserved)
213
{
214 215 216
    // Keep a reference on the Java VM.
    myVm = vm;

217
    pthread_mutex_init(&vout_android_lock, NULL);
218
    pthread_cond_init(&vout_android_surf_attached, NULL);
219

220
    LOGD("JNI interface loaded.");
221
    return VLC_JNI_VERSION;
222 223
}

224 225
void JNI_OnUnload(JavaVM* vm, void* reserved) {
    pthread_mutex_destroy(&vout_android_lock);
226
    pthread_cond_destroy(&vout_android_surf_attached);
227 228
}

229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248
int jni_attach_thread(JNIEnv **env, const char *thread_name)
{
    JavaVMAttachArgs args;
    jint result;

    args.version = VLC_JNI_VERSION;
    args.name = thread_name;
    args.group = NULL;

    result = (*myVm)->AttachCurrentThread(myVm, env, &args);
    return result == JNI_OK ? 0 : -1;
}

void jni_detach_thread()
{
    (*myVm)->DetachCurrentThread(myVm);
}

int jni_get_env(JNIEnv **env)
{
249
    return (*myVm)->GetEnv(myVm, (void **)env, VLC_JNI_VERSION) == JNI_OK ? 0 : -1;
250 251
}

Rafaël Carré's avatar
Rafaël Carré committed
252 253
// FIXME: use atomics
static bool verbosity;
254

255
void Java_org_videolan_libvlc_LibVLC_nativeInit(JNIEnv *env, jobject thiz)
256
{
257 258 259
    //only use OpenSLES if java side says we can
    jclass cls = (*env)->GetObjectClass(env, thiz);
    jmethodID methodId = (*env)->GetMethodID(env, cls, "getAout", "()I");
Thomas Guillem's avatar
Thomas Guillem committed
260
    int aout = (*env)->CallIntMethod(env, thiz, methodId);
261

262
    methodId = (*env)->GetMethodID(env, cls, "getVout", "()I");
263
    int vout = (*env)->CallIntMethod(env, thiz, methodId);
264

265 266 267
    methodId = (*env)->GetMethodID(env, cls, "timeStretchingEnabled", "()Z");
    bool enable_time_stretch = (*env)->CallBooleanMethod(env, thiz, methodId);

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

Edward Wang's avatar
Edward Wang committed
271 272
    methodId = (*env)->GetMethodID(env, cls, "getDeblocking", "()I");
    int deblocking = (*env)->CallIntMethod(env, thiz, methodId);
Rafaël Carré's avatar
Rafaël Carré committed
273 274
    char deblockstr[2];
    snprintf(deblockstr, sizeof(deblockstr), "%d", deblocking);
Edward Wang's avatar
Edward Wang committed
275
    LOGD("Using deblocking level %d", deblocking);
276

Edward Wang's avatar
Edward Wang committed
277 278
    methodId = (*env)->GetMethodID(env, cls, "getNetworkCaching", "()I");
    int networkCaching = (*env)->CallIntMethod(env, thiz, methodId);
Rafaël Carré's avatar
Rafaël Carré committed
279
    char networkCachingstr[25];
Edward Wang's avatar
Edward Wang committed
280
    if(networkCaching > 0) {
Rafaël Carré's avatar
Rafaël Carré committed
281
        snprintf(networkCachingstr, sizeof(networkCachingstr), "--network-caching=%d", networkCaching);
Edward Wang's avatar
Edward Wang committed
282 283 284
        LOGD("Using network caching of %d ms", networkCaching);
    }

285 286 287
    methodId = (*env)->GetMethodID(env, cls, "getHttpReconnect", "()Z");
    bool enable_http_reconnect = (*env)->CallBooleanMethod(env, thiz, methodId);

288 289 290 291
    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
292

293 294 295
    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
296
    LOGD("Subtitle encoding set to \"%s\"", subsencodingstr);
297

298 299 300
    methodId = (*env)->GetMethodID(env, cls, "isVerboseMode", "()Z");
    verbosity = (*env)->CallBooleanMethod(env, thiz, methodId);

301 302
    methodId = (*env)->GetMethodID(env, cls, "isDirectRendering", "()Z");
    bool direct_rendering = (*env)->CallBooleanMethod(env, thiz, methodId);
303
    /* With the MediaCodec opaque mode we cannot use the OpenGL ES vout. */
304
    if (direct_rendering)
305
        vout = VOUT_ANDROID_WINDOW;
306

flx42's avatar
flx42 committed
307 308
    methodId = (*env)->GetMethodID(env, cls, "getCachePath", "()Ljava/lang/String;");
    jstring cachePath = (*env)->CallObjectMethod(env, thiz, methodId);
309 310 311 312 313
    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
314

315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359
#define MAX_ARGV 18
    const char *argv[MAX_ARGV];
    int argc = 0;

    /* CPU intensive plugin, setting for slow devices */
    argv[argc++] = enable_time_stretch ? "--audio-time-stretch" : "--no-audio-time-stretch";
    /* avcodec-skiploopfilter */
    argv[argc++] = "--avcodec-skiploopfilter";
    argv[argc++] = deblockstr;
    /* avcodec-skip-frame */
    argv[argc++] = "--avcodec-skip-frame";
    argv[argc++] = enable_frame_skip ? "2" : "0";
    /* avcodec-skip-idct */
    argv[argc++] = "--avcodec-skip-idct";
    argv[argc++] = enable_frame_skip ? "2" : "0";
    /* Remove me when UTF-8 is enforced by law */
    argv[argc++] = "--subsdec-encoding";
    argv[argc++] = subsencodingstr;
    /* Enable statistics */
    argv[argc++] = "--stats";
    /* XXX: why can't the default be fine ? #7792 */
    if (networkCaching > 0)
        argv[argc++] = networkCachingstr;
    /* Android audio API */
    argv[argc++] = aout == AOUT_OPENSLES ? "--aout=opensles" :
        (aout == AOUT_AUDIOTRACK ? "--aout=android_audiotrack" : "--aout=dummy");
    /* Android video API  */
    argv[argc++] = vout == VOUT_ANDROID_WINDOW ? "--vout=androidwindow" :
        (vout == VOUT_OPENGLES2 ? "--vout=gles2" : "--vout=androidsurface");
    /* chroma */
    argv[argc++] = "--androidsurface-chroma";
    argv[argc++] = chromastr != NULL && chromastr[0] != 0 ? chromastr : "RV32";
    /* direct rendering */
    if (!direct_rendering) {
        argv[argc++] = "--no-mediacodec-dr";
#ifdef HAVE_IOMX_DR
        argv[argc++] = "--no-omxil-dr";
#endif
    }
    /* Reconnect on lost HTTP streams, e.g. network change */
    if (enable_http_reconnect)
        argv[argc++] = "--http-reconnect";

    assert(MAX_ARGV >= argc);
    libvlc_instance_t *instance = libvlc_new(argc, argv);
360

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

363
    (*env)->ReleaseStringUTFChars(env, chroma, chromastr);
364 365
    (*env)->ReleaseStringUTFChars(env, subsencoding, subsencodingstr);

366 367
    if (!instance)
    {
368
        jclass exc = (*env)->FindClass(env, "org/videolan/libvlc/LibVlcException");
369 370 371 372
        (*env)->ThrowNew(env, exc, "Unable to instantiate LibVLC");
    }

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

Rafaël Carré's avatar
Rafaël Carré committed
374
    libvlc_log_set(instance, debug_log, &verbosity);
375 376

    init_native_crash_handler(env, thiz);
377 378
}

379
void Java_org_videolan_libvlc_LibVLC_nativeDestroy(JNIEnv *env, jobject thiz)
380
{
381 382
    destroy_native_crash_handler(env);

383
    releaseMediaPlayer(env, thiz);
Edward Wang's avatar
Edward Wang committed
384
    jlong libVlcInstance = getLong(env, thiz, "mLibVlcInstance");
385 386 387
    if (!libVlcInstance)
        return; // Already destroyed

Ludovic Fauvet's avatar
Ludovic Fauvet committed
388
    libvlc_instance_t *instance = (libvlc_instance_t*)(intptr_t) libVlcInstance;
Rafaël Carré's avatar
Rafaël Carré committed
389
    libvlc_log_unset(instance);
390 391
    libvlc_release(instance);

Edward Wang's avatar
Edward Wang committed
392
    setLong(env, thiz, "mLibVlcInstance", 0);
393 394
}

395
void Java_org_videolan_libvlc_LibVLC_detachEventHandler(JNIEnv *env, jobject thiz)
396
{
397 398 399
    if (eventHandlerInstance != NULL) {
        (*env)->DeleteGlobalRef(env, eventHandlerInstance);
        eventHandlerInstance = NULL;
400 401 402
    }
}

403
void Java_org_videolan_libvlc_LibVLC_setEventHandler(JNIEnv *env, jobject thiz, jobject eventHandler)
404
{
405 406 407
    if (eventHandlerInstance != NULL) {
        (*env)->DeleteGlobalRef(env, eventHandlerInstance);
        eventHandlerInstance = NULL;
408 409
    }

410
    eventHandlerInstance = getEventHandlerReference(env, thiz, eventHandler);
411 412
}

413
void Java_org_videolan_libvlc_LibVLC_playMRL(JNIEnv *env, jobject thiz,
414 415
                                             jstring mrl, jobjectArray mediaOptions)
{
416 417 418
    /* Release previous media player, if any */
    releaseMediaPlayer(env, thiz);

419 420
    libvlc_instance_t *p_instance = getLibVlcInstance(env, thiz);

421
    /* Create a media player playing environment */
422
    libvlc_media_player_t *mp = libvlc_media_player_new(p_instance);
Rafaël Carré's avatar
Rafaël Carré committed
423
    libvlc_media_player_set_video_title_display(mp, libvlc_position_disable, 0);
424
    jobject myJavaLibVLC = (*env)->NewGlobalRef(env, thiz); // freed in aout_close
425

426
    // If AOUT_AUDIOTRACK_JAVA, use amem
427 428 429
    jclass cls = (*env)->GetObjectClass(env, thiz);
    jmethodID methodId = (*env)->GetMethodID(env, cls, "getAout", "()I");
    if ( (*env)->CallIntMethod(env, thiz, methodId) == AOUT_AUDIOTRACK_JAVA )
430
    {
431
        libvlc_audio_set_callbacks(mp, aout_play, aout_pause, NULL, NULL, NULL,
Sébastien Toque's avatar
Sébastien Toque committed
432 433
                                   (void*) myJavaLibVLC);
        libvlc_audio_set_format_callbacks(mp, aout_open, aout_close);
434 435
    }

436 437
    /* Connect the event manager */
    libvlc_event_manager_t *ev = libvlc_media_player_event_manager(mp);
438 439 440 441 442
    static const libvlc_event_type_t mp_events[] = {
        libvlc_MediaPlayerPlaying,
        libvlc_MediaPlayerPaused,
        libvlc_MediaPlayerEndReached,
        libvlc_MediaPlayerStopped,
443
        libvlc_MediaPlayerVout,
444
        libvlc_MediaPlayerPositionChanged,
445
        libvlc_MediaPlayerTimeChanged,
446
        libvlc_MediaPlayerEncounteredError
447
    };
448
    for(int i = 0; i < (sizeof(mp_events) / sizeof(*mp_events)); i++)
449 450
        libvlc_event_attach(ev, mp_events[i], vlc_event_callback, myVm);

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

454 455 456 457
    cls = (*env)->GetObjectClass(env, thiz);
    jmethodID methodID = (*env)->GetMethodID(env, cls, "applyEqualizer", "()V");
    (*env)->CallVoidMethod(env, thiz, methodID);

458 459
    const char* p_mrl = (*env)->GetStringUTFChars(env, mrl, 0);

460
    libvlc_media_t* p_md = libvlc_media_new_location(p_instance, p_mrl);
461
    /* media options */
462
    if (mediaOptions != NULL)
463
        add_media_options(p_md, env, mediaOptions);
464

465 466
    (*env)->ReleaseStringUTFChars(env, mrl, p_mrl);

467 468 469
    /* 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[] = {
Alexandre Perraud's avatar
Alexandre Perraud committed
470 471
        libvlc_MediaParsedChanged,
        libvlc_MediaMetaChanged,
472 473 474 475
    };
    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);

476 477
    libvlc_media_player_set_media(mp, p_md);
    libvlc_media_player_play(mp);
478 479
}

480
jfloat Java_org_videolan_libvlc_LibVLC_getRate(JNIEnv *env, jobject thiz) {
Edward Wang's avatar
Edward Wang committed
481 482 483 484 485 486 487
    libvlc_media_player_t* mp = getMediaPlayer(env, thiz);
    if(mp)
        return libvlc_media_player_get_rate(mp);
    else
        return 1.00;
}

488
void Java_org_videolan_libvlc_LibVLC_setRate(JNIEnv *env, jobject thiz, jfloat rate) {
Edward Wang's avatar
Edward Wang committed
489 490 491 492 493
    libvlc_media_player_t* mp = getMediaPlayer(env, thiz);
    if(mp)
        libvlc_media_player_set_rate(mp, rate);
}

494
jboolean Java_org_videolan_libvlc_LibVLC_isPlaying(JNIEnv *env, jobject thiz)
495
{
496
    libvlc_media_player_t *mp = getMediaPlayer(env, thiz);
497
    if (mp)
498
        return !!libvlc_media_player_is_playing(mp);
499 500
    else
        return 0;
501 502
}

503
jboolean Java_org_videolan_libvlc_LibVLC_isSeekable(JNIEnv *env, jobject thiz)
504
{
505 506 507
    libvlc_media_player_t *mp = getMediaPlayer(env, thiz);
    if (mp)
        return !!libvlc_media_player_is_seekable(mp);
508
    return 0;
509 510
}

511
void Java_org_videolan_libvlc_LibVLC_play(JNIEnv *env, jobject thiz)
512
{
513
    libvlc_media_player_t *mp = getMediaPlayer(env, thiz);
514
    if (mp)
515
        libvlc_media_player_play(mp);
516 517
}

518
void Java_org_videolan_libvlc_LibVLC_pause(JNIEnv *env, jobject thiz)
519
{
520
    libvlc_media_player_t *mp = getMediaPlayer(env, thiz);
521
    if (mp)
522
        libvlc_media_player_pause(mp);
523 524
}

525
void Java_org_videolan_libvlc_LibVLC_stop(JNIEnv *env, jobject thiz)
526
{
527
    libvlc_media_player_t *mp = getMediaPlayer(env, thiz);
528
    if (mp)
529
        libvlc_media_player_stop(mp);
530 531
}

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

540
jint Java_org_videolan_libvlc_LibVLC_getVolume(JNIEnv *env, jobject thiz)
541
{
542 543 544
    libvlc_media_player_t *mp = getMediaPlayer(env, thiz);
    if (mp)
        return (jint) libvlc_audio_get_volume(mp);
545 546 547
    return -1;
}

548
jint Java_org_videolan_libvlc_LibVLC_setVolume(JNIEnv *env, jobject thiz, jint volume)
549
{
550 551
    libvlc_media_player_t *mp = getMediaPlayer(env, thiz);
    if (mp)
552
        //Returns 0 if the volume was set, -1 if it was out of range or error
553
        return (jint) libvlc_audio_set_volume(mp, (int) volume);
554 555 556
    return -1;
}

557
jlong Java_org_videolan_libvlc_LibVLC_getTime(JNIEnv *env, jobject thiz)
558
{
559 560 561
    libvlc_media_player_t *mp = getMediaPlayer(env, thiz);
    if (mp)
        return libvlc_media_player_get_time(mp);
562 563 564
    return -1;
}

565
void Java_org_videolan_libvlc_LibVLC_setTime(JNIEnv *env, jobject thiz, jlong time)
566
{
567 568 569
    libvlc_media_player_t *mp = getMediaPlayer(env, thiz);
    if (mp)
        libvlc_media_player_set_time(mp, time);
570 571
}

572
jfloat Java_org_videolan_libvlc_LibVLC_getPosition(JNIEnv *env, jobject thiz)
573
{
574 575 576
    libvlc_media_player_t *mp = getMediaPlayer(env, thiz);
    if (mp)
        return (jfloat) libvlc_media_player_get_position(mp);
577 578 579
    return -1;
}

580
void Java_org_videolan_libvlc_LibVLC_setPosition(JNIEnv *env, jobject thiz, jfloat pos)
581
{
582 583 584
    libvlc_media_player_t *mp = getMediaPlayer(env, thiz);
    if (mp)
        libvlc_media_player_set_position(mp, pos);
585 586
}

587
jlong Java_org_videolan_libvlc_LibVLC_getLength(JNIEnv *env, jobject thiz)
588
{
589 590 591
    libvlc_media_player_t *mp = getMediaPlayer(env, thiz);
    if (mp)
        return (jlong) libvlc_media_player_get_length(mp);
592 593 594
    return -1;
}

595
jstring Java_org_videolan_libvlc_LibVLC_version(JNIEnv* env, jobject thiz)
596
{
597 598
    return (*env)->NewStringUTF(env, libvlc_get_version());
}
599

600
jstring Java_org_videolan_libvlc_LibVLC_compiler(JNIEnv* env, jobject thiz)
601 602 603 604
{
    return (*env)->NewStringUTF(env, libvlc_get_compiler());
}

605
jstring Java_org_videolan_libvlc_LibVLC_changeset(JNIEnv* env, jobject thiz)
606 607 608
{
    return (*env)->NewStringUTF(env, libvlc_get_changeset());
}
609

610 611 612
jstring Java_org_videolan_libvlc_LibVLC_getMeta(JNIEnv *env, jobject thiz, int meta)
{
    libvlc_media_player_t *mp = getMediaPlayer(env, thiz);
613 614
    char *psz_meta;
    jstring string = NULL;
615 616 617 618 619 620 621
    if (!mp)
        return NULL;

    libvlc_media_t *p_mp = libvlc_media_player_get_media(mp);
    if (!p_mp)
        return NULL;

622 623 624 625 626 627
    psz_meta = libvlc_media_get_meta(p_mp, meta);
    if (psz_meta) {
        string = (*env)->NewStringUTF(env, psz_meta);
        free(psz_meta);
    }
    return string;
628 629
}

630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651
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
652 653 654 655 656 657 658 659

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;
}
Geoffrey Métais's avatar
Geoffrey Métais committed
660 661 662 663 664 665 666 667 668

void Java_org_videolan_libvlc_LibVLC_playerNavigate(JNIEnv *env, jobject thiz, jint navigate)
{
    unsigned nav = navigate;
    libvlc_media_player_t *mp = getMediaPlayer(env, thiz);
    if (mp)
        libvlc_media_player_navigate(mp, (unsigned) nav);
}

Thomas Guillem's avatar
Thomas Guillem committed
669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688
// TODO: remove static variables
static int i_window_width = 0;
static int i_window_height = 0;

void Java_org_videolan_libvlc_LibVLC_setWindowSize(JNIEnv *env, jobject thiz, jint width, jint height)
{
    pthread_mutex_lock(&vout_android_lock);
    i_window_width = width;
    i_window_height = height;
    pthread_mutex_unlock(&vout_android_lock);
}

int jni_GetWindowSize(int *width, int *height)
{
    pthread_mutex_lock(&vout_android_lock);
    *width = i_window_width;
    *height = i_window_height;
    pthread_mutex_unlock(&vout_android_lock);
    return 0;
}