mediaplayer在native层的C/S架构关系

一、前言:
本文内容旨在分析native层中mediaplayer是如何获取mediaplayerservice服务的以及他们之间是如何建立联系的,内容前提是建立在你已经知道mediaplayer从java到jni的调用并且熟悉Android中的binder机制。

二、mediaserver的建立:
还是老生常谈的mediaserver的建立:

frameworks\av\media\mediaserver\main_mediaserver.cpp

		...
        sp<ProcessState> proc(ProcessState::self());
        sp<IServiceManager> sm = defaultServiceManager();
        ALOGI("ServiceManager: %p", sm.get());
        AudioFlinger::instantiate();
        MediaPlayerService::instantiate();
        CameraService::instantiate();
        AudioPolicyService::instantiate();
        SoundTriggerHwService::instantiate();
        ...
        registerExtensions();
        ProcessState::self()->startThreadPool();
        IPCThreadState::self()->joinThreadPool();

以上代码摘自文件中的main函数,在Android系统的init.rc启动脚本中,会去执行mediaserver代码,就会运行到这一段,这是binder中service端的典型代码,从代码中可以看到,一共建立了5个服务,xxx::instantiate完成的操作就是将对应的服务添加到service manager中;

三、 mediaplayer绑定服务:
mediaplayer获取mediaserver是从setdatasource开始的:

frameworks\av\media\libmedia\mediaplayer.cpp

上层调用setdatasource播放文件的时候,会分为本地场景和URL场景,这里以本地播放场景为例,贴出代码如下:

status_t MediaPlayer::setDataSource(int fd, int64_t offset, int64_t length)
{
    ALOGV("setDataSource(%d, %" PRId64 ", %" PRId64 ")", fd, offset, length);
    status_t err = UNKNOWN_ERROR;
    /* 1.获取mediaserver */
    const sp<IMediaPlayerService>& service(getMediaPlayerService());
    if (service != 0) {
    	/* 2.在service端创建名为client的Bn */
        sp<IMediaPlayer> player(service->create(this, mAudioSessionId));
        if(mRenderMode == RENDER_MODE_VR){
            player->setRenderMode(mRenderMode);
        }

        if ((NO_ERROR != doSetRetransmitEndpoint(player)) ||
        	/* 3.调用client中的setdatasource */
            (NO_ERROR != player->setDataSource(fd, offset, length))) {
            player.clear();
        }
        /* 4.绑定Bn的client至此 */
        err = attachNewPlayer(player);
    }
    return err;
}

这段代码分4部分分析:

  1. getMediaPlayerService();
    代码实现在如下路径

frameworks\av\media\libmedia\IMediaDeathNotifier.cpp

IMediaDeathNotifier::getMediaPlayerService()
{
    ALOGV("getMediaPlayerService");
    Mutex::Autolock _l(sServiceLock);
    if (sMediaPlayerService == 0) {
        sp<IServiceManager> sm = defaultServiceManager();
        sp<IBinder> binder;
        do {
            binder = sm->getService(String16("media.player"));
            if (binder != 0) {
                break;
            }
            ALOGW("Media player service not published, waiting...");
            usleep(500000); // 0.5 s
        } while (true);
		...
    }
	...
}

从service manager获取服务;

  1. 绕过中间的匿名binder,直接到Bn端看实现,也就是mediaplayerservice,分析下create函数:
sp<IMediaPlayer> MediaPlayerService::create(const sp<IMediaPlayerClient>& client,
        int 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());

    ALOGV("Create new client(%d) from pid %d, uid %d, ", connId, pid,
         IPCThreadState::self()->getCallingUid());

    wp<Client> w = c;
    {
        Mutex::Autolock lock(mLock);
        mClients.add(w);
    }
    return c;
}

这里的client,是mediaplayerservice的内部类,里面的接口跟IMediaPlayer.h中是一一对应的,贴一下类的继承:

class Client : public BnMediaPlayer

这里就比较明朗了,client就是Bn的子类,也就是在binder中,service端最终调用的地方;

  1. 理解了第二步,这里的setDataSource就明白了,是调用的mediaplayerservice中client的setdatasource函数:
status_t MediaPlayerService::Client::setDataSource(int fd, int64_t offset, int64_t length)
{
	...
    player_type playerType = MediaPlayerFactory::getPlayerType(this,
                                                               fd,
                                                               offset,
                                                               length);
    sp<MediaPlayerBase> p = setDataSource_pre(playerType);
    if (p == NULL) {
        return NO_INIT;
    }

	...
}

这里面就是下层业务逻辑了,从factory中找到一个最适合的播放器,然后去播放对应的码流;

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 != mPlayer)) {
        p->disconnect();
    }

    return err;
}

核心就一个,将mediaplayerservice中的client赋值给这里的mPlayer ;

三、 总结:
mediaplayer首先去获取service,然后让service端创建一个client,这个client实际上就是mediaplayer中的Bn端,之后,mediaplayer的所有调用接口就直接通过mediaplayer的client来实现了;

在这里插入图片描述

发布了36 篇原创文章 · 获赞 35 · 访问量 3022
展开阅读全文

没有更多推荐了,返回首页

©️2019 CSDN 皮肤主题: 书香水墨 设计师: CSDN官方博客

分享到微信朋友圈

×

扫一扫,手机浏览