Android多媒体深入学习之Audio1----MediaPlayer

Android多媒体深入学习之Audio1----MediaPlayer

  • NOTE
  • 一、 环境说明
  • 二、 APK
  • 三、 MediaPlayer.create分析
    • 3.1 init
      • 3.1.1 framework-java
      • 3.1.2 framework-jni
      • 3.1.3 framework-library
    • 3.2 setDataSource
      • 3.2.1 framework-java
      • 3.2.2 framework-jni
      • 3.2.3 framework-library
    • 3.3 prepare
      • 3.3.1 framework-java
      • 3.3.2 framework-jni
    • 3.4 start
      • 3.4.1 framework-java
      • 3.4.2 framework-jni
      • 3.4.3 framework-library
  • 四、 参考

NOTE

以下为笔记,如有错误请指正。


一、 环境说明

基于android-9.0.0_r46(aosp)


二、 APK

创建一个简单的APK,播放本地音乐。

使用MediaPlayer播放一个Audio

        if (mPlayer == null) {
            mPlayer = MediaPlayer.create(getContext(), R.raw.lang);
        }
        mPlayer.start();

create方式不需要prepare


三、 MediaPlayer.create分析

3.1 init

3.1.1 framework-java

APK中使用 MediaPlayer.create(…) 创建player示例,所以进入MediaPlayer分析:

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

通过log发现调用的是:

    public static MediaPlayer create(Context context, int resid) {
        int s = AudioSystem.newAudioSessionId();
        return create(context, resid, null, s > 0 ? s : 0);
    }

上文中函数int s = AudioSystem.newAudioSessionId();,通过 base/media/java/android/media/AudioSystem.java 中的public static native int newAudioSessionId();调用 base/core/jni/android_media_AudioSystem.cpp 中的newAudioSessionId函数。

继续往下:

    public static MediaPlayer create(Context context, int resid, AudioAttributes audioAttributes, int audioSessionId) {
        try {
            AssetFileDescriptor afd = context.getResources().openRawResourceFd(resid);
            if (afd == null) return null;

            MediaPlayer mp = new MediaPlayer();

            final AudioAttributes aa = audioAttributes != null ? audioAttributes :
                new AudioAttributes.Builder().build();
            mp.setAudioAttributes(aa);
            mp.setAudioSessionId(audioSessionId);

            mp.setDataSource(afd.getFileDescriptor(), afd.getStartOffset(), afd.getLength());
            afd.close();
            mp.prepare();
            return mp;
        } 
        ...
        return null;
    }

其中有初始化对象MediaPlayer mp = new MediaPlayer()动作:

    public MediaPlayer() {
        super(new AudioAttributes.Builder().build(),
                AudioPlaybackConfiguration.PLAYER_TYPE_JAM_MEDIAPLAYER);

        Looper looper;
        if ((looper = Looper.myLooper()) != null) {
            mEventHandler = new EventHandler(this, looper);
        } else if ((looper = Looper.getMainLooper()) != null) {
            mEventHandler = new EventHandler(this, looper);
        } else {
            mEventHandler = null;
        }

        mTimeProvider = new TimeProvider(this);
        mOpenSubtitleSources = new Vector<InputStream>();

        /* Native setup requires a weak reference to our object.
         * It's easier to create it here than in C++.
         */
        native_setup(new WeakReference<MediaPlayer>(this)); // native 方法

        baseRegisterPlayer();
    }

既然natvie_setup() 是 native方法,那么肯定有.so库的加载:

    static {
        System.loadLibrary("media_jni");
        native_init();
    }

3.1.2 framework-jni

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

查资料得知,System.loadLibrary("…") 的时候会调用 JNI_OnLoad() 函数:

参考:

  1. JNI_OnLoad调用时机
  2. JNI_OnLoad和JNI_OnUnload
jint JNI_OnLoad(JavaVM* vm, void* /* reserved */)
{
    JNIEnv* env = NULL;
    jint result = -1;

    if (vm->GetEnv((void**) &env, JNI_VERSION_1_4) != JNI_OK) {
        ALOGE("ERROR: GetEnv failed\n");
        goto bail;
    }
    assert(env != NULL);

    if (register_android_media_ImageWriter(env) != JNI_OK) {
        ALOGE("ERROR: ImageWriter native registration failed");
        goto bail;
    }

    ...... //initialize

    /* success -- return valid version number */
    result = JNI_VERSION_1_4;

bail:
    return result;
}

