Merge "audio: add device definitions for BLE Audio"
diff --git a/media/codec2/components/gav1/C2SoftGav1Dec.cpp b/media/codec2/components/gav1/C2SoftGav1Dec.cpp
index 8415b30..dfed76c 100644
--- a/media/codec2/components/gav1/C2SoftGav1Dec.cpp
+++ b/media/codec2/components/gav1/C2SoftGav1Dec.cpp
@@ -446,15 +446,6 @@
return;
}
- } else {
- const Libgav1StatusCode status = mCodecCtx->SignalEOS();
- if (status != kLibgav1StatusOk) {
- ALOGE("Failed to flush av1 decoder. status: %d.", status);
- work->result = C2_CORRUPTED;
- work->workletsProcessed = 1u;
- mSignalledError = true;
- return;
- }
}
(void)outputBuffer(pool, work);
diff --git a/media/libaaudio/src/client/AudioEndpoint.cpp b/media/libaaudio/src/client/AudioEndpoint.cpp
index 06f66d3..0a19d17 100644
--- a/media/libaaudio/src/client/AudioEndpoint.cpp
+++ b/media/libaaudio/src/client/AudioEndpoint.cpp
@@ -137,7 +137,7 @@
return AAUDIO_ERROR_INTERNAL;
}
- mUpCommandQueue = std::make_unique<FifoBuffer>(
+ mUpCommandQueue = std::make_unique<FifoBufferIndirect>(
descriptor->bytesPerFrame,
descriptor->capacityInFrames,
descriptor->readCounterAddress,
@@ -166,7 +166,7 @@
? &mDataWriteCounter
: descriptor->writeCounterAddress;
- mDataQueue = std::make_unique<FifoBuffer>(
+ mDataQueue = std::make_unique<FifoBufferIndirect>(
descriptor->bytesPerFrame,
descriptor->capacityInFrames,
readCounterAddress,
diff --git a/media/libaaudio/src/client/AudioEndpoint.h b/media/libaaudio/src/client/AudioEndpoint.h
index 484d917..4c8d60f 100644
--- a/media/libaaudio/src/client/AudioEndpoint.h
+++ b/media/libaaudio/src/client/AudioEndpoint.h
@@ -93,8 +93,8 @@
void dump() const;
private:
- std::unique_ptr<android::FifoBuffer> mUpCommandQueue;
- std::unique_ptr<android::FifoBuffer> mDataQueue;
+ std::unique_ptr<android::FifoBufferIndirect> mUpCommandQueue;
+ std::unique_ptr<android::FifoBufferIndirect> mDataQueue;
bool mFreeRunning;
android::fifo_counter_t mDataReadCounter; // only used if free-running
android::fifo_counter_t mDataWriteCounter; // only used if free-running
diff --git a/media/libaaudio/src/fifo/FifoBuffer.cpp b/media/libaaudio/src/fifo/FifoBuffer.cpp
index f5113f2..5c11882 100644
--- a/media/libaaudio/src/fifo/FifoBuffer.cpp
+++ b/media/libaaudio/src/fifo/FifoBuffer.cpp
@@ -31,40 +31,37 @@
#include "FifoBuffer.h"
using android::FifoBuffer;
+using android::FifoBufferAllocated;
+using android::FifoBufferIndirect;
using android::fifo_frames_t;
-FifoBuffer::FifoBuffer(int32_t bytesPerFrame, fifo_frames_t capacityInFrames)
- : mBytesPerFrame(bytesPerFrame)
+FifoBuffer::FifoBuffer(int32_t bytesPerFrame)
+ : mBytesPerFrame(bytesPerFrame) {}
+
+FifoBufferAllocated::FifoBufferAllocated(int32_t bytesPerFrame, fifo_frames_t capacityInFrames)
+ : FifoBuffer(bytesPerFrame)
{
mFifo = std::make_unique<FifoController>(capacityInFrames, capacityInFrames);
// allocate buffer
int32_t bytesPerBuffer = bytesPerFrame * capacityInFrames;
- mStorage = new uint8_t[bytesPerBuffer];
- mStorageOwned = true;
+ mInternalStorage = std::make_unique<uint8_t[]>(bytesPerBuffer);
ALOGV("%s() capacityInFrames = %d, bytesPerFrame = %d",
__func__, capacityInFrames, bytesPerFrame);
}
-FifoBuffer::FifoBuffer( int32_t bytesPerFrame,
+FifoBufferIndirect::FifoBufferIndirect( int32_t bytesPerFrame,
fifo_frames_t capacityInFrames,
- fifo_counter_t * readIndexAddress,
- fifo_counter_t * writeIndexAddress,
+ fifo_counter_t *readIndexAddress,
+ fifo_counter_t *writeIndexAddress,
void * dataStorageAddress
)
- : mBytesPerFrame(bytesPerFrame)
- , mStorage(static_cast<uint8_t *>(dataStorageAddress))
+ : FifoBuffer(bytesPerFrame)
+ , mExternalStorage(static_cast<uint8_t *>(dataStorageAddress))
{
mFifo = std::make_unique<FifoControllerIndirect>(capacityInFrames,
capacityInFrames,
readIndexAddress,
writeIndexAddress);
- mStorageOwned = false;
-}
-
-FifoBuffer::~FifoBuffer() {
- if (mStorageOwned) {
- delete[] mStorage;
- }
}
int32_t FifoBuffer::convertFramesToBytes(fifo_frames_t frames) {
@@ -76,15 +73,16 @@
int32_t startIndex) {
wrappingBuffer->data[1] = nullptr;
wrappingBuffer->numFrames[1] = 0;
+ uint8_t *storage = getStorage();
if (framesAvailable > 0) {
fifo_frames_t capacity = mFifo->getCapacity();
- uint8_t *source = &mStorage[convertFramesToBytes(startIndex)];
+ uint8_t *source = &storage[convertFramesToBytes(startIndex)];
// Does the available data cross the end of the FIFO?
if ((startIndex + framesAvailable) > capacity) {
wrappingBuffer->data[0] = source;
fifo_frames_t firstFrames = capacity - startIndex;
wrappingBuffer->numFrames[0] = firstFrames;
- wrappingBuffer->data[1] = &mStorage[0];
+ wrappingBuffer->data[1] = &storage[0];
wrappingBuffer->numFrames[1] = framesAvailable - firstFrames;
} else {
wrappingBuffer->data[0] = source;
@@ -191,6 +189,6 @@
void FifoBuffer::eraseMemory() {
int32_t numBytes = convertFramesToBytes(getBufferCapacityInFrames());
if (numBytes > 0) {
- memset(mStorage, 0, (size_t) numBytes);
+ memset(getStorage(), 0, (size_t) numBytes);
}
}
diff --git a/media/libaaudio/src/fifo/FifoBuffer.h b/media/libaaudio/src/fifo/FifoBuffer.h
index 0d188c4..37548f0 100644
--- a/media/libaaudio/src/fifo/FifoBuffer.h
+++ b/media/libaaudio/src/fifo/FifoBuffer.h
@@ -38,15 +38,9 @@
class FifoBuffer {
public:
- FifoBuffer(int32_t bytesPerFrame, fifo_frames_t capacityInFrames);
+ FifoBuffer(int32_t bytesPerFrame);
- FifoBuffer(int32_t bytesPerFrame,
- fifo_frames_t capacityInFrames,
- fifo_counter_t *readCounterAddress,
- fifo_counter_t *writeCounterAddress,
- void *dataStorageAddress);
-
- ~FifoBuffer();
+ virtual ~FifoBuffer() = default;
int32_t convertFramesToBytes(fifo_frames_t frames);
@@ -121,19 +115,53 @@
*/
void eraseMemory();
-private:
+protected:
+
+ virtual uint8_t *getStorage() const = 0;
void fillWrappingBuffer(WrappingBuffer *wrappingBuffer,
int32_t framesAvailable, int32_t startIndex);
const int32_t mBytesPerFrame;
- // We do not use a std::unique_ptr for mStorage because it is often a pointer to
- // memory shared between processes and cannot be deleted trivially.
- uint8_t *mStorage = nullptr;
- bool mStorageOwned = false; // did this object allocate the storage?
std::unique_ptr<FifoControllerBase> mFifo{};
};
+// Define two subclasses to handle the two ways that storage is allocated.
+
+// Allocate storage internally.
+class FifoBufferAllocated : public FifoBuffer {
+public:
+ FifoBufferAllocated(int32_t bytesPerFrame, fifo_frames_t capacityInFrames);
+
+private:
+
+ uint8_t *getStorage() const override {
+ return mInternalStorage.get();
+ };
+
+ std::unique_ptr<uint8_t[]> mInternalStorage;
+};
+
+// Allocate storage externally and pass it in.
+class FifoBufferIndirect : public FifoBuffer {
+public:
+ // We use raw pointers because the memory may be
+ // in the middle of an allocated block and cannot be deleted directly.
+ FifoBufferIndirect(int32_t bytesPerFrame,
+ fifo_frames_t capacityInFrames,
+ fifo_counter_t* readCounterAddress,
+ fifo_counter_t* writeCounterAddress,
+ void* dataStorageAddress);
+
+private:
+
+ uint8_t *getStorage() const override {
+ return mExternalStorage;
+ };
+
+ uint8_t *mExternalStorage = nullptr;
+};
+
} // android
#endif //FIFO_FIFO_BUFFER_H
diff --git a/media/libaaudio/src/fifo/FifoControllerIndirect.h b/media/libaaudio/src/fifo/FifoControllerIndirect.h
index 5832d9c..ec48e57 100644
--- a/media/libaaudio/src/fifo/FifoControllerIndirect.h
+++ b/media/libaaudio/src/fifo/FifoControllerIndirect.h
@@ -27,7 +27,7 @@
/**
* A FifoControllerBase with counters external to the class.
*
- * The actual copunters may be stored in separate regions of shared memory
+ * The actual counters may be stored in separate regions of shared memory
* with different access rights.
*/
class FifoControllerIndirect : public FifoControllerBase {
diff --git a/media/libaaudio/tests/test_atomic_fifo.cpp b/media/libaaudio/tests/test_atomic_fifo.cpp
index 130ef43..4dbb219 100644
--- a/media/libaaudio/tests/test_atomic_fifo.cpp
+++ b/media/libaaudio/tests/test_atomic_fifo.cpp
@@ -26,6 +26,7 @@
using android::fifo_counter_t;
using android::FifoController;
using android::FifoBuffer;
+using android::FifoBufferIndirect;
using android::WrappingBuffer;
TEST(test_fifo_controller, fifo_indices) {
@@ -325,7 +326,7 @@
verifyStorageIntegrity();
}
- FifoBuffer mFifoBuffer;
+ FifoBufferIndirect mFifoBuffer;
fifo_frames_t mNextWriteIndex = 0;
fifo_frames_t mNextVerifyIndex = 0;
fifo_frames_t mThreshold;
diff --git a/media/libmediametrics/Android.bp b/media/libmediametrics/Android.bp
index 03068c7..a63b8b4 100644
--- a/media/libmediametrics/Android.bp
+++ b/media/libmediametrics/Android.bp
@@ -53,6 +53,7 @@
visibility: [
"//cts/tests/tests/nativemedia/mediametrics",
"//frameworks/av:__subpackages__",
+ "//frameworks/base/apex/media/framework",
"//frameworks/base/core/jni",
"//frameworks/base/media/jni",
],
diff --git a/media/libstagefright/tests/writer/Android.bp b/media/libstagefright/tests/writer/Android.bp
index d058ed3..b5d453e 100644
--- a/media/libstagefright/tests/writer/Android.bp
+++ b/media/libstagefright/tests/writer/Android.bp
@@ -29,13 +29,14 @@
"liblog",
"libutils",
"libmedia",
+ "libmediandk",
+ "libstagefright",
],
static_libs: [
"libstagefright_webm",
- "libdatasource",
- "libstagefright",
"libstagefright_foundation",
+ "libdatasource",
"libstagefright_esds",
"libogg",
],
diff --git a/media/libstagefright/tests/writer/AndroidTest.xml b/media/libstagefright/tests/writer/AndroidTest.xml
index a21be8a..cc890fe 100644
--- a/media/libstagefright/tests/writer/AndroidTest.xml
+++ b/media/libstagefright/tests/writer/AndroidTest.xml
@@ -19,7 +19,7 @@
<option name="cleanup" value="true" />
<option name="push" value="writerTest->/data/local/tmp/writerTest" />
<option name="push-file"
- key="https://storage.googleapis.com/android_media/frameworks/av/media/libstagefright/tests/writer/WriterTestRes.zip?unzip=true"
+ key="https://storage.googleapis.com/android_media/frameworks/av/media/libstagefright/tests/writer/WriterTestRes-1.1.zip?unzip=true"
value="/data/local/tmp/WriterTestRes/" />
</target_preparer>
<test class="com.android.tradefed.testtype.GTest" >
diff --git a/media/libstagefright/tests/writer/README.md b/media/libstagefright/tests/writer/README.md
index e103613..0e54ca7 100644
--- a/media/libstagefright/tests/writer/README.md
+++ b/media/libstagefright/tests/writer/README.md
@@ -19,10 +19,10 @@
adb push ${OUT}/data/nativetest/writerTest/writerTest /data/local/tmp/
-The resource file for the tests is taken from [here](https://storage.googleapis.com/android_media/frameworks/av/media/libstagefright/tests/writer/WriterTestRes.zip).
+The resource file for the tests is taken from [here](https://storage.googleapis.com/android_media/frameworks/av/media/libstagefright/tests/writer/WriterTestRes-1.1.zip).
Download and extract the folder. Push all the files in this folder to /data/local/tmp/ on the device.
```
-adb push WriterTestRes /data/local/tmp/
+adb push WriterTestRes-1.1/. /data/local/tmp/WriterTestRes/
```
usage: writerTest -P \<path_to_res_folder\> -C <remove_output_file>
diff --git a/media/libstagefright/tests/writer/WriterTest.cpp b/media/libstagefright/tests/writer/WriterTest.cpp
index 4c0add4..4ca02b0 100644
--- a/media/libstagefright/tests/writer/WriterTest.cpp
+++ b/media/libstagefright/tests/writer/WriterTest.cpp
@@ -18,9 +18,13 @@
#define LOG_TAG "WriterTest"
#include <utils/Log.h>
+#include <binder/ProcessState.h>
+
+#include <inttypes.h>
#include <fstream>
#include <iostream>
+#include <media/NdkMediaExtractor.h>
#include <media/stagefright/MediaDefs.h>
#include <media/stagefright/MetaData.h>
#include <media/stagefright/Utils.h>
@@ -39,15 +43,13 @@
#define OUTPUT_FILE_NAME "/data/local/tmp/writer.out"
-static WriterTestEnvironment *gEnv = nullptr;
+// Stts values within 0.1ms(100us) difference are fudged to save too
+// many stts entries in MPEG4Writer.
+constexpr int32_t kMpeg4MuxToleranceTimeUs = 100;
+// Tolerance value for other writers
+constexpr int32_t kMuxToleranceTimeUs = 1;
-struct configFormat {
- char mime[128];
- int32_t width;
- int32_t height;
- int32_t sampleRate;
- int32_t channelCount;
-};
+static WriterTestEnvironment *gEnv = nullptr;
enum inputId {
// audio streams
@@ -82,8 +84,8 @@
int32_t secondParam;
bool isAudio;
} kInputData[] = {
- {AAC_1, MEDIA_MIMETYPE_AUDIO_AAC, "bbb_aac_stereo_128kbps_48000hz.aac",
- "bbb_aac_stereo_128kbps_48000hz.info", 48000, 2, true},
+ {AAC_1, MEDIA_MIMETYPE_AUDIO_AAC, "audio_aac_stereo_8kbps_11025hz.aac",
+ "audio_aac_stereo_8kbps_11025hz.info", 11025, 2, true},
{AAC_ADTS_1, MEDIA_MIMETYPE_AUDIO_AAC_ADTS, "Mps_2_c2_fr1_Sc1_Dc2_0x03_raw.adts",
"Mps_2_c2_fr1_Sc1_Dc2_0x03_raw.info", 48000, 2, true},
{AMR_NB_1, MEDIA_MIMETYPE_AUDIO_AMR_NB, "sine_amrnb_1ch_12kbps_8000hz.amrnb",
@@ -94,17 +96,17 @@
"bbb_flac_stereo_680kbps_48000hz.info", 48000, 2, true},
{OPUS_1, MEDIA_MIMETYPE_AUDIO_OPUS, "bbb_opus_stereo_128kbps_48000hz.opus",
"bbb_opus_stereo_128kbps_48000hz.info", 48000, 2, true},
- {VORBIS_1, MEDIA_MIMETYPE_AUDIO_VORBIS, "bbb_vorbis_stereo_128kbps_48000hz.vorbis",
- "bbb_vorbis_stereo_128kbps_48000hz.info", 48000, 2, true},
+ {VORBIS_1, MEDIA_MIMETYPE_AUDIO_VORBIS, "bbb_vorbis_1ch_64kbps_16kHz.vorbis",
+ "bbb_vorbis_1ch_64kbps_16kHz.info", 16000, 1, true},
{AV1_1, MEDIA_MIMETYPE_VIDEO_AV1, "bbb_av1_176_144.av1", "bbb_av1_176_144.info", 176, 144,
false},
- {AVC_1, MEDIA_MIMETYPE_VIDEO_AVC, "bbb_avc_176x144_300kbps_60fps.h264",
- "bbb_avc_176x144_300kbps_60fps.info", 176, 144, false},
+ {AVC_1, MEDIA_MIMETYPE_VIDEO_AVC, "bbb_avc_352x288_768kbps_30fps.avc",
+ "bbb_avc_352x288_768kbps_30fps.info", 352, 288, false},
{H263_1, MEDIA_MIMETYPE_VIDEO_H263, "bbb_h263_352x288_300kbps_12fps.h263",
"bbb_h263_352x288_300kbps_12fps.info", 352, 288, false},
- {HEVC_1, MEDIA_MIMETYPE_VIDEO_HEVC, "bbb_hevc_176x144_176kbps_60fps.hevc",
- "bbb_hevc_176x144_176kbps_60fps.info", 176, 144, false},
+ {HEVC_1, MEDIA_MIMETYPE_VIDEO_HEVC, "bbb_hevc_340x280_768kbps_30fps.hevc",
+ "bbb_hevc_340x280_768kbps_30fps.info", 340, 280, false},
{MPEG4_1, MEDIA_MIMETYPE_VIDEO_MPEG4, "bbb_mpeg4_352x288_512kbps_30fps.m4v",
"bbb_mpeg4_352x288_512kbps_30fps.info", 352, 288, false},
{VP8_1, MEDIA_MIMETYPE_VIDEO_VP8, "bbb_vp8_176x144_240kbps_60fps.vp8",
@@ -164,6 +166,14 @@
int32_t addWriterSource(bool isAudio, configFormat params, int32_t idx = 0);
+ void setupExtractor(AMediaExtractor *extractor, string inputFileName, int32_t &trackCount);
+
+ void extract(AMediaExtractor *extractor, configFormat ¶ms, vector<BufferInfo> &bufferInfo,
+ uint8_t *buffer, size_t bufSize, size_t *bytesExtracted, int32_t idx);
+
+ void compareParams(configFormat srcParam, configFormat dstParam, vector<BufferInfo> dstBufInfo,
+ int32_t index);
+
enum standardWriters {
OGG,
AAC,
@@ -316,6 +326,146 @@
return;
}
+void WriterTest::setupExtractor(AMediaExtractor *extractor, string inputFileName,
+ int32_t &trackCount) {
+ ALOGV("Input file for extractor: %s", inputFileName.c_str());
+
+ int32_t fd = open(inputFileName.c_str(), O_RDONLY);
+ ASSERT_GE(fd, 0) << "Failed to open writer's output file to validate";
+
+ struct stat buf;
+ int32_t status = fstat(fd, &buf);
+ ASSERT_EQ(status, 0) << "Failed to get properties of input file for extractor";
+
+ size_t fileSize = buf.st_size;
+ ALOGV("Size of input file to extractor: %zu", fileSize);
+
+ status = AMediaExtractor_setDataSourceFd(extractor, fd, 0, fileSize);
+ ASSERT_EQ(status, AMEDIA_OK) << "Failed to set data source for extractor";
+
+ trackCount = AMediaExtractor_getTrackCount(extractor);
+ ASSERT_GT(trackCount, 0) << "No tracks reported by extractor";
+ ALOGV("Number of tracks reported by extractor : %d", trackCount);
+ return;
+}
+
+void WriterTest::extract(AMediaExtractor *extractor, configFormat ¶ms,
+ vector<BufferInfo> &bufferInfo, uint8_t *buffer, size_t bufSize,
+ size_t *bytesExtracted, int32_t idx) {
+ AMediaExtractor_selectTrack(extractor, idx);
+ AMediaFormat *format = AMediaExtractor_getTrackFormat(extractor, idx);
+ ASSERT_NE(format, nullptr) << "Track format is NULL";
+ ALOGI("Track format = %s", AMediaFormat_toString(format));
+
+ const char *mime = nullptr;
+ AMediaFormat_getString(format, AMEDIAFORMAT_KEY_MIME, &mime);
+ ASSERT_NE(mime, nullptr) << "Track mime is NULL";
+ ALOGI("Track mime = %s", mime);
+ strlcpy(params.mime, mime, kMimeSize);
+
+ if (!strncmp(mime, "audio/", 6)) {
+ ASSERT_TRUE(
+ AMediaFormat_getInt32(format, AMEDIAFORMAT_KEY_CHANNEL_COUNT, ¶ms.channelCount))
+ << "Extractor did not report channel count";
+ ASSERT_TRUE(AMediaFormat_getInt32(format, AMEDIAFORMAT_KEY_SAMPLE_RATE, ¶ms.sampleRate))
+ << "Extractor did not report sample rate";
+ } else if (!strncmp(mime, "video/", 6) || !strncmp(mime, "image/", 6)) {
+ ASSERT_TRUE(AMediaFormat_getInt32(format, AMEDIAFORMAT_KEY_WIDTH, ¶ms.width))
+ << "Extractor did not report width";
+ ASSERT_TRUE(AMediaFormat_getInt32(format, AMEDIAFORMAT_KEY_HEIGHT, ¶ms.height))
+ << "Extractor did not report height";
+ } else {
+ ASSERT_TRUE(false) << "Invalid mime " << mime;
+ }
+
+ int32_t bufferOffset = 0;
+ // Get CSD data
+ int index = 0;
+ void *csdBuf;
+ while (1) {
+ csdBuf = nullptr;
+ char csdName[16];
+ snprintf(csdName, 16, "csd-%d", index);
+ size_t csdSize = 0;
+ bool csdFound = AMediaFormat_getBuffer(format, csdName, &csdBuf, &csdSize);
+ if (!csdFound || !csdBuf || !csdSize) break;
+
+ bufferInfo.push_back({static_cast<int32_t>(csdSize), CODEC_CONFIG_FLAG, 0});
+ memcpy(buffer + bufferOffset, csdBuf, csdSize);
+ bufferOffset += csdSize;
+ index++;
+ }
+
+ // Get frame data
+ while (1) {
+ ssize_t sampleSize = AMediaExtractor_getSampleSize(extractor);
+ if (sampleSize < 0) break;
+
+ uint8_t *sampleBuffer = (uint8_t *)malloc(sampleSize);
+ ASSERT_NE(sampleBuffer, nullptr) << "Failed to allocate the buffer of size " << sampleSize;
+
+ int bytesRead = AMediaExtractor_readSampleData(extractor, sampleBuffer, sampleSize);
+ ASSERT_EQ(bytesRead, sampleSize)
+ << "Number of bytes extracted does not match with sample size";
+ int64_t pts = AMediaExtractor_getSampleTime(extractor);
+ uint32_t flag = AMediaExtractor_getSampleFlags(extractor);
+
+ if (mime == MEDIA_MIMETYPE_AUDIO_VORBIS) {
+ // Removing 4 bytes of AMEDIAFORMAT_KEY_VALID_SAMPLES from sample size
+ bytesRead = bytesRead - 4;
+ }
+
+ ASSERT_LE(bufferOffset + bytesRead, bufSize)
+ << "Size of the buffer is insufficient to store the extracted data";
+ bufferInfo.push_back({bytesRead, flag, pts});
+ memcpy(buffer + bufferOffset, sampleBuffer, bytesRead);
+ bufferOffset += bytesRead;
+
+ AMediaExtractor_advance(extractor);
+ free(sampleBuffer);
+ }
+ *bytesExtracted = bufferOffset;
+ return;
+}
+
+void WriterTest::compareParams(configFormat srcParam, configFormat dstParam,
+ vector<BufferInfo> dstBufInfo, int32_t index) {
+ ASSERT_STREQ(srcParam.mime, dstParam.mime)
+ << "Extracted mime type does not match with input mime type";
+
+ if (!strncmp(srcParam.mime, "audio/", 6)) {
+ ASSERT_EQ(srcParam.channelCount, dstParam.channelCount)
+ << "Extracted channel count does not match with input channel count";
+ ASSERT_EQ(srcParam.sampleRate, dstParam.sampleRate)
+ << "Extracted sample rate does not match with input sample rate";
+ } else if (!strncmp(srcParam.mime, "video/", 6) || !strncmp(srcParam.mime, "image/", 6)) {
+ ASSERT_EQ(srcParam.width, dstParam.width)
+ << "Extracted width does not match with input width";
+ ASSERT_EQ(srcParam.height, dstParam.height)
+ << "Extracted height does not match with input height";
+ } else {
+ ASSERT_TRUE(false) << "Invalid mime type" << srcParam.mime;
+ }
+
+ int32_t toleranceValueUs = kMuxToleranceTimeUs;
+ if (mWriterName == MPEG4) {
+ toleranceValueUs = kMpeg4MuxToleranceTimeUs;
+ }
+ for (int32_t i = 0; i < dstBufInfo.size(); i++) {
+ ASSERT_EQ(mBufferInfo[index][i].size, dstBufInfo[i].size)
+ << "Input size " << mBufferInfo[index][i].size << " mismatched with extracted size "
+ << dstBufInfo[i].size;
+ ASSERT_EQ(mBufferInfo[index][i].flags, dstBufInfo[i].flags)
+ << "Input flag " << mBufferInfo[index][i].flags
+ << " mismatched with extracted size " << dstBufInfo[i].flags;
+ ASSERT_LE(abs(mBufferInfo[index][i].timeUs - dstBufInfo[i].timeUs), toleranceValueUs)
+ << "Difference between original timestamp " << mBufferInfo[index][i].timeUs
+ << " and extracted timestamp " << dstBufInfo[i].timeUs
+ << "is greater than tolerance value = " << toleranceValueUs << " micro seconds";
+ }
+ return;
+}
+
TEST_P(WriteFunctionalityTest, CreateWriterTest) {
if (mDisableTest) return;
ALOGV("Tests the creation of writers");
@@ -350,16 +500,23 @@
if (inpId[1] != UNUSED_ID) {
numTracks++;
}
+
+ size_t fileSize[numTracks];
+ configFormat param[numTracks];
for (int32_t idx = 0; idx < numTracks; idx++) {
string inputFile = gEnv->getRes();
string inputInfo = gEnv->getRes();
- configFormat param;
bool isAudio;
- getFileDetails(inputFile, inputInfo, param, isAudio, inpId[idx]);
+ getFileDetails(inputFile, inputInfo, param[idx], isAudio, inpId[idx]);
ASSERT_NE(inputFile.compare(gEnv->getRes()), 0) << "No input file specified";
+ struct stat buf;
+ status = stat(inputFile.c_str(), &buf);
+ ASSERT_EQ(status, 0) << "Failed to get properties of input file:" << inputFile;
+ fileSize[idx] = buf.st_size;
+
ASSERT_NO_FATAL_FAILURE(getInputBufferInfo(inputFile, inputInfo, idx));
- status = addWriterSource(isAudio, param, idx);
+ status = addWriterSource(isAudio, param[idx], idx);
ASSERT_EQ((status_t)OK, status) << "Failed to add source for " << writerFormat << "Writer";
}
@@ -389,6 +546,50 @@
status = mWriter->stop();
ASSERT_EQ((status_t)OK, status) << "Failed to stop the writer";
close(fd);
+
+ // Validate the output muxed file created by writer
+ // TODO(b/146423022): Skip validating output for webm writer
+ // TODO(b/146421018): Skip validating output for ogg writer
+ if (mWriterName != OGG && mWriterName != WEBM) {
+ configFormat extractorParams[numTracks];
+ vector<BufferInfo> extractorBufferInfo[numTracks];
+ int32_t trackCount = -1;
+
+ AMediaExtractor *extractor = AMediaExtractor_new();
+ ASSERT_NE(extractor, nullptr) << "Failed to create extractor";
+ ASSERT_NO_FATAL_FAILURE(setupExtractor(extractor, outputFile, trackCount));
+ ASSERT_EQ(trackCount, numTracks)
+ << "Tracks reported by extractor does not match with input number of tracks";
+
+ for (int32_t idx = 0; idx < numTracks; idx++) {
+ char *inputBuffer = (char *)malloc(fileSize[idx]);
+ ASSERT_NE(inputBuffer, nullptr)
+ << "Failed to allocate the buffer of size " << fileSize[idx];
+ mInputStream[idx].seekg(0, mInputStream[idx].beg);
+ mInputStream[idx].read(inputBuffer, fileSize[idx]);
+ ASSERT_EQ(mInputStream[idx].gcount(), fileSize[idx]);
+
+ uint8_t *extractedBuffer = (uint8_t *)malloc(fileSize[idx]);
+ ASSERT_NE(extractedBuffer, nullptr)
+ << "Failed to allocate the buffer of size " << fileSize[idx];
+ size_t bytesExtracted = 0;
+
+ ASSERT_NO_FATAL_FAILURE(extract(extractor, extractorParams[idx],
+ extractorBufferInfo[idx], extractedBuffer,
+ fileSize[idx], &bytesExtracted, idx));
+ ASSERT_GT(bytesExtracted, 0) << "Total bytes extracted by extractor cannot be zero";
+
+ ASSERT_NO_FATAL_FAILURE(
+ compareParams(param[idx], extractorParams[idx], extractorBufferInfo[idx], idx));
+
+ ASSERT_EQ(memcmp(extractedBuffer, (uint8_t *)inputBuffer, bytesExtracted), 0)
+ << "Extracted bit stream does not match with input bit stream";
+
+ free(inputBuffer);
+ free(extractedBuffer);
+ }
+ AMediaExtractor_delete(extractor);
+ }
}
TEST_P(WriteFunctionalityTest, PauseWriterTest) {
@@ -704,6 +905,7 @@
make_tuple("webm", VORBIS_1, VP8_1, 0.25)));
int main(int argc, char **argv) {
+ ProcessState::self()->startThreadPool();
gEnv = new WriterTestEnvironment();
::testing::AddGlobalTestEnvironment(gEnv);
::testing::InitGoogleTest(&argc, argv);
diff --git a/media/libstagefright/tests/writer/WriterUtility.h b/media/libstagefright/tests/writer/WriterUtility.h
index 5e79298..716844a 100644
--- a/media/libstagefright/tests/writer/WriterUtility.h
+++ b/media/libstagefright/tests/writer/WriterUtility.h
@@ -34,6 +34,7 @@
constexpr uint32_t kMaxTrackCount = 2;
constexpr uint32_t kMaxCSDStrlen = 16;
constexpr uint32_t kMaxCount = 20;
+constexpr int32_t kMimeSize = 128;
struct BufferInfo {
int32_t size;
@@ -41,6 +42,14 @@
int64_t timeUs;
};
+struct configFormat {
+ char mime[kMimeSize];
+ int32_t width;
+ int32_t height;
+ int32_t sampleRate;
+ int32_t channelCount;
+};
+
int32_t sendBuffersToWriter(ifstream &inputStream, vector<BufferInfo> &bufferInfo,
int32_t &inputFrameId, sp<MediaAdapter> ¤tTrack, int32_t offset,
int32_t range, bool isPaused = false,
diff --git a/services/audiopolicy/common/managerdefinitions/src/DeviceDescriptor.cpp b/services/audiopolicy/common/managerdefinitions/src/DeviceDescriptor.cpp
index 68a32a2..d410ffd 100644
--- a/services/audiopolicy/common/managerdefinitions/src/DeviceDescriptor.cpp
+++ b/services/audiopolicy/common/managerdefinitions/src/DeviceDescriptor.cpp
@@ -227,6 +227,7 @@
{
bool added = false;
for (const auto& device : devices) {
+ ALOG_ASSERT(device != nullptr, "Null pointer found when adding DeviceVector");
if (indexOf(device) < 0 && SortedVector::add(device) >= 0) {
added = true;
}
@@ -238,6 +239,7 @@
ssize_t DeviceVector::add(const sp<DeviceDescriptor>& item)
{
+ ALOG_ASSERT(item != nullptr, "Adding null pointer to DeviceVector");
ssize_t ret = indexOf(item);
if (ret < 0) {
diff --git a/services/audiopolicy/enginedefault/src/Engine.cpp b/services/audiopolicy/enginedefault/src/Engine.cpp
index b14d2bb..8b39ebe 100755
--- a/services/audiopolicy/enginedefault/src/Engine.cpp
+++ b/services/audiopolicy/enginedefault/src/Engine.cpp
@@ -452,22 +452,26 @@
devices = availableOutputDevices.getDevicesFromType(AUDIO_DEVICE_OUT_TELEPHONY_TX);
break;
+ case STRATEGY_NONE:
+ // Happens when internal strategies are processed ("rerouting", "patch"...)
+ break;
+
default:
- ALOGW("getDevicesForStrategy() unknown strategy: %d", strategy);
+ ALOGW("%s unknown strategy: %d", __func__, strategy);
break;
}
if (devices.isEmpty()) {
- ALOGV("getDevicesForStrategy() no device found for strategy %d", strategy);
+ ALOGV("%s no device found for strategy %d", __func__, strategy);
sp<DeviceDescriptor> defaultOutputDevice = getApmObserver()->getDefaultOutputDevice();
if (defaultOutputDevice != nullptr) {
devices.add(defaultOutputDevice);
}
ALOGE_IF(devices.isEmpty(),
- "getDevicesForStrategy() no default device defined");
+ "%s no default device defined", __func__);
}
- ALOGVV("getDevices ForStrategy() strategy %d, device %s",
+ ALOGVV("%s strategy %d, device %s", __func__,
strategy, dumpDeviceTypes(devices.types()).c_str());
return devices;
}
diff --git a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
index dd4fda8..470c925 100644
--- a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
+++ b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
@@ -463,7 +463,16 @@
}
}
}
-
+ auto musicStrategy = streamToStrategy(AUDIO_STREAM_MUSIC);
+ for (size_t i = 0; i < mOutputs.size(); i++) {
+ sp<SwAudioOutputDescriptor> desc = mOutputs.valueAt(i);
+ // mute media strategies and delay device switch by the largest
+ // This avoid sending the music tail into the earpiece or headset.
+ setStrategyMute(musicStrategy, true, desc);
+ setStrategyMute(musicStrategy, false, desc, MUTE_TIME_MS,
+ mEngine->getOutputDevicesForAttributes(attributes_initializer(AUDIO_USAGE_MEDIA),
+ nullptr, true /*fromCache*/).types());
+ }
// Toggle the device state: UNAVAILABLE -> AVAILABLE
// This will force reading again the device configuration
status = setDeviceConnectionState(device,
diff --git a/services/camera/libcameraservice/device3/Camera3Device.cpp b/services/camera/libcameraservice/device3/Camera3Device.cpp
index 35c389e..9696e19 100644
--- a/services/camera/libcameraservice/device3/Camera3Device.cpp
+++ b/services/camera/libcameraservice/device3/Camera3Device.cpp
@@ -1833,10 +1833,12 @@
mStatusWaiters++;
+ bool signalPipelineDrain = false;
if (!active && mUseHalBufManager) {
auto streamIds = mOutputStreams.getStreamIds();
if (mStatus == STATUS_ACTIVE) {
mRequestThread->signalPipelineDrain(streamIds);
+ signalPipelineDrain = true;
}
mRequestBufferSM.onWaitUntilIdle();
}
@@ -1866,6 +1868,10 @@
}
} while (!stateSeen);
+ if (signalPipelineDrain) {
+ mRequestThread->resetPipelineDrain();
+ }
+
mStatusWaiters--;
return res;
@@ -4785,6 +4791,12 @@
mStreamIdsToBeDrained = streamIds;
}
+void Camera3Device::RequestThread::resetPipelineDrain() {
+ Mutex::Autolock pl(mPauseLock);
+ mNotifyPipelineDrain = false;
+ mStreamIdsToBeDrained.clear();
+}
+
void Camera3Device::RequestThread::clearPreviousRequest() {
Mutex::Autolock l(mRequestLock);
mPrevRequest.clear();
diff --git a/services/camera/libcameraservice/device3/Camera3Device.h b/services/camera/libcameraservice/device3/Camera3Device.h
index 8e2c2f9..2aad09a 100644
--- a/services/camera/libcameraservice/device3/Camera3Device.h
+++ b/services/camera/libcameraservice/device3/Camera3Device.h
@@ -832,6 +832,7 @@
}
void signalPipelineDrain(const std::vector<int>& streamIds);
+ void resetPipelineDrain();
status_t switchToOffline(
const std::vector<int32_t>& streamsToKeep,
diff --git a/services/mediametrics/MediaMetricsService.cpp b/services/mediametrics/MediaMetricsService.cpp
index 48e766e..bf6e428 100644
--- a/services/mediametrics/MediaMetricsService.cpp
+++ b/services/mediametrics/MediaMetricsService.cpp
@@ -468,6 +468,7 @@
"codec",
"extractor",
"mediadrm",
+ "mediaparser",
"nuplayer",
}) {
if (key == allowedKey) {
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;
};