aaudio test: use OboeTester analyzer

Use latency and glitch analyzer code from /external/oboe
instead of a copy. We can make a similar change on CTS Verifier.

Bug: 129788315
Test: adb shell aaudio_loopback -pl -Pl -x -X -tl
Test: adb shell aaudio_loopback -pl -Pl -x -X -tg
Change-Id: I3990b29d93eccc7c669be0b97faa1b48630d39de
diff --git a/media/libaaudio/examples/loopback/Android.bp b/media/libaaudio/examples/loopback/Android.bp
index 5b7d956..4de632f 100644
--- a/media/libaaudio/examples/loopback/Android.bp
+++ b/media/libaaudio/examples/loopback/Android.bp
@@ -4,9 +4,11 @@
     srcs: ["src/loopback.cpp"],
     cflags: ["-Wall", "-Werror"],
     static_libs: ["libsndfile"],
+    include_dirs: ["external/oboe/apps/OboeTester/app/src/main/cpp"],
     shared_libs: [
         "libaaudio",
         "libaudioutils",
+        "liblog"
         ],
     header_libs: ["libaaudio_example_utils"],
 }
diff --git a/media/libaaudio/examples/loopback/src/analyzer/GlitchAnalyzer.h b/media/libaaudio/examples/loopback/src/analyzer/GlitchAnalyzer.h
deleted file mode 100644
index 04435d1..0000000
--- a/media/libaaudio/examples/loopback/src/analyzer/GlitchAnalyzer.h
+++ /dev/null
@@ -1,445 +0,0 @@
-/*
- * Copyright (C) 2017 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.
- */
-
-#ifndef ANALYZER_GLITCH_ANALYZER_H
-#define ANALYZER_GLITCH_ANALYZER_H
-
-#include <algorithm>
-#include <cctype>
-#include <iomanip>
-#include <iostream>
-
-#include "LatencyAnalyzer.h"
-#include "PseudoRandom.h"
-
-/**
- * Output a steady sine wave and analyze the return signal.
- *
- * Use a cosine transform to measure the predicted magnitude and relative phase of the
- * looped back sine wave. Then generate a predicted signal and compare with the actual signal.
- */
-class GlitchAnalyzer : public LoopbackProcessor {
-public:
-
-    int32_t getState() const {
-        return mState;
-    }
-
-    double getPeakAmplitude() const {
-        return mPeakFollower.getLevel();
-    }
-
-    double getTolerance() {
-        return mTolerance;
-    }
-
-    void setTolerance(double tolerance) {
-        mTolerance = tolerance;
-        mScaledTolerance = mMagnitude * mTolerance;
-    }
-
-    void setMagnitude(double magnitude) {
-        mMagnitude = magnitude;
-        mScaledTolerance = mMagnitude * mTolerance;
-    }
-
-    int32_t getGlitchCount() const {
-        return mGlitchCount;
-    }
-
-    int32_t getStateFrameCount(int state) const {
-        return mStateFrameCounters[state];
-    }
-
-    double getSignalToNoiseDB() {
-        static const double threshold = 1.0e-14;
-        if (mMeanSquareSignal < threshold || mMeanSquareNoise < threshold) {
-            return 0.0;
-        } else {
-            double signalToNoise = mMeanSquareSignal / mMeanSquareNoise; // power ratio
-            double signalToNoiseDB = 10.0 * log(signalToNoise);
-            if (signalToNoiseDB < MIN_SNR_DB) {
-                ALOGD("ERROR - signal to noise ratio is too low! < %d dB. Adjust volume.",
-                     MIN_SNR_DB);
-                setResult(ERROR_VOLUME_TOO_LOW);
-            }
-            return signalToNoiseDB;
-        }
-    }
-
-    std::string analyze() override {
-        std::stringstream report;
-        report << "GlitchAnalyzer ------------------\n";
-        report << LOOPBACK_RESULT_TAG "peak.amplitude     = " << std::setw(8)
-               << getPeakAmplitude() << "\n";
-        report << LOOPBACK_RESULT_TAG "sine.magnitude     = " << std::setw(8)
-               << mMagnitude << "\n";
-        report << LOOPBACK_RESULT_TAG "rms.noise          = " << std::setw(8)
-               << mMeanSquareNoise << "\n";
-        report << LOOPBACK_RESULT_TAG "signal.to.noise.db = " << std::setw(8)
-               << getSignalToNoiseDB() << "\n";
-        report << LOOPBACK_RESULT_TAG "frames.accumulated = " << std::setw(8)
-               << mFramesAccumulated << "\n";
-        report << LOOPBACK_RESULT_TAG "sine.period        = " << std::setw(8)
-               << mSinePeriod << "\n";
-        report << LOOPBACK_RESULT_TAG "test.state         = " << std::setw(8)
-               << mState << "\n";
-        report << LOOPBACK_RESULT_TAG "frame.count        = " << std::setw(8)
-               << mFrameCounter << "\n";
-        // Did we ever get a lock?
-        bool gotLock = (mState == STATE_LOCKED) || (mGlitchCount > 0);
-        if (!gotLock) {
-            report << "ERROR - failed to lock on reference sine tone.\n";
-            setResult(ERROR_NO_LOCK);
-        } else {
-            // Only print if meaningful.
-            report << LOOPBACK_RESULT_TAG "glitch.count       = " << std::setw(8)
-                   << mGlitchCount << "\n";
-            report << LOOPBACK_RESULT_TAG "max.glitch         = " << std::setw(8)
-                   << mMaxGlitchDelta << "\n";
-            if (mGlitchCount > 0) {
-                report << "ERROR - number of glitches > 0\n";
-                setResult(ERROR_GLITCHES);
-            }
-        }
-        return report.str();
-    }
-
-    void printStatus() override {
-        ALOGD("st = %d, #gl = %3d,", mState, mGlitchCount);
-    }
-    /**
-     * Calculate the magnitude of the component of the input signal
-     * that matches the analysis frequency.
-     * Also calculate the phase that we can use to create a
-     * signal that matches that component.
-     * The phase will be between -PI and +PI.
-     */
-    double calculateMagnitude(double *phasePtr = nullptr) {
-        if (mFramesAccumulated == 0) {
-            return 0.0;
-        }
-        double sinMean = mSinAccumulator / mFramesAccumulated;
-        double cosMean = mCosAccumulator / mFramesAccumulated;
-        double magnitude = 2.0 * sqrt((sinMean * sinMean) + (cosMean * cosMean));
-        if (phasePtr != nullptr) {
-            double phase = M_PI_2 - atan2(sinMean, cosMean);
-            *phasePtr = phase;
-        }
-        return magnitude;
-    }
-
-    /**
-     * @param frameData contains microphone data with sine signal feedback
-     * @param channelCount
-     */
-    result_code processInputFrame(float *frameData, int /* channelCount */) override {
-        result_code result = RESULT_OK;
-
-        float sample = frameData[0];
-        float peak = mPeakFollower.process(sample);
-
-        // Force a periodic glitch to test the detector!
-        if (mForceGlitchDuration > 0) {
-            if (mForceGlitchCounter == 0) {
-                ALOGE("%s: force a glitch!!", __func__);
-                mForceGlitchCounter = getSampleRate();
-            } else if (mForceGlitchCounter <= mForceGlitchDuration) {
-                // Force an abrupt offset.
-                sample += (sample > 0.0) ? -0.5f : 0.5f;
-            }
-            --mForceGlitchCounter;
-        }
-
-        mStateFrameCounters[mState]++; // count how many frames we are in each state
-
-        switch (mState) {
-            case STATE_IDLE:
-                mDownCounter--;
-                if (mDownCounter <= 0) {
-                    mState = STATE_IMMUNE;
-                    mDownCounter = IMMUNE_FRAME_COUNT;
-                    mInputPhase = 0.0; // prevent spike at start
-                    mOutputPhase = 0.0;
-                }
-                break;
-
-            case STATE_IMMUNE:
-                mDownCounter--;
-                if (mDownCounter <= 0) {
-                    mState = STATE_WAITING_FOR_SIGNAL;
-                }
-                break;
-
-            case STATE_WAITING_FOR_SIGNAL:
-                if (peak > mThreshold) {
-                    mState = STATE_WAITING_FOR_LOCK;
-                    //ALOGD("%5d: switch to STATE_WAITING_FOR_LOCK", mFrameCounter);
-                    resetAccumulator();
-                }
-                break;
-
-            case STATE_WAITING_FOR_LOCK:
-                mSinAccumulator += sample * sinf(mInputPhase);
-                mCosAccumulator += sample * cosf(mInputPhase);
-                mFramesAccumulated++;
-                // Must be a multiple of the period or the calculation will not be accurate.
-                if (mFramesAccumulated == mSinePeriod * PERIODS_NEEDED_FOR_LOCK) {
-                    double phaseOffset = 0.0;
-                    setMagnitude(calculateMagnitude(&phaseOffset));
-//                    ALOGD("%s() mag = %f, offset = %f, prev = %f",
-//                            __func__, mMagnitude, mPhaseOffset, mPreviousPhaseOffset);
-                    if (mMagnitude > mThreshold) {
-                        if (abs(phaseOffset) < kMaxPhaseError) {
-                            mState = STATE_LOCKED;
-//                            ALOGD("%5d: switch to STATE_LOCKED", mFrameCounter);
-                        }
-                        // Adjust mInputPhase to match measured phase
-                        mInputPhase += phaseOffset;
-                    }
-                    resetAccumulator();
-                }
-                incrementInputPhase();
-                break;
-
-            case STATE_LOCKED: {
-                // Predict next sine value
-                double predicted = sinf(mInputPhase) * mMagnitude;
-                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 {
-                    mSumSquareSignal += predicted * predicted;
-                    mSumSquareNoise += diff * diff;
-                    // Track incoming signal and slowly adjust magnitude to account
-                    // for drift in the DRC or AGC.
-                    mSinAccumulator += sample * sinf(mInputPhase);
-                    mCosAccumulator += sample * cosf(mInputPhase);
-                    mFramesAccumulated++;
-                    // Must be a multiple of the period or the calculation will not be accurate.
-                    if (mFramesAccumulated == mSinePeriod) {
-                        const double coefficient = 0.1;
-                        double phaseOffset = 0.0;
-                        double magnitude = calculateMagnitude(&phaseOffset);
-                        // One pole averaging filter.
-                        setMagnitude((mMagnitude * (1.0 - coefficient)) + (magnitude * coefficient));
-
-                        mMeanSquareNoise = mSumSquareNoise * mInverseSinePeriod;
-                        mMeanSquareSignal = mSumSquareSignal * mInverseSinePeriod;
-                        resetAccumulator();
-
-                        if (abs(phaseOffset) > kMaxPhaseError) {
-                            result = ERROR_GLITCHES;
-                            onGlitchStart();
-                            ALOGD("phase glitch detected, phaseOffset = %g", phaseOffset);
-                        } else if (mMagnitude < mThreshold) {
-                            result = ERROR_GLITCHES;
-                            onGlitchStart();
-                            ALOGD("magnitude glitch detected, mMagnitude = %g", mMagnitude);
-                        }
-                    }
-                }
-                incrementInputPhase();
-            } break;
-
-            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.
-                    // We don't want to just consider a zero crossing the end of a glitch.
-                    if (mNonGlitchCount++ > mSinePeriod) {
-                        onGlitchEnd();
-                    }
-                } else {
-                    mNonGlitchCount = 0;
-                    if (mGlitchLength > (4 * mSinePeriod)) {
-                        relock();
-                    }
-                }
-                incrementInputPhase();
-            } break;
-
-            case NUM_STATES: // not a real state
-                break;
-        }
-
-        mFrameCounter++;
-
-        return result;
-    }
-
-    // advance and wrap phase
-    void incrementInputPhase() {
-        mInputPhase += mPhaseIncrement;
-        if (mInputPhase > M_PI) {
-            mInputPhase -= (2.0 * M_PI);
-        }
-    }
-
-    // advance and wrap phase
-    void incrementOutputPhase() {
-        mOutputPhase += mPhaseIncrement;
-        if (mOutputPhase > M_PI) {
-            mOutputPhase -= (2.0 * M_PI);
-        }
-    }
-
-    /**
-     * @param frameData upon return, contains the reference sine wave
-     * @param channelCount
-     */
-    result_code processOutputFrame(float *frameData, int channelCount) override {
-        float output = 0.0f;
-        // Output sine wave so we can measure it.
-        if (mState != STATE_IDLE) {
-            float sinOut = sinf(mOutputPhase);
-            incrementOutputPhase();
-            output = (sinOut * mOutputAmplitude)
-                     + (mWhiteNoise.nextRandomDouble() * kNoiseAmplitude);
-            // ALOGD("sin(%f) = %f, %f\n", mOutputPhase, sinOut,  mPhaseIncrement);
-        }
-        frameData[0] = output;
-        for (int i = 1; i < channelCount; i++) {
-            frameData[i] = 0.0f;
-        }
-        return RESULT_OK;
-    }
-
-    void onGlitchStart() {
-        mGlitchCount++;
-//        ALOGD("%5d: STARTED a glitch # %d", mFrameCounter, mGlitchCount);
-        mState = STATE_GLITCHING;
-        mGlitchLength = 1;
-        mNonGlitchCount = 0;
-    }
-
-    void onGlitchEnd() {
-//        ALOGD("%5d: ENDED a glitch # %d, length = %d", mFrameCounter, mGlitchCount, mGlitchLength);
-        mState = STATE_LOCKED;
-        resetAccumulator();
-    }
-
-    // reset the sine wave detector
-    void resetAccumulator() {
-        mFramesAccumulated = 0;
-        mSinAccumulator = 0.0;
-        mCosAccumulator = 0.0;
-        mSumSquareSignal = 0.0;
-        mSumSquareNoise = 0.0;
-    }
-
-    void relock() {
-//        ALOGD("relock: %d because of a very long %d glitch", mFrameCounter, mGlitchLength);
-        mState = STATE_WAITING_FOR_LOCK;
-        resetAccumulator();
-    }
-
-    void reset() override {
-        LoopbackProcessor::reset();
-        mState = STATE_IDLE;
-        mDownCounter = IDLE_FRAME_COUNT;
-        resetAccumulator();
-    }
-
-    void prepareToTest() override {
-        LoopbackProcessor::prepareToTest();
-        mSinePeriod = getSampleRate() / kTargetGlitchFrequency;
-        mOutputPhase = 0.0f;
-        mInverseSinePeriod = 1.0 / mSinePeriod;
-        mPhaseIncrement = 2.0 * M_PI * mInverseSinePeriod;
-        mGlitchCount = 0;
-        mMaxGlitchDelta = 0.0;
-        for (int i = 0; i < NUM_STATES; i++) {
-            mStateFrameCounters[i] = 0;
-        }
-    }
-
-private:
-
-    // These must match the values in GlitchActivity.java
-    enum sine_state_t {
-        STATE_IDLE,               // beginning
-        STATE_IMMUNE,             // ignoring input, waiting fo HW to settle
-        STATE_WAITING_FOR_SIGNAL, // looking for a loud signal
-        STATE_WAITING_FOR_LOCK,   // trying to lock onto the phase of the sine
-        STATE_LOCKED,             // locked on the sine wave, looking for glitches
-        STATE_GLITCHING,           // locked on the sine wave but glitching
-        NUM_STATES
-    };
-
-    enum constants {
-        // Arbitrary durations, assuming 48000 Hz
-        IDLE_FRAME_COUNT = 48 * 100,
-        IMMUNE_FRAME_COUNT = 48 * 100,
-        PERIODS_NEEDED_FOR_LOCK = 8,
-        MIN_SNR_DB = 65
-    };
-
-    static constexpr float kNoiseAmplitude = 0.00; // Used to experiment with warbling caused by DRC.
-    static constexpr int kTargetGlitchFrequency = 607;
-    static constexpr double kMaxPhaseError = M_PI * 0.05;
-
-    float   mTolerance = 0.10; // scaled from 0.0 to 1.0
-    double  mThreshold = 0.005;
-    int     mSinePeriod = 1; // this will be set before use
-    double  mInverseSinePeriod = 1.0;
-
-    int32_t mStateFrameCounters[NUM_STATES];
-
-    double  mPhaseIncrement = 0.0;
-    double  mInputPhase = 0.0;
-    double  mOutputPhase = 0.0;
-    double  mMagnitude = 0.0;
-    int32_t mFramesAccumulated = 0;
-    double  mSinAccumulator = 0.0;
-    double  mCosAccumulator = 0.0;
-    double  mMaxGlitchDelta = 0.0;
-    int32_t mGlitchCount = 0;
-    int32_t mNonGlitchCount = 0;
-    int32_t mGlitchLength = 0;
-    // This is used for processing every frame so we cache it here.
-    double  mScaledTolerance = 0.0;
-    int     mDownCounter = IDLE_FRAME_COUNT;
-    int32_t mFrameCounter = 0;
-    double  mOutputAmplitude = 0.75;
-
-    int32_t mForceGlitchDuration = 0; // if > 0 then force a glitch for debugging
-    int32_t mForceGlitchCounter = 4 * 48000; // count down and trigger at zero
-
-    // measure background noise continuously as a deviation from the expected signal
-    double  mSumSquareSignal = 0.0;
-    double  mSumSquareNoise = 0.0;
-    double  mMeanSquareSignal = 0.0;
-    double  mMeanSquareNoise = 0.0;
-
-    PeakDetector  mPeakFollower;
-
-    PseudoRandom  mWhiteNoise;
-
-    sine_state_t  mState = STATE_IDLE;
-};
-
-
-#endif //ANALYZER_GLITCH_ANALYZER_H
diff --git a/media/libaaudio/examples/loopback/src/analyzer/LatencyAnalyzer.h b/media/libaaudio/examples/loopback/src/analyzer/LatencyAnalyzer.h
deleted file mode 100644
index e506791..0000000
--- a/media/libaaudio/examples/loopback/src/analyzer/LatencyAnalyzer.h
+++ /dev/null
@@ -1,606 +0,0 @@
-/*
- * Copyright (C) 2017 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.
- */
-
-/**
- * Tools for measuring latency and for detecting glitches.
- * These classes are pure math and can be used with any audio system.
- */
-
-#ifndef ANALYZER_LATENCY_ANALYZER_H
-#define ANALYZER_LATENCY_ANALYZER_H
-
-#include <algorithm>
-#include <assert.h>
-#include <cctype>
-#include <iomanip>
-#include <iostream>
-#include <math.h>
-#include <memory>
-#include <sstream>
-#include <stdio.h>
-#include <stdlib.h>
-#include <unistd.h>
-#include <vector>
-
-#include "PeakDetector.h"
-#include "PseudoRandom.h"
-#include "RandomPulseGenerator.h"
-
-// This is used when the code is in Oboe.
-#ifndef ALOGD
-#define ALOGD printf
-#define ALOGE printf
-#define ALOGW printf
-#endif
-
-#define LOOPBACK_RESULT_TAG  "RESULT: "
-
-static constexpr int32_t kDefaultSampleRate = 48000;
-static constexpr int32_t kMillisPerSecond   = 1000;
-static constexpr int32_t kMaxLatencyMillis  = 700;  // arbitrary and generous
-static constexpr double  kMinimumConfidence = 0.2;
-
-struct LatencyReport {
-    int32_t latencyInFrames = 0.0;
-    double confidence = 0.0;
-
-    void reset() {
-        latencyInFrames = 0;
-        confidence = 0.0;
-    }
-};
-
-// Calculate a normalized cross correlation.
-static double calculateNormalizedCorrelation(const float *a,
-                                             const float *b,
-                                             int windowSize) {
-    double correlation = 0.0;
-    double sumProducts = 0.0;
-    double sumSquares = 0.0;
-
-    // Correlate a against b.
-    for (int i = 0; i < windowSize; i++) {
-        float s1 = a[i];
-        float s2 = b[i];
-        // Use a normalized cross-correlation.
-        sumProducts += s1 * s2;
-        sumSquares += ((s1 * s1) + (s2 * s2));
-    }
-
-    if (sumSquares >= 1.0e-9) {
-        correlation = 2.0 * sumProducts / sumSquares;
-    }
-    return correlation;
-}
-
-static double calculateRootMeanSquare(float *data, int32_t numSamples) {
-    double sum = 0.0;
-    for (int32_t i = 0; i < numSamples; i++) {
-        float sample = data[i];
-        sum += sample * sample;
-    }
-    return sqrt(sum / numSamples);
-}
-
-/**
- * Monophonic recording with processing.
- */
-class AudioRecording
-{
-public:
-
-    void allocate(int maxFrames) {
-        mData = std::make_unique<float[]>(maxFrames);
-        mMaxFrames = maxFrames;
-    }
-
-    // Write SHORT data from the first channel.
-    int32_t write(int16_t *inputData, int32_t inputChannelCount, int32_t numFrames) {
-        // stop at end of buffer
-        if ((mFrameCounter + numFrames) > mMaxFrames) {
-            numFrames = mMaxFrames - mFrameCounter;
-        }
-        for (int i = 0; i < numFrames; i++) {
-            mData[mFrameCounter++] = inputData[i * inputChannelCount] * (1.0f / 32768);
-        }
-        return numFrames;
-    }
-
-    // Write FLOAT data from the first channel.
-    int32_t write(float *inputData, int32_t inputChannelCount, int32_t numFrames) {
-        // stop at end of buffer
-        if ((mFrameCounter + numFrames) > mMaxFrames) {
-            numFrames = mMaxFrames - mFrameCounter;
-        }
-        for (int i = 0; i < numFrames; i++) {
-            mData[mFrameCounter++] = inputData[i * inputChannelCount];
-        }
-        return numFrames;
-    }
-
-    // Write FLOAT data from the first channel.
-    int32_t write(float sample) {
-        // stop at end of buffer
-        if (mFrameCounter < mMaxFrames) {
-            mData[mFrameCounter++] = sample;
-            return 1;
-        }
-        return 0;
-    }
-
-    void clear() {
-        mFrameCounter = 0;
-    }
-    int32_t size() const {
-        return mFrameCounter;
-    }
-
-    bool isFull() const {
-        return mFrameCounter >= mMaxFrames;
-    }
-
-    float *getData() const {
-        return mData.get();
-    }
-
-    void setSampleRate(int32_t sampleRate) {
-        mSampleRate = sampleRate;
-    }
-
-    int32_t getSampleRate() const {
-        return mSampleRate;
-    }
-
-    /**
-     * Square the samples so they are all positive and so the peaks are emphasized.
-     */
-    void square() {
-        float *x = mData.get();
-        for (int i = 0; i < mFrameCounter; i++) {
-            x[i] *= x[i];
-        }
-    }
-
-    /**
-     * Amplify a signal so that the peak matches the specified target.
-     *
-     * @param target final max value
-     * @return gain applied to signal
-     */
-    float normalize(float target) {
-        float maxValue = 1.0e-9f;
-        for (int i = 0; i < mFrameCounter; i++) {
-            maxValue = std::max(maxValue, abs(mData[i]));
-        }
-        float gain = target / maxValue;
-        for (int i = 0; i < mFrameCounter; i++) {
-            mData[i] *= gain;
-        }
-        return gain;
-    }
-
-private:
-    std::unique_ptr<float[]> mData;
-    int32_t       mFrameCounter = 0;
-    int32_t       mMaxFrames = 0;
-    int32_t       mSampleRate = kDefaultSampleRate; // common default
-};
-
-static int measureLatencyFromPulse(AudioRecording &recorded,
-                                   AudioRecording &pulse,
-                                   LatencyReport *report) {
-
-    report->latencyInFrames = 0;
-    report->confidence = 0.0;
-
-    int numCorrelations = recorded.size() - pulse.size();
-    if (numCorrelations < 10) {
-        ALOGE("%s() recording too small = %d frames\n", __func__, recorded.size());
-        return -1;
-    }
-    std::unique_ptr<float[]> correlations= std::make_unique<float[]>(numCorrelations);
-
-    // Correlate pulse against the recorded data.
-    for (int i = 0; i < numCorrelations; i++) {
-        float correlation = (float) calculateNormalizedCorrelation(&recorded.getData()[i],
-                                                                   &pulse.getData()[0],
-                                                                   pulse.size());
-        correlations[i] = correlation;
-    }
-
-    // Find highest peak in correlation array.
-    float peakCorrelation = 0.0;
-    int peakIndex = -1;
-    for (int i = 0; i < numCorrelations; i++) {
-        float value = abs(correlations[i]);
-        if (value > peakCorrelation) {
-            peakCorrelation = value;
-            peakIndex = i;
-        }
-    }
-    if (peakIndex < 0) {
-        ALOGE("%s() no signal for correlation\n", __func__);
-        return -2;
-    }
-
-    report->latencyInFrames = peakIndex;
-    report->confidence = peakCorrelation;
-
-    return 0;
-}
-
-// ====================================================================================
-class LoopbackProcessor {
-public:
-    virtual ~LoopbackProcessor() = default;
-
-    enum result_code {
-        RESULT_OK = 0,
-        ERROR_NOISY = -99,
-        ERROR_VOLUME_TOO_LOW,
-        ERROR_VOLUME_TOO_HIGH,
-        ERROR_CONFIDENCE,
-        ERROR_INVALID_STATE,
-        ERROR_GLITCHES,
-        ERROR_NO_LOCK
-    };
-
-    virtual void prepareToTest() {
-        reset();
-    }
-
-    virtual void reset() {
-        mResult = 0;
-        mResetCount++;
-    }
-
-    virtual result_code processInputFrame(float *frameData, int channelCount) = 0;
-    virtual result_code processOutputFrame(float *frameData, int channelCount) = 0;
-
-    void process(float *inputData, int inputChannelCount, int numInputFrames,
-                 float *outputData, int outputChannelCount, int numOutputFrames) {
-        int numBoth = std::min(numInputFrames, numOutputFrames);
-        // Process one frame at a time.
-        for (int i = 0; i < numBoth; i++) {
-            processInputFrame(inputData, inputChannelCount);
-            inputData += inputChannelCount;
-            processOutputFrame(outputData, outputChannelCount);
-            outputData += outputChannelCount;
-        }
-        // If there is more input than output.
-        for (int i = numBoth; i < numInputFrames; i++) {
-            processInputFrame(inputData, inputChannelCount);
-            inputData += inputChannelCount;
-        }
-        // If there is more output than input.
-        for (int i = numBoth; i < numOutputFrames; i++) {
-            processOutputFrame(outputData, outputChannelCount);
-            outputData += outputChannelCount;
-        }
-    }
-
-    virtual std::string analyze() = 0;
-
-    virtual void printStatus() {};
-
-    int32_t getResult() {
-        return mResult;
-    }
-
-    void setResult(int32_t result) {
-        mResult = result;
-    }
-
-    virtual bool isDone() {
-        return false;
-    }
-
-    virtual int save(const char *fileName) {
-        (void) fileName;
-        return -1;
-    }
-
-    virtual int load(const char *fileName) {
-        (void) fileName;
-        return -1;
-    }
-
-    virtual void setSampleRate(int32_t sampleRate) {
-        mSampleRate = sampleRate;
-    }
-
-    int32_t getSampleRate() const {
-        return mSampleRate;
-    }
-
-    int32_t getResetCount() const {
-        return mResetCount;
-    }
-
-    /** Called when not enough input frames could be read after synchronization.
-     */
-    virtual void onInsufficientRead() {
-        reset();
-    }
-
-protected:
-    int32_t   mResetCount = 0;
-
-private:
-    int32_t mSampleRate = kDefaultSampleRate;
-    int32_t mResult = 0;
-};
-
-class LatencyAnalyzer : public LoopbackProcessor {
-public:
-
-    LatencyAnalyzer() : LoopbackProcessor() {}
-    virtual ~LatencyAnalyzer() = default;
-
-    virtual int32_t getProgress() const = 0;
-
-    virtual int getState() = 0;
-
-    // @return latency in frames
-    virtual int32_t getMeasuredLatency() = 0;
-
-    virtual double getMeasuredConfidence() = 0;
-
-    virtual double getBackgroundRMS() = 0;
-
-    virtual double getSignalRMS() = 0;
-
-};
-
-// ====================================================================================
-/**
- * Measure latency given a loopback stream data.
- * Use an encoded bit train as the sound source because it
- * has an unambiguous correlation value.
- * Uses a state machine to cycle through various stages.
- *
- */
-class PulseLatencyAnalyzer : public LatencyAnalyzer {
-public:
-
-    PulseLatencyAnalyzer() : LatencyAnalyzer() {
-        int32_t maxLatencyFrames = getSampleRate() * kMaxLatencyMillis / kMillisPerSecond;
-        int32_t numPulseBits = getSampleRate() * kPulseLengthMillis
-                / (kFramesPerEncodedBit * kMillisPerSecond);
-        int32_t  pulseLength = numPulseBits * kFramesPerEncodedBit;
-        mFramesToRecord = pulseLength + maxLatencyFrames;
-        mAudioRecording.allocate(mFramesToRecord);
-        mAudioRecording.setSampleRate(getSampleRate());
-        generateRandomPulse(pulseLength);
-    }
-
-    void generateRandomPulse(int32_t pulseLength) {
-        mPulse.allocate(pulseLength);
-        RandomPulseGenerator pulser(kFramesPerEncodedBit);
-        for (int i = 0; i < pulseLength; i++) {
-            mPulse.write(pulser.nextFloat());
-        }
-    }
-
-    int getState() override {
-        return mState;
-    }
-
-    void setSampleRate(int32_t sampleRate) override {
-        LoopbackProcessor::setSampleRate(sampleRate);
-        mAudioRecording.setSampleRate(sampleRate);
-    }
-
-    void reset() override {
-        LoopbackProcessor::reset();
-        mDownCounter = getSampleRate() / 2;
-        mLoopCounter = 0;
-
-        mPulseCursor = 0;
-        mBackgroundSumSquare = 0.0f;
-        mBackgroundSumCount = 0;
-        mBackgroundRMS = 0.0f;
-        mSignalRMS = 0.0f;
-
-        mState = STATE_MEASURE_BACKGROUND;
-        mAudioRecording.clear();
-        mLatencyReport.reset();
-    }
-
-    bool hasEnoughData() {
-        return mAudioRecording.isFull();
-    }
-
-    bool isDone() override {
-        return mState == STATE_DONE;
-    }
-
-    int32_t getProgress() const override {
-        return mAudioRecording.size();
-    }
-
-    std::string analyze() override {
-        std::stringstream report;
-        report << "PulseLatencyAnalyzer ---------------\n";
-        report << LOOPBACK_RESULT_TAG "test.state             = "
-                << std::setw(8) << mState << "\n";
-        report << LOOPBACK_RESULT_TAG "test.state.name        = "
-                << convertStateToText(mState) << "\n";
-        report << LOOPBACK_RESULT_TAG "background.rms         = "
-                << std::setw(8) << mBackgroundRMS << "\n";
-
-        int32_t newResult = RESULT_OK;
-        if (mState != STATE_GOT_DATA) {
-            report << "WARNING - Bad state. Check volume on device.\n";
-            // setResult(ERROR_INVALID_STATE);
-        } else {
-            float gain = mAudioRecording.normalize(1.0f);
-            measureLatencyFromPulse(mAudioRecording,
-                                    mPulse,
-                                    &mLatencyReport);
-
-            if (mLatencyReport.confidence < kMinimumConfidence) {
-                report << "   ERROR - confidence too low!";
-                newResult = ERROR_CONFIDENCE;
-            } else {
-                mSignalRMS = calculateRootMeanSquare(
-                        &mAudioRecording.getData()[mLatencyReport.latencyInFrames], mPulse.size())
-                                / gain;
-            }
-            double latencyMillis = kMillisPerSecond * (double) mLatencyReport.latencyInFrames
-                                   / getSampleRate();
-            report << LOOPBACK_RESULT_TAG "latency.frames         = " << std::setw(8)
-                   << mLatencyReport.latencyInFrames << "\n";
-            report << LOOPBACK_RESULT_TAG "latency.msec           = " << std::setw(8)
-                   << latencyMillis << "\n";
-            report << LOOPBACK_RESULT_TAG "latency.confidence     = " << std::setw(8)
-                   << mLatencyReport.confidence << "\n";
-        }
-        mState = STATE_DONE;
-        if (getResult() == RESULT_OK) {
-            setResult(newResult);
-        }
-
-        return report.str();
-    }
-
-    int32_t getMeasuredLatency() override {
-        return mLatencyReport.latencyInFrames;
-    }
-
-    double getMeasuredConfidence() override {
-        return mLatencyReport.confidence;
-    }
-
-    double getBackgroundRMS() override {
-        return mBackgroundRMS;
-    }
-
-    double getSignalRMS() override {
-        return mSignalRMS;
-    }
-
-    void printStatus() override {
-        ALOGD("st = %d", mState);
-    }
-
-    result_code processInputFrame(float *frameData, int channelCount) override {
-        echo_state nextState = mState;
-        mLoopCounter++;
-
-        switch (mState) {
-            case STATE_MEASURE_BACKGROUND:
-                // Measure background RMS on channel 0
-                mBackgroundSumSquare += frameData[0] * frameData[0];
-                mBackgroundSumCount++;
-                mDownCounter--;
-                if (mDownCounter <= 0) {
-                    mBackgroundRMS = sqrtf(mBackgroundSumSquare / mBackgroundSumCount);
-                    nextState = STATE_IN_PULSE;
-                    mPulseCursor = 0;
-                }
-                break;
-
-            case STATE_IN_PULSE:
-                // Record input until the mAudioRecording is full.
-                mAudioRecording.write(frameData, channelCount, 1);
-                if (hasEnoughData()) {
-                    nextState = STATE_GOT_DATA;
-                }
-                break;
-
-            case STATE_GOT_DATA:
-            case STATE_DONE:
-            default:
-                break;
-        }
-
-        mState = nextState;
-        return RESULT_OK;
-    }
-
-    result_code processOutputFrame(float *frameData, int channelCount) override {
-        switch (mState) {
-            case STATE_IN_PULSE:
-                if (mPulseCursor < mPulse.size()) {
-                    float pulseSample = mPulse.getData()[mPulseCursor++];
-                    for (int i = 0; i < channelCount; i++) {
-                        frameData[i] = pulseSample;
-                    }
-                } else {
-                    for (int i = 0; i < channelCount; i++) {
-                        frameData[i] = 0;
-                    }
-                }
-                break;
-
-            case STATE_MEASURE_BACKGROUND:
-            case STATE_GOT_DATA:
-            case STATE_DONE:
-            default:
-                for (int i = 0; i < channelCount; i++) {
-                    frameData[i] = 0.0f; // silence
-                }
-                break;
-        }
-
-        return RESULT_OK;
-    }
-
-private:
-
-    enum echo_state {
-        STATE_MEASURE_BACKGROUND,
-        STATE_IN_PULSE,
-        STATE_GOT_DATA, // must match RoundTripLatencyActivity.java
-        STATE_DONE,
-    };
-
-    const char *convertStateToText(echo_state state) {
-        switch (state) {
-            case STATE_MEASURE_BACKGROUND:
-                return "INIT";
-            case STATE_IN_PULSE:
-                return "PULSE";
-            case STATE_GOT_DATA:
-                return "GOT_DATA";
-            case STATE_DONE:
-                return "DONE";
-        }
-        return "UNKNOWN";
-    }
-
-    int32_t         mDownCounter = 500;
-    int32_t         mLoopCounter = 0;
-    echo_state      mState = STATE_MEASURE_BACKGROUND;
-
-    static constexpr int32_t kFramesPerEncodedBit = 8; // multiple of 2
-    static constexpr int32_t kPulseLengthMillis = 500;
-
-    AudioRecording     mPulse;
-    int32_t            mPulseCursor = 0;
-
-    double             mBackgroundSumSquare = 0.0;
-    int32_t            mBackgroundSumCount = 0;
-    double             mBackgroundRMS = 0.0;
-    double             mSignalRMS = 0.0;
-    int32_t            mFramesToRecord = 0;
-
-    AudioRecording     mAudioRecording; // contains only the input after starting the pulse
-    LatencyReport      mLatencyReport;
-};
-
-#endif // ANALYZER_LATENCY_ANALYZER_H
diff --git a/media/libaaudio/examples/loopback/src/analyzer/ManchesterEncoder.h b/media/libaaudio/examples/loopback/src/analyzer/ManchesterEncoder.h
deleted file mode 100644
index 0a4bd5b..0000000
--- a/media/libaaudio/examples/loopback/src/analyzer/ManchesterEncoder.h
+++ /dev/null
@@ -1,98 +0,0 @@
-/*
- * 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.
- */
-
-#ifndef ANALYZER_MANCHESTER_ENCODER_H
-#define ANALYZER_MANCHESTER_ENCODER_H
-
-#include <cstdint>
-
-/**
- * Encode bytes using Manchester Coding scheme.
- *
- * Manchester Code is self clocking.
- * There is a transition in the middle of every bit.
- * Zero is high then low.
- * One is low then high.
- *
- * This avoids having long DC sections that would droop when
- * passed though analog circuits with AC coupling.
- *
- * IEEE 802.3 compatible.
- */
-
-class ManchesterEncoder {
-public:
-    ManchesterEncoder(int samplesPerPulse)
-            : mSamplesPerPulse(samplesPerPulse)
-            , mSamplesPerPulseHalf(samplesPerPulse / 2)
-            , mCursor(samplesPerPulse) {
-    }
-
-    virtual ~ManchesterEncoder() = default;
-
-    /**
-     * This will be called when the next byte is needed.
-     * @return
-     */
-    virtual uint8_t onNextByte() = 0;
-
-    /**
-     * Generate the next floating point sample.
-     * @return
-     */
-    virtual float nextFloat() {
-        advanceSample();
-        if (mCurrentBit) {
-            return (mCursor < mSamplesPerPulseHalf) ? -1.0f : 1.0f; // one
-        } else {
-            return (mCursor < mSamplesPerPulseHalf) ? 1.0f : -1.0f; // zero
-        }
-    }
-
-protected:
-    /**
-     * This will be called when a new bit is ready to be encoded.
-     * It can be used to prepare the encoded samples.
-     * @param current
-     */
-    virtual void onNextBit(bool /* current */) {};
-
-    void advanceSample() {
-        // Are we ready for a new bit?
-        if (++mCursor >= mSamplesPerPulse) {
-            mCursor = 0;
-            if (mBitsLeft == 0) {
-                mCurrentByte = onNextByte();
-                mBitsLeft = 8;
-            }
-            --mBitsLeft;
-            mCurrentBit = (mCurrentByte >> mBitsLeft) & 1;
-            onNextBit(mCurrentBit);
-        }
-    }
-
-    bool getCurrentBit() {
-        return mCurrentBit;
-    }
-
-    const int mSamplesPerPulse;
-    const int mSamplesPerPulseHalf;
-    int       mCursor;
-    int       mBitsLeft = 0;
-    uint8_t   mCurrentByte = 0;
-    bool      mCurrentBit = false;
-};
-#endif //ANALYZER_MANCHESTER_ENCODER_H
diff --git a/media/libaaudio/examples/loopback/src/analyzer/PeakDetector.h b/media/libaaudio/examples/loopback/src/analyzer/PeakDetector.h
deleted file mode 100644
index 4b3b4e7..0000000
--- a/media/libaaudio/examples/loopback/src/analyzer/PeakDetector.h
+++ /dev/null
@@ -1,68 +0,0 @@
-/*
- * Copyright 2015 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.
- */
-
-#ifndef ANALYZER_PEAK_DETECTOR_H
-#define ANALYZER_PEAK_DETECTOR_H
-
-#include <math.h>
-
-/**
- * Measure a peak envelope by rising with the peaks,
- * and decaying exponentially after each peak.
- * The absolute value of the input signal is used.
- */
-class PeakDetector {
-public:
-
-    void reset() {
-        mLevel = 0.0;
-    }
-
-    double process(double input) {
-        mLevel *= mDecay; // exponential decay
-        input = fabs(input);
-        // never fall below the input signal
-        if (input > mLevel) {
-            mLevel = input;
-        }
-        return mLevel;
-    }
-
-    double getLevel() const {
-        return mLevel;
-    }
-
-    double getDecay() const {
-        return mDecay;
-    }
-
-    /**
-     * Multiply the level by this amount on every iteration.
-     * This provides an exponential decay curve.
-     * A value just under 1.0 is best, for example, 0.99;
-     * @param decay scale level for each input
-     */
-    void setDecay(double decay) {
-        mDecay = decay;
-    }
-
-private:
-    static constexpr double kDefaultDecay = 0.99f;
-
-    double mLevel = 0.0;
-    double mDecay = kDefaultDecay;
-};
-#endif //ANALYZER_PEAK_DETECTOR_H
diff --git a/media/libaaudio/examples/loopback/src/analyzer/PseudoRandom.h b/media/libaaudio/examples/loopback/src/analyzer/PseudoRandom.h
deleted file mode 100644
index 1c4938c..0000000
--- a/media/libaaudio/examples/loopback/src/analyzer/PseudoRandom.h
+++ /dev/null
@@ -1,57 +0,0 @@
-/*
- * Copyright (C) 2017 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.
- */
-
-
-#ifndef ANALYZER_PSEUDORANDOM_H
-#define ANALYZER_PSEUDORANDOM_H
-
-#include <cctype>
-
-class PseudoRandom {
-public:
-    PseudoRandom(int64_t seed = 99887766)
-            :    mSeed(seed)
-    {}
-
-    /**
-     * Returns the next random double from -1.0 to 1.0
-     *
-     * @return value from -1.0 to 1.0
-     */
-    double nextRandomDouble() {
-        return nextRandomInteger() * (0.5 / (((int32_t)1) << 30));
-    }
-
-    /** Calculate random 32 bit number using linear-congruential method
-     * with known real-time performance.
-     */
-    int32_t nextRandomInteger() {
-#if __has_builtin(__builtin_mul_overflow) && __has_builtin(__builtin_add_overflow)
-        int64_t prod;
-        // Use values for 64-bit sequence from MMIX by Donald Knuth.
-        __builtin_mul_overflow(mSeed, (int64_t)6364136223846793005, &prod);
-        __builtin_add_overflow(prod, (int64_t)1442695040888963407, &mSeed);
-#else
-        mSeed = (mSeed * (int64_t)6364136223846793005) + (int64_t)1442695040888963407;
-#endif
-        return (int32_t) (mSeed >> 32); // The higher bits have a longer sequence.
-    }
-
-private:
-    int64_t mSeed;
-};
-
-#endif //ANALYZER_PSEUDORANDOM_H
diff --git a/media/libaaudio/examples/loopback/src/analyzer/RandomPulseGenerator.h b/media/libaaudio/examples/loopback/src/analyzer/RandomPulseGenerator.h
deleted file mode 100644
index 030050b..0000000
--- a/media/libaaudio/examples/loopback/src/analyzer/RandomPulseGenerator.h
+++ /dev/null
@@ -1,43 +0,0 @@
-/*
- * Copyright 2015 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.
- */
-
-#ifndef ANALYZER_RANDOM_PULSE_GENERATOR_H
-#define ANALYZER_RANDOM_PULSE_GENERATOR_H
-
-#include <stdlib.h>
-#include "RoundedManchesterEncoder.h"
-
-/**
- * Encode random ones and zeros using Manchester Code per IEEE 802.3.
- */
-class RandomPulseGenerator : public RoundedManchesterEncoder {
-public:
-    RandomPulseGenerator(int samplesPerPulse)
-    : RoundedManchesterEncoder(samplesPerPulse) {
-    }
-
-    virtual ~RandomPulseGenerator() = default;
-
-    /**
-     * This will be called when the next byte is needed.
-     * @return random byte
-     */
-    uint8_t onNextByte() override {
-        return static_cast<uint8_t>(rand());
-    }
-};
-
-#endif //ANALYZER_RANDOM_PULSE_GENERATOR_H
diff --git a/media/libaaudio/examples/loopback/src/analyzer/RoundedManchesterEncoder.h b/media/libaaudio/examples/loopback/src/analyzer/RoundedManchesterEncoder.h
deleted file mode 100644
index f2eba84..0000000
--- a/media/libaaudio/examples/loopback/src/analyzer/RoundedManchesterEncoder.h
+++ /dev/null
@@ -1,88 +0,0 @@
-/*
- * 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.
- */
-
-#ifndef ANALYZER_ROUNDED_MANCHESTER_ENCODER_H
-#define ANALYZER_ROUNDED_MANCHESTER_ENCODER_H
-
-#include <math.h>
-#include <memory.h>
-#include <stdlib.h>
-#include "ManchesterEncoder.h"
-
-/**
- * Encode bytes using Manchester Code.
- * Round the edges using a half cosine to reduce ringing caused by a hard edge.
- */
-
-class RoundedManchesterEncoder : public ManchesterEncoder {
-public:
-    RoundedManchesterEncoder(int samplesPerPulse)
-            : ManchesterEncoder(samplesPerPulse) {
-        int rampSize = samplesPerPulse / 4;
-        mZeroAfterZero = std::make_unique<float[]>(samplesPerPulse);
-        mZeroAfterOne = std::make_unique<float[]>(samplesPerPulse);
-
-        int sampleIndex = 0;
-        for (int rampIndex = 0; rampIndex < rampSize; rampIndex++) {
-            float phase = (rampIndex + 1) * M_PI / rampSize;
-            float sample = -cosf(phase);
-            mZeroAfterZero[sampleIndex] = sample;
-            mZeroAfterOne[sampleIndex] = 1.0f;
-            sampleIndex++;
-        }
-        for (int rampIndex = 0; rampIndex < rampSize; rampIndex++) {
-            mZeroAfterZero[sampleIndex] = 1.0f;
-            mZeroAfterOne[sampleIndex] = 1.0f;
-            sampleIndex++;
-        }
-        for (int rampIndex = 0; rampIndex < rampSize; rampIndex++) {
-            float phase = (rampIndex + 1) * M_PI / rampSize;
-            float sample = cosf(phase);
-            mZeroAfterZero[sampleIndex] = sample;
-            mZeroAfterOne[sampleIndex] = sample;
-            sampleIndex++;
-        }
-        for (int rampIndex = 0; rampIndex < rampSize; rampIndex++) {
-            mZeroAfterZero[sampleIndex] = -1.0f;
-            mZeroAfterOne[sampleIndex] = -1.0f;
-            sampleIndex++;
-        }
-    }
-
-    void onNextBit(bool current) override {
-        // Do we need to use the rounded edge?
-        mCurrentSamples = (current ^ mPreviousBit)
-                          ? mZeroAfterOne.get()
-                          : mZeroAfterZero.get();
-        mPreviousBit = current;
-    }
-
-    float nextFloat() override {
-        advanceSample();
-        float output = mCurrentSamples[mCursor];
-        if (getCurrentBit()) output = -output;
-        return output;
-    }
-
-private:
-
-    bool mPreviousBit = false;
-    float *mCurrentSamples = nullptr;
-    std::unique_ptr<float[]> mZeroAfterZero;
-    std::unique_ptr<float[]> mZeroAfterOne;
-};
-
-#endif //ANALYZER_ROUNDED_MANCHESTER_ENCODER_H
diff --git a/media/libaaudio/examples/loopback/src/loopback.cpp b/media/libaaudio/examples/loopback/src/loopback.cpp
index 0d2ec70..6fff568 100644
--- a/media/libaaudio/examples/loopback/src/loopback.cpp
+++ b/media/libaaudio/examples/loopback/src/loopback.cpp
@@ -36,8 +36,12 @@
 #include "AAudioSimpleRecorder.h"
 #include "AAudioExampleUtils.h"
 
+// Get logging macros from OboeTester
+#include "android_debug.h"
+// Get signal analyzers from OboeTester
 #include "analyzer/GlitchAnalyzer.h"
 #include "analyzer/LatencyAnalyzer.h"
+
 #include "../../utils/AAudioExampleUtils.h"
 
 // V0.4.00 = rectify and low-pass filter the echos, auto-correlate entire echo
@@ -45,8 +49,9 @@
 //           fix -n option to set output buffer for -tm
 //           plot first glitch
 // V0.4.02 = allow -n0 for minimal buffer size
-// V0.5.00 = use latency analyzer from OboeTester, uses random noise for latency
-#define APP_VERSION             "0.5.00"
+// V0.5.00 = use latency analyzer copied from OboeTester, uses random noise for latency
+// V0.5.01 = use latency analyzer directly from OboeTester in external/oboe
+#define APP_VERSION             "0.5.01"
 
 // Tag for machine readable results as property = value pairs
 #define RESULT_TAG              "RESULT: "