1 /* 2 * Copyright (C) 2017 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 #ifndef ANALYZER_GLITCH_ANALYZER_H 18 #define ANALYZER_GLITCH_ANALYZER_H 19 20 #include <algorithm> 21 #include <cctype> 22 #include <iomanip> 23 #include <iostream> 24 25 #include "InfiniteRecording.h" 26 #include "LatencyAnalyzer.h" 27 #include "BaseSineAnalyzer.h" 28 #include "PseudoRandom.h" 29 30 /** 31 * Output a steady sine wave and analyze the return signal. 32 * 33 * Use a cosine transform to measure the predicted magnitude and relative phase of the 34 * looped back sine wave. Then generate a predicted signal and compare with the actual signal. 35 */ 36 class GlitchAnalyzer : public BaseSineAnalyzer { 37 public: 38 GlitchAnalyzer()39 GlitchAnalyzer() : BaseSineAnalyzer() {} 40 getState()41 int32_t getState() const { 42 return mState; 43 } 44 getPeakAmplitude()45 double getPeakAmplitude() const { 46 return mPeakFollower.getLevel(); 47 } 48 getSineAmplitude()49 double getSineAmplitude() const { 50 return mMagnitude; 51 } 52 getGlitchCount()53 int32_t getGlitchCount() const { 54 return mGlitchCount; 55 } 56 getStateFrameCount(int state)57 int32_t getStateFrameCount(int state) const { 58 return mStateFrameCounters[state]; 59 } 60 getSignalToNoiseDB()61 double getSignalToNoiseDB() { 62 static const double threshold = 1.0e-14; 63 if (mState != STATE_LOCKED 64 || mMeanSquareSignal < threshold 65 || mMeanSquareNoise < threshold) { 66 return 0.0; 67 } else { 68 double signalToNoise = mMeanSquareSignal / mMeanSquareNoise; // power ratio 69 double signalToNoiseDB = 10.0 * log(signalToNoise); 70 if (signalToNoiseDB < MIN_SNR_DB) { 71 setResult(ERROR_VOLUME_TOO_LOW); 72 } 73 return signalToNoiseDB; 74 } 75 } 76 analyze()77 std::string analyze() override { 78 std::stringstream report; 79 report << "GlitchAnalyzer ------------------\n"; 80 report << LOOPBACK_RESULT_TAG "peak.amplitude = " << std::setw(8) 81 << getPeakAmplitude() << "\n"; 82 report << LOOPBACK_RESULT_TAG "sine.magnitude = " << std::setw(8) 83 << getSineAmplitude() << "\n"; 84 report << LOOPBACK_RESULT_TAG "rms.noise = " << std::setw(8) 85 << mMeanSquareNoise << "\n"; 86 report << LOOPBACK_RESULT_TAG "signal.to.noise.db = " << std::setw(8) 87 << getSignalToNoiseDB() << "\n"; 88 report << LOOPBACK_RESULT_TAG "frames.accumulated = " << std::setw(8) 89 << mFramesAccumulated << "\n"; 90 report << LOOPBACK_RESULT_TAG "sine.period = " << std::setw(8) 91 << mSinePeriod << "\n"; 92 report << LOOPBACK_RESULT_TAG "test.state = " << std::setw(8) 93 << mState << "\n"; 94 report << LOOPBACK_RESULT_TAG "frame.count = " << std::setw(8) 95 << mFrameCounter << "\n"; 96 // Did we ever get a lock? 97 bool gotLock = (mState == STATE_LOCKED) || (mGlitchCount > 0); 98 if (!gotLock) { 99 report << "ERROR - failed to lock on reference sine tone.\n"; 100 setResult(ERROR_NO_LOCK); 101 } else { 102 // Only print if meaningful. 103 report << LOOPBACK_RESULT_TAG "glitch.count = " << std::setw(8) 104 << mGlitchCount << "\n"; 105 report << LOOPBACK_RESULT_TAG "max.glitch = " << std::setw(8) 106 << mMaxGlitchDelta << "\n"; 107 if (mGlitchCount > 0) { 108 report << "ERROR - number of glitches > 0\n"; 109 setResult(ERROR_GLITCHES); 110 } 111 } 112 return report.str(); 113 } 114 printStatus()115 void printStatus() override { 116 ALOGD("st = %d, #gl = %3d,", mState, mGlitchCount); 117 } 118 119 /** 120 * @param frameData contains microphone data with sine signal feedback 121 * @param channelCount 122 */ processInputFrame(const float * frameData,int)123 result_code processInputFrame(const float *frameData, int /* channelCount */) override { 124 result_code result = RESULT_OK; 125 126 float sample = frameData[getInputChannel()]; 127 float peak = mPeakFollower.process(sample); 128 mInfiniteRecording.write(sample); 129 130 // Force a periodic glitch to test the detector! 131 if (mForceGlitchDuration > 0) { 132 if (mForceGlitchCounter == 0) { 133 ALOGE("%s: force a glitch!!", __func__); 134 mForceGlitchCounter = getSampleRate(); 135 } else if (mForceGlitchCounter <= mForceGlitchDuration) { 136 // Force an abrupt offset. 137 sample += (sample > 0.0) ? -0.5f : 0.5f; 138 } 139 --mForceGlitchCounter; 140 } 141 142 mStateFrameCounters[mState]++; // count how many frames we are in each state 143 144 switch (mState) { 145 case STATE_IDLE: 146 mDownCounter--; 147 if (mDownCounter <= 0) { 148 mState = STATE_IMMUNE; 149 mDownCounter = IMMUNE_FRAME_COUNT; 150 mInputPhase = 0.0; // prevent spike at start 151 mOutputPhase = 0.0; 152 resetAccumulator(); 153 } 154 break; 155 156 case STATE_IMMUNE: 157 mDownCounter--; 158 if (mDownCounter <= 0) { 159 mState = STATE_WAITING_FOR_SIGNAL; 160 } 161 break; 162 163 case STATE_WAITING_FOR_SIGNAL: 164 if (peak > mThreshold) { 165 mState = STATE_WAITING_FOR_LOCK; 166 //ALOGD("%5d: switch to STATE_WAITING_FOR_LOCK", mFrameCounter); 167 resetAccumulator(); 168 } 169 break; 170 171 case STATE_WAITING_FOR_LOCK: 172 mSinAccumulator += static_cast<double>(sample) * sinf(mInputPhase); 173 mCosAccumulator += static_cast<double>(sample) * cosf(mInputPhase); 174 mFramesAccumulated++; 175 // Must be a multiple of the period or the calculation will not be accurate. 176 if (mFramesAccumulated == mSinePeriod * PERIODS_NEEDED_FOR_LOCK) { 177 setMagnitude(calculateMagnitudePhase(&mPhaseOffset)); 178 // ALOGD("%s() mag = %f, offset = %f, prev = %f", 179 // __func__, mMagnitude, mPhaseOffset, mPreviousPhaseOffset); 180 if (mMagnitude > mThreshold) { 181 if (abs(mPhaseOffset) < kMaxPhaseError) { 182 mState = STATE_LOCKED; 183 // ALOGD("%5d: switch to STATE_LOCKED", mFrameCounter); 184 } 185 // Adjust mInputPhase to match measured phase 186 mInputPhase += mPhaseOffset; 187 } 188 resetAccumulator(); 189 } 190 incrementInputPhase(); 191 break; 192 193 case STATE_LOCKED: { 194 // Predict next sine value 195 double predicted = sinf(mInputPhase) * mMagnitude; 196 double diff = predicted - sample; 197 double absDiff = fabs(diff); 198 mMaxGlitchDelta = std::max(mMaxGlitchDelta, absDiff); 199 if (absDiff > mScaledTolerance) { 200 result = ERROR_GLITCHES; 201 onGlitchStart(); 202 // LOGI("diff glitch detected, absDiff = %g", absDiff); 203 } else { 204 mSumSquareSignal += predicted * predicted; 205 mSumSquareNoise += diff * diff; 206 207 208 // Track incoming signal and slowly adjust magnitude to account 209 // for drift in the DRC or AGC. 210 // Must be a multiple of the period or the calculation will not be accurate. 211 if (transformSample(sample, mInputPhase)) { 212 mMeanSquareNoise = mSumSquareNoise * mInverseSinePeriod; 213 mMeanSquareSignal = mSumSquareSignal * mInverseSinePeriod; 214 resetAccumulator(); 215 216 if (abs(mPhaseOffset) > kMaxPhaseError) { 217 result = ERROR_GLITCHES; 218 onGlitchStart(); 219 ALOGD("phase glitch detected, phaseOffset = %g", mPhaseOffset); 220 } else if (mMagnitude < mThreshold) { 221 result = ERROR_GLITCHES; 222 onGlitchStart(); 223 ALOGD("magnitude glitch detected, mMagnitude = %g", mMagnitude); 224 } 225 } 226 } 227 incrementInputPhase(); 228 } break; 229 230 case STATE_GLITCHING: { 231 // Predict next sine value 232 mGlitchLength++; 233 double predicted = sinf(mInputPhase) * mMagnitude; 234 double diff = predicted - sample; 235 double absDiff = fabs(diff); 236 mMaxGlitchDelta = std::max(mMaxGlitchDelta, absDiff); 237 if (absDiff < mScaledTolerance) { // close enough? 238 // If we get a full sine period of non-glitch samples in a row then consider the glitch over. 239 // We don't want to just consider a zero crossing the end of a glitch. 240 if (mNonGlitchCount++ > mSinePeriod) { 241 onGlitchEnd(); 242 } 243 } else { 244 mNonGlitchCount = 0; 245 if (mGlitchLength > (4 * mSinePeriod)) { 246 relock(); 247 } 248 } 249 incrementInputPhase(); 250 } break; 251 252 case NUM_STATES: // not a real state 253 break; 254 } 255 256 mFrameCounter++; 257 258 return result; 259 } 260 261 // advance and wrap phase incrementInputPhase()262 void incrementInputPhase() { 263 mInputPhase += mPhaseIncrement; 264 if (mInputPhase > M_PI) { 265 mInputPhase -= (2.0 * M_PI); 266 } 267 } 268 isOutputEnabled()269 bool isOutputEnabled() override { return mState != STATE_IDLE; } 270 onGlitchStart()271 void onGlitchStart() { 272 mGlitchCount++; 273 // ALOGD("%5d: STARTED a glitch # %d", mFrameCounter, mGlitchCount); 274 mState = STATE_GLITCHING; 275 mGlitchLength = 1; 276 mNonGlitchCount = 0; 277 mLastGlitchPosition = mInfiniteRecording.getTotalWritten(); 278 } 279 onGlitchEnd()280 void onGlitchEnd() { 281 // ALOGD("%5d: ENDED a glitch # %d, length = %d", mFrameCounter, mGlitchCount, mGlitchLength); 282 mState = STATE_LOCKED; 283 resetAccumulator(); 284 } 285 286 // reset the sine wave detector resetAccumulator()287 void resetAccumulator() override { 288 BaseSineAnalyzer::resetAccumulator(); 289 mSumSquareSignal = 0.0; 290 mSumSquareNoise = 0.0; 291 } 292 relock()293 void relock() { 294 // ALOGD("relock: %d because of a very long %d glitch", mFrameCounter, mGlitchLength); 295 mState = STATE_WAITING_FOR_LOCK; 296 resetAccumulator(); 297 } 298 reset()299 void reset() override { 300 BaseSineAnalyzer::reset(); 301 mState = STATE_IDLE; 302 mDownCounter = IDLE_FRAME_COUNT; 303 } 304 prepareToTest()305 void prepareToTest() override { 306 BaseSineAnalyzer::prepareToTest(); 307 mGlitchCount = 0; 308 mMaxGlitchDelta = 0.0; 309 for (int i = 0; i < NUM_STATES; i++) { 310 mStateFrameCounters[i] = 0; 311 } 312 } 313 getLastGlitch(float * buffer,int32_t length)314 int32_t getLastGlitch(float *buffer, int32_t length) { 315 return mInfiniteRecording.readFrom(buffer, mLastGlitchPosition - 32, length); 316 } 317 318 private: 319 320 // These must match the values in GlitchActivity.java 321 enum sine_state_t { 322 STATE_IDLE, // beginning 323 STATE_IMMUNE, // ignoring input, waiting for HW to settle 324 STATE_WAITING_FOR_SIGNAL, // looking for a loud signal 325 STATE_WAITING_FOR_LOCK, // trying to lock onto the phase of the sine 326 STATE_LOCKED, // locked on the sine wave, looking for glitches 327 STATE_GLITCHING, // locked on the sine wave but glitching 328 NUM_STATES 329 }; 330 331 enum constants { 332 // Arbitrary durations, assuming 48000 Hz 333 IDLE_FRAME_COUNT = 48 * 100, 334 IMMUNE_FRAME_COUNT = 48 * 100, 335 PERIODS_NEEDED_FOR_LOCK = 8, 336 MIN_SNR_DB = 65 337 }; 338 339 static constexpr double kMaxPhaseError = M_PI * 0.05; 340 341 double mThreshold = 0.005; 342 343 int32_t mStateFrameCounters[NUM_STATES]; 344 sine_state_t mState = STATE_IDLE; 345 int64_t mLastGlitchPosition; 346 347 double mInputPhase = 0.0; 348 double mMaxGlitchDelta = 0.0; 349 int32_t mGlitchCount = 0; 350 int32_t mNonGlitchCount = 0; 351 int32_t mGlitchLength = 0; 352 int mDownCounter = IDLE_FRAME_COUNT; 353 int32_t mFrameCounter = 0; 354 355 int32_t mForceGlitchDuration = 0; // if > 0 then force a glitch for debugging 356 int32_t mForceGlitchCounter = 4 * 48000; // count down and trigger at zero 357 358 // measure background noise continuously as a deviation from the expected signal 359 double mSumSquareSignal = 0.0; 360 double mSumSquareNoise = 0.0; 361 double mMeanSquareSignal = 0.0; 362 double mMeanSquareNoise = 0.0; 363 364 PeakDetector mPeakFollower; 365 }; 366 367 368 #endif //ANALYZER_GLITCH_ANALYZER_H 369