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方法