AudioFlinger: synchronize OutputTracks start on duplicating threads
When playback starts on a duplicating thread and target output
mixer threads exit standby, it is possible that one output stream takes
a long time to actually start playback (e.g. for Bluetooth software
encoder path). In this case, the OutputTrack on the other mixer thread
will underrun and audio will get choppy on this output stream.
In order to avoid this, an actual stream start detection mechanism is
added on the mixer thread and the OutputTrack write method will wait
for the target thread to actually start when exiting standby before
sending actual audio.
Bug: 218803475
Test: repro steps in bug
Change-Id: I0eec8c5817c97f7b7643a7151037aff5dc73f3ae
Merged-In: I0eec8c5817c97f7b7643a7151037aff5dc73f3ae
diff --git a/services/audioflinger/Threads.h b/services/audioflinger/Threads.h
index 7b4c150..e88134b 100644
--- a/services/audioflinger/Threads.h
+++ b/services/audioflinger/Threads.h
@@ -1116,6 +1116,32 @@
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
@@ -1415,6 +1441,14 @@
// 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