对于创建MediaPlay我们可以使用create方式,也可以通过new MediaPlay的方式。下面以create方式来切入源码。
public static MediaPlayer create(Context context, Uri uri, SurfaceHolder holder,
AudioAttributes audioAttributes, int audioSessionId) {
try {
//1、
MediaPlayer mp = new MediaPlayer();
//2、
mp.setDataSource(context, uri);
if (holder != null) {
//3、
mp.setDisplay(holder);
}
//4、
mp.prepare();
return mp;
}
//..
return null;
}
首先重点分析1处MediaPlayer的创建过程:MediaPlayer构造方法如下。
public 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;
}
//重点
native_setup(new WeakReference<MediaPlayer>(this));
baseRegisterPlayer();
}
首先根据当前线程的Looper创建一个EventHandler对象。这个EventHandler继承至Handler,和我们自己写的Handler差不多,用来接收消息,回调对应的方法。比如当我们给MediaPlayer设置了OnPreparedListener监听(setOnPreparedListener),当一切就绪后,C++层会通过JNI通知到JAVA层(postEventFromNative),之后postEventFromNative方法内就会发送一个MEDIA_PREPARED 消息给EventHandler,EventHandler收到就会调用onPreparedListener.onPrepared(mMediaPlayer)方法。
然后调用native_setup方法。这个方法很重要,它建立了Java层MediaPlayer和C++层MediaPlayer之间的关联,可以说Java层的MediaPlayer就是个皮包公司,它所作的工作包括setDataSource、prepare、start等,最后都是交给C++层的MediaPlayer。注意这个方法将Java层MediaPlayer的弱引用传给了JNI层。
private native final void native_setup(Object mediaplayer_this)
这是一个native方法,所以需要去扒一扒C/C++的底了。根据JNI的命名规则找到:
–》android_media_MediaPlayer.cpp
static void
android_media_MediaPlayer_native_setup(JNIEnv *env, jobject thiz, jobject weak_this)
{
//创建一个C++层的MediaPlayer
sp<MediaPlayer> mp = new MediaPlayer();
//...
//创建一个JNIMediaPlayerListener,以便C++层MediaPlayer通过这个listener 通知到JAVA层的//MediaPlayer去。
sp<JNIMediaPlayerListener> listener = new JNIMediaPlayerListener(env, thiz, weak_this);
mp->setListener(listener);
//建立JAVA层MediaPlayer和C++层MediaPlayer之间的关联
setMediaPlayer(env, thiz, mp);
}
可以看到 setMediaPlayer(env, thiz, mp)方法的后面两个参数thiz指代了Java层的那个MediaPlayer,mp指代了C++层的MediaPlayer。
static sp<MediaPlayer> setMediaPlayer(JNIEnv* env, jobject thiz, const sp<MediaPlayer>& player)
{
//...
//将C++层的MediaPlayer地址保存到Java层MediaPlayer的mNativeContext字段
env->SetLongField(thiz, fields.context, (jlong)player.get());
return old;
}
这样JAVA和C++层的MediaPlayer就建立了关联,那么fields.context什么时候被赋值的呢?在MediaPlayer.java的静态代码块可以看到如下:
–》MediaPlayer.java
static {
//加载so
System.loadLibrary("media_jni");
//初始化
native_init();
}
–》android_media_MediaPlayer.cpp
static void
android_media_MediaPlayer_native_init(JNIEnv *env)
{
jclass clazz;
clazz = env->FindClass("android/media/MediaPlayer");
if (clazz == NULL) {
return;
}
//mNativeContext用来保存C++层MediaPlayer的地址,拿到它的FieldID
fields.context = env->GetFieldID(clazz, "mNativeContext", "J");
if (fields.context == NULL) {
return;
}
//拿到postEventFromNative的MethodID,以后JNI就可以通过这个方法通知Java层啦
fields.post_event = env->GetStaticMethodID(clazz, "postEventFromNative",
"(Ljava/lang/Object;IIILjava/lang/Object;)V");
if (fields.post_event == NULL) {
return;
}
//这个是和显示相关的。
fields.surface_texture = env->GetFieldID(clazz, "mNativeSurfaceTexture", "J");
if (fields.surface_texture == NULL) {
return;
}
env->DeleteLocalRef(clazz);
//...
}
这样MediaPlayer的构造方法就分析完了,总结一下:
- 1、创建了EventHandler,以便处理JNI层通过postEventFromNative传递过来的消息。
- 2、创建了C++层的MediaPlayer并和JAVA层的MediaPlayer建立关系。
MediaPlayer对象创建完成,紧接着调用了setDataSource方法(这篇文章就是以这条线分析的,其他方法类似):
–》MediaPlayer.java
private void setDataSource(String path, String[] keys, String[] values,
List<HttpCookie> cookies) {
final Uri uri = Uri.parse(path);
final String scheme = uri.getScheme();
if ("file".equals(scheme)) {
path = uri.getPath();
} else if (scheme != null) {
//...
}
final File file = new File(path);
try (FileInputStream is = new FileInputStream(file)) {
setDataSource(is.getFD());
}
}
这里只分析数据源是文件的情况,获取到数据源的FileDescriptor接着又调用了
–》setDataSource(fd, 0, 0x7ffffffffffffffL)–》_setDataSource(fd, offset, length)。_setDataSource是一个native 方法,因此去android_media_MediaPlayer.cpp看看其具体实现。
–》android_media_MediaPlayer.cpp
static void
android_media_MediaPlayer_setDataSourceFD(JNIEnv *env, jobject thiz, jobject fileDescriptor, jlong offset, jlong length)
{
//1、获取C++层的MediaPlayer指针
sp<MediaPlayer> mp = getMediaPlayer(env, thiz);
//2、获取文件描述符。
int fd = jniGetFDFromFileDescriptor(env, fileDescriptor);
//3、调用C++层的MediaPlayer的setDataSource方法
process_media_player_call( env, thiz, mp->setDataSource(fd, offset, length), "java/io/IOException", "setDataSourceFD failed." );
}
那么如何获取C++层的MediaPlayer指针?
static sp<MediaPlayer> getMediaPlayer(JNIEnv* env, jobject thiz)
{
Mutex::Autolock l(sLock);
MediaPlayer* const p = (MediaPlayer*)env->GetLongField(thiz, fields.context);
return sp<MediaPlayer>(p);
}
很简单,就是拿到Java层MediaPlayer中mNativeContext保存的值,这个值保存的就是C++层MediaPlayer的地址,然后赋给指针p 。
对于process_media_player_call这个函数,其实就是根据 mp->setDataSource(fd, offset, length)返回值,来决定是否抛出异常或者通知到Java层。
Ok,现在的执行流程已经从Java层MediaPlayer.setDataSource进入了C++层MediaPlayer.setDataSource,继续跟进。
–》mediaplayer.cpp
status_t MediaPlayer::setDataSource(int fd, int64_t offset, int64_t length)
{
//给err 赋一个初值
status_t err = UNKNOWN_ERROR;
//1、获取BpMediaPlayerService,
const sp<IMediaPlayerService> service(getMediaPlayerService());
if (service != 0) {
//2、
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;
}
首先在第一步获取一个BpMediaPlayerService,这里说有必要多说几句:
只要看到BpXXX就不得不想到BpBinder和BBinder。Binder是Android系统C/S架构提供的一种IPC(进程间通信)机制。BpBinder就是客户端用来与Server交互的代理类,BBinder代表了通信的目的也就是服务端,每一个BpBinder都有一个BBinder与之一一对应(通过构造函数传入的handle对应)。
继续跟进getMediaPlayerService()方法。
–》IMediaDeathNotifier.cpp
const sp<IMediaPlayerService> IMediaDeathNotifier::getMediaPlayerService()
{
if (sMediaPlayerService == 0) {//如果还没有创建就先创建
//先获取BpServiceManager
sp<IServiceManager> sm = defaultServiceManager();
sp<IBinder> binder;
do {
//通过BpServiceManager去ServiceManager查询MediaPlayerService的Binder句柄
binder = sm->getService(String16("media.player"));
if (binder != 0) {
break;
}
//如果MediaPlayerService还没注册到ServiceManager中,此时肯定获取不到,就等等。
usleep(500000); // 0.5 s
} while (true);
//。。。
//通过MediaPlayerService的Binder句柄创建BpMediaPlayerService
sMediaPlayerService = interface_cast<IMediaPlayerService>(binder);
}
return sMediaPlayerService;
}
代码虽然很少,但是还是要好好捋捋的。首先要明白getMediaPlayerService这个函数返回的是BpMediaPlayerService。
对于系统服务来说,通常都是注册到ServiceManager中,由ServiceManager统一管理。如果某个应用需要获取系统服务,需要先去ServiceManager查询,如果这个服务还没被注册到ServiceManager,此时肯定获取不到,就等等在尝试获取。反之,则会返回这个系统服务的BBinder句柄对应的BpBinder给我们。
Client查询服务、使用服务;Service向ServiceManager注册服务都是IPC过程。对于SerciceManager来说,Client、Server都是C;对于Server来说Client是C。
在getMediaPlayerService中首先通过defaultServiceManager()获取BpServiceManager。
–》IServiceManager.cpp
sp<IServiceManager> defaultServiceManager()
{
if (gDefaultServiceManager != NULL) return gDefaultServiceManager;
{
AutoMutex _l(gDefaultServiceManagerLock);
while (gDefaultServiceManager == NULL) {
gDefaultServiceManager = interface_cast<IServiceManager>(
ProcessState::self()->getContextObject(NULL));
if (gDefaultServiceManager == NULL)
sleep(1);
}
}
return gDefaultServiceManager;
}
这个方法返回的就是BpServiceManager,以单例的方式实现。首先看ProcessState::self()->getContextObject(NULL)
这行代码。
Tip:文章的主题是分析MediaPlayer,关于binder机制不会细说,但为了更好的理解也会解释下。
ProcessState这个类是进程唯一的,在它的构造方法中会打开Binder驱动,映射一块内存供Binder接收数据。
–》ProcessState.cpp
ProcessState::ProcessState(const char *driver)
: mDriverName(String8(driver))
, mDriverFD(open_driver(driver))//打开binder驱动
//。。。。
{
if (mDriverFD >= 0) {
//映射一块内存
mVMStart = mmap(0, BINDER_VM_SIZE, PROT_READ, MAP_PRIVATE | MAP_NORESERVE, mDriverFD, 0);
}
}
当然主要还是分析要ProcessState::self()->getContextObject(NULL))方法。注意这里传入的是一个参数NULL
–》ProcessState.cpp
sp<IBinder> ProcessState::getContextObject(const sp<IBinder>& /*caller*/)
{
return getStrongProxyForHandle(0);
}
接着调用了getStrongProxyForHandle传入了0(这个0是有特殊含义的,待会就知道了)
–》ProcessState.cpp
sp<IBinder> ProcessState::getStrongProxyForHandle(int32_t handle)
{
sp<IBinder> result;
AutoMutex _l(mLock);
handle_entry* e = lookupHandleLocked(handle);
if (e != NULL) {
//省略了部分代码
IBinder* b = e->binder;
if (b == NULL || !e->refs->attemptIncWeak(this)) {
//直接通过这个handle创建了一个BpBinder
b = new BpHwBinder(handle);
e->binder = b;
if (b) e->refs = b->getWeakRefs();
result = b;
}
}
return result;
}
在调用getStrongProxyForHandle传入的是0,然后这个0在new BpHwBinder时又被传入了BpHwBinder的构造。那么这个0有什么含义呢?前面说过,客户端的每一个BpBinder都对应目的端的一个BBinder,那么怎么一一对应的呢?就是通过这个handle,0就对应ServiceManager端的BBinder句柄。
所以defaultServiceManager代码就相当于这样:
sp<IServiceManager> defaultServiceManager()
{
if (gDefaultServiceManager != NULL) return gDefaultServiceManager;
{
AutoMutex _l(gDefaultServiceManagerLock);
while (gDefaultServiceManager == NULL) {
gDefaultServiceManager = interface_cast<IServiceManager>(
new BpHwBinder(0));
if (gDefaultServiceManager == NULL)
sleep(1);
}
}
return gDefaultServiceManager;
}
ok继续看看interface_cast又干了啥。
–》IInterface.h
template<typename INTERFACE>
inline sp<INTERFACE> interface_cast(const sp<IBinder>& obj)
{
return INTERFACE::asInterface(obj);
}
一个模板函数,相当于IServiceManager::asInterface(new BpHwBinder(0))
–》IServiceManager.h
class IServiceManager : public IInterface
{
public:
//这个宏声明在IInterface中
DECLARE_META_INTERFACE(ServiceManager)
//....省略代码专用逗号....
};
继续跟进IInterface.h文件
–》IInterface.h
//申明
#define DECLARE_META_INTERFACE(INTERFACE) \
//看这里 \
static ::android::sp<I##INTERFACE> asInterface( \
const ::android::sp<::android::IBinder>& obj); \
//实现
#define IMPLEMENT_META_INTERFACE(INTERFACE, NAME) \
//再看这里 \
::android::sp<I##INTERFACE> I##INTERFACE::asInterface( \
const ::android::sp<::android::IBinder>& obj) \
{ \
::android::sp<I##INTERFACE> intr; \
if (obj != NULL) { \
intr = static_cast<I##INTERFACE*>( \
obj->queryLocalInterface( \
I##INTERFACE::descriptor).get()); \
if (intr == NULL) {
//快看这 快看这 快看这
intr = new Bp##INTERFACE(obj); \
} \
} \
return intr; \
}
现在知道了,原来defaultServiceManager代码就相当于这样:
sp<IServiceManager> defaultServiceManager()
{
if (gDefaultServiceManager != NULL) return gDefaultServiceManager;
{
//...
gDefaultServiceManager = new BpServiceManager(new BpHwBinder(0))));
}
return gDefaultServiceManager;
}
BpServiceManager内部持有BpBinder,由BpServiceManager处理业务BpBinder和Binder打交道。
终于拿到了BpServiceManager,之后就可以通过它和ServiceManager打交道(IPC),
再来粘贴下getMediaPlayerService的方法
IMediaDeathNotifier::getMediaPlayerService()
{
if (sMediaPlayerService == 0) {
//获取BpServiceManager
sp<IServiceManager> sm = defaultServiceManager();
sp<IBinder> binder;
do {
//去ServiceManager查询MediaPlayerService服务,获取其BpBinder
binder = sm->getService(String16("media.player"));
//创建BpMediaPlayerService
sMediaPlayerService = interface_cast<IMediaPlayerService>(binder);
}
return sMediaPlayerService;
}
sm->getService(String16(“media.player”)),最终会跨进程去ServiceManager查询出MediaPlayerService的BpBinder句柄,这其中会经过将数据写入binder缓存(mOut),接收响应,就不再细说了。
接着又走到interface_cast(binder),又碰到这个了。
所以getMediaPlayerService就相当于:
IMediaDeathNotifier::getMediaPlayerService()
{
if (sMediaPlayerService == 0) {
//获取BpServiceManager
sp<IServiceManager> sm = defaultServiceManager();
sp<IBinder> binder;
do {
//去ServiceManager查询MediaPlayerService服务,获取其BpBinder
binder = sm->getService(String16("media.player"));
//创建BpMediaPlayerService
sMediaPlayerService = new BpMediaPlayerService(binder);
}
return sMediaPlayerService;
}
获取了BpMediaPlayerService之后就可以跨进程调用目的端BnMediaPlayerService的create方法了。
status_t MediaPlayer::setDataSource(int fd, int64_t offset, int64_t length)
{
status_t err = UNKNOWN_ERROR;
const sp<IMediaPlayerService> service(getMediaPlayerService());
if (service != 0) {
//IPC创建BpMediaPlayer
sp<IMediaPlayer> player(service->create(this, mAudioSessionId));
//。。。
//调用BpMediaPlayer的setDataSource方法
player->setDataSource(fd, offset, length)
//将player保存为mPlayer
err = attachNewPlayer(player);
}
return err;
}
MediaPlayerService继承自BnMediaPlayerService,BnMediaPlayerService的create的具体业务应该去MediaPlayerService中找如下:
–》MediaPlayerService.cpp
sp<IMediaPlayer> MediaPlayerService::create(const sp<IMediaPlayerClient>& client,
audio_session_t audioSessionId)
{
pid_t pid = IPCThreadState::self()->getCallingPid();
int32_t connId = android_atomic_inc(&mNextConnId);
//创建一个MediaPlayerService::Client
sp<Client> c = new Client(
this, pid, connId, client, audioSessionId,
IPCThreadState::self()->getCallingUid());
wp<Client> w = c;
{
Mutex::Autolock lock(mLock);
mClients.add(w);
}
return c;
}
MediaPlayerService::Client继承自BnMediaPlayer。
所以现在搞清楚了,原来C++层的MediaPlayer也不干事,比如setDataSource,经过一顿猛如虎的操作调到了BpMediaPlayer的setDataSource方法,最后跨进程调用了 MediaPlayerService::Client对应的方法。分析到这里setDataSource在C端的调用其实就差不多了,后面就走到了S端(MediaPlayerService::Client)的setDataSource,对于其他的方法,调用过程都是类似的,关于音视频的处理过程是放在MediaPlayerService端的,因为篇幅原因将在下一篇记录。