Report data from aaudio mmap path to audio flinger.
Report data from aaudio mmap path to audio flinger for sound dose
computation. A shared memory is allocated for read and write counter.
The client will shared the write counter with the aaudio service. The
command thread will wake up every 5 burst time to report the data to
audio flinger.
Test: atest AAudioTests
Test: test_marshalling
Test: dump wav file in audio flinger and play
Bug: 264254430
Change-Id: Ib732442c5afc9169fe891212cf77b458c41a87f1
diff --git a/include/media/MmapStreamInterface.h b/include/media/MmapStreamInterface.h
index 61de987..7725175 100644
--- a/include/media/MmapStreamInterface.h
+++ b/include/media/MmapStreamInterface.h
@@ -155,6 +155,18 @@
*/
virtual status_t standby() = 0;
+ /**
+ * Report when data being written to a playback buffer. Currently, this is used by mmap
+ * playback thread for sound dose computation.
+ *
+ * \param[in] buffer a pointer to the audio data
+ * \param[in] frameCount the number of frames written by the CPU
+ * \return OK in case of success.
+ * NO_INIT in case of initialization error
+ * INVALID_OPERATION in case of wrong thread type
+ */
+ virtual status_t reportData(const void* buffer, size_t frameCount) = 0;
+
protected:
// Subclasses can not be constructed directly by clients.
MmapStreamInterface() {}
diff --git a/media/libaaudio/src/binding/AudioEndpointParcelable.cpp b/media/libaaudio/src/binding/AudioEndpointParcelable.cpp
index b1262df..d15d2fa 100644
--- a/media/libaaudio/src/binding/AudioEndpointParcelable.cpp
+++ b/media/libaaudio/src/binding/AudioEndpointParcelable.cpp
@@ -18,6 +18,7 @@
//#define LOG_NDEBUG 0
#include <utils/Log.h>
+#include <map>
#include <stdint.h>
#include <binder/Parcel.h>
@@ -37,8 +38,7 @@
: mUpMessageQueueParcelable(parcelable.upMessageQueueParcelable),
mDownMessageQueueParcelable(parcelable.downMessageQueueParcelable),
mUpDataQueueParcelable(parcelable.upDataQueueParcelable),
- mDownDataQueueParcelable(parcelable.downDataQueueParcelable),
- mNumSharedMemories(parcelable.sharedMemories.size()) {
+ mDownDataQueueParcelable(parcelable.downDataQueueParcelable) {
for (size_t i = 0; i < parcelable.sharedMemories.size() && i < MAX_SHARED_MEMORIES; ++i) {
// Re-construct.
mSharedMemories[i].~SharedMemoryParcelable();
@@ -52,15 +52,48 @@
return *this;
}
+namespace {
+
+void updateSharedMemoryIndex(SharedRegion* sharedRegion, int oldIndex, int newIndex) {
+ if (sharedRegion->sharedMemoryIndex == oldIndex) {
+ sharedRegion->sharedMemoryIndex = newIndex;
+ }
+}
+
+void updateSharedMemoryIndex(RingBuffer* ringBuffer, int oldIndex, int newIndex) {
+ updateSharedMemoryIndex(&ringBuffer->readCounterParcelable, oldIndex, newIndex);
+ updateSharedMemoryIndex(&ringBuffer->writeCounterParcelable, oldIndex, newIndex);
+ updateSharedMemoryIndex(&ringBuffer->dataParcelable, oldIndex, newIndex);
+}
+
+void updateSharedMemoryIndex(Endpoint* endpoint, int oldIndex, int newIndex) {
+ updateSharedMemoryIndex(&endpoint->upMessageQueueParcelable, oldIndex, newIndex);
+ updateSharedMemoryIndex(&endpoint->downMessageQueueParcelable, oldIndex, newIndex);
+ updateSharedMemoryIndex(&endpoint->upDataQueueParcelable, oldIndex, newIndex);
+ updateSharedMemoryIndex(&endpoint->downDataQueueParcelable, oldIndex, newIndex);
+}
+
+} // namespace
+
Endpoint AudioEndpointParcelable::parcelable()&& {
Endpoint result;
result.upMessageQueueParcelable = mUpMessageQueueParcelable.parcelable();
result.downMessageQueueParcelable = mDownMessageQueueParcelable.parcelable();
result.upDataQueueParcelable = mUpDataQueueParcelable.parcelable();
result.downDataQueueParcelable = mDownDataQueueParcelable.parcelable();
- result.sharedMemories.reserve(std::min(mNumSharedMemories, MAX_SHARED_MEMORIES));
- for (size_t i = 0; i < mNumSharedMemories && i < MAX_SHARED_MEMORIES; ++i) {
- result.sharedMemories.emplace_back(std::move(mSharedMemories[i]).parcelable());
+ // To transfer through binder, only valid/in-use shared memory is allowed. By design, the
+ // shared memories that are currently in-use may not be placed continuously from position 0.
+ // However, when marshalling the shared memories into Endpoint, the shared memories will be
+ // re-indexed from 0. In that case, when placing a shared memory, it is needed to update the
+ // corresponding cached indexes.
+ for (int i = 0; i < MAX_SHARED_MEMORIES; ++i) {
+ if (mSharedMemories[i].isInUse()) {
+ const int index = result.sharedMemories.size();
+ result.sharedMemories.emplace_back(std::move(mSharedMemories[i]).parcelable());
+ // Updating all the SharedRegion that is using `i` as shared memory index with the
+ // new shared memory index as `result.sharedMemories.size() - 1`.
+ updateSharedMemoryIndex(&result, i, index);
+ }
}
return result;
}
@@ -71,28 +104,50 @@
*/
int32_t AudioEndpointParcelable::addFileDescriptor(const unique_fd& fd,
int32_t sizeInBytes) {
- if (mNumSharedMemories >= MAX_SHARED_MEMORIES) {
+ const int32_t index = getNextAvailableSharedMemoryPosition();
+ if (index < 0) {
return AAUDIO_ERROR_OUT_OF_RANGE;
}
- int32_t index = mNumSharedMemories++;
mSharedMemories[index].setup(fd, sizeInBytes);
return index;
}
void AudioEndpointParcelable::closeDataFileDescriptor() {
- const int32_t curDataMemoryIndex = mDownDataQueueParcelable.getSharedMemoryIndex();
- mSharedMemories[curDataMemoryIndex].closeAndReleaseFd();
+ for (const int32_t memoryIndex : std::set{mDownDataQueueParcelable.getDataSharedMemoryIndex(),
+ mDownDataQueueParcelable.getReadCounterSharedMemoryIndex(),
+ mDownDataQueueParcelable.getWriteCounterSharedMemoryIndex()}) {
+ mSharedMemories[memoryIndex].closeAndReleaseFd();
+ }
}
-void AudioEndpointParcelable::updateDataFileDescriptor(
+aaudio_result_t AudioEndpointParcelable::updateDataFileDescriptor(
AudioEndpointParcelable* endpointParcelable) {
- const int32_t curDataMemoryIndex = mDownDataQueueParcelable.getSharedMemoryIndex();
- const int32_t newDataMemoryIndex =
- endpointParcelable->mDownDataQueueParcelable.getSharedMemoryIndex();
- mSharedMemories[curDataMemoryIndex].close();
- mSharedMemories[curDataMemoryIndex].setup(
- endpointParcelable->mSharedMemories[newDataMemoryIndex]);
- mDownDataQueueParcelable.updateMemory(endpointParcelable->mDownDataQueueParcelable);
+ // Before updating data file descriptor, close the old shared memories.
+ closeDataFileDescriptor();
+ // The given endpoint parcelable and this one are two different objects, the indexes in
+ // `mSharedMemories` for `mDownDataQueueParcelable` can be different. In that case, an index
+ // map, which maps from the index in given endpoint parcelable to the index in this endpoint
+ // parcelable, is required when updating shared memory.
+ std::map<int32_t, int32_t> memoryIndexMap;
+ auto& downDataQueueParcelable = endpointParcelable->mDownDataQueueParcelable;
+ for (const int32_t memoryIndex : {downDataQueueParcelable.getDataSharedMemoryIndex(),
+ downDataQueueParcelable.getReadCounterSharedMemoryIndex(),
+ downDataQueueParcelable.getWriteCounterSharedMemoryIndex()}) {
+ if (memoryIndexMap.find(memoryIndex) != memoryIndexMap.end()) {
+ // This shared memory has been set up in this endpoint parcelable.
+ continue;
+ }
+ // Set up the memory in the next available shared memory position.
+ const int index = getNextAvailableSharedMemoryPosition();
+ if (index < 0) {
+ return AAUDIO_ERROR_OUT_OF_RANGE;
+ }
+ mSharedMemories[index].setup(endpointParcelable->mSharedMemories[memoryIndex]);
+ memoryIndexMap.emplace(memoryIndex, index);
+ }
+ mDownDataQueueParcelable.updateMemory(
+ endpointParcelable->mDownDataQueueParcelable, memoryIndexMap);
+ return AAUDIO_OK;
}
aaudio_result_t AudioEndpointParcelable::resolve(EndpointDescriptor *descriptor) {
@@ -114,26 +169,29 @@
aaudio_result_t AudioEndpointParcelable::close() {
int err = 0;
- for (int i = 0; i < mNumSharedMemories; i++) {
- int lastErr = mSharedMemories[i].close();
+ for (auto& sharedMemory : mSharedMemories) {
+ const int lastErr = sharedMemory.close();
if (lastErr < 0) err = lastErr;
}
return AAudioConvert_androidToAAudioResult(err);
}
-aaudio_result_t AudioEndpointParcelable::validate() const {
- if (mNumSharedMemories < 0 || mNumSharedMemories >= MAX_SHARED_MEMORIES) {
- ALOGE("invalid mNumSharedMemories = %d", mNumSharedMemories);
- return AAUDIO_ERROR_INTERNAL;
+int32_t AudioEndpointParcelable::getNextAvailableSharedMemoryPosition() const {
+ for (int i = 0; i < MAX_SHARED_MEMORIES; ++i) {
+ if (!mSharedMemories[i].isInUse()) {
+ return i;
+ }
}
- return AAUDIO_OK;
+ return -1;
}
void AudioEndpointParcelable::dump() {
ALOGD("======================================= BEGIN");
- ALOGD("mNumSharedMemories = %d", mNumSharedMemories);
- for (int i = 0; i < mNumSharedMemories; i++) {
- mSharedMemories[i].dump();
+ for (int i = 0; i < MAX_SHARED_MEMORIES; ++i) {
+ if (mSharedMemories[i].isInUse()) {
+ ALOGD("Shared memory index=%d", i);
+ mSharedMemories[i].dump();
+ }
}
ALOGD("mUpMessageQueueParcelable =========");
mUpMessageQueueParcelable.dump();
diff --git a/media/libaaudio/src/binding/AudioEndpointParcelable.h b/media/libaaudio/src/binding/AudioEndpointParcelable.h
index 5d2c38f..722dd14 100644
--- a/media/libaaudio/src/binding/AudioEndpointParcelable.h
+++ b/media/libaaudio/src/binding/AudioEndpointParcelable.h
@@ -61,8 +61,10 @@
* Update current data file descriptor with given endpoint parcelable.
* @param endpointParcelable an endpoint parcelable that contains new data file
* descriptor information
+ * @return AAUDIO_OK if the data file descriptor updates successfully.
+ * AAUDIO_ERROR_OUT_OF_RANGE if there is not enough space for the shared memory.
*/
- void updateDataFileDescriptor(AudioEndpointParcelable* endpointParcelable);
+ aaudio_result_t updateDataFileDescriptor(AudioEndpointParcelable* endpointParcelable);
aaudio_result_t resolve(EndpointDescriptor *descriptor);
aaudio_result_t resolveDataQueue(RingBufferDescriptor *descriptor);
@@ -84,9 +86,10 @@
RingBufferParcelable mDownDataQueueParcelable; // eg. playback
private:
- aaudio_result_t validate() const;
+ // Return the first available shared memory position. Return -1 if all shared memories are
+ // in use.
+ int32_t getNextAvailableSharedMemoryPosition() const;
- int32_t mNumSharedMemories = 0;
SharedMemoryParcelable mSharedMemories[MAX_SHARED_MEMORIES];
};
diff --git a/media/libaaudio/src/binding/RingBufferParcelable.cpp b/media/libaaudio/src/binding/RingBufferParcelable.cpp
index 3bc51d0..f8d748e 100644
--- a/media/libaaudio/src/binding/RingBufferParcelable.cpp
+++ b/media/libaaudio/src/binding/RingBufferParcelable.cpp
@@ -33,7 +33,6 @@
: mReadCounterParcelable(parcelable.readCounterParcelable),
mWriteCounterParcelable(parcelable.writeCounterParcelable),
mDataParcelable(parcelable.dataParcelable),
- mSharedMemoryIndex(parcelable.sharedMemoryIndex),
mBytesPerFrame(parcelable.bytesPerFrame),
mFramesPerBurst(parcelable.framesPerBurst),
mCapacityInFrames(parcelable.capacityInFrames),
@@ -46,7 +45,6 @@
result.readCounterParcelable = mReadCounterParcelable.parcelable();
result.writeCounterParcelable = mWriteCounterParcelable.parcelable();
result.dataParcelable = mDataParcelable.parcelable();
- result.sharedMemoryIndex = mSharedMemoryIndex;
result.bytesPerFrame = mBytesPerFrame;
result.framesPerBurst = mFramesPerBurst;
result.capacityInFrames = mCapacityInFrames;
@@ -62,19 +60,26 @@
int32_t readCounterOffset,
int32_t writeCounterOffset,
int32_t counterSizeBytes) {
- mSharedMemoryIndex = sharedMemoryIndex;
- mReadCounterParcelable.setup(sharedMemoryIndex, readCounterOffset, counterSizeBytes);
- mWriteCounterParcelable.setup(sharedMemoryIndex, writeCounterOffset, counterSizeBytes);
- mDataParcelable.setup(sharedMemoryIndex, dataMemoryOffset, dataSizeInBytes);
+ mReadCounterParcelable.setup({sharedMemoryIndex, readCounterOffset, counterSizeBytes});
+ mWriteCounterParcelable.setup({sharedMemoryIndex, writeCounterOffset, counterSizeBytes});
+ mDataParcelable.setup({sharedMemoryIndex, dataMemoryOffset, dataSizeInBytes});
}
void RingBufferParcelable::setupMemory(int32_t sharedMemoryIndex,
int32_t dataMemoryOffset,
int32_t dataSizeInBytes) {
- mSharedMemoryIndex = sharedMemoryIndex;
- mReadCounterParcelable.setup(sharedMemoryIndex, 0, 0);
- mWriteCounterParcelable.setup(sharedMemoryIndex, 0, 0);
- mDataParcelable.setup(sharedMemoryIndex, dataMemoryOffset, dataSizeInBytes);
+ mReadCounterParcelable.setup({sharedMemoryIndex, 0, 0});
+ mWriteCounterParcelable.setup({sharedMemoryIndex, 0, 0});
+ mDataParcelable.setup({sharedMemoryIndex, dataMemoryOffset, dataSizeInBytes});
+}
+
+void RingBufferParcelable::setupMemory(
+ const SharedRegionParcelable::MemoryInfoTuple& dataMemoryInfo,
+ const SharedRegionParcelable::MemoryInfoTuple& readCounterInfo,
+ const SharedRegionParcelable::MemoryInfoTuple& writeCounterInfo) {
+ mReadCounterParcelable.setup(readCounterInfo);
+ mWriteCounterParcelable.setup(writeCounterInfo);
+ mDataParcelable.setup(dataMemoryInfo);
}
int32_t RingBufferParcelable::getBytesPerFrame() const {
@@ -128,9 +133,11 @@
return AAUDIO_OK;
}
-void RingBufferParcelable::updateMemory(const RingBufferParcelable& parcelable) {
- setupMemory(mSharedMemoryIndex, 0,
- parcelable.getCapacityInFrames() * parcelable.getBytesPerFrame());
+void RingBufferParcelable::updateMemory(const RingBufferParcelable& parcelable,
+ const std::map<int32_t, int32_t>& memoryIndexMap) {
+ setupMemory(parcelable.mDataParcelable.getMemoryInfo(&memoryIndexMap),
+ parcelable.mReadCounterParcelable.getMemoryInfo(&memoryIndexMap),
+ parcelable.mWriteCounterParcelable.getMemoryInfo(&memoryIndexMap));
setBytesPerFrame(parcelable.getBytesPerFrame());
setFramesPerBurst(parcelable.getFramesPerBurst());
setCapacityInFrames(parcelable.getCapacityInFrames());
@@ -152,7 +159,6 @@
return AAUDIO_OK;
}
-
void RingBufferParcelable::dump() {
ALOGD("mCapacityInFrames = %d ---------", mCapacityInFrames);
if (mCapacityInFrames > 0) {
diff --git a/media/libaaudio/src/binding/RingBufferParcelable.h b/media/libaaudio/src/binding/RingBufferParcelable.h
index 29d0d86..4363191 100644
--- a/media/libaaudio/src/binding/RingBufferParcelable.h
+++ b/media/libaaudio/src/binding/RingBufferParcelable.h
@@ -17,6 +17,7 @@
#ifndef ANDROID_AAUDIO_RINGBUFFER_PARCELABLE_H
#define ANDROID_AAUDIO_RINGBUFFER_PARCELABLE_H
+#include <map>
#include <stdint.h>
#include <aaudio/RingBuffer.h>
@@ -46,6 +47,22 @@
int32_t dataMemoryOffset,
int32_t dataSizeInBytes);
+ /**
+ * Set up memory for the RingBufferParcelable.
+ *
+ * This function will take three MemoryInfoTuple as parameters to set up memory. The
+ * MemoryInfoTuple contains the shared memory index, offset in the shared memory and size
+ * of the object. This will allow setting up the read counter, write counter and data memory
+ * that are located in different shared memory blocks.
+ *
+ * @param dataMemoryInfo
+ * @param readCounterInfo
+ * @param writeCounterInfo
+ */
+ void setupMemory(const SharedRegionParcelable::MemoryInfoTuple& dataMemoryInfo,
+ const SharedRegionParcelable::MemoryInfoTuple& readCounterInfo,
+ const SharedRegionParcelable::MemoryInfoTuple& writeCounterInfo);
+
int32_t getBytesPerFrame() const;
void setBytesPerFrame(int32_t bytesPerFrame);
@@ -62,10 +79,24 @@
aaudio_result_t resolve(SharedMemoryParcelable *memoryParcels, RingBufferDescriptor *descriptor);
- void updateMemory(const RingBufferParcelable& parcelable);
+ /**
+ * Update this ring buffer with the given ring buffer.
+ *
+ * @param parcelable the ring buffer to be used to update this ring buffer.
+ * @param memoryIndexMap a map from the shared memory indexes used by the given ring buffer
+ * to the shared memory indexes used by this ring buffer.
+ */
+ void updateMemory(const RingBufferParcelable& parcelable,
+ const std::map<int32_t, int32_t>& memoryIndexMap);
- int32_t getSharedMemoryIndex() const {
- return mSharedMemoryIndex;
+ int32_t getReadCounterSharedMemoryIndex() const {
+ return mReadCounterParcelable.getSharedMemoryIndex();
+ }
+ int32_t getWriteCounterSharedMemoryIndex() const {
+ return mWriteCounterParcelable.getSharedMemoryIndex();
+ }
+ int32_t getDataSharedMemoryIndex() const {
+ return mDataParcelable.getSharedMemoryIndex();
}
void dump();
@@ -77,7 +108,6 @@
SharedRegionParcelable mReadCounterParcelable;
SharedRegionParcelable mWriteCounterParcelable;
SharedRegionParcelable mDataParcelable;
- int32_t mSharedMemoryIndex = -1;
int32_t mBytesPerFrame = 0; // index is in frames
int32_t mFramesPerBurst = 0; // for ISOCHRONOUS queues
int32_t mCapacityInFrames = 0; // zero if unused
diff --git a/media/libaaudio/src/binding/SharedMemoryParcelable.cpp b/media/libaaudio/src/binding/SharedMemoryParcelable.cpp
index 741aefc..c360a1f 100644
--- a/media/libaaudio/src/binding/SharedMemoryParcelable.cpp
+++ b/media/libaaudio/src/binding/SharedMemoryParcelable.cpp
@@ -146,7 +146,7 @@
return AAUDIO_OK;
}
-void SharedMemoryParcelable::dump() {
+void SharedMemoryParcelable::dump() const {
ALOGD("mFd = %d", mFd.get());
ALOGD("mSizeInBytes = %" PRId64, mSizeInBytes);
}
diff --git a/media/libaaudio/src/binding/SharedMemoryParcelable.h b/media/libaaudio/src/binding/SharedMemoryParcelable.h
index 7762fef..909f3a6 100644
--- a/media/libaaudio/src/binding/SharedMemoryParcelable.h
+++ b/media/libaaudio/src/binding/SharedMemoryParcelable.h
@@ -64,7 +64,9 @@
int32_t getSizeInBytes();
- void dump();
+ bool isInUse() const { return mFd.get() != -1; }
+
+ void dump() const;
// Extract a parcelable representation of this object.
// Since we own a unique FD, move semantics are provided to avoid the need to dupe.
diff --git a/media/libaaudio/src/binding/SharedRegionParcelable.cpp b/media/libaaudio/src/binding/SharedRegionParcelable.cpp
index 6fa109b..fd69ef1 100644
--- a/media/libaaudio/src/binding/SharedRegionParcelable.cpp
+++ b/media/libaaudio/src/binding/SharedRegionParcelable.cpp
@@ -46,12 +46,17 @@
return result;
}
-void SharedRegionParcelable::setup(int32_t sharedMemoryIndex,
- int32_t offsetInBytes,
- int32_t sizeInBytes) {
- mSharedMemoryIndex = sharedMemoryIndex;
- mOffsetInBytes = offsetInBytes;
- mSizeInBytes = sizeInBytes;
+void SharedRegionParcelable::setup(MemoryInfoTuple memoryInfoTuple) {
+ mSharedMemoryIndex = std::get<MEMORY_INDEX>(memoryInfoTuple);
+ mOffsetInBytes = std::get<OFFSET>(memoryInfoTuple);
+ mSizeInBytes = std::get<SIZE>(memoryInfoTuple);
+}
+
+SharedRegionParcelable::MemoryInfoTuple SharedRegionParcelable::getMemoryInfo(
+ const std::map<int32_t, int32_t>* memoryIndexMap) const {
+ return {memoryIndexMap == nullptr ? mSharedMemoryIndex : memoryIndexMap->at(mSharedMemoryIndex),
+ mOffsetInBytes,
+ mSizeInBytes};
}
aaudio_result_t SharedRegionParcelable::resolve(SharedMemoryParcelable *memoryParcels,
diff --git a/media/libaaudio/src/binding/SharedRegionParcelable.h b/media/libaaudio/src/binding/SharedRegionParcelable.h
index c15fc30..74ea75d 100644
--- a/media/libaaudio/src/binding/SharedRegionParcelable.h
+++ b/media/libaaudio/src/binding/SharedRegionParcelable.h
@@ -37,12 +37,36 @@
// Construct based on a parcelable representation.
explicit SharedRegionParcelable(const SharedRegion& parcelable);
- void setup(int32_t sharedMemoryIndex, int32_t offsetInBytes, int32_t sizeInBytes);
+ // A tuple that contains information for setting up shared memory.
+ // The information in the tuple is <shared memory index, offset, size in byte>.
+ using MemoryInfoTuple = std::tuple<int, int, int>;
+ // Enums to use as index to query from MemoryInfoTuple
+ enum {
+ MEMORY_INDEX = 0,
+ OFFSET = 1,
+ SIZE = 2,
+ };
+ void setup(MemoryInfoTuple memoryInfoTuple);
aaudio_result_t resolve(SharedMemoryParcelable *memoryParcels, void **regionAddressPtr);
bool isFileDescriptorSafe(SharedMemoryParcelable *memoryParcels);
+ int32_t getSharedMemoryIndex() const { return mSharedMemoryIndex; }
+
+ /**
+ * Get the memory information of this SharedRegionParcelable.
+ *
+ * If the `memoryIndexMap` is not null, it indicates the caller has a different indexing for
+ * the shared memory. In that case, the `memoryIndexMap` must contains information from the
+ * shared memory indexes used by this object to the caller's shared memory indexes.
+ *
+ * @param memoryIndexMap a pointer to a map of memory index, which map the current shared
+ * memory index to a new shared memory index.
+ * @return
+ */
+ MemoryInfoTuple getMemoryInfo(const std::map<int32_t, int32_t>* memoryIndexMap) const;
+
void dump();
// Extract a parcelable representation of this object.
diff --git a/media/libaaudio/src/binding/aidl/aaudio/RingBuffer.aidl b/media/libaaudio/src/binding/aidl/aaudio/RingBuffer.aidl
index dd64493..998fc66 100644
--- a/media/libaaudio/src/binding/aidl/aaudio/RingBuffer.aidl
+++ b/media/libaaudio/src/binding/aidl/aaudio/RingBuffer.aidl
@@ -26,5 +26,4 @@
int framesPerBurst; // for ISOCHRONOUS queues
int capacityInFrames; // zero if unused
int /* RingbufferFlags */ flags; // = RingbufferFlags::NONE;
- int sharedMemoryIndex;
-}
\ No newline at end of file
+}
diff --git a/media/libaaudio/src/client/AudioStreamInternal.cpp b/media/libaaudio/src/client/AudioStreamInternal.cpp
index 8fe8569..525ebb4 100644
--- a/media/libaaudio/src/client/AudioStreamInternal.cpp
+++ b/media/libaaudio/src/client/AudioStreamInternal.cpp
@@ -384,7 +384,11 @@
goto exit;
}
// Reconstruct data queue descriptor using new shared file descriptor.
- mEndPointParcelable.updateDataFileDescriptor(&endpointParcelable);
+ result = mEndPointParcelable.updateDataFileDescriptor(&endpointParcelable);
+ if (result != AAUDIO_OK) {
+ ALOGE("%s failed to update data file descriptor, error=%d", __func__, result);
+ goto exit;
+ }
result = mEndPointParcelable.resolveDataQueue(&mEndpointDescriptor.dataQueueDescriptor);
if (result != AAUDIO_OK) {
ALOGE("Failed to resolve data queue after exiting standby, error=%d", result);
diff --git a/media/libaaudio/tests/test_marshalling.cpp b/media/libaaudio/tests/test_marshalling.cpp
index 49213dc..dfb1620 100644
--- a/media/libaaudio/tests/test_marshalling.cpp
+++ b/media/libaaudio/tests/test_marshalling.cpp
@@ -109,7 +109,7 @@
sharedMemories[0].setup(fd, memSizeBytes);
int32_t regionOffset1 = 32;
int32_t regionSize1 = 16;
- sharedRegionA.setup(0, regionOffset1, regionSize1);
+ sharedRegionA.setup({0, regionOffset1, regionSize1});
void *region1;
EXPECT_EQ(AAUDIO_OK, sharedRegionA.resolve(sharedMemories, ®ion1));
diff --git a/services/audioflinger/AudioFlinger.h b/services/audioflinger/AudioFlinger.h
index 9fc503b..876acbc 100644
--- a/services/audioflinger/AudioFlinger.h
+++ b/services/audioflinger/AudioFlinger.h
@@ -757,6 +757,7 @@
audio_port_handle_t *handle);
virtual status_t stop(audio_port_handle_t handle);
virtual status_t standby();
+ status_t reportData(const void* buffer, size_t frameCount) override;
private:
const sp<MmapThread> mThread;
diff --git a/services/audioflinger/Threads.cpp b/services/audioflinger/Threads.cpp
index 163e2a0..c617ef7 100644
--- a/services/audioflinger/Threads.cpp
+++ b/services/audioflinger/Threads.cpp
@@ -9823,6 +9823,10 @@
return mThread->standby();
}
+status_t AudioFlinger::MmapThreadHandle::reportData(const void* buffer, size_t frameCount) {
+ return mThread->reportData(buffer, frameCount);
+}
+
AudioFlinger::MmapThread::MmapThread(
const sp<AudioFlinger>& audioFlinger, audio_io_handle_t id,
@@ -10133,6 +10137,11 @@
return NO_ERROR;
}
+status_t AudioFlinger::MmapThread::reportData(const void* /*buffer*/, size_t /*frameCount*/) {
+ // This is a stub implementation. The MmapPlaybackThread overrides this function.
+ return INVALID_OPERATION;
+}
+
void AudioFlinger::MmapThread::readHalParameters_l()
{
@@ -10815,6 +10824,13 @@
return status;
}
+status_t AudioFlinger::MmapPlaybackThread::reportData(const void* buffer, size_t frameCount) {
+ // TODO(264254430): send the data to mel processor.
+ (void) buffer;
+ (void) frameCount;
+ return NO_ERROR;
+}
+
void AudioFlinger::MmapPlaybackThread::dumpInternals_l(int fd, const Vector<String16>& args)
{
MmapThread::dumpInternals_l(fd, args);
diff --git a/services/audioflinger/Threads.h b/services/audioflinger/Threads.h
index ddae7ae..47d5333 100644
--- a/services/audioflinger/Threads.h
+++ b/services/audioflinger/Threads.h
@@ -2130,6 +2130,7 @@
status_t stop(audio_port_handle_t handle);
status_t standby();
virtual status_t getExternalPosition(uint64_t *position, int64_t *timeNaos) = 0;
+ virtual status_t reportData(const void* buffer, size_t frameCount);
// RefBase
virtual void onFirstRef();
@@ -2272,6 +2273,8 @@
return !(mOutput == nullptr || mOutput->stream == nullptr);
}
+ status_t reportData(const void* buffer, size_t frameCount) override;
+
protected:
void dumpInternals_l(int fd, const Vector<String16>& args) override;
diff --git a/services/oboeservice/AAudioServiceEndpointMMAP.cpp b/services/oboeservice/AAudioServiceEndpointMMAP.cpp
index d4cdb0b..78e5270 100644
--- a/services/oboeservice/AAudioServiceEndpointMMAP.cpp
+++ b/services/oboeservice/AAudioServiceEndpointMMAP.cpp
@@ -58,7 +58,7 @@
result << " MMAP: framesTransferred = " << mFramesTransferred.get();
result << ", HW nanos = " << mHardwareTimeOffsetNanos;
result << ", port handle = " << mPortHandle;
- result << ", audio data FD = " << mAudioDataFileDescriptor;
+ result << ", audio data FD = " << mAudioDataWrapper->getDataFileDescriptor();
result << "\n";
result << " HW Offset Micros: " <<
@@ -89,6 +89,7 @@
aaudio_result_t AAudioServiceEndpointMMAP::open(const aaudio::AAudioStreamRequest &request) {
aaudio_result_t result = AAUDIO_OK;
+ mAudioDataWrapper = std::make_unique<SharedMemoryWrapper>();
copyFrom(request.getConstantConfiguration());
mRequestedDeviceId = getDeviceId();
@@ -219,7 +220,7 @@
__func__, audioFormat, getDeviceId(), getSessionId());
// Create MMAP/NOIRQ buffer.
- result = createMmapBuffer(&mAudioDataFileDescriptor);
+ result = createMmapBuffer();
if (result != AAUDIO_OK) {
goto error;
}
@@ -243,6 +244,8 @@
mTimestampGracePeriodMs = ((int64_t) kTimestampGraceBurstCount * mFramesPerBurst
* AAUDIO_MILLIS_PER_SECOND) / getSampleRate();
+ mDataReportOffsetNanos = ((int64_t)mTimestampGracePeriodMs) * AAUDIO_NANOS_PER_MILLISECOND;
+
ALOGD("%s() got rate = %d, channels = %d channelMask = %#x, deviceId = %d, capacity = %d\n",
__func__, getSampleRate(), getSamplesPerFrame(), getChannelMask(),
deviceId, getBufferCapacity());
@@ -327,17 +330,10 @@
if (mMmapStream == nullptr) {
return AAUDIO_ERROR_NULL;
}
- mAudioDataFileDescriptor.reset();
- const aaudio_result_t result = createMmapBuffer(&mAudioDataFileDescriptor);
+ mAudioDataWrapper->reset();
+ const aaudio_result_t result = createMmapBuffer();
if (result == AAUDIO_OK) {
- const int32_t bytesPerFrame = calculateBytesPerFrame();
- const int32_t capacityInBytes = getBufferCapacity() * bytesPerFrame;
- const int fdIndex = parcelable->addFileDescriptor(
- mAudioDataFileDescriptor, capacityInBytes);
- parcelable->mDownDataQueueParcelable.setupMemory(fdIndex, 0, capacityInBytes);
- parcelable->mDownDataQueueParcelable.setBytesPerFrame(bytesPerFrame);
- parcelable->mDownDataQueueParcelable.setFramesPerBurst(mFramesPerBurst);
- parcelable->mDownDataQueueParcelable.setCapacityInFrames(getBufferCapacity());
+ getDownDataDescription(parcelable);
}
return result;
}
@@ -427,14 +423,19 @@
aaudio_result_t AAudioServiceEndpointMMAP::getDownDataDescription(
AudioEndpointParcelable* parcelable)
{
+ if (mAudioDataWrapper->setupFifoBuffer(calculateBytesPerFrame(), getBufferCapacity())
+ != AAUDIO_OK) {
+ ALOGE("Failed to setup audio data wrapper, will not be able to "
+ "set data for sound dose computation");
+ // This will not affect the audio processing capability
+ }
// Gather information on the data queue based on HAL info.
- const int32_t bytesPerFrame = calculateBytesPerFrame();
- const int32_t capacityInBytes = getBufferCapacity() * bytesPerFrame;
- const int fdIndex = parcelable->addFileDescriptor(mAudioDataFileDescriptor, capacityInBytes);
- parcelable->mDownDataQueueParcelable.setupMemory(fdIndex, 0, capacityInBytes);
- parcelable->mDownDataQueueParcelable.setBytesPerFrame(bytesPerFrame);
- parcelable->mDownDataQueueParcelable.setFramesPerBurst(mFramesPerBurst);
- parcelable->mDownDataQueueParcelable.setCapacityInFrames(getBufferCapacity());
+ mAudioDataWrapper->fillParcelable(parcelable, parcelable->mDownDataQueueParcelable,
+ calculateBytesPerFrame(), mFramesPerBurst,
+ getBufferCapacity(),
+ getDirection() == AAUDIO_DIRECTION_OUTPUT
+ ? SharedMemoryWrapper::WRITE
+ : SharedMemoryWrapper::NONE);
return AAUDIO_OK;
}
@@ -518,8 +519,7 @@
return mHalExternalPositionStatus;
}
-aaudio_result_t AAudioServiceEndpointMMAP::createMmapBuffer(
- android::base::unique_fd* fileDescriptor)
+aaudio_result_t AAudioServiceEndpointMMAP::createMmapBuffer()
{
memset(&mMmapBufferinfo, 0, sizeof(struct audio_mmap_buffer_info));
int32_t minSizeFrames = getBufferCapacity();
@@ -555,8 +555,9 @@
// AAudio creates a copy of this FD and retains ownership of the copy.
// Assume that AudioFlinger will close the original shared_memory_fd.
- fileDescriptor->reset(dup(mMmapBufferinfo.shared_memory_fd));
- if (fileDescriptor->get() == -1) {
+
+ mAudioDataWrapper->getDataFileDescriptor().reset(dup(mMmapBufferinfo.shared_memory_fd));
+ if (mAudioDataWrapper->getDataFileDescriptor().get() == -1) {
ALOGE("%s() - could not dup shared_memory_fd", __func__);
return AAUDIO_ERROR_INTERNAL;
}
@@ -571,3 +572,31 @@
return AAUDIO_OK;
}
+
+int64_t AAudioServiceEndpointMMAP::nextDataReportTime() {
+ return getDirection() == AAUDIO_DIRECTION_OUTPUT
+ ? AudioClock::getNanoseconds() + mDataReportOffsetNanos
+ : std::numeric_limits<int64_t>::max();
+}
+
+void AAudioServiceEndpointMMAP::reportData() {
+ if (mMmapStream == nullptr) {
+ // This must not happen
+ ALOGE("%s() invalid state, mmap stream is not initialized", __func__);
+ return;
+ }
+ auto fifo = mAudioDataWrapper->getFifoBuffer();
+ if (fifo == nullptr) {
+ ALOGE("%s() fifo buffer is not initialized, cannot report data", __func__);
+ return;
+ }
+
+ WrappingBuffer wrappingBuffer;
+ fifo_frames_t framesAvailable = fifo->getFullDataAvailable(&wrappingBuffer);
+ for (size_t i = 0; i < WrappingBuffer::SIZE; ++i) {
+ if (wrappingBuffer.numFrames[i] > 0) {
+ mMmapStream->reportData(wrappingBuffer.data[i], wrappingBuffer.numFrames[i]);
+ }
+ }
+ fifo->advanceReadIndex(framesAvailable);
+}
diff --git a/services/oboeservice/AAudioServiceEndpointMMAP.h b/services/oboeservice/AAudioServiceEndpointMMAP.h
index 4f77393..38cf0ba 100644
--- a/services/oboeservice/AAudioServiceEndpointMMAP.h
+++ b/services/oboeservice/AAudioServiceEndpointMMAP.h
@@ -30,6 +30,7 @@
#include "AAudioServiceStreamMMAP.h"
#include "AAudioMixer.h"
#include "AAudioService.h"
+#include "SharedMemoryWrapper.h"
namespace aaudio {
@@ -90,11 +91,15 @@
aaudio_result_t getExternalPosition(uint64_t *positionFrames, int64_t *timeNanos);
+ int64_t nextDataReportTime();
+
+ void reportData();
+
private:
aaudio_result_t openWithFormat(audio_format_t audioFormat, audio_format_t* nextFormatToTry);
- aaudio_result_t createMmapBuffer(android::base::unique_fd* fileDescriptor);
+ aaudio_result_t createMmapBuffer();
MonotonicCounter mFramesTransferred;
@@ -107,7 +112,7 @@
android::AAudioService &mAAudioService;
- android::base::unique_fd mAudioDataFileDescriptor;
+ std::unique_ptr<SharedMemoryWrapper> mAudioDataWrapper;
int64_t mHardwareTimeOffsetNanos = 0; // TODO get from HAL
@@ -117,6 +122,7 @@
int32_t mTimestampGracePeriodMs;
int32_t mFrozenPositionCount = 0;
int32_t mFrozenTimestampCount = 0;
+ int64_t mDataReportOffsetNanos = 0;
};
diff --git a/services/oboeservice/AAudioServiceStreamBase.cpp b/services/oboeservice/AAudioServiceStreamBase.cpp
index 8e1e497..51ef2d9 100644
--- a/services/oboeservice/AAudioServiceStreamBase.cpp
+++ b/services/oboeservice/AAudioServiceStreamBase.cpp
@@ -404,7 +404,8 @@
// Hold onto the ref counted stream until the end.
android::sp<AAudioServiceStreamBase> holdStream(this);
TimestampScheduler timestampScheduler;
- int64_t nextTime;
+ int64_t nextTimestampReportTime;
+ int64_t nextDataReportTime;
int64_t standbyTime = AudioClock::getNanoseconds() + IDLE_TIMEOUT_NANOS;
// Balance the incStrong from when the thread was launched.
holdStream->decStrong(nullptr);
@@ -418,7 +419,8 @@
loopCount++;
int64_t timeoutNanos = -1;
if (isRunning() || (isIdle_l() && !isStandby_l())) {
- timeoutNanos = (isRunning() ? nextTime : standbyTime) - AudioClock::getNanoseconds();
+ timeoutNanos = (isRunning() ? std::min(nextTimestampReportTime, nextDataReportTime)
+ : standbyTime) - AudioClock::getNanoseconds();
timeoutNanos = std::max<int64_t>(0, timeoutNanos);
}
@@ -428,13 +430,20 @@
break;
}
- if (isRunning() && AudioClock::getNanoseconds() >= nextTime) {
- // It is time to update timestamp.
- if (sendCurrentTimestamp_l() != AAUDIO_OK) {
- ALOGE("Failed to send current timestamp, stop updating timestamp");
- disconnect_l();
- } else {
- nextTime = timestampScheduler.nextAbsoluteTime();
+ if (isRunning()) {
+ auto currentTimestamp = AudioClock::getNanoseconds();
+ if (currentTimestamp >= nextDataReportTime) {
+ reportData_l();
+ nextDataReportTime = nextDataReportTime_l();
+ }
+ if (currentTimestamp >= nextTimestampReportTime) {
+ // It is time to update timestamp.
+ if (sendCurrentTimestamp_l() != AAUDIO_OK) {
+ ALOGE("Failed to send current timestamp, stop updating timestamp");
+ disconnect_l();
+ } else {
+ nextTimestampReportTime = timestampScheduler.nextAbsoluteTime();
+ }
}
}
if (isIdle_l() && AudioClock::getNanoseconds() >= standbyTime) {
@@ -456,7 +465,8 @@
command->result = start_l();
timestampScheduler.setBurstPeriod(mFramesPerBurst, getSampleRate());
timestampScheduler.start(AudioClock::getNanoseconds());
- nextTime = timestampScheduler.nextAbsoluteTime();
+ nextTimestampReportTime = timestampScheduler.nextAbsoluteTime();
+ nextDataReportTime = nextDataReportTime_l();
break;
case PAUSE:
command->result = pause_l();
diff --git a/services/oboeservice/AAudioServiceStreamBase.h b/services/oboeservice/AAudioServiceStreamBase.h
index 0f51503..bc7ccde 100644
--- a/services/oboeservice/AAudioServiceStreamBase.h
+++ b/services/oboeservice/AAudioServiceStreamBase.h
@@ -346,6 +346,11 @@
|| mState == AAUDIO_STREAM_STATE_STOPPED;
}
+ virtual int64_t nextDataReportTime_l() REQUIRES(mLock) {
+ return std::numeric_limits<int64_t>::max();
+ }
+ virtual void reportData_l() REQUIRES(mLock) { return; }
+
pid_t mRegisteredClientThread = ILLEGAL_THREAD_ID;
std::mutex mUpMessageQueueLock;
diff --git a/services/oboeservice/AAudioServiceStreamMMAP.cpp b/services/oboeservice/AAudioServiceStreamMMAP.cpp
index ec9b2e2..89f6e33 100644
--- a/services/oboeservice/AAudioServiceStreamMMAP.cpp
+++ b/services/oboeservice/AAudioServiceStreamMMAP.cpp
@@ -238,3 +238,25 @@
static_cast<AAudioServiceEndpointMMAP *>(endpoint.get());
return serviceEndpointMMAP->getDownDataDescription(parcelable);
}
+
+int64_t AAudioServiceStreamMMAP::nextDataReportTime_l() {
+ sp<AAudioServiceEndpoint> endpoint = mServiceEndpointWeak.promote();
+ if (endpoint == nullptr) {
+ ALOGE("%s() has no endpoint", __func__);
+ return std::numeric_limits<int64_t>::max();
+ }
+ sp<AAudioServiceEndpointMMAP> serviceEndpointMMAP =
+ static_cast<AAudioServiceEndpointMMAP *>(endpoint.get());
+ return serviceEndpointMMAP->nextDataReportTime();
+}
+
+void AAudioServiceStreamMMAP::reportData_l() {
+ sp<AAudioServiceEndpoint> endpoint = mServiceEndpointWeak.promote();
+ if (endpoint == nullptr) {
+ ALOGE("%s() has no endpoint", __func__);
+ return;
+ }
+ sp<AAudioServiceEndpointMMAP> serviceEndpointMMAP =
+ static_cast<AAudioServiceEndpointMMAP *>(endpoint.get());
+ return serviceEndpointMMAP->reportData();
+}
diff --git a/services/oboeservice/AAudioServiceStreamMMAP.h b/services/oboeservice/AAudioServiceStreamMMAP.h
index 8b8c5e6..db3c8d0 100644
--- a/services/oboeservice/AAudioServiceStreamMMAP.h
+++ b/services/oboeservice/AAudioServiceStreamMMAP.h
@@ -84,6 +84,10 @@
aaudio_result_t getHardwareTimestamp_l(
int64_t *positionFrames, int64_t *timeNanos) REQUIRES(mLock) override;
+ int64_t nextDataReportTime_l() REQUIRES(mLock) override;
+
+ void reportData_l() REQUIRES(mLock) override;
+
/**
* Device specific startup.
* @return AAUDIO_OK or negative error.
diff --git a/services/oboeservice/Android.bp b/services/oboeservice/Android.bp
index 56c0dc9..c5080a4 100644
--- a/services/oboeservice/Android.bp
+++ b/services/oboeservice/Android.bp
@@ -104,6 +104,7 @@
"AAudioStreamTracker.cpp",
"AAudioThread.cpp",
"SharedMemoryProxy.cpp",
+ "SharedMemoryWrapper.cpp",
"SharedRingBuffer.cpp",
"TimestampScheduler.cpp",
],
diff --git a/services/oboeservice/SharedMemoryWrapper.cpp b/services/oboeservice/SharedMemoryWrapper.cpp
new file mode 100644
index 0000000..c0dcccb
--- /dev/null
+++ b/services/oboeservice/SharedMemoryWrapper.cpp
@@ -0,0 +1,132 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "SharedMemoryWrapper"
+//#define LOG_NDEBUG 0
+#include <utils/Log.h>
+
+#include <iomanip>
+#include <iostream>
+#include <sys/mman.h>
+
+#include "SharedMemoryWrapper.h"
+
+namespace aaudio {
+
+constexpr int COUNTER_SIZE_IN_BYTES = sizeof(android::fifo_counter_t);
+constexpr int WRAPPER_SIZE_IN_BYTES = 2 * COUNTER_SIZE_IN_BYTES;
+
+SharedMemoryWrapper::SharedMemoryWrapper() {
+ mCounterFd.reset(ashmem_create_region("AAudioSharedMemoryWrapper", WRAPPER_SIZE_IN_BYTES));
+ if (mCounterFd.get() == -1) {
+ ALOGE("allocate() ashmem_create_region() failed %d", errno);
+ return;
+ }
+ int err = ashmem_set_prot_region(mCounterFd.get(), PROT_READ|PROT_WRITE);
+ if (err < 0) {
+ ALOGE("allocate() ashmem_set_prot_region() failed %d", errno);
+ mCounterFd.reset();
+ return;
+ }
+ auto tmpPtr = (uint8_t *) mmap(nullptr, WRAPPER_SIZE_IN_BYTES,
+ PROT_READ|PROT_WRITE,
+ MAP_SHARED,
+ mCounterFd.get(), 0);
+ if (tmpPtr == MAP_FAILED) {
+ ALOGE("allocate() mmap() failed %d", errno);
+ mCounterFd.reset();
+ return;
+ }
+ mCounterMemoryAddress = tmpPtr;
+
+ mReadCounterAddress = (android::fifo_counter_t*) mCounterMemoryAddress;
+ mWriteCounterAddress = (android::fifo_counter_t*) &mCounterMemoryAddress[COUNTER_SIZE_IN_BYTES];
+}
+
+SharedMemoryWrapper::~SharedMemoryWrapper()
+{
+ reset();
+ if (mCounterMemoryAddress != nullptr) {
+ munmap(mCounterMemoryAddress, COUNTER_SIZE_IN_BYTES);
+ mCounterMemoryAddress = nullptr;
+ }
+}
+
+aaudio_result_t SharedMemoryWrapper::setupFifoBuffer(android::fifo_frames_t bytesPerFrame,
+ android::fifo_frames_t capacityInFrames) {
+ if (mDataFd.get() == -1) {
+ ALOGE("%s data file descriptor is not initialized", __func__);
+ return AAUDIO_ERROR_INTERNAL;
+ }
+ if (mCounterMemoryAddress == nullptr) {
+ ALOGE("%s the counter memory is not allocated correctly", __func__);
+ return AAUDIO_ERROR_INTERNAL;
+ }
+ mSharedMemorySizeInBytes = bytesPerFrame * capacityInFrames;
+ auto tmpPtr = (uint8_t *) mmap(nullptr, mSharedMemorySizeInBytes,
+ PROT_READ|PROT_WRITE,
+ MAP_SHARED,
+ mDataFd.get(), 0);
+ if (tmpPtr == MAP_FAILED) {
+ ALOGE("allocate() mmap() failed %d", errno);
+ return AAUDIO_ERROR_INTERNAL;
+ }
+ mSharedMemory = tmpPtr;
+
+ mFifoBuffer = std::make_shared<android::FifoBufferIndirect>(
+ bytesPerFrame, capacityInFrames, mReadCounterAddress,
+ mWriteCounterAddress, mSharedMemory);
+ return AAUDIO_OK;
+}
+
+void SharedMemoryWrapper::reset() {
+ mFifoBuffer.reset();
+ if (mSharedMemory != nullptr) {
+ munmap(mSharedMemory, mSharedMemorySizeInBytes);
+ mSharedMemory = nullptr;
+ }
+ mDataFd.reset();
+}
+
+void SharedMemoryWrapper::fillParcelable(
+ AudioEndpointParcelable* endpointParcelable, RingBufferParcelable &ringBufferParcelable,
+ int32_t bytesPerFrame, int32_t framesPerBurst, int32_t capacityInFrames,
+ CounterFilling counterFilling) {
+ const int capacityInBytes = bytesPerFrame * capacityInFrames;
+ const int dataFdIndex =
+ endpointParcelable->addFileDescriptor(mDataFd, mSharedMemorySizeInBytes);
+ ringBufferParcelable.setBytesPerFrame(bytesPerFrame);
+ ringBufferParcelable.setFramesPerBurst(framesPerBurst);
+ ringBufferParcelable.setCapacityInFrames(capacityInFrames);
+ if (mCounterFd.get() == -1 || counterFilling == NONE) {
+ // Failed to create shared memory for read/write counter or requesting no filling counters.
+ ALOGD("%s no counter is filled, counterFd=%d", __func__, mCounterFd.get());
+ ringBufferParcelable.setupMemory(dataFdIndex, 0, capacityInBytes);
+ } else {
+ int counterFdIndex =
+ endpointParcelable->addFileDescriptor(mCounterFd, WRAPPER_SIZE_IN_BYTES);
+ const int readCounterSize = (counterFilling & READ) == NONE ? 0 : COUNTER_SIZE_IN_BYTES;
+ const int writeCounterSize = (counterFilling & WRITE) == NONE ? 0 : COUNTER_SIZE_IN_BYTES;
+ ALOGD("%s counterFdIndex=%d readCounterSize=%d, writeCounterSize=%d",
+ __func__, counterFdIndex, readCounterSize, writeCounterSize);
+ ringBufferParcelable.setupMemory(
+ {dataFdIndex, 0 /*offset*/, capacityInBytes},
+ {counterFdIndex, 0 /*offset*/, readCounterSize},
+ {counterFdIndex, COUNTER_SIZE_IN_BYTES, writeCounterSize});
+ }
+}
+
+} // namespace aaudio
diff --git a/services/oboeservice/SharedMemoryWrapper.h b/services/oboeservice/SharedMemoryWrapper.h
new file mode 100644
index 0000000..323c7f1
--- /dev/null
+++ b/services/oboeservice/SharedMemoryWrapper.h
@@ -0,0 +1,86 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <android-base/unique_fd.h>
+#include <cutils/ashmem.h>
+#include <stdint.h>
+#include <string>
+#include <sys/mman.h>
+
+#include "fifo/FifoBuffer.h"
+#include "binding/RingBufferParcelable.h"
+#include "binding/AudioEndpointParcelable.h"
+
+namespace aaudio {
+
+/**
+ * Wrap the shared memory with read and write counters. Provide a fifo buffer to access the
+ * wrapped shared memory.
+ */
+class SharedMemoryWrapper {
+public:
+ explicit SharedMemoryWrapper();
+
+ virtual ~SharedMemoryWrapper();
+
+ android::base::unique_fd& getDataFileDescriptor() { return mDataFd; }
+
+ aaudio_result_t setupFifoBuffer(android::fifo_frames_t bytesPerFrame,
+ android::fifo_frames_t capacityInFrames);
+
+ void reset();
+
+ enum CounterFilling {
+ NONE = 0,
+ READ = 1,
+ WRITE = 2,
+ };
+ /**
+ * Fill shared memory into parcelable.
+ *
+ * @param endpointParcelable container for ring buffers and shared memories
+ * @param ringBufferParcelable the ring buffer
+ * @param bytesPerFrame the bytes per frame of the data memory
+ * @param framesPerBurst the frame per burst of the data memory
+ * @param capacityInFrames the capacity in frames of the data memory
+ * @param counterFilling a bit mask to control if the counter from the wrapper should be filled
+ * or not.
+ */
+ void fillParcelable(AudioEndpointParcelable* endpointParcelable,
+ RingBufferParcelable &ringBufferParcelable,
+ int32_t bytesPerFrame,
+ int32_t framesPerBurst,
+ int32_t capacityInFrames,
+ CounterFilling counterFilling = NONE);
+
+ std::shared_ptr<android::FifoBuffer> getFifoBuffer() {
+ return mFifoBuffer;
+ }
+
+private:
+ android::base::unique_fd mDataFd;
+ android::base::unique_fd mCounterFd;
+ uint8_t* mCounterMemoryAddress = nullptr;
+ android::fifo_counter_t* mReadCounterAddress = nullptr;
+ android::fifo_counter_t* mWriteCounterAddress = nullptr;
+ std::shared_ptr<android::FifoBufferIndirect> mFifoBuffer;
+ uint8_t* mSharedMemory = nullptr;
+ int32_t mSharedMemorySizeInBytes = 0;
+};
+
+} /* namespace aaudio */