Android Media Player回调事件传递
--- 比如:节目播放完成事件如何回馈到Java应用空间
通过分析回调事件的传递,有助于进一步理解Android Media Player 框架。 (1) setOnCompletionListener(): 应用程序注册回调对象
[MediaPlayer.java]
----------------------------------------------------------------------------------
public interface OnCompletionListener { void onCompletion(MediaPlayer mp); } public void setOnCompletionListener(OnCompletionListener listener) { mOnCompletionListener = listener; } private OnCompletionListener mOnCompletionListener; ---------------------------------------------------------------------------------- 应用程序调用setOnCompletionListener()注册回调对象,该对象的onCompletion()方法在MediaPlayer.EventHandler.handleMessage()中被调用。 ---------------------------------------------------------------------------------- case MEDIA_PLAYBACK_COMPLETE: if (mOnCompletionListener != null) mOnCompletionListener.onCompletion(mMediaPlayer); return; ---------------------------------------------------------------------------------- (2) postEventFromNative(): 传递来自Native的事件 [MediaPlayer.java] ---------------------------------------------------------------------------------- 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 (mp.mEventHandler != null) { Message m = mp.mEventHandler.obtainMessage(what, arg1, arg2, obj); mp.mEventHandler.sendMessage(m); } } ---------------------------------------------------------------------------------- postEventFromNative()是在哪里被调用的呢?应该是Native世界。 (3) env->CallStaticVoidMethod(): 调用postEventFromNative() [android_media_MediaPlayer.cpp] I. android_media_MediaPlayer_native_init(): 记录"postEventFromNative()"方法的ID ----------------------------------------------------------------------------------- android_media_MediaPlayer_native_init(JNIEnv *env) { clazz = env->FindClass("android/media/MediaPlayer"); fields.post_event = env->GetStaticMethodID(clazz, "postEventFromNative", "(Ljava/lang/Object;IIILjava/lang/Object;) V"); } ----------------------------------------------------------------------------------- 该native方法在MediaPlayer.java类第一次被加载时调用。 ----------------------------------------------------------------------------------- [MediaPlayer.java] public class MediaPlayer { ... ... static { System.loadLibrary("media_jni"); native_init(); } ... ... } ----------------------------------------------------------------------------------- II. android_media_MediaPlayer_native_setup(): 创建Native中的MediaPlayer客户端 该native方法在构造MediaPlayer.java对象时被调用, ----------------------------------------------------------------------------------- [MediaPlayer.java] public class MediaPlayer { ... ... public MediaPlayer() { ... ... native_setup(new WeakReference<MediaPlayer>(this)); } ... ... } ----------------------------------------------------------------------------------- 该方法创建Native的MediaPlayer, ----------------------------------------------------------------------------------- static void android_media_MediaPlayer_native_setup(JNIEnv *env, jobject thiz, jobject weak_this) { sp<MediaPlayer> mp = new MediaPlayer(); sp<JNIMediaPlayerListener> listener = new JNIMediaPlayerListener (env, thiz, weak_this); mp->setListener(listener); setMediaPlayer(env, thiz, mp); } ----------------------------------------------------------------------------------- 也就是说MediaPlayer.java构造时,创建了一个Native的MediaPlayer, 该MediaPlayer继承BnMediaPlayerClient,所以可称为 --- 提供Binder服 务的MediaPlayer客户端。也就是说,它本身是MediaPlayer客户端,同 时它也提供Binder服务,估计目的就是使MediaPlayer服务端能回调客户 端的方法。简称Native中的MediaPlayer客户端。 该方法同时设置了listener,该listener的notify()方法会调用 postEventFromNative()。 ----------------------------------------------------------------------------------- void JNIMediaPlayerListener::notify(int msg, int ext1, int ext2, const Parcel *obj) { JNIEnv *env = AndroidRuntime::getJNIEnv(); env->CallStaticVoidMethod(mClass, fields.post_event, mObject, msg, ext1, ext2, NULL); } ----------------------------------------------------------------------------------- III. MediaPlayer::notify(): Native中的MediaPlayer客户端notify()方法 ----------------------------------------------------------------------------------- void MediaPlayer::notify(int msg, int ext1, int ext2, const Parcel *obj) { ... ... mListener->notify(msg, ext1, ext2, obj); } ----------------------------------------------------------------------------------- 所以MediaPlayer::notify()何时被调用? 应该是被BpMediaPlayerClient调用,怎么找到它? IV. MediaPlayer::setDataSource():传出Native中MediaPlayer客户端的代理 ----------------------------------------------------------------------------------- status_t MediaPlayer::setDataSource( const char *url, const KeyedVector<String8, String8> *headers) { const sp<IMediaPlayerService>& service(getMediaPlayerService()); if (service != 0) { sp<IMediaPlayer> player(service->create(getpid(), this, mAudioSessionId)); if (NO_ERROR != player->setDataSource(url, headers)) { player.clear(); } err = attachNewPlayer(player); } return err; } ----------------------------------------------------------------------------------- 这里取得IMediaPlayer的代理端,同时也把IMediaPlayerClient的服务端即BnMediaPlayerClient传递出去。 总结一: MediaPlayer.java对象构造时,创建Native中的MediaPlayer客户端。 setDataSource()方法会取得IMediaPlayer代理端。来自IMediaPlayer的回调通过BpMediaPlayerClient调用到Java空间。 V. BpMediaPlayerClient.notify()被调用 BnMediaPlayerClient通过上面的service->create()传递,该create最后调用(通过binder), ----------------------------------------------------------------------------------- sp<IMediaPlayer> MediaPlayerService::create(pid_t pid, const sp<IMediaPlayerClient>& client, int audioSessionId) { sp<Client> c = new Client( this, pid, connId, client, audioSessionId, IPCThreadState::self()->getCallingUid()); ... ... return c; } ----------------------------------------------------------------------------------- Client的构造函数,记录client到mClient中。client的notify()方法被MediaPlayerService::Client::notify()调用。 VI. setDataSource() 最终创建MeidaPlayerBase ----------------------------------------------------------------------------------- sp<MediaPlayerBase> MediaPlayerService::Client::createPlayer (player_type playerType) { sp<MediaPlayerBase> p = mPlayer; if (p == NULL) { p = android::createPlayer(playerType, this, notify); } return p; } static sp<MediaPlayerBase> createPlayer(player_type playerType, void* cookie, notify_callback_f notifyFunc) { sp<MediaPlayerBase> p; switch (playerType) { case STAGEFRIGHT_PLAYER: LOGV(" create StagefrightPlayer"); p = new StagefrightPlayer; break; case NU_PLAYER: LOGV(" create NuPlayer"); p = new NuPlayerDriver; break; default: LOGE("Unknown player type: %d", playerType); return NULL; } if (p != NULL) { if (p->initCheck() == NO_ERROR) { p->setNotifyCallback(cookie, notifyFunc); } else { p.clear(); } } return p; } ----------------------------------------------------------------------------------- VII. StagefrightPlayer->setNotifyCallback() 记录notifyFunc到mNotify中 VIII. StageFrightPlayer->sendEvent() 最终连锁触发到postEventFromNative() [base\media\libstagefright\awesomePlayer.cpp] void AwesomePlayer::onStreamDone() { ... ... notifyListener_l(MEDIA_PLAYBACK_COMPLETE); } void AwesomePlayer::notifyListener_l(int msg, int ext1, int ext2) { if (mListener != NULL) { sp<MediaPlayerBase> listener = mListener.promote(); if (listener != NULL) { listener->sendEvent(msg, ext1, ext2); } } } 这样整个旧贯通了。 再总结: 1) MediaPlayer.java对象构造,创建Native中的MediaPlayer客户端; setDataSource()方法会取得IMediaPlayer代理端, 即创建了IMediaPlayer的服务端,进而创建如StageFrightPlayer。 回调通过StageFrightPlayer引用BpMediaPlayerClient送给BnMediaPlayerClient,即Native中的MediaPlayer客户端,然后调回java空间。 可惜图片发不了!