在分析AudioTrack时已经分析到IAudioTrack接口了,下面我们继续从IAudioTrack接口向下继续分析,先来张图:
首先是TrackHandle,它是IAudioTrack 的服务端:
//frameworks/av/services/audioflinger/AudioFlinger.h
// server side of the client's IAudioTrack
class TrackHandle : public android::media::BnAudioTrack {
public:
explicit TrackHandle(const sp<PlaybackThread::Track>& track);
virtual ~TrackHandle();
binder::Status getCblk(std::optional<media::SharedFileRegion>* _aidl_return) override;
binder::Status start(int32_t* _aidl_return) override;
binder::Status stop() override;
binder::Status flush() override;
binder::Status pause() override;
binder::Status attachAuxEffect(int32_t effectId, int32_t* _aidl_return) override;
binder::Status setParameters(const std::string& keyValuePairs,
int32_t* _aidl_return) override;
binder::Status selectPresentation(int32_t presentationId, int32_t programId,
int32_t* _aidl_return) override;
binder::Status getTimestamp(media::AudioTimestampInternal* timestamp,
int32_t* _aidl_return) override;
binder::Status signal() override;
binder::Status applyVolumeShaper(const media::VolumeShaperConfiguration& configuration,
const media::VolumeShaperOperation& operation,
int32_t* _aidl_return) override;
binder::Status getVolumeShaperState(
int32_t id,
std::optional<media::VolumeShaperState>* _aidl_return) override;
binder::Status getDualMonoMode(media::AudioDualMonoMode* _aidl_return) override;
binder::Status setDualMonoMode(media::AudioDualMonoMode mode) override;
binder::Status getAudioDescriptionMixLevel(float* _aidl_return) override;
binder::Status setAudioDescriptionMixLevel(float leveldB) override;
binder::Status getPlaybackRateParameters(
media::AudioPlaybackRate* _aidl_return) override;
binder::Status setPlaybackRateParameters(
const media::AudioPlaybackRate& playbackRate) override;
private:
const sp<PlaybackThread::Track> mTrack; 指向PlaybackThread::Track的强指针
};
//frameworks/av/services/audioflinger/Tracks.cpp
Status AudioFlinger::TrackHandle::start(int32_t* _aidl_return) {
*_aidl_return = mTrack->start();
return Status::ok();
}
在Tracks的AudioFlinger::TrackHandle::start中会调用mTrack->start()也是就调用PlaybackThread::Track的start方法:
//frameworks/av/services/audioflinger/PlaybackTracks.h
sp<AudioTrackServerProxy> mAudioTrackServerProxy;
//frameworks/av/services/audioflinger/Tracks.cpp
status_t AudioFlinger::PlaybackThread::Track::start(AudioSystem::sync_event_t event __unused,
audio_session_t triggerSession __unused)
{
status_t status = NO_ERROR;
ALOGV("%s(%d): calling pid %d session %d",
__func__, mId, IPCThreadState::self()->getCallingPid(), mSessionId);
sp<ThreadBase> thread = mThread.promote();
// 这个Thread就是调用createTrack_l的那个thread对象,这里是MixerThread
if (thread != 0) {
if (isOffloaded()) {
Mutex::Autolock _laf(thread->mAudioFlinger->mLock);
Mutex::Autolock _lth(thread->mLock);
sp<EffectChain> ec = thread->getEffectChain_l(mSessionId);
if (thread->mAudioFlinger->isNonOffloadableGlobalEffectEnabled_l() ||
(ec != 0 && ec->isNonOffloadableEnabled())) {
invalidate();
return PERMISSION_DENIED;
}
}
Mutex::Autolock _lth(thread->mLock);
track_state state = mState;
// here the track could be either new, or restarted
// in both cases "unstop" the track
// initial state-stopping. next state-pausing.
// What if resume is called ?
if (state == FLUSHED) {
// avoid underrun glitches when starting after flush
reset();
}
// clear mPauseHwPending because of pause (and possibly flush) during underrun.
mPauseHwPending = false;
//根据当前播放状态更新播放状态
if (state == PAUSED || state == PAUSING) {
if (mResumeToStopping) {
// happened we need to resume to STOPPING_1
mState = TrackBase::STOPPING_1;
ALOGV("%s(%d): PAUSED => STOPPING_1 on thread %d",
__func__, mId, (int)mThreadIoHandle);
} else {
mState = TrackBase::RESUMING;
ALOGV("%s(%d): PAUSED => RESUMING on thread %d",
__func__, mId, (int)mThreadIoHandle);
}
} else {
mState = TrackBase::ACTIVE;
ALOGV("%s(%d): ? => ACTIVE on thread %d",
__func__, mId, (int)mThreadIoHandle);
}
// states to reset position info for non-offloaded/direct tracks
if (!isOffloaded() && !isDirect()
&& (state == IDLE || state == STOPPED || state == FLUSHED)) {
mFrameMap.reset();
}
PlaybackThread *playbackThread = (PlaybackThread *)thread.get(); //获取playbackThread
if (isFastTrack()) {
// refresh fast track underruns on start because that field is never cleared
// by the fast mixer; furthermore, the same track can be recycled, i.e. start
// after stop.
mObservedUnderruns = playbackThread->getFastTrackUnderruns(mFastIndex);
}
status = playbackThread->addTrack_l(this); // 将当前track加入到playbackThread中
if (status == INVALID_OPERATION || status == PERMISSION_DENIED) {
triggerEvents(AudioSystem::SYNC_EVENT_PRESENTATION_COMPLETE);
// restore previous state if start was rejected by policy manager
if (status == PERMISSION_DENIED) {
mState = state;
}
}
// Audio timing metrics are computed a few mix cycles after starting.
{
mLogStartCountdown = LOG_START_COUNTDOWN;
mLogStartTimeNs = systemTime();
mLogStartFrames = mAudioTrackServerProxy->getTimestamp()
.mPosition[ExtendedTimestamp::LOCATION_KERNEL];
mLogLatencyMs = 0.;
}
if (status == NO_ERROR || status == ALREADY_EXISTS) {
// for streaming tracks, remove the buffer read stop limit.
mAudioTrackServerProxy->start();
}
// track was already in the active list, not a problem
if (status == ALREADY_EXISTS) {
status = NO_ERROR;
} else {
// Acknowledge any pending flush(), so that subsequent new data isn't discarded.
// It is usually unsafe to access the server proxy from a binder thread.
// But in this case we know the mixer thread (whether normal mixer or fast mixer)
// isn't looking at this track yet: we still hold the normal mixer thread lock,
// and for fast tracks the track is not yet in the fast mixer thread's active set.
// For static tracks, this is used to acknowledge change in position or loop.
ServerProxy::Buffer buffer;
buffer.mFrameCount = 1;
(void) mAudioTrackServerProxy->obtainBuffer(&buffer, true /*ackFlush*/); //获取AudioTrack缓冲区数据
}
} else {
status = BAD_VALUE;
}
if (status == NO_ERROR) {
forEachTeePatchTrack([](auto patchTrack) { patchTrack->start(); });
}
return status;
}
这里重要的处理有两步,分别是:
-
调用playbackThread->addTrack_l(this); 将当前track加入到playbackTrack中。
-
调用AudioTrackServerProxy的obtainBuffer函数,获取AudioTrack缓冲区数据。
下面分别进行分析:
playbackThread addTrack_l
调用playbackThread->addTrack_l(this); 将当前track加入到playbackTrack中:
待更新
AudioTrackServerProxy obtainBuffer
我们先看obtainBuffer函数,该函数的主要功能就是对传入的audioBuffer进行赋值:
//frameworks/av/media/libaudioclient/AudioTrackShared.cpp
status_t ServerProxy::obtainBuffer(Buffer* buffer, bool ackFlush)
{
LOG_ALWAYS_FATAL_IF(buffer == NULL || buffer->mFrameCount == 0,
"%s: null or zero frame buffer, buffer:%p", __func__, buffer);
if (mIsShutdown) {
goto no_init;
}
{
audio_track_cblk_t* cblk = mCblk;
// compute number of frames available to write (AudioTrack) or read (AudioRecord),
// or use previous cached value from framesReady(), with added barrier if it omits.
int32_t front;
int32_t rear;
// See notes on barriers at ClientProxy::obtainBuffer()
if (mIsOut) {
flushBufferIfNeeded(); // might modify mFront
rear = getRear();
front = cblk->u.mStreaming.mFront;
} else {
front = android_atomic_acquire_load(&cblk->u.mStreaming.mFront);
rear = cblk->u.mStreaming.mRear;
}
ssize_t filled = audio_utils::safe_sub_overflow(rear, front);
// pipe should not already be overfull
if (!(0 <= filled && (size_t) filled <= mFrameCount)) {
ALOGE("Shared memory control block is corrupt (filled=%zd, mFrameCount=%zu); shutting down",
filled, mFrameCount);
mIsShutdown = true;
}
if (mIsShutdown) {
goto no_init;
}
// don't allow filling pipe beyond the nominal size
size_t availToServer;
if (mIsOut) {
availToServer = filled;
mAvailToClient = mFrameCount - filled;
} else {
availToServer = mFrameCount - filled;
mAvailToClient = filled;
}
// 'availToServer' may be non-contiguous, so return only the first contiguous chunk
size_t part1;
if (mIsOut) {
front &= mFrameCountP2 - 1;
part1 = mFrameCountP2 - front;
} else {
rear &= mFrameCountP2 - 1;
part1 = mFrameCountP2 - rear;
}
if (part1 > availToServer) {
part1 = availToServer;
}
size_t ask = buffer->mFrameCount;
if (part1 > ask) {
part1 = ask;
}
// is assignment redundant in some cases?
buffer->mFrameCount = part1;
buffer->mRaw = part1 > 0 ?
&((char *) mBuffers)[(mIsOut ? front : rear) * mFrameSize] : NULL;
buffer->mNonContig = availToServer - part1;
// After flush(), allow releaseBuffer() on a previously obtained buffer;
// see "Acknowledge any pending flush()" in audioflinger/Tracks.cpp.
if (!ackFlush) {
mUnreleased = part1;
}
return part1 > 0 ? NO_ERROR : WOULD_BLOCK;
}
no_init:
buffer->mFrameCount = 0;
buffer->mRaw = NULL;
buffer->mNonContig = 0;
mUnreleased = 0;
return NO_INIT;
}
然后我们再看playbackThread->addTrack_l(this);:
//frameworks/av/services/audioflinger/Threads.h
ActiveTracks<Track> mActiveTracks;
//frameworks/av/services/audioflinger/Tracks.cpp
status_t AudioFlinger::PlaybackThread::addTrack_l(const sp<Track>& track)
{
status_t status = ALREADY_EXISTS;
if (mActiveTracks.indexOf(track) < 0) {
// the track is newly added, make sure it fills up all its
// buffers before playing. This is to ensure the client will
// effectively get the latency it requested.
if (track->isExternalTrack()) {
TrackBase::track_state state = track->mState;
mLock.unlock();
status = AudioSystem::startOutput(track->portId()); //这边实际上是调用到了AudioOutputDescriptor中,增加了mPorfile->curActiveCount的计数
mLock.lock();
// abort track was stopped/paused while we released the lock
if (state != track->mState) {
if (status == NO_ERROR) {
mLock.unlock();
AudioSystem::stopOutput(track->portId());
mLock.lock();
}
return INVALID_OPERATION;
}
// abort if start is rejected by audio policy manager
if (status != NO_ERROR) {
return PERMISSION_DENIED;
}
#ifdef ADD_BATTERY_DATA
// to track the speaker usage
addBatteryData(IMediaPlayerService::kBatteryDataAudioFlingerStart);
#endif
sendIoConfigEvent_l(AUDIO_CLIENT_STARTED, track->creatorPid(), track->portId());
}
// set retry count for buffer fill
if (track->isOffloaded()) {
if (track->isStopping_1()) {
track->mRetryCount = kMaxTrackStopRetriesOffload;
} else {
track->mRetryCount = kMaxTrackStartupRetriesOffload;
}
track->mFillingUpStatus = mStandby ? Track::FS_FILLING : Track::FS_FILLED;
} else {
track->mRetryCount = kMaxTrackStartupRetries;
track->mFillingUpStatus =
track->sharedBuffer() != 0 ? Track::FS_FILLED : Track::FS_FILLING;
}
sp<EffectChain> chain = getEffectChain_l(track->sessionId());
if (mHapticChannelMask != AUDIO_CHANNEL_NONE
&& ((track->channelMask() & AUDIO_CHANNEL_HAPTIC_ALL) != AUDIO_CHANNEL_NONE
|| (chain != nullptr && chain->containsHapticGeneratingEffect_l()))) {
// Unlock due to VibratorService will lock for this call and will
// call Tracks.mute/unmute which also require thread's lock.
mLock.unlock();
const int intensity = AudioFlinger::onExternalVibrationStart(
track->getExternalVibration());
std::optional<media::AudioVibratorInfo> vibratorInfo;
{
// TODO(b/184194780): Use the vibrator information from the vibrator that will be
// used to play this track.
Mutex::Autolock _l(mAudioFlinger->mLock);
vibratorInfo = std::move(mAudioFlinger->getDefaultVibratorInfo_l());
}
mLock.lock();
track->setHapticIntensity(static_cast<os::HapticScale>(intensity));
if (vibratorInfo) {
track->setHapticMaxAmplitude(vibratorInfo->maxAmplitude);
}
// Haptic playback should be enabled by vibrator service.
if (track->getHapticPlaybackEnabled()) {
// Disable haptic playback of all active track to ensure only
// one track playing haptic if current track should play haptic.
for (const auto &t : mActiveTracks) {
t->setHapticPlaybackEnabled(false);
}
}
// Set haptic intensity for effect
if (chain != nullptr) {
chain->setHapticIntensity_l(track->id(), intensity);
}
}
track->mResetDone = false;
track->resetPresentationComplete();
mActiveTracks.add(track); //mActiveTracks在PlaybackThread中是Track也就是playbackTrack,将当前track加入到playbackTrack中
if (chain != 0) {
ALOGV("addTrack_l() starting track on chain %p for session %d", chain.get(),
track->sessionId());
chain->incActiveTrackCnt();
}
track->logBeginInterval(patchSinksToString(&mPatch)); // log to MediaMetrics
status = NO_ERROR;
}
onAddNewTrack_l(); //这里是对我们playbackThread进行了唤醒
return status;
}
void AudioFlinger::PlaybackThread::onAddNewTrack_l()
{
ALOGV("signal playback thread");
broadcast_l();
}
AudioFlinger PlaybackThread threadLoop
addTrack_l之后playbackThread会被唤醒,然后就会开始它自己的工作,thread_loop会动起来,这里面包含集合函数:threadloop_mix、threadloop_write、threadloop_standby,分别是对音频进行混音、通过数据流将数据写到HAL层、暂停,上层play之后就会开始往HAL层写数据,然后就放出了了我们听到的音乐,这个track在framework层的使命就算是成功完成了,然后处理的事情就交给了HAL层和kernel及ALSA。