audio flinger: fix wraparound issues in AudioRecord shared audi history implementation
Fix issues with the implementation of the shared audio history record start
point in RecordThread input resampling buffer when indexes wrapround.
Bug: 185972521
Test: atest AudioRecordSharedAudioTest
Change-Id: Idcb664f1253b5a488991b39647c13087fc46b0c4
diff --git a/services/audioflinger/RecordTracks.h b/services/audioflinger/RecordTracks.h
index b953c0b..451c198 100644
--- a/services/audioflinger/RecordTracks.h
+++ b/services/audioflinger/RecordTracks.h
@@ -70,7 +70,7 @@
audio_input_flags_t flags,
track_type type,
audio_port_handle_t portId = AUDIO_PORT_HANDLE_NONE,
- int64_t startTimeMs = -1);
+ int32_t startFrames = -1);
virtual ~RecordTrack();
virtual status_t initCheck() const;
@@ -110,7 +110,7 @@
status_t setPreferredMicrophoneFieldDimension(float zoom);
status_t shareAudioHistory(const std::string& sharedAudioPackageName,
int64_t sharedAudioStartMs);
- int64_t startTimeMs() { return mStartTimeMs; }
+ int32_t startFrames() { return mStartFrames; }
static bool checkServerLatencySupported(
audio_format_t format, audio_input_flags_t flags) {
@@ -152,7 +152,7 @@
// used to enforce OP_RECORD_AUDIO
sp<OpRecordAudioMonitor> mOpRecordAudioMonitor;
std::string mSharedAudioPackageName = {};
- int64_t mStartTimeMs = -1;
+ int32_t mStartFrames = -1;
};
// playback track, used by PatchPanel
diff --git a/services/audioflinger/Threads.cpp b/services/audioflinger/Threads.cpp
index 6da4543..d6594bd 100644
--- a/services/audioflinger/Threads.cpp
+++ b/services/audioflinger/Threads.cpp
@@ -7932,18 +7932,18 @@
{ // scope for mLock
Mutex::Autolock _l(mLock);
- long startTimeMs = -1;
+ int32_t startFrames = -1;
if (!mSharedAudioPackageName.empty()
&& mSharedAudioPackageName == checkedIdentity.packageName
&& mSharedAudioSessionId == sessionId
&& captureHotwordAllowed(checkedIdentity)) {
- startTimeMs = mSharedAudioStartMs;
+ startFrames = mSharedAudioStartFrames;
}
track = new RecordTrack(this, client, attr, sampleRate,
format, channelMask, frameCount,
nullptr /* buffer */, (size_t)0 /* bufferSize */, sessionId, creatorPid,
- checkedIdentity, *flags, TrackBase::TYPE_DEFAULT, portId, startTimeMs);
+ checkedIdentity, *flags, TrackBase::TYPE_DEFAULT, portId, startFrames);
lStatus = track->initCheck();
if (lStatus != NO_ERROR) {
@@ -8200,17 +8200,32 @@
if ((hasAudioSession_l(sharedSessionId) & ThreadBase::TRACK_SESSION) == 0) {
return BAD_VALUE;
}
- if (sharedAudioStartMs < 0 || sharedAudioStartMs * mSampleRate / 1000 > mRsmpInRear) {
+
+ if (sharedAudioStartMs < 0
+ || sharedAudioStartMs > INT64_MAX / mSampleRate) {
return BAD_VALUE;
}
+ // Current implementation of the input resampling buffer wraps around indexes at 32 bit.
+ // As we cannot detect more than one wraparound, only accept values up current write position
+ // after one wraparound
+ // We assume recent wraparounds on mRsmpInRear only given it is unlikely that the requesting
+ // app waits several hours after the start time was computed.
+ const int64_t sharedAudioStartFrames = sharedAudioStartMs * mSampleRate / 1000;
+ const int32_t sharedOffset = audio_utils::safe_sub_overflow(mRsmpInRear,
+ (int32_t)sharedAudioStartFrames);
+ if (sharedOffset < 0
+ || sharedOffset > mRsmpInFrames) {
+ return BAD_VALUE;
+ }
+
mSharedAudioPackageName = sharedAudioPackageName;
if (mSharedAudioPackageName.empty()) {
mSharedAudioSessionId = AUDIO_SESSION_NONE;
- mSharedAudioStartMs = -1;
+ mSharedAudioStartFrames = -1;
} else {
mSharedAudioSessionId = sharedSessionId;
- mSharedAudioStartMs = sharedAudioStartMs;
+ mSharedAudioStartFrames = (int32_t)sharedAudioStartFrames;
}
return NO_ERROR;
}
@@ -8357,14 +8372,14 @@
mRsmpInUnrel = 0;
const int32_t rear = recordThread->mRsmpInRear;
ssize_t deltaFrames = 0;
- if (mRecordTrack->startTimeMs() >= 0) {
- int32_t startFrames = mRecordTrack->startTimeMs() * recordThread->sampleRate() / 1000;
- // start frame has to be in the past
- //TODO: b/185972521 fix in case rear or startFrames wrap around
- if (startFrames > rear) {
- startFrames = rear;
+ if (mRecordTrack->startFrames() >= 0) {
+ int32_t startFrames = mRecordTrack->startFrames();
+ // Accept a recent wraparound of mRsmpInRear
+ if (startFrames <= rear) {
+ deltaFrames = rear - startFrames;
+ } else {
+ deltaFrames = (int32_t)((int64_t)rear + UINT32_MAX + 1 - startFrames);
}
- deltaFrames = rear - startFrames;
// start frame cannot be further in the past than start of resampling buffer
if ((size_t) deltaFrames > recordThread->mRsmpInFrames) {
deltaFrames = recordThread->mRsmpInFrames;
@@ -8826,17 +8841,22 @@
if (mTracks.size() == 0) {
return 0;
}
- //TODO: b/185972521 fix in case of wrap around on one track:
- // want the max(rear - front) for all tracks.
- int32_t front = INT_MAX;
+ int32_t oldestFront = mRsmpInRear;
+ int32_t maxFilled = 0;
for (size_t i = 0; i < mTracks.size(); i++) {
- front = std::min(front, mTracks[i]->mResamplerBufferProvider->getFront());
+ int32_t front = mTracks[i]->mResamplerBufferProvider->getFront();
+ int32_t filled;
+ if (front <= mRsmpInRear) {
+ filled = mRsmpInRear - front;
+ } else {
+ filled = (int32_t)((int64_t)mRsmpInRear + UINT32_MAX + 1 - front);
+ }
+ if (filled > maxFilled) {
+ oldestFront = front;
+ maxFilled = filled;
+ }
}
- // discard any audio past the buffer size
- if (audio_utils::safe_add_overflow(front, (int32_t)mRsmpInFrames) < mRsmpInRear) {
- front = audio_utils::safe_sub_overflow(mRsmpInRear, (int32_t)mRsmpInFrames);
- }
- return front;
+ return oldestFront;
}
void AudioFlinger::RecordThread::updateFronts_l(int32_t offset)
diff --git a/services/audioflinger/Threads.h b/services/audioflinger/Threads.h
index 03ed6fd..b6f7f24 100644
--- a/services/audioflinger/Threads.h
+++ b/services/audioflinger/Threads.h
@@ -1863,7 +1863,7 @@
DeviceDescriptorBaseVector mOutDevices;
std::string mSharedAudioPackageName = {};
- long mSharedAudioStartMs = 0;
+ int32_t mSharedAudioStartFrames = -1;
audio_session_t mSharedAudioSessionId = AUDIO_SESSION_NONE;
};
diff --git a/services/audioflinger/Tracks.cpp b/services/audioflinger/Tracks.cpp
index 6549236..3e04804 100644
--- a/services/audioflinger/Tracks.cpp
+++ b/services/audioflinger/Tracks.cpp
@@ -2378,7 +2378,7 @@
audio_input_flags_t flags,
track_type type,
audio_port_handle_t portId,
- int64_t startTimeMs)
+ int32_t startFrames)
: TrackBase(thread, client, attr, sampleRate, format,
channelMask, frameCount, buffer, bufferSize, sessionId,
creatorPid,
@@ -2396,7 +2396,7 @@
mFlags(flags),
mSilenced(false),
mOpRecordAudioMonitor(OpRecordAudioMonitor::createIfNeeded(identity, attr)),
- mStartTimeMs(startTimeMs)
+ mStartFrames(startFrames)
{
if (mCblk == NULL) {
return;