继续往下走会调用native_init()方法:

    {"native_init",         "()V",                              (void *)android_media_MediaPlayer_native_init},

// This function gets some field IDs, which in turn causes class initialization.
// It is called from a static block in MediaPlayer, which won't run until the
// first time an instance of this class is used.
static void
android_media_MediaPlayer_native_init(JNIEnv *env)
{
    jclass clazz;
    ...... // Initialization of some variables
    gBufferingParamsFields.init(env);

    // Modular DRM
    FIND_CLASS(clazz, "android/media/MediaDrm$MediaDrmStateException");
    if (clazz) {
        GET_METHOD_ID(gStateExceptionFields.init, clazz, "", "(ILjava/lang/String;)V");
        gStateExceptionFields.classId = static_cast<jclass>(env->NewGlobalRef(clazz));

        env->DeleteLocalRef(clazz);
    } else {
        ALOGE("JNI android_media_MediaPlayer_native_init couldn't "
              "get clazz android/media/MediaDrm$MediaDrmStateException");
    }

    gPlaybackParamsFields.init(env);
    gSyncParamsFields.init(env);
    gVolumeShaperFields.init(env);
}

native_init运行完成,回到 native_setup(…) 中:

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);
    mp->setListener(listener);

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

其中初始化MediaPlayer对象 sp mp = new MediaPlayer(); 调用的是:

3.1.3 framework-library

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

MediaPlayer::MediaPlayer()
{
    ALOGV("constructor");
    mListener = NULL;
    mCookie = NULL;
    mStreamType = AUDIO_STREAM_MUSIC;
    mAudioAttributesParcel = NULL;
    mCurrentPosition = -1;
    mCurrentSeekMode = MediaPlayerSeekMode::SEEK_PREVIOUS_SYNC;
    mSeekPosition = -1;
    mSeekMode = MediaPlayerSeekMode::SEEK_PREVIOUS_SYNC;
    mCurrentState = MEDIA_PLAYER_IDLE;
    mPrepareSync = false;
    mPrepareStatus = NO_ERROR;
    mLoop = false;
    mLeftVolume = mRightVolume = 1.0;
    mVideoWidth = mVideoHeight = 0;
    mLockThreadId = 0;
    mAudioSessionId = (audio_session_t) AudioSystem::newAudioUniqueId(AUDIO_UNIQUE_ID_USE_SESSION);
    AudioSystem::acquireAudioSessionId(mAudioSessionId, -1);
    mSendLevel = 0;
    mRetransmitEndpointValid = false;
}

至此,初始化动作基本完成。

3.2 setDataSource

3.2.1 framework-java

回到MediaPlayer.create函数中,调用了 mp.setDataSource(…),即:

    public void setDataSource(FileDescriptor fd, long offset, long length)
            throws IOException, IllegalArgumentException, IllegalStateException {
        _setDataSource(fd, offset, length); //是个native方法
    }
    
    private native void _setDataSource(FileDescriptor fd, long offset, long length)
            throws IOException, IllegalArgumentException, IllegalStateException;

3.2.2 framework-jni

然后在 android_media_MediaPlayer.cpp :

{"_setDataSource",      "(Ljava/io/FileDescriptor;JJ)V",    (void *)android_media_MediaPlayer_setDataSourceFD},

......

static void
android_media_MediaPlayer_setDataSourceFD(JNIEnv *env, jobject thiz, jobject fileDescriptor, jlong offset, jlong length)
{
	...
    int fd = jniGetFDFromFileDescriptor(env, fileDescriptor);
    ALOGV("setDataSourceFD: fd %d", fd);
    process_media_player_call( env, thiz, mp->setDataSource(fd, offset, length), "java/io/IOException", "setDataSourceFD failed." );
}

调用了 mp->setDataSource(fd, offset, length),根据参数:

3.2.3 framework-library

