aaudio: refactor references to shared FIFO
Reduce passing of raw pointers.
Use shared_ptrs and unique_ptrs.
Simplify memory management.
Refactor FifoBuffer into two subclasses so that
the internal memory management is simpler.
Bug: 151650670
Test: OboeTester "TEST OUTPUT"
Test: disable EXCLUSIVE mode
Test: OboeTester "ECHO INPUT TO OUTPUT"
Test: disable INPUT EXCLUSIVE mode
Change-Id: I10981767f8719f3cc3525df211285c53219a7979
diff --git a/services/oboeservice/AAudioMixer.cpp b/services/oboeservice/AAudioMixer.cpp
index c5d40b8..ad4b830 100644
--- a/services/oboeservice/AAudioMixer.cpp
+++ b/services/oboeservice/AAudioMixer.cpp
@@ -45,7 +45,7 @@
memset(mOutputBuffer.get(), 0, mBufferSizeInBytes);
}
-int32_t AAudioMixer::mix(int streamIndex, FifoBuffer *fifo, bool allowUnderflow) {
+int32_t AAudioMixer::mix(int streamIndex, std::shared_ptr<FifoBuffer> fifo, bool allowUnderflow) {
WrappingBuffer wrappingBuffer;
float *destination = mOutputBuffer.get();
diff --git a/services/oboeservice/AAudioMixer.h b/services/oboeservice/AAudioMixer.h
index dd466ac..1a120f2 100644
--- a/services/oboeservice/AAudioMixer.h
+++ b/services/oboeservice/AAudioMixer.h
@@ -37,7 +37,7 @@
* @param allowUnderflow if true then allow mixer to advance read index past the write index
* @return frames read from this stream
*/
- int32_t mix(int streamIndex, android::FifoBuffer *fifo, bool allowUnderflow);
+ int32_t mix(int streamIndex, std::shared_ptr<android::FifoBuffer> fifo, bool allowUnderflow);
float *getOutputBuffer();
diff --git a/services/oboeservice/AAudioServiceEndpointCapture.cpp b/services/oboeservice/AAudioServiceEndpointCapture.cpp
index c603e4e..de36d50 100644
--- a/services/oboeservice/AAudioServiceEndpointCapture.cpp
+++ b/services/oboeservice/AAudioServiceEndpointCapture.cpp
@@ -75,48 +75,14 @@
// Distribute data to each active stream.
{ // brackets are for lock_guard
-
std::lock_guard <std::mutex> lock(mLockStreams);
for (const auto& clientStream : mRegisteredStreams) {
if (clientStream->isRunning() && !clientStream->isSuspended()) {
- int64_t clientFramesWritten = 0;
-
sp<AAudioServiceStreamShared> streamShared =
static_cast<AAudioServiceStreamShared *>(clientStream.get());
-
- {
- // Lock the AudioFifo to protect against close.
- std::lock_guard <std::mutex> lock(streamShared->getAudioDataQueueLock());
-
- FifoBuffer *fifo = streamShared->getAudioDataFifoBuffer_l();
- if (fifo != nullptr) {
-
- // Determine offset between framePosition in client's stream
- // vs the underlying MMAP stream.
- clientFramesWritten = fifo->getWriteCounter();
- // There are two indices that refer to the same frame.
- int64_t positionOffset = mmapFramesRead - clientFramesWritten;
- streamShared->setTimestampPositionOffset(positionOffset);
-
- // Is the buffer too full to write a burst?
- if (fifo->getEmptyFramesAvailable() <
- getFramesPerBurst()) {
- streamShared->incrementXRunCount();
- } else {
- fifo->write(mDistributionBuffer.get(), getFramesPerBurst());
- }
- clientFramesWritten = fifo->getWriteCounter();
- }
- }
-
- if (clientFramesWritten > 0) {
- // This timestamp represents the completion of data being written into the
- // client buffer. It is sent to the client and used in the timing model
- // to decide when data will be available to read.
- Timestamp timestamp(clientFramesWritten, AudioClock::getNanoseconds());
- streamShared->markTransferTime(timestamp);
- }
-
+ streamShared->writeDataIfRoom(mmapFramesRead,
+ mDistributionBuffer.get(),
+ getFramesPerBurst());
}
}
}
diff --git a/services/oboeservice/AAudioServiceEndpointPlay.cpp b/services/oboeservice/AAudioServiceEndpointPlay.cpp
index bda4b90..1603e41 100644
--- a/services/oboeservice/AAudioServiceEndpointPlay.cpp
+++ b/services/oboeservice/AAudioServiceEndpointPlay.cpp
@@ -100,9 +100,10 @@
{
// Lock the AudioFifo to protect against close.
std::lock_guard <std::mutex> lock(streamShared->getAudioDataQueueLock());
-
- FifoBuffer *fifo = streamShared->getAudioDataFifoBuffer_l();
- if (fifo != nullptr) {
+ std::shared_ptr<SharedRingBuffer> audioDataQueue
+ = streamShared->getAudioDataQueue_l();
+ std::shared_ptr<FifoBuffer> fifo;
+ if (audioDataQueue && (fifo = audioDataQueue->getFifoBuffer())) {
// Determine offset between framePosition in client's stream
// vs the underlying MMAP stream.
diff --git a/services/oboeservice/AAudioServiceStreamBase.cpp b/services/oboeservice/AAudioServiceStreamBase.cpp
index 663dae2..ea691cf 100644
--- a/services/oboeservice/AAudioServiceStreamBase.cpp
+++ b/services/oboeservice/AAudioServiceStreamBase.cpp
@@ -46,8 +46,7 @@
*/
AAudioServiceStreamBase::AAudioServiceStreamBase(AAudioService &audioService)
- : mUpMessageQueue(nullptr)
- , mTimestampThread("AATime")
+ : mTimestampThread("AATime")
, mAtomicStreamTimestamp()
, mAudioService(audioService) {
mMmapClient.clientUid = -1;
@@ -56,6 +55,8 @@
}
AAudioServiceStreamBase::~AAudioServiceStreamBase() {
+ ALOGD("%s() called", __func__);
+
// May not be set if open failed.
if (mMetricsId.size() > 0) {
mediametrics::LogItem(mMetricsId)
@@ -140,7 +141,7 @@
return AAUDIO_ERROR_INVALID_STATE;
}
- mUpMessageQueue = new SharedRingBuffer();
+ mUpMessageQueue = std::make_shared<SharedRingBuffer>();
result = mUpMessageQueue->allocate(sizeof(AAudioServiceMessage),
QUEUE_UP_CAPACITY_COMMANDS);
if (result != AAUDIO_OK) {
@@ -179,6 +180,8 @@
return AAUDIO_OK;
}
+ // This will call stopTimestampThread() and also stop the stream,
+ // just in case it was not already stopped.
stop_l();
aaudio_result_t result = AAUDIO_OK;
@@ -194,13 +197,6 @@
mServiceEndpoint.clear(); // endpoint will hold the pointer after this method returns.
}
- {
- std::lock_guard<std::mutex> lock(mUpMessageQueueLock);
- stopTimestampThread();
- delete mUpMessageQueue;
- mUpMessageQueue = nullptr;
- }
-
setState(AAUDIO_STREAM_STATE_CLOSED);
mediametrics::LogItem(mMetricsId)
@@ -514,12 +510,8 @@
ALOGE("%s(): mUpMessageQueue null! - stream not open", __func__);
return true;
}
- int32_t framesAvailable = mUpMessageQueue->getFifoBuffer()
- ->getFullFramesAvailable();
- int32_t capacity = mUpMessageQueue->getFifoBuffer()
- ->getBufferCapacityInFrames();
// Is it half full or more
- return framesAvailable >= (capacity / 2);
+ return mUpMessageQueue->getFractionalFullness() >= 0.5;
}
aaudio_result_t AAudioServiceStreamBase::writeUpMessageQueue(AAudioServiceMessage *command) {
diff --git a/services/oboeservice/AAudioServiceStreamBase.h b/services/oboeservice/AAudioServiceStreamBase.h
index 94cc980..51c26e9 100644
--- a/services/oboeservice/AAudioServiceStreamBase.h
+++ b/services/oboeservice/AAudioServiceStreamBase.h
@@ -284,8 +284,8 @@
pid_t mRegisteredClientThread = ILLEGAL_THREAD_ID;
- SharedRingBuffer* mUpMessageQueue;
std::mutex mUpMessageQueueLock;
+ std::shared_ptr<SharedRingBuffer> mUpMessageQueue;
AAudioThread mTimestampThread;
// This is used by one thread to tell another thread to exit. So it must be atomic.
diff --git a/services/oboeservice/AAudioServiceStreamShared.cpp b/services/oboeservice/AAudioServiceStreamShared.cpp
index f2cf016..e88a81e 100644
--- a/services/oboeservice/AAudioServiceStreamShared.cpp
+++ b/services/oboeservice/AAudioServiceStreamShared.cpp
@@ -59,12 +59,7 @@
result << AAudioServiceStreamBase::dump();
- auto fifo = mAudioDataQueue->getFifoBuffer();
- int32_t readCounter = fifo->getReadCounter();
- int32_t writeCounter = fifo->getWriteCounter();
- result << std::setw(10) << writeCounter;
- result << std::setw(10) << readCounter;
- result << std::setw(8) << (writeCounter - readCounter);
+ result << mAudioDataQueue->dump();
result << std::setw(8) << getXRunCount();
return result.str();
@@ -180,7 +175,7 @@
{
std::lock_guard<std::mutex> lock(mAudioDataQueueLock);
// Create audio data shared memory buffer for client.
- mAudioDataQueue = new SharedRingBuffer();
+ mAudioDataQueue = std::make_shared<SharedRingBuffer>();
result = mAudioDataQueue->allocate(calculateBytesPerFrame(), getBufferCapacity());
if (result != AAUDIO_OK) {
ALOGE("%s() could not allocate FIFO with %d frames",
@@ -203,18 +198,6 @@
return result;
}
-aaudio_result_t AAudioServiceStreamShared::close_l() {
- aaudio_result_t result = AAudioServiceStreamBase::close_l();
-
- {
- std::lock_guard<std::mutex> lock(mAudioDataQueueLock);
- delete mAudioDataQueue;
- mAudioDataQueue = nullptr;
- }
-
- return result;
-}
-
/**
* Get an immutable description of the data queue created by this service.
*/
@@ -273,3 +256,37 @@
*positionFrames = position;
return result;
}
+
+void AAudioServiceStreamShared::writeDataIfRoom(int64_t mmapFramesRead,
+ const void *buffer, int32_t numFrames) {
+ int64_t clientFramesWritten = 0;
+
+ // Lock the AudioFifo to protect against close.
+ std::lock_guard <std::mutex> lock(mAudioDataQueueLock);
+
+ if (mAudioDataQueue != nullptr) {
+ std::shared_ptr<FifoBuffer> fifo = mAudioDataQueue->getFifoBuffer();
+ // Determine offset between framePosition in client's stream
+ // vs the underlying MMAP stream.
+ clientFramesWritten = fifo->getWriteCounter();
+ // There are two indices that refer to the same frame.
+ int64_t positionOffset = mmapFramesRead - clientFramesWritten;
+ setTimestampPositionOffset(positionOffset);
+
+ // Is the buffer too full to write a burst?
+ if (fifo->getEmptyFramesAvailable() < getFramesPerBurst()) {
+ incrementXRunCount();
+ } else {
+ fifo->write(buffer, numFrames);
+ }
+ clientFramesWritten = fifo->getWriteCounter();
+ }
+
+ if (clientFramesWritten > 0) {
+ // This timestamp represents the completion of data being written into the
+ // client buffer. It is sent to the client and used in the timing model
+ // to decide when data will be available to read.
+ Timestamp timestamp(clientFramesWritten, AudioClock::getNanoseconds());
+ markTransferTime(timestamp);
+ }
+}
diff --git a/services/oboeservice/AAudioServiceStreamShared.h b/services/oboeservice/AAudioServiceStreamShared.h
index abcb782..5b1f8da 100644
--- a/services/oboeservice/AAudioServiceStreamShared.h
+++ b/services/oboeservice/AAudioServiceStreamShared.h
@@ -52,23 +52,23 @@
aaudio_result_t open(const aaudio::AAudioStreamRequest &request) override;
- aaudio_result_t close_l() override;
-
/**
- * This must be locked when calling getAudioDataFifoBuffer_l() and while
- * using the FifoBuffer it returns.
+ * This must be locked when calling getAudioDataQueue_l() and while
+ * using the FifoBuffer it contains.
*/
std::mutex &getAudioDataQueueLock() {
return mAudioDataQueueLock;
}
+ void writeDataIfRoom(int64_t mmapFramesRead, const void *buffer, int32_t numFrames);
+
/**
- * This must only be call under getAudioDataQueueLock().
+ * This must only be called under getAudioDataQueueLock().
* @return
*/
- android::FifoBuffer *getAudioDataFifoBuffer_l() { return (mAudioDataQueue == nullptr)
- ? nullptr
- : mAudioDataQueue->getFifoBuffer(); }
+ std::shared_ptr<SharedRingBuffer> getAudioDataQueue_l() {
+ return mAudioDataQueue;
+ }
/* Keep a record of when a buffer transfer completed.
* This allows for a more accurate timing model.
@@ -106,7 +106,8 @@
int32_t framesPerBurst);
private:
- SharedRingBuffer *mAudioDataQueue = nullptr; // protected by mAudioDataQueueLock
+
+ std::shared_ptr<SharedRingBuffer> mAudioDataQueue; // protected by mAudioDataQueueLock
std::mutex mAudioDataQueueLock;
std::atomic<int64_t> mTimestampPositionOffset;
diff --git a/services/oboeservice/SharedRingBuffer.cpp b/services/oboeservice/SharedRingBuffer.cpp
index 2454446..0a9196a 100644
--- a/services/oboeservice/SharedRingBuffer.cpp
+++ b/services/oboeservice/SharedRingBuffer.cpp
@@ -18,6 +18,8 @@
//#define LOG_NDEBUG 0
#include <utils/Log.h>
+#include <iomanip>
+#include <iostream>
#include <sys/mman.h>
#include "binding/RingBufferParcelable.h"
@@ -30,8 +32,8 @@
SharedRingBuffer::~SharedRingBuffer()
{
+ mFifoBuffer.reset(); // uses mSharedMemory
if (mSharedMemory != nullptr) {
- delete mFifoBuffer;
munmap(mSharedMemory, mSharedMemorySizeInBytes);
mSharedMemory = nullptr;
}
@@ -76,7 +78,7 @@
(fifo_counter_t *) &mSharedMemory[SHARED_RINGBUFFER_WRITE_OFFSET];
uint8_t *dataAddress = &mSharedMemory[SHARED_RINGBUFFER_DATA_OFFSET];
- mFifoBuffer = new FifoBuffer(bytesPerFrame, capacityInFrames,
+ mFifoBuffer = std::make_shared<FifoBufferIndirect>(bytesPerFrame, capacityInFrames,
readCounterAddress, writeCounterAddress, dataAddress);
return AAUDIO_OK;
}
@@ -94,3 +96,19 @@
ringBufferParcelable.setFramesPerBurst(1);
ringBufferParcelable.setCapacityInFrames(mCapacityInFrames);
}
+
+double SharedRingBuffer::getFractionalFullness() const {
+ int32_t framesAvailable = mFifoBuffer->getFullFramesAvailable();
+ int32_t capacity = mFifoBuffer->getBufferCapacityInFrames();
+ return framesAvailable / (double) capacity;
+}
+
+std::string SharedRingBuffer::dump() const {
+ std::stringstream result;
+ int32_t readCounter = mFifoBuffer->getReadCounter();
+ int32_t writeCounter = mFifoBuffer->getWriteCounter();
+ result << std::setw(10) << writeCounter;
+ result << std::setw(10) << readCounter;
+ result << std::setw(8) << (writeCounter - readCounter);
+ return result.str();
+}
diff --git a/services/oboeservice/SharedRingBuffer.h b/services/oboeservice/SharedRingBuffer.h
index 79169bc..c3a9bb7 100644
--- a/services/oboeservice/SharedRingBuffer.h
+++ b/services/oboeservice/SharedRingBuffer.h
@@ -18,8 +18,9 @@
#define AAUDIO_SHARED_RINGBUFFER_H
#include <android-base/unique_fd.h>
-#include <stdint.h>
#include <cutils/ashmem.h>
+#include <stdint.h>
+#include <string>
#include <sys/mman.h>
#include "fifo/FifoBuffer.h"
@@ -47,15 +48,25 @@
void fillParcelable(AudioEndpointParcelable &endpointParcelable,
RingBufferParcelable &ringBufferParcelable);
- android::FifoBuffer * getFifoBuffer() {
+ /**
+ * Return available frames as a fraction of the capacity.
+ * @return fullness between 0.0 and 1.0
+ */
+ double getFractionalFullness() const;
+
+ // dump: write# read# available
+ std::string dump() const;
+
+ std::shared_ptr<android::FifoBuffer> getFifoBuffer() {
return mFifoBuffer;
}
private:
android::base::unique_fd mFileDescriptor;
- android::FifoBuffer *mFifoBuffer = nullptr;
- uint8_t *mSharedMemory = nullptr;
+ std::shared_ptr<android::FifoBufferIndirect> mFifoBuffer;
+ uint8_t *mSharedMemory = nullptr; // mmap
int32_t mSharedMemorySizeInBytes = 0;
+ // size of memory used for data vs counters
int32_t mDataMemorySizeInBytes = 0;
android::fifo_frames_t mCapacityInFrames = 0;
};