版权声明:本文为博主原创文章,未经博主允许不得转载。
在各层处理消息时都是使用notify将处理的信息返回的。各层都对下一层注册了notify函数。
Java层是处理返回给应用层的消息,postEventFromNative
[java] view plain copy 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); } } 之后将一些消息扔给EventHandler处理。有些是调用app注册的回调函数,如onPrepared,onCompletion,onBufferingUpdate,onSeekComplete等。JNI层首先定义了各种Java层的本地变量和回调函数,MediaPlayer的Java层回调函数使用post_event:
[cpp] view plain copy struct fields_t { jfieldID context; jfieldID surface_texture; jmethodID post_event; jmethodID proxyConfigGetHost; jmethodID proxyConfigGetPort; jmethodID proxyConfigGetExclusionList; }; static fields_t fields; 获取post_event的代码: [cpp] view plain copy jclass clazz; clazz = env->FindClass("android/media/MediaPlayer"); if (clazz == NULL) { return; } 。。。。。。 fields.post_event = env->GetStaticMethodID(clazz, "postEventFromNative", "(Ljava/lang/Object;IIILjava/lang/Object;)V"); if (fields.post_event == NULL) { return; } 那么在什么地方调用它呢?当然是在jni层提供给下层的notify中了 [cpp] view plain copy void JNIMediaPlayerListener::notify(int msg, int ext1, int ext2, const Parcel *obj) { JNIEnv *env = AndroidRuntime::getJNIEnv(); if (obj && obj->dataSize() > 0) { jobject jParcel = createJavaParcelObject(env); if (jParcel != NULL) { Parcel* nativeParcel = parcelForJavaObject(env, jParcel); nativeParcel->setData(obj->data(), obj->dataSize()); env->CallStaticVoidMethod(mClass, fields.post_event, mObject, msg, ext1, ext2, jParcel); env->DeleteLocalRef(jParcel); } } else { env->CallStaticVoidMethod(mClass, <strong>fields.post_event</strong>, mObject, msg, ext1, ext2, NULL); } if (env->ExceptionCheck()) { ALOGW("An exception occurred while notifying an event."); LOGW_EX(env); env->ExceptionClear(); } } 下层注册回调的地方是 [cpp] view plain copy 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) { jniThrowException(env, "java/lang/RuntimeException", "Out of memory"); return; } // create new listener and give it to MediaPlayer sp<JNIMediaPlayerListener> listener = new JNIMediaPlayerListener(env, thiz, weak_this); <strong>mp->setListener(listener)</strong>; // Stow our new C++ MediaPlayer in an opaque field in the Java object. setMediaPlayer(env, thiz, mp); } 继续看MediaPlayer层的setListener [cpp] view plain copy status_t MediaPlayer::setListener(const sp<MediaPlayerListener>& listener) { ALOGV("setListener"); Mutex::Autolock _l(mLock); mListener = listener; return NO_ERROR; } 这层就是将JNI层的JNIMediaPlayerListener赋值给mListener。那么何时调用notify呢?在MediaPlayer给下层的notify中找到了它,同时我们也找到了MediaPlayer给Stagefright层注册的notify回调
[cpp] view plain copy void MediaPlayer::notify(int msg, int ext1, int ext2, const Parcel *obj) { ALOGV("message received msg=%d, ext1=%d, ext2=%d", msg, ext1, ext2); bool send = true; bool locked = false; // TODO: In the future, we might be on the same thread if the app is // running in the same process as the media server. In that case, // this will deadlock. // // The threadId hack below works around this for the care of prepare // and seekTo within the same process. // FIXME: Remember, this is a hack, it's not even a hack that is applied // consistently for all use-cases, this needs to be revisited. if (mLockThreadId != getThreadId()) { mLock.lock(); locked = true; } // Allows calls from JNI in idle state to notify errors if (!(msg == MEDIA_ERROR && mCurrentState == MEDIA_PLAYER_IDLE) && mPlayer == 0) { ALOGV("notify(%d, %d, %d) callback on disconnected mediaplayer", msg, ext1, ext2); if (locked) mLock.unlock(); // release the lock when done. return; } switch (msg) { case MEDIA_NOP: // interface test message break; case MEDIA_PREPARED: ALOGV("prepared"); mCurrentState = MEDIA_PLAYER_PREPARED; if (mPrepareSync) { ALOGV("signal application thread"); mPrepareSync = false; mPrepareStatus = NO_ERROR; mSignal.signal(); } break; case MEDIA_PLAYBACK_COMPLETE: ALOGV("playback complete"); if (mCurrentState == MEDIA_PLAYER_IDLE) { ALOGE("playback complete in idle state"); } if (!mLoop) { mCurrentState = MEDIA_PLAYER_PLAYBACK_COMPLETE; } break; case MEDIA_ERROR: // Always log errors. // ext1: Media framework error code. // ext2: Implementation dependant error code. ALOGE("error (%d, %d)", ext1, ext2); mCurrentState = MEDIA_PLAYER_STATE_ERROR; if (mPrepareSync) { ALOGV("signal application thread"); mPrepareSync = false; mPrepareStatus = ext1; mSignal.signal(); send = false; } break; case MEDIA_INFO: // ext1: Media framework error code. // ext2: Implementation dependant error code. if (ext1 != MEDIA_INFO_VIDEO_TRACK_LAGGING) { ALOGW("info/warning (%d, %d)", ext1, ext2); } break; case MEDIA_SEEK_COMPLETE: ALOGV("Received seek complete"); if (mSeekPosition != mCurrentPosition) { ALOGV("Executing queued seekTo(%d)", mSeekPosition); mSeekPosition = -1; seekTo_l(mCurrentPosition); } else { ALOGV("All seeks complete - return to regularly scheduled program"); mCurrentPosition = mSeekPosition = -1; } break; case MEDIA_BUFFERING_UPDATE: ALOGV("buffering %d", ext1); break; case MEDIA_SET_VIDEO_SIZE: ALOGV("New video size %d x %d", ext1, ext2); mVideoWidth = ext1; mVideoHeight = ext2; break; case MEDIA_TIMED_TEXT: ALOGV("Received timed text message"); break; case MEDIA_SUBTITLE_DATA: ALOGV("Received subtitle data message"); break; default: ALOGV("unrecognized message: (%d, %d, %d)", msg, ext1, ext2); break; } sp<MediaPlayerListener> <strong>listener = mListene</strong>r; if (locked) mLock.unlock(); // this prevents re-entrant calls into client code if ((listener != 0) && send) { Mutex::Autolock _l(mNotifyLock); ALOGV("callback application"); <strong>listener->notify</strong>(msg, ext1, ext2, obj); ALOGV("back from callback"); } } 根据前一篇的分析,MediaPlayer是一个BpMediaPlayer,而调用它的notify的函数肯定在BnMediaPlayer里。BnMediaPlayer是MediaPlayer::Client那么BnMediaPlayer的notify函数里肯定有BpMediaPlayer的notify,继续寻找:
[cpp] view plain copy void MediaPlayerService::Client::notify( void* cookie, int msg, int ext1, int ext2, const Parcel *obj) { Client* client = static_cast<Client*>(cookie); if (client == NULL) { return; } sp<IMediaPlayerClient> c; { Mutex::Autolock l(client->mLock); <strong>c = client->mClient</strong>; if (msg == MEDIA_PLAYBACK_COMPLETE && client->mNextClient != NULL) { if (client->mAudioOutput != NULL) client->mAudioOutput->switchToNextOutput(); client->mNextClient->start(); client->mNextClient->mClient->notify(MEDIA_INFO, MEDIA_INFO_STARTED_AS_NEXT, 0, obj); } } if (MEDIA_INFO == msg && MEDIA_INFO_METADATA_UPDATE == ext1) { const media::Metadata::Type metadata_type = ext2; if(client->shouldDropMetadata(metadata_type)) { return; } // Update the list of metadata that have changed. getMetadata // also access mMetadataUpdated and clears it. client->addNewMetadataUpdate(metadata_type); } if (c != NULL) { ALOGV("[%d] notify (%p, %d, %d, %d)", client->mConnId, cookie, msg, ext1, ext2); <strong>c->notify</strong>(msg, ext1, ext2, obj); } }上面的c代表BpMediaPlayer对象。
这样,MediaPlayerService::Client::notify就是BnMediaPlayer的通知函数了。接着找调用它的位置。再往下找根据前一篇的分析,肯定是要到AwesomePlayer里找,但是我们只在AwesomePlayer里找到了AwesomePlayer::notifyListener_l。
那么究竟是从什么地方注册了MediaPlayerService::Client::notify,又是从什么地方调用它的呢?继续找
我们按照前一篇的思路,从create函数开始找。
[cpp] view plain copy sp<MediaPlayerBase> MediaPlayerService::Client::createPlayer(player_type playerType) { // determine if we have the right player type sp<MediaPlayerBase> p = mPlayer; if ((p != NULL) && (p->playerType() != playerType)) { ALOGV("delete player"); p.clear(); } if (p == NULL) { p = MediaPlayerFactory::createPlayer(playerType, this, <strong><span style="color:#ff0000;">notify</span></strong>); } if (p != NULL) { p->setUID(mUID); } return p; } 一下就找到了MediaPlayerService::Client::notify,继续往下找 [cpp] view plain copy sp<MediaPlayerBase> MediaPlayerFactory::createPlayer( player_type playerType, void* cookie, notify_callback_f <strong>notifyFunc</strong>) { sp<MediaPlayerBase> p; IFactory* factory; status_t init_result; Mutex::Autolock lock_(&sLock); if (sFactoryMap.indexOfKey(playerType) < 0) { ALOGE("Failed to create player object of type %d, no registered" " factory", playerType); return p; } factory = sFactoryMap.valueFor(playerType); CHECK(NULL != factory); p = factory->createPlayer(); if (p == NULL) { ALOGE("Failed to create player object of type %d, create failed", playerType); return p; } init_result = p->initCheck(); if (init_result == NO_ERROR) { <strong><span style="color:#ff0000;">p->setNotifyCallback(cookie, notifyFunc)</span></strong>; } else { ALOGE("Failed to create player object of type %d, initCheck failed" " (res = %d)", playerType, init_result); p.clear(); } return p; } 变量p是MediaPlayerBase类的对象,那么setNotifyCallback就是将MediaPlayerService::Client::notify注册给了它。我们来看看setNotifyCallback函数,很简单,就是赋值
[cpp] view plain copy void setNotifyCallback( void* cookie, notify_callback_f notifyFunc) { Mutex::Autolock autoLock(mNotifyLock); mCookie = cookie; mNotify = notifyFunc; } 终于在MediaPlayerBase类里找到了notify赋值的地方,那么对应的就应该有调用的地方。没错,就在下面的sendEvent
[cpp] view plain copy void sendEvent(int msg, int ext1=0, int ext2=0, const Parcel *obj=NULL) { Mutex::Autolock autoLock(mNotifyLock); if (mNotify) mNotify(mCookie, msg, ext1, ext2, obj); } 而这个sendEvent就是在AwesomePlayer::notifyListener_l里调用的: [cpp] view plain copy void AwesomePlayer::notifyListener_l(int msg, int ext1, int ext2) { if ((mListener != NULL) && !mAudioTearDown) { sp<MediaPlayerBase> listener = mListener.promote(); if (listener != NULL) { listener->sendEvent(msg, ext1, ext2); } } } 看来帅哥为了通知上面的app,也是费尽周折啊。 [cpp] view plain copy AwesomePlayer.cpp: notifyListener_l(MEDIA_PAUSED); AwesomePlayer.cpp: notifyListener_l(MEDIA_PAUSED); AwesomePlayer.cpp: notifyListener_l(MEDIA_PAUSED); AwesomePlayer.cpp: notifyListener_l(MEDIA_SEEK_COMPLETE); AwesomePlayer.cpp: notifyListener_l(MEDIA_SKIPPED); AwesomePlayer.cpp: notifyListener_l(MEDIA_SEEK_COMPLETE); AwesomePlayer.cpp: notifyListener_l(MEDIA_INFO, MEDIA_INFO_RENDERING_START); AwesomePlayer.cpp: notifyListener_l(MEDIA_SEEK_COMPLETE); AwesomePlayer.cpp: notifyListener_l(MEDIA_ERROR, MEDIA_ERROR_UNKNOWN, err); AwesomePlayer.cpp: notifyListener_l(MEDIA_SET_VIDEO_SIZE, 0, 0); AwesomePlayer.cpp: notifyListener_l(MEDIA_PREPARED); AwesomePlayer.cpp: notifyListener_l(MEDIA_INFO, MEDIA_INFO_BUFFERING_END); 这里仅列出一部分通知的调用。