Merge "aaudio: offset MMAP timestamps"
diff --git a/media/libaaudio/src/client/AudioStreamInternal.cpp b/media/libaaudio/src/client/AudioStreamInternal.cpp
index 52eadd4..2ece474 100644
--- a/media/libaaudio/src/client/AudioStreamInternal.cpp
+++ b/media/libaaudio/src/client/AudioStreamInternal.cpp
@@ -232,6 +232,24 @@
mCallbackBuffer = new uint8_t[callbackBufferSize];
}
+ // For debugging and analyzing the distribution of MMAP timestamps.
+ // For OUTPUT, use a NEGATIVE offset to move the CPU writes further BEFORE the HW reads.
+ // For INPUT, use a POSITIVE offset to move the CPU reads further AFTER the HW writes.
+ // You can use this offset to reduce glitching.
+ // You can also use this offset to force glitching. By iterating over multiple
+ // values you can reveal the distribution of the hardware timing jitter.
+ if (mAudioEndpoint.isFreeRunning()) { // MMAP?
+ int32_t offsetMicros = (getDirection() == AAUDIO_DIRECTION_OUTPUT)
+ ? AAudioProperty_getOutputMMapOffsetMicros()
+ : AAudioProperty_getInputMMapOffsetMicros();
+ // This log is used to debug some tricky glitch issues. Please leave.
+ ALOGD_IF(offsetMicros, "%s() - %s mmap offset = %d micros",
+ __func__,
+ (getDirection() == AAUDIO_DIRECTION_OUTPUT) ? "output" : "input",
+ offsetMicros);
+ mTimeOffsetNanos = offsetMicros * AAUDIO_NANOS_PER_MICROSECOND;
+ }
+
setState(AAUDIO_STREAM_STATE_OPEN);
return result;
@@ -478,7 +496,8 @@
#if LOG_TIMESTAMPS
logTimestamp(*message);
#endif
- processTimestamp(message->timestamp.position, message->timestamp.timestamp);
+ processTimestamp(message->timestamp.position,
+ message->timestamp.timestamp + mTimeOffsetNanos);
return AAUDIO_OK;
}
diff --git a/media/libaaudio/src/client/AudioStreamInternal.h b/media/libaaudio/src/client/AudioStreamInternal.h
index 86c4698..9395416 100644
--- a/media/libaaudio/src/client/AudioStreamInternal.h
+++ b/media/libaaudio/src/client/AudioStreamInternal.h
@@ -194,6 +194,7 @@
// By delaying slightly we can avoid waking up before other side is ready.
const int32_t mWakeupDelayNanos; // delay past typical wakeup jitter
const int32_t mMinimumSleepNanos; // minimum sleep while polling
+ int32_t mTimeOffsetNanos = 0; // add to time part of an MMAP timestamp
AudioEndpointParcelable mEndPointParcelable; // description of the buffers filled by service
EndpointDescriptor mEndpointDescriptor; // buffer description with resolved addresses
diff --git a/media/libaaudio/src/utility/AAudioUtilities.cpp b/media/libaaudio/src/utility/AAudioUtilities.cpp
index cdd02c0..0ff6333 100644
--- a/media/libaaudio/src/utility/AAudioUtilities.cpp
+++ b/media/libaaudio/src/utility/AAudioUtilities.cpp
@@ -335,6 +335,30 @@
return prop;
}
+static int32_t AAudioProperty_getMMapOffsetMicros(const char *functionName,
+ const char *propertyName) {
+ const int32_t minMicros = -20000; // arbitrary
+ const int32_t defaultMicros = 0; // arbitrary
+ const int32_t maxMicros = 20000; // arbitrary
+ int32_t prop = property_get_int32(propertyName, defaultMicros);
+ if (prop < minMicros) {
+ ALOGW("%s: clipped %d to %d", functionName, prop, minMicros);
+ prop = minMicros;
+ } else if (prop > maxMicros) {
+ ALOGW("%s: clipped %d to %d", functionName, prop, minMicros);
+ prop = maxMicros;
+ }
+ return prop;
+}
+
+int32_t AAudioProperty_getInputMMapOffsetMicros() {
+ return AAudioProperty_getMMapOffsetMicros(__func__, AAUDIO_PROP_INPUT_MMAP_OFFSET_USEC);
+}
+
+int32_t AAudioProperty_getOutputMMapOffsetMicros() {
+ return AAudioProperty_getMMapOffsetMicros(__func__, AAUDIO_PROP_OUTPUT_MMAP_OFFSET_USEC);
+}
+
aaudio_result_t AAudio_isFlushAllowed(aaudio_stream_state_t state) {
aaudio_result_t result = AAUDIO_OK;
switch (state) {
diff --git a/media/libaaudio/src/utility/AAudioUtilities.h b/media/libaaudio/src/utility/AAudioUtilities.h
index 76d0457..55824f7 100644
--- a/media/libaaudio/src/utility/AAudioUtilities.h
+++ b/media/libaaudio/src/utility/AAudioUtilities.h
@@ -94,31 +94,26 @@
// Note that this code may be replaced by Settings or by some other system configuration tool.
+/**
+ * Read system property.
+ * @return AAUDIO_UNSPECIFIED, AAUDIO_POLICY_NEVER or AAUDIO_POLICY_AUTO or AAUDIO_POLICY_ALWAYS
+ */
+int32_t AAudioProperty_getMMapPolicy();
#define AAUDIO_PROP_MMAP_POLICY "aaudio.mmap_policy"
/**
* Read system property.
* @return AAUDIO_UNSPECIFIED, AAUDIO_POLICY_NEVER or AAUDIO_POLICY_AUTO or AAUDIO_POLICY_ALWAYS
*/
-int32_t AAudioProperty_getMMapPolicy();
-
-#define AAUDIO_PROP_MMAP_EXCLUSIVE_POLICY "aaudio.mmap_exclusive_policy"
-
-/**
- * Read system property.
- * @return AAUDIO_UNSPECIFIED, AAUDIO_POLICY_NEVER or AAUDIO_POLICY_AUTO or AAUDIO_POLICY_ALWAYS
- */
int32_t AAudioProperty_getMMapExclusivePolicy();
-
-#define AAUDIO_PROP_MIXER_BURSTS "aaudio.mixer_bursts"
+#define AAUDIO_PROP_MMAP_EXCLUSIVE_POLICY "aaudio.mmap_exclusive_policy"
/**
* Read system property.
* @return number of bursts per AAudio service mixer cycle
*/
int32_t AAudioProperty_getMixerBursts();
-
-#define AAUDIO_PROP_HW_BURST_MIN_USEC "aaudio.hw_burst_min_usec"
+#define AAUDIO_PROP_MIXER_BURSTS "aaudio.mixer_bursts"
/**
* Read a system property that specifies the number of extra microseconds that a thread
@@ -130,7 +125,6 @@
* @return number of microseconds to delay the wakeup.
*/
int32_t AAudioProperty_getWakeupDelayMicros();
-
#define AAUDIO_PROP_WAKEUP_DELAY_USEC "aaudio.wakeup_delay_usec"
/**
@@ -139,7 +133,6 @@
* @return minimum number of microseconds to sleep.
*/
int32_t AAudioProperty_getMinimumSleepMicros();
-
#define AAUDIO_PROP_MINIMUM_SLEEP_USEC "aaudio.minimum_sleep_usec"
/**
@@ -153,7 +146,21 @@
* @return minimum number of microseconds for a MMAP HW burst
*/
int32_t AAudioProperty_getHardwareBurstMinMicros();
+#define AAUDIO_PROP_HW_BURST_MIN_USEC "aaudio.hw_burst_min_usec"
+/**
+ * Read a system property that specifies an offset that will be added to MMAP timestamps.
+ * This can be used to correct bias in the timestamp.
+ * It can also be used to analyze the time distribution of the timestamp
+ * by progressively modifying the offset and listening for glitches.
+ *
+ * @return number of microseconds to offset the time part of an MMAP timestamp
+ */
+int32_t AAudioProperty_getInputMMapOffsetMicros();
+#define AAUDIO_PROP_INPUT_MMAP_OFFSET_USEC "aaudio.in_mmap_offset_usec"
+
+int32_t AAudioProperty_getOutputMMapOffsetMicros();
+#define AAUDIO_PROP_OUTPUT_MMAP_OFFSET_USEC "aaudio.out_mmap_offset_usec"
/**
* Is flush allowed for the given state?