diff options
-rw-r--r-- | services/audioflinger/PlaybackTracks.h | 15 | ||||
-rw-r--r-- | services/audioflinger/Threads.cpp | 23 | ||||
-rw-r--r-- | services/audioflinger/Threads.h | 30 | ||||
-rw-r--r-- | services/audioflinger/Tracks.cpp | 10 |
4 files changed, 69 insertions, 9 deletions
diff --git a/services/audioflinger/PlaybackTracks.h b/services/audioflinger/PlaybackTracks.h index 3381e773db..a93899b7b4 100644 --- a/services/audioflinger/PlaybackTracks.h +++ b/services/audioflinger/PlaybackTracks.h @@ -244,7 +244,7 @@ public: AudioSystem::SYNC_EVENT_NONE, audio_session_t triggerSession = AUDIO_SESSION_NONE); virtual void stop(); - bool write(void* data, uint32_t frames); + ssize_t write(void* data, uint32_t frames); bool bufferQueueEmpty() const { return mBufferQueue.size() == 0; } bool isActive() const { return mActive; } const wp<ThreadBase>& thread() const { return mThread; } @@ -252,6 +252,18 @@ public: void copyMetadataTo(MetadataInserter& backInserter) const override; /** Set the metadatas of the upstream tracks. Thread safe. */ void setMetadatas(const SourceMetadatas& metadatas); + /** returns client timestamp to the upstream duplicating thread. */ + ExtendedTimestamp getClientProxyTimestamp() const { + // server - kernel difference is not true latency when drained + // i.e. mServerProxy->isDrained(). + ExtendedTimestamp timestamp; + (void) mClientProxy->getTimestamp(×tamp); + // On success, the timestamp LOCATION_SERVER and LOCATION_KERNEL + // entries will be properly filled. If getTimestamp() + // is unsuccessful, then a default initialized timestamp + // (with mTimeNs[] filled with -1's) is returned. + return timestamp; + } private: status_t obtainBuffer(AudioBufferProvider::Buffer* buffer, @@ -268,6 +280,7 @@ private: bool mActive; DuplicatingThread* const mSourceThread; // for waitTimeMs() in write() sp<AudioTrackClientProxy> mClientProxy; + /** Attributes of the source tracks. * * This member must be accessed with mTrackMetadatasMutex taken. diff --git a/services/audioflinger/Threads.cpp b/services/audioflinger/Threads.cpp index d61b1f0d15..b737edec1f 100644 --- a/services/audioflinger/Threads.cpp +++ b/services/audioflinger/Threads.cpp @@ -3203,12 +3203,10 @@ bool AudioFlinger::PlaybackThread::threadLoop() // and associate with the sink frames written out. We need // this to convert the sink timestamp to the track timestamp. bool kernelLocationUpdate = false; - if (mNormalSink != 0) { - // Note: The DuplicatingThread may not have a mNormalSink. + ExtendedTimestamp timestamp; // use private copy to fetch + if (threadloop_getHalTimestamp_l(×tamp) == OK) { // We always fetch the timestamp here because often the downstream // sink will block while writing. - ExtendedTimestamp timestamp; // use private copy to fetch - (void) mNormalSink->getTimestamp(timestamp); // We keep track of the last valid kernel position in case we are in underrun // and the normal mixer period is the same as the fast mixer period, or there @@ -6096,7 +6094,22 @@ void AudioFlinger::DuplicatingThread::threadLoop_sleepTime() ssize_t AudioFlinger::DuplicatingThread::threadLoop_write() { for (size_t i = 0; i < outputTracks.size(); i++) { - outputTracks[i]->write(mSinkBuffer, writeFrames); + const ssize_t actualWritten = outputTracks[i]->write(mSinkBuffer, writeFrames); + + // Consider the first OutputTrack for timestamp and frame counting. + + // The threadLoop() generally assumes writing a full sink buffer size at a time. + // Here, we correct for writeFrames of 0 (a stop) or underruns because + // we always claim success. + if (i == 0) { + const ssize_t correction = mSinkBufferSize / mFrameSize - actualWritten; + ALOGD_IF(correction != 0 && writeFrames != 0, + "%s: writeFrames:%u actualWritten:%zd correction:%zd mFramesWritten:%lld", + __func__, writeFrames, actualWritten, correction, (long long)mFramesWritten); + mFramesWritten -= correction; + } + + // TODO: Report correction for the other output tracks and show in the dump. } mStandby = false; return (ssize_t)mSinkBufferSize; diff --git a/services/audioflinger/Threads.h b/services/audioflinger/Threads.h index 680e021ade..b691ca9612 100644 --- a/services/audioflinger/Threads.h +++ b/services/audioflinger/Threads.h @@ -434,6 +434,12 @@ protected: virtual void setMasterMono_l(bool mono __unused) { } virtual bool requireMonoBlend() { return false; } + // called within the threadLoop to obtain timestamp from the HAL. + virtual status_t threadloop_getHalTimestamp_l( + ExtendedTimestamp *timestamp __unused) const { + return INVALID_OPERATION; + } + friend class AudioFlinger; // for mEffectChains const type_t mType; @@ -1150,6 +1156,14 @@ public: return mFastMixerDumpState.mTracks[fastIndex].mUnderruns; } + status_t threadloop_getHalTimestamp_l( + ExtendedTimestamp *timestamp) const override { + if (mNormalSink.get() != nullptr) { + return mNormalSink->getTimestamp(*timestamp); + } + return INVALID_OPERATION; + } + protected: virtual void setMasterMono_l(bool mono) { mMasterMono.store(mono); @@ -1314,6 +1328,22 @@ private: SortedVector < sp<OutputTrack> > mOutputTracks; public: virtual bool hasFastMixer() const { return false; } + status_t threadloop_getHalTimestamp_l( + ExtendedTimestamp *timestamp) const override { + if (mOutputTracks.size() > 0) { + // forward the first OutputTrack's kernel information for timestamp. + const ExtendedTimestamp trackTimestamp = + mOutputTracks[0]->getClientProxyTimestamp(); + if (trackTimestamp.mTimeNs[ExtendedTimestamp::LOCATION_KERNEL] > 0) { + timestamp->mTimeNs[ExtendedTimestamp::LOCATION_KERNEL] = + trackTimestamp.mTimeNs[ExtendedTimestamp::LOCATION_KERNEL]; + timestamp->mPosition[ExtendedTimestamp::LOCATION_KERNEL] = + trackTimestamp.mPosition[ExtendedTimestamp::LOCATION_KERNEL]; + return OK; // discard server timestamp - that's ignored. + } + } + return INVALID_OPERATION; + } }; // record thread diff --git a/services/audioflinger/Tracks.cpp b/services/audioflinger/Tracks.cpp index 5966f85814..4fa024ea32 100644 --- a/services/audioflinger/Tracks.cpp +++ b/services/audioflinger/Tracks.cpp @@ -435,7 +435,8 @@ AudioFlinger::PlaybackThread::Track::Track( } mName = TRACK_NAME_PENDING; - mServerLatencySupported = thread->type() == ThreadBase::MIXER; + mServerLatencySupported = thread->type() == ThreadBase::MIXER + || thread->type() == ThreadBase::DUPLICATING; #ifdef TEE_SINK mTee.setId(std::string("_") + std::to_string(mThreadIoHandle) + "_" + std::to_string(mId) + @@ -1354,7 +1355,7 @@ void AudioFlinger::PlaybackThread::OutputTrack::stop() mActive = false; } -bool AudioFlinger::PlaybackThread::OutputTrack::write(void* data, uint32_t frames) +ssize_t AudioFlinger::PlaybackThread::OutputTrack::write(void* data, uint32_t frames) { Buffer *pInBuffer; Buffer inBuffer; @@ -1443,9 +1444,12 @@ bool AudioFlinger::PlaybackThread::OutputTrack::write(void* data, uint32_t frame mBufferQueue.add(pInBuffer); ALOGV("OutputTrack::write() %p thread %p adding overflow buffer %zu", this, mThread.unsafe_get(), mBufferQueue.size()); + // audio data is consumed (stored locally); set frameCount to 0. + inBuffer.frameCount = 0; } else { ALOGW("OutputTrack::write() %p thread %p no more overflow buffers", mThread.unsafe_get(), this); + // TODO: return error for this. } } } @@ -1456,7 +1460,7 @@ bool AudioFlinger::PlaybackThread::OutputTrack::write(void* data, uint32_t frame stop(); } - return outputBufferFull; + return frames - inBuffer.frameCount; // number of frames consumed. } void AudioFlinger::PlaybackThread::OutputTrack::copyMetadataTo(MetadataInserter& backInserter) const |