AudioTrack的start方法用於實現Android的音頻輸出,start究竟做了什么?回顧一下上一小節createTrack_l的最后部分,通過binder返回了一個Track的句柄,並以被保存了下來
status_t AudioTrack::createTrack_l(...)
{
sp<IAudioTrack> track = audioFlinger->createTrack(...);
mAudioTrack = track;
}
start主要就是調用這個track的start方法實現音頻輸出功能的
// -------------------------------------------------------------------------
status_t AudioTrack::start()
{
AutoMutex lock(mLock);
//如果該AudioTrack已經是start狀態,直接返回
if (mState == STATE_ACTIVE) {
return INVALID_OPERATION;
}
mInUnderrun = true;
//保存上一次的狀態
State previousState = mState;
//設置當前狀態
if (previousState == STATE_PAUSED_STOPPING) {
mState = STATE_STOPPING;
} else {
mState = STATE_ACTIVE;
}
//如果上一狀態是停止狀態,表明需要重新把position設置為0,從頭播放
if (previousState == STATE_STOPPED || previousState == STATE_FLUSHED) {
// reset current position as seen by client to 0
mProxy->setEpoch(mProxy->getEpoch() - mProxy->getPosition());
// force refresh of remaining frames by processAudioBuffer() as last
// write before stop could be partial.
mRefreshRemaining = true;
}
//當前位置
mNewPosition = mProxy->getPosition() + mUpdatePeriod;
//獲取share buffer的flag,原子操作
int32_t flags = android_atomic_and(~CBLK_DISABLED, &mCblk->mFlags);
//是否有回調線程,一般如果我們在apk端獨立調用AudioTrack,是不會設置回調線程的,但是AudioPlayer這種系統播放器則會設置回調線程
//這樣做是為了設置優先級,否則Audio可能會由於得不到時間片,而卡頓
//如果是AudioPlayer,會有自己定義的優先級,AudioTrack后面新創建的線程則會繼承它的優先級
//如果是Apk調用,優先級一般都是固定的,那么我們需要在這里設置一個ANDROID_PRIORITY_AUDIO的優先級來保證Audio的流暢輸出
sp<AudioTrackThread> t = mAudioTrackThread;
if (t != 0) {
if (previousState == STATE_STOPPING) {
//中斷
mProxy->interrupt();
} else {
//恢復播放
t->resume();
}
} else {
//保存當前線程優先級,在后面停止的時候設置回來
mPreviousPriority = getpriority(PRIO_PROCESS, 0);
get_sched_policy(0, &mPreviousSchedulingGroup);
//設置線程優先級為ANDROID_PRIORITY_AUDIO
androidSetThreadPriority(0, ANDROID_PRIORITY_AUDIO);
}
status_t status = NO_ERROR;
if (!(flags & CBLK_INVALID)) {
//如果share buffer可用,則調用track的start方法
status = mAudioTrack->start();
if (status == DEAD_OBJECT) {
flags |= CBLK_INVALID;
}
}
if (flags & CBLK_INVALID) {
status = restoreTrack_l("start");
}
if (status != NO_ERROR) {
//start出錯后的處理
ALOGE("start() status %d", status);
mState = previousState;
if (t != 0) {
if (previousState != STATE_STOPPING) {
t->pause();
}
} else {
setpriority(PRIO_PROCESS, 0, mPreviousPriority);
set_sched_policy(0, mPreviousSchedulingGroup);
}
}
return status;
}
由於mAudioTrack是binder的proxy對象,因此start會調用到BBinder對象的start方法,即
status_t AudioFlinger::TrackHandle::start() {
return mTrack->start();
}
由於我們是在PlaybackThread下進行音頻輸出的,因此會進一步調用到PlaybackThread::Track:: start方法,其中最主要的是下面兩個步驟:
status_t AudioFlinger::PlaybackThread::Track::start(
PlaybackThread *playbackThread = (PlaybackThread *)thread.get();
status = playbackThread->addTrack_l(this);
}
還記得我們在getOutput的時候創建了一個MixerThread嗎,而且在createTrack_l的時候把這個Thread加入了mPlaybackThreads進行管理,現在我們要把它取出來,調用它的addTrack_l方法了
audio_io_handle_t AudioFlinger::openOutput(audio_module_handle_t module,...)
{ thread = new MixerThread(this, output, id, *pDevices); return id;
}
AudioFlinger::PlaybackThread *AudioFlinger::checkPlaybackThread_l(audio_io_handle_t output) const
{ return mPlaybackThreads.valueFor(output).get();
}
在addTrack_l方法內,主要步驟有三個:
- 如果該track(share buffer)是新增track,則需要調用startOutput進行初始化
- 把該track加入mActiveTracks
- 發送廣播,通知MixerThread開始工作
// addTrack_l() must be called with ThreadBase::mLock held
status_t AudioFlinger::PlaybackThread::addTrack_l(const sp<Track>& track)
{
if (mActiveTracks.indexOf(track) < 0) {
status = AudioSystem::startOutput(mId, track->streamType(), track->sessionId());
}
mActiveTracks.add(track);
broadcast_l();
}
1. track初始化
在分析getOutput的時候,我們已經知道Audio接口的調用流程,即AudioSystem->AudioPolicyService->Audio_policy_hal->AudioPolicyManagerBase,現在我們來看一下AudioPolicyManagerBase:: startOutput做了什么
status_t AudioPolicyManagerBase::startOutput(audio_io_handle_t output,
AudioSystem::stream_type stream,
int session)
{
checkAndSetVolume(stream,
mStreams[stream].getVolumeIndex(newDevice),
output,
newDevice);
}
checkAndSetVolume其實只是設置了stream volume.
2. track加入mAudioTrack
mAudioTrack即當前MixerThread所包含的Track集合,在后面就是對這些Track集合進行混音
3. broadcast_l
void AudioFlinger::PlaybackThread::broadcast_l()
{
// Thread could be blocked waiting for async
// so signal it to handle state changes immediately
// If threadLoop is currently unlocked a signal of mWaitWorkCV will
// be lost so we also flag to prevent it blocking on mWaitWorkCV
mSignalPending = true;
mWaitWorkCV.broadcast();
}
我們已經有了MixerThread,由於MixerThread繼承與PlaybackThread,因此跑的是PlaybackThread::threadLoop,在threadLoop內,如果mActiveTrack為空的話,表明沒有音頻數據等待輸出,那么threadLoop會進入睡眠,等待喚醒,這里的broadcast就是做了這個喚醒的工作
bool AudioFlinger::PlaybackThread::threadLoop()
{
if ((!mActiveTracks.size() && systemTime() > standbyTime) ||
isSuspended())
mWaitWorkCV.wait(mLock);
}
...
}
下面是start的總體流程

