aaudio: test 24 and 32 bit formats
Modify write sine tests.
Bug: 75038760
Test: adb shell write_sine_callback -f3
Test: adb shell write_sine_callback -f4
Change-Id: I61eccbffbf898e50ee241e135d21acebb6a63524
diff --git a/media/libaaudio/examples/utils/AAudioArgsParser.h b/media/libaaudio/examples/utils/AAudioArgsParser.h
index 4bba436..e670642 100644
--- a/media/libaaudio/examples/utils/AAudioArgsParser.h
+++ b/media/libaaudio/examples/utils/AAudioArgsParser.h
@@ -421,7 +421,9 @@
printf(" -f{0|1|2} set format\n");
printf(" 0 = UNSPECIFIED\n");
printf(" 1 = PCM_I16\n");
- printf(" 2 = FLOAT\n");
+ printf(" 2 = PCM_FLOAT\n");
+ printf(" 3 = PCM_I24_PACKED\n");
+ printf(" 4 = PCM_I32\n");
printf(" -i{inputPreset} eg. 5 for AAUDIO_INPUT_PRESET_CAMCORDER\n");
printf(" -m{0|1|2|3} set MMAP policy\n");
printf(" 0 = _UNSPECIFIED, use aaudio.mmap_policy system property, default\n");
diff --git a/media/libaaudio/examples/utils/AAudioExampleUtils.h b/media/libaaudio/examples/utils/AAudioExampleUtils.h
index 46b8895..5819dfd 100644
--- a/media/libaaudio/examples/utils/AAudioExampleUtils.h
+++ b/media/libaaudio/examples/utils/AAudioExampleUtils.h
@@ -32,6 +32,7 @@
#define NANOS_PER_MILLISECOND (NANOS_PER_MICROSECOND * 1000)
#define NANOS_PER_SECOND (NANOS_PER_MILLISECOND * 1000)
+// Use template functions to avoid warning of unused static functions.
template <class T = aaudio_sharing_mode_t>
const char *getSharingModeText(aaudio_sharing_mode_t mode) {
const char *text = "unknown";
@@ -48,6 +49,7 @@
return text;
}
+template <class T = aaudio_performance_mode_t>
const char *getPerformanceModeText(aaudio_performance_mode_t mode) {
const char *text = "unknown";
switch (mode) {
@@ -66,6 +68,7 @@
return text;
}
+template <class T = aaudio_direction_t>
const char *getDirectionText(aaudio_direction_t direction) {
const char *text = "unknown";
switch (direction) {
@@ -81,6 +84,29 @@
return text;
}
+template <class T = aaudio_direction_t>
+constexpr int32_t getBytesPerSample(aaudio_format_t format) {
+ switch (format) {
+ case AAUDIO_FORMAT_PCM_I16:
+ return 2;
+ case AAUDIO_FORMAT_PCM_FLOAT:
+ return 4;
+ case AAUDIO_FORMAT_PCM_I24_PACKED:
+ return 3;
+ case AAUDIO_FORMAT_PCM_I32:
+ return 4;
+ default:
+ return -1;
+ }
+}
+
+// Return true if CPU is native Little Endian
+inline bool isNativeLittleEndian() {
+ // If the first byte of the data word in memory is 1 then Little Endian.
+ constexpr union { unsigned u; unsigned char c[sizeof(unsigned)]; } one = {1};
+ return one.c[0] != 0;
+}
+
template <class T = int64_t>
void convertNanosecondsToTimespec(int64_t nanoseconds, struct timespec *time) {
time->tv_sec = nanoseconds / NANOS_PER_SECOND;
diff --git a/media/libaaudio/examples/utils/AAudioSimplePlayer.h b/media/libaaudio/examples/utils/AAudioSimplePlayer.h
index fd1fc45..7daac20 100644
--- a/media/libaaudio/examples/utils/AAudioSimplePlayer.h
+++ b/media/libaaudio/examples/utils/AAudioSimplePlayer.h
@@ -359,22 +359,38 @@
int32_t samplesPerFrame = AAudioStream_getChannelCount(stream);
-
- int numActiveOscilators = (samplesPerFrame > MAX_CHANNELS) ? MAX_CHANNELS : samplesPerFrame;
+ int numActiveOscillators = std::min(samplesPerFrame, MAX_CHANNELS);
switch (AAudioStream_getFormat(stream)) {
case AAUDIO_FORMAT_PCM_I16: {
int16_t *audioBuffer = (int16_t *) audioData;
- for (int i = 0; i < numActiveOscilators; ++i) {
- sineData->sineOscillators[i].render(&audioBuffer[i], samplesPerFrame,
- numFrames);
+ for (int i = 0; i < numActiveOscillators; ++i) {
+ sineData->sineOscillators[i].render(&audioBuffer[i],
+ samplesPerFrame, numFrames);
}
}
break;
case AAUDIO_FORMAT_PCM_FLOAT: {
float *audioBuffer = (float *) audioData;
- for (int i = 0; i < numActiveOscilators; ++i) {
- sineData->sineOscillators[i].render(&audioBuffer[i], samplesPerFrame,
- numFrames);
+ for (int i = 0; i < numActiveOscillators; ++i) {
+ sineData->sineOscillators[i].render(&audioBuffer[i],
+ samplesPerFrame, numFrames);
+ }
+ }
+ break;
+ case AAUDIO_FORMAT_PCM_I24_PACKED: {
+ uint8_t *audioBuffer = (uint8_t *) audioData;
+ for (int i = 0; i < numActiveOscillators; ++i) {
+ static const int bytesPerSample = getBytesPerSample(AAUDIO_FORMAT_PCM_I24_PACKED);
+ sineData->sineOscillators[i].render24(&audioBuffer[i * bytesPerSample],
+ samplesPerFrame, numFrames);
+ }
+ }
+ break;
+ case AAUDIO_FORMAT_PCM_I32: {
+ int32_t *audioBuffer = (int32_t *) audioData;
+ for (int i = 0; i < numActiveOscillators; ++i) {
+ sineData->sineOscillators[i].render(&audioBuffer[i],
+ samplesPerFrame, numFrames);
}
}
break;
diff --git a/media/libaaudio/examples/utils/SineGenerator.h b/media/libaaudio/examples/utils/SineGenerator.h
index 9e6d46d..66a08fd 100644
--- a/media/libaaudio/examples/utils/SineGenerator.h
+++ b/media/libaaudio/examples/utils/SineGenerator.h
@@ -41,20 +41,54 @@
}
}
+ float next() {
+ float value = sinf(mPhase) * mAmplitude;
+ advancePhase();
+ return value;
+ }
+
void render(int16_t *buffer, int32_t channelStride, int32_t numFrames) {
int sampleIndex = 0;
for (int i = 0; i < numFrames; i++) {
- buffer[sampleIndex] = (int16_t) (INT16_MAX * sin(mPhase) * mAmplitude);
+ buffer[sampleIndex] = (int16_t) (INT16_MAX * next());
sampleIndex += channelStride;
- advancePhase();
}
}
+
void render(float *buffer, int32_t channelStride, int32_t numFrames) {
int sampleIndex = 0;
for (int i = 0; i < numFrames; i++) {
- buffer[sampleIndex] = sin(mPhase) * mAmplitude;
+ buffer[sampleIndex] = next();
sampleIndex += channelStride;
- advancePhase();
+ }
+ }
+
+ void render(int32_t *buffer, int32_t channelStride, int32_t numFrames) {
+ int sampleIndex = 0;
+ for (int i = 0; i < numFrames; i++) {
+ buffer[sampleIndex] = (int32_t) (INT32_MAX * next());
+ sampleIndex += channelStride;
+ }
+ }
+
+ void render24(uint8_t *buffer, int32_t channelStride, int32_t numFrames) {
+ int sampleIndex = 0;
+ constexpr int32_t INT24_MAX = (1 << 23) - 1;
+ constexpr int bytesPerSample = getBytesPerSample(AAUDIO_FORMAT_PCM_I24_PACKED);
+ const bool isLittleEndian = isNativeLittleEndian();
+ for (int i = 0; i < numFrames; i++) {
+ int32_t sample = (int32_t) (INT24_MAX * next());
+ uint32_t usample = (uint32_t) sample;
+ if (isLittleEndian) {
+ buffer[sampleIndex] = usample; // little end first
+ buffer[sampleIndex + 1] = usample >> 8;
+ buffer[sampleIndex + 2] = usample >> 16;
+ } else {
+ buffer[sampleIndex] = usample >> 16; // big end first
+ buffer[sampleIndex + 1] = usample >> 8;
+ buffer[sampleIndex + 2] = usample;
+ }
+ sampleIndex += channelStride * bytesPerSample;
}
}
@@ -100,4 +134,3 @@
};
#endif /* SINE_GENERATOR_H */
-
diff --git a/media/libaaudio/examples/write_sine/src/write_sine.cpp b/media/libaaudio/examples/write_sine/src/write_sine.cpp
index 8e33a31..33d07f0 100644
--- a/media/libaaudio/examples/write_sine/src/write_sine.cpp
+++ b/media/libaaudio/examples/write_sine/src/write_sine.cpp
@@ -47,9 +47,11 @@
int32_t framesToPlay = 0;
int32_t framesLeft = 0;
int32_t xRunCount = 0;
- int numActiveOscilators = 0;
+ int numActiveOscillators = 0;
float *floatData = nullptr;
int16_t *shortData = nullptr;
+ int32_t *int32Data = nullptr;
+ uint8_t *byteData = nullptr;
int testFd = -1;
@@ -57,7 +59,7 @@
// in a buffer if we hang or crash.
setvbuf(stdout, nullptr, _IONBF, (size_t) 0);
- printf("%s - Play a sine wave using AAudio V0.1.3\n", argv[0]);
+ printf("%s - Play a sine wave using AAudio V0.1.4\n", argv[0]);
if (argParser.parseArgs(argc, argv)) {
return EXIT_FAILURE;
@@ -91,13 +93,23 @@
printf("Buffer: framesPerWrite = %d\n",framesPerWrite);
// Allocate a buffer for the audio data.
- if (actualDataFormat == AAUDIO_FORMAT_PCM_FLOAT) {
- floatData = new float[framesPerWrite * actualChannelCount];
- } else if (actualDataFormat == AAUDIO_FORMAT_PCM_I16) {
- shortData = new int16_t[framesPerWrite * actualChannelCount];
- } else {
- printf("ERROR Unsupported data format!\n");
- goto finish;
+ switch (actualDataFormat) {
+ case AAUDIO_FORMAT_PCM_FLOAT:
+ floatData = new float[framesPerWrite * actualChannelCount];
+ break;
+ case AAUDIO_FORMAT_PCM_I16:
+ shortData = new int16_t[framesPerWrite * actualChannelCount];
+ break;
+ case AAUDIO_FORMAT_PCM_I24_PACKED:
+ byteData = new uint8_t[framesPerWrite * actualChannelCount
+ * getBytesPerSample(AAUDIO_FORMAT_PCM_I24_PACKED)];
+ break;
+ case AAUDIO_FORMAT_PCM_I32:
+ int32Data = new int32_t[framesPerWrite * actualChannelCount];
+ break;
+ default:
+ printf("ERROR Unsupported data format!\n");
+ goto finish;
}
testFd = open("/data/aaudio_temp.raw", O_CREAT | O_RDWR, S_IRWXU);
@@ -117,29 +129,56 @@
// Play for a while.
framesToPlay = actualSampleRate * argParser.getDurationSeconds();
framesLeft = framesToPlay;
- numActiveOscilators = (actualChannelCount > MAX_CHANNELS) ? MAX_CHANNELS : actualChannelCount;
+ numActiveOscillators = (actualChannelCount > MAX_CHANNELS) ? MAX_CHANNELS : actualChannelCount;
while (framesLeft > 0) {
// Render as FLOAT or PCM
- if (actualDataFormat == AAUDIO_FORMAT_PCM_FLOAT) {
- for (int i = 0; i < numActiveOscilators; ++i) {
- myData.sineOscillators[i].render(&floatData[i], actualChannelCount,
- framesPerWrite);
- }
- } else if (actualDataFormat == AAUDIO_FORMAT_PCM_I16) {
- for (int i = 0; i < numActiveOscilators; ++i) {
- myData.sineOscillators[i].render(&shortData[i], actualChannelCount,
- framesPerWrite);
- }
+ switch (actualDataFormat) {
+ case AAUDIO_FORMAT_PCM_FLOAT:
+ for (int i = 0; i < numActiveOscillators; ++i) {
+ myData.sineOscillators[i].render(&floatData[i], actualChannelCount,
+ framesPerWrite);
+ }
+ break;
+ case AAUDIO_FORMAT_PCM_I16:
+ for (int i = 0; i < numActiveOscillators; ++i) {
+ myData.sineOscillators[i].render(&shortData[i], actualChannelCount,
+ framesPerWrite);
+ }
+ break;
+ case AAUDIO_FORMAT_PCM_I32:
+ for (int i = 0; i < numActiveOscillators; ++i) {
+ myData.sineOscillators[i].render(&int32Data[i], actualChannelCount,
+ framesPerWrite);
+ }
+ break;
+ case AAUDIO_FORMAT_PCM_I24_PACKED:
+ for (int i = 0; i < numActiveOscillators; ++i) {
+ static const int
+ bytesPerSample = getBytesPerSample(AAUDIO_FORMAT_PCM_I24_PACKED);
+ myData.sineOscillators[i].render24(&byteData[i * bytesPerSample],
+ actualChannelCount,
+ framesPerWrite);
+ }
+ break;
}
// Write audio data to the stream.
int64_t timeoutNanos = 1000 * NANOS_PER_MILLISECOND;
int32_t minFrames = (framesToPlay < framesPerWrite) ? framesToPlay : framesPerWrite;
int32_t actual = 0;
- if (actualDataFormat == AAUDIO_FORMAT_PCM_FLOAT) {
- actual = AAudioStream_write(aaudioStream, floatData, minFrames, timeoutNanos);
- } else if (actualDataFormat == AAUDIO_FORMAT_PCM_I16) {
- actual = AAudioStream_write(aaudioStream, shortData, minFrames, timeoutNanos);
+ switch (actualDataFormat) {
+ case AAUDIO_FORMAT_PCM_FLOAT:
+ actual = AAudioStream_write(aaudioStream, floatData, minFrames, timeoutNanos);
+ break;
+ case AAUDIO_FORMAT_PCM_I16:
+ actual = AAudioStream_write(aaudioStream, shortData, minFrames, timeoutNanos);
+ break;
+ case AAUDIO_FORMAT_PCM_I32:
+ actual = AAudioStream_write(aaudioStream, int32Data, minFrames, timeoutNanos);
+ break;
+ case AAUDIO_FORMAT_PCM_I24_PACKED:
+ actual = AAudioStream_write(aaudioStream, byteData, minFrames, timeoutNanos);
+ break;
}
if (actual < 0) {
fprintf(stderr, "ERROR - AAudioStream_write() returned %d\n", actual);
@@ -196,6 +235,8 @@
delete[] floatData;
delete[] shortData;
+ delete[] int32Data;
+ delete[] byteData;
printf("exiting - AAudio result = %d = %s\n", result, AAudio_convertResultToText(result));
return (result != AAUDIO_OK) ? EXIT_FAILURE : EXIT_SUCCESS;
}
diff --git a/media/libaaudio/examples/write_sine/src/write_sine_callback.cpp b/media/libaaudio/examples/write_sine/src/write_sine_callback.cpp
index ca60233..cdc987b 100644
--- a/media/libaaudio/examples/write_sine/src/write_sine_callback.cpp
+++ b/media/libaaudio/examples/write_sine/src/write_sine_callback.cpp
@@ -31,7 +31,7 @@
#include "AAudioSimplePlayer.h"
#include "AAudioArgsParser.h"
-#define APP_VERSION "0.1.7"
+#define APP_VERSION "0.1.8"
constexpr int32_t kDefaultHangTimeMSec = 10;