我们知道连接蓝牙下播放手机铃声,手机铃声是双出的,即会从speaker和蓝牙同时输出,其使用的回话线程即为DuplicatingThread,那么在Android中DuplicatingThread中的音频数据流是什么样的呢?实际上DuplicatingThread主要起到了回放线程管理和数据拷贝的作用,如下图所示。
1. AudioTrack到DuplicatingThread音频数据的传递
连接蓝牙下预览手机铃声,当然需要创建AudioTrack,同时AudioFlinger也会创建一个Track与之对应,代码如下所示:
status_t AudioTrack::createTrack_l()
{
......
//AudioFlinger创建与AudioTrack对应的Track
sp<IAudioTrack> track = audioFlinger->createTrack(streamType,
mSampleRate,
mFormat,
mChannelMask,
&temp,
&flags,
mSharedBuffer,
output,
mClientPid,
tid,
&mSessionId,
mClientUid,
&status);
......
}
AudioFlinger最终调用回话线程的createTrack_l来生成Track,代码如下:
sp<IAudioTrack> AudioFlinger::createTrack(
audio_stream_type_t streamType,
uint32_t sampleRate,
audio_format_t format,
audio_channel_mask_t channelMask,
size_t *frameCount,
audio_output_flags_t *flags,
const sp<IMemory>& sharedBuffer,
audio_io_handle_t output,
pid_t pid,
pid_t tid,
audio_session_t *sessionId,
int clientUid,
status_t *status)
{
......
//该thread即为DuplicatingThread
track = thread->createTrack_l(client, streamType, sampleRate, format,
channelMask, frameCount, sharedBuffer, lSessionId, flags, tid, clientUid, &lStatus);
......
}
跟踪到回放线程中的代码:
sp<AudioFlinger::PlaybackThread::Track> AudioFlinger::PlaybackThread::createTrack_l(
const sp<AudioFlinger::Client>& client,
audio_stream_type_t streamType,
uint32_t sampleRate,
audio_format_t format,
audio_channel_mask_t channelMask,
size_t *pFrameCount,
const sp<IMemory>& sharedBuffer,
audio_session_t sessionId,
audio_output_flags_t *flags,
pid_t tid,
int uid,
status_t *status)
{
......
//构建Track,在Track中创建AudioTrack与Track间的共享环形buffer
track = new Track(this, client, streamType, sampleRate, format,
channelMask, frameCount, NULL, sharedBuffer,
sessionId, uid, *flags, TrackBase::TYPE_DEFAULT);
......
//将创建出的track加入到当前回放线程的集合中,这样在AudioMixer中就可以读取环形buffer中的数据
mTracks.add(track);
......
}
以上过程创建国AudioTrack与DuplicatingThread之间共享的环形buffer。
2. DuplicatingThread向真正的回放线程写音频数据
首先我们要清楚DuplicatingThread的生成的过程,在连接蓝牙耳机后,AudioPolichManager会执行如下代码:
status_t AudioPolicyManager::checkOutputsForDevice(const sp<DeviceDescriptor> devDesc,
audio_policy_dev_state_t state,
SortedVector<audio_io_handle_t>& outputs,
const String8 address)
{
......
//在连接蓝牙场景下,output为蓝牙输出设备handle,mPrimaryOutput->mIoHandle代表primary设备handle
duplicatedOutput = mpClientInterface->openDuplicateOutput(output,mPrimaryOutput->mIoHandle);
......
}
最终会调用到AudioFlinger中,代码如下:
audio_io_handle_t AudioFlinger::openDuplicateOutput(audio_io_handle_t output1,
audio_io_handle_t output2)
{
Mutex::Autolock _l(mLock);
MixerThread *thread1 = checkMixerThread_l(output1); //蓝牙输出设备的回放线程
MixerThread *thread2 = checkMixerThread_l(output2); //primary输出设备的回放线程
if (thread1 == NULL || thread2 == NULL) {
ALOGW("openDuplicateOutput() wrong output mixer type for output %d or %d", output1,
output2);
return AUDIO_IO_HANDLE_NONE;
}
audio_io_handle_t id = nextUniqueId(AUDIO_UNIQUE_ID_USE_OUTPUT);
//创建了DuplicatingThread
DuplicatingThread *thread = new DuplicatingThread(this, thread1, id, mSystemReady);
//DuplicatingThread中又添加了primary输出设备回放线程
thread->addOutputTrack(thread2);
mPlaybackThreads.add(id, thread);
// notify client processes of the new output creation
thread->ioConfigChanged(AUDIO_OUTPUT_OPENED);
return id;
}
至此,DuplicatingThread创建出来,而且DuplicatingThread中管理国两个回放线程:蓝牙的回放线程和primary设备(如speaker)的回放线程,那么DuplicatingThread是如何创建和这些回放线程之间的共享的环形buffer的呢?接着看DuplicatingThread的构造和函数,代码如下:
//注意这里传的mainThread即为输出设备为蓝牙的回放线程
AudioFlinger::DuplicatingThread::DuplicatingThread(const sp<AudioFlinger>& audioFlinger,
AudioFlinger::MixerThread* mainThread, audio_io_handle_t id, bool systemReady)
: MixerThread(audioFlinger, mainThread->getOutput(), id, mainThread->outDevice(),
systemReady, DUPLICATING),
mWaitTimeMs(UINT_MAX)
{
//调用国DuplicatingThread的内部函数
addOutputTrack(mainThread);
}
接着看addOutputTrack函数,代码如下:
void AudioFlinger::DuplicatingThread::addOutputTrack(MixerThread *thread)
{
......
//创建了OutputTrack对象,thread为输出设备为蓝牙的回放线程
sp<OutputTrack> outputTrack = new OutputTrack(thread,
this,
mSampleRate,
mFormat,
mChannelMask,
frameCount,
IPCThreadState::self()->getCallingUid());
......
}
那么OutputTrack又是什么呢?看下其构造函数,代码如下:
//playbackThread为输出设备为蓝牙的回放线程
AudioFlinger::PlaybackThread::OutputTrack::OutputTrack(
PlaybackThread *playbackThread,
DuplicatingThread *sourceThread,
uint32_t sampleRate,
audio_format_t format,
audio_channel_mask_t channelMask,
size_t frameCount,
int uid)
//OutputTrack为Track的子类
: Track(playbackThread, NULL, AUDIO_STREAM_PATCH,
sampleRate, format, channelMask, frameCount,
NULL, 0, AUDIO_SESSION_NONE, uid, AUDIO_OUTPUT_FLAG_NONE,
TYPE_OUTPUT),
mActive(false), mSourceThread(sourceThread), mClientProxy(NULL)
{
if (mCblk != NULL) {
mOutBuffer.frameCount = 0;
//playbackThread中添加了要播放的音频数据track
playbackThread->mTracks.add(this);
ALOGV("OutputTrack constructor mCblk %p, mBuffer %p, "
"frameCount %zu, mChannelMask 0x%08x",
mCblk, mBuffer,
frameCount, mChannelMask);
// since client and server are in the same process,
// the buffer has the same virtual address on both sides
//创建了访问环形buffer的proxy
mClientProxy = new AudioTrackClientProxy(mCblk, mBuffer, mFrameCount, mFrameSize,
true /*clientInServer*/);
mClientProxy->setVolumeLR(GAIN_MINIFLOAT_PACKED_UNITY);
mClientProxy->setSendLevel(0.0);
mClientProxy->setSampleRate(sampleRate);
} else {
ALOGW("Error creating output track on thread %p", playbackThread);
}
}
从以上代码可以看出,OutputTrack为Track的子类,而在Track中会创建环形buffer CBLK,而playbackThread(输出设备为蓝牙的回话线程)又将该OutputTrack加入到国其要回话的mTracks列表中,因此构造OutputTrack的过程中就相当于建立了一个DuplicatingThread和某个输出设备的回放线程间的共享的环形buffer CBLK。
同理在openDuplicateOutput函数中的thread->addOutputTrack(thread2);语句建立了DuplicatingThread与primary输出设备的回放线程间的共享的环形buffer。
接下来我们需要了解的是DuplicatingThread是如何向其管理的回放线程的环形buffer写音频数据的。为了搞清这点,首先我们要明白,DuplicatingThread继承自MixerThread,而MixerThread又继承了PlaybackThread,由于MixerThread和DuplicatingThread均没有重新实现threadLoop,因此DuplicatingThread执行的threadLoop实际上是PlaybackThread的threadLoop。在PlaybackThread的threadLoop函数中会调用threadLoop_write,由于DuplicatingThread重新实现了该函数,因此这里调用的为DuplicatingThread的threadLoop_write函数,代码如下:
ssize_t AudioFlinger::DuplicatingThread::threadLoop_write()
{
for (size_t i = 0; i < outputTracks.size(); i++) {
//调用国OutputTrack的write函数来写DuplicatingThread经过AudioMixer处理后的数据mSinkBuffer
outputTracks[i]->write(mSinkBuffer, writeFrames);
}
mStandby = false;
return (ssize_t)mSinkBufferSize;
}
接着看OutputTrack的write函数,代码如下:
bool AudioFlinger::PlaybackThread::OutputTrack::write(void* data, uint32_t frames)
{
......
//获得playbackThread的环形buffer的可写的起始地址和大小
status_t status = obtainBuffer(&mOutBuffer, waitTimeLeftMs);
......
//将数据拷贝到环形buffer中
memcpy(mOutBuffer.raw, pInBuffer->raw, outFrames * mFrameSize);
......
}
由此可以看出DuplicatingThread是如何向其管理的回放线程中写音频数据的。
接下来的播放就是各个回放线程在threadLoop中循环获得各自的环形buffer中的音频数据并写到HAL层了。