AudioTrack与AudioFlinger的sharebuffer

       AudioTrack作为音频数据的生产者,AudioFlinger是消费者,会有一块共享内存用于传输pcm数据,这块共享内存在AudioTrack创建时候就开辟好,主要就是在AudioTrack的set方法,该方法中调用了createTrack_l创建IAudioTrack,createTrack_l的作用主要就是创建出一块share buffer,供AudioTrack写入和AudioFlinger读取。同时还会根据是否在参数中传入callback函数来决定是否创建AudioTrackThread,用以以callback的形式来要数据,但无论是这种callback形式还是直接write的形式都需要通过createTrack_l创建的share buffer。

createTrack_l的主要工作有调用AudioFlinger的createTrack,创建sharebuffer和Audioflinger对sharebuffer进行控制的对象AudioTrackServerProxy,客户端AudioTrack则有相对应的控制对象AudioTrackClientProxy。

步骤为:

1.获取输出线程PlaybackThread,先通过AudioSystem::getOutputForAttr获取输出的信息,再通过checkPlaybackThread_l获取到PlaybackThread,PlaybackThread是在系统启动初期audioflinger和audiopolicy服务起来的时候就一同被创建。

lStatus = AudioSystem::getOutputForAttr(&input.attr, &output.outputId, sessionId, &streamType,
                                            clientPid, clientUid, &input.config, input.flags,
                                            &output.selectedDeviceId, &portId);



PlaybackThread *thread = checkPlaybackThread_l(output.outputId);
        if (thread == NULL) {
            ALOGE("no playback thread found for output handle %d", output.outputId);
            lStatus = BAD_VALUE;
            goto Exit;
        }

2.调用获取到的PlaybackThread的createTrack_l函数来创建Track对象,在Track对象内部会创建sharebuffer

track = thread->createTrack_l(client, streamType, input.attr, &output.sampleRate,
                                      input.config.format, input.config.channel_mask,
                                      &output.frameCount, &output.notificationFrameCount,
                                      input.notificationsPerBuffer, input.speed,
                                      input.sharedBuffer, sessionId, &output.flags,
                                      input.clientInfo.clientTid, clientUid, &lStatus, portId);

3.最后创建TrackHandle,返回给AudioTrack,TrackHandlebao包含了上一步创建的track的信息

PlaybackThread的createTrack_l函数中调用了new Track来创建share buffer

track = new Track(this, client, streamType, attr, sampleRate, format,
                          channelMask, frameCount,
                          nullptr /* buffer */, (size_t)0 /* bufferSize */, sharedBuffer,
                          sessionId, uid, *flags, TrackBase::TYPE_DEFAULT, portId);

Track的父类TrackBase对象,sharebuffer即在这里创建,其中audio_track_cblk_t是这个buffer的头,头记录了很多例如AUdioTrack和AudioFlinger读写指针位置的关键信息,在读写过程中不断使用到。

AudioFlinger::ThreadBase::TrackBase::TrackBase(...)
{
...
if (mCblk != NULL) {
        new(mCblk) audio_track_cblk_t();
        switch (alloc) {
        case ALLOC_READONLY: {
            const sp<MemoryDealer> roHeap(thread->readOnlyHeap());
            if (roHeap == 0 ||
                    (mBufferMemory = roHeap->allocate(bufferSize)) == 0 ||
                    (mBuffer = mBufferMemory->pointer()) == NULL) {
                ALOGE("not enough memory for read-only buffer size=%zu", bufferSize);
                if (roHeap != 0) {
                    roHeap->dump("buffer");
                }
                mCblkMemory.clear();
                mBufferMemory.clear();
                return;
            }
            memset(mBuffer, 0, bufferSize);
            } break;
        case ALLOC_PIPE:
            mBufferMemory = thread->pipeMemory();
            // mBuffer is the virtual address as seen from current process (mediaserver),
            // and should normally be coming from mBufferMemory->pointer().
            // However in this case the TrackBase does not reference the buffer directly.
            // It should references the buffer via the pipe.
            // Therefore, to detect incorrect usage of the buffer, we set mBuffer to NULL.
            mBuffer = NULL;
            bufferSize = 0;
            break;
        case ALLOC_CBLK:
            // clear all buffers
            if (buffer == NULL) {
                mBuffer = (char*)mCblk + sizeof(audio_track_cblk_t);
                memset(mBuffer, 0, bufferSize);
            } else {
                mBuffer = buffer;
#if 0
                mCblk->mFlags = CBLK_FORCEREADY;    // FIXME hack, need to fix the track ready logic
#endif
            }
            break;
        case ALLOC_LOCAL:
            mBuffer = calloc(1, bufferSize);
            break;
        case ALLOC_NONE:
            mBuffer = buffer;
            break;
        default:
            LOG_ALWAYS_FATAL("invalid allocation type: %d", (int)alloc);
        }
        mBufferSize = bufferSize;
.....
}

new Track在构造函数体内,会创建AudioTrackServerProxy,用作AudioFlinger这边的buffer操作,回头再看AudioTrack的createTrack_l函数中也创建了AudioTrackClientProxy对象用于AudioTrack的buffer操作。

共享内存开辟出来之后,AudioTrack就可以将数据写入这块内存,而这个过程就是AudioTrackClientProxy对象获取sharebuffer可用空间,再将数据copy到这块内存上,AudioTrack的obtainBuffer函数调用AudioTrackClientProxy的父类对象ClientProxy的obtainBuffer方法

 

 


版权声明:本文为songche123原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。