Android MediaPlayer 源码分析(四) —— prepare和start流程

830 阅读4分钟

前言

前文中分析了MediaPlayer的设置数据源和设置显示控件的流程,那么完成这些设置流程以后,MediaPlayer还需要一个prepare即数据准备的流程才能进行播放。

MediaPlayer提供了两个数据准备的方法,prepareAsync和prepare。

//同步prepare
mMediaPlayer.prepare();

//设置prepareAsync回调
mMediaPlayer.setOnPreparedListener(mOnPreparedListener);
//异步prepare
mMediaPlayer.prepareAsync();

prepareAsync和prepare 两者的流程基本一致,而prepareAsync可以通过setOnPreparedListener方法设置一个回调,最终调用onPrepared方法通知APP prepare流程执行完成。

完成数据准备工作之后,就可以开始播放了。

mMediaPlayer.start();

prepareAsync流程分析

首先来分析一下MediaPlayer.java的prepareAsync方法,prepareAsync就是一个native方法,直接调用到Jni层。

// frameworks/base/media/java/android/media/MediaPlayer.java

public native void prepareAsync() throws IllegalStateException;

通过Jni的动态注册, prepareAsync调用到android_media_MediaPlayer_prepareAsync方法

// frameworks/base/media/jni/android_media_MediaPlayer.cpp

static void
android_media_MediaPlayer_prepareAsync(JNIEnv *env, jobject thiz)
{   
    // 获取之前缓存的C++层的MediaPlayer对象
    sp<MediaPlayer> mp = getMediaPlayer(env, thiz);
    if (mp == NULL ) {
        jniThrowException(env, "java/lang/IllegalStateException", NULL);
        return;
    }

    // Handle the case where the display surface was set before the mp was
    // initialized. We try again to make it stick.
    // 再次设置显示控件
    sp<IGraphicBufferProducer> st = getVideoSurfaceTexture(env, thiz);
    mp->setVideoSurfaceTexture(st);
    
    // mp->prepareAsync() 调用C++层MediaPlayer的prepareAsync方法, 如果异常则通过process_media_player_call抛给Java层处理
    process_media_player_call( env, thiz, mp->prepareAsync(), "java/io/IOException", "Prepare Async failed." );
}

再来分析MediaPlayer.cpp中的prepareAsync方法

// frameworks/av/media/libmedia/mediaplayer.cpp

status_t MediaPlayer::prepareAsync()
{
    ALOGV("prepareAsync");
    //加锁操作
    Mutex::Autolock _l(mLock);
    return prepareAsync_l();
}

// must call with lock held
status_t MediaPlayer::prepareAsync_l()
{
    // 判断当前状态是否是INITIALIZED或STOP状态
    if ( (mPlayer != 0) && ( mCurrentState & (MEDIA_PLAYER_INITIALIZED | MEDIA_PLAYER_STOPPED) ) ) {
        if (mAudioAttributesParcel != NULL) {
            // 设置音频属性参数
            mPlayer->setParameter(KEY_PARAMETER_AUDIO_ATTRIBUTES, *mAudioAttributesParcel);
        } else {
            // 设置音频流类型信息
            mPlayer->setAudioStreamType(mStreamType);
        }
        // 设置当前状态为正在prepare流程状态
        mCurrentState = MEDIA_PLAYER_PREPARING;
        // 调用IMediaPlayer的prepareAsync方法
        return mPlayer->prepareAsync();
    }
    ALOGE("prepareAsync called in state %d, mPlayer(%p)", mCurrentState, mPlayer.get());
    return INVALID_OPERATION;
}

上面代码可以看出,prepareAsync方法最终还是会通过IMediaPlayer对象,最终调用到MediaPlayerService中的播放器对象的prepareAsync,这一部分我们在分析MediaPlayerService和播放器的源码时再详细分析。

到这里,我们客户端的MediaPlayer的prepare流程就完成了,那么它又是如何接收到prepare流程的回调通知呢?

其实我们在第一篇文章中就已经分析了这一部分流程,简单来说就是,MediaPlayerService通过IMediaPlayerClient对象持有客户端的MediaPlayer.cpp对象的接口代理对象,通过notify方法来给客户端发送消息。

