frameworks\base\media\java\android\media\MediaPlayer.java
首先明确一点:MediaPlayer只是向java层暴露了具体播放的接口,其具体实现都是通过JNI接口调用c++代码实现的;
先看一个简单的接口 :start(); 他调用了native层的 _start() 方法
public void start() throws IllegalStateException { //FIXME use lambda to pass startImpl to superclass final int delay = getStartDelayMs(); if (delay == 0) { startImpl(); } else { new Thread() { public void run() { try { Thread.sleep(delay); } catch (InterruptedException e) { e.printStackTrace(); } baseSetStartDelayMs(0); try { startImpl(); } catch (IllegalStateException e) { // fail silently for a state exception when it is happening after // a delayed start, as the player state could have changed between the // call to start() and the execution of startImpl() } } }.start(); } }
private void startImpl() { baseStart(0); // unknown device at this point stayAwake(true); tryToEnableNativeRoutingCallback(); _start(); } private native void _start() throws IllegalStateException;
JNI也是用Native语言编写的,它属于Native层。但是为了便于学习和分析,我们将与JNI相关的代码划 分到JNI层,JNI层是Native层的一部分。
JNI是 Java Native Interface的缩写,通过JNI可以让Java方法与Native方法相互调用,其中Native方法一般是用 C/C++编写的。因此,JNI就是连接Java层和Native层的桥梁。要使用JNI需要先加载JNI库,在 MediaPlayer.java中有如下代码
static { System.loadLibrary("media_jni"); native_init(); }
在静态代码块中加载JNI库,并调用native_init方法。这里加载的名为"media_jni"的 JIN 库指的是 libmedia.so。
MediaPlayer 的 JNI 层的代码在 frameworks/base/media/jni/android_media_MediaPlayer.cpp中。我们需要通过JNI调用Native方法,那么就应该有一个结构来保存Java层Native方法与JNI层方法的对应关系,这个结构就是 android_media_MediaPlayer.cpp中定义的JNINativeMethod数组,代码如下所示
static const JNINativeMethod gMethods[] = { { "nativeSetDataSource", "(Landroid/os/IBinder;Ljava/lang/String;[Ljava/lang/String;" "[Ljava/lang/String;)V", (void *)android_media_MediaPlayer_setDataSourceAndHeaders }, {"_setDataSource", "(Ljava/io/FileDescriptor;JJ)V", (void *)android_media_MediaPlayer_setDataSourceFD}, {"_setDataSource", "(Landroid/media/MediaDataSource;)V",(void *)android_media_MediaPlayer_setDataSourceCallback }, {"_setVideoSurface", "(Landroid/view/Surface;)V", (void *)android_media_MediaPlayer_setVideoSurface}, {"_prepare", "()V", (void *)android_media_MediaPlayer_prepare}, {"prepareAsync", "()V", (void *)android_media_MediaPlayer_prepareAsync}, {"_start", "()V", (void *)android_media_MediaPlayer_start}, {"_stop", "()V", (void *)android_media_MediaPlayer_stop}, {"getVideoWidth", "()I", (void *)android_media_MediaPlayer_getVideoWidth}, {"getVideoHeight", "()I", (void *)android_media_MediaPlayer_getVideoHeight}, {"native_getMetrics", "()Landroid/os/PersistableBundle;", (void *)android_media_MediaPlayer_native_getMetrics}, {"setPlaybackParams", "(Landroid/media/PlaybackParams;)V", (void *)android_media_MediaPlayer_setPlaybackParams}, {"getPlaybackParams", "()Landroid/media/PlaybackParams;", (void *)android_media_MediaPlayer_getPlaybackParams}, {"setSyncParams", "(Landroid/media/SyncParams;)V", (void *)android_media_MediaPlayer_setSyncParams}, {"getSyncParams", "()Landroid/media/SyncParams;", (void *)android_media_MediaPlayer_getSyncParams}, {"_seekTo", "(JI)V", (void *)android_media_MediaPlayer_seekTo}, {"_notifyAt", "(J)V", (void *)android_media_MediaPlayer_notifyAt}, {"_pause", "()V", (void *)android_media_MediaPlayer_pause}, {"isPlaying", "()Z", (void *)android_media_MediaPlayer_isPlaying}, {"getCurrentPosition", "()I", (void *)android_media_MediaPlayer_getCurrentPosition}, {"getDuration", "()I", (void *)android_media_MediaPlayer_getDuration}, {"_release", "()V", (void *)android_media_MediaPlayer_release}, {"_reset", "()V", (void *)android_media_MediaPlayer_reset}, {"_setAudioStreamType", "(I)V", (void *)android_media_MediaPlayer_setAudioStreamType}, {"_getAudioStreamType", "()I", (void *)android_media_MediaPlayer_getAudioStreamType}, {"setParameter", "(ILandroid/os/Parcel;)Z", (void *)android_media_MediaPlayer_setParameter}, {"setLooping", "(Z)V", (void *)android_media_MediaPlayer_setLooping}, {"isLooping", "()Z", (void *)android_media_MediaPlayer_isLooping}, {"_setVolume", "(FF)V", (void *)android_media_MediaPlayer_setVolume}, {"native_invoke", "(Landroid/os/Parcel;Landroid/os/Parcel;)I",(void *)android_media_MediaPlayer_invoke}, {"native_setMetadataFilter", "(Landroid/os/Parcel;)I", (void *)android_media_MediaPlayer_setMetadataFilter}, {"native_getMetadata", "(ZZLandroid/os/Parcel;)Z", (void *)android_media_MediaPlayer_getMetadata}, {"native_init", "()V", (void *)android_media_MediaPlayer_native_init}, {"native_setup", "(Ljava/lang/Object;Landroid/os/Parcel;)V",(void *)android_media_MediaPlayer_native_setup}, {"native_finalize", "()V", (void *)android_media_MediaPlayer_native_finalize}, {"getAudioSessionId", "()I", (void *)android_media_MediaPlayer_get_audio_session_id}, {"native_setAudioSessionId", "(I)V", (void *)android_media_MediaPlayer_set_audio_session_id}, {"_setAuxEffectSendLevel", "(F)V", (void *)android_media_MediaPlayer_setAuxEffectSendLevel}, {"attachAuxEffect", "(I)V", (void *)android_media_MediaPlayer_attachAuxEffect}, {"native_pullBatteryData", "(Landroid/os/Parcel;)I", (void *)android_media_MediaPlayer_pullBatteryData}, {"native_setRetransmitEndpoint", "(Ljava/lang/String;I)I", (void *)android_media_MediaPlayer_setRetransmitEndpoint}, {"setNextMediaPlayer", "(Landroid/media/MediaPlayer;)V", (void *)android_media_MediaPlayer_setNextMediaPlayer}, {"native_applyVolumeShaper", "(Landroid/media/VolumeShaper$Configuration;Landroid/media/VolumeShaper$Operation;)I", (void *)android_media_MediaPlayer_applyVolumeShaper}, {"native_getVolumeShaperState", "(I)Landroid/media/VolumeShaper$State;", (void *)android_media_MediaPlayer_getVolumeShaperState}, // Modular DRM { "_prepareDrm", "([B[B)V", (void *)android_media_MediaPlayer_prepareDrm }, { "_releaseDrm", "()V", (void *)android_media_MediaPlayer_releaseDrm }, // AudioRouting {"native_setOutputDevice", "(I)Z", (void *)android_media_MediaPlayer_setOutputDevice}, {"native_getRoutedDeviceId", "()I", (void *)android_media_MediaPlayer_getRoutedDeviceId}, {"native_enableDeviceCallback", "(Z)V", (void *)android_media_MediaPlayer_enableDeviceCallback}, };
从上面来看,JNINativeMethod数组有3个参数。
• 第一个参数,比如"_prepare",它是Java 层Native 方法的名称。在Java层调用Native方法,交由JNI层来 实现。
• 第二个参数是 Java 层 Native 方法的参数和返回值。其中()中的字符代表参数,后面的字母则代表 返回值。
• 第三个参数是Java层Native方法对应的JNI层的方法,比如_prepare方法对应JNI层的方法为 android_media_MediaPlayer_prepare。通过JNI层的方法就可以调用Native层相应的方法
前面在MediaPlayer.java的静态代码块中调用了native_init方法,这个方法是一个Native方法,查询 JNINativeMethod数组,它对应的是android_media_MediaPlayer_native_init方法,如下所示:
// This function gets some field IDs, which in turn causes class initialization. // It is called from a static block in MediaPlayer, which won't run until the // first time an instance of this class is used. static void android_media_MediaPlayer_native_init(JNIEnv *env) { jclass clazz; //JNI层调用Java层,获取MediaPlayer对象 clazz = env->FindClass("android/media/MediaPlayer"); if (clazz == NULL) { return; } fields.context = env->GetFieldID(clazz, "mNativeContext", "J"); if (fields.context == NULL) { return; } //获取Java层的postEventFromNative方法 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); clazz = env->FindClass("android/net/ProxyInfo"); if (clazz == NULL) { return; } fields.proxyConfigGetHost = env->GetMethodID(clazz, "getHost", "()Ljava/lang/String;"); fields.proxyConfigGetPort = env->GetMethodID(clazz, "getPort", "()I"); fields.proxyConfigGetExclusionList = env->GetMethodID(clazz, "getExclusionListAsString", "()Ljava/lang/String;"); env->DeleteLocalRef(clazz); // Modular DRM FIND_CLASS(clazz, "android/media/MediaDrm$MediaDrmStateException"); if (clazz) { GET_METHOD_ID(gStateExceptionFields.init, clazz, "<init>", "(ILjava/lang/String;)V"); gStateExceptionFields.classId = static_cast<jclass>(env->NewGlobalRef(clazz)); env->DeleteLocalRef(clazz); } else { ALOGE("JNI android_media_MediaPlayer_native_init couldn't " "get clazz android/media/MediaDrm$MediaDrmStateException"); } gPlaybackParamsFields.init(env); gSyncParamsFields.init(env); gVolumeShaperFields.init(env); }
Native层可以通过JNI层来调用Java层代码。
static void android_media_MediaPlayer_start(JNIEnv *env, jobject thiz) { ALOGV("start"); sp<MediaPlayer> mp = getMediaPlayer(env, thiz);//得到MediaPlayer的强指针 if (mp == NULL ) { jniThrowException(env, "java/lang/IllegalStateException", NULL); return; } //通过 JNI 层的android_media_MediaPlayer_start方法调用了 Native 层的 start方法 process_media_player_call( env, thiz, mp->start(), NULL, NULL ); }
MediaPlayer的Native层整体是一个C/S(Client/Server)架构,Client端和Server端运行在两个进程中,它们之间通过Binder机制来进行通信。Client端MediaPlayer对应的动态库是libmedia.so,Server端 MediaPlayerService对应的动态库为libmediaservice.so
1.Client端分析
MediaPlayer Client 端的功能实现定义的头文件为 mediaplayer.h,相应的源文件为
frameworks\av\media\libmedia\mediaplayer.cpp
我们 接着来查看mediaplayer.cpp的prepare方法,如下所示 调用了prepareAsync_l方法
// TODO: In case of error, prepareAsync provides the caller with 2 error codes, // one defined in the Android framework and one provided by the implementation // that generated the error. The sync version of prepare returns only 1 error // code. status_t MediaPlayer::prepare() { ALOGV("prepare"); Mutex::Autolock _l(mLock); mLockThreadId = getThreadId(); if (mPrepareSync) { mLockThreadId = 0; return -EALREADY; } mPrepareSync = true; status_t ret = prepareAsync_l(); if (ret != NO_ERROR) { mLockThreadId = 0; return ret; } if (mPrepareSync) { mSignal.wait(mLock); // wait for prepare done mPrepareSync = false; } ALOGV("prepare complete - status=%d", mPrepareStatus); mLockThreadId = 0; return mPrepareStatus; }
// must call with lock held status_t MediaPlayer::prepareAsync_l() { if ( (mPlayer != 0) && ( mCurrentState & (MEDIA_PLAYER_INITIALIZED | MEDIA_PLAYER_STOPPED) ) ) { if (mAudioAttributesParcel != NULL) { mPlayer->setParameter(KEY_PARAMETER_AUDIO_ATTRIBUTES, *mAudioAttributesParcel); } else { mPlayer->setAudioStreamType(mStreamType); } mCurrentState = MEDIA_PLAYER_PREPARING; return mPlayer->prepareAsync(); } ALOGE("prepareAsync called in state %d, mPlayer(%p)", mCurrentState, mPlayer.get()); return INVALID_OPERATION; }
调用了mPlayer的prepareAsync方法,那么mPlayer指的是什么呢?我们带着这个问题 来查看mediaplayer.cpp的setDataSource方法
status_t MediaPlayer::setDataSource(const sp<IDataSource> &source) { ALOGV("setDataSource(IDataSource)"); status_t err = UNKNOWN_ERROR; //通过getMediaPlayerService方法得到IMediaPlayerService指针 //IMediaPlayerService指针指向的就是MediaPlayer的Service端:MediaPlayerService const sp<IMediaPlayerService> service(getMediaPlayerService()); if (service != 0) { //通过IMediaPlayerService的create方法得到 //IMediaPlayer指针。通过IMediaPlayer指针就可以调用MediaPlayerService所提供的各种功能 sp<IMediaPlayer> player(service->create(this, mAudioSessionId, mAttributionSource)); if ((NO_ERROR != doSetRetransmitEndpoint(player)) || (NO_ERROR != player->setDataSource(source))) { player.clear(); } err = attachNewPlayer(player); } return err; }
status_t MediaPlayer::attachNewPlayer(const sp<IMediaPlayer>& player) { status_t err = UNKNOWN_ERROR; sp<IMediaPlayer> p; { // scope for the lock Mutex::Autolock _l(mLock); if ( !( (mCurrentState & MEDIA_PLAYER_IDLE) || (mCurrentState == MEDIA_PLAYER_STATE_ERROR ) ) ) { ALOGE("attachNewPlayer called in state %d", mCurrentState); return INVALID_OPERATION; } clear_l(); p = mPlayer; mPlayer = player; if (player != 0) { mCurrentState = MEDIA_PLAYER_INITIALIZED; err = NO_ERROR; } else { ALOGE("Unable to create media player"); } } if (p != 0) { p->disconnect(); } return err; }
attachNewPlayer方法将player赋值给mPlayer。因此,前面遗留下的问题得到了解决:mPlayer指的就是 IMediaPlayer指针,调用mPlayer的prepareAsync方法其实就是调用MediaPlayerService的prepareAsync方法。
2.Server端分析
在多媒体架构中除了C/S架构中的Client和Server,还有一个全局的ServiceManager,它用来管理系统中 的各种Service。Client、Server和ServiceManager的关系如图所示。
1.首先Server进程会注册一些Service到ServiceManager中
2.Client要使用某个Service,则需要先到ServiceManager查询Service的相关信息
3.然后Client根据Service的相关信息与Service所在的Server进程建立通信通路,这样Client就可以使用Service了。
Android的多媒体服务是由一个叫作 MediaServer的服务进程提供的,它是一个可执行程序,在Android系统启动时,MediaServer也会被启动。
frameworks\av\media\mediaserver\main_mediaserver.cpp
int main(int argc __unused, char **argv __unused) { signal(SIGPIPE, SIG_IGN); sp<ProcessState> proc(ProcessState::self()); //得到IServiceManager指针,这样我们就可以与另一个进程的ServiceManager进行通信。 sp<IServiceManager> sm(defaultServiceManager()); ALOGI("ServiceManager: %p", sm.get()); //注册服务 MediaPlayerService::instantiate(); ResourceManagerService::instantiate(); registerExtensions(); ::android::hardware::configureRpcThreadpool(16, false); ProcessState::self()->startThreadPool(); IPCThreadState::self()->joinThreadPool(); ::android::hardware::joinRpcThreadpool(); }
frameworks\av\media\libmediaplayerservice\MediaPlayerService.cpp
向 ServiceManager 添加一个名为media.player 的 MediaPlayerService 服务。这样 MediaPlayerService 就被添加到 ServiceManager中,MediaPlayer 就可以通过 字符串"media.player"来查询 MediaPlayerService。
void MediaPlayerService::instantiate() { defaultServiceManager()->addService( String16("media.player"), new MediaPlayerService()); }
MediaPlayer是在setDataSource的getMediaPlayerService方法中查询MediaPlayerService的
frameworks\av\media\libmedia\IMediaDeathNotifier.cpp
// establish binder interface to MediaPlayerService /*static*/const sp<IMediaPlayerService> IMediaDeathNotifier::getMediaPlayerService() { ALOGV("getMediaPlayerService"); Mutex::Autolock _l(sServiceLock); if (sMediaPlayerService == 0) { //得到 IServiceManager 指针 sp<IServiceManager> sm = defaultServiceManager(); sp<IBinder> binder; do { //查询名称为"media.player"的服务。这样MediaPlayer就获取了MediaPlayerService的信息, //通过这些信息就可以与在MediaServer进程中的MediaPlayerService进行通信了 binder = sm->getService(String16("media.player")); if (binder != 0) { break; } ALOGW("Media player service not published, waiting..."); usleep(500000); // 0.5 s } while (true); if (sDeathNotifier == NULL) { sDeathNotifier = new DeathNotifier(); } binder->linkToDeath(sDeathNotifier); sMediaPlayerService = interface_cast<IMediaPlayerService>(binder); } ALOGE_IF(sMediaPlayerService == 0, "no media player service!?"); return sMediaPlayerService; }
当我们调用MediaPlayer的setDataSource方法时,会调用MediaPlayerService 的setDataSource方法: frameworks/av/media/libmediaplayerservice/MediaPlayerService.cpp
status_t MediaPlayerService::Client::setDataSource( const sp<IMediaHTTPService> &httpService, const char *url, const KeyedVector<String8, String8> *headers) { ALOGV("setDataSource(%s)", url); if (url == NULL) return UNKNOWN_ERROR; if ((strncmp(url, "http://", 7) == 0) || (strncmp(url, "https://", 8) == 0) || (strncmp(url, "rtsp://", 7) == 0)) { if (!checkPermission("android.permission.INTERNET")) { return PERMISSION_DENIED; } } if (strncmp(url, "content://", 10) == 0) { // get a filedescriptor for the content Uri and // pass it to the setDataSource(fd) method String16 url16(url); int fd = android::openContentProviderFile(url16); if (fd < 0) { ALOGE("Couldn't open fd for %s", url); return UNKNOWN_ERROR; } status_t status = setDataSource(fd, 0, 0x7fffffffffLL); // this sets mStatus close(fd); return mStatus = status; } else { //获取播放器的类型playerType player_type playerType = MediaPlayerFactory::getPlayerType(this, url); sp<MediaPlayerBase> p = setDataSource_pre(playerType); if (p == NULL) { return NO_INIT; } return mStatus = setDataSource_post( p, p->setDataSource(httpService, url, headers)); } }
sp<MediaPlayerBase> MediaPlayerService::Client::setDataSource_pre( player_type playerType) { ALOGV("player type = %d", playerType); // create the right type of player sp<MediaPlayerBase> p = createPlayer(playerType); }
sp<MediaPlayerBase> MediaPlayerService::Client::createPlayer(player_type playerType) { // determine if we have the right player type sp<MediaPlayerBase> p = getPlayer(); if ((p != NULL) && (p->playerType() != playerType)) { ALOGV("delete player"); p.clear(); } if (p == NULL) { p = MediaPlayerFactory::createPlayer(playerType, mListener, VALUE_OR_FATAL(aidl2legacy_int32_t_pid_t(mAttributionSource.pid))); } if (p != NULL) { p->setUID(VALUE_OR_FATAL(aidl2legacy_int32_t_uid_t(mAttributionSource.uid))); } return p; }
frameworks\av\media\libmediaplayerservice\MediaPlayerFactory.cpp
sp<MediaPlayerBase> MediaPlayerFactory::createPlayer( player_type playerType, const sp<MediaPlayerBase::Listener> &listener, pid_t pid) { sp<MediaPlayerBase> p; IFactory* factory; status_t init_result; Mutex::Autolock lock_(&sLock); if (sFactoryMap.indexOfKey(playerType) < 0) { ALOGE("Failed to create player object of type %d, no registered" " factory", playerType); return p; } factory = sFactoryMap.valueFor(playerType); CHECK(NULL != factory); p = factory->createPlayer(pid); if (p == NULL) { ALOGE("Failed to create player object of type %d, create failed", playerType); return p; } init_result = p->initCheck(); if (init_result == NO_ERROR) { p->setNotifyCallback(listener); } else { ALOGE("Failed to create player object of type %d, initCheck failed" " (res = %d)", playerType, init_result); p.clear(); } return p; }
在Android 6.0中, MediaPlayerFactory 中有 3 个播放器 Factory,分别是 StagefrightPlayerFactory、NuPlayerFactory和 TestPlayerFactory。其中,StagefrightPlayerFactory用于创建Stagefright框架。Stagefright 框架在 Android 2.0 中被引入系统以替代庞大复杂的 OpenCore 框架。但是由于Stagefright 存在严重漏洞,并被黑客所利用,因 此在 Android 7.0 以后中,谷歌去掉了StagefrightPlayerFactory,也就是Stagefright框架。默认的播放器使用谷歌自己研发的NuPlayer框架。NuPlayerFactory的createPlayer方法如下所示
virtual sp<MediaPlayerBase> createPlayer(pid_t pid) { ALOGV(" create NuPlayer"); return new NuPlayerDriver(pid); }