Android Audio 框架简读 <3>

来源:互联网 发布:maxwell软件 百科 编辑:程序博客网 时间:2024/06/11 00:22

上面一篇最后提到Binder,我个人感觉Android系统需要申请内存空间基本上都是Binder完成的,

可以基本认知Binder:Binder在linux层是专门有一个binder驱动层的,这个驱动层可以用于分配设备内存空间.它同时提供接口给其他设备使用,用于分配内存和管理内存,其他设备需要申请内存都需要实现它的接口,通过它提供的接口分配内存和管理内存.

Android Audio 录播都需要分配内存用于存放音频数据,android Audio这个分配是在AudioFlinger核心部分完成的,但是看了很多网上面的说分配内存有两个地方,一个可以是AudioTrack,一个才是AudioFlinger,但是我个人看了很多次这部分源代码,没有发现AudioTrack分配内存的地方,也搜索了关键字 : heap()->allocate ,但是个人觉得AudioTrack应该不可能去申请内存空间,因为数据的操作和使用都是由AudioFlinger完成的---个人观点.

下面看看代码,我个人总是感觉AudioTrack.cpp部分看的不多,因为他最终都是"赖给"AudioFlinger去做事了,所以可以直接从AudioFlinger开始:

sp<IAudioTrack> AudioFlinger::createTrack(        pid_t pid,        audio_stream_type_t streamType,        uint32_t sampleRate,        audio_format_t format,        audio_channel_mask_t channelMask,        int frameCount,        IAudioFlinger::track_flags_t flags,        const sp<IMemory>& sharedBuffer,        audio_io_handle_t output,        pid_t tid,        int *sessionId,        status_t *status){

从上面开始,这里面不涉及其他的,就看看内存分配,函数里面构造一个Track对象:

track = thread->createTrack_l(client, streamType, sampleRate, format,                channelMask, frameCount, sharedBuffer, lSessionId, flags, tid, &lStatus);


进入:这是一个PlaybackThread的内种类:

sp<AudioFlinger::PlaybackThread::Track> AudioFlinger::PlaybackThread::createTrack_l

最终在这里:

 if (!isTimed) {            track = new Track(this, client, streamType, sampleRate, format,                    channelMask, frameCount, sharedBuffer, sessionId, flags);        } else {            track = TimedTrack::create(this, client, streamType, sampleRate, format,                    channelMask, frameCount, sharedBuffer, sessionId);        }


无论isTimed是否成立,最终都会使用new Track(...)这个去构建.可以看下:

AudioFlinger::PlaybackThread::TimedTrack::TimedTrack(            PlaybackThread *thread,            const sp<Client>& client,            audio_stream_type_t streamType,            uint32_t sampleRate,            audio_format_t format,            audio_channel_mask_t channelMask,            int frameCount,            const sp<IMemory>& sharedBuffer,            int sessionId)    : Track(thread, client, streamType, sampleRate, format, channelMask,            frameCount, sharedBuffer, sessionId, IAudioFlinger::TRACK_TIMED),

最后两行.

到Track还没完,因为最终完成是TrackBase,可以看一下Track的构造体:

AudioFlinger::PlaybackThread::Track::Track(            PlaybackThread *thread,            const sp<Client>& client,            audio_stream_type_t streamType,            uint32_t sampleRate,            audio_format_t format,            audio_channel_mask_t channelMask,            int frameCount,            const sp<IMemory>& sharedBuffer,            int sessionId,            IAudioFlinger::track_flags_t flags)    :   TrackBase(thread, client, sampleRate, format, channelMask, frameCount, sharedBuffer, sessionId),

最后一行出现了TrackBase,然后继续跟踪:

if (client != NULL) {        mCblkMemory = client->heap()->allocate(size);

突然出现了一个client,怎么是它分配呢?回过头看看:

sp<IAudioTrack> AudioFlinger::createTrack(        pid_t pid,        audio_stream_type_t streamType,        uint32_t sampleRate,        audio_format_t format,        audio_channel_mask_t channelMask,        int frameCount,        IAudioFlinger::track_flags_t flags,        const sp<IMemory>& sharedBuffer,        audio_io_handle_t output,        pid_t tid,        int *sessionId,        status_t *status){    sp<PlaybackThread::Track> track;    sp<TrackHandle> trackHandle;    sp<Client> client;


初始化:

client = registerPid_l(pid);

(这里面要注意函数名:createTrack和createTrack_l,名字非常相近,不知道android是怎么想的哈).

经过上面的一番折腾内存空间就给分配了.

但是可能又会问,分配内存不是Binder去搞定吗,怎么没看出来呀.

我们把下面这一句话继续展开:

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

heap是谁的?看Client类:

sp<MemoryDealer>    heap() const;

那么MemoryDealer又是什么?allocate又是如何处理的?

virtual sp<IMemory> allocate(size_t size);

终于到IMemory,只要多看一眼前面的createTrack等函数,就会发现它们构造体里面一直传递了一个IMemory的参数,不过这个传递进来的不是用来分配的,主要作用大概有两个:

<1> : 作为AudioTrack.cpp部分的回调;

<2> : 作为AudioTrack和AudioFlinger直接数据生产和消费,再就是协调数据进出有序的,FIFO.

继续allocate:

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


最后分配:

Allocation::Allocation(        const sp<MemoryDealer>& dealer,        const sp<IMemoryHeap>& heap, ssize_t offset, size_t size)    : MemoryBase(heap, offset, size), mDealer(dealer){#ifndef NDEBUG    void* const start_ptr = (void*)(intptr_t(heap->base()) + offset);    memset(start_ptr, 0xda, size);#endif}

上面中的IMemoryHeap或者IMemory都是binder的接口,在IMemory.cpp文件中:大致有三点:

<1> : 前面程序会看到IMemory->Pointer:

void* IMemory::pointer() const {    ssize_t offset;    sp<IMemoryHeap> heap = getMemory(&offset);    void* const base = heap!=0 ? heap->base() : MAP_FAILED;    if (base == MAP_FAILED)        return 0;    return static_cast<char*>(base) + offset;}size_t IMemory::size() const {    size_t size;    getMemory(NULL, &size);    return size;}ssize_t IMemory::offset() const {    ssize_t offset;    getMemory(&offset);    return offset;}

这个是反馈分配的内存偏移量和内存大小,偏移量比较难理解的话,就可以勉强理解为分配的内存所在的位置.

<2> : Bn***,Bp***中的BpMemory 类:Bp全名:Binder Proxy : Binder代理

BpMemory::BpMemory(const sp<IBinder>& impl)    : BpInterface<IMemory>(impl), mOffset(0), mSize(0){}BpMemory::~BpMemory(){}sp<IMemoryHeap> BpMemory::getMemory(ssize_t* offset, size_t* size) const{    if (mHeap == 0) {        Parcel data, reply;        data.writeInterfaceToken(IMemory::getInterfaceDescriptor());        if (remote()->transact(GET_MEMORY, data, &reply) == NO_ERROR) {            sp<IBinder> heap = reply.readStrongBinder();            ssize_t o = reply.readInt32();            size_t s = reply.readInt32();            if (heap != 0) {                mHeap = interface_cast<IMemoryHeap>(heap);                if (mHeap != 0) {                    mOffset = o;                    mSize = s;                }            }        }    }    if (offset) *offset = mOffset;    if (size) *size = mSize;    return mHeap;}

其实这东西一两句话说不完,我自己的理解就是binder有货(内存空间,且分配好了的),你要"拿货",你找binder的代理(商),不要直接去找binder,当然binder也没有时间搭理你,另外binder自身分配的时候也不是同步的,所以如果同时直接去操作binder,就不知道有什么后果了.

<3> : BnMemory :这也是个好同志,将数据写入内存中,网上称为服务器端,但个人认为它是最终可以与binder linux节点交互的部分,上面BpMemory最终也是要和BnMemory交互的,至于binder详细,可以阅读:framework/base/libs/binder/下面的源代码.

BnMemory::BnMemory() {}BnMemory::~BnMemory() {}status_t BnMemory::onTransact(    uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags){    switch(code) {        case GET_MEMORY: {            CHECK_INTERFACE(IMemory, data, reply);            ssize_t offset;            size_t size;            reply->writeStrongBinder( getMemory(&offset, &size)->asBinder() );            reply->writeInt32(offset);            reply->writeInt32(size);            return NO_ERROR;        } break;        default:            return BBinder::onTransact(code, data, reply, flags);    }}

最后还扯一个东西:AudioTrack和AudioFlinger,他们两在使用同一个内存区里面的数据时,怎么协调,AudioTrack把播放的数据缓存到binder分配的内存中,AudioFlinger如何调用的到那个内存中的数据,首先要清楚一点的是:

binder分配的内存区,提供了接口可以让多个设备共同读写同一个内存区,也就是说AudioTrack和AudioFlinger虽然在不同的进程,但是可以通过binder机制共同使用同一片内存数据.但是使用过程中,就会有一个协调的工作,不能出现差错,不然声音要么延迟,缎带,要么重复播放.它主要靠下面的结构体实现数据FIFO的协调工作:

// Important: do not add any virtual methods, including ~struct audio_track_cblk_t{    // The data members are grouped so that members accessed frequently and in the same context    // are in the same line of data cache.                Mutex       lock;           // sizeof(int)                Condition   cv;             // sizeof(int)                // next 4 are offsets within "buffers"    volatile    uint32_t    user;    volatile    uint32_t    server;                uint32_t    userBase;                uint32_t    serverBase;                // if there is a shared buffer, "buffers" is the value of pointer() for the shared                // buffer, otherwise "buffers" points immediately after the control block                void*       buffers;                uint32_t    frameCount;                // Cache line boundary                uint32_t    loopStart;                uint32_t    loopEnd;        // read-only for server, read/write for client                int         loopCount;      // read/write for client                // Channel volumes are fixed point U4.12, so 0x1000 means 1.0.                // Left channel is in [0:15], right channel is in [16:31].                // Always read and write the combined pair atomically.                // For AudioTrack only, not used by AudioRecord.private:                uint32_t    mVolumeLR;public:                uint32_t    sampleRate;                // NOTE: audio_track_cblk_t::frameSize is not equal to AudioTrack::frameSize() for                // 8 bit PCM data: in this case,  mCblk->frameSize is based on a sample size of                // 16 bit because data is converted to 16 bit before being stored in buffer                // read-only for client, server writes once at initialization and is then read-only                uint8_t     frameSize;       // would normally be size_t, but 8 bits is plenty                uint8_t     mName;           // normal tracks: track name, fast tracks: track index                // used by client only                uint16_t    bufferTimeoutMs; // Maximum cumulated timeout before restarting audioflinger                uint16_t    waitTimeMs;      // Cumulated wait time, used by client onlyprivate:                // client write-only, server read-only                uint16_t    mSendLevel;      // Fixed point U4.12 so 0x1000 means 1.0public:    volatile    int32_t     flags;                // Cache line boundary (32 bytes)                // Since the control block is always located in shared memory, this constructor                // is only used for placement new().  It is never used for regular new() or stack.                            audio_track_cblk_t();                uint32_t    stepUser(uint32_t frameCount);      // called by client only, where                // client includes regular AudioTrack and AudioFlinger::PlaybackThread::OutputTrack                bool        stepServer(uint32_t frameCount);    // called by server only                void*       buffer(uint32_t offset) const;                uint32_t    framesAvailable();                uint32_t    framesAvailable_l();                uint32_t    framesReady();                      // called by server only                bool        tryLock();                // No barriers on the following operations, so the ordering of loads/stores                // with respect to other parameters is UNPREDICTABLE. That's considered safe.                // for AudioTrack client only, caller must limit to 0.0 <= sendLevel <= 1.0                void        setSendLevel(float sendLevel) {                    mSendLevel = uint16_t(sendLevel * 0x1000);                }                // for AudioFlinger only; the return value must be validated by the caller                uint16_t    getSendLevel_U4_12() const {                    return mSendLevel;                }                // for AudioTrack client only, caller must limit to 0 <= volumeLR <= 0x10001000                void        setVolumeLR(uint32_t volumeLR) {                    mVolumeLR = volumeLR;                }                // for AudioFlinger only; the return value must be validated by the caller                uint32_t    getVolumeLR() const {                    return mVolumeLR;                }};

播放状态,播放位置(内存offset)...记录了播放过程中数据使用过程的所有状态和处理.这个地方千万要注意的是,AudioTrack和AudioFlinger两者通过传递这个结构实现数据同步的,读写内存本身是不能够同步进行的,需要人为去实现这个操作同步.


后面还有一个重采样的处理,以及后面的设备选择.
































0 0