• 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.05);
42     }
43 
44     /**
45      * @param frameData contains microphone data with sine signal feedback
46      * @param channelCount
47      */
processInputFrame(float * frameData,int)48     result_code processInputFrame(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         }
57 
58         // Update MaxMagnitude if we are locked.
59         double diff = abs(mPhaseOffset - mPreviousPhaseOffset);
60         if (diff < mPhaseTolerance) {
61             mMaxMagnitude = std::max(mMagnitude, mMaxMagnitude);
62         }
63         mPreviousPhaseOffset = mPhaseOffset;
64         return result;
65     }
66 
analyze()67     std::string analyze() override {
68         std::stringstream report;
69         report << "DataPathAnalyzer ------------------\n";
70         report << LOOPBACK_RESULT_TAG "sine.magnitude     = " << std::setw(8)
71                << mMagnitude << "\n";
72         report << LOOPBACK_RESULT_TAG "frames.accumulated = " << std::setw(8)
73                << mFramesAccumulated << "\n";
74         report << LOOPBACK_RESULT_TAG "sine.period        = " << std::setw(8)
75                << mSinePeriod << "\n";
76         return report.str();
77     }
78 
reset()79     void reset() override {
80         BaseSineAnalyzer::reset();
81         mPreviousPhaseOffset = 999.0; // Arbitrary high offset to prevent early lock.
82         mMaxMagnitude = 0.0;
83     }
84 
getMaxMagnitude()85     double getMaxMagnitude() {
86         return mMaxMagnitude;
87     }
88 
89 private:
90     double  mPreviousPhaseOffset = 0.0;
91     double  mPhaseTolerance = 2 * M_PI  / 48;
92     double  mMaxMagnitude = 0.0;
93 };
94 #endif // ANALYZER_DATA_PATH_ANALYZER_H
95