Audio播放流程(一)---MediaPlayer流程

在这里插入图片描述
1. 对于APP而言要播放一个MP3很简单,只需要如下几步:

mp3 = MediaPlayer.create(MainActivity.this,R.raw.gem);
mp3.prepare(); 
mp3.start();          //开始播放

如上即可完成,But,Android系统在后台需要完成哪些更复杂的逻辑呢 ?
2. Android MediaPlayer流程

第一步: MediaPlayer类会先加载"media_jni"的库,然后调用native_init进入native完成初始化

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

第二步:创建MediaPlayer的Java端对象

    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();
			//设置音频属性,例如:flag,source,format
            final AudioAttributes aa = audioAttributes != null ? audioAttributes :
                new AudioAttributes.Builder().build();
			//为Java端对象设置属性	
            mp.setAudioAttributes(aa);
            //为Java端对象设置会话id
            mp.setAudioSessionId(audioSessionId);
			//设置需要播放的音频文件大小,偏移等到Native中
            mp.setDataSource(afd.getFileDescriptor(), afd.getStartOffset(), afd.getLength());
            afd.close();
            //调用prepare
            mp.prepare();
            return mp;
            ...
          }

再看看mediaplayer的构造方法:

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

        Looper looper;
        //如果调用MediaPlayer构造方法的线程有自己的looper,就用子线程的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));
    }

总结下目前为止,JAVA端下发到JNI的native方法:
在这里插入图片描述

来到native看下代码的流程

frameworks\base\media\jni\android_media_MediaPlayer.cpp

native_setup的本地实现

android_media_MediaPlayer_native_setup
	JNIMediaPlayerFactory *jniMediaPlayerFactory = new JNIMediaPlayerFactory();
	sp<MediaPlayerListener> listener = new JNIMediaPlayerListener(env, thiz, weak_this);
	//创建native的MediaPlayer对象
	mp = new MediaPlayer();
	//为native的对象设置监听
	mp->setListener(listener);
	//将native对象的保存到Java对象的成员mNativeContext中
	setMediaPlayer(env, thiz, mp);

setDataSource的本地实现

android_media_MediaPlayer_setDataSourceFD
	//获取native的mediaplayer的对象
	sp<MediaPlayer> mp = getMediaPlayer(env, thiz);
	//将java端的文件描述符转化为本地的描述符
	int fd = jniGetFDFromFileDescriptor(env, fileDescriptor);
	//这条语句是指,如果mp->setDataSource(fd, offset, length)这个方法执行出粗,将会抛出相应的异常
	process_media_player_call( env, thiz, mp->setDataSource(fd, offset, length), "java/io/IOException", "setDataSourceFD failed." );

BTW,mp->setDataSource将会调用到mediaplayerservice完成相应的操作

prepare的本地实现

static void
android_media_MediaPlayer_prepare(JNIEnv *env, jobject thiz)
{
    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);

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

这里的mp->prepare()实现如下:

status_t MediaPlayer::prepare()
...
status_t ret = prepareAsync_l();
				//这里的默认mStreamType是AUDIO_STREAM_MUSIC,当然你可以手动设置改变它
			   ---->mPlayer->setAudioStreamType(mStreamType);
			   ---->mPlayer->prepareAsync();
...
}

同理这里的prepareAsync_l会调度到mediaplayerservice中去;

然后我们来看最后一个native的方法----start

status_t MediaPlayer::start()
{
    ALOGV("start");
	...
	//这里的mloop默认是false的
	mPlayer->setLooping(mLoop);
	mPlayer->setVolume(mLeftVolume, mRightVolume);
	mPlayer->setAuxEffectSendLevel(mSendLevel);
	mCurrentState = MEDIA_PLAYER_STARTED;
	ret = mPlayer->start();
	...
    return ret;
}

ok,这里再做一下总结,MediaPlayer发送到MediaPlayerService中去执行的方法如下:

在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/zhuyong006/article/details/86080498
今日推荐