而客户端接收到消息以后,最终通过 MediaPlayer.cpp —> android_media_MediaPlayer.cpp —> MediaPlayer.java 一层一层向上传给给APP端。

start流程分析

当所有准备工作都已经就绪以后,MediaPlayer的状态应当为MEDIA_PLAYER_PREPARED,此时我们就可以开始播放了。

// frameworks/base/media/java/android/media/MediaPlayer.java

    public void start() throws IllegalStateException {
        //FIXME use lambda to pass startImpl to superclass
        //获取延时事件
        final int delay = getStartDelayMs();
        if (delay == 0) {
            //不需要延时,直接start
            startImpl();
        } else {
            new Thread() {
                public void run() {
                    //休眠延时时间
                    try {
                        Thread.sleep(delay);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    //重置延时时间
                    baseSetStartDelayMs(0);
                    try {
                        //开始start
                        startImpl();
                    } catch (IllegalStateException e) {
                        // fail silently for a state exception when it is happening after
                        // a delayed start, as the player state could have changed between the
                        // call to start() and the execution of startImpl()
                    }
                }
            }.start();
        }
    }

    private void startImpl() {
        //更新播放状态
        baseStart();
        //唤醒锁处理
        stayAwake(true);
        //调用JNI层的start
        _start();
    }
    
    private native void _start() throws IllegalStateException;

上面代码可以看到,start之前,需要先处理休眠时间、更新播放状态、唤醒锁处理,最后才调用到JNI层的_start()。

// frameworks/base/media/jni/android_media_MediaPlayer.cpp

static void
android_media_MediaPlayer_start(JNIEnv *env, jobject thiz)
{
    ALOGV("start");
    // 获取之前缓存的C++层的MediaPlayer对象
    sp<MediaPlayer> mp = getMediaPlayer(env, thiz);
    if (mp == NULL ) {
        jniThrowException(env, "java/lang/IllegalStateException", NULL);
        return;
    }
    // mp->start() 调用C++层MediaPlayer的start方法, 如果异常则通过process_media_player_call抛给Java层处理
    process_media_player_call( env, thiz, mp->start(), NULL, NULL );
}

与之前的几个步骤基本相同,先获取创建好的C++层的MediaPlayer对象,再调用它的start()方法,如果异常则通过process_media_player_call抛给Java层处理。

// frameworks/av/media/libmedia/mediaplayer.cpp

status_t MediaPlayer::start()
{
    ALOGV("start");
    //加锁操作
    status_t ret = NO_ERROR;
    Mutex::Autolock _l(mLock);

    mLockThreadId = getThreadId();

    if (mCurrentState & MEDIA_PLAYER_STARTED) {
        ret = NO_ERROR;
    // 如果当前状态 
    } else if ( (mPlayer != 0) && ( mCurrentState & ( MEDIA_PLAYER_PREPARED |
                    MEDIA_PLAYER_PLAYBACK_COMPLETE | MEDIA_PLAYER_PAUSED ) ) ) {
        mPlayer->setLooping(mLoop);
        //设置左右声的音量
        mPlayer->setVolume(mLeftVolume, mRightVolume);
        //设置音效增益等级
        mPlayer->setAuxEffectSendLevel(mSendLevel);
        //设置当前状态为开始播放状态
        mCurrentState = MEDIA_PLAYER_STARTED;
        //调用IMediaPlayer的start方法
        ret = mPlayer->start();
        if (ret != NO_ERROR) {
            mCurrentState = MEDIA_PLAYER_STATE_ERROR;
        } else {
            if (mCurrentState == MEDIA_PLAYER_PLAYBACK_COMPLETE) {
                ALOGV("playback completed immediately following start()");
            }
        }
    } else {
        ALOGE("start called in state %d, mPlayer(%p)", mCurrentState, mPlayer.get());
        ret = INVALID_OPERATION;
    }

    mLockThreadId = 0;

    return ret;
}

与之前几个步骤相同,start方法最终也是会通过IMediaPlayer对象,调用到MediaPlayerService中的播放器对象的start。

到此,MediaPlayer的播放流程基本上分析完成。