status_t MediaPlayer::setDataSource(int fd, int64_t offset, int64_t length)
{
    ALOGV("setDataSource(%d, %" PRId64 ", %" PRId64 ")", fd, offset, length);
    status_t err = UNKNOWN_ERROR;
    const sp<IMediaPlayerService> service(getMediaPlayerService());
    if (service != 0) {
        sp<IMediaPlayer> player(service->create(this, mAudioSessionId));
        if ((NO_ERROR != doSetRetransmitEndpoint(player)) ||
            (NO_ERROR != player->setDataSource(fd, offset, length))) {
            player.clear();
        }
        err = attachNewPlayer(player);
    }
    return err;
}

const sp service(getMediaPlayerService());可知,MediaPlayer和MediaPlayerService是C/S架构。后面再分析MediaPlayerService。

参考:Audio笔记之MediaPlayerService:setDataSource

继续分析MediaPlayer::setDataSource会发现其调用了player->setDataSource(fd, offset, length),其中player就是通过MediaPlayerService获取的实例:sp player(service->create(this, mAudioSessionId));,根据参数:

    status_t setDataSource(int fd, int64_t offset, int64_t length) {
        Parcel data, reply;
        data.writeInterfaceToken(IMediaPlayer::getInterfaceDescriptor());
        data.writeFileDescriptor(fd);
        data.writeInt64(offset);
        data.writeInt64(length);
        remote()->transact(SET_DATA_SOURCE_FD, data, &reply);
        return reply.readInt32();
    }

处理完成后,返回到 android_media_MediaPlayer_setDataSourceFD 中的 process_media_player_call(…) 函数中,process_media_player_call根据返回结果进行适当的处理(暂未详细分析)。

至此,setDataSource基本分析完成。

3.3 prepare

3.3.1 framework-java

接下来分析 mp.prepare();,即:

    public static MediaPlayer create(Context context, int resid, AudioAttributes audioAttributes, int audioSessionId) {
        try {
            ......
            mp.prepare();
            ......
        } 
        ...
    }
    public void prepare() throws IOException, IllegalStateException {
        _prepare();
        scanInternalSubtitleTracks();

        // DrmInfo, if any, has been resolved by now.
        synchronized (mDrmLock) {
            mDrmInfoResolved = true;
        }
    }

    private native void _prepare() throws IOException, IllegalStateException;

3.3.2 framework-jni

static void
android_media_MediaPlayer_prepare(JNIEnv *env, jobject thiz)
{
    sp<MediaPlayer> mp = getMediaPlayer(env, thiz);
    // android_media_MediaPlayer_native_setup()中有setMediaPlayer的动作

    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);

    process_media_player_call( env, thiz, mp->prepare(), "java/io/IOException", "Prepare failed." );
}

类似setDataSource,通过MediaPlayerService完成prepare的相关动作。

至此,prepare基本分析完成。

3.4 start

接下来分析APK中的mPlayer.start();

3.4.1 framework-java

    // 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) {
            startImpl();
        } else {
            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();
        }
    }

    private void startImpl() {
        baseStart();
        stayAwake(true);
        _start();
    }

    private native void _start() throws IllegalStateException;

3.4.2 framework-jni

// frameworks/base/media/jni/android_media_MediaPlayer.cpp
static void
android_media_MediaPlayer_start(JNIEnv *env, jobject thiz)
{
    ALOGV("start");
    sp<MediaPlayer> mp = getMediaPlayer(env, thiz);
    if (mp == NULL ) {
        jniThrowException(env, "java/lang/IllegalStateException", NULL);
        return;
    }
    process_media_player_call( env, thiz, mp->start(), NULL, NULL );
}

3.4.3 framework-library

// 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;
        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;
}
    // frameworks/av/media/libmedia/IMediaPlayer.cpp
    status_t start()
    {
        Parcel data, reply;
        data.writeInterfaceToken(IMediaPlayer::getInterfaceDescriptor());
        remote()->transact(START, data, &reply);
        return reply.readInt32();
    }

四、 参考

  1. Audio播放流程(一)—MediaPlayer流程
  2. Android源码分析之Framework的MediaPlayer
  3. Audio笔记之MediaPlayerService:setDataSource

你可能感兴趣的:(音视频开发,android多媒体,android音视频开发)