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 IPCThreadState
instance 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:
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.h
,mediaplayer.h
,ImediaPlayerClient.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客户端的接口。
综上所述:
- mediaplayer.h的功能时对外(JNI层)的接口类,它最主要的是定义了一个MediaPlayer类(C++层),我们在android_media_MediaPlayer.cpp中就引入了 media/mediaplayer.
- IMediaPlayer.h则是一个实现 MediaPlayer(C++)功能的接口
- IMediaPlayerClient.h的功能时描述一个MediaPlayer(这里暂且为前面说的Client)客户端的接口