前言

之前的《MediaPlayer java层介绍》只是介绍了java中的常用方法,对于JNI层的调用没有进一步介绍,今天就介绍一下JNI层。

个人流水账哈,推荐看其他人的,我这只是自己的跟踪记录

涉及的代码:

  1. frameworks\base\media\java\android\media\MediaPlayer.java
  2. frameworks\base\media\jni\android_media_MediaPlayer.cpp
  3. frameworks\base\core\jni\AndroidRuntime.cpp
  4. frameworks\av\media\libmedia\mediaplayer.cpp
  5. libnativehelper\include\nativehelper\JNIHelp.h
  6. frameworks\av\media\libmedia\IMediaPlayer.cpp
  7. frameworks\av\media\libmedia\IMediaDeathNotifier.cpp
  8. frameworks\native\libs\binder\IServiceManager.cpp
  9. frameworks\av\media\libmedia\IMediaPlayerService.cpp
复制

正文

MediaPlayer.java

接上次demo调用的方法,主要涉及的本地方法,本文主要是按照下面的顺序去看代码的:

  1. 1. System.loadLibrary("media_jni");
  2. 2. native_init();
  3. 3. native_setup();
  4. 4. _setDataSource();
  5. 5. _prepare();
  6. 6. _start();
复制

当然还有其他方法,都类似。

android_media_MediaPlayer.cpp

按照以前学习的知识,JNI对应的代码是以包名+类名命名,也就是android_media_MediaPlayer.cpp。

loadLibrary(“media_jni”)

动态注册,会调用JNI_OnLoad(),具体就不解释了。

我们关注点

  1. static int register_android_media_MediaPlayer(JNIEnv *env){
  2.   return AndroidRuntime::registerNativeMethods(env,
  3.               "android/media/MediaPlayer", gMethods, NELEM(gMethods));
  4. }
复制
  1. int AndroidRuntime::registerNativeMethods(JNIEnv* env,
  2. const char* className, const JNINativeMethod* gMethods, int numMethods){
  3.   return jniRegisterNativeMethods(env, className, gMethods, numMethods);
  4. }
复制

jniRegisterNativeMethods是jniRegisterNativeMethods函数是Android平台提供的帮助函数,可看:

  1. libnativehelper\include\nativehelper\JNIHelp.h
复制

gMethods中可以看对应实现的方法

  1. //部分
  2. static const JNINativeMethod gMethods[] = {
  3.   {"_setDataSource",     "(Ljava/io/FileDescriptor;JJ)V",   (void *)android_media_MediaPlayer_setDataSourceFD},
  4.   {"native_init",         "()V",                             (void *)android_media_MediaPlayer_native_init},
  5.   {"native_setup",       "(Ljava/lang/Object;)V",           (void *)android_media_MediaPlayer_native_setup},
  6.   {"native_finalize",     "()V",                             (void *)android_media_MediaPlayer_native_finalize},
  7. };
复制
native_init

从上面gMethods可以知道

  1. static void android_media_MediaPlayer_native_init(JNIEnv *env){
  2.   jclass clazz;
  3. //加载android.media.MediaPlayer
  4.   clazz = env->FindClass("android/media/MediaPlayer");
  5.   //略
  6. // postEventFromNative java方法ID,用于回调
  7.   fields.post_event = env->GetStaticMethodID(clazz, "postEventFromNative","(Ljava/lang/Object;IIILjava/lang/Object;)V");
  8.   if (fields.post_event == NULL) {
  9.       return;
  10.   }
  11. //释放
  12.   env->DeleteLocalRef(clazz);
  13. //略
  14. }
复制

有个重点,获取了Java方法的MethodID,后面可以调用postEventFromNative(),下面会介绍到。

native_setup()
  1. static void android_media_MediaPlayer_native_setup(JNIEnv *env, jobject thiz, jobject weak_this){
  2. //创建MediaPlayer对象
  3.   sp<MediaPlayer> mp = new MediaPlayer();
  4.   //回调监听,调用Java方法postEventFromNative回调
  5.   sp<JNIMediaPlayerListener> listener = new JNIMediaPlayerListener(env, thiz, weak_this);
  6.   mp->setListener(listener);
  7. //把MediaPlayer对象保存起来了,后面会通过get获取
  8.   setMediaPlayer(env, thiz, mp);
  9. }
复制

MediaPlayer()后面看。

JNIMediaPlayerListener

