android_media_MediaPlayer.cpp revision 23dfee521a7782bf901344beec6f94614e0b02b8
1/*
2**
3** Copyright 2007, The Android Open Source Project
4**
5** Licensed under the Apache License, Version 2.0 (the "License");
6** you may not use this file except in compliance with the License.
7** You may obtain a copy of the License at
8**
9**     http://www.apache.org/licenses/LICENSE-2.0
10**
11** Unless required by applicable law or agreed to in writing, software
12** distributed under the License is distributed on an "AS IS" BASIS,
13** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14** See the License for the specific language governing permissions and
15** limitations under the License.
16*/
17
18//#define LOG_NDEBUG 0
19#define LOG_TAG "MediaPlayer-JNI"
20#include "utils/Log.h"
21
22#include <media/mediaplayer.h>
23#include <media/AudioResamplerPublic.h>
24#include <media/IMediaHTTPService.h>
25#include <media/MediaPlayerInterface.h>
26#include <stdio.h>
27#include <assert.h>
28#include <limits.h>
29#include <unistd.h>
30#include <fcntl.h>
31#include <utils/threads.h>
32#include "jni.h"
33#include "JNIHelp.h"
34#include "android_runtime/AndroidRuntime.h"
35#include "android_runtime/android_view_Surface.h"
36#include "android_runtime/Log.h"
37#include "utils/Errors.h"  // for status_t
38#include "utils/KeyedVector.h"
39#include "utils/String8.h"
40#include "android_media_BufferingParams.h"
41#include "android_media_MediaDataSource.h"
42#include "android_media_PlaybackParams.h"
43#include "android_media_SyncParams.h"
44#include "android_media_Utils.h"
45
46#include "android_os_Parcel.h"
47#include "android_util_Binder.h"
48#include <binder/Parcel.h>
49#include <gui/IGraphicBufferProducer.h>
50#include <gui/Surface.h>
51#include <binder/IPCThreadState.h>
52#include <binder/IServiceManager.h>
53
54#include "android_util_Binder.h"
55// ----------------------------------------------------------------------------
56
57using namespace android;
58
59// ----------------------------------------------------------------------------
60
61struct fields_t {
62    jfieldID    context;
63    jfieldID    surface_texture;
64
65    jmethodID   post_event;
66
67    jmethodID   proxyConfigGetHost;
68    jmethodID   proxyConfigGetPort;
69    jmethodID   proxyConfigGetExclusionList;
70};
71static fields_t fields;
72
73static BufferingParams::fields_t gBufferingParamsFields;
74static PlaybackParams::fields_t gPlaybackParamsFields;
75static SyncParams::fields_t gSyncParamsFields;
76
77static Mutex sLock;
78
79// ----------------------------------------------------------------------------
80// ref-counted object for callbacks
81class JNIMediaPlayerListener: public MediaPlayerListener
82{
83public:
84    JNIMediaPlayerListener(JNIEnv* env, jobject thiz, jobject weak_thiz);
85    ~JNIMediaPlayerListener();
86    virtual void notify(int msg, int ext1, int ext2, const Parcel *obj = NULL);
87private:
88    JNIMediaPlayerListener();
89    jclass      mClass;     // Reference to MediaPlayer class
90    jobject     mObject;    // Weak ref to MediaPlayer Java object to call on
91};
92
93JNIMediaPlayerListener::JNIMediaPlayerListener(JNIEnv* env, jobject thiz, jobject weak_thiz)
94{
95
96    // Hold onto the MediaPlayer class for use in calling the static method
97    // that posts events to the application thread.
98    jclass clazz = env->GetObjectClass(thiz);
99    if (clazz == NULL) {
100        ALOGE("Can't find android/media/MediaPlayer");
101        jniThrowException(env, "java/lang/Exception", NULL);
102        return;
103    }
104    mClass = (jclass)env->NewGlobalRef(clazz);
105
106    // We use a weak reference so the MediaPlayer object can be garbage collected.
107    // The reference is only used as a proxy for callbacks.
108    mObject  = env->NewGlobalRef(weak_thiz);
109}
110
111JNIMediaPlayerListener::~JNIMediaPlayerListener()
112{
113    // remove global references
114    JNIEnv *env = AndroidRuntime::getJNIEnv();
115    env->DeleteGlobalRef(mObject);
116    env->DeleteGlobalRef(mClass);
117}
118
119void JNIMediaPlayerListener::notify(int msg, int ext1, int ext2, const Parcel *obj)
120{
121    JNIEnv *env = AndroidRuntime::getJNIEnv();
122    if (obj && obj->dataSize() > 0) {
123        jobject jParcel = createJavaParcelObject(env);
124        if (jParcel != NULL) {
125            Parcel* nativeParcel = parcelForJavaObject(env, jParcel);
126            nativeParcel->setData(obj->data(), obj->dataSize());
127            env->CallStaticVoidMethod(mClass, fields.post_event, mObject,
128                    msg, ext1, ext2, jParcel);
129            env->DeleteLocalRef(jParcel);
130        }
131    } else {
132        env->CallStaticVoidMethod(mClass, fields.post_event, mObject,
133                msg, ext1, ext2, NULL);
134    }
135    if (env->ExceptionCheck()) {
136        ALOGW("An exception occurred while notifying an event.");
137        LOGW_EX(env);
138        env->ExceptionClear();
139    }
140}
141
142// ----------------------------------------------------------------------------
143
144static sp<MediaPlayer> getMediaPlayer(JNIEnv* env, jobject thiz)
145{
146    Mutex::Autolock l(sLock);
147    MediaPlayer* const p = (MediaPlayer*)env->GetLongField(thiz, fields.context);
148    return sp<MediaPlayer>(p);
149}
150
151static sp<MediaPlayer> setMediaPlayer(JNIEnv* env, jobject thiz, const sp<MediaPlayer>& player)
152{
153    Mutex::Autolock l(sLock);
154    sp<MediaPlayer> old = (MediaPlayer*)env->GetLongField(thiz, fields.context);
155    if (player.get()) {
156        player->incStrong((void*)setMediaPlayer);
157    }
158    if (old != 0) {
159        old->decStrong((void*)setMediaPlayer);
160    }
161    env->SetLongField(thiz, fields.context, (jlong)player.get());
162    return old;
163}
164
165// If exception is NULL and opStatus is not OK, this method sends an error
166// event to the client application; otherwise, if exception is not NULL and
167// opStatus is not OK, this method throws the given exception to the client
168// application.
169static void process_media_player_call(JNIEnv *env, jobject thiz, status_t opStatus, const char* exception, const char *message)
170{
171    if (exception == NULL) {  // Don't throw exception. Instead, send an event.
172        if (opStatus != (status_t) OK) {
173            sp<MediaPlayer> mp = getMediaPlayer(env, thiz);
174            if (mp != 0) mp->notify(MEDIA_ERROR, opStatus, 0);
175        }
176    } else {  // Throw exception!
177        if ( opStatus == (status_t) INVALID_OPERATION ) {
178            jniThrowException(env, "java/lang/IllegalStateException", NULL);
179        } else if ( opStatus == (status_t) BAD_VALUE ) {
180            jniThrowException(env, "java/lang/IllegalArgumentException", NULL);
181        } else if ( opStatus == (status_t) PERMISSION_DENIED ) {
182            jniThrowException(env, "java/lang/SecurityException", NULL);
183        } else if ( opStatus != (status_t) OK ) {
184            if (strlen(message) > 230) {
185               // if the message is too long, don't bother displaying the status code
186               jniThrowException( env, exception, message);
187            } else {
188               char msg[256];
189                // append the status code to the message
190               sprintf(msg, "%s: status=0x%X", message, opStatus);
191               jniThrowException( env, exception, msg);
192            }
193        }
194    }
195}
196
197static void
198android_media_MediaPlayer_setDataSourceAndHeaders(
199        JNIEnv *env, jobject thiz, jobject httpServiceBinderObj, jstring path,
200        jobjectArray keys, jobjectArray values) {
201
202    sp<MediaPlayer> mp = getMediaPlayer(env, thiz);
203    if (mp == NULL ) {
204        jniThrowException(env, "java/lang/IllegalStateException", NULL);
205        return;
206    }
207
208    if (path == NULL) {
209        jniThrowException(env, "java/lang/IllegalArgumentException", NULL);
210        return;
211    }
212
213    const char *tmp = env->GetStringUTFChars(path, NULL);
214    if (tmp == NULL) {  // Out of memory
215        return;
216    }
217    ALOGV("setDataSource: path %s", tmp);
218
219    String8 pathStr(tmp);
220    env->ReleaseStringUTFChars(path, tmp);
221    tmp = NULL;
222
223    // We build a KeyedVector out of the key and val arrays
224    KeyedVector<String8, String8> headersVector;
225    if (!ConvertKeyValueArraysToKeyedVector(
226            env, keys, values, &headersVector)) {
227        return;
228    }
229
230    sp<IMediaHTTPService> httpService;
231    if (httpServiceBinderObj != NULL) {
232        sp<IBinder> binder = ibinderForJavaObject(env, httpServiceBinderObj);
233        httpService = interface_cast<IMediaHTTPService>(binder);
234    }
235
236    status_t opStatus =
237        mp->setDataSource(
238                httpService,
239                pathStr,
240                headersVector.size() > 0? &headersVector : NULL);
241
242    process_media_player_call(
243            env, thiz, opStatus, "java/io/IOException",
244            "setDataSource failed." );
245}
246
247static void
248android_media_MediaPlayer_setDataSourceFD(JNIEnv *env, jobject thiz, jobject fileDescriptor, jlong offset, jlong length)
249{
250    sp<MediaPlayer> mp = getMediaPlayer(env, thiz);
251    if (mp == NULL ) {
252        jniThrowException(env, "java/lang/IllegalStateException", NULL);
253        return;
254    }
255
256    if (fileDescriptor == NULL) {
257        jniThrowException(env, "java/lang/IllegalArgumentException", NULL);
258        return;
259    }
260    int fd = jniGetFDFromFileDescriptor(env, fileDescriptor);
261    ALOGV("setDataSourceFD: fd %d", fd);
262    process_media_player_call( env, thiz, mp->setDataSource(fd, offset, length), "java/io/IOException", "setDataSourceFD failed." );
263}
264
265static void
266android_media_MediaPlayer_setDataSourceCallback(JNIEnv *env, jobject thiz, jobject dataSource)
267{
268    sp<MediaPlayer> mp = getMediaPlayer(env, thiz);
269    if (mp == NULL ) {
270        jniThrowException(env, "java/lang/IllegalStateException", NULL);
271        return;
272    }
273
274    if (dataSource == NULL) {
275        jniThrowException(env, "java/lang/IllegalArgumentException", NULL);
276        return;
277    }
278    sp<IDataSource> callbackDataSource = new JMediaDataSource(env, dataSource);
279    process_media_player_call(env, thiz, mp->setDataSource(callbackDataSource), "java/lang/RuntimeException", "setDataSourceCallback failed." );
280}
281
282static sp<IGraphicBufferProducer>
283getVideoSurfaceTexture(JNIEnv* env, jobject thiz) {
284    IGraphicBufferProducer * const p = (IGraphicBufferProducer*)env->GetLongField(thiz, fields.surface_texture);
285    return sp<IGraphicBufferProducer>(p);
286}
287
288static void
289decVideoSurfaceRef(JNIEnv *env, jobject thiz)
290{
291    sp<MediaPlayer> mp = getMediaPlayer(env, thiz);
292    if (mp == NULL) {
293        return;
294    }
295
296    sp<IGraphicBufferProducer> old_st = getVideoSurfaceTexture(env, thiz);
297    if (old_st != NULL) {
298        old_st->decStrong((void*)decVideoSurfaceRef);
299    }
300}
301
302static void
303setVideoSurface(JNIEnv *env, jobject thiz, jobject jsurface, jboolean mediaPlayerMustBeAlive)
304{
305    sp<MediaPlayer> mp = getMediaPlayer(env, thiz);
306    if (mp == NULL) {
307        if (mediaPlayerMustBeAlive) {
308            jniThrowException(env, "java/lang/IllegalStateException", NULL);
309        }
310        return;
311    }
312
313    decVideoSurfaceRef(env, thiz);
314
315    sp<IGraphicBufferProducer> new_st;
316    if (jsurface) {
317        sp<Surface> surface(android_view_Surface_getSurface(env, jsurface));
318        if (surface != NULL) {
319            new_st = surface->getIGraphicBufferProducer();
320            if (new_st == NULL) {
321                jniThrowException(env, "java/lang/IllegalArgumentException",
322                    "The surface does not have a binding SurfaceTexture!");
323                return;
324            }
325            new_st->incStrong((void*)decVideoSurfaceRef);
326        } else {
327            jniThrowException(env, "java/lang/IllegalArgumentException",
328                    "The surface has been released");
329            return;
330        }
331    }
332
333    env->SetLongField(thiz, fields.surface_texture, (jlong)new_st.get());
334
335    // This will fail if the media player has not been initialized yet. This
336    // can be the case if setDisplay() on MediaPlayer.java has been called
337    // before setDataSource(). The redundant call to setVideoSurfaceTexture()
338    // in prepare/prepareAsync covers for this case.
339    mp->setVideoSurfaceTexture(new_st);
340}
341
342static void
343android_media_MediaPlayer_setVideoSurface(JNIEnv *env, jobject thiz, jobject jsurface)
344{
345    setVideoSurface(env, thiz, jsurface, true /* mediaPlayerMustBeAlive */);
346}
347
348static jobject
349android_media_MediaPlayer_getDefaultBufferingParams(JNIEnv *env, jobject thiz)
350{
351    sp<MediaPlayer> mp = getMediaPlayer(env, thiz);
352    if (mp == NULL) {
353        jniThrowException(env, "java/lang/IllegalStateException", NULL);
354        return NULL;
355    }
356
357    BufferingParams bp;
358    BufferingSettings &settings = bp.settings;
359    process_media_player_call(
360            env, thiz, mp->getDefaultBufferingSettings(&settings),
361            "java/lang/IllegalStateException", "unexpected error");
362    ALOGV("getDefaultBufferingSettings:{%s}", settings.toString().string());
363
364    return bp.asJobject(env, gBufferingParamsFields);
365}
366
367static jobject
368android_media_MediaPlayer_getBufferingParams(JNIEnv *env, jobject thiz)
369{
370    sp<MediaPlayer> mp = getMediaPlayer(env, thiz);
371    if (mp == NULL) {
372        jniThrowException(env, "java/lang/IllegalStateException", NULL);
373        return NULL;
374    }
375
376    BufferingParams bp;
377    BufferingSettings &settings = bp.settings;
378    process_media_player_call(
379            env, thiz, mp->getBufferingSettings(&settings),
380            "java/lang/IllegalStateException", "unexpected error");
381    ALOGV("getBufferingSettings:{%s}", settings.toString().string());
382
383    return bp.asJobject(env, gBufferingParamsFields);
384}
385
386static void
387android_media_MediaPlayer_setBufferingParams(JNIEnv *env, jobject thiz, jobject params)
388{
389    if (params == NULL) {
390        return;
391    }
392
393    sp<MediaPlayer> mp = getMediaPlayer(env, thiz);
394    if (mp == NULL) {
395        jniThrowException(env, "java/lang/IllegalStateException", NULL);
396        return;
397    }
398
399    BufferingParams bp;
400    bp.fillFromJobject(env, gBufferingParamsFields, params);
401    ALOGV("setBufferingParams:{%s}", bp.settings.toString().string());
402
403    process_media_player_call(
404            env, thiz, mp->setBufferingSettings(bp.settings),
405            "java/lang/IllegalStateException", "unexpected error");
406}
407
408static void
409android_media_MediaPlayer_prepare(JNIEnv *env, jobject thiz)
410{
411    sp<MediaPlayer> mp = getMediaPlayer(env, thiz);
412    if (mp == NULL ) {
413        jniThrowException(env, "java/lang/IllegalStateException", NULL);
414        return;
415    }
416
417    // Handle the case where the display surface was set before the mp was
418    // initialized. We try again to make it stick.
419    sp<IGraphicBufferProducer> st = getVideoSurfaceTexture(env, thiz);
420    mp->setVideoSurfaceTexture(st);
421
422    process_media_player_call( env, thiz, mp->prepare(), "java/io/IOException", "Prepare failed." );
423}
424
425static void
426android_media_MediaPlayer_prepareAsync(JNIEnv *env, jobject thiz)
427{
428    sp<MediaPlayer> mp = getMediaPlayer(env, thiz);
429    if (mp == NULL ) {
430        jniThrowException(env, "java/lang/IllegalStateException", NULL);
431        return;
432    }
433
434    // Handle the case where the display surface was set before the mp was
435    // initialized. We try again to make it stick.
436    sp<IGraphicBufferProducer> st = getVideoSurfaceTexture(env, thiz);
437    mp->setVideoSurfaceTexture(st);
438
439    process_media_player_call( env, thiz, mp->prepareAsync(), "java/io/IOException", "Prepare Async failed." );
440}
441
442static void
443android_media_MediaPlayer_start(JNIEnv *env, jobject thiz)
444{
445    ALOGV("start");
446    sp<MediaPlayer> mp = getMediaPlayer(env, thiz);
447    if (mp == NULL ) {
448        jniThrowException(env, "java/lang/IllegalStateException", NULL);
449        return;
450    }
451    process_media_player_call( env, thiz, mp->start(), NULL, NULL );
452}
453
454static void
455android_media_MediaPlayer_stop(JNIEnv *env, jobject thiz)
456{
457    ALOGV("stop");
458    sp<MediaPlayer> mp = getMediaPlayer(env, thiz);
459    if (mp == NULL ) {
460        jniThrowException(env, "java/lang/IllegalStateException", NULL);
461        return;
462    }
463    process_media_player_call( env, thiz, mp->stop(), NULL, NULL );
464}
465
466static void
467android_media_MediaPlayer_pause(JNIEnv *env, jobject thiz)
468{
469    ALOGV("pause");
470    sp<MediaPlayer> mp = getMediaPlayer(env, thiz);
471    if (mp == NULL ) {
472        jniThrowException(env, "java/lang/IllegalStateException", NULL);
473        return;
474    }
475    process_media_player_call( env, thiz, mp->pause(), NULL, NULL );
476}
477
478static jboolean
479android_media_MediaPlayer_isPlaying(JNIEnv *env, jobject thiz)
480{
481    sp<MediaPlayer> mp = getMediaPlayer(env, thiz);
482    if (mp == NULL ) {
483        jniThrowException(env, "java/lang/IllegalStateException", NULL);
484        return JNI_FALSE;
485    }
486    const jboolean is_playing = mp->isPlaying();
487
488    ALOGV("isPlaying: %d", is_playing);
489    return is_playing;
490}
491
492static void
493android_media_MediaPlayer_setPlaybackParams(JNIEnv *env, jobject thiz, jobject params)
494{
495    sp<MediaPlayer> mp = getMediaPlayer(env, thiz);
496    if (mp == NULL) {
497        jniThrowException(env, "java/lang/IllegalStateException", NULL);
498        return;
499    }
500
501    PlaybackParams pbp;
502    pbp.fillFromJobject(env, gPlaybackParamsFields, params);
503    ALOGV("setPlaybackParams: %d:%f %d:%f %d:%u %d:%u",
504            pbp.speedSet, pbp.audioRate.mSpeed,
505            pbp.pitchSet, pbp.audioRate.mPitch,
506            pbp.audioFallbackModeSet, pbp.audioRate.mFallbackMode,
507            pbp.audioStretchModeSet, pbp.audioRate.mStretchMode);
508
509    AudioPlaybackRate rate;
510    status_t err = mp->getPlaybackSettings(&rate);
511    if (err == OK) {
512        bool updatedRate = false;
513        if (pbp.speedSet) {
514            rate.mSpeed = pbp.audioRate.mSpeed;
515            updatedRate = true;
516        }
517        if (pbp.pitchSet) {
518            rate.mPitch = pbp.audioRate.mPitch;
519            updatedRate = true;
520        }
521        if (pbp.audioFallbackModeSet) {
522            rate.mFallbackMode = pbp.audioRate.mFallbackMode;
523            updatedRate = true;
524        }
525        if (pbp.audioStretchModeSet) {
526            rate.mStretchMode = pbp.audioRate.mStretchMode;
527            updatedRate = true;
528        }
529        if (updatedRate) {
530            err = mp->setPlaybackSettings(rate);
531        }
532    }
533    process_media_player_call(
534            env, thiz, err,
535            "java/lang/IllegalStateException", "unexpected error");
536}
537
538static jobject
539android_media_MediaPlayer_getPlaybackParams(JNIEnv *env, jobject thiz)
540{
541    sp<MediaPlayer> mp = getMediaPlayer(env, thiz);
542    if (mp == NULL) {
543        jniThrowException(env, "java/lang/IllegalStateException", NULL);
544        return NULL;
545    }
546
547    PlaybackParams pbp;
548    AudioPlaybackRate &audioRate = pbp.audioRate;
549    process_media_player_call(
550            env, thiz, mp->getPlaybackSettings(&audioRate),
551            "java/lang/IllegalStateException", "unexpected error");
552    ALOGV("getPlaybackSettings: %f %f %d %d",
553            audioRate.mSpeed, audioRate.mPitch, audioRate.mFallbackMode, audioRate.mStretchMode);
554
555    pbp.speedSet = true;
556    pbp.pitchSet = true;
557    pbp.audioFallbackModeSet = true;
558    pbp.audioStretchModeSet = true;
559
560    return pbp.asJobject(env, gPlaybackParamsFields);
561}
562
563static void
564android_media_MediaPlayer_setSyncParams(JNIEnv *env, jobject thiz, jobject params)
565{
566    sp<MediaPlayer> mp = getMediaPlayer(env, thiz);
567    if (mp == NULL) {
568        jniThrowException(env, "java/lang/IllegalStateException", NULL);
569        return;
570    }
571
572    SyncParams scp;
573    scp.fillFromJobject(env, gSyncParamsFields, params);
574    ALOGV("setSyncParams: %d:%d %d:%d %d:%f %d:%f",
575          scp.syncSourceSet, scp.sync.mSource,
576          scp.audioAdjustModeSet, scp.sync.mAudioAdjustMode,
577          scp.toleranceSet, scp.sync.mTolerance,
578          scp.frameRateSet, scp.frameRate);
579
580    AVSyncSettings avsync;
581    float videoFrameRate;
582    status_t err = mp->getSyncSettings(&avsync, &videoFrameRate);
583    if (err == OK) {
584        bool updatedSync = scp.frameRateSet;
585        if (scp.syncSourceSet) {
586            avsync.mSource = scp.sync.mSource;
587            updatedSync = true;
588        }
589        if (scp.audioAdjustModeSet) {
590            avsync.mAudioAdjustMode = scp.sync.mAudioAdjustMode;
591            updatedSync = true;
592        }
593        if (scp.toleranceSet) {
594            avsync.mTolerance = scp.sync.mTolerance;
595            updatedSync = true;
596        }
597        if (updatedSync) {
598            err = mp->setSyncSettings(avsync, scp.frameRateSet ? scp.frameRate : -1.f);
599        }
600    }
601    process_media_player_call(
602            env, thiz, err,
603            "java/lang/IllegalStateException", "unexpected error");
604}
605
606static jobject
607android_media_MediaPlayer_getSyncParams(JNIEnv *env, jobject thiz)
608{
609    sp<MediaPlayer> mp = getMediaPlayer(env, thiz);
610    if (mp == NULL) {
611        jniThrowException(env, "java/lang/IllegalStateException", NULL);
612        return NULL;
613    }
614
615    SyncParams scp;
616    scp.frameRate = -1.f;
617    process_media_player_call(
618            env, thiz, mp->getSyncSettings(&scp.sync, &scp.frameRate),
619            "java/lang/IllegalStateException", "unexpected error");
620
621    ALOGV("getSyncSettings: %d %d %f %f",
622            scp.sync.mSource, scp.sync.mAudioAdjustMode, scp.sync.mTolerance, scp.frameRate);
623
624    // sanity check params
625    if (scp.sync.mSource >= AVSYNC_SOURCE_MAX
626            || scp.sync.mAudioAdjustMode >= AVSYNC_AUDIO_ADJUST_MODE_MAX
627            || scp.sync.mTolerance < 0.f
628            || scp.sync.mTolerance >= AVSYNC_TOLERANCE_MAX) {
629        jniThrowException(env,  "java/lang/IllegalStateException", NULL);
630        return NULL;
631    }
632
633    scp.syncSourceSet = true;
634    scp.audioAdjustModeSet = true;
635    scp.toleranceSet = true;
636    scp.frameRateSet = scp.frameRate >= 0.f;
637
638    return scp.asJobject(env, gSyncParamsFields);
639}
640
641static void
642android_media_MediaPlayer_seekTo(JNIEnv *env, jobject thiz, jint msec, jint mode)
643{
644    sp<MediaPlayer> mp = getMediaPlayer(env, thiz);
645    if (mp == NULL ) {
646        jniThrowException(env, "java/lang/IllegalStateException", NULL);
647        return;
648    }
649    ALOGV("seekTo: %d(msec), mode=%d", msec, mode);
650    process_media_player_call( env, thiz, mp->seekTo(msec, (MediaPlayerSeekMode)mode), NULL, NULL );
651}
652
653static jint
654android_media_MediaPlayer_getVideoWidth(JNIEnv *env, jobject thiz)
655{
656    sp<MediaPlayer> mp = getMediaPlayer(env, thiz);
657    if (mp == NULL ) {
658        jniThrowException(env, "java/lang/IllegalStateException", NULL);
659        return 0;
660    }
661    int w;
662    if (0 != mp->getVideoWidth(&w)) {
663        ALOGE("getVideoWidth failed");
664        w = 0;
665    }
666    ALOGV("getVideoWidth: %d", w);
667    return (jint) w;
668}
669
670static jint
671android_media_MediaPlayer_getVideoHeight(JNIEnv *env, jobject thiz)
672{
673    sp<MediaPlayer> mp = getMediaPlayer(env, thiz);
674    if (mp == NULL ) {
675        jniThrowException(env, "java/lang/IllegalStateException", NULL);
676        return 0;
677    }
678    int h;
679    if (0 != mp->getVideoHeight(&h)) {
680        ALOGE("getVideoHeight failed");
681        h = 0;
682    }
683    ALOGV("getVideoHeight: %d", h);
684    return (jint) h;
685}
686
687
688static jint
689android_media_MediaPlayer_getCurrentPosition(JNIEnv *env, jobject thiz)
690{
691    sp<MediaPlayer> mp = getMediaPlayer(env, thiz);
692    if (mp == NULL ) {
693        jniThrowException(env, "java/lang/IllegalStateException", NULL);
694        return 0;
695    }
696    int msec;
697    process_media_player_call( env, thiz, mp->getCurrentPosition(&msec), NULL, NULL );
698    ALOGV("getCurrentPosition: %d (msec)", msec);
699    return (jint) msec;
700}
701
702static jint
703android_media_MediaPlayer_getDuration(JNIEnv *env, jobject thiz)
704{
705    sp<MediaPlayer> mp = getMediaPlayer(env, thiz);
706    if (mp == NULL ) {
707        jniThrowException(env, "java/lang/IllegalStateException", NULL);
708        return 0;
709    }
710    int msec;
711    process_media_player_call( env, thiz, mp->getDuration(&msec), NULL, NULL );
712    ALOGV("getDuration: %d (msec)", msec);
713    return (jint) msec;
714}
715
716static void
717android_media_MediaPlayer_reset(JNIEnv *env, jobject thiz)
718{
719    ALOGV("reset");
720    sp<MediaPlayer> mp = getMediaPlayer(env, thiz);
721    if (mp == NULL ) {
722        jniThrowException(env, "java/lang/IllegalStateException", NULL);
723        return;
724    }
725    process_media_player_call( env, thiz, mp->reset(), NULL, NULL );
726}
727
728static void
729android_media_MediaPlayer_setAudioStreamType(JNIEnv *env, jobject thiz, jint streamtype)
730{
731    ALOGV("setAudioStreamType: %d", streamtype);
732    sp<MediaPlayer> mp = getMediaPlayer(env, thiz);
733    if (mp == NULL ) {
734        jniThrowException(env, "java/lang/IllegalStateException", NULL);
735        return;
736    }
737    process_media_player_call( env, thiz, mp->setAudioStreamType((audio_stream_type_t) streamtype) , NULL, NULL );
738}
739
740static jint
741android_media_MediaPlayer_getAudioStreamType(JNIEnv *env, jobject thiz)
742{
743    sp<MediaPlayer> mp = getMediaPlayer(env, thiz);
744    if (mp == NULL ) {
745        jniThrowException(env, "java/lang/IllegalStateException", NULL);
746        return 0;
747    }
748    audio_stream_type_t streamtype;
749    process_media_player_call( env, thiz, mp->getAudioStreamType(&streamtype), NULL, NULL );
750    ALOGV("getAudioStreamType: %d (streamtype)", streamtype);
751    return (jint) streamtype;
752}
753
754static jboolean
755android_media_MediaPlayer_setParameter(JNIEnv *env, jobject thiz, jint key, jobject java_request)
756{
757    ALOGV("setParameter: key %d", key);
758    sp<MediaPlayer> mp = getMediaPlayer(env, thiz);
759    if (mp == NULL ) {
760        jniThrowException(env, "java/lang/IllegalStateException", NULL);
761        return false;
762    }
763
764    Parcel *request = parcelForJavaObject(env, java_request);
765    status_t err = mp->setParameter(key, *request);
766    if (err == OK) {
767        return true;
768    } else {
769        return false;
770    }
771}
772
773static void
774android_media_MediaPlayer_setLooping(JNIEnv *env, jobject thiz, jboolean looping)
775{
776    ALOGV("setLooping: %d", looping);
777    sp<MediaPlayer> mp = getMediaPlayer(env, thiz);
778    if (mp == NULL ) {
779        jniThrowException(env, "java/lang/IllegalStateException", NULL);
780        return;
781    }
782    process_media_player_call( env, thiz, mp->setLooping(looping), NULL, NULL );
783}
784
785static jboolean
786android_media_MediaPlayer_isLooping(JNIEnv *env, jobject thiz)
787{
788    ALOGV("isLooping");
789    sp<MediaPlayer> mp = getMediaPlayer(env, thiz);
790    if (mp == NULL ) {
791        jniThrowException(env, "java/lang/IllegalStateException", NULL);
792        return JNI_FALSE;
793    }
794    return mp->isLooping() ? JNI_TRUE : JNI_FALSE;
795}
796
797static void
798android_media_MediaPlayer_setVolume(JNIEnv *env, jobject thiz, jfloat leftVolume, jfloat rightVolume)
799{
800    ALOGV("setVolume: left %f  right %f", (float) leftVolume, (float) rightVolume);
801    sp<MediaPlayer> mp = getMediaPlayer(env, thiz);
802    if (mp == NULL ) {
803        jniThrowException(env, "java/lang/IllegalStateException", NULL);
804        return;
805    }
806    process_media_player_call( env, thiz, mp->setVolume((float) leftVolume, (float) rightVolume), NULL, NULL );
807}
808
809// Sends the request and reply parcels to the media player via the
810// binder interface.
811static jint
812android_media_MediaPlayer_invoke(JNIEnv *env, jobject thiz,
813                                 jobject java_request, jobject java_reply)
814{
815    sp<MediaPlayer> media_player = getMediaPlayer(env, thiz);
816    if (media_player == NULL ) {
817        jniThrowException(env, "java/lang/IllegalStateException", NULL);
818        return UNKNOWN_ERROR;
819    }
820
821    Parcel *request = parcelForJavaObject(env, java_request);
822    Parcel *reply = parcelForJavaObject(env, java_reply);
823
824    // Don't use process_media_player_call which use the async loop to
825    // report errors, instead returns the status.
826    return (jint) media_player->invoke(*request, reply);
827}
828
829// Sends the new filter to the client.
830static jint
831android_media_MediaPlayer_setMetadataFilter(JNIEnv *env, jobject thiz, jobject request)
832{
833    sp<MediaPlayer> media_player = getMediaPlayer(env, thiz);
834    if (media_player == NULL ) {
835        jniThrowException(env, "java/lang/IllegalStateException", NULL);
836        return UNKNOWN_ERROR;
837    }
838
839    Parcel *filter = parcelForJavaObject(env, request);
840
841    if (filter == NULL ) {
842        jniThrowException(env, "java/lang/RuntimeException", "Filter is null");
843        return UNKNOWN_ERROR;
844    }
845
846    return (jint) media_player->setMetadataFilter(*filter);
847}
848
849static jboolean
850android_media_MediaPlayer_getMetadata(JNIEnv *env, jobject thiz, jboolean update_only,
851                                      jboolean apply_filter, jobject reply)
852{
853    sp<MediaPlayer> media_player = getMediaPlayer(env, thiz);
854    if (media_player == NULL ) {
855        jniThrowException(env, "java/lang/IllegalStateException", NULL);
856        return JNI_FALSE;
857    }
858
859    Parcel *metadata = parcelForJavaObject(env, reply);
860
861    if (metadata == NULL ) {
862        jniThrowException(env, "java/lang/RuntimeException", "Reply parcel is null");
863        return JNI_FALSE;
864    }
865
866    metadata->freeData();
867    // On return metadata is positioned at the beginning of the
868    // metadata. Note however that the parcel actually starts with the
869    // return code so you should not rewind the parcel using
870    // setDataPosition(0).
871    if (media_player->getMetadata(update_only, apply_filter, metadata) == OK) {
872        return JNI_TRUE;
873    } else {
874        return JNI_FALSE;
875    }
876}
877
878// This function gets some field IDs, which in turn causes class initialization.
879// It is called from a static block in MediaPlayer, which won't run until the
880// first time an instance of this class is used.
881static void
882android_media_MediaPlayer_native_init(JNIEnv *env)
883{
884    jclass clazz;
885
886    clazz = env->FindClass("android/media/MediaPlayer");
887    if (clazz == NULL) {
888        return;
889    }
890
891    fields.context = env->GetFieldID(clazz, "mNativeContext", "J");
892    if (fields.context == NULL) {
893        return;
894    }
895
896    fields.post_event = env->GetStaticMethodID(clazz, "postEventFromNative",
897                                               "(Ljava/lang/Object;IIILjava/lang/Object;)V");
898    if (fields.post_event == NULL) {
899        return;
900    }
901
902    fields.surface_texture = env->GetFieldID(clazz, "mNativeSurfaceTexture", "J");
903    if (fields.surface_texture == NULL) {
904        return;
905    }
906
907    env->DeleteLocalRef(clazz);
908
909    clazz = env->FindClass("android/net/ProxyInfo");
910    if (clazz == NULL) {
911        return;
912    }
913
914    fields.proxyConfigGetHost =
915        env->GetMethodID(clazz, "getHost", "()Ljava/lang/String;");
916
917    fields.proxyConfigGetPort =
918        env->GetMethodID(clazz, "getPort", "()I");
919
920    fields.proxyConfigGetExclusionList =
921        env->GetMethodID(clazz, "getExclusionListAsString", "()Ljava/lang/String;");
922
923    env->DeleteLocalRef(clazz);
924
925    gBufferingParamsFields.init(env);
926    gPlaybackParamsFields.init(env);
927    gSyncParamsFields.init(env);
928}
929
930static void
931android_media_MediaPlayer_native_setup(JNIEnv *env, jobject thiz, jobject weak_this)
932{
933    ALOGV("native_setup");
934    sp<MediaPlayer> mp = new MediaPlayer();
935    if (mp == NULL) {
936        jniThrowException(env, "java/lang/RuntimeException", "Out of memory");
937        return;
938    }
939
940    // create new listener and give it to MediaPlayer
941    sp<JNIMediaPlayerListener> listener = new JNIMediaPlayerListener(env, thiz, weak_this);
942    mp->setListener(listener);
943
944    // Stow our new C++ MediaPlayer in an opaque field in the Java object.
945    setMediaPlayer(env, thiz, mp);
946}
947
948static void
949android_media_MediaPlayer_release(JNIEnv *env, jobject thiz)
950{
951    ALOGV("release");
952    decVideoSurfaceRef(env, thiz);
953    sp<MediaPlayer> mp = setMediaPlayer(env, thiz, 0);
954    if (mp != NULL) {
955        // this prevents native callbacks after the object is released
956        mp->setListener(0);
957        mp->disconnect();
958    }
959}
960
961static void
962android_media_MediaPlayer_native_finalize(JNIEnv *env, jobject thiz)
963{
964    ALOGV("native_finalize");
965    sp<MediaPlayer> mp = getMediaPlayer(env, thiz);
966    if (mp != NULL) {
967        ALOGW("MediaPlayer finalized without being released");
968    }
969    android_media_MediaPlayer_release(env, thiz);
970}
971
972static void android_media_MediaPlayer_set_audio_session_id(JNIEnv *env,  jobject thiz,
973        jint sessionId) {
974    ALOGV("set_session_id(): %d", sessionId);
975    sp<MediaPlayer> mp = getMediaPlayer(env, thiz);
976    if (mp == NULL ) {
977        jniThrowException(env, "java/lang/IllegalStateException", NULL);
978        return;
979    }
980    process_media_player_call( env, thiz, mp->setAudioSessionId((audio_session_t) sessionId), NULL,
981            NULL);
982}
983
984static jint android_media_MediaPlayer_get_audio_session_id(JNIEnv *env,  jobject thiz) {
985    ALOGV("get_session_id()");
986    sp<MediaPlayer> mp = getMediaPlayer(env, thiz);
987    if (mp == NULL ) {
988        jniThrowException(env, "java/lang/IllegalStateException", NULL);
989        return 0;
990    }
991
992    return (jint) mp->getAudioSessionId();
993}
994
995static void
996android_media_MediaPlayer_setAuxEffectSendLevel(JNIEnv *env, jobject thiz, jfloat level)
997{
998    ALOGV("setAuxEffectSendLevel: level %f", level);
999    sp<MediaPlayer> mp = getMediaPlayer(env, thiz);
1000    if (mp == NULL ) {
1001        jniThrowException(env, "java/lang/IllegalStateException", NULL);
1002        return;
1003    }
1004    process_media_player_call( env, thiz, mp->setAuxEffectSendLevel(level), NULL, NULL );
1005}
1006
1007static void android_media_MediaPlayer_attachAuxEffect(JNIEnv *env,  jobject thiz, jint effectId) {
1008    ALOGV("attachAuxEffect(): %d", effectId);
1009    sp<MediaPlayer> mp = getMediaPlayer(env, thiz);
1010    if (mp == NULL ) {
1011        jniThrowException(env, "java/lang/IllegalStateException", NULL);
1012        return;
1013    }
1014    process_media_player_call( env, thiz, mp->attachAuxEffect(effectId), NULL, NULL );
1015}
1016
1017static jint
1018android_media_MediaPlayer_pullBatteryData(
1019        JNIEnv *env, jobject /* thiz */, jobject java_reply)
1020{
1021    sp<IBinder> binder = defaultServiceManager()->getService(String16("media.player"));
1022    sp<IMediaPlayerService> service = interface_cast<IMediaPlayerService>(binder);
1023    if (service.get() == NULL) {
1024        jniThrowException(env, "java/lang/RuntimeException", "cannot get MediaPlayerService");
1025        return UNKNOWN_ERROR;
1026    }
1027
1028    Parcel *reply = parcelForJavaObject(env, java_reply);
1029
1030    return (jint) service->pullBatteryData(reply);
1031}
1032
1033static jint
1034android_media_MediaPlayer_setRetransmitEndpoint(JNIEnv *env, jobject thiz,
1035                                                jstring addrString, jint port) {
1036    sp<MediaPlayer> mp = getMediaPlayer(env, thiz);
1037    if (mp == NULL ) {
1038        jniThrowException(env, "java/lang/IllegalStateException", NULL);
1039        return INVALID_OPERATION;
1040    }
1041
1042    const char *cAddrString = NULL;
1043
1044    if (NULL != addrString) {
1045        cAddrString = env->GetStringUTFChars(addrString, NULL);
1046        if (cAddrString == NULL) {  // Out of memory
1047            return NO_MEMORY;
1048        }
1049    }
1050    ALOGV("setRetransmitEndpoint: %s:%d",
1051            cAddrString ? cAddrString : "(null)", port);
1052
1053    status_t ret;
1054    if (cAddrString && (port > 0xFFFF)) {
1055        ret = BAD_VALUE;
1056    } else {
1057        ret = mp->setRetransmitEndpoint(cAddrString,
1058                static_cast<uint16_t>(port));
1059    }
1060
1061    if (NULL != addrString) {
1062        env->ReleaseStringUTFChars(addrString, cAddrString);
1063    }
1064
1065    if (ret == INVALID_OPERATION ) {
1066        jniThrowException(env, "java/lang/IllegalStateException", NULL);
1067    }
1068
1069    return (jint) ret;
1070}
1071
1072static void
1073android_media_MediaPlayer_setNextMediaPlayer(JNIEnv *env, jobject thiz, jobject java_player)
1074{
1075    ALOGV("setNextMediaPlayer");
1076    sp<MediaPlayer> thisplayer = getMediaPlayer(env, thiz);
1077    if (thisplayer == NULL) {
1078        jniThrowException(env, "java/lang/IllegalStateException", "This player not initialized");
1079        return;
1080    }
1081    sp<MediaPlayer> nextplayer = (java_player == NULL) ? NULL : getMediaPlayer(env, java_player);
1082    if (nextplayer == NULL && java_player != NULL) {
1083        jniThrowException(env, "java/lang/IllegalStateException", "That player not initialized");
1084        return;
1085    }
1086
1087    if (nextplayer == thisplayer) {
1088        jniThrowException(env, "java/lang/IllegalArgumentException", "Next player can't be self");
1089        return;
1090    }
1091    // tie the two players together
1092    process_media_player_call(
1093            env, thiz, thisplayer->setNextMediaPlayer(nextplayer),
1094            "java/lang/IllegalArgumentException",
1095            "setNextMediaPlayer failed." );
1096    ;
1097}
1098
1099// ----------------------------------------------------------------------------
1100
1101static const JNINativeMethod gMethods[] = {
1102    {
1103        "nativeSetDataSource",
1104        "(Landroid/os/IBinder;Ljava/lang/String;[Ljava/lang/String;"
1105        "[Ljava/lang/String;)V",
1106        (void *)android_media_MediaPlayer_setDataSourceAndHeaders
1107    },
1108
1109    {"_setDataSource",      "(Ljava/io/FileDescriptor;JJ)V",    (void *)android_media_MediaPlayer_setDataSourceFD},
1110    {"_setDataSource",      "(Landroid/media/MediaDataSource;)V",(void *)android_media_MediaPlayer_setDataSourceCallback },
1111    {"_setVideoSurface",    "(Landroid/view/Surface;)V",        (void *)android_media_MediaPlayer_setVideoSurface},
1112    {"getDefaultBufferingParams", "()Landroid/media/BufferingParams;", (void *)android_media_MediaPlayer_getDefaultBufferingParams},
1113    {"getBufferingParams", "()Landroid/media/BufferingParams;", (void *)android_media_MediaPlayer_getBufferingParams},
1114    {"setBufferingParams", "(Landroid/media/BufferingParams;)V", (void *)android_media_MediaPlayer_setBufferingParams},
1115    {"_prepare",            "()V",                              (void *)android_media_MediaPlayer_prepare},
1116    {"prepareAsync",        "()V",                              (void *)android_media_MediaPlayer_prepareAsync},
1117    {"_start",              "()V",                              (void *)android_media_MediaPlayer_start},
1118    {"_stop",               "()V",                              (void *)android_media_MediaPlayer_stop},
1119    {"getVideoWidth",       "()I",                              (void *)android_media_MediaPlayer_getVideoWidth},
1120    {"getVideoHeight",      "()I",                              (void *)android_media_MediaPlayer_getVideoHeight},
1121    {"setPlaybackParams", "(Landroid/media/PlaybackParams;)V", (void *)android_media_MediaPlayer_setPlaybackParams},
1122    {"getPlaybackParams", "()Landroid/media/PlaybackParams;", (void *)android_media_MediaPlayer_getPlaybackParams},
1123    {"setSyncParams",     "(Landroid/media/SyncParams;)V",  (void *)android_media_MediaPlayer_setSyncParams},
1124    {"getSyncParams",     "()Landroid/media/SyncParams;",   (void *)android_media_MediaPlayer_getSyncParams},
1125    {"_seekTo",             "(II)V",                            (void *)android_media_MediaPlayer_seekTo},
1126    {"_pause",              "()V",                              (void *)android_media_MediaPlayer_pause},
1127    {"isPlaying",           "()Z",                              (void *)android_media_MediaPlayer_isPlaying},
1128    {"getCurrentPosition",  "()I",                              (void *)android_media_MediaPlayer_getCurrentPosition},
1129    {"getDuration",         "()I",                              (void *)android_media_MediaPlayer_getDuration},
1130    {"_release",            "()V",                              (void *)android_media_MediaPlayer_release},
1131    {"_reset",              "()V",                              (void *)android_media_MediaPlayer_reset},
1132    {"_setAudioStreamType", "(I)V",                             (void *)android_media_MediaPlayer_setAudioStreamType},
1133    {"_getAudioStreamType", "()I",                              (void *)android_media_MediaPlayer_getAudioStreamType},
1134    {"setParameter",        "(ILandroid/os/Parcel;)Z",          (void *)android_media_MediaPlayer_setParameter},
1135    {"setLooping",          "(Z)V",                             (void *)android_media_MediaPlayer_setLooping},
1136    {"isLooping",           "()Z",                              (void *)android_media_MediaPlayer_isLooping},
1137    {"_setVolume",          "(FF)V",                            (void *)android_media_MediaPlayer_setVolume},
1138    {"native_invoke",       "(Landroid/os/Parcel;Landroid/os/Parcel;)I",(void *)android_media_MediaPlayer_invoke},
1139    {"native_setMetadataFilter", "(Landroid/os/Parcel;)I",      (void *)android_media_MediaPlayer_setMetadataFilter},
1140    {"native_getMetadata", "(ZZLandroid/os/Parcel;)Z",          (void *)android_media_MediaPlayer_getMetadata},
1141    {"native_init",         "()V",                              (void *)android_media_MediaPlayer_native_init},
1142    {"native_setup",        "(Ljava/lang/Object;)V",            (void *)android_media_MediaPlayer_native_setup},
1143    {"native_finalize",     "()V",                              (void *)android_media_MediaPlayer_native_finalize},
1144    {"getAudioSessionId",   "()I",                              (void *)android_media_MediaPlayer_get_audio_session_id},
1145    {"setAudioSessionId",   "(I)V",                             (void *)android_media_MediaPlayer_set_audio_session_id},
1146    {"_setAuxEffectSendLevel", "(F)V",                          (void *)android_media_MediaPlayer_setAuxEffectSendLevel},
1147    {"attachAuxEffect",     "(I)V",                             (void *)android_media_MediaPlayer_attachAuxEffect},
1148    {"native_pullBatteryData", "(Landroid/os/Parcel;)I",        (void *)android_media_MediaPlayer_pullBatteryData},
1149    {"native_setRetransmitEndpoint", "(Ljava/lang/String;I)I",  (void *)android_media_MediaPlayer_setRetransmitEndpoint},
1150    {"setNextMediaPlayer",  "(Landroid/media/MediaPlayer;)V",   (void *)android_media_MediaPlayer_setNextMediaPlayer},
1151};
1152
1153// This function only registers the native methods
1154static int register_android_media_MediaPlayer(JNIEnv *env)
1155{
1156    return AndroidRuntime::registerNativeMethods(env,
1157                "android/media/MediaPlayer", gMethods, NELEM(gMethods));
1158}
1159extern int register_android_media_ImageReader(JNIEnv *env);
1160extern int register_android_media_ImageWriter(JNIEnv *env);
1161extern int register_android_media_Crypto(JNIEnv *env);
1162extern int register_android_media_Drm(JNIEnv *env);
1163extern int register_android_media_MediaCodec(JNIEnv *env);
1164extern int register_android_media_MediaExtractor(JNIEnv *env);
1165extern int register_android_media_MediaCodecList(JNIEnv *env);
1166extern int register_android_media_MediaHTTPConnection(JNIEnv *env);
1167extern int register_android_media_MediaMetadataRetriever(JNIEnv *env);
1168extern int register_android_media_MediaMuxer(JNIEnv *env);
1169extern int register_android_media_MediaRecorder(JNIEnv *env);
1170extern int register_android_media_MediaScanner(JNIEnv *env);
1171extern int register_android_media_MediaSync(JNIEnv *env);
1172extern int register_android_media_ResampleInputStream(JNIEnv *env);
1173extern int register_android_media_MediaProfiles(JNIEnv *env);
1174extern int register_android_mtp_MtpDatabase(JNIEnv *env);
1175extern int register_android_mtp_MtpDevice(JNIEnv *env);
1176extern int register_android_mtp_MtpServer(JNIEnv *env);
1177
1178jint JNI_OnLoad(JavaVM* vm, void* /* reserved */)
1179{
1180    JNIEnv* env = NULL;
1181    jint result = -1;
1182
1183    if (vm->GetEnv((void**) &env, JNI_VERSION_1_4) != JNI_OK) {
1184        ALOGE("ERROR: GetEnv failed\n");
1185        goto bail;
1186    }
1187    assert(env != NULL);
1188
1189    if (register_android_media_ImageWriter(env) != JNI_OK) {
1190        ALOGE("ERROR: ImageWriter native registration failed");
1191        goto bail;
1192    }
1193
1194    if (register_android_media_ImageReader(env) < 0) {
1195        ALOGE("ERROR: ImageReader native registration failed");
1196        goto bail;
1197    }
1198
1199    if (register_android_media_MediaPlayer(env) < 0) {
1200        ALOGE("ERROR: MediaPlayer native registration failed\n");
1201        goto bail;
1202    }
1203
1204    if (register_android_media_MediaRecorder(env) < 0) {
1205        ALOGE("ERROR: MediaRecorder native registration failed\n");
1206        goto bail;
1207    }
1208
1209    if (register_android_media_MediaScanner(env) < 0) {
1210        ALOGE("ERROR: MediaScanner native registration failed\n");
1211        goto bail;
1212    }
1213
1214    if (register_android_media_MediaMetadataRetriever(env) < 0) {
1215        ALOGE("ERROR: MediaMetadataRetriever native registration failed\n");
1216        goto bail;
1217    }
1218
1219    if (register_android_media_ResampleInputStream(env) < 0) {
1220        ALOGE("ERROR: ResampleInputStream native registration failed\n");
1221        goto bail;
1222    }
1223
1224    if (register_android_media_MediaProfiles(env) < 0) {
1225        ALOGE("ERROR: MediaProfiles native registration failed");
1226        goto bail;
1227    }
1228
1229    if (register_android_mtp_MtpDatabase(env) < 0) {
1230        ALOGE("ERROR: MtpDatabase native registration failed");
1231        goto bail;
1232    }
1233
1234    if (register_android_mtp_MtpDevice(env) < 0) {
1235        ALOGE("ERROR: MtpDevice native registration failed");
1236        goto bail;
1237    }
1238
1239    if (register_android_mtp_MtpServer(env) < 0) {
1240        ALOGE("ERROR: MtpServer native registration failed");
1241        goto bail;
1242    }
1243
1244    if (register_android_media_MediaCodec(env) < 0) {
1245        ALOGE("ERROR: MediaCodec native registration failed");
1246        goto bail;
1247    }
1248
1249    if (register_android_media_MediaSync(env) < 0) {
1250        ALOGE("ERROR: MediaSync native registration failed");
1251        goto bail;
1252    }
1253
1254    if (register_android_media_MediaExtractor(env) < 0) {
1255        ALOGE("ERROR: MediaCodec native registration failed");
1256        goto bail;
1257    }
1258
1259    if (register_android_media_MediaMuxer(env) < 0) {
1260        ALOGE("ERROR: MediaMuxer native registration failed");
1261        goto bail;
1262    }
1263
1264    if (register_android_media_MediaCodecList(env) < 0) {
1265        ALOGE("ERROR: MediaCodec native registration failed");
1266        goto bail;
1267    }
1268
1269    if (register_android_media_Crypto(env) < 0) {
1270        ALOGE("ERROR: MediaCodec native registration failed");
1271        goto bail;
1272    }
1273
1274    if (register_android_media_Drm(env) < 0) {
1275        ALOGE("ERROR: MediaDrm native registration failed");
1276        goto bail;
1277    }
1278
1279    if (register_android_media_MediaHTTPConnection(env) < 0) {
1280        ALOGE("ERROR: MediaHTTPConnection native registration failed");
1281        goto bail;
1282    }
1283
1284    /* success -- return valid version number */
1285    result = JNI_VERSION_1_4;
1286
1287bail:
1288    return result;
1289}
1290
1291// KTHXBYE
1292