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的總體流程