• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2020 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_DATA_PATH_ANALYZER_H
18 #define ANALYZER_DATA_PATH_ANALYZER_H
19 
20 #include <algorithm>
21 #include <cctype>
22 #include <iomanip>
23 #include <iostream>
24 #include <math.h>
25 
26 #include "BaseSineAnalyzer.h"
27 #include "InfiniteRecording.h"
28 #include "LatencyAnalyzer.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.
35  */
36 class DataPathAnalyzer : public BaseSineAnalyzer {
37 public:
38 
DataPathAnalyzer()39     DataPathAnalyzer() : BaseSineAnalyzer() {
40         // Add a little bit of noise to reduce blockage by speaker protection and DRC.
41         setNoiseAmplitude(0.02);
42     }
43 
44     /**
45      * @param frameData contains microphone data with sine signal feedback
46      * @param channelCount
47      */
processInputFrame(const float * frameData,int)48     result_code processInputFrame(const float *frameData, int /* channelCount */) override {
49         result_code result = RESULT_OK;
50 
51         float sample = frameData[getInputChannel()];
52         mInfiniteRecording.write(sample);
53 
54         if (transformSample(sample, mOutputPhase)) {
55             resetAccumulator();
56             // Analyze magnitude and phase on every period.
57             double diff = abs(mPhaseOffset - mPreviousPhaseOffset);
58             if (diff < mPhaseTolerance) {
59                 mMaxMagnitude = std::max(mMagnitude, mMaxMagnitude);
60             }
61             mPreviousPhaseOffset = mPhaseOffset;
62         }
63         return result;
64     }
65 
analyze()66     std::string analyze() override {
67         std::stringstream report;
68         report << "DataPathAnalyzer ------------------\n";
69         report << LOOPBACK_RESULT_TAG "sine.magnitude     = " << std::setw(8)
70                << mMagnitude << "\n";
71         report << LOOPBACK_RESULT_TAG "frames.accumulated = " << std::setw(8)
72                << mFramesAccumulated << "\n";
73         report << LOOPBACK_RESULT_TAG "sine.period        = " << std::setw(8)
74                << mSinePeriod << "\n";
75         return report.str();
76     }
77 
reset()78     void reset() override {
79         BaseSineAnalyzer::reset();
80         mPreviousPhaseOffset = 999.0; // Arbitrary high offset to prevent early lock.
81         mMaxMagnitude = 0.0;
82     }
83 
getMaxMagnitude()84     double getMaxMagnitude() {
85         return mMaxMagnitude;
86     }
87 
88 private:
89     double  mPreviousPhaseOffset = 0.0;
90     double  mPhaseTolerance = 2 * M_PI  / 48;
91     double  mMaxMagnitude = 0.0;
92 };
93 #endif // ANALYZER_DATA_PATH_ANALYZER_H
94