Loading services/audioflinger/PlaybackTracks.h +1 −0 Original line number Diff line number Diff line Loading @@ -426,6 +426,7 @@ public: private: status_t obtainBuffer(AudioBufferProvider::Buffer* buffer, uint32_t waitTimeMs); void queueBuffer(Buffer& inBuffer); void clearBufferQueue(); void restartIfDisabled(); Loading services/audioflinger/Threads.cpp +12 −4 Original line number Diff line number Diff line Loading @@ -4023,7 +4023,7 @@ NO_THREAD_SAFETY_ANALYSIS // manual locking of AudioFlinger LOG_AUDIO_STATE(); mThreadMetrics.logEndInterval(); mThreadSnapshot.onEnd(); mStandby = true; setStandby_l(); } sendStatistics(false /* force */); } Loading Loading @@ -4103,6 +4103,14 @@ NO_THREAD_SAFETY_ANALYSIS // manual locking of AudioFlinger activeTracks.insert(activeTracks.end(), mActiveTracks.begin(), mActiveTracks.end()); setHalLatencyMode_l(); // signal actual start of output stream when the render position reported by the kernel // starts moving. if (!mStandby && !mHalStarted && mKernelPositionOnStandby != mTimestamp.mPosition[ExtendedTimestamp::LOCATION_KERNEL]) { mHalStarted = true; mWaitHalStartCV.broadcast(); } } // mLock scope ends if (mBytesRemaining == 0) { Loading Loading @@ -4488,7 +4496,7 @@ NO_THREAD_SAFETY_ANALYSIS // manual locking of AudioFlinger if (!mStandby) { threadLoop_standby(); mStandby = true; setStandby(); } releaseWakeLock(); Loading Loading @@ -6239,7 +6247,7 @@ bool AudioFlinger::MixerThread::checkForNewParameter_l(const String8& keyValuePa if (!mStandby) { mThreadMetrics.logEndInterval(); mThreadSnapshot.onEnd(); mStandby = true; setStandby_l(); } mBytesWritten = 0; status = mOutput->stream->setParameters(keyValuePair); Loading Loading @@ -6890,7 +6898,7 @@ bool AudioFlinger::DirectOutputThread::checkForNewParameter_l(const String8& key if (!mStandby) { mThreadMetrics.logEndInterval(); mThreadSnapshot.onEnd(); mStandby = true; setStandby_l(); } mBytesWritten = 0; status = mOutput->stream->setParameters(keyValuePair); Loading services/audioflinger/Threads.h +34 −0 Original line number Diff line number Diff line Loading @@ -1116,6 +1116,32 @@ public: void startMelComputation_l(const sp<audio_utils::MelProcessor>& processor) override; void stopMelComputation_l() override; void setStandby() { Mutex::Autolock _l(mLock); setStandby_l(); } void setStandby_l() { mStandby = true; mHalStarted = false; mKernelPositionOnStandby = mTimestamp.mPosition[ExtendedTimestamp::LOCATION_KERNEL]; } bool waitForHalStart() { Mutex::Autolock _l(mLock); static const nsecs_t kWaitHalTimeoutNs = seconds(2); nsecs_t endWaitTimetNs = systemTime() + kWaitHalTimeoutNs; while (!mHalStarted) { nsecs_t timeNs = systemTime(); if (timeNs >= endWaitTimetNs) { break; } nsecs_t waitTimeLeftNs = endWaitTimetNs - timeNs; mWaitHalStartCV.waitRelative(mLock, waitTimeLeftNs); } return mHalStarted; } protected: // updated by readOutputParameters_l() size_t mNormalFrameCount; // normal mixer and effects Loading Loading @@ -1415,6 +1441,14 @@ private: // Downstream patch latency, available if mDownstreamLatencyStatMs.getN() > 0. audio_utils::Statistics<double> mDownstreamLatencyStatMs{0.999}; // output stream start detection based on render position returned by the kernel // condition signalled when the output stream has started Condition mWaitHalStartCV; // true when the output stream render position has moved, reset to false in standby bool mHalStarted = false; // last kernel render position saved when entering standby int64_t mKernelPositionOnStandby = 0; public: virtual bool hasFastMixer() const = 0; virtual FastTrackUnderruns getFastTrackUnderruns(size_t fastIndex __unused) const Loading services/audioflinger/Tracks.cpp +63 −25 Original line number Diff line number Diff line Loading @@ -2056,17 +2056,50 @@ void AudioFlinger::PlaybackThread::OutputTrack::stop() ssize_t AudioFlinger::PlaybackThread::OutputTrack::write(void* data, uint32_t frames) { Buffer *pInBuffer; Buffer inBuffer; inBuffer.frameCount = frames; inBuffer.raw = data; if (!mActive && frames != 0) { sp<ThreadBase> thread = mThread.promote(); if (thread != nullptr && thread->standby()) { // preload one silent buffer to trigger mixer on start() ClientProxy::Buffer buf { .mFrameCount = mClientProxy->getStartThresholdInFrames() }; status_t status = mClientProxy->obtainBuffer(&buf); if (status != NO_ERROR && status != NOT_ENOUGH_DATA && status != WOULD_BLOCK) { ALOGE("%s(%d): could not obtain buffer on start", __func__, mId); return 0; } memset(buf.mRaw, 0, buf.mFrameCount * mFrameSize); mClientProxy->releaseBuffer(&buf); uint32_t waitTimeLeftMs = mSourceThread->waitTimeMs(); (void) start(); if (!mActive && frames != 0) { // wait for HAL stream to start before sending actual audio. Doing this on each // OutputTrack makes that playback start on all output streams is synchronized. // If another OutputTrack has already started it can underrun but this is OK // as only silence has been played so far and the retry count is very high on // OutputTrack. auto pt = static_cast<PlaybackThread *>(thread.get()); if (!pt->waitForHalStart()) { ALOGW("%s(%d): timeout waiting for thread to exit standby", __func__, mId); stop(); return 0; } // enqueue the first buffer and exit so that other OutputTracks will also start before // write() is called again and this buffer actually consumed. Buffer firstBuffer; firstBuffer.frameCount = frames; firstBuffer.raw = data; queueBuffer(firstBuffer); return frames; } else { (void) start(); } } Buffer *pInBuffer; Buffer inBuffer; inBuffer.frameCount = frames; inBuffer.raw = data; uint32_t waitTimeLeftMs = mSourceThread->waitTimeMs(); while (waitTimeLeftMs) { // First write pending buffers, then new data if (mBufferQueue.size()) { Loading Loading @@ -2134,8 +2167,23 @@ ssize_t AudioFlinger::PlaybackThread::OutputTrack::write(void* data, uint32_t fr if (inBuffer.frameCount) { sp<ThreadBase> thread = mThread.promote(); if (thread != 0 && !thread->standby()) { queueBuffer(inBuffer); } } // Calling write() with a 0 length buffer means that no more data will be written: // We rely on stop() to set the appropriate flags to allow the remaining frames to play out. if (frames == 0 && mBufferQueue.size() == 0 && mActive) { stop(); } return frames - inBuffer.frameCount; // number of frames consumed. } void AudioFlinger::PlaybackThread::OutputTrack::queueBuffer(Buffer& inBuffer) { if (mBufferQueue.size() < kMaxOverFlowBuffers) { pInBuffer = new Buffer; Buffer *pInBuffer = new Buffer; const size_t bufferSize = inBuffer.frameCount * mFrameSize; pInBuffer->mBuffer = malloc(bufferSize); LOG_ALWAYS_FATAL_IF(pInBuffer->mBuffer == nullptr, Loading @@ -2154,16 +2202,6 @@ ssize_t AudioFlinger::PlaybackThread::OutputTrack::write(void* data, uint32_t fr // TODO: return error for this. } } } // Calling write() with a 0 length buffer means that no more data will be written: // We rely on stop() to set the appropriate flags to allow the remaining frames to play out. if (frames == 0 && mBufferQueue.size() == 0 && mActive) { stop(); } return frames - inBuffer.frameCount; // number of frames consumed. } void AudioFlinger::PlaybackThread::OutputTrack::copyMetadataTo(MetadataInserter& backInserter) const { Loading Loading
services/audioflinger/PlaybackTracks.h +1 −0 Original line number Diff line number Diff line Loading @@ -426,6 +426,7 @@ public: private: status_t obtainBuffer(AudioBufferProvider::Buffer* buffer, uint32_t waitTimeMs); void queueBuffer(Buffer& inBuffer); void clearBufferQueue(); void restartIfDisabled(); Loading
services/audioflinger/Threads.cpp +12 −4 Original line number Diff line number Diff line Loading @@ -4023,7 +4023,7 @@ NO_THREAD_SAFETY_ANALYSIS // manual locking of AudioFlinger LOG_AUDIO_STATE(); mThreadMetrics.logEndInterval(); mThreadSnapshot.onEnd(); mStandby = true; setStandby_l(); } sendStatistics(false /* force */); } Loading Loading @@ -4103,6 +4103,14 @@ NO_THREAD_SAFETY_ANALYSIS // manual locking of AudioFlinger activeTracks.insert(activeTracks.end(), mActiveTracks.begin(), mActiveTracks.end()); setHalLatencyMode_l(); // signal actual start of output stream when the render position reported by the kernel // starts moving. if (!mStandby && !mHalStarted && mKernelPositionOnStandby != mTimestamp.mPosition[ExtendedTimestamp::LOCATION_KERNEL]) { mHalStarted = true; mWaitHalStartCV.broadcast(); } } // mLock scope ends if (mBytesRemaining == 0) { Loading Loading @@ -4488,7 +4496,7 @@ NO_THREAD_SAFETY_ANALYSIS // manual locking of AudioFlinger if (!mStandby) { threadLoop_standby(); mStandby = true; setStandby(); } releaseWakeLock(); Loading Loading @@ -6239,7 +6247,7 @@ bool AudioFlinger::MixerThread::checkForNewParameter_l(const String8& keyValuePa if (!mStandby) { mThreadMetrics.logEndInterval(); mThreadSnapshot.onEnd(); mStandby = true; setStandby_l(); } mBytesWritten = 0; status = mOutput->stream->setParameters(keyValuePair); Loading Loading @@ -6890,7 +6898,7 @@ bool AudioFlinger::DirectOutputThread::checkForNewParameter_l(const String8& key if (!mStandby) { mThreadMetrics.logEndInterval(); mThreadSnapshot.onEnd(); mStandby = true; setStandby_l(); } mBytesWritten = 0; status = mOutput->stream->setParameters(keyValuePair); Loading
services/audioflinger/Threads.h +34 −0 Original line number Diff line number Diff line Loading @@ -1116,6 +1116,32 @@ public: void startMelComputation_l(const sp<audio_utils::MelProcessor>& processor) override; void stopMelComputation_l() override; void setStandby() { Mutex::Autolock _l(mLock); setStandby_l(); } void setStandby_l() { mStandby = true; mHalStarted = false; mKernelPositionOnStandby = mTimestamp.mPosition[ExtendedTimestamp::LOCATION_KERNEL]; } bool waitForHalStart() { Mutex::Autolock _l(mLock); static const nsecs_t kWaitHalTimeoutNs = seconds(2); nsecs_t endWaitTimetNs = systemTime() + kWaitHalTimeoutNs; while (!mHalStarted) { nsecs_t timeNs = systemTime(); if (timeNs >= endWaitTimetNs) { break; } nsecs_t waitTimeLeftNs = endWaitTimetNs - timeNs; mWaitHalStartCV.waitRelative(mLock, waitTimeLeftNs); } return mHalStarted; } protected: // updated by readOutputParameters_l() size_t mNormalFrameCount; // normal mixer and effects Loading Loading @@ -1415,6 +1441,14 @@ private: // Downstream patch latency, available if mDownstreamLatencyStatMs.getN() > 0. audio_utils::Statistics<double> mDownstreamLatencyStatMs{0.999}; // output stream start detection based on render position returned by the kernel // condition signalled when the output stream has started Condition mWaitHalStartCV; // true when the output stream render position has moved, reset to false in standby bool mHalStarted = false; // last kernel render position saved when entering standby int64_t mKernelPositionOnStandby = 0; public: virtual bool hasFastMixer() const = 0; virtual FastTrackUnderruns getFastTrackUnderruns(size_t fastIndex __unused) const Loading
services/audioflinger/Tracks.cpp +63 −25 Original line number Diff line number Diff line Loading @@ -2056,17 +2056,50 @@ void AudioFlinger::PlaybackThread::OutputTrack::stop() ssize_t AudioFlinger::PlaybackThread::OutputTrack::write(void* data, uint32_t frames) { Buffer *pInBuffer; Buffer inBuffer; inBuffer.frameCount = frames; inBuffer.raw = data; if (!mActive && frames != 0) { sp<ThreadBase> thread = mThread.promote(); if (thread != nullptr && thread->standby()) { // preload one silent buffer to trigger mixer on start() ClientProxy::Buffer buf { .mFrameCount = mClientProxy->getStartThresholdInFrames() }; status_t status = mClientProxy->obtainBuffer(&buf); if (status != NO_ERROR && status != NOT_ENOUGH_DATA && status != WOULD_BLOCK) { ALOGE("%s(%d): could not obtain buffer on start", __func__, mId); return 0; } memset(buf.mRaw, 0, buf.mFrameCount * mFrameSize); mClientProxy->releaseBuffer(&buf); uint32_t waitTimeLeftMs = mSourceThread->waitTimeMs(); (void) start(); if (!mActive && frames != 0) { // wait for HAL stream to start before sending actual audio. Doing this on each // OutputTrack makes that playback start on all output streams is synchronized. // If another OutputTrack has already started it can underrun but this is OK // as only silence has been played so far and the retry count is very high on // OutputTrack. auto pt = static_cast<PlaybackThread *>(thread.get()); if (!pt->waitForHalStart()) { ALOGW("%s(%d): timeout waiting for thread to exit standby", __func__, mId); stop(); return 0; } // enqueue the first buffer and exit so that other OutputTracks will also start before // write() is called again and this buffer actually consumed. Buffer firstBuffer; firstBuffer.frameCount = frames; firstBuffer.raw = data; queueBuffer(firstBuffer); return frames; } else { (void) start(); } } Buffer *pInBuffer; Buffer inBuffer; inBuffer.frameCount = frames; inBuffer.raw = data; uint32_t waitTimeLeftMs = mSourceThread->waitTimeMs(); while (waitTimeLeftMs) { // First write pending buffers, then new data if (mBufferQueue.size()) { Loading Loading @@ -2134,8 +2167,23 @@ ssize_t AudioFlinger::PlaybackThread::OutputTrack::write(void* data, uint32_t fr if (inBuffer.frameCount) { sp<ThreadBase> thread = mThread.promote(); if (thread != 0 && !thread->standby()) { queueBuffer(inBuffer); } } // Calling write() with a 0 length buffer means that no more data will be written: // We rely on stop() to set the appropriate flags to allow the remaining frames to play out. if (frames == 0 && mBufferQueue.size() == 0 && mActive) { stop(); } return frames - inBuffer.frameCount; // number of frames consumed. } void AudioFlinger::PlaybackThread::OutputTrack::queueBuffer(Buffer& inBuffer) { if (mBufferQueue.size() < kMaxOverFlowBuffers) { pInBuffer = new Buffer; Buffer *pInBuffer = new Buffer; const size_t bufferSize = inBuffer.frameCount * mFrameSize; pInBuffer->mBuffer = malloc(bufferSize); LOG_ALWAYS_FATAL_IF(pInBuffer->mBuffer == nullptr, Loading @@ -2154,16 +2202,6 @@ ssize_t AudioFlinger::PlaybackThread::OutputTrack::write(void* data, uint32_t fr // TODO: return error for this. } } } // Calling write() with a 0 length buffer means that no more data will be written: // We rely on stop() to set the appropriate flags to allow the remaining frames to play out. if (frames == 0 && mBufferQueue.size() == 0 && mActive) { stop(); } return frames - inBuffer.frameCount; // number of frames consumed. } void AudioFlinger::PlaybackThread::OutputTrack::copyMetadataTo(MetadataInserter& backInserter) const { Loading