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

来源:互联网 发布:知峰保暖内衣价格 编辑:程序博客网 时间:2024/06/09 23:15

在各层处理消息时都是使用notify将处理的信息返回的。各层都对下一层注册了notify函数。

Java层是处理返回给应用层的消息,postEventFromNative

[java] view plain copy
  1. private static void postEventFromNative(Object mediaplayer_ref,  
  2.                                         int what, int arg1, int arg2, Object obj)  
  3. {  
  4.     MediaPlayer mp = (MediaPlayer)((WeakReference)mediaplayer_ref).get();  
  5.     if (mp == null) {  
  6.         return;  
  7.     }  
  8.   
  9.     if (what == MEDIA_INFO && arg1 == MEDIA_INFO_STARTED_AS_NEXT) {  
  10.         // this acquires the wakelock if needed, and sets the client side state  
  11.         mp.start();  
  12.     }  
  13.     if (mp.mEventHandler != null) {  
  14.         Message m = mp.mEventHandler.obtainMessage(what, arg1, arg2, obj);  
  15.         mp.mEventHandler.sendMessage(m);  
  16.     }  
  17. }  
之后将一些消息扔给EventHandler处理。有些是调用app注册的回调函数,如onPrepared,onCompletion,onBufferingUpdate,onSeekComplete等。

JNI层首先定义了各种Java层的本地变量和回调函数,MediaPlayer的Java层回调函数使用post_event:

[cpp] view plain copy
  1. struct fields_t {  
  2.     jfieldID    context;  
  3.     jfieldID    surface_texture;  
  4.   
  5.     jmethodID   post_event;  
  6.   
  7.     jmethodID   proxyConfigGetHost;  
  8.     jmethodID   proxyConfigGetPort;  
  9.     jmethodID   proxyConfigGetExclusionList;  
  10. };  
  11. static fields_t fields;  
获取post_event的代码:

[cpp] view plain copy
  1. jclass clazz;  
  2.   
  3. clazz = env->FindClass("android/media/MediaPlayer");  
  4. if (clazz == NULL) {  
  5.     return;  
  6. }  
  7.   
  8. 。。。。。。  
  9.   
  10. fields.post_event = env->GetStaticMethodID(clazz, "postEventFromNative",  
  11.                                            "(Ljava/lang/Object;IIILjava/lang/Object;)V");  
  12. if (fields.post_event == NULL) {  
  13.     return;  
  14. }  
那么在什么地方调用它呢?当然是在jni层提供给下层的notify中了

[cpp] view plain copy
  1. void JNIMediaPlayerListener::notify(int msg, int ext1, int ext2, const Parcel *obj)  
  2. {  
  3.     JNIEnv *env = AndroidRuntime::getJNIEnv();  
  4.     if (obj && obj->dataSize() > 0) {  
  5.         jobject jParcel = createJavaParcelObject(env);  
  6.         if (jParcel != NULL) {  
  7.             Parcel* nativeParcel = parcelForJavaObject(env, jParcel);  
  8.             nativeParcel->setData(obj->data(), obj->dataSize());  
  9.             env->CallStaticVoidMethod(mClass, fields.post_event, mObject,  
  10.                     msg, ext1, ext2, jParcel);  
  11.             env->DeleteLocalRef(jParcel);  
  12.         }  
  13.     } else {  
  14.         env->CallStaticVoidMethod(mClass, <strong>fields.post_event</strong>, mObject,  
  15.                 msg, ext1, ext2, NULL);  
  16.     }  
  17.     if (env->ExceptionCheck()) {  
  18.         ALOGW("An exception occurred while notifying an event.");  
  19.         LOGW_EX(env);  
  20.         env->ExceptionClear();  
  21.     }  
  22. }  
下层注册回调的地方是

[cpp] view plain copy
  1. static void  
  2. android_media_MediaPlayer_native_setup(JNIEnv *env, jobject thiz, jobject weak_this)  
  3. {  
  4.     ALOGV("native_setup");  
  5.     sp<MediaPlayer> mp = new MediaPlayer();  
  6.     if (mp == NULL) {  
  7.         jniThrowException(env, "java/lang/RuntimeException""Out of memory");  
  8.         return;  
  9.     }  
  10.   
  11.     // create new listener and give it to MediaPlayer  
  12.     sp<JNIMediaPlayerListener> listener = new JNIMediaPlayerListener(env, thiz, weak_this);  
  13.     <strong>mp->setListener(listener)</strong>;  
  14.   
  15.     // Stow our new C++ MediaPlayer in an opaque field in the Java object.  
  16.     setMediaPlayer(env, thiz, mp);  
  17. }  
继续看MediaPlayer层的setListener

[cpp] view plain copy
  1. status_t MediaPlayer::setListener(const sp<MediaPlayerListener>& listener)  
  2. {  
  3.     ALOGV("setListener");  
  4.     Mutex::Autolock _l(mLock);  
  5.     mListener = listener;  
  6.     return NO_ERROR;  
  7. }  
这层就是将JNI层的JNIMediaPlayerListener赋值给mListener。那么何时调用notify呢?

在MediaPlayer给下层的notify中找到了它,同时我们也找到了MediaPlayer给Stagefright层注册的notify回调

[cpp] view plain copy
  1. void MediaPlayer::notify(int msg, int ext1, int ext2, const Parcel *obj)  
  2. {  
  3.     ALOGV("message received msg=%d, ext1=%d, ext2=%d", msg, ext1, ext2);  
  4.     bool send = true;  
  5.     bool locked = false;  
  6.   
  7.     // TODO: In the future, we might be on the same thread if the app is  
  8.     // running in the same process as the media server. In that case,  
  9.     // this will deadlock.  
  10.     //  
  11.     // The threadId hack below works around this for the care of prepare  
  12.     // and seekTo within the same process.  
  13.     // FIXME: Remember, this is a hack, it's not even a hack that is applied  
  14.     // consistently for all use-cases, this needs to be revisited.  
  15.     if (mLockThreadId != getThreadId()) {  
  16.         mLock.lock();  
  17.         locked = true;  
  18.     }  
  19.   
  20.     // Allows calls from JNI in idle state to notify errors  
  21.     if (!(msg == MEDIA_ERROR && mCurrentState == MEDIA_PLAYER_IDLE) && mPlayer == 0) {  
  22.         ALOGV("notify(%d, %d, %d) callback on disconnected mediaplayer", msg, ext1, ext2);  
  23.         if (locked) mLock.unlock();   // release the lock when done.  
  24.         return;  
  25.     }  
  26.   
  27.     switch (msg) {  
  28.     case MEDIA_NOP: // interface test message  
  29.         break;  
  30.     case MEDIA_PREPARED:  
  31.         ALOGV("prepared");  
  32.         mCurrentState = MEDIA_PLAYER_PREPARED;  
  33.         if (mPrepareSync) {  
  34.             ALOGV("signal application thread");  
  35.             mPrepareSync = false;  
  36.             mPrepareStatus = NO_ERROR;  
  37.             mSignal.signal();  
  38.         }  
  39.         break;  
  40.     case MEDIA_PLAYBACK_COMPLETE:  
  41.         ALOGV("playback complete");  
  42.         if (mCurrentState == MEDIA_PLAYER_IDLE) {  
  43.             ALOGE("playback complete in idle state");  
  44.         }  
  45.         if (!mLoop) {  
  46.             mCurrentState = MEDIA_PLAYER_PLAYBACK_COMPLETE;  
  47.         }  
  48.         break;  
  49.     case MEDIA_ERROR:  
  50.         // Always log errors.  
  51.         // ext1: Media framework error code.  
  52.         // ext2: Implementation dependant error code.  
  53.         ALOGE("error (%d, %d)", ext1, ext2);  
  54.         mCurrentState = MEDIA_PLAYER_STATE_ERROR;  
  55.         if (mPrepareSync)  
  56.         {  
  57.             ALOGV("signal application thread");  
  58.             mPrepareSync = false;  
  59.             mPrepareStatus = ext1;  
  60.             mSignal.signal();  
  61.             send = false;  
  62.         }  
  63.         break;  
  64.     case MEDIA_INFO:  
  65.         // ext1: Media framework error code.  
  66.         // ext2: Implementation dependant error code.  
  67.         if (ext1 != MEDIA_INFO_VIDEO_TRACK_LAGGING) {  
  68.             ALOGW("info/warning (%d, %d)", ext1, ext2);  
  69.         }  
  70.         break;  
  71.     case MEDIA_SEEK_COMPLETE:  
  72.         ALOGV("Received seek complete");  
  73.         if (mSeekPosition != mCurrentPosition) {  
  74.             ALOGV("Executing queued seekTo(%d)", mSeekPosition);  
  75.             mSeekPosition = -1;  
  76.             seekTo_l(mCurrentPosition);  
  77.         }  
  78.         else {  
  79.             ALOGV("All seeks complete - return to regularly scheduled program");  
  80.             mCurrentPosition = mSeekPosition = -1;  
  81.         }  
  82.         break;  
  83.     case MEDIA_BUFFERING_UPDATE:  
  84.         ALOGV("buffering %d", ext1);  
  85.         break;  
  86.     case MEDIA_SET_VIDEO_SIZE:  
  87.         ALOGV("New video size %d x %d", ext1, ext2);  
  88.         mVideoWidth = ext1;  
  89.         mVideoHeight = ext2;  
  90.         break;  
  91.     case MEDIA_TIMED_TEXT:  
  92.         ALOGV("Received timed text message");  
  93.         break;  
  94.     case MEDIA_SUBTITLE_DATA:  
  95.         ALOGV("Received subtitle data message");  
  96.         break;  
  97.     default:  
  98.         ALOGV("unrecognized message: (%d, %d, %d)", msg, ext1, ext2);  
  99.         break;  
  100.     }  
  101.   
  102.     sp<MediaPlayerListener> <strong>listener = mListene</strong>r;  
  103.     if (locked) mLock.unlock();  
  104.   
  105.     // this prevents re-entrant calls into client code  
  106.     if ((listener != 0) && send) {  
  107.         Mutex::Autolock _l(mNotifyLock);  
  108.         ALOGV("callback application");  
  109.         <strong>listener->notify</strong>(msg, ext1, ext2, obj);  
  110.         ALOGV("back from callback");  
  111.     }  
  112. }  
根据前一篇的分析,MediaPlayer是一个BpMediaPlayer,而调用它的notify的函数肯定在BnMediaPlayer里。BnMediaPlayer是MediaPlayer::Client

那么BnMediaPlayer的notify函数里肯定有BpMediaPlayer的notify,继续寻找:

[cpp] view plain copy
  1. void MediaPlayerService::Client::notify(  
  2.         void* cookie, int msg, int ext1, int ext2, const Parcel *obj)  
  3. {  
  4.     Client* client = static_cast<Client*>(cookie);  
  5.     if (client == NULL) {  
  6.         return;  
  7.     }  
  8.   
  9.     sp<IMediaPlayerClient> c;  
  10.     {  
  11.         Mutex::Autolock l(client->mLock);  
  12.         <strong>c = client->mClient</strong>;  
  13.         if (msg == MEDIA_PLAYBACK_COMPLETE && client->mNextClient != NULL) {  
  14.             if (client->mAudioOutput != NULL)  
  15.                 client->mAudioOutput->switchToNextOutput();  
  16.             client->mNextClient->start();  
  17.             client->mNextClient->mClient->notify(MEDIA_INFO, MEDIA_INFO_STARTED_AS_NEXT, 0, obj);  
  18.         }  
  19.     }  
  20.   
  21.     if (MEDIA_INFO == msg &&  
  22.         MEDIA_INFO_METADATA_UPDATE == ext1) {  
  23.         const media::Metadata::Type metadata_type = ext2;  
  24.   
  25.         if(client->shouldDropMetadata(metadata_type)) {  
  26.             return;  
  27.         }  
  28.   
  29.         // Update the list of metadata that have changed. getMetadata  
  30.         // also access mMetadataUpdated and clears it.  
  31.         client->addNewMetadataUpdate(metadata_type);  
  32.     }  
  33.   
  34.     if (c != NULL) {  
  35.         ALOGV("[%d] notify (%p, %d, %d, %d)", client->mConnId, cookie, msg, ext1, ext2);  
  36.         <strong>c->notify</strong>(msg, ext1, ext2, obj);  
  37.     }  
  38. }  

上面的c代表BpMediaPlayer对象。

这样,MediaPlayerService::Client::notify就是BnMediaPlayer的通知函数了。接着找调用它的位置。

再往下找根据前一篇的分析,肯定是要到AwesomePlayer里找,但是我们只在AwesomePlayer里找到了AwesomePlayer::notifyListener_l。

那么究竟是从什么地方注册了MediaPlayerService::Client::notify,又是从什么地方调用它的呢?继续找

我们按照前一篇的思路,从create函数开始找。

[cpp] view plain copy
  1. sp<MediaPlayerBase> MediaPlayerService::Client::createPlayer(player_type playerType)  
  2. {  
  3.     // determine if we have the right player type  
  4.     sp<MediaPlayerBase> p = mPlayer;  
  5.     if ((p != NULL) && (p->playerType() != playerType)) {  
  6.         ALOGV("delete player");  
  7.         p.clear();  
  8.     }  
  9.     if (p == NULL) {  
  10.         p = MediaPlayerFactory::createPlayer(playerType, this, <strong><span style="color:#ff0000;">notify</span></strong>);  
  11.     }  
  12.   
  13.     if (p != NULL) {  
  14.         p->setUID(mUID);  
  15.     }  
  16.   
  17.     return p;  
  18. }  
一下就找到了MediaPlayerService::Client::notify,继续往下找

[cpp] view plain copy
  1. sp<MediaPlayerBase> MediaPlayerFactory::createPlayer(  
  2.         player_type playerType,  
  3.         void* cookie,  
  4.         notify_callback_f <strong>notifyFunc</strong>) {  
  5.     sp<MediaPlayerBase> p;  
  6.     IFactory* factory;  
  7.     status_t init_result;  
  8.     Mutex::Autolock lock_(&sLock);  
  9.   
  10.     if (sFactoryMap.indexOfKey(playerType) < 0) {  
  11.         ALOGE("Failed to create player object of type %d, no registered"  
  12.               " factory", playerType);  
  13.         return p;  
  14.     }  
  15.   
  16.     factory = sFactoryMap.valueFor(playerType);  
  17.     CHECK(NULL != factory);  
  18.     p = factory->createPlayer();  
  19.   
  20.     if (p == NULL) {  
  21.         ALOGE("Failed to create player object of type %d, create failed",  
  22.                playerType);  
  23.         return p;  
  24.     }  
  25.   
  26.     init_result = p->initCheck();  
  27.     if (init_result == NO_ERROR) {  
  28.         <strong><span style="color:#ff0000;">p->setNotifyCallback(cookie, notifyFunc)</span></strong>;  
  29.     } else {  
  30.         ALOGE("Failed to create player object of type %d, initCheck failed"  
  31.               " (res = %d)", playerType, init_result);  
  32.         p.clear();  
  33.     }  
  34.   
  35.     return p;  
  36. }  
变量p是MediaPlayerBase类的对象,那么setNotifyCallback就是将MediaPlayerService::Client::notify注册给了它。

我们来看看setNotifyCallback函数,很简单,就是赋值

[cpp] view plain copy
  1. void        setNotifyCallback(  
  2.         void* cookie, notify_callback_f notifyFunc) {  
  3.     Mutex::Autolock autoLock(mNotifyLock);  
  4.     mCookie = cookie; mNotify = notifyFunc;  
  5. }  
终于在MediaPlayerBase类里找到了notify赋值的地方,那么对应的就应该有调用的地方。

没错,就在下面的sendEvent

[cpp] view plain copy
  1. void        sendEvent(int msg, int ext1=0, int ext2=0,  
  2.                       const Parcel *obj=NULL) {  
  3.     Mutex::Autolock autoLock(mNotifyLock);  
  4.     if (mNotify) mNotify(mCookie, msg, ext1, ext2, obj);  
  5. }  
而这个sendEvent就是在AwesomePlayer::notifyListener_l里调用的:

[cpp] view plain copy
  1. void AwesomePlayer::notifyListener_l(int msg, int ext1, int ext2) {  
  2.     if ((mListener != NULL) && !mAudioTearDown) {  
  3.         sp<MediaPlayerBase> listener = mListener.promote();  
  4.   
  5.         if (listener != NULL) {  
  6.             listener->sendEvent(msg, ext1, ext2);  
  7.         }  
  8.     }  
  9. }  
看来帅哥为了通知上面的app,也是费尽周折啊。
[cpp] view plain copy
  1. AwesomePlayer.cpp:            notifyListener_l(MEDIA_PAUSED);  
  2. AwesomePlayer.cpp:    notifyListener_l(MEDIA_PAUSED);  
  3. AwesomePlayer.cpp:        notifyListener_l(MEDIA_PAUSED);  
  4. AwesomePlayer.cpp:        notifyListener_l(MEDIA_SEEK_COMPLETE);  
  5. AwesomePlayer.cpp:        notifyListener_l(MEDIA_SKIPPED);  
  6. AwesomePlayer.cpp:        notifyListener_l(MEDIA_SEEK_COMPLETE);  
  7. AwesomePlayer.cpp:            notifyListener_l(MEDIA_INFO, MEDIA_INFO_RENDERING_START);  
  8. AwesomePlayer.cpp:            notifyListener_l(MEDIA_SEEK_COMPLETE);  
  9. AwesomePlayer.cpp:        notifyListener_l(MEDIA_ERROR, MEDIA_ERROR_UNKNOWN, err);  
  10. AwesomePlayer.cpp:            notifyListener_l(MEDIA_SET_VIDEO_SIZE, 0, 0);  
  11. AwesomePlayer.cpp:        notifyListener_l(MEDIA_PREPARED);  
  12. AwesomePlayer.cpp:                notifyListener_l(MEDIA_INFO, MEDIA_INFO_BUFFERING_END);  
这里仅列出一部分通知的调用。
原创粉丝点击