Loading media/libheadtracking/VectorRecorder.cpp +4 −4 Original line number Diff line number Diff line Loading @@ -21,7 +21,7 @@ namespace android::media { // Convert data to string with level indentation. // No need for a lock as the SimpleLog is thread-safe. std::string VectorRecorder::toString(size_t indent) const { return mRecordLog.dumpToString(std::string(indent + 1, ' ').c_str(), mMaxLocalLogLine); return mRecordLog.dumpToString(std::string(indent, ' ').c_str(), mMaxLocalLogLine); } // Record into local log when it is time. Loading @@ -36,9 +36,9 @@ void VectorRecorder::record(const std::vector<float>& record) { sumToAverage_l(); mRecordLog.log( "mean: %s, min: %s, max %s, calculated %zu samples in %0.4f second(s)", toString(mSum).c_str(), toString(mMin).c_str(), toString(mMax).c_str(), toString(mSum, mDelimiterIdx, mFormatString.c_str()).c_str(), toString(mMin, mDelimiterIdx, mFormatString.c_str()).c_str(), toString(mMax, mDelimiterIdx, mFormatString.c_str()).c_str(), mNumberOfSamples, mNumberOfSecondsSinceFirstSample.count()); resetRecord_l(); Loading media/libheadtracking/include/media/VectorRecorder.h +41 −4 Original line number Diff line number Diff line Loading @@ -34,9 +34,25 @@ namespace android::media { */ class VectorRecorder { public: /** * @param vectorSize is the size of the vector input. * If the input does not match this size, it is ignored. * @param threshold is the time interval we bucket for averaging. * @param maxLogLine is the number of lines we log. At this * threshold, the oldest line will expire when the new line comes in. * @param delimiterIdx is an optional array of delimiter indices that * replace the ',' with a ':'. For example if delimiterIdx = { 3 } then * the above example would format as [0.00, 0.00, 0.00 : -1.29, -0.50, 15.27]. * @param formatString is the sprintf format string for the double converted data * to use. */ VectorRecorder( size_t vectorSize, std::chrono::duration<double> threshold, int maxLogLine) size_t vectorSize, std::chrono::duration<double> threshold, int maxLogLine, std::vector<size_t> delimiterIdx = {}, const std::string_view formatString = {}) : mVectorSize(vectorSize) , mDelimiterIdx(std::move(delimiterIdx)) , mFormatString(formatString) , mRecordLog(maxLogLine) , mRecordThreshold(threshold) { Loading @@ -55,19 +71,38 @@ class VectorRecorder { /** * Format vector to a string, [0.00, 0.00, 0.00, -1.29, -0.50, 15.27]. * * @param delimiterIdx is an optional array of delimiter indices that * replace the ',' with a ':'. For example if delimiterIdx = { 3 } then * the above example would format as [0.00, 0.00, 0.00 : -1.29, -0.50, 15.27]. * @param formatString is the sprintf format string for the double converted data * to use. */ template <typename T> static std::string toString(const std::vector<T>& record) { static std::string toString(const std::vector<T>& record, const std::vector<size_t>& delimiterIdx = {}, const char * const formatString = nullptr) { if (record.size() == 0) { return "[]"; } std::string ss = "["; auto nextDelimiter = delimiterIdx.begin(); for (size_t i = 0; i < record.size(); ++i) { if (i > 0) { if (nextDelimiter != delimiterIdx.end() && *nextDelimiter <= i) { ss.append(" : "); ++nextDelimiter; } else { ss.append(", "); } base::StringAppendF(&ss, "%0.2lf", static_cast<double>(record[i])); } if (formatString != nullptr && *formatString) { base::StringAppendF(&ss, formatString, static_cast<double>(record[i])); } else { base::StringAppendF(&ss, "%5.2lf", static_cast<double>(record[i])); } } ss.append("]"); return ss; Loading @@ -77,6 +112,8 @@ class VectorRecorder { static constexpr int mMaxLocalLogLine = 10; const size_t mVectorSize; const std::vector<size_t> mDelimiterIdx; const std::string mFormatString; // Local log for historical vector data. // Locked internally, so does not need mutex below. Loading services/audiopolicy/service/Spatializer.cpp +3 −3 Original line number Diff line number Diff line Loading @@ -1092,13 +1092,13 @@ std::string Spatializer::toString(unsigned level) const { if (mPoseController != nullptr) { ss.append(mPoseController->toString(level + 1)) .append(prefixSpace) .append("Pose (active stage-to-head) [tx, ty, tz, pitch, roll, yaw]:\n") .append("Pose (active stage-to-head) [tx, ty, tz : pitch, roll, yaw]:\n") .append(prefixSpace) .append(" PerMinuteHistory:\n") .append(mPoseDurableRecorder.toString(level + 2)) .append(mPoseDurableRecorder.toString(level + 3)) .append(prefixSpace) .append(" PerSecondHistory:\n") .append(mPoseRecorder.toString(level + 2)); .append(mPoseRecorder.toString(level + 3)); } else { ss.append(prefixSpace).append("SpatializerPoseController not exist\n"); } Loading services/audiopolicy/service/Spatializer.h +2 −2 Original line number Diff line number Diff line Loading @@ -404,10 +404,10 @@ private: */ // Record one log line per second (up to mMaxLocalLogLine) to capture most recent sensor data. media::VectorRecorder mPoseRecorder GUARDED_BY(mLock) { 6 /* vectorSize */, std::chrono::seconds(1), mMaxLocalLogLine }; 6 /* vectorSize */, std::chrono::seconds(1), mMaxLocalLogLine, { 3 } /* delimiterIdx */}; // Record one log line per minute (up to mMaxLocalLogLine) to capture durable sensor data. media::VectorRecorder mPoseDurableRecorder GUARDED_BY(mLock) { 6 /* vectorSize */, std::chrono::minutes(1), mMaxLocalLogLine }; 6 /* vectorSize */, std::chrono::minutes(1), mMaxLocalLogLine, { 3 } /* delimiterIdx */}; }; // Spatializer }; // namespace android Loading services/audiopolicy/service/SpatializerPoseController.cpp +27 −19 Original line number Diff line number Diff line Loading @@ -290,22 +290,29 @@ void SpatializerPoseController::onPose(int64_t timestamp, int32_t sensor, const const float delayMs = (elapsedRealtimeNano() - timestamp) * NANOS_TO_MILLIS; // CLOCK_BOOTTIME if (sensor == mHeadSensor) { std::vector<float> pryxyzdt(8); // pitch, roll, yaw, rot_vel_x, rot_vel_y, rot_vel_z, std::vector<float> pryprydt(8); // pitch, roll, yaw, d_pitch, d_roll, d_yaw, // discontinuity, timestamp_delay media::quaternionToAngles(pose.rotation(), &pryxyzdt[0], &pryxyzdt[1], &pryxyzdt[2]); media::quaternionToAngles(pose.rotation(), &pryprydt[0], &pryprydt[1], &pryprydt[2]); if (twist) { const auto rotationalVelocity = twist->rotationalVelocity(); for (size_t i = 0; i < 3; ++i) { pryxyzdt[i + 3] = rotationalVelocity[i]; } } pryxyzdt[6] = isNewReference; pryxyzdt[7] = delayMs; for (size_t i = 0; i < 3; ++i) { // pitch, roll, yaw only. rotational velocity in rad/s. pryxyzdt[i] *= RAD_TO_DEGREE; } mHeadSensorRecorder.record(pryxyzdt); mHeadSensorDurableRecorder.record(pryxyzdt); // The rotational velocity is an intrinsic transform (i.e. based on the head // coordinate system, not the world coordinate system). It is a 3 element vector: // axis (d theta / dt). // // We leave rotational velocity relative to the head coordinate system, // as the initial head tracking sensor's world frame is arbitrary. media::quaternionToAngles(media::rotationVectorToQuaternion(rotationalVelocity), &pryprydt[3], &pryprydt[4], &pryprydt[5]); } pryprydt[6] = isNewReference; pryprydt[7] = delayMs; for (size_t i = 0; i < 6; ++i) { // pitch, roll, yaw in degrees, referenced in degrees on the world frame. // d_pitch, d_roll, d_yaw rotational velocity in degrees/s, based on the world frame. pryprydt[i] *= RAD_TO_DEGREE; } mHeadSensorRecorder.record(pryprydt); mHeadSensorDurableRecorder.record(pryprydt); mProcessor->setWorldToHeadPose(timestamp, pose, twist.value_or(Twist3f()) / kTicksPerSecond); Loading Loading @@ -346,15 +353,16 @@ std::string SpatializerPoseController::toString(unsigned level) const { if (mHeadSensor == INVALID_SENSOR) { ss += "HeadSensor: INVALID\n"; } else { base::StringAppendF(&ss, "HeadSensor: 0x%08x (active world-to-head) " "[ pitch, roll, yaw, vx, vy, vz, disc, delay ] " "(degrees, rad/s, bool, ms)\n", mHeadSensor); base::StringAppendF(&ss, "HeadSensor: 0x%08x " "(active world-to-head : head-relative velocity) " "[ pitch, roll, yaw : d_pitch, d_roll, d_yaw : disc : delay ] " "(degrees, degrees/s, bool, ms)\n", mHeadSensor); ss.append(prefixSpace) .append(" PerMinuteHistory:\n") .append(mHeadSensorDurableRecorder.toString(level + 2)) .append(mHeadSensorDurableRecorder.toString(level + 3)) .append(prefixSpace) .append(" PerSecondHistory:\n") .append(mHeadSensorRecorder.toString(level + 2)); .append(mHeadSensorRecorder.toString(level + 3)); } ss += prefixSpace; Loading @@ -362,14 +370,14 @@ std::string SpatializerPoseController::toString(unsigned level) const { ss += "ScreenSensor: INVALID\n"; } else { base::StringAppendF(&ss, "ScreenSensor: 0x%08x (active world-to-screen) " "[ pitch, roll, yaw, delay ] " "[ pitch, roll, yaw : delay ] " "(degrees, ms)\n", mScreenSensor); ss.append(prefixSpace) .append(" PerMinuteHistory:\n") .append(mScreenSensorDurableRecorder.toString(level + 2)) .append(mScreenSensorDurableRecorder.toString(level + 3)) .append(prefixSpace) .append(" PerSecondHistory:\n") .append(mScreenSensorRecorder.toString(level + 2)); .append(mScreenSensorRecorder.toString(level + 3)); } ss += prefixSpace; Loading Loading
media/libheadtracking/VectorRecorder.cpp +4 −4 Original line number Diff line number Diff line Loading @@ -21,7 +21,7 @@ namespace android::media { // Convert data to string with level indentation. // No need for a lock as the SimpleLog is thread-safe. std::string VectorRecorder::toString(size_t indent) const { return mRecordLog.dumpToString(std::string(indent + 1, ' ').c_str(), mMaxLocalLogLine); return mRecordLog.dumpToString(std::string(indent, ' ').c_str(), mMaxLocalLogLine); } // Record into local log when it is time. Loading @@ -36,9 +36,9 @@ void VectorRecorder::record(const std::vector<float>& record) { sumToAverage_l(); mRecordLog.log( "mean: %s, min: %s, max %s, calculated %zu samples in %0.4f second(s)", toString(mSum).c_str(), toString(mMin).c_str(), toString(mMax).c_str(), toString(mSum, mDelimiterIdx, mFormatString.c_str()).c_str(), toString(mMin, mDelimiterIdx, mFormatString.c_str()).c_str(), toString(mMax, mDelimiterIdx, mFormatString.c_str()).c_str(), mNumberOfSamples, mNumberOfSecondsSinceFirstSample.count()); resetRecord_l(); Loading
media/libheadtracking/include/media/VectorRecorder.h +41 −4 Original line number Diff line number Diff line Loading @@ -34,9 +34,25 @@ namespace android::media { */ class VectorRecorder { public: /** * @param vectorSize is the size of the vector input. * If the input does not match this size, it is ignored. * @param threshold is the time interval we bucket for averaging. * @param maxLogLine is the number of lines we log. At this * threshold, the oldest line will expire when the new line comes in. * @param delimiterIdx is an optional array of delimiter indices that * replace the ',' with a ':'. For example if delimiterIdx = { 3 } then * the above example would format as [0.00, 0.00, 0.00 : -1.29, -0.50, 15.27]. * @param formatString is the sprintf format string for the double converted data * to use. */ VectorRecorder( size_t vectorSize, std::chrono::duration<double> threshold, int maxLogLine) size_t vectorSize, std::chrono::duration<double> threshold, int maxLogLine, std::vector<size_t> delimiterIdx = {}, const std::string_view formatString = {}) : mVectorSize(vectorSize) , mDelimiterIdx(std::move(delimiterIdx)) , mFormatString(formatString) , mRecordLog(maxLogLine) , mRecordThreshold(threshold) { Loading @@ -55,19 +71,38 @@ class VectorRecorder { /** * Format vector to a string, [0.00, 0.00, 0.00, -1.29, -0.50, 15.27]. * * @param delimiterIdx is an optional array of delimiter indices that * replace the ',' with a ':'. For example if delimiterIdx = { 3 } then * the above example would format as [0.00, 0.00, 0.00 : -1.29, -0.50, 15.27]. * @param formatString is the sprintf format string for the double converted data * to use. */ template <typename T> static std::string toString(const std::vector<T>& record) { static std::string toString(const std::vector<T>& record, const std::vector<size_t>& delimiterIdx = {}, const char * const formatString = nullptr) { if (record.size() == 0) { return "[]"; } std::string ss = "["; auto nextDelimiter = delimiterIdx.begin(); for (size_t i = 0; i < record.size(); ++i) { if (i > 0) { if (nextDelimiter != delimiterIdx.end() && *nextDelimiter <= i) { ss.append(" : "); ++nextDelimiter; } else { ss.append(", "); } base::StringAppendF(&ss, "%0.2lf", static_cast<double>(record[i])); } if (formatString != nullptr && *formatString) { base::StringAppendF(&ss, formatString, static_cast<double>(record[i])); } else { base::StringAppendF(&ss, "%5.2lf", static_cast<double>(record[i])); } } ss.append("]"); return ss; Loading @@ -77,6 +112,8 @@ class VectorRecorder { static constexpr int mMaxLocalLogLine = 10; const size_t mVectorSize; const std::vector<size_t> mDelimiterIdx; const std::string mFormatString; // Local log for historical vector data. // Locked internally, so does not need mutex below. Loading
services/audiopolicy/service/Spatializer.cpp +3 −3 Original line number Diff line number Diff line Loading @@ -1092,13 +1092,13 @@ std::string Spatializer::toString(unsigned level) const { if (mPoseController != nullptr) { ss.append(mPoseController->toString(level + 1)) .append(prefixSpace) .append("Pose (active stage-to-head) [tx, ty, tz, pitch, roll, yaw]:\n") .append("Pose (active stage-to-head) [tx, ty, tz : pitch, roll, yaw]:\n") .append(prefixSpace) .append(" PerMinuteHistory:\n") .append(mPoseDurableRecorder.toString(level + 2)) .append(mPoseDurableRecorder.toString(level + 3)) .append(prefixSpace) .append(" PerSecondHistory:\n") .append(mPoseRecorder.toString(level + 2)); .append(mPoseRecorder.toString(level + 3)); } else { ss.append(prefixSpace).append("SpatializerPoseController not exist\n"); } Loading
services/audiopolicy/service/Spatializer.h +2 −2 Original line number Diff line number Diff line Loading @@ -404,10 +404,10 @@ private: */ // Record one log line per second (up to mMaxLocalLogLine) to capture most recent sensor data. media::VectorRecorder mPoseRecorder GUARDED_BY(mLock) { 6 /* vectorSize */, std::chrono::seconds(1), mMaxLocalLogLine }; 6 /* vectorSize */, std::chrono::seconds(1), mMaxLocalLogLine, { 3 } /* delimiterIdx */}; // Record one log line per minute (up to mMaxLocalLogLine) to capture durable sensor data. media::VectorRecorder mPoseDurableRecorder GUARDED_BY(mLock) { 6 /* vectorSize */, std::chrono::minutes(1), mMaxLocalLogLine }; 6 /* vectorSize */, std::chrono::minutes(1), mMaxLocalLogLine, { 3 } /* delimiterIdx */}; }; // Spatializer }; // namespace android Loading
services/audiopolicy/service/SpatializerPoseController.cpp +27 −19 Original line number Diff line number Diff line Loading @@ -290,22 +290,29 @@ void SpatializerPoseController::onPose(int64_t timestamp, int32_t sensor, const const float delayMs = (elapsedRealtimeNano() - timestamp) * NANOS_TO_MILLIS; // CLOCK_BOOTTIME if (sensor == mHeadSensor) { std::vector<float> pryxyzdt(8); // pitch, roll, yaw, rot_vel_x, rot_vel_y, rot_vel_z, std::vector<float> pryprydt(8); // pitch, roll, yaw, d_pitch, d_roll, d_yaw, // discontinuity, timestamp_delay media::quaternionToAngles(pose.rotation(), &pryxyzdt[0], &pryxyzdt[1], &pryxyzdt[2]); media::quaternionToAngles(pose.rotation(), &pryprydt[0], &pryprydt[1], &pryprydt[2]); if (twist) { const auto rotationalVelocity = twist->rotationalVelocity(); for (size_t i = 0; i < 3; ++i) { pryxyzdt[i + 3] = rotationalVelocity[i]; } } pryxyzdt[6] = isNewReference; pryxyzdt[7] = delayMs; for (size_t i = 0; i < 3; ++i) { // pitch, roll, yaw only. rotational velocity in rad/s. pryxyzdt[i] *= RAD_TO_DEGREE; } mHeadSensorRecorder.record(pryxyzdt); mHeadSensorDurableRecorder.record(pryxyzdt); // The rotational velocity is an intrinsic transform (i.e. based on the head // coordinate system, not the world coordinate system). It is a 3 element vector: // axis (d theta / dt). // // We leave rotational velocity relative to the head coordinate system, // as the initial head tracking sensor's world frame is arbitrary. media::quaternionToAngles(media::rotationVectorToQuaternion(rotationalVelocity), &pryprydt[3], &pryprydt[4], &pryprydt[5]); } pryprydt[6] = isNewReference; pryprydt[7] = delayMs; for (size_t i = 0; i < 6; ++i) { // pitch, roll, yaw in degrees, referenced in degrees on the world frame. // d_pitch, d_roll, d_yaw rotational velocity in degrees/s, based on the world frame. pryprydt[i] *= RAD_TO_DEGREE; } mHeadSensorRecorder.record(pryprydt); mHeadSensorDurableRecorder.record(pryprydt); mProcessor->setWorldToHeadPose(timestamp, pose, twist.value_or(Twist3f()) / kTicksPerSecond); Loading Loading @@ -346,15 +353,16 @@ std::string SpatializerPoseController::toString(unsigned level) const { if (mHeadSensor == INVALID_SENSOR) { ss += "HeadSensor: INVALID\n"; } else { base::StringAppendF(&ss, "HeadSensor: 0x%08x (active world-to-head) " "[ pitch, roll, yaw, vx, vy, vz, disc, delay ] " "(degrees, rad/s, bool, ms)\n", mHeadSensor); base::StringAppendF(&ss, "HeadSensor: 0x%08x " "(active world-to-head : head-relative velocity) " "[ pitch, roll, yaw : d_pitch, d_roll, d_yaw : disc : delay ] " "(degrees, degrees/s, bool, ms)\n", mHeadSensor); ss.append(prefixSpace) .append(" PerMinuteHistory:\n") .append(mHeadSensorDurableRecorder.toString(level + 2)) .append(mHeadSensorDurableRecorder.toString(level + 3)) .append(prefixSpace) .append(" PerSecondHistory:\n") .append(mHeadSensorRecorder.toString(level + 2)); .append(mHeadSensorRecorder.toString(level + 3)); } ss += prefixSpace; Loading @@ -362,14 +370,14 @@ std::string SpatializerPoseController::toString(unsigned level) const { ss += "ScreenSensor: INVALID\n"; } else { base::StringAppendF(&ss, "ScreenSensor: 0x%08x (active world-to-screen) " "[ pitch, roll, yaw, delay ] " "[ pitch, roll, yaw : delay ] " "(degrees, ms)\n", mScreenSensor); ss.append(prefixSpace) .append(" PerMinuteHistory:\n") .append(mScreenSensorDurableRecorder.toString(level + 2)) .append(mScreenSensorDurableRecorder.toString(level + 3)) .append(prefixSpace) .append(" PerSecondHistory:\n") .append(mScreenSensorRecorder.toString(level + 2)); .append(mScreenSensorRecorder.toString(level + 3)); } ss += prefixSpace; Loading