Android 13(T) - Media框架(3)- mediaserver

上一节我们了解到android_media_MediaPlayer.cpp中封装的是MediaPlayer native实现,这一节我们就来了解它的内部实现。

1、MediaPlayer

MediaPlayer native代码位于frameworks/av/media/libmedia/mediaplayer.cpp

先来看MediaPlayer的声明,它继承于BnMediaPlayerClient,包含一个IMediaPlayer成员以及一个notify方法。

cpp 复制代码
class MediaPlayer : public BnMediaPlayerClient,
                    public virtual IMediaDeathNotifier
{
	sp<IMediaPlayer>            mPlayer;
	void            notify(int msg, int ext1, int ext2, const Parcel *obj = NULL);
}
  • mPlayer是通过mediaserver获取到的;
  • notify用于底层向上callback;
  • 继承于BnMediaPlayerClient是因为MediaPlayer对象会通过binder传递给IMediaPlayer,从而实现callback功能,从IMediaPlayerClient.h中可以看到binder接口只有一个notify;

callback用的比较多方法的是声明一个ICallback对象,里面存储有上层对象,将这个ICallback通过binder传递到底层,而不是将上层对象直接传递下去,这里的用法比较少见,可以学习一下~

接下来看如何获取IMediaPlayer对象的:

cpp 复制代码
status_t MediaPlayer::setDataSource(
        const sp<IMediaHTTPService> &httpService,
        const char *url, const KeyedVector<String8, String8> *headers)
{
    status_t err = BAD_VALUE;
    if (url != NULL) {
    	// 获取MediaPlayerService
        const sp<IMediaPlayerService> service(getMediaPlayerService());
        if (service != 0) {
        	// create player
            sp<IMediaPlayer> player(service->create(this, mAudioSessionId, mAttributionSource));
            // call setDataSource
            player->setDataSource(httpService, url, headers);
            // save player
            err = attachNewPlayer(player);
        }
    }
    return err;
}
  1. 先获取media.player服务;
  2. 调用服务的create方法创建本地IMediaPlayer对象,并将自身作为参数传递,返回IMediaPlayer的远程代理;
  3. 调用IMediaPlayersetDataSource方法;
  4. IMediaPlayer对象存储到mPlayer

IMediaPlayer的销毁流程如下:

cpp 复制代码
void MediaPlayer::disconnect()
{
    sp<IMediaPlayer> p;
    {
        Mutex::Autolock _l(mLock);
        p = mPlayer;
        mPlayer.clear();
    }

    if (p != 0) {
        p->disconnect();
    }
}
  1. 调用IMediaPlayer的disconnect方法
  2. 离开disconnect函数作用域,IMediaPlayer自动销毁

MediaPlayer::disconnect中会先加锁,接着将mPlayer赋给一个新的局部变量p,然后释放掉mPlayer的内容。为什么要这么做?我猜想是为了缩短锁占用的时间。

最后来看callback方法notify,这个方法可以透过binder来跨进程调用,所以最后一个自定义的数据类型是Parcel。底层调用notify后,mediaplayer native会根据事件类型判断是否再将事件上抛。

cpp 复制代码
void MediaPlayer::notify(int msg, int ext1, int ext2, const Parcel *obj)
{
    ALOGV("message received msg=%d, ext1=%d, ext2=%d", msg, ext1, ext2);
    bool send = true;
    ....
    sp<MediaPlayerListener> listener = mListener;
	...
    if ((listener != 0) && send) {
        Mutex::Autolock _l(mNotifyLock);
        listener->notify(msg, ext1, ext2, obj);
    }
}

2、MediaServer

上一节我们了解了MediaPlayer native封装的是一个IMediaPlayer对象,这个对象是由mediaserver这个binder service创建的,这一节我们就来了解mediaserver

mediaserver服务的启动代码位于frameworks/av/media/mediaserver/main_mediaserver.cpp

cpp 复制代码
int main(int argc __unused, char **argv __unused)
{
	......
    MediaPlayerService::instantiate();
    ResourceManagerService::instantiate();
	......
}

mediaserver其实提供有两个服务,一个是MediaPlayerService(media.player),另一个是资源管理服务ResourceManagerService(media.resource_manager),这里我们仅了解MediaPlayerService。


3、MediaPlayerService

相关推荐
robotx2 小时前
安卓线程相关
android
消失的旧时光-19433 小时前
Android 面试高频:JSON 文件、大数据存储与断电安全(从原理到工程实践)
android·面试·json
dalancon4 小时前
VSYNC 信号流程分析 (Android 14)
android
dalancon4 小时前
VSYNC 信号完整流程2
android
dalancon4 小时前
SurfaceFlinger 上帧后 releaseBuffer 完整流程分析
android
用户69371750013845 小时前
不卷AI速度,我卷自己的从容——北京程序员手记
android·前端·人工智能
程序员Android5 小时前
Android 刷新一帧流程trace拆解
android
墨狂之逸才6 小时前
解决 Android/Gradle 编译报错:Comparison method violates its general contract!
android
阿明的小蝴蝶7 小时前
记一次Gradle环境的编译问题与解决
android·前端·gradle
汪海游龙7 小时前
开源项目 Trending AI 招募 Google Play 内测人员(12 名)
android·github