Android MediaPlayer学习笔记

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& service(getMediaPlayerService());
    if (service != 0) {
        sp player(service->create(getpid(), this, mAudioSessionId));                  
        if ((NO_ERROR != doSetRetransmitEndpoint(player)) ||
            (NO_ERROR != player->setDataSource(fd, offset, length))) {
            player.clear();
        }
        err = attachNewPlayer(player);
    }
    return err;
}

 2) sp player(service->create(getpid(), this, mAudioSessionId))调用的是BpMediaPlayerService的create,   remote()->transact(CREATE, data, &reply)调用通过Binder传到MediaPlayerService,再调用其的create函数,其返回了一个MediaPlayerService::Client的实例,返回后到interface_cast(reply.readStrongBinder())这一句,这里有个interface_cast,这是在干什么呢?

在Java里每次new出一个MediaPlayer,在服务端也会新建一个实例。

    virtual sp create(
            pid_t pid, const sp& client, int audioSessionId) {
        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(reply.readStrongBinder());
    }


sp MediaPlayerService::create(pid_t pid, const sp& client,
        int audioSessionId)
{
    int32_t connId = android_atomic_inc(&mNextConnId);

    sp 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 w = c;
    {
        Mutex::Autolock lock(mLock);
        mClients.add(w);
    }
    return c;
}
 
 3) interface_cast是在IInterface.h里定义的如下:

template
inline sp interface_cast(const sp& obj)
{
    return INTERFACE::asInterface(obj);
}
代入IMediaPlayer后如下:

template
inline sp interface_cast(const sp& obj)
{
    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 p = setDataSource_pre(playerType);
 在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(p.get())->setAudioSink(mAudioOutput);
    }

3. 在AudioTrack也是一个通过Binder来通信的家伙,主要来用在MediaPlayerService和AudioFlinger两个进程之间通信,一步一步来:

在AudioTrack的构造函数里会调用mStatus = set(...),set调用createTrack_l,进去后调用sp track = audioFlinger->createTrack(...),audioFlinger是一个服务,所以这里就跳到IAudioFlinger.cpp文件里的类BpAudioFlinger里的createTrack函数,通过Binder,到BnAudioFlinger里面:CREATE_TRACK,sp track = createTrack(...),这里的createTrack是AudioFlinger.cpp文件里的AudioFlinger::createTrack(...),其返回的就是一个new TrackHandle(track)。TrackHandle从BnAudioTrack里继承而来。我们走了这么远终于看到在MediaPlayerService::AudioOut里的诸如start,stop,pause等调用都会传到这里。而这个的实现就是通过IAudioTrack来通信。当然, TrackHandle也没有做任何的处理,而是全部丢给了AudioFlinger::PlaybackThead::Track的函数。这里才是这个这几个函数的最终归宿。

一路分析而来,突然有一种感受,那就是我们平时听说的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->pointer());

cblk是从AudioFlinger里分配来的,以下内容来处AudioFlinger.cpp:

    sp cblk = track->getCblk();

    sp track = audioFlinger->createTrack(getpid(),...)

在AudioFlinger里面它也叫做mCblkMemory:

    virtual sp getCblk() const { return mCblkMemory; }

在TrackBase构造函数里做如下调用:

mCblkMemory = client->heap()->allocate(size);

client又是什么呢?

   client = registerPid_l(pid);  client是在这个调用里new出来的。

heap()函数:

sp AudioFlinger::Client::heap() const

{
    return mMemoryDealer;
}

mMemoryDealer是一个MemoryDealer对象,所以allocate在MemoryDealer.cpp里:

sp MemoryDealer::allocate(size_t size)
{
    sp memory;
    const ssize_t offset = allocator()->allocate(size);
    if (offset >= 0) {
        memory = new Allocation(this, heap(), offset, size);
    }
    return memory;
}

你可能感兴趣的:(Android)