Android audio and video entry-development (3) C ++ MediaPlayer in the C / S structure

One in front, all calls to the Java JNI layer by layer, and the layer down to the C ++ JNI layer is not introduced.
This section first analysis a Java function layer in the C ++ layer MediaPlayer. (Path: /frameworks/av/media/libmedia/mediaplayer.cpp)

After below with reference mp-> setDataSource (), the C ++ layer setDataSource()to look at the process of C / S Mode

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;
        //通过IMediaPlayerService获取service端的MediaPlayerService
        const sp<IMediaPlayerService> service(getMediaPlayerService());
        if (service != 0) {
            //如果Service不为空,则调用service的create函数
            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;
    }

setDataSource get to IMediaPlayerService, we all know, the class name of this band I, are generally server-side classes in the proxy client , we call its methods, is actually a method that removing the I class of server calls , so we have to /frameworks/av/media/libmediaplayerservice/MediaPlayerService.cpp go inside and take it service the create process. And this time, the angle of the code came to S (service) from layer C (Client):

    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);
        //表示校验调用仿的uid,用来进行身份验证
        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());

        //把构造的Client强引用对象赋值成 弱引用对象
        wp<Client> w = c;
        {
            Mutex::Autolock lock(mLock);
            //mClient声明为 SortedVector< wp<Client> >
            mClients.add(w);
        }
        return c;
    }

create summary:
incoming clientId and Pid, ConnId authentication, create a Client-side referenced in the Service, and the strong reference into a weak reference.
Created through a process IPCThreadState, each thread has an IPCThreadStateinstance of the subsidiary level in the context of Linux thread data. Binder is responsible for reading, writing and request processing.

In fact, get a reference to it in a Client's Service Layer . Client can not get to communicate with each other yet -
and this Client is specifically refer to what generation we see and discover from one of the C / S figure, in the header file Client is inherited BnMediaPlayer, and contains IMediaPlayer related interfaces .

In summary, the inheritance relationship Client -> BnMediaPlayer -> IMediaPlayer. create, create a Client Client and add this to the global list mClients, this mClients is a SortedVector, followed by a player- perform in the Client> setDataSource (url, headers), namely Client :: setDataSource. It can be directly considered player == client

So in C ++, the Client and MediaPlayer is what to do with it?

  • Client is MediaPlayerService internal classes, from the code above is known as MediaPlayerService executed on the server, it is also executed on the server Client
  • Client in MediaPlayerService.h in, then take a look at that to realize MediaPlayerService Invoke implementation process some MediaPlayerService functions, the same back serDataSource (), the code is as follows:
        //判断是否通过contentprovider提供的数据
        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 {
            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));
        }
    }

Client, and the function is a bottom view and (seen in the previous section) corresponding to:
Here Insert Picture Description
the beginning of the code, the last executederr =attachNewPlayer(player)

status_t MediaPlayer::attachNewPlayer(const sp<IMediaPlayer>& player)
{
    status_t err = UNKNOWN_ERROR;
    //IMediaPlayer就是Client声明在客户端处的代理类
    sp<IMediaPlayer> p;
    { 
        //加锁
        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();
        //赋值给代理类,mPlayer在MediaPlayer.h中声明,
        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;
}

上面的函数,一个是MediaPlayer的setDataSource,会调用到attachNewPlayer(),这个函数最终会调用服务器端Client对应的函数。
这时候出现IMediaPlayer.hmediaplayer.hImediaPlayerClient.h,看的人都晕了,这个时候来分别看一下:

  • 从包结构上:IMediaPlayer和IMediaPlayerClient.h都在 /frameworks/av/media/libmedia中,而mediaplayer.h在/av/include/media中
  • 从功能上:他们的责任也不一样

而IMediaPlayer.h中都是虚函数,所以它的功能是作为 MediaPlayer功能的接口。
接下来来看看IMediaPlayerClient.h:

namespace android {

enum {
    NOTIFY = IBinder::FIRST_CALL_TRANSACTION,
};

class BpMediaPlayerClient: public BpInterface<IMediaPlayerClient>
{
public:
    explicit BpMediaPlayerClient(const sp<IBinder>& impl)
        : BpInterface<IMediaPlayerClient>(impl)
    {
    }

    virtual void notify(int msg, int ext1, int ext2, const Parcel *obj)
    {
        Parcel data, reply;
        data.writeInterfaceToken(IMediaPlayerClient::getInterfaceDescriptor());
        data.writeInt32(msg);
        data.writeInt32(ext1);
        data.writeInt32(ext2);
        if (obj && obj->dataSize() > 0) {
            data.appendFrom(const_cast<Parcel *>(obj), 0, obj->dataSize());
        }
        remote()->transact(NOTIFY, data, &reply, IBinder::FLAG_ONEWAY);
    }
};

IMPLEMENT_META_INTERFACE(MediaPlayerClient, "android.media.IMediaPlayerClient");

// ----------------------------------------------------------------------

status_t BnMediaPlayerClient::onTransact(
    uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
{
    switch (code) {
        case NOTIFY: {
            CHECK_INTERFACE(IMediaPlayerClient, data, reply);
            int msg = data.readInt32();
            int ext1 = data.readInt32();
            int ext2 = data.readInt32();
            Parcel obj;
            if (data.dataAvail() > 0) {
                obj.appendFrom(const_cast<Parcel *>(&data), data.dataPosition(), data.dataAvail());
            }

            notify(msg, ext1, ext2, &obj);
            return NO_ERROR;
        } break;
        default:
            return BBinder::onTransact(code, data, reply, flags);
    }
}

}

来总结一下上面的代码:
在内部定义一个 BpMediaPlayerClient,也就是Client的父类。然后有一个onTranscat(),它是Binder通信中的回到函数。
所以说前面的player是C/S模式,IMediaPlayerClient.h的功能时一个MediaPlayer客户端的接口。

综上所述:

  1. mediaplayer.h的功能时对外(JNI层)的接口类,它最主要的是定义了一个MediaPlayer类(C++层),我们在android_media_MediaPlayer.cpp中就引入了 media/mediaplayer.
  2. IMediaPlayer.h则是一个实现 MediaPlayer(C++)功能的接口
  3. IMediaPlayerClient.h的功能时描述一个MediaPlayer(这里暂且为前面说的Client)客户端的接口
Published 248 original articles · won praise 99 · Views 100,000 +

Guess you like

Origin blog.csdn.net/rikkatheworld/article/details/102916252