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中去执行的方法如下: