Skip to content

Commit

Permalink
Merge main into 1.8-stable (#1962)
Browse files Browse the repository at this point in the history
  • Loading branch information
robertwu1 authored Feb 13, 2024
1 parent 987538b commit 18c9fc6
Show file tree
Hide file tree
Showing 41 changed files with 890 additions and 230 deletions.
2 changes: 2 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -45,10 +45,12 @@ set (oboe_sources
src/flowgraph/SinkI16.cpp
src/flowgraph/SinkI24.cpp
src/flowgraph/SinkI32.cpp
src/flowgraph/SinkI8_24.cpp
src/flowgraph/SourceFloat.cpp
src/flowgraph/SourceI16.cpp
src/flowgraph/SourceI24.cpp
src/flowgraph/SourceI32.cpp
src/flowgraph/SourceI8_24.cpp
src/flowgraph/resampler/IntegerRatio.cpp
src/flowgraph/resampler/LinearResampler.cpp
src/flowgraph/resampler/MultiChannelResampler.cpp
Expand Down
4 changes: 2 additions & 2 deletions apps/OboeTester/app/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,8 @@ android {
applicationId = "com.mobileer.oboetester"
minSdkVersion 23
targetSdkVersion 34
versionCode 78
versionName "2.5.7"
versionCode 81
versionName "2.5.10"
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
externalNativeBuild {
cmake {
Expand Down
2 changes: 1 addition & 1 deletion apps/OboeTester/app/src/main/cpp/FullDuplexAnalyzer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ oboe::DataCallbackResult FullDuplexAnalyzer::onBothStreamsReadyFloat(
inputFloat += inputStride;
mRecording->write(buffer, 1);
}
// Handle mismatch in in numFrames.
// Handle mismatch in numFrames.
buffer[0] = 0.0f; // gap in output
for (int i = numBoth; i < numInputFrames; i++) {
buffer[1] = *inputFloat;
Expand Down
3 changes: 2 additions & 1 deletion apps/OboeTester/app/src/main/cpp/InterpolatingDelayLine.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,8 @@
* limitations under the License.
*/

#include "common/OboeDebug.h"
#include <algorithm>

#include "InterpolatingDelayLine.h"

InterpolatingDelayLine::InterpolatingDelayLine(int32_t delaySize) {
Expand Down
2 changes: 0 additions & 2 deletions apps/OboeTester/app/src/main/cpp/InterpolatingDelayLine.h
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,6 @@
#include <unistd.h>
#include <sys/types.h>

#include "oboe/Oboe.h"

/**
* Monophonic delay line.
*/
Expand Down
4 changes: 2 additions & 2 deletions apps/OboeTester/app/src/main/cpp/analyzer/BaseSineAnalyzer.h
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,6 @@ class BaseSineAnalyzer : public LoopbackProcessor {
: LoopbackProcessor()
, mInfiniteRecording(64 * 1024) {}


virtual bool isOutputEnabled() { return true; }

void setMagnitude(double magnitude) {
Expand Down Expand Up @@ -185,7 +184,8 @@ class BaseSineAnalyzer : public LoopbackProcessor {
}

protected:
static constexpr int32_t kTargetGlitchFrequency = 1000;
// Try to get a prime period so the waveform plot changes every time.
static constexpr int32_t kTargetGlitchFrequency = 48000 / 113;

int32_t mSinePeriod = 1; // this will be set before use
double mInverseSinePeriod = 1.0;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ class DataPathAnalyzer : public BaseSineAnalyzer {

if (transformSample(sample, mOutputPhase)) {
// Analyze magnitude and phase on every period.
double diff = abs(calculatePhaseError(mPhaseOffset, mPreviousPhaseOffset));
double diff = fabs(calculatePhaseError(mPhaseOffset, mPreviousPhaseOffset));
if (diff < mPhaseTolerance) {
mMaxMagnitude = std::max(mMagnitude, mMaxMagnitude);
}
Expand Down
135 changes: 98 additions & 37 deletions apps/OboeTester/app/src/main/cpp/analyzer/GlitchAnalyzer.h
Original file line number Diff line number Diff line change
Expand Up @@ -50,10 +50,22 @@ class GlitchAnalyzer : public BaseSineAnalyzer {
return mMagnitude;
}

int getSinePeriod() const {
return mSinePeriod;
}

float getPhaseOffset() const {
return mPhaseOffset;
}

int32_t getGlitchCount() const {
return mGlitchCount;
}

int32_t getGlitchLength() const {
return mGlitchLength;
}

int32_t getStateFrameCount(int state) const {
return mStateFrameCounters[state];
}
Expand Down Expand Up @@ -124,21 +136,22 @@ class GlitchAnalyzer : public BaseSineAnalyzer {
result_code result = RESULT_OK;

float sample = frameData[getInputChannel()];
float peak = mPeakFollower.process(sample);
mInfiniteRecording.write(sample);

// Force a periodic glitch to test the detector!
if (mForceGlitchDuration > 0) {
if (mForceGlitchDurationFrames > 0) {
if (mForceGlitchCounter == 0) {
ALOGE("%s: force a glitch!!", __func__);
mForceGlitchCounter = getSampleRate();
} else if (mForceGlitchCounter <= mForceGlitchDuration) {
ALOGE("%s: finish a glitch!!", __func__);
mForceGlitchCounter = kForceGlitchPeriod;
} else if (mForceGlitchCounter <= mForceGlitchDurationFrames) {
// Force an abrupt offset.
sample += (sample > 0.0) ? -0.5f : 0.5f;
sample += (sample > 0.0) ? -kForceGlitchOffset : kForceGlitchOffset;
}
--mForceGlitchCounter;
}

float peak = mPeakFollower.process(sample);
mInfiniteRecording.write(sample);

mStateFrameCounters[mState]++; // count how many frames we are in each state

switch (mState) {
Expand Down Expand Up @@ -178,8 +191,9 @@ class GlitchAnalyzer : public BaseSineAnalyzer {
// ALOGD("%s() mag = %f, offset = %f, prev = %f",
// __func__, mMagnitude, mPhaseOffset, mPreviousPhaseOffset);
if (mMagnitude > mThreshold) {
if (abs(mPhaseOffset) < kMaxPhaseError) {
if (fabs(mPhaseOffset) < kMaxPhaseError) {
mState = STATE_LOCKED;
mConsecutiveBadFrames = 0;
// ALOGD("%5d: switch to STATE_LOCKED", mFrameCounter);
}
// Adjust mInputPhase to match measured phase
Expand All @@ -196,24 +210,36 @@ class GlitchAnalyzer : public BaseSineAnalyzer {
double diff = predicted - sample;
double absDiff = fabs(diff);
mMaxGlitchDelta = std::max(mMaxGlitchDelta, absDiff);
if (absDiff > mScaledTolerance) {
result = ERROR_GLITCHES;
onGlitchStart();
// LOGI("diff glitch detected, absDiff = %g", absDiff);
} else {
if (absDiff > mScaledTolerance) { // bad frame
mConsecutiveBadFrames++;
mConsecutiveGoodFrames = 0;
LOGI("diff glitch frame #%d detected, absDiff = %g > %g",
mConsecutiveBadFrames, absDiff, mScaledTolerance);
if (mConsecutiveBadFrames > 0) {
result = ERROR_GLITCHES;
onGlitchStart();
}
resetAccumulator();
} else { // good frame
mConsecutiveBadFrames = 0;
mConsecutiveGoodFrames++;

mSumSquareSignal += predicted * predicted;
mSumSquareNoise += diff * diff;

// Track incoming signal and slowly adjust magnitude to account
// for drift in the DRC or AGC.
// Must be a multiple of the period or the calculation will not be accurate.
if (transformSample(sample, mInputPhase)) {
// Adjust phase to account for sample rate drift.
mInputPhase += mPhaseOffset;

mMeanSquareNoise = mSumSquareNoise * mInverseSinePeriod;
mMeanSquareSignal = mSumSquareSignal * mInverseSinePeriod;
mSumSquareNoise = 0.0;
mSumSquareSignal = 0.0;

if (abs(mPhaseOffset) > kMaxPhaseError) {
if (fabs(mPhaseOffset) > kMaxPhaseError) {
result = ERROR_GLITCHES;
onGlitchStart();
ALOGD("phase glitch detected, phaseOffset = %g", mPhaseOffset);
Expand All @@ -229,22 +255,25 @@ class GlitchAnalyzer : public BaseSineAnalyzer {

case STATE_GLITCHING: {
// Predict next sine value
mGlitchLength++;
double predicted = sinf(mInputPhase) * mMagnitude;
double diff = predicted - sample;
double absDiff = fabs(diff);
mMaxGlitchDelta = std::max(mMaxGlitchDelta, absDiff);
if (absDiff < mScaledTolerance) { // close enough?
// If we get a full sine period of non-glitch samples in a row then consider the glitch over.
if (absDiff > mScaledTolerance) { // bad frame
mConsecutiveBadFrames++;
mConsecutiveGoodFrames = 0;
mGlitchLength++;
if (mGlitchLength > maxMeasurableGlitchLength()) {
onGlitchTerminated();
}
} else { // good frame
mConsecutiveBadFrames = 0;
mConsecutiveGoodFrames++;
// If we get a full sine period of good samples in a row then consider the glitch over.
// We don't want to just consider a zero crossing the end of a glitch.
if (mNonGlitchCount++ > mSinePeriod) {
if (mConsecutiveGoodFrames > mSinePeriod) {
onGlitchEnd();
}
} else {
mNonGlitchCount = 0;
if (mGlitchLength > (4 * mSinePeriod)) {
relock();
}
}
incrementInputPhase();
} break;
Expand All @@ -258,6 +287,8 @@ class GlitchAnalyzer : public BaseSineAnalyzer {
return result;
}

int maxMeasurableGlitchLength() const { return 2 * mSinePeriod; }

// advance and wrap phase
void incrementInputPhase() {
mInputPhase += mPhaseIncrement;
Expand All @@ -269,16 +300,29 @@ class GlitchAnalyzer : public BaseSineAnalyzer {
bool isOutputEnabled() override { return mState != STATE_IDLE; }

void onGlitchStart() {
mGlitchCount++;
// ALOGD("%5d: STARTED a glitch # %d", mFrameCounter, mGlitchCount);
mState = STATE_GLITCHING;
mGlitchLength = 1;
mNonGlitchCount = 0;
mLastGlitchPosition = mInfiniteRecording.getTotalWritten();
ALOGD("%5d: STARTED a glitch # %d, pos = %5d",
mFrameCounter, mGlitchCount, (int)mLastGlitchPosition);
ALOGD("glitch mSinePeriod = %d", mSinePeriod);
}

/**
* Give up waiting for a glitch to end and try to resync.
*/
void onGlitchTerminated() {
mGlitchCount++;
ALOGD("%5d: TERMINATED a glitch # %d, length = %d", mFrameCounter, mGlitchCount, mGlitchLength);
// We don't know how long the glitch really is so set the length to -1.
mGlitchLength = -1;
mState = STATE_WAITING_FOR_LOCK;
resetAccumulator();
}

void onGlitchEnd() {
// ALOGD("%5d: ENDED a glitch # %d, length = %d", mFrameCounter, mGlitchCount, mGlitchLength);
mGlitchCount++;
ALOGD("%5d: ENDED a glitch # %d, length = %d", mFrameCounter, mGlitchCount, mGlitchLength);
mState = STATE_LOCKED;
resetAccumulator();
}
Expand All @@ -288,12 +332,6 @@ class GlitchAnalyzer : public BaseSineAnalyzer {
BaseSineAnalyzer::resetAccumulator();
}

void relock() {
// ALOGD("relock: %d because of a very long %d glitch", mFrameCounter, mGlitchLength);
mState = STATE_WAITING_FOR_LOCK;
resetAccumulator();
}

void reset() override {
BaseSineAnalyzer::reset();
mState = STATE_IDLE;
Expand All @@ -303,14 +341,34 @@ class GlitchAnalyzer : public BaseSineAnalyzer {
void prepareToTest() override {
BaseSineAnalyzer::prepareToTest();
mGlitchCount = 0;
mGlitchLength = 0;
mMaxGlitchDelta = 0.0;
for (int i = 0; i < NUM_STATES; i++) {
mStateFrameCounters[i] = 0;
}
}

int32_t getLastGlitch(float *buffer, int32_t length) {
return mInfiniteRecording.readFrom(buffer, mLastGlitchPosition - 32, length);
const int margin = mSinePeriod;
int32_t numSamples = mInfiniteRecording.readFrom(buffer,
mLastGlitchPosition - margin,
length);
ALOGD("%s: glitch at %d, edge = %7.4f, %7.4f, %7.4f",
__func__, (int)mLastGlitchPosition,
buffer[margin - 1], buffer[margin], buffer[margin+1]);
return numSamples;
}

int32_t getRecentSamples(float *buffer, int32_t length) {
int firstSample = mInfiniteRecording.getTotalWritten() - length;
int32_t numSamples = mInfiniteRecording.readFrom(buffer,
firstSample,
length);
return numSamples;
}

void setForcedGlitchDuration(int frames) {
mForceGlitchDurationFrames = frames;
}

private:
Expand Down Expand Up @@ -345,13 +403,16 @@ class GlitchAnalyzer : public BaseSineAnalyzer {
double mInputPhase = 0.0;
double mMaxGlitchDelta = 0.0;
int32_t mGlitchCount = 0;
int32_t mNonGlitchCount = 0;
int32_t mConsecutiveBadFrames = 0;
int32_t mConsecutiveGoodFrames = 0;
int32_t mGlitchLength = 0;
int mDownCounter = IDLE_FRAME_COUNT;
int32_t mFrameCounter = 0;

int32_t mForceGlitchDuration = 0; // if > 0 then force a glitch for debugging
int32_t mForceGlitchCounter = 4 * 48000; // count down and trigger at zero
int32_t mForceGlitchDurationFrames = 0; // if > 0 then force a glitch for debugging
static constexpr int32_t kForceGlitchPeriod = 2 * 48000; // How often we glitch
static constexpr float kForceGlitchOffset = 0.20f;
int32_t mForceGlitchCounter = kForceGlitchPeriod; // count down and trigger at zero

// measure background noise continuously as a deviation from the expected signal
double mSumSquareSignal = 0.0;
Expand Down
5 changes: 3 additions & 2 deletions apps/OboeTester/app/src/main/cpp/analyzer/InfiniteRecording.h
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ class InfiniteRecording {
int32_t readFrom(T *buffer, size_t position, size_t count) {
const size_t maxPosition = mWritten.load();
position = std::min(position, maxPosition);

size_t numToRead = std::min(count, mMaxSamples);
numToRead = std::min(numToRead, maxPosition - position);
if (numToRead == 0) return 0;
Expand Down Expand Up @@ -61,7 +62,7 @@ class InfiniteRecording {

private:
std::unique_ptr<T[]> mData;
std::atomic<size_t> mWritten{0};
const size_t mMaxSamples;
std::atomic<size_t> mWritten{0};
const size_t mMaxSamples;
};
#endif //OBOETESTER_INFINITE_RECORDING_H
Loading

0 comments on commit 18c9fc6

Please sign in to comment.