Android13 MediaPlayer start流程分析

我们从MediaPlayer的start方法开始:

//frameworks/base/media/java/android/media/MediaPlayer.java
public class MediaPlayer extends PlayerBase implements SubtitleController.Listener, VolumeAutomation, AudioRouting {
    public void start() throws IllegalStateException {
        //FIXME use lambda to pass startImpl to superclass
        final int delay = getStartDelayMs();
        if (delay == 0) { //如果delay时间为0,直接调用startImpl方法
            startImpl();
        } else { //如果delay不为了,创建一个线程,然后让线程sleep,sleep的时间为delay,然后再调用startImpl方法
            new Thread() {
                public void run() {
                    try {
                        Thread.sleep(delay);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    baseSetStartDelayMs(0);
                    try {
                        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();
        }
    }
}

调用startImpl方法:

//frameworks/base/media/java/android/media/MediaPlayer.java
public class MediaPlayer extends PlayerBase implements SubtitleController.Listener, VolumeAutomation, AudioRouting {
    private void startImpl() {
        baseStart(0); // unknown device at this point
        stayAwake(true); //保持唤醒状态
        tryToEnableNativeRoutingCallback();
        _start();
    }
}

上面方法主要处理如下:

调用baseStart方法,也就是父类PlayerBase的baseStart方法。

调用stayAwake方法,保持电源唤醒状态。

调用_start方法,_start是一个native方法,因此会通过JNI调用android_media_MediaPlayer_start方法。

baseStart

首先是baseStart方法:

//frameworks/base/media/java/android/media/PlayerBase.java
public abstract class PlayerBase {
    void baseStart(int deviceId) {
        if (DEBUG) {
            Log.v(TAG, "baseStart() piid=" + mPlayerIId + " deviceId=" + deviceId);
        }
        updateState(AudioPlaybackConfiguration.PLAYER_STATE_STARTED, deviceId);
    }
}

调用updateState方法:

//frameworks/base/media/java/android/media/PlayerBase.java
public abstract class PlayerBase {
    private void updateState(int state, int deviceId) {
        final int piid;
        synchronized (mLock) {
            mState = state;
            piid = mPlayerIId;
            mDeviceId = deviceId;
        }
        try {
            getService().playerEvent(piid, state, deviceId); //调用getService返回IAudioService接口,调用IAudioService的playerEvent方法
        } catch (RemoteException e) {
            Log.e(TAG, "Error talking to audio service, "
                    + AudioPlaybackConfiguration.toLogFriendlyPlayerState(state)
                    + " state will not be tracked for piid=" + piid, e);
        }
    }
}

调用getService返回IAudioService接口,调用IAudioService的playerEvent方法,IAudioService接口由AudioService实现,因此调用AudioService的playerEvent方法:

待补充

stayAwake

stayAwake用于对屏幕进行操作,首先通过PowerManager的new WakLock(int flags, String tag)来生成WakeLock实例。int flags指示要获取那种WakeLock,不同的锁对CPU、屏幕、键盘灯有不同的影响。

//frameworks/base/media/java/android/media/MediaPlayer.java
public class MediaPlayer extends PlayerBase implements SubtitleController.Listener, VolumeAutomation, AudioRouting {
    private void stayAwake(boolean awake) {
        if (mWakeLock != null) {
            if (awake && !mWakeLock.isHeld()) {
                mWakeLock.acquire();
            } else if (!awake && mWakeLock.isHeld()) {
                mWakeLock.release();
            }
        }
        mStayAwake = awake;
        updateSurfaceScreenOn();
    }
}

调用updateSurfaceScreenOn方法,更新屏幕上的Surface:

//frameworks/base/media/java/android/media/MediaPlayer.java
public class MediaPlayer extends PlayerBase implements SubtitleController.Listener, VolumeAutomation, AudioRouting {
    private void updateSurfaceScreenOn() {
        if (mSurfaceHolder != null) {
            mSurfaceHolder.setKeepScreenOn(mScreenOnWhilePlaying && mStayAwake);
        }
    }
}

_start

_start是一个native方法,因此会通过JNI调用android_media_MediaPlayer_start方法:

//frameworks/base/core/jni/android_media_MediaPlayer.cpp
static void
android_media_MediaPlayer_start(JNIEnv *env, jobject thiz)
{
    ALOGV("start");
    sp<MediaPlayer> mp = getMediaPlayer(env, thiz); //取得getMediaPlayer
    if (mp == NULL ) {
        jniThrowException(env, "java/lang/IllegalStateException", NULL);
        return;
    }
    process_media_player_call( env, thiz, mp->start(), NULL, NULL ); //调用MediaPlayer的start方法,然后将调用结果作成参数再调用process_media_player_call方法进行错误处理(回调)
}

我们先看process_media_player_call方法:

//frameworks/base/core/jni/android_media_MediaPlayer.cpp
static void process_media_player_call(JNIEnv *env, jobject thiz, status_t opStatus, const char* exception, const char *message)
{
    if (exception == NULL) {  // Don't throw exception. Instead, send an event.
        if (opStatus != (status_t) OK) {
            sp<MediaPlayer> mp = getMediaPlayer(env, thiz);
            if (mp != 0) mp->notify(MEDIA_ERROR, opStatus, 0);
        }
    } else {  // Throw exception!
        if ( opStatus == (status_t) INVALID_OPERATION ) {
            jniThrowException(env, "java/lang/IllegalStateException", NULL);
        } else if ( opStatus == (status_t) BAD_VALUE ) {
            jniThrowException(env, "java/lang/IllegalArgumentException", NULL);
        } else if ( opStatus == (status_t) PERMISSION_DENIED ) {
            jniThrowException(env, "java/lang/SecurityException", NULL);
        } else if ( opStatus != (status_t) OK ) {
            if (strlen(message) > 230) {
               // if the message is too long, don't bother displaying the status code
               jniThrowException( env, exception, message);
            } else {
               char msg[256];
                // append the status code to the message
               sprintf(msg, "%s: status=0x%X", message, opStatus);
               jniThrowException( env, exception, msg);
            }
        }
    }
}

我们继续看MediaPlayer的start方法:

sp<IMediaPlayer>            mPlayer;
//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) { //MediaPlayer当前状态是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; //将MediaPlayer的状态设置为MEDIA_PLAYER_STARTED
        ret = mPlayer->start(); //调用IMediaPlayer的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;
}

上面方法主要处理如下:

调用IMediaPlayer的setLooping方法,设置循环或非循环播放。

调用IMediaPlayer的setVolume方法,设置音量。

调用IMediaPlayer的start方法,开始播放。

其中setLooping和setVolume不在这里分析,我们继续分析IMediaPlayer的start方法:

//frameworks/av/media/libmedia/IMediaPlayer.cpp
class BpMediaPlayer: public BpInterface<IMediaPlayer>
{
    status_t start()
    {
        Parcel data, reply;
        data.writeInterfaceToken(IMediaPlayer::getInterfaceDescriptor());
        remote()->transact(START, data, &reply); 
        return reply.readInt32();
    }
}

调用remote()->transact(START, data, &reply);,会在onTransact中处理:

//frameworks/av/media/libmedia/IMediaPlayer.cpp
status_t BnMediaPlayer::onTransact(
    uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
{
    switch (code) {
        case START: {
            CHECK_INTERFACE(IMediaPlayer, data, reply);
            reply->writeInt32(start()); //调用MediaPlayerService::Client的start方法
            return NO_ERROR;
        } break;
    }
}

调用MediaPlayerService的start方法:

Android13 MediaPlayerService start流程分析-CSDN博客

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值