aaudio: improve accuracy of timestamps
Account for latency added by the AAudio service.
Fix input timestamps.
Bug: 37080396
Test: test_timestamps.cpp input_monitor.cpp
Change-Id: I1053cd21af722bb9b9371df4e5731bf4a0a57b0b
diff --git a/media/libaaudio/examples/input_monitor/src/input_monitor.cpp b/media/libaaudio/examples/input_monitor/src/input_monitor.cpp
index edf644a..2dfd0a7 100644
--- a/media/libaaudio/examples/input_monitor/src/input_monitor.cpp
+++ b/media/libaaudio/examples/input_monitor/src/input_monitor.cpp
@@ -27,9 +27,11 @@
#include "AAudioSimpleRecorder.h"
// TODO support FLOAT
-#define REQUIRED_FORMAT AAUDIO_FORMAT_PCM_I16
+#define REQUIRED_FORMAT AAUDIO_FORMAT_PCM_I16
#define MIN_FRAMES_TO_READ 48 /* arbitrary, 1 msec at 48000 Hz */
+static const int FRAMES_PER_LINE = 20000;
+
int main(int argc, const char **argv)
{
AAudioArgsParser argParser;
@@ -46,7 +48,10 @@
int32_t framesPerRead = 0;
int32_t framesToRecord = 0;
int32_t framesLeft = 0;
+ int32_t nextFrameCount = 0;
+ int32_t frameCount = 0;
int32_t xRunCount = 0;
+ int64_t previousFramePosition = -1;
int16_t *data = nullptr;
float peakLevel = 0.0;
int loopCounter = 0;
@@ -56,7 +61,7 @@
// in a buffer if we hang or crash.
setvbuf(stdout, nullptr, _IONBF, (size_t) 0);
- printf("%s - Monitor input level using AAudio\n", argv[0]);
+ printf("%s - Monitor input level using AAudio V0.1.1\n", argv[0]);
argParser.setFormat(REQUIRED_FORMAT);
if (argParser.parseArgs(argc, argv)) {
@@ -133,6 +138,7 @@
goto finish;
}
framesLeft -= actual;
+ frameCount += actual;
// Peak finder.
for (int frameIndex = 0; frameIndex < actual; frameIndex++) {
@@ -143,9 +149,36 @@
}
// Display level as stars, eg. "******".
- if ((loopCounter++ % 10) == 0) {
+ if (frameCount > nextFrameCount) {
displayPeakLevel(peakLevel);
peakLevel = 0.0;
+ nextFrameCount += FRAMES_PER_LINE;
+ }
+
+ // Print timestamps.
+ int64_t framePosition = 0;
+ int64_t frameTime = 0;
+ aaudio_result_t timeResult;
+ timeResult = AAudioStream_getTimestamp(aaudioStream, CLOCK_MONOTONIC,
+ &framePosition, &frameTime);
+
+ if (timeResult == AAUDIO_OK) {
+ if (framePosition > (previousFramePosition + FRAMES_PER_LINE)) {
+ int64_t realTime = getNanoseconds();
+ int64_t framesRead = AAudioStream_getFramesRead(aaudioStream);
+
+ double latencyMillis = calculateLatencyMillis(framesRead, realTime,
+ framePosition, frameTime,
+ actualSampleRate);
+
+ printf("--- timestamp: result = %4d, position = %lld, at %lld nanos"
+ ", latency = %7.2f msec\n",
+ timeResult,
+ (long long) framePosition,
+ (long long) frameTime,
+ latencyMillis);
+ previousFramePosition = framePosition;
+ }
}
}
diff --git a/media/libaaudio/examples/utils/AAudioExampleUtils.h b/media/libaaudio/examples/utils/AAudioExampleUtils.h
index 66de25f..6cbcc58 100644
--- a/media/libaaudio/examples/utils/AAudioExampleUtils.h
+++ b/media/libaaudio/examples/utils/AAudioExampleUtils.h
@@ -25,7 +25,7 @@
#define NANOS_PER_MILLISECOND (NANOS_PER_MICROSECOND * 1000)
#define NANOS_PER_SECOND (NANOS_PER_MILLISECOND * 1000)
-static const char *getSharingModeText(aaudio_sharing_mode_t mode) {
+const char *getSharingModeText(aaudio_sharing_mode_t mode) {
const char *modeText = "unknown";
switch (mode) {
case AAUDIO_SHARING_MODE_EXCLUSIVE:
@@ -49,7 +49,7 @@
return (time.tv_sec * NANOS_PER_SECOND) + time.tv_nsec;
}
-void displayPeakLevel(float peakLevel) {
+static void displayPeakLevel(float peakLevel) {
printf("%5.3f ", peakLevel);
const int maxStars = 50; // arbitrary, fits on one line
int numStars = (int) (peakLevel * maxStars);
@@ -59,4 +59,24 @@
printf("\n");
}
+/**
+ * @param position1 position of hardware frame
+ * @param nanoseconds1
+ * @param position2 position of client read/write
+ * @param nanoseconds2
+ * @param sampleRate
+ * @return latency in milliseconds
+ */
+static double calculateLatencyMillis(int64_t position1, int64_t nanoseconds1,
+ int64_t position2, int64_t nanoseconds2,
+ int64_t sampleRate) {
+ int64_t deltaFrames = position2 - position1;
+ int64_t deltaTime =
+ (NANOS_PER_SECOND * deltaFrames / sampleRate);
+ int64_t timeCurrentFramePlayed = nanoseconds1 + deltaTime;
+ int64_t latencyNanos = timeCurrentFramePlayed - nanoseconds2;
+ double latencyMillis = latencyNanos / 1000000.0;
+ return latencyMillis;
+}
+
#endif // AAUDIO_EXAMPLE_UTILS_H