MediaPlayer(四)--MediaPlayer()流程
基于Android8.1代码
java MediaPlayer()
先从源头开始看
frameworks/base/media/java/android/media/MediaPlayer.java
public MediaPlayer() {
super(new AudioAttributes.Builder().build(),
AudioPlaybackConfiguration.PLAYER_TYPE_JAM_MEDIAPLAYER);
//1
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;
}
//2
mTimeProvider = new TimeProvider(this);
//3
mOpenSubtitleSources = new Vector<InputStream>();
//4
/* 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));
//5
baseRegisterPlayer();
}
1 创建EventHandler(重点)
后面jni回调java时会调用到postEventFromNative, postEventFromNative会将消息发给handler处理
2 mTimeProvider
对这个不太了解, 这是MediaPlayer的一个内部类,继承自MediaTimeProvider, 好像是一个用了提供Meida 播放,seek,buffer时间数据的类。
3 mOpenSubtitleSources
字幕源
4 native_setup(重点)
是对 native层MediaPlayer和回调listener的创建和初始化
5 baseRegisterPlayer()
这个函数在MediaPlayer的父类PlayerBase.主要是获取AppOpsService, 即Application Operations Service,是关于系统应用权限管理的,这些API不对第三方应用开放。
这里主干创建流程主要关注1 和 4. 即创建handle和native层的MediaPlayer, 后续native层即可回调java层接口,java层将信息发送给handle处理
native_setup(new WeakReference<MediaPlayer>(this));
frameworks/base/media/jni/android_media_MediaPlayer.cpp
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);
}
native_setup做了几件事情,
1 创建native层播放器实例MediaPlayer()
2 创建了JNIMediaPlayerListener,将java的MediaPlayer实例传递进去
3 将JNIMediaPlayerListener 设置给MediaPlayer()
4 将FFMediaPlayer 设置给Java层的mNativeContext
后面native层的MediaPlayer 就通过JNIMediaPlayerListener 回调java层接口。JNIMediaPlayerListener 能够访问全局变量 fields.post_event, 同时拥有 java的MediaPlayer实例,所以JNIMediaPlayerListener能够回调java层的postEventFromNative,并将MediaPlayer实例传递回去
关于这一部分listener的介绍可以参考
搭建ffmpeg player(一)--搭建上层框架
下面在分析一下setMediaPlayer,函数的目的是将将c++层MediaPlayer实例设置到java层的变量中。对于不熟悉智能指针的朋友可能有点绕
//假设引用计数为n, 这里传参不会增加计数
static sp<MediaPlayer> setMediaPlayer(JNIEnv* env, jobject thiz, const sp<MediaPlayer>& player)
{
Mutex::Autolock l(sLock);
//使用临时变量old,引用计数加1, n+1
sp<MediaPlayer> old = (MediaPlayer*)env->GetLongField(thiz, fields.context);
if (player.get()) {
//主动增加新设置的player的引用计数, n+2
player->incStrong((void*)setMediaPlayer);
}
if (old != 0) {
//主动减少旧的player的引用计数, n+1
old->decStrong((void*)setMediaPlayer);
}
env->SetLongField(thiz, fields.context, (jlong)player.get());
return old;
}
//函数结束,如果外部没有使用函数的返回值,则引用计数会减1,变为n
- 参数 sp<MediaPlayer>& player
这个参数传的是智能指针的引用, 引用不会增加智能指针的计数,这会导致什么问题呢。如果外部智能指针的计数为0了,MediaPlayer的实例会被释放掉的。如果参数是用传值,则会增加智能指针的计数,在函数执行结束后智能指针计数会减1。 - sp<MediaPlayer> old = (MediaPlayer*)env->GetLongField(thiz, fields.context);
这里是先获取java层的mNativeContext变量,因为jni层均为static方法,是对应java层所有实例对象的,jni层本身不保存任何的实例,所以这里需要先获取java层对应实例对象的变量mNativeContext,即保存的c++层MediaPlayer实例。 - env->SetLongField(thiz, fields.context, (jlong)player.get());
函数最后将MediaPlayer的指针传递给java层。使用get()返回的指针,当最后一个对应的智能指针销毁后,指针就变为无效了。所以需要有办法保证MediaPlayer在销毁之前,player智能指针的引用计数不能为0.
一种方法是使用全局的sp变量来引用MediaPlayer,不过Android并没有这么做,因为采用全局变量,则jni层只能给唯一一个播放器应用使用,这显然不符合要求。
Android的做法是将sp<MediaPlayer>的计数同 java层保存该指针的变量 private long mNativeContext 对应起来。首先参数采用引用sp<MediaPlayer>&,不会增加计数,接着用临时变量获取java层实例会增加计数。接着主动增加sp<MediaPlayer>的引用计数,在主动减少旧的sp<MediaPlayer>的引用计数,再通过get()方法将指针传递给java层,这样保证java层变量不销毁时,sp<MediaPlayer>的引用计数不为0。不过这样就需要在后续java层实例销毁的流程中,主动将引用计数减1
c++ MediaPlayer()
frameworks/av/media/libmedia/mediaplayer.cpp
MediaPlayer::MediaPlayer()
{
ALOGV("constructor");
mListener = NULL; // MediaPlayerListener, JNIMediaPlayerListener的父类,回调java层
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; //播放器当前状态 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;
}
在构造函数里将mCurrentState 设置成MEDIA_PLAYER_IDLE