在各层处理消息时都是使用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 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
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);
这里仅列出一部分通知的调用。