Android的MediaPlayer应该算是一个大的子系统,整个流程比较长,不过好的是流程还比较清晰,代码跟起来也不是很难。
MediaPlayer是从MediaPlayer.java开始的,应用如果想播放音乐,先要new 一个MediaPlayer,并设置其相关的参数。
先列出主要的代码文件,他们都在frameworks里面:
Java层代码:
base/media/java/android/media/MediaPlayer.java
Jni层代码:
base/media/jni/android_media_MediaPlayer.cpp
本地代码:
av/media/libmedia/mediaplayer.cpp
./av/media/libmedia/IMediaPlayer.cpp
MediaPlayerService:
av/media/libmediaplayerservice/MediaPlayerService.cpp
这里MediaPlayerService里的内部类Client从BnMediaPlayer继承,从IMediaPlayer的BnMediaPlayer里的调用会到这里;然后又会跳到AudioOutput里,这个类是从MediaPlayerInterface.h里的MediaPlayerBase::AudioSink继承而来。
在新建一个MediaPlayer时会调用setDataSource这个函数,这个函数会调用MediaPlayerFactory::getPlayerType,根据播放文件的类型选择合适的播放器。
av/media/libmedia/AudioTrack.cpp
av/media/libmedia/IAudioTrack.cpp
av/services/audioflinger/AudioFlinger.cpp
1. 新建一个MediaPlayer的实例:
1)Java中new出一个MediaPlayer实例后,紧接着就会调用setDataSource,调用传到mediaplayer.java中会调用:
status_t MediaPlayer::setDataSource(int fd, int64_t offset, int64_t length)
{
ALOGV("setDataSource(%d, %lld, %lld)", fd, offset, length);
status_t err = UNKNOWN_ERROR;
// 得到MediaPlayerService的BpMediaPlayerService引用
const sp
if (service != 0) {
sp
if ((NO_ERROR != doSetRetransmitEndpoint(player)) ||
(NO_ERROR != player->setDataSource(fd, offset, length))) {
player.clear();
}
err = attachNewPlayer(player);
}
return err;
}
2) sp
在Java里每次new出一个MediaPlayer,在服务端也会新建一个实例。
virtual sp
pid_t pid, const sp
Parcel data, reply;
data.writeInterfaceToken(IMediaPlayerService::getInterfaceDescriptor());
data.writeInt32(pid);
data.writeStrongBinder(client->asBinder());
data.writeInt32(audioSessionId);
remote()->transact(CREATE, data, &reply);
return interface_cast
}
sp
int audioSessionId)
{
int32_t connId = android_atomic_inc(&mNextConnId);
sp
this, pid, connId, client, audioSessionId,
IPCThreadState::self()->getCallingUid());
ALOGV("Create new client(%d) from pid %d, uid %d, ", connId, pid,
IPCThreadState::self()->getCallingUid());
wp
{
Mutex::Autolock lock(mLock);
mClients.add(w);
}
return c;
}
3) interface_cast是在IInterface.h里定义的如下:
template
inline sp
{
return INTERFACE::asInterface(obj);
}
代入IMediaPlayer后如下:
template
inline sp
{
return IMediaPlayer::asInterface(obj);
}
asInterface(obj)的定义也在这个文件中,在其定义中返回了new BpMediaPlayer的实例,所以在1)中的player其实就是BpMediaPlayer的强引用。后面的player->setDataSource(fd, offset, length)调用的就是BpMediaPlayer里的函数,通过Binder,会传到BnMediaPlayer,BnMediaPlayer又是MediaPlayerService::Client的父类,最终其实就是在调用MediaPlayerService::Client的函数。
2. setDataSource函数,这是一个很重要的函数,在MediaPlayerService::Client中的setDataSource,会根据播放文件的类型选择合适的播放器。setDataSource_pre会调用createPlayer(),然后调用MediaPlayerFactory::createPlayer(playerType, this, notify),返回播放器的实例。
player_type playerType = MediaPlayerFactory::getPlayerType(this,
fd,
offset,
length);
sp
在setDataSource_pre中接着new AudioOutput,最后一句把mAudioOutput传到MediaPlayerInterface中,又因为播放器都是从类MediaPlayerInterface中继承而来,比如class StagefrightPlayer : public MediaPlayerInterface,所以播放器可以通过这个来操作AudioOutput里的函数。AudioOutput里的函数大都通过AudioTrack的函数来操作,AudioTrack是在status_t MediaPlayerService::AudioOutput::open(...)这个函数里new出来的。
if (!p->hardwareOutput()) {
mAudioOutput = new AudioOutput(mAudioSessionId);
static_cast
}
3. 在AudioTrack也是一个通过Binder来通信的家伙,主要来用在MediaPlayerService和AudioFlinger两个进程之间通信,一步一步来:
在AudioTrack的构造函数里会调用mStatus = set(...),set调用createTrack_l,进去后调用sp
一路分析而来,突然有一种感受,那就是我们平时听说的MediaPlayerService和AudioFlinger都如同人世间一样,风光的都是这些大哥们,实际是干活的都是它们下面的小弟。大哥们只负责把工作接过来,然后就丢给任劳任怨的小弟们。
4. 我们都知道在音乐或其他声音播放过程中一定会有一个循环,用来向Buffer里面填数据,这样音乐就能一直播放,直到播放完成。那我们的这个循环在哪里实现的呢?
在StagefrightPlayer里的AwesomePlayer里,有个AudioPlayer,这个类下面有个fillBuffer函数,看名字就知道它是用来填Buffer的。只要我们跟踪这个函数的调用源头就一定能找到这个循环。AudioSinkCallback(AudioPlayer) <-- start(AudioPlayer) <-- mAudioSink->open(MediaPlayerService::AudioOutput) <-- CallbackWrapper (MediaPlayerService::AudioOutput) <-- new AudioTrack(..., CallbackWrapper,...)(MediaPlayerService::AudioOutput) <-- set (AudioTrack) <-- mCbf = cbf(AudioTrack) <-- processAudioBuffer (AudioTrack), processAudioBuffer这个函数里进行了多次调用mCbf。而processAudioBuffer正是新new出来的一个线程AudioTrackThread里的threadLoop里调用的。所以这个循环我们就找到了。它就是processAudioBuffer这个函数。根据threadLoop的定义,只要其不返回false,就会一直调用threadLoop,循环就跑起来了。
5. 另一个问题:Buffer是怎么分配的?
status_t AudioTrack::obtainBuffer(Buffer* audioBuffer, int32_t waitCount)
audio_track_cblk_t* cblk = mCblk;
mCblkMemory是整个内存块,mCblk只是内存块中audio_track_cblk_t的一部分,当然是啊前面的那部分:
mCblkMemory = cblk;
通过cblk->pointer(),即IMemory里的pointer(),获得申请好的内存块,这块内存中包含了audio_track_cblk_t,这里用static_cast进行指针转换后得到audio_track_cblk_t结构的地址。我的理解是申请的这块内存一开始是空的,对audio_track_cblk_t的修改可以做一些控制,stop()调用其实就是把loopStart,loopEnd,loopCount三个值写为0。
mCblk = static_cast
cblk是从AudioFlinger里分配来的,以下内容来处AudioFlinger.cpp:
sp
sp
在AudioFlinger里面它也叫做mCblkMemory:
virtual sp
在TrackBase构造函数里做如下调用:
mCblkMemory = client->heap()->allocate(size);
client又是什么呢?
client = registerPid_l(pid); client是在这个调用里new出来的。
heap()函数:
sp
{
return mMemoryDealer;
}
mMemoryDealer是一个MemoryDealer对象,所以allocate在MemoryDealer.cpp里:
sp
{
sp
const ssize_t offset = allocator()->allocate(size);
if (offset >= 0) {
memory = new Allocation(this, heap(), offset, size);
}
return memory;
}