Merge changes from topic "audio-histogram"
* changes:
aaudio: test audio_utils::Histogram
aaudio: add histogram to clock model
diff --git a/media/libaaudio/src/client/IsochronousClockModel.cpp b/media/libaaudio/src/client/IsochronousClockModel.cpp
index 07b6ad0..bd46d05 100644
--- a/media/libaaudio/src/client/IsochronousClockModel.cpp
+++ b/media/libaaudio/src/client/IsochronousClockModel.cpp
@@ -18,18 +18,30 @@
//#define LOG_NDEBUG 0
#include <log/log.h>
+#define __STDC_FORMAT_MACROS
+#include <inttypes.h>
#include <stdint.h>
#include <algorithm>
#include "utility/AudioClock.h"
+#include "utility/AAudioUtilities.h"
#include "IsochronousClockModel.h"
using namespace aaudio;
+using namespace android::audio_utils;
+
#ifndef ICM_LOG_DRIFT
#define ICM_LOG_DRIFT 0
#endif // ICM_LOG_DRIFT
+// To enable the timestamp histogram, enter this before opening the stream:
+// adb root
+// adb shell setprop aaudio.log_mask 1
+// A histogram of the lateness of the timestamps will be cleared when the stream is started.
+// It will be updated when the model is stable and receives a timestamp,
+// and dumped to the log when the stream is stopped.
+
IsochronousClockModel::IsochronousClockModel()
: mMarkerFramePosition(0)
, mMarkerNanoTime(0)
@@ -39,6 +51,10 @@
, mLatenessForDriftNanos(kInitialLatenessForDriftNanos)
, mState(STATE_STOPPED)
{
+ if ((AAudioProperty_getLogMask() & AAUDIO_LOG_CLOCK_MODEL_HISTOGRAM) != 0) {
+ mHistogramMicros = std::make_unique<Histogram>(kHistogramBinCount,
+ kHistogramBinWidthMicros);
+ }
}
IsochronousClockModel::~IsochronousClockModel() {
@@ -54,6 +70,9 @@
ALOGV("start(nanos = %lld)\n", (long long) nanoTime);
mMarkerNanoTime = nanoTime;
mState = STATE_STARTING;
+ if (mHistogramMicros) {
+ mHistogramMicros->clear();
+ }
}
void IsochronousClockModel::stop(int64_t nanoTime) {
@@ -63,6 +82,9 @@
setPositionAndTime(convertTimeToPosition(nanoTime), nanoTime);
// TODO should we set position?
mState = STATE_STOPPED;
+ if (mHistogramMicros) {
+ dumpHistogram();
+ }
}
bool IsochronousClockModel::isStarting() const {
@@ -113,6 +135,9 @@
}
break;
case STATE_RUNNING:
+ if (mHistogramMicros) {
+ mHistogramMicros->add(latenessNanos / AAUDIO_NANOS_PER_MICROSECOND);
+ }
// Modify estimated position based on lateness.
// This affects the "early" side of the window, which controls output glitches.
if (latenessNanos < 0) {
@@ -121,10 +146,9 @@
// Or we may be drifting due to a fast HW clock.
setPositionAndTime(framePosition, nanoTime);
#if ICM_LOG_DRIFT
- int microsDelta = (int) (nanosDelta / 1000);
- int expectedMicrosDelta = (int) (expectedNanosDelta / 1000);
+ int earlyDeltaMicros = (int) ((expectedNanosDelta - nanosDelta)/ 1000);
ALOGD("%s() - STATE_RUNNING - #%d, %4d micros EARLY",
- __func__, mTimestampCount, expectedMicrosDelta - microsDelta);
+ __func__, mTimestampCount, earlyDeltaMicros);
#endif
} else if (latenessNanos > mLatenessForDriftNanos) {
// When we are on the late side, it may be because of preemption in the kernel,
@@ -242,10 +266,19 @@
}
void IsochronousClockModel::dump() const {
- ALOGD("mMarkerFramePosition = %16lld", (long long) mMarkerFramePosition);
- ALOGD("mMarkerNanoTime = %16lld", (long long) mMarkerNanoTime);
- ALOGD("mSampleRate = %8d", mSampleRate);
- ALOGD("mFramesPerBurst = %8d", mFramesPerBurst);
- ALOGD("mState = %8d", mState);
- ALOGD("max lateness nanos = %8d", mMaxMeasuredLatenessNanos);
+ ALOGD("mMarkerFramePosition = %" PRIu64, mMarkerFramePosition);
+ ALOGD("mMarkerNanoTime = %" PRIu64, mMarkerNanoTime);
+ ALOGD("mSampleRate = %6d", mSampleRate);
+ ALOGD("mFramesPerBurst = %6d", mFramesPerBurst);
+ ALOGD("mMaxMeasuredLatenessNanos = %6d", mMaxMeasuredLatenessNanos);
+ ALOGD("mState = %6d", mState);
+}
+
+void IsochronousClockModel::dumpHistogram() const {
+ if (!mHistogramMicros) return;
+ std::istringstream istr(mHistogramMicros->dump());
+ std::string line;
+ while (std::getline(istr, line)) {
+ ALOGD("lateness, %s", line.c_str());
+ }
}
diff --git a/media/libaaudio/src/client/IsochronousClockModel.h b/media/libaaudio/src/client/IsochronousClockModel.h
index a86d264..40f066b 100644
--- a/media/libaaudio/src/client/IsochronousClockModel.h
+++ b/media/libaaudio/src/client/IsochronousClockModel.h
@@ -18,6 +18,9 @@
#define ANDROID_AAUDIO_ISOCHRONOUS_CLOCK_MODEL_H
#include <stdint.h>
+
+#include <audio_utils/Histogram.h>
+
#include "utility/AudioClock.h"
namespace aaudio {
@@ -122,6 +125,8 @@
void dump() const;
+ void dumpHistogram() const;
+
private:
int32_t getLateTimeOffsetNanos() const;
@@ -140,6 +145,9 @@
// Initial small threshold for causing a drift later in time.
static constexpr int32_t kInitialLatenessForDriftNanos = 10 * 1000;
+ static constexpr int32_t kHistogramBinWidthMicros = 50;
+ static constexpr int32_t kHistogramBinCount = 128;
+
int64_t mMarkerFramePosition; // Estimated HW position.
int64_t mMarkerNanoTime; // Estimated HW time.
int32_t mSampleRate;
@@ -153,6 +161,9 @@
int32_t mTimestampCount = 0; // For logging.
+ // distribution of timestamps relative to earliest
+ std::unique_ptr<android::audio_utils::Histogram> mHistogramMicros;
+
void update();
};
diff --git a/media/libaaudio/src/utility/AAudioUtilities.cpp b/media/libaaudio/src/utility/AAudioUtilities.cpp
index 0ff6333..c2f7fd0 100644
--- a/media/libaaudio/src/utility/AAudioUtilities.cpp
+++ b/media/libaaudio/src/utility/AAudioUtilities.cpp
@@ -359,6 +359,10 @@
return AAudioProperty_getMMapOffsetMicros(__func__, AAUDIO_PROP_OUTPUT_MMAP_OFFSET_USEC);
}
+int32_t AAudioProperty_getLogMask() {
+ return property_get_int32(AAUDIO_PROP_LOG_MASK, 0);
+}
+
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 55824f7..5dcddf3 100644
--- a/media/libaaudio/src/utility/AAudioUtilities.h
+++ b/media/libaaudio/src/utility/AAudioUtilities.h
@@ -162,6 +162,20 @@
int32_t AAudioProperty_getOutputMMapOffsetMicros();
#define AAUDIO_PROP_OUTPUT_MMAP_OFFSET_USEC "aaudio.out_mmap_offset_usec"
+// These are powers of two that can be combined as a bit mask.
+// AAUDIO_LOG_CLOCK_MODEL_HISTOGRAM must be enabled before the stream is opened.
+#define AAUDIO_LOG_CLOCK_MODEL_HISTOGRAM 1
+#define AAUDIO_LOG_RESERVED_2 2
+#define AAUDIO_LOG_RESERVED_4 4
+#define AAUDIO_LOG_RESERVED_8 8
+
+/**
+ * Use a mask to enable various logs in AAudio.
+ * @return mask that enables various AAudio logs, such as AAUDIO_LOG_CLOCK_MODEL_HISTOGRAM
+ */
+int32_t AAudioProperty_getLogMask();
+#define AAUDIO_PROP_LOG_MASK "aaudio.log_mask"
+
/**
* Is flush allowed for the given state?
* @param state
diff --git a/media/libaaudio/tests/Android.bp b/media/libaaudio/tests/Android.bp
index 19cd0a0..73fd896 100644
--- a/media/libaaudio/tests/Android.bp
+++ b/media/libaaudio/tests/Android.bp
@@ -215,3 +215,14 @@
srcs: ["test_full_queue.cpp"],
shared_libs: ["libaaudio"],
}
+
+cc_test {
+ name: "test_histogram",
+ defaults: ["libaaudio_tests_defaults"],
+ srcs: ["test_histogram.cpp"],
+ shared_libs: [
+ "libaudioutils",
+ "libcutils",
+ "libutils",
+ ],
+}
diff --git a/media/libaaudio/tests/test_histogram.cpp b/media/libaaudio/tests/test_histogram.cpp
new file mode 100644
index 0000000..431373d
--- /dev/null
+++ b/media/libaaudio/tests/test_histogram.cpp
@@ -0,0 +1,89 @@
+/*
+ * Copyright 2019 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.
+ */
+
+/*
+ * Test Histogram
+ */
+
+#include <iostream>
+
+#include <gtest/gtest.h>
+
+#include <audio_utils/Histogram.h>
+
+using namespace android::audio_utils;
+
+static constexpr int32_t kBinWidth = 10;
+static constexpr int32_t kNumBins = 20;
+
+TEST(test_histogram, module_sinki16) {
+ Histogram histogram(kNumBins, kBinWidth);
+ ASSERT_EQ(kNumBins, histogram.getNumBinsInRange());
+
+ // Is it clear initially?
+ for (int i = 0; i < kNumBins; i++) {
+ ASSERT_EQ(0, histogram.getCount(i));
+ }
+ ASSERT_EQ(0, histogram.getCountBelowRange());
+ ASSERT_EQ(0, histogram.getCountAboveRange());
+ ASSERT_EQ(0, histogram.getCount());
+
+ // Add some items.
+ histogram.add(27);
+ histogram.add(53);
+ histogram.add(171);
+ histogram.add(23);
+
+ // Did they count correctly.
+ ASSERT_EQ(2, histogram.getCount(2)); // For items 27 and 23
+ ASSERT_EQ(3, histogram.getLastItemNumber(2)); // Item 23 was the 0,1,2,3th item added.
+ ASSERT_EQ(1, histogram.getCount(5)); // For item 53
+ ASSERT_EQ(1, histogram.getLastItemNumber(5)); // item 53 was the second item added.
+ ASSERT_EQ(1, histogram.getCount(17)); // For item 171
+ ASSERT_EQ(4, histogram.getCount()); // A total of four items were added.
+
+ // Add values out of range.
+ histogram.add(-5);
+ ASSERT_EQ(1, histogram.getCountBelowRange()); // -5 is below zero.
+ ASSERT_EQ(0, histogram.getCountAboveRange());
+ ASSERT_EQ(5, histogram.getCount());
+
+ histogram.add(200);
+ ASSERT_EQ(1, histogram.getCountBelowRange());
+ ASSERT_EQ(1, histogram.getCountAboveRange()); // 200 is above top bin
+ ASSERT_EQ(6, histogram.getCount());
+
+ // Try to read values out of range. Should not crash.
+ // Legal index range is 0 to numBins-1
+ histogram.add(-1);
+ histogram.add(kNumBins);
+ ASSERT_EQ(0, histogram.getCount(-1)); // edge
+ ASSERT_EQ(0, histogram.getCount(kNumBins)); // edge
+ ASSERT_EQ(0, histogram.getCount(-1234)); // extreme
+ ASSERT_EQ(0, histogram.getCount(98765)); // extreme
+ ASSERT_EQ(0, histogram.getLastItemNumber(-1));
+ ASSERT_EQ(0, histogram.getLastItemNumber(kNumBins));
+
+ // Clear all the counts.
+ histogram.clear();
+ // Is it clear?
+ for (int i = 0; i < kNumBins; i++) {
+ ASSERT_EQ(0, histogram.getCount(i));
+ }
+ ASSERT_EQ(0, histogram.getCountBelowRange());
+ ASSERT_EQ(0, histogram.getCountAboveRange());
+ ASSERT_EQ(0, histogram.getCount());
+}
diff --git a/services/oboeservice/Android.bp b/services/oboeservice/Android.bp
index 1b7a20c..ca1354d 100644
--- a/services/oboeservice/Android.bp
+++ b/services/oboeservice/Android.bp
@@ -46,6 +46,7 @@
"libaaudio_internal",
"libaudioclient",
"libaudioflinger",
+ "libaudioutils",
"libbase",
"libbinder",
"libcutils",