JNIMediaPlayerListener类中有个notify()方法

  1. void JNIMediaPlayerListener::notify(int msg, int ext1, int ext2, const Parcel *obj){
  2.   JNIEnv *env = AndroidRuntime::getJNIEnv();
  3.   if (obj && obj->dataSize() > 0) {
  4.       jobject jParcel = createJavaParcelObject(env);
  5.       //数据封装
  6.       if (jParcel != NULL) {
  7.           Parcel* nativeParcel = parcelForJavaObject(env, jParcel);
  8.           nativeParcel->setData(obj->data(), obj->dataSize());
  9.           //重点
  10.           env->CallStaticVoidMethod(mClass, fields.post_event, mObject,
  11.                   msg, ext1, ext2, jParcel);
  12.           env->DeleteLocalRef(jParcel);
  13.       }
  14.   } else {
  15.   //重点
  16.       env->CallStaticVoidMethod(mClass, fields.post_event, mObject,
  17.               msg, ext1, ext2, NULL);
  18.   }
  19. }
复制

很明显,这里调用了java中的postEventFromNative方法,fields.post_event就是在native_init()获取的MedthoID。

CallStaticVoidMethod是jni.h中定义的,还有很多类似的方法,比如:

  1. CallStaticDoubleMethod()
  2. CallStaticIntMethod()
  3. CallStaticBooleanMethodA()
复制

根据Java方法回调的参数和属性进行调用不同的方法。

具体可看android-ndk-r21d-windows-x86_64[这个我下载的的NDK版本]中找jni.h文件,里面有很多JNI相关的定义。

setMediaPlayer

用于保存MediaPlayer对象

  1. static sp<MediaPlayer> getMediaPlayer(JNIEnv* env, jobject thiz){
  2.   Mutex::Autolock l(sLock);//锁
  3. //获取已经初始化过的MediaPlayer
  4.   MediaPlayer* const p = (MediaPlayer*)env->GetLongField(thiz, fields.context);
  5.   return sp<MediaPlayer>(p);
  6. }
  7. static sp<MediaPlayer> setMediaPlayer(JNIEnv* env, jobject thiz, const sp<MediaPlayer>& player){
  8.   Mutex::Autolock l(sLock);
  9.   sp<MediaPlayer> old = (MediaPlayer*)env->GetLongField(thiz, fields.context);
  10.   if (player.get()) {
  11.       player->incStrong((void*)setMediaPlayer);
  12.   }
  13.   if (old != 0) {
  14.       old->decStrong((void*)setMediaPlayer);
  15.   }
  16. //保存MediaPlayer,后面会获取
  17.   env->SetLongField(thiz, fields.context, (jlong)player.get());
  18.   return old;
  19. }
复制
_setDataSource()

_setDataSource在MediaPlayer.java中有两个方法

  1. private native void _setDataSource(FileDescriptor fd, long offset, long length);
  2. private native void _setDataSource(MediaDataSource dataSource);
复制

因此在android_media_MediaPlayer.cpp也有两个,只不过两个传的参数不一样。看我们demo中调用的

  1. static void android_media_MediaPlayer_setDataSourceFD(JNIEnv *env, jobject thiz, jobject fileDescriptor, jlong offset, jlong length){
  2.   //获取MediaPlayer对象
  3. sp<MediaPlayer> mp = getMediaPlayer(env, thiz);
  4. //也在上面nativehelper\JNIHelp.h定义,这里不关心
  5.   int fd = jniGetFDFromFileDescriptor(env, fileDescriptor);
  6.   //重点mp->setDataSource(fd, offset, length)
  7.   //process_media_player_call只是处理状态码,后面很多方法都用这个。
  8.   process_media_player_call( env, thiz, mp->setDataSource(fd, offset, length), "java/io/IOException", "setDataSourceFD failed." );
  9. }
复制

进入mediaplayer.cpp中的setDataSource()啦,暂时跳过,后面看。

prepare()
  1. static void android_media_MediaPlayer_prepare(JNIEnv *env, jobject thiz){
  2. //获取MediaPlayer对象
  3.   sp<MediaPlayer> mp = getMediaPlayer(env, thiz);
  4. //mp->prepare()
  5.   process_media_player_call( env, thiz, mp->prepare(), "java/io/IOException", "Prepare failed." );
  6. }
复制

最终也是mp->prepare(),这里暂时跳过。

_start()
  1. static void android_media_MediaPlayer_start(JNIEnv *env, jobject thiz){
  2.   sp<MediaPlayer> mp = getMediaPlayer(env, thiz);
  3. //mp->start()
  4.   process_media_player_call( env, thiz, mp->start(), NULL, NULL );
  5. }
复制

最终也是 mp->start()。

到此,其他方法都差不多,最终也是MediaPlayer类[mediaplayer.cpp]的调用。

mediaplayer.cpp

这里进入mediaplayer.cpp啦,然后根据上面进入的方法走一下。

接上面native_setup()中

  1. sp<MediaPlayer> mp = new MediaPlayer();
复制

初始化mp对象,构造函数中就是一些默认值的初始化,这里就不附上了。

native_setup()中传入了

  1. sp<JNIMediaPlayerListener> listener = new JNIMediaPlayerListener(env, thiz, weak_this);
  2. mp->setListener(listener);
复制

传入JNIMediaPlayerListener,我们知道JNIMediaPlayerListener.notify()【上面有介绍】会调用postEventFromNative()方法,用于返回播放状态和状态等信息。

setDataSource()
  1. status_t MediaPlayer::setDataSource(
  2.       const sp<IMediaHTTPService> &httpService,
  3.       const char *url, const KeyedVector<String8, String8> *headers){
  4.   status_t err = BAD_VALUE;
  5.   if (url != NULL) {
  6. //[重点]。BpMediaPlayerService的对象service
  7.       const sp<IMediaPlayerService> service(getMediaPlayerService());
  8.       if (service != 0) {
  9. //[重点]。创建BpMediaPlayer对象player
  10.           sp<IMediaPlayer> player(service->create(this, mAudioSessionId));
  11.           if ((NO_ERROR != doSetRetransmitEndpoint(player)) ||
  12. //BpMediaPlayer.setDataSource();
  13.               (NO_ERROR != player->setDataSource(httpService, url, headers))) {
  14.               player.clear();
  15.           }
  16.           err = attachNewPlayer(player);
  17.       }
  18.   }
  19.   return err;
  20. }
复制
为啥说service是BpMediaPlayerService的对象?

getMediaPlayerService()

  1. const sp<IMediaPlayerService>IMediaDeathNotifier::getMediaPlayerService()
  2. {
  3.   Mutex::Autolock _l(sServiceLock);
  4. //单例模式,如果是第一次,sMediaPlayerService==0
  5.   if (sMediaPlayerService == 0) {
  6. //interface_cast获取BpMediaPlayerService的对象
  7.       sMediaPlayerService = interface_cast<IMediaPlayerService>(binder);
  8.   }
  9.   return sMediaPlayerService;
  10. }
复制

至于interface_cast,推荐看《interface_cast简介

为啥说player是BpMediaPlayer
  1. virtual sp<IMediaPlayer> create(
  2.       const sp<IMediaPlayerClient>& client, audio_session_t audioSessionId) {
  3.   Parcel data, reply;
  4. data.writeInterfaceToken(IMediaPlayerService::getInterfaceDescriptor());
  5.   data.writeStrongBinder(IInterface::asBinder(client));
  6.   data.writeInt32(audioSessionId);
  7.   remote()->transact(CREATE, data, &reply);
  8. //interface_cast获取BpMediaPlayer
  9.   return interface_cast<IMediaPlayer>(reply.readStrongBinder());
  10. }
复制

最后调用的是BpMediaPlayer的setDataSource()

  1. status_t setDataSource(int fd, int64_t offset, int64_t length) {
  2.   Parcel data, reply;
  3.   data.writeInterfaceToken(IMediaPlayer::getInterfaceDescriptor());
  4.   data.writeFileDescriptor(fd);
  5.   data.writeInt64(offset);
  6.   data.writeInt64(length);
  7.   //有点晕,BpBinder(0)
  8.   remote()->transact(SET_DATA_SOURCE_FD, data, &reply);
  9.   return reply.readInt32();
  10. }
复制

PS: 至于remote()这个是谁,是BpBinder(0)?我目前有点晕了。。。后续补上

最终真正处理,也不是mediaplayer.cpp,,,好绕啊。今天不展开了。等下集。

prepare()
  1. //prepare()
  2. status_t MediaPlayer::prepare(){
  3.   Mutex::Autolock _l(mLock);
  4.   mLockThreadId = getThreadId();
  5.   if (mPrepareSync) {
  6.       mLockThreadId = 0;
  7.       return -EALREADY;
  8.   }
  9.   mPrepareSync = true;
  10. //最终都是走了prepareAsync_l()
  11.   status_t ret = prepareAsync_l();
  12.   if (ret != NO_ERROR) {
  13.       mLockThreadId = 0;
  14.       return ret;
  15.   }
  16.   //[重点] 等待Prepare完成,也就是等mSignal释放锁,
  17.   //这里跟prepareAsync()的区别
  18.   if (mPrepareSync) {
  19.       mSignal.wait(mLock);  
  20.       mPrepareSync = false;
  21.   }
  22.   mLockThreadId = 0;
  23.   return mPrepareStatus;
  24. }
  25. //prepareAsync()
  26. status_t MediaPlayer::prepareAsync(){
  27.   Mutex::Autolock _l(mLock);
  28. //最终都是走了prepareAsync_l()
  29.   return prepareAsync_l();
  30. }
复制

或许你会问题 mSignal.wait(mLock)啥时候等到呢?具体看

  1. void MediaPlayer::notify(int msg, int ext1, int ext2, const Parcel *obj){
  2.   bool send = true;
  3.   bool locked = false;
  4.   if (mLockThreadId != getThreadId()) {
  5.       mLock.lock();
  6.       locked = true;
  7.   }
  8.   switch (msg) {
  9.   case MEDIA_PREPARED:
  10.       mCurrentState = MEDIA_PLAYER_PREPARED;
  11.       if (mPrepareSync) {
  12.           mPrepareSync = false;
  13.           mPrepareStatus = NO_ERROR;
  14.           mSignal.signal();
  15.       }
  16.       break;
  17.   case MEDIA_ERROR:
  18.       mCurrentState = MEDIA_PLAYER_STATE_ERROR;
  19.       if (mPrepareSync){
  20.           mPrepareSync = false;
  21.           mPrepareStatus = ext1;
  22.           mSignal.signal();
  23.           send = false;
  24.       }
  25.       break;
  26.   }
  27.   sp<MediaPlayerListener> listener = mListener;
  28.   if (locked) mLock.unlock();
  29.   if ((listener != 0) && send) {
  30.       Mutex::Autolock _l(mNotifyLock);
  31.       // 这个就是我们传入的JNIMediaPlayerListener
  32.       listener->notify(msg, ext1, ext2, obj);
  33.   }
  34. }
复制

prepareAsync()和prepare()都调用prepareAsync_l()

  1. status_t MediaPlayer::prepareAsync_l(){
  2.   if ( (mPlayer != 0) && ( mCurrentState & (MEDIA_PLAYER_INITIALIZED | MEDIA_PLAYER_STOPPED) ) ) {
  3. //执行BpMediaPlayer.prepareAsync()
  4.       return mPlayer->prepareAsync();
  5.   }
  6.   //有个短暂的PREPARING状态
  7.   mCurrentState = MEDIA_PLAYER_PREPARING;
  8.   return INVALID_OPERATION;
  9. }
复制

BpMediaPlayer.prepareAsync()中也是调用远程的服务,这里暂不深入。

start()
  1. status_t MediaPlayer::start(){
  2.   status_t ret = NO_ERROR;
  3.   Mutex::Autolock _l(mLock);
  4.   mLockThreadId = getThreadId();
  5.   if (mCurrentState & MEDIA_PLAYER_STARTED) {
  6.       ret = NO_ERROR;
  7.   } else if ( (mPlayer != 0) && ( mCurrentState & ( MEDIA_PLAYER_PREPARED |
  8.                   MEDIA_PLAYER_PLAYBACK_COMPLETE | MEDIA_PLAYER_PAUSED ) ) ) {
  9. //设置是否循环mLoop
  10.       mPlayer->setLooping(mLoop);
  11. //设置音量
  12.       mPlayer->setVolume(mLeftVolume, mRightVolume);
  13. //这个不太懂。。。一般APP没设置过
  14.       mPlayer->setAuxEffectSendLevel(mSendLevel);
  15. //改变播放状态
  16.       mCurrentState = MEDIA_PLAYER_STARTED;
  17. //BpMediaPlayer.prepareAsync()
  18.       ret = mPlayer->start();
  19.       if (ret != NO_ERROR) {
  20.           mCurrentState = MEDIA_PLAYER_STATE_ERROR;
  21.       }
  22.   } else {
  23.       ret = INVALID_OPERATION;
  24.   }
  25.   mLockThreadId = 0;
  26.   return ret;
  27. }
复制

提前设置配置部分配置,不过最终还是调用BpMediaPlayer中的方法。

对于其他的方法,其实也是调用BpMediaPlayer中的,这个后面继续分析。

参考文章

  1. MediaPlayer java层介绍

  2. Android 音频子系统,音频系统跟应用层直接相关的部分(八)

  3. interface_cast简介

  4. android 系统核心机制binder(04)binder C++层 TestServer分析

相关文章

暂无评论

none
暂无评论...