栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

MediaPlayer的消息机制分析

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

MediaPlayer的消息机制分析

一、引子:
先贴一段log:

08-18 21:57:20.110 11775 11812 V MediaPlayer: resetDrmState:  mDrmInfo=null mDrmProvisioningThread=null mPrepareDrmInProgress=false mActiveDrmScheme=false
08-18 21:57:20.110 11775 11775 E MediaPlayerNative: error (-38, 0)
08-18 21:57:20.110  3206  3206 D MTK_KL  : 4,60541,9379664038,-;[MI_AUDIO_Stop:8901][3079] u32ErrCode:0x0
08-18 21:57:20.110  3206  3206 D MTK_KL  : 4,60542,9379664153,-;[_MI_AOUT_NotifyDisconnectInput:7948][3079] hAoutImpl:0x17000002, hInputImpl:0x19000000
08-18 21:57:20.110  3206  3206 D MTK_KL  : 4,60543,9379664175,-;[_MI_AOUT_SetMultiMute:2794][3079] ePath:2, pszMuteName:_MI_AOUT_NotifyDisconnectInput, bMute:1, u32AutoUnmuteTimer:246, u32AoutMuteFlag:0x3
08-18 21:57:20.110 11775 11812 V MediaPlayer: cleanDrmObj: mDrmObj=null mDrmSessionId=null
08-18 21:57:20.110 11775 11775 E MediaPlayer: Error (-38,0)
08-18 21:57:20.110 11775 11812 V MediaPlayer: resetDrmState:  mDrmInfo=null mDrmProvisioningThread=null mPrepareDrmInProgress=false mActiveDrmScheme=false
08-18 21:57:20.110 11775 11812 V MediaPlayer: cleanDrmObj: mDrmObj=null mDrmSessionId=null

经常处理媒体问题的朋友肯定遇到过上述log中的打印,实际上,这是Android原生MediaPlayer的消息回调机制。将底层的error/info/waring回调至应用层,而往往出现问题的时候,我们想要确认是哪个消息出现的问题却无从下手,这就需要真正理解这个消息机制才行,实际上,我们只需要关注三个点:listener、post event 和 notify。这三者的作用是:注册监听器给下层,下层调用监听器发送回调事件,上层处理该消息,而伴随着binder机制,这三者并不是在framework层代码中成对存在的,下面就对这三者依次进行分析。

二、Java(framework)->JNI:
先看看Java层是如何接收到消息的:JNI层利用Java层反射机制调用至Java层。

notify@ frameworksbasemediajniandroid_media_MediaPlayer.cpp

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, fields.post_event, mObject,
                msg, ext1, ext2, NULL);
    }
    if (env->ExceptionCheck()) {
        ALOGW("An exception occurred while notifying an event.");
        LOGW_EX(env);
        env->ExceptionClear();
    }
}

看一下fields.post_event是什么:

    fields.post_event = env->GetStaticMethodID(clazz, "postEventFromNative",
                                               "(Ljava/lang/Object;IIILjava/lang/Object;)V");

对应的是MediaPlayer.java中的postEventFromNative方法:

postEventFromNative@ frameworksbasemediajavaandroidmediaMediaPlayer.java

private static void postEventFromNative(Object mediaplayer_ref,
                                        int what, int arg1, int arg2, Object obj)
{
	...
    if (mp.mEventHandler != null) {
       Message m = mp.mEventHandler.obtainMessage(what, arg1, arg2, obj);
       
       mp.mEventHandler.sendMessage(m);
   }
}

继续跟进:

public void handleMessage(Message msg) {
	...
	switch(msg.what) {
            case MEDIA_PREPARED:
				...
			    onPreparedListener onPreparedListener = mOnPreparedListener;
                if (onPreparedListener != null)
                	
                    onPreparedListener.onPrepared(mMediaPlayer);
                return;
	}
}

可以看到,mediaplayer.java中可以注册非常多的listener,mediaplayer.java会调用这些listener的回调函数至apk,完成应用需要的操作。

三、JNI->mediaplayer.cpp:
先看listener的注册:

static void
android_media_MediaPlayer_native_setup(JNIEnv *env, jobject thiz, jobject weak_this)
{
    ALOGV("native_setup");
    
    sp mp = new MediaPlayer();
    if (mp == NULL) {
        jniThrowException(env, "java/lang/RuntimeException", "Out of memory");
        return;
    }

	
    // create new listener and give it to MediaPlayer
    sp listener = new JNIMediaPlayerListener(env, thiz, weak_this);
    mp->setListener(listener);

    // Stow our new C++ MediaPlayer in an opaque field in the Java object.
    setMediaPlayer(env, thiz, mp);
}

可以看到,JNI层自己创建了一个listener并设置到下层中。下面看一下mediaplayer.cpp的处理:

void MediaPlayer::notify(int msg, int ext1, int ext2, const Parcel *obj)
{
	...
	
	sp listener = mListener;
    if (locked) mLock.unlock();

    // this prevents re-entrant calls into client code
    if ((listener != 0) && send) {
        Mutex::Autolock _l(mNotifyLock);
        ALOGV("callback application");
        
        listener->notify(msg, ext1, ext2, obj);
        ALOGV("back from callback");
    }
}

四、mediaplayer.cpp(Bp)->mediaplayerservice(Bn):
这里就告诉了我们上面的notify是何时调用的,答案而是直接从Bn端的notify中回调上来的:

client::notify@ frameworksavmedialibmediaplayerserviceMediaPlayerService.cpp

void MediaPlayerService::Client::notify(
        int msg, int ext1, int ext2, const Parcel *obj)
{
	...
	
	if (c != NULL) {
        ALOGV("[%d] notify (%d, %d, %d)", mConnId, msg, ext1, ext2);
        c->notify(msg, ext1, ext2, obj);
    }
}

五、mediaplayerservice(Bn)->底层播放器:
首先Bn端需要有一个listener,在MediaPlayerService::Client::Client构造函数中:

MediaPlayerService::Client::Client(
        const sp& service, pid_t pid,
        int32_t connId, const sp& client,
        audio_session_t audioSessionId, uid_t uid)
{
	...
	mListener = new Listener(this);
	...
}

这里会构建一个listener,这个listener拿来是注册到底层播放器中的,什么时候注册的?来看
MediaPlayerService::Client::createPlayer:

sp MediaPlayerService::Client::createPlayer(player_type playerType)
{
    // determine if we have the right player type
    sp p = getPlayer();
    if ((p != NULL) && (p->playerType() != playerType)) {
        ALOGV("delete player");
        p.clear();
    }
    if (p == NULL) {
    	
        p = MediaPlayerFactory::createPlayer(playerType, mListener, mPid);
    }

    if (p != NULL) {
        p->setUID(mUid);
    }

    return p;
}

跟进下createPlayer:

createPlayer@ frameworksavmedialibmediaplayerserviceMediaPlayerFactory.cpp:

sp MediaPlayerFactory::createPlayer(
        player_type playerType,
        const sp &listener,
        pid_t pid) {
		...
		
		p = factory->createPlayer(pid);
		...
		init_result = p->initCheck();
    	if (init_result == NO_ERROR) {
    		
        	p->setNotifyCallback(listener);
    	} else {
        	ALOGE("Failed to create player object of type %d, initCheck failed"
              " (res = %d)", playerType, init_result);
        p.clear();
        ...
    }
}

继续往下跟进,MediaPlayerbase在MediaPlayerInterface.h中:

setNotifyCallback@frameworksavmedialibmediaplayerserviceincludeMediaPlayerInterface.h:

void        setNotifyCallback(
        const sp &listener) {
    Mutex::Autolock autoLock(mNotifyLock);
    mListener = listener;
}

这里需要注意一下继承关系,mstplayer: MediaPlayerInterface: MediaPlayerbase,所以Bn端的这个listener会一路注册到底层的播放器中,之后,底层播放器就会调用sendevent将消息返回上来了:

void        sendEvent(int msg, int ext1=0, int ext2=0,
                      const Parcel *obj=NULL) {
    sp listener;
    {
        Mutex::Autolock autoLock(mNotifyLock);
        listener = mListener;
    }

    if (listener != NULL) {
    	
        listener->notify(msg, ext1, ext2, obj);
    }
}

六、总结:

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/305858.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号