Loading services/audioflinger/PlaybackTracks.h +22 −4 Original line number Diff line number Diff line Loading @@ -222,10 +222,23 @@ protected: sp<IMemory> sharedBuffer() const { return mSharedBuffer; } // presentationComplete checked by frames. (Mixed Tracks). // framesWritten is cumulative, never reset, and is shared all tracks // audioHalFrames is derived from output latency // FIXME parameters not needed, could get them from the thread bool presentationComplete(int64_t framesWritten, size_t audioHalFrames); // presentationComplete checked by time. (Direct Tracks). bool presentationComplete(uint32_t latencyMs); void resetPresentationComplete() { mPresentationCompleteFrames = 0; mPresentationCompleteTimeNs = 0; } // notifyPresentationComplete is called when presentationComplete() detects // that the track is finished stopping. void notifyPresentationComplete(); void signalClientFlag(int32_t flag); public: Loading Loading @@ -256,9 +269,6 @@ protected: int32_t *mAuxBuffer; int mAuxEffectId; bool mHasVolumeController; size_t mPresentationCompleteFrames; // number of frames written to the // audio HAL when this track will be fully rendered // zero means not monitoring // access these three variables only when holding thread lock. LinearMap<int64_t> mFrameMap; // track frame to server frame mapping Loading Loading @@ -294,6 +304,14 @@ private: for (auto& tp : mTeePatches) { f(tp.patchTrack); } }; size_t mPresentationCompleteFrames = 0; // (Used for Mixed tracks) // The number of frames written to the // audio HAL when this track is considered fully rendered. // Zero means not monitoring. int64_t mPresentationCompleteTimeNs = 0; // (Used for Direct tracks) // The time when this track is considered fully rendered. // Zero means not monitoring. // The following fields are only for fast tracks, and should be in a subclass int mFastIndex; // index within FastMixerState::mFastTracks[]; // either mFastIndex == -1 if not isFastTrack() Loading services/audioflinger/Threads.cpp +3 −18 Original line number Diff line number Diff line Loading @@ -2631,7 +2631,7 @@ status_t AudioFlinger::PlaybackThread::addTrack_l(const sp<Track>& track) } track->mResetDone = false; track->mPresentationCompleteFrames = 0; track->resetPresentationComplete(); mActiveTracks.add(track); if (chain != 0) { ALOGV("addTrack_l() starting track on chain %p for session %d", chain.get(), Loading Loading @@ -6038,16 +6038,8 @@ AudioFlinger::PlaybackThread::mixer_state AudioFlinger::DirectOutputThread::prep track->isStopping_2() || track->isPaused()) { // We have consumed all the buffers of this track. // Remove it from the list of active tracks. size_t audioHALFrames; if (audio_has_proportional_frames(mFormat)) { audioHALFrames = (latency_l() * mSampleRate) / 1000; } else { audioHALFrames = 0; } int64_t framesWritten = mBytesWritten / mFrameSize; if (mStandby || !last || track->presentationComplete(framesWritten, audioHALFrames) || track->presentationComplete(latency_l()) || track->isPaused() || mHwPaused) { if (track->isStopping_2()) { track->mState = TrackBase::STOPPED; Loading Loading @@ -6621,14 +6613,7 @@ AudioFlinger::PlaybackThread::mixer_state AudioFlinger::OffloadThread::prepareTr // Drain has completed or we are in standby, signal presentation complete if (!(mDrainSequence & 1) || !last || mStandby) { track->mState = TrackBase::STOPPED; uint32_t latency = 0; status_t result = mOutput->stream->getLatency(&latency); ALOGE_IF(result != OK, "Error when retrieving output stream latency: %d", result); size_t audioHALFrames = (latency * mSampleRate) / 1000; int64_t framesWritten = mBytesWritten / mOutput->getFrameSize(); track->presentationComplete(framesWritten, audioHALFrames); track->presentationComplete(latency_l()); track->reset(); tracksToRemove->add(track); // OFFLOADED stop resets frame counts. Loading services/audioflinger/Tracks.cpp +47 −7 Original line number Diff line number Diff line Loading @@ -650,7 +650,6 @@ AudioFlinger::PlaybackThread::Track::Track( mMainBuffer(thread->sinkBuffer()), mAuxBuffer(NULL), mAuxEffectId(0), mHasVolumeController(false), mPresentationCompleteFrames(0), mFrameMap(16 /* sink-frame-to-track-frame map memory */), mVolumeHandler(new media::VolumeHandler(sampleRate)), mOpPlayAudioMonitor(OpPlayAudioMonitor::createIfNeeded(attributionSource, attr, id(), Loading Loading @@ -1462,6 +1461,7 @@ void AudioFlinger::PlaybackThread::Track::setAuxBuffer(int EffectId, int32_t *bu mAuxBuffer = buffer; } // presentationComplete verified by frames, used by Mixed tracks. bool AudioFlinger::PlaybackThread::Track::presentationComplete( int64_t framesWritten, size_t audioHalFrames) { Loading @@ -1480,30 +1480,70 @@ bool AudioFlinger::PlaybackThread::Track::presentationComplete( (long long)mPresentationCompleteFrames, (long long)framesWritten); if (mPresentationCompleteFrames == 0) { mPresentationCompleteFrames = framesWritten + audioHalFrames; ALOGV("%s(%d): presentationComplete() reset:" ALOGV("%s(%d): set:" " mPresentationCompleteFrames %lld audioHalFrames %zu", __func__, mId, (long long)mPresentationCompleteFrames, audioHalFrames); } bool complete; if (isOffloaded()) { complete = true; } else if (isDirect() || isFastTrack()) { // these do not go through linear map if (isFastTrack()) { // does not go through linear map complete = framesWritten >= (int64_t) mPresentationCompleteFrames; ALOGV("%s(%d): %s framesWritten:%lld mPresentationCompleteFrames:%lld", __func__, mId, (complete ? "complete" : "waiting"), (long long) framesWritten, (long long) mPresentationCompleteFrames); } else { // Normal tracks, OutputTracks, and PatchTracks complete = framesWritten >= (int64_t) mPresentationCompleteFrames && mAudioTrackServerProxy->isDrained(); } if (complete) { triggerEvents(AudioSystem::SYNC_EVENT_PRESENTATION_COMPLETE); mAudioTrackServerProxy->setStreamEndDone(); notifyPresentationComplete(); return true; } return false; } // presentationComplete checked by time, used by DirectTracks. bool AudioFlinger::PlaybackThread::Track::presentationComplete(uint32_t latencyMs) { // For Offloaded or Direct tracks. // For a direct track, we incorporated time based testing for presentationComplete. // For an offloaded track the HAL+h/w delay is variable so a HAL drain() is used // to detect when all frames have been played. In this case latencyMs isn't // useful because it doesn't always reflect whether there is data in the h/w // buffers, particularly if a track has been paused and resumed during draining constexpr float MIN_SPEED = 0.125f; // min speed scaling allowed for timely response. if (mPresentationCompleteTimeNs == 0) { mPresentationCompleteTimeNs = systemTime() + latencyMs * 1e6 / fmax(mSpeed, MIN_SPEED); ALOGV("%s(%d): set: latencyMs %u mPresentationCompleteTimeNs:%lld", __func__, mId, latencyMs, (long long) mPresentationCompleteTimeNs); } bool complete; if (isOffloaded()) { complete = true; } else { // Direct complete = systemTime() >= mPresentationCompleteTimeNs; ALOGV("%s(%d): %s", __func__, mId, (complete ? "complete" : "waiting")); } if (complete) { notifyPresentationComplete(); return true; } return false; } void AudioFlinger::PlaybackThread::Track::notifyPresentationComplete() { // This only triggers once. TODO: should we enforce this? triggerEvents(AudioSystem::SYNC_EVENT_PRESENTATION_COMPLETE); mAudioTrackServerProxy->setStreamEndDone(); } void AudioFlinger::PlaybackThread::Track::triggerEvents(AudioSystem::sync_event_t type) { for (size_t i = 0; i < mSyncEvents.size();) { Loading Loading
services/audioflinger/PlaybackTracks.h +22 −4 Original line number Diff line number Diff line Loading @@ -222,10 +222,23 @@ protected: sp<IMemory> sharedBuffer() const { return mSharedBuffer; } // presentationComplete checked by frames. (Mixed Tracks). // framesWritten is cumulative, never reset, and is shared all tracks // audioHalFrames is derived from output latency // FIXME parameters not needed, could get them from the thread bool presentationComplete(int64_t framesWritten, size_t audioHalFrames); // presentationComplete checked by time. (Direct Tracks). bool presentationComplete(uint32_t latencyMs); void resetPresentationComplete() { mPresentationCompleteFrames = 0; mPresentationCompleteTimeNs = 0; } // notifyPresentationComplete is called when presentationComplete() detects // that the track is finished stopping. void notifyPresentationComplete(); void signalClientFlag(int32_t flag); public: Loading Loading @@ -256,9 +269,6 @@ protected: int32_t *mAuxBuffer; int mAuxEffectId; bool mHasVolumeController; size_t mPresentationCompleteFrames; // number of frames written to the // audio HAL when this track will be fully rendered // zero means not monitoring // access these three variables only when holding thread lock. LinearMap<int64_t> mFrameMap; // track frame to server frame mapping Loading Loading @@ -294,6 +304,14 @@ private: for (auto& tp : mTeePatches) { f(tp.patchTrack); } }; size_t mPresentationCompleteFrames = 0; // (Used for Mixed tracks) // The number of frames written to the // audio HAL when this track is considered fully rendered. // Zero means not monitoring. int64_t mPresentationCompleteTimeNs = 0; // (Used for Direct tracks) // The time when this track is considered fully rendered. // Zero means not monitoring. // The following fields are only for fast tracks, and should be in a subclass int mFastIndex; // index within FastMixerState::mFastTracks[]; // either mFastIndex == -1 if not isFastTrack() Loading
services/audioflinger/Threads.cpp +3 −18 Original line number Diff line number Diff line Loading @@ -2631,7 +2631,7 @@ status_t AudioFlinger::PlaybackThread::addTrack_l(const sp<Track>& track) } track->mResetDone = false; track->mPresentationCompleteFrames = 0; track->resetPresentationComplete(); mActiveTracks.add(track); if (chain != 0) { ALOGV("addTrack_l() starting track on chain %p for session %d", chain.get(), Loading Loading @@ -6038,16 +6038,8 @@ AudioFlinger::PlaybackThread::mixer_state AudioFlinger::DirectOutputThread::prep track->isStopping_2() || track->isPaused()) { // We have consumed all the buffers of this track. // Remove it from the list of active tracks. size_t audioHALFrames; if (audio_has_proportional_frames(mFormat)) { audioHALFrames = (latency_l() * mSampleRate) / 1000; } else { audioHALFrames = 0; } int64_t framesWritten = mBytesWritten / mFrameSize; if (mStandby || !last || track->presentationComplete(framesWritten, audioHALFrames) || track->presentationComplete(latency_l()) || track->isPaused() || mHwPaused) { if (track->isStopping_2()) { track->mState = TrackBase::STOPPED; Loading Loading @@ -6621,14 +6613,7 @@ AudioFlinger::PlaybackThread::mixer_state AudioFlinger::OffloadThread::prepareTr // Drain has completed or we are in standby, signal presentation complete if (!(mDrainSequence & 1) || !last || mStandby) { track->mState = TrackBase::STOPPED; uint32_t latency = 0; status_t result = mOutput->stream->getLatency(&latency); ALOGE_IF(result != OK, "Error when retrieving output stream latency: %d", result); size_t audioHALFrames = (latency * mSampleRate) / 1000; int64_t framesWritten = mBytesWritten / mOutput->getFrameSize(); track->presentationComplete(framesWritten, audioHALFrames); track->presentationComplete(latency_l()); track->reset(); tracksToRemove->add(track); // OFFLOADED stop resets frame counts. Loading
services/audioflinger/Tracks.cpp +47 −7 Original line number Diff line number Diff line Loading @@ -650,7 +650,6 @@ AudioFlinger::PlaybackThread::Track::Track( mMainBuffer(thread->sinkBuffer()), mAuxBuffer(NULL), mAuxEffectId(0), mHasVolumeController(false), mPresentationCompleteFrames(0), mFrameMap(16 /* sink-frame-to-track-frame map memory */), mVolumeHandler(new media::VolumeHandler(sampleRate)), mOpPlayAudioMonitor(OpPlayAudioMonitor::createIfNeeded(attributionSource, attr, id(), Loading Loading @@ -1462,6 +1461,7 @@ void AudioFlinger::PlaybackThread::Track::setAuxBuffer(int EffectId, int32_t *bu mAuxBuffer = buffer; } // presentationComplete verified by frames, used by Mixed tracks. bool AudioFlinger::PlaybackThread::Track::presentationComplete( int64_t framesWritten, size_t audioHalFrames) { Loading @@ -1480,30 +1480,70 @@ bool AudioFlinger::PlaybackThread::Track::presentationComplete( (long long)mPresentationCompleteFrames, (long long)framesWritten); if (mPresentationCompleteFrames == 0) { mPresentationCompleteFrames = framesWritten + audioHalFrames; ALOGV("%s(%d): presentationComplete() reset:" ALOGV("%s(%d): set:" " mPresentationCompleteFrames %lld audioHalFrames %zu", __func__, mId, (long long)mPresentationCompleteFrames, audioHalFrames); } bool complete; if (isOffloaded()) { complete = true; } else if (isDirect() || isFastTrack()) { // these do not go through linear map if (isFastTrack()) { // does not go through linear map complete = framesWritten >= (int64_t) mPresentationCompleteFrames; ALOGV("%s(%d): %s framesWritten:%lld mPresentationCompleteFrames:%lld", __func__, mId, (complete ? "complete" : "waiting"), (long long) framesWritten, (long long) mPresentationCompleteFrames); } else { // Normal tracks, OutputTracks, and PatchTracks complete = framesWritten >= (int64_t) mPresentationCompleteFrames && mAudioTrackServerProxy->isDrained(); } if (complete) { triggerEvents(AudioSystem::SYNC_EVENT_PRESENTATION_COMPLETE); mAudioTrackServerProxy->setStreamEndDone(); notifyPresentationComplete(); return true; } return false; } // presentationComplete checked by time, used by DirectTracks. bool AudioFlinger::PlaybackThread::Track::presentationComplete(uint32_t latencyMs) { // For Offloaded or Direct tracks. // For a direct track, we incorporated time based testing for presentationComplete. // For an offloaded track the HAL+h/w delay is variable so a HAL drain() is used // to detect when all frames have been played. In this case latencyMs isn't // useful because it doesn't always reflect whether there is data in the h/w // buffers, particularly if a track has been paused and resumed during draining constexpr float MIN_SPEED = 0.125f; // min speed scaling allowed for timely response. if (mPresentationCompleteTimeNs == 0) { mPresentationCompleteTimeNs = systemTime() + latencyMs * 1e6 / fmax(mSpeed, MIN_SPEED); ALOGV("%s(%d): set: latencyMs %u mPresentationCompleteTimeNs:%lld", __func__, mId, latencyMs, (long long) mPresentationCompleteTimeNs); } bool complete; if (isOffloaded()) { complete = true; } else { // Direct complete = systemTime() >= mPresentationCompleteTimeNs; ALOGV("%s(%d): %s", __func__, mId, (complete ? "complete" : "waiting")); } if (complete) { notifyPresentationComplete(); return true; } return false; } void AudioFlinger::PlaybackThread::Track::notifyPresentationComplete() { // This only triggers once. TODO: should we enforce this? triggerEvents(AudioSystem::SYNC_EVENT_PRESENTATION_COMPLETE); mAudioTrackServerProxy->setStreamEndDone(); } void AudioFlinger::PlaybackThread::Track::triggerEvents(AudioSystem::sync_event_t type) { for (size_t i = 0; i < mSyncEvents.size();) { Loading