MediaPlayer代码分析(2)-处理返回机制Notify
来源:互联网 发布:java周末班 编辑:程序博客网 时间:2024/05/16 11:21
在各层处理消息时都是使用notify将处理的信息返回的。各层都对下一层注册了notify函数。
Java层是处理返回给应用层的消息,postEventFromNative
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:
struct fields_t { jfieldID context; jfieldID surface_texture; jmethodID post_event; jmethodID proxyConfigGetHost; jmethodID proxyConfigGetPort; jmethodID proxyConfigGetExclusionList;};static fields_t fields;获取post_event的代码:
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中了
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(); }}下层注册回调的地方是
static voidandroid_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
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回调
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,继续寻找:
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函数开始找。
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,继续往下找
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函数,很简单,就是赋值
void setNotifyCallback( void* cookie, notify_callback_f notifyFunc) { Mutex::Autolock autoLock(mNotifyLock); mCookie = cookie; mNotify = notifyFunc; }终于在MediaPlayerBase类里找到了notify赋值的地方,那么对应的就应该有调用的地方。
没错,就在下面的sendEvent
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里调用的:
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,也是费尽周折啊。
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);这里仅列出一部分通知的调用。
0 0
- MediaPlayer代码分析(2)-处理返回机制Notify
- MediaPlayer代码分析(2)-处理返回机制Notify
- MediaPlayer的notify监听机制
- android4.0 MediaPlayer的notify监听机制的全面剖析
- android4.0 MediaPlayer的notify监听机制的全面剖析
- android4.0 MediaPlayer的notify监听机制的全面剖析
- android4.0 MediaPlayer的notify监听机制的全面剖析
- android4.0 MediaPlayer的notify监听机制的全面剖析
- android4.0 MediaPlayer的notify监听机制的全面剖析
- android4.0 MediaPlayer的notify监听机制的全面剖析
- android4.0 MediaPlayer的notify监听机制的全面剖析
- [转]android4.0 MediaPlayer的notify监听机制的全面剖析
- notify和notifyAll的一段代码分析
- notify机制
- mediaplayer分析
- android binder机制分析 以MediaPlayer为例子
- android binder机制分析 以MediaPlayer为例子
- Android binder机制分析-以MediaPlayer为例子
- 关于oracle插入clob数据类型的问题
- 《Linux内核设计与实现》——虚拟文件系统
- ECharts使用例子
- Soft Knee (Compression)
- 算法--判断一个数字序列是否为二叉排序树的后续遍历
- MediaPlayer代码分析(2)-处理返回机制Notify
- VB.net 对MSSQL操作 查、删、改 三个常规操作
- less和sass的区别
- 第十三周项目一 数组的大折腾(5)
- PHP验证登录用户名和密码
- 清空mstsc远程桌面连接保存的密码
- 【c#】第一讲:概述和规则
- android分页查询垃圾短信数据库信息
- Qt SQLite事务