summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--services/audioflinger/PlaybackTracks.h15
-rw-r--r--services/audioflinger/Threads.cpp23
-rw-r--r--services/audioflinger/Threads.h30
-rw-r--r--services/audioflinger/Tracks.cpp10
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(&timestamp);
+ // 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(&timestamp) == 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