在使用java层MediaPlayer去播放一个音视频文件时,经常需要获取各种通知.具体体现在代码中就是注册各种监听器来获取事件通知.
例如:
MediaPlayer player = new MediaPlayer();
player.setDataSource("rtsp://10.0.149.217:554/stream1");
player.prepareAsync();
player.setOnPreparedListener(new OnPreparedListener () {
public void onPrepared(MediaPlayer mp) {
}
});
player.setOnInfoListener(new OnInfoListener() {
public boolean onInfo(MediaPlayer mp, int what, int extra) {
}
});
player.start();
例如上面代码中就注册了两种监听器OnPreparedListener和OnInfoListener,前一个监听器用于当播放器准备完成后获取通知,后一个用于通知各种消息.当然MediaPlayer中还定义了其它几种监听器.我们以OnPreparedListener为例来分析,要获取准备完成通知消息,必须要设置准备完成监听器,即调用方法setOnPreparedListener(),它的代码实现如下:
public void setOnPreparedListener(OnPreparedListener listener)
{
mOnPreparedListener = listener;
}
也就是保存到java层MediaPlayer对象的mOnPreparedListener成员中.
MediaPlayer类中定义了一个嵌套类EventHandler,用于处理Handler消息,它的部分代码如下:
private class EventHandler extends Handler
{
private MediaPlayer mMediaPlayer;
public EventHandler(MediaPlayer mp, Looper looper) {
super(looper);
mMediaPlayer = mp;
}
@Override
public void handleMessage(Message msg) {
if (mMediaPlayer.mNativeContext == 0) {
Log.w(TAG, "mediaplayer went away with unhandled events");
return;
}
switch(msg.what) {
case MEDIA_PREPARED:
scanInternalSubtitleTracks();
if (mOnPreparedListener != null)
mOnPreparedListener.onPrepared(mMediaPlayer);
return;
.......//
}
从代码中可以看到,当收到Handler消息MEDIA_PREPARED时,就会调用 mOnPreparedListener.onPrepared(mMediaPlayer);
那么这个消息是被谁发送的呢,在MediaPlayer中有一个方法postEventFromNative(),它用于发送Handler消息,但是我们在MediaPlayer.java中找不到postEventFromNative()这个方法的调用者,因此最可能是被native层MediaPlayer来调用.
private static void postEventFromNative(Object mediaplayer_ref,
int what, int arg1, int arg2, Object obj)
{
MediaPlayer mp = (MediaPlayer)((WeakReference)mediaplayer_ref).get();
if (mp == null) {
return;
}
if (what == MEDIA_INFO && arg1 == MEDIA_INFO_STARTED_AS_NEXT) {
// this acquires the wakelock if needed, and sets the client side state
mp.start();
}
if (mp.mEventHandler != null) {
Message m = mp.mEventHandler.obtainMessage(what, arg1, arg2, obj);
mp.mEventHandler.sendMessage(m);
}
}
我们在前面分析过,创建一个java层的MeidaPlayer对象时,它的构造函数中会调用native_setup方法,它对应的jni实现如下:
android_media_Mediaplayer.cpp中的方法如下:
static void
android_media_MediaPlayer_native_setup(JNIEnv *env, jobject thiz, jobject weak_this)
{
ALOGV("native_setup");
sp<MediaPlayer> mp = new MediaPlayer();
if (mp == NULL) {