MediaPlayer代码分析(2)-处理返回机制Notify

xiaoxiao2021-02-28  111

在各层处理消息时都是使用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);   这里仅列出一部分通知的调用。
转载请注明原文地址: https://www.6miu.com/read-43723.html

最新回复(0)