Spatial Audio: Generalize VectorRecorder for logging
Move from audiopolicy/service/Spatializer.h.
The VectorRecorder class can be used for head tracking and
sensor recording as well.
Test: adb shell dumpsys media.audio_policy
Bug: 269620212
Merged-In: I7f94932e135fcb5f194ed85b75e4b1234d1d2903
Change-Id: I7f94932e135fcb5f194ed85b75e4b1234d1d2903
diff --git a/services/audiopolicy/service/Spatializer.cpp b/services/audiopolicy/service/Spatializer.cpp
index 2fe7b9e..cf9543c 100644
--- a/services/audiopolicy/service/Spatializer.cpp
+++ b/services/audiopolicy/service/Spatializer.cpp
@@ -75,6 +75,16 @@
return maxMask;
}
+std::vector<float> recordFromRotationVector(const std::vector<float>& rotationVector) {
+ constexpr float RAD_TO_DEGREE = 180.f / M_PI;
+ std::vector<float> record{
+ rotationVector[0], rotationVector[1], rotationVector[2],
+ rotationVector[3] * RAD_TO_DEGREE,
+ rotationVector[4] * RAD_TO_DEGREE,
+ rotationVector[5] * RAD_TO_DEGREE};
+ return record;
+}
+
// ---------------------------------------------------------------------------
class Spatializer::EngineCallbackHandler : public AHandler {
@@ -185,41 +195,6 @@
};
// ---------------------------------------------------------------------------
-
-// Convert recorded sensor data to string with level indentation.
-std::string Spatializer::HeadToStagePoseRecorder::toString(unsigned level) const {
- std::string prefixSpace(level, ' ');
- return mPoseRecordLog.dumpToString((prefixSpace + " ").c_str(), Spatializer::mMaxLocalLogLine);
-}
-
-// Compute sensor data, record into local log when it is time.
-void Spatializer::HeadToStagePoseRecorder::record(const std::vector<float>& headToStage) {
- if (headToStage.size() != mPoseVectorSize) return;
-
- if (mNumOfSampleSinceLastRecord++ == 0) {
- mFirstSampleTimestamp = std::chrono::steady_clock::now();
- }
- // if it's time, do record and reset.
- if (shouldRecordLog()) {
- poseSumToAverage();
- mPoseRecordLog.log(
- "mean: %s, min: %s, max %s, calculated %d samples in %0.4f second(s)",
- Spatializer::toString<double>(mPoseRadianSum, true /* radianToDegree */).c_str(),
- Spatializer::toString<float>(mMinPoseAngle, true /* radianToDegree */).c_str(),
- Spatializer::toString<float>(mMaxPoseAngle, true /* radianToDegree */).c_str(),
- mNumOfSampleSinceLastRecord, mNumOfSecondsSinceLastRecord.count());
- resetRecord();
- }
- // update stream average.
- for (int i = 0; i < mPoseVectorSize; i++) {
- mPoseRadianSum[i] += headToStage[i];
- mMaxPoseAngle[i] = std::max(mMaxPoseAngle[i], headToStage[i]);
- mMinPoseAngle[i] = std::min(mMinPoseAngle[i], headToStage[i]);
- }
- return;
-}
-
-// ---------------------------------------------------------------------------
sp<Spatializer> Spatializer::create(SpatializerPolicyCallback *callback) {
sp<Spatializer> spatializer;
@@ -590,7 +565,8 @@
}
std::lock_guard lock(mLock);
if (mPoseController != nullptr) {
- mLocalLog.log("%s with screenToStage %s", __func__, toString<float>(screenToStage).c_str());
+ mLocalLog.log("%s with screenToStage %s", __func__,
+ media::VectorRecorder::toString<float>(screenToStage).c_str());
mPoseController->setScreenToStagePose(maybePose.value());
}
return Status::ok();
diff --git a/services/audiopolicy/service/Spatializer.h b/services/audiopolicy/service/Spatializer.h
index 0f6bafe..b433e1a 100644
--- a/services/audiopolicy/service/Spatializer.h
+++ b/services/audiopolicy/service/Spatializer.h
@@ -27,6 +27,7 @@
#include <audio_utils/SimpleLog.h>
#include <math.h>
#include <media/AudioEffect.h>
+#include <media/VectorRecorder.h>
#include <media/audiohal/EffectHalInterface.h>
#include <media/stagefright/foundation/ALooper.h>
#include <system/audio_effects/effect_spatializer.h>
@@ -172,30 +173,6 @@
media::audio::common::toString(*result) : "unknown_latency_mode";
}
- /**
- * Format head to stage vector to a string, [0.00, 0.00, 0.00, -1.29, -0.50, 15.27].
- */
- template <typename T>
- static std::string toString(const std::vector<T>& vec, bool radianToDegree = false) {
- if (vec.size() == 0) {
- return "[]";
- }
-
- std::string ss = "[";
- for (auto f = vec.begin(); f != vec.end(); ++f) {
- if (f != vec.begin()) {
- ss .append(", ");
- }
- if (radianToDegree) {
- base::StringAppendF(&ss, "%0.2f", HeadToStagePoseRecorder::getDegreeWithRadian(*f));
- } else {
- base::StringAppendF(&ss, "%f", *f);
- }
- }
- ss.append("]");
- return ss;
- };
-
// If the Spatializer is not created, we send the status for metrics purposes.
// OK: Spatializer not expected to be created.
// NO_INIT: Spatializer creation failed.
@@ -427,92 +404,12 @@
* @brief Calculate and record sensor data.
* Dump to local log with max/average pose angle every mPoseRecordThreshold.
*/
- class HeadToStagePoseRecorder {
- public:
- HeadToStagePoseRecorder(std::chrono::duration<double> threshold, int maxLogLine)
- : mPoseRecordThreshold(threshold), mPoseRecordLog(maxLogLine) {
- resetRecord();
- }
-
- /** Convert recorded sensor data to string with level indentation */
- std::string toString(unsigned level) const;
-
- /**
- * @brief Calculate sensor data, record into local log when it is time.
- *
- * @param headToStage The vector from Pose3f::toVector().
- */
- void record(const std::vector<float>& headToStage);
-
- static constexpr float getDegreeWithRadian(const float radian) {
- float radianToDegreeRatio = (180 / PI);
- return (radian * radianToDegreeRatio);
- }
-
- private:
- static constexpr float PI = M_PI;
- /**
- * Pose recorder time threshold to record sensor data in local log.
- * Sensor data will be recorded into log at least every mPoseRecordThreshold.
- */
- std::chrono::duration<double> mPoseRecordThreshold;
- // Number of seconds pass since last record.
- std::chrono::duration<double> mNumOfSecondsSinceLastRecord;
- /**
- * According to frameworks/av/media/libheadtracking/include/media/Pose.h
- * "The vector will have exactly 6 elements, where the first three are a translation vector
- * and the last three are a rotation vector."
- */
- static constexpr size_t mPoseVectorSize = 6;
- /**
- * Timestamp of last sensor data record in local log.
- */
- std::chrono::time_point<std::chrono::steady_clock> mFirstSampleTimestamp;
- /**
- * Number of sensor samples received since last record, sample rate is ~100Hz which produce
- * ~6k samples/minute.
- */
- uint32_t mNumOfSampleSinceLastRecord = 0;
- /* The sum of pose angle represented by radian since last dump, div
- * mNumOfSampleSinceLastRecord to get arithmetic mean. Largest possible value: 2PI * 100Hz *
- * mPoseRecordThreshold.
- */
- std::vector<double> mPoseRadianSum;
- std::vector<float> mMaxPoseAngle;
- std::vector<float> mMinPoseAngle;
- // Local log for history sensor data.
- SimpleLog mPoseRecordLog{mMaxLocalLogLine};
-
- bool shouldRecordLog() {
- mNumOfSecondsSinceLastRecord = std::chrono::duration_cast<std::chrono::seconds>(
- std::chrono::steady_clock::now() - mFirstSampleTimestamp);
- return mNumOfSecondsSinceLastRecord >= mPoseRecordThreshold;
- }
-
- void resetRecord() {
- mPoseRadianSum.assign(mPoseVectorSize, 0);
- mMaxPoseAngle.assign(mPoseVectorSize, -PI);
- mMinPoseAngle.assign(mPoseVectorSize, PI);
- mNumOfSampleSinceLastRecord = 0;
- mNumOfSecondsSinceLastRecord = std::chrono::seconds(0);
- }
-
- // Add each sample to sum and only calculate when record.
- void poseSumToAverage() {
- if (mNumOfSampleSinceLastRecord == 0) return;
- for (auto& p : mPoseRadianSum) {
- const float reciprocal = 1.f / mNumOfSampleSinceLastRecord;
- p *= reciprocal;
- }
- }
- }; // HeadToStagePoseRecorder
-
// Record one log line per second (up to mMaxLocalLogLine) to capture most recent sensor data.
- HeadToStagePoseRecorder mPoseRecorder GUARDED_BY(mLock) =
- HeadToStagePoseRecorder(std::chrono::seconds(1), mMaxLocalLogLine);
+ media::VectorRecorder mPoseRecorder GUARDED_BY(mLock) {
+ 6 /* vectorSize */, std::chrono::seconds(1), mMaxLocalLogLine };
// Record one log line per minute (up to mMaxLocalLogLine) to capture durable sensor data.
- HeadToStagePoseRecorder mPoseDurableRecorder GUARDED_BY(mLock) =
- HeadToStagePoseRecorder(std::chrono::minutes(1), mMaxLocalLogLine);
+ media::VectorRecorder mPoseDurableRecorder GUARDED_BY(mLock) {
+ 6 /* vectorSize */, std::chrono::minutes(1), mMaxLocalLogLine };
}; // Spatializer
}; // namespace android