Merge "Cleanup/enhance AEC test. Standardize ReportLog keys."
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/audio/AudioAEC.java b/apps/CtsVerifier/src/com/android/cts/verifier/audio/AudioAEC.java
index 06340e3..fe898b0 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/audio/AudioAEC.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/audio/AudioAEC.java
@@ -17,8 +17,11 @@
 package com.android.cts.verifier.audio;
 
 import android.content.Context;
-import android.media.*;
 import android.media.audiofx.AcousticEchoCanceler;
+import android.media.AudioManager;
+import android.media.AudioTrack;
+import android.media.AudioRecord;
+import android.media.MediaRecorder;
 import android.os.Bundle;
 import android.util.Log;
 import android.view.View;
@@ -26,130 +29,74 @@
 import android.widget.LinearLayout;
 import android.widget.ProgressBar;
 import android.widget.TextView;
+
 import com.android.compatibility.common.util.ResultType;
 import com.android.compatibility.common.util.ResultUnit;
-import com.android.cts.verifier.CtsVerifierReportLog;
-import com.android.cts.verifier.R;
+import com.android.cts.verifier.audio.soundio.SoundPlayerObject;
+import com.android.cts.verifier.audio.soundio.SoundRecorderObject;
 import com.android.cts.verifier.audio.wavelib.*;
+import com.android.cts.verifier.CtsVerifierReportLog;
+import com.android.cts.verifier.PassFailButtons;
+import com.android.cts.verifier.R;
+
+import static com.android.cts.verifier.TestListActivity.sCurrentDisplayMode;
+import static com.android.cts.verifier.TestListAdapter.setTestNameSuffix;
 
 public class AudioAEC extends AudioFrequencyActivity implements View.OnClickListener {
     private static final String TAG = "AudioAEC";
 
-    private static final int TEST_NONE = -1;
+    // Test State
     private static final int TEST_AEC = 0;
-    private static final int TEST_COUNT = 1;
-    private static final float MAX_VAL = (float)(1 << 15);
 
-    private int mCurrentTest = TEST_NONE;
+    // UI
     private LinearLayout mLinearLayout;
     private Button mButtonTest;
     private Button mButtonMandatoryYes;
     private Button mButtonMandatoryNo;
     private ProgressBar mProgress;
     private TextView mResultTest;
-    private boolean mTestAECPassed;
-    private SoundPlayerObject mSPlayer;
-    private SoundRecorderObject mSRecorder;
-    private AcousticEchoCanceler mAec;
 
-    private boolean mMandatory = true;
-
+    // Sound IO
     private final int mBlockSizeSamples = 4096;
     private final int mSamplingRate = 48000;
     private final int mSelectedRecordSource = MediaRecorder.AudioSource.VOICE_COMMUNICATION;
 
+    private SoundPlayerObject mSPlayer;
+    private SoundRecorderObject mSRecorder;
+
+    // Test Results
+    private boolean mMandatory = true;
+    private boolean mTestAECPassed;
+
     private final int TEST_DURATION_MS = 8000;
     private final int SHOT_FREQUENCY_MS = 200;
     private final int CORRELATION_DURATION_MS = TEST_DURATION_MS - 3000;
     private final int SHOT_COUNT_CORRELATION = CORRELATION_DURATION_MS/SHOT_FREQUENCY_MS;
     private final int SHOT_COUNT = TEST_DURATION_MS/SHOT_FREQUENCY_MS;
+
     private final float MIN_RMS_DB = -60.0f; //dB
     private final float MIN_RMS_VAL = (float)Math.pow(10,(MIN_RMS_DB/20));
 
     private final double TEST_THRESHOLD_AEC_ON = 0.5;
     private final double TEST_THRESHOLD_AEC_OFF = 0.6;
-    private RmsHelper mRMSRecorder1 = new RmsHelper(mBlockSizeSamples, SHOT_COUNT);
-    private RmsHelper mRMSRecorder2 = new RmsHelper(mBlockSizeSamples, SHOT_COUNT);
+    private RmsHelper mRMSRecorder1 =
+            new RmsHelper(mBlockSizeSamples, SHOT_COUNT, MIN_RMS_DB, MIN_RMS_VAL);
+    private RmsHelper mRMSRecorder2 =
+            new RmsHelper(mBlockSizeSamples, SHOT_COUNT, MIN_RMS_DB, MIN_RMS_VAL);
 
-    private RmsHelper mRMSPlayer1 = new RmsHelper(mBlockSizeSamples, SHOT_COUNT);
-    private RmsHelper mRMSPlayer2 = new RmsHelper(mBlockSizeSamples, SHOT_COUNT);
+    private RmsHelper mRMSPlayer1 =
+            new RmsHelper(mBlockSizeSamples, SHOT_COUNT, MIN_RMS_DB, MIN_RMS_VAL);
+    private RmsHelper mRMSPlayer2 =
+            new RmsHelper(mBlockSizeSamples, SHOT_COUNT, MIN_RMS_DB, MIN_RMS_VAL);
 
     private Thread mTestThread;
 
-    //RMS helpers
-    public class RmsHelper {
-        private double mRmsCurrent;
-        public int mBlockSize;
-        private int mShoutCount;
-        public boolean mRunning = false;
-
-        private short[] mAudioShortArray;
-
-        private DspBufferDouble mRmsSnapshots;
-        private int mShotIndex;
-
-        public RmsHelper(int blockSize, int shotCount) {
-            mBlockSize = blockSize;
-            mShoutCount = shotCount;
-            reset();
-        }
-
-        public void reset() {
-            mAudioShortArray = new short[mBlockSize];
-            mRmsSnapshots = new DspBufferDouble(mShoutCount);
-            mShotIndex = 0;
-            mRmsCurrent = 0;
-            mRunning = false;
-        }
-
-        public void captureShot() {
-            if (mShotIndex >= 0 && mShotIndex < mRmsSnapshots.getSize()) {
-                mRmsSnapshots.setValue(mShotIndex++, mRmsCurrent);
-            }
-        }
-
-        public void setRunning(boolean running) {
-            mRunning = running;
-        }
-
-        public double getRmsCurrent() {
-            return mRmsCurrent;
-        }
-
-        public DspBufferDouble getRmsSnapshots() {
-            return mRmsSnapshots;
-        }
-
-        public boolean updateRms(PipeShort pipe, int channelCount, int channel) {
-            if (mRunning) {
-                int samplesAvailable = pipe.availableToRead();
-                while (samplesAvailable >= mBlockSize) {
-                    pipe.read(mAudioShortArray, 0, mBlockSize);
-
-                    double rmsTempSum = 0;
-                    int count = 0;
-                    for (int i = channel; i < mBlockSize; i += channelCount) {
-                        float value = mAudioShortArray[i] / MAX_VAL;
-
-                        rmsTempSum += value * value;
-                        count++;
-                    }
-                    float rms = count > 0 ? (float)Math.sqrt(rmsTempSum / count) : 0f;
-                    if (rms < MIN_RMS_VAL) {
-                        rms = MIN_RMS_VAL;
-                    }
-
-                    double alpha = 0.9;
-                    double total_rms = rms * alpha + mRmsCurrent * (1.0f - alpha);
-                    mRmsCurrent = total_rms;
-
-                    samplesAvailable = pipe.availableToRead();
-                }
-                return true;
-            }
-            return false;
-        }
-    }
+    // ReportLog schema
+    private static final String SECTION_AEC = "aec_activity";
+    private static final String KEY_AEC_MANDATORY = "aec_mandatory";
+    private static final String KEY_AEC_MAX_WITH = "max_with_aec";
+    private static final String KEY_AEC_MAX_WITHOUT = "max_without_aec";
+    private static final String KEY_AEC_RESULT = "result_string";
 
     //compute Acoustic Coupling Factor
     private double computeAcousticCouplingFactor(DspBufferDouble buffRmsPlayer,
@@ -196,7 +143,7 @@
         super.onCreate(savedInstanceState);
         setContentView(R.layout.audio_aec_activity);
 
-        //
+        // "AEC Mandatory" Buttons
         mLinearLayout = (LinearLayout)findViewById(R.id.audio_aec_test_layout);
         mButtonMandatoryYes = (Button) findViewById(R.id.audio_aec_mandatory_yes);
         mButtonMandatoryYes.setOnClickListener(this);
@@ -204,16 +151,15 @@
         mButtonMandatoryNo.setOnClickListener(this);
         enableUILayout(mLinearLayout, false);
 
-        // Test
+        // Test Button
         mButtonTest = (Button) findViewById(R.id.audio_aec_button_test);
         mButtonTest.setOnClickListener(this);
         mProgress = (ProgressBar) findViewById(R.id.audio_aec_test_progress_bar);
         mResultTest = (TextView) findViewById(R.id.audio_aec_test_result);
 
-        showView(mProgress, false);
+        showProgressIndicator(false);
 
         mSPlayer = new SoundPlayerObject(false, mBlockSizeSamples) {
-
             @Override
             public void periodicNotification(AudioTrack track) {
                 int channelCount = getChannelCount();
@@ -233,12 +179,11 @@
 
         setPassFailButtonClickListeners();
         getPassButton().setEnabled(false);
-        setInfoResources(R.string.audio_aec_test,
-                R.string.audio_aec_info, -1);
+        setInfoResources(R.string.audio_aec_test, R.string.audio_aec_info, -1);
     }
 
-    private void showView(View v, boolean show) {
-        v.setVisibility(show ? View.VISIBLE : View.INVISIBLE);
+    private void showProgressIndicator(boolean show) {
+        mProgress.setVisibility(show ? View.VISIBLE : View.INVISIBLE);
     }
 
     @Override
@@ -263,7 +208,6 @@
                 mMandatory = true;
                 Log.v(TAG,"AEC marked as mandatory");
                 break;
-
         }
     }
 
@@ -273,7 +217,11 @@
             Log.v(TAG,"test Thread already running.");
             return;
         }
+
         mTestThread = new Thread(new AudioTestRunner(TAG, TEST_AEC, mMessageHandler) {
+            // AcousticEchoCanceler
+            private AcousticEchoCanceler mAec;
+
             public void run() {
                 super.run();
 
@@ -489,28 +437,38 @@
                                   String msg) {
 
         CtsVerifierReportLog reportLog = getReportLog();
-        reportLog.addValue("AEC_mandatory",
+        reportLog.addValue(KEY_AEC_MANDATORY,
                 aecMandatory,
                 ResultType.NEUTRAL,
                 ResultUnit.NONE);
 
-        reportLog.addValue("max_with_AEC",
+        reportLog.addValue(KEY_AEC_MAX_WITH,
                 maxAEC,
                 ResultType.LOWER_BETTER,
                 ResultUnit.SCORE);
 
-        reportLog.addValue("max_without_AEC",
+        reportLog.addValue(KEY_AEC_MAX_WITHOUT,
                 maxNoAEC,
                 ResultType.HIGHER_BETTER,
                 ResultUnit.SCORE);
 
-        reportLog.addValue("result_string",
+        reportLog.addValue(KEY_AEC_RESULT,
                 msg,
                 ResultType.NEUTRAL,
                 ResultUnit.NONE);
     }
 
-    @Override // PassFailButtons
+    //
+    // PassFailButtons Overrides
+    //
+    public String getReportFileName() { return PassFailButtons.AUDIO_TESTS_REPORT_LOG_NAME; }
+
+    @Override
+    public final String getReportSectionName() {
+        return setTestNameSuffix(sCurrentDisplayMode, SECTION_AEC);
+    }
+
+    @Override
     public void recordTestResults() {
         getReportLog().submit();
     }
@@ -522,7 +480,7 @@
         public void testStarted(int testId, String str) {
             super.testStarted(testId, str);
             Log.v(TAG, "Test Started! " + testId + " str:"+str);
-            showView(mProgress, true);
+            showProgressIndicator(true);
             mTestAECPassed = false;
             getPassButton().setEnabled(false);
             mResultTest.setText("test in progress..");
@@ -539,7 +497,7 @@
         public void testEndedOk(int testId, String str) {
             super.testEndedOk(testId, str);
             Log.v(TAG, "Test EndedOk. " + testId + " str:"+str);
-            showView(mProgress, false);
+            showProgressIndicator(false);
             mResultTest.setText("test completed. " + str);
             if (mTestAECPassed) {
                 getPassButton().setEnabled(true);;
@@ -550,7 +508,7 @@
         public void testEndedError(int testId, String str) {
             super.testEndedError(testId, str);
             Log.v(TAG, "Test EndedError. " + testId + " str:"+str);
-            showView(mProgress, false);
+            showProgressIndicator(false);
             mResultTest.setText("test failed. " + str);
         }
     };
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/audio/AudioFrequencyLineActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/audio/AudioFrequencyLineActivity.java
index 22e2c7d..654506d 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/audio/AudioFrequencyLineActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/audio/AudioFrequencyLineActivity.java
@@ -18,6 +18,7 @@
 
 import com.android.cts.verifier.CtsVerifierReportLog;
 import com.android.cts.verifier.R;
+import com.android.cts.verifier.audio.soundio.SoundPlayerObject;
 import com.android.cts.verifier.audio.wavelib.*;
 import com.android.compatibility.common.util.ResultType;
 import com.android.compatibility.common.util.ResultUnit;
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/audio/AudioFrequencyMicActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/audio/AudioFrequencyMicActivity.java
index 72f5ae1..f46fe8c 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/audio/AudioFrequencyMicActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/audio/AudioFrequencyMicActivity.java
@@ -19,6 +19,7 @@
 import com.android.cts.verifier.R;
 
 import com.android.cts.verifier.CtsVerifierReportLog;
+import com.android.cts.verifier.audio.soundio.SoundPlayerObject;
 import com.android.cts.verifier.audio.wavelib.*;
 import com.android.compatibility.common.util.ResultType;
 import com.android.compatibility.common.util.ResultUnit;
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/audio/AudioFrequencySpeakerActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/audio/AudioFrequencySpeakerActivity.java
index 3788048..deb1887 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/audio/AudioFrequencySpeakerActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/audio/AudioFrequencySpeakerActivity.java
@@ -18,6 +18,7 @@
 
 import com.android.cts.verifier.CtsVerifierReportLog;
 import com.android.cts.verifier.R;
+import com.android.cts.verifier.audio.soundio.SoundPlayerObject;
 import com.android.cts.verifier.audio.wavelib.*;
 import com.android.compatibility.common.util.ResultType;
 import com.android.compatibility.common.util.ResultUnit;
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/audio/AudioFrequencyUnprocessedActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/audio/AudioFrequencyUnprocessedActivity.java
index 5509501..182d8be 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/audio/AudioFrequencyUnprocessedActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/audio/AudioFrequencyUnprocessedActivity.java
@@ -18,6 +18,7 @@
 
 import com.android.cts.verifier.CtsVerifierReportLog;
 import com.android.cts.verifier.R;
+import com.android.cts.verifier.audio.soundio.SoundPlayerObject;
 import com.android.cts.verifier.audio.wavelib.*;
 import com.android.compatibility.common.util.ResultType;
 import com.android.compatibility.common.util.ResultUnit;
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/audio/AudioFrequencyVoiceRecognitionActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/audio/AudioFrequencyVoiceRecognitionActivity.java
index 5ed51e3..2435da5 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/audio/AudioFrequencyVoiceRecognitionActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/audio/AudioFrequencyVoiceRecognitionActivity.java
@@ -18,6 +18,8 @@
 
 import com.android.cts.verifier.CtsVerifierReportLog;
 import com.android.cts.verifier.R;
+import com.android.cts.verifier.audio.soundio.SoundPlayerObject;
+import com.android.cts.verifier.audio.soundio.SoundRecorderObject;
 import com.android.cts.verifier.audio.wavelib.*;
 import com.android.compatibility.common.util.ResultType;
 import com.android.compatibility.common.util.ResultUnit;
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/audio/HifiUltrasoundSpeakerTestActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/audio/HifiUltrasoundSpeakerTestActivity.java
index 01802a4..dcac83ab 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/audio/HifiUltrasoundSpeakerTestActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/audio/HifiUltrasoundSpeakerTestActivity.java
@@ -37,6 +37,10 @@
 import android.widget.TextView;
 import java.util.Arrays;
 
+import com.android.cts.verifier.audio.audiolib.AudioCommon;
+import com.android.cts.verifier.audio.soundio.SoundGenerator;
+import com.android.cts.verifier.audio.wavlib.WavAnalyzer;
+
 import com.androidplot.xy.PointLabelFormatter;
 import com.androidplot.xy.LineAndPointFormatter;
 import com.androidplot.xy.SimpleXYSeries;
@@ -181,11 +185,12 @@
               @Override
               public void run() {
                 Double recordingDuration_millis = new Double(1000 * (2.5
-                    + Common.PREFIX_LENGTH_S
-                    + Common.PAUSE_BEFORE_PREFIX_DURATION_S
-                    + Common.PAUSE_AFTER_PREFIX_DURATION_S
-                    + Common.PIP_NUM * (Common.PIP_DURATION_S + Common.PAUSE_DURATION_S)
-                    * Common.REPETITIONS));
+                    + AudioCommon.PREFIX_LENGTH_S
+                    + AudioCommon.PAUSE_BEFORE_PREFIX_DURATION_S
+                    + AudioCommon.PAUSE_AFTER_PREFIX_DURATION_S
+                    + AudioCommon.PIP_NUM
+                        * (AudioCommon.PIP_DURATION_S + AudioCommon.PAUSE_DURATION_S)
+                    * AudioCommon.REPETITIONS));
                 Log.d(TAG, "Recording for " + recordingDuration_millis + "ms");
                 try {
                   Thread.sleep(recordingDuration_millis.intValue());
@@ -262,17 +267,17 @@
     XYPlot plot = (XYPlot) popupView.findViewById(R.id.responseChart);
     plot.setDomainStep(XYStepMode.INCREMENT_BY_VAL, 2000);
 
-    Double[] frequencies = new Double[Common.PIP_NUM];
-    for (int i = 0; i < Common.PIP_NUM; i++) {
-      frequencies[i] = new Double(Common.FREQUENCIES_ORIGINAL[i]);
+    Double[] frequencies = new Double[AudioCommon.PIP_NUM];
+    for (int i = 0; i < AudioCommon.PIP_NUM; i++) {
+      frequencies[i] = new Double(AudioCommon.FREQUENCIES_ORIGINAL[i]);
     }
 
     if (wavAnalyzerTask != null) {
 
       double[][] power = wavAnalyzerTask.getPower();
-      for(int i = 0; i < Common.REPETITIONS; i++) {
-        Double[] powerWrap = new Double[Common.PIP_NUM];
-        for (int j = 0; j < Common.PIP_NUM; j++) {
+      for(int i = 0; i < AudioCommon.REPETITIONS; i++) {
+        Double[] powerWrap = new Double[AudioCommon.PIP_NUM];
+        for (int j = 0; j < AudioCommon.PIP_NUM; j++) {
           powerWrap[j] = new Double(10 * Math.log10(power[j][i]));
         }
         XYSeries series = new SimpleXYSeries(
@@ -287,8 +292,8 @@
       }
 
       double[] noiseDB = wavAnalyzerTask.getNoiseDB();
-      Double[] noiseDBWrap = new Double[Common.PIP_NUM];
-      for (int i = 0; i < Common.PIP_NUM; i++) {
+      Double[] noiseDBWrap = new Double[AudioCommon.PIP_NUM];
+      for (int i = 0; i < AudioCommon.PIP_NUM; i++) {
         noiseDBWrap[i] = new Double(noiseDB[i]);
       }
 
@@ -303,8 +308,8 @@
       plot.addSeries(noiseSeries, noiseSeriesFormat);
 
       double[] dB = wavAnalyzerTask.getDB();
-      Double[] dBWrap = new Double[Common.PIP_NUM];
-      for (int i = 0; i < Common.PIP_NUM; i++) {
+      Double[] dBWrap = new Double[AudioCommon.PIP_NUM];
+      for (int i = 0; i < AudioCommon.PIP_NUM; i++) {
         dBWrap[i] = new Double(dB[i]);
       }
 
@@ -318,7 +323,7 @@
           R.xml.ultrasound_line_formatter_median);
       plot.addSeries(series, seriesFormat);
 
-      Double[] passX = new Double[] {Common.MIN_FREQUENCY_HZ, Common.MAX_FREQUENCY_HZ};
+      Double[] passX = new Double[] {AudioCommon.MIN_FREQUENCY_HZ, AudioCommon.MAX_FREQUENCY_HZ};
       Double[] passY = new Double[] {wavAnalyzerTask.getThreshold(), wavAnalyzerTask.getThreshold()};
       XYSeries passSeries = new SimpleXYSeries(
           Arrays.asList(passX), Arrays.asList(passY), "passing");
@@ -334,7 +339,7 @@
    * Plays the generated pips.
    */
   private void play() {
-    play(SoundGenerator.getInstance().getByte(), Common.PLAYING_SAMPLE_RATE_HZ);
+    play(SoundGenerator.getInstance().getByte(), AudioCommon.PLAYING_SAMPLE_RATE_HZ);
   }
 
   /**
@@ -364,7 +369,7 @@
     WavAnalyzer wavAnalyzer;
 
     public WavAnalyzerTask(byte[] recording) {
-      wavAnalyzer = new WavAnalyzer(recording, Common.RECORDING_SAMPLE_RATE_HZ,
+      wavAnalyzer = new WavAnalyzer(recording, AudioCommon.RECORDING_SAMPLE_RATE_HZ,
           WavAnalyzerTask.this);
     }
 
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/audio/HifiUltrasoundTestActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/audio/HifiUltrasoundTestActivity.java
index f5e4271..3d5688d 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/audio/HifiUltrasoundTestActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/audio/HifiUltrasoundTestActivity.java
@@ -37,6 +37,10 @@
 import android.widget.TextView;
 import java.util.Arrays;
 
+import com.android.cts.verifier.audio.audiolib.AudioCommon;
+import com.android.cts.verifier.audio.soundio.SoundGenerator;
+import com.android.cts.verifier.audio.wavlib.WavAnalyzer;
+
 import com.androidplot.xy.PointLabelFormatter;
 import com.androidplot.xy.LineAndPointFormatter;
 import com.androidplot.xy.SimpleXYSeries;
@@ -161,11 +165,11 @@
               @Override
               public void run() {
                 Double recordingDuration_millis = new Double(1000 * (2.5
-                    + Common.PREFIX_LENGTH_S
-                    + Common.PAUSE_BEFORE_PREFIX_DURATION_S
-                    + Common.PAUSE_AFTER_PREFIX_DURATION_S
-                    + Common.PIP_NUM * (Common.PIP_DURATION_S + Common.PAUSE_DURATION_S)
-                    * Common.REPETITIONS));
+                    + AudioCommon.PREFIX_LENGTH_S
+                    + AudioCommon.PAUSE_BEFORE_PREFIX_DURATION_S
+                    + AudioCommon.PAUSE_AFTER_PREFIX_DURATION_S
+                    + AudioCommon.PIP_NUM * (AudioCommon.PIP_DURATION_S + AudioCommon.PAUSE_DURATION_S)
+                    * AudioCommon.REPETITIONS));
                 Log.d(TAG, "Recording for " + recordingDuration_millis + "ms");
                 try {
                   Thread.sleep(recordingDuration_millis.intValue());
@@ -221,18 +225,18 @@
     XYPlot plot = (XYPlot) popupView.findViewById(R.id.responseChart);
     plot.setDomainStep(XYStepMode.INCREMENT_BY_VAL, 2000);
 
-    Double[] frequencies = new Double[Common.PIP_NUM];
-    for (int i = 0; i < Common.PIP_NUM; i++) {
-      frequencies[i] = new Double(Common.FREQUENCIES_ORIGINAL[i]);
+    Double[] frequencies = new Double[AudioCommon.PIP_NUM];
+    for (int i = 0; i < AudioCommon.PIP_NUM; i++) {
+      frequencies[i] = new Double(AudioCommon.FREQUENCIES_ORIGINAL[i]);
     }
 
     if (wavAnalyzerTask != null && wavAnalyzerTask.getPower() != null &&
         wavAnalyzerTask.getNoiseDB() != null && wavAnalyzerTask.getDB() != null) {
 
       double[][] power = wavAnalyzerTask.getPower();
-      for(int i = 0; i < Common.REPETITIONS; i++) {
-        Double[] powerWrap = new Double[Common.PIP_NUM];
-        for (int j = 0; j < Common.PIP_NUM; j++) {
+      for(int i = 0; i < AudioCommon.REPETITIONS; i++) {
+        Double[] powerWrap = new Double[AudioCommon.PIP_NUM];
+        for (int j = 0; j < AudioCommon.PIP_NUM; j++) {
           powerWrap[j] = new Double(10 * Math.log10(power[j][i]));
         }
         XYSeries series = new SimpleXYSeries(
@@ -247,8 +251,8 @@
       }
 
       double[] noiseDB = wavAnalyzerTask.getNoiseDB();
-      Double[] noiseDBWrap = new Double[Common.PIP_NUM];
-      for (int i = 0; i < Common.PIP_NUM; i++) {
+      Double[] noiseDBWrap = new Double[AudioCommon.PIP_NUM];
+      for (int i = 0; i < AudioCommon.PIP_NUM; i++) {
         noiseDBWrap[i] = new Double(noiseDB[i]);
       }
 
@@ -263,8 +267,8 @@
       plot.addSeries(noiseSeries, noiseSeriesFormat);
 
       double[] dB = wavAnalyzerTask.getDB();
-      Double[] dBWrap = new Double[Common.PIP_NUM];
-      for (int i = 0; i < Common.PIP_NUM; i++) {
+      Double[] dBWrap = new Double[AudioCommon.PIP_NUM];
+      for (int i = 0; i < AudioCommon.PIP_NUM; i++) {
         dBWrap[i] = new Double(dB[i]);
       }
 
@@ -278,7 +282,7 @@
           R.xml.ultrasound_line_formatter_median);
       plot.addSeries(series, seriesFormat);
 
-      Double[] passX = new Double[] {Common.MIN_FREQUENCY_HZ, Common.MAX_FREQUENCY_HZ};
+      Double[] passX = new Double[] {AudioCommon.MIN_FREQUENCY_HZ, AudioCommon.MAX_FREQUENCY_HZ};
       Double[] passY = new Double[] {wavAnalyzerTask.getThreshold(), wavAnalyzerTask.getThreshold()};
       XYSeries passSeries = new SimpleXYSeries(
           Arrays.asList(passX), Arrays.asList(passY), "passing");
@@ -294,7 +298,7 @@
    * Plays the generated pips.
    */
   private void play() {
-    play(SoundGenerator.getInstance().getByte(), Common.PLAYING_SAMPLE_RATE_HZ);
+    play(SoundGenerator.getInstance().getByte(), AudioCommon.PLAYING_SAMPLE_RATE_HZ);
   }
 
   /**
@@ -324,7 +328,7 @@
     WavAnalyzer wavAnalyzer;
 
     public WavAnalyzerTask(byte[] recording) {
-      wavAnalyzer = new WavAnalyzer(recording, Common.RECORDING_SAMPLE_RATE_HZ,
+      wavAnalyzer = new WavAnalyzer(recording, AudioCommon.RECORDING_SAMPLE_RATE_HZ,
           WavAnalyzerTask.this);
     }
 
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/audio/SoundGenerator.java b/apps/CtsVerifier/src/com/android/cts/verifier/audio/SoundGenerator.java
deleted file mode 100644
index 0ad9371..0000000
--- a/apps/CtsVerifier/src/com/android/cts/verifier/audio/SoundGenerator.java
+++ /dev/null
@@ -1,81 +0,0 @@
-package com.android.cts.verifier.audio;
-
-/**
- * Sound generator.
- */
-public class SoundGenerator {
-
-  private static SoundGenerator instance;
-
-  private final byte[] generatedSound;
-  private final double[] sample;
-
-  private SoundGenerator() {
-    // Initialize sample.
-    int pipNum = Common.PIP_NUM;
-    int prefixTotalLength = Util.toLength(Common.PREFIX_LENGTH_S, Common.PLAYING_SAMPLE_RATE_HZ)
-        + Util.toLength(Common.PAUSE_BEFORE_PREFIX_DURATION_S, Common.PLAYING_SAMPLE_RATE_HZ)
-        + Util.toLength(Common.PAUSE_AFTER_PREFIX_DURATION_S, Common.PLAYING_SAMPLE_RATE_HZ);
-    int repetitionLength = pipNum * Util.toLength(
-        Common.PIP_DURATION_S + Common.PAUSE_DURATION_S, Common.PLAYING_SAMPLE_RATE_HZ);
-    int sampleLength = prefixTotalLength + Common.REPETITIONS * repetitionLength;
-    sample = new double[sampleLength];
-
-    // Fill sample with prefix.
-    System.arraycopy(Common.PREFIX_FOR_PLAYER, 0, sample,
-        Util.toLength(Common.PAUSE_BEFORE_PREFIX_DURATION_S, Common.PLAYING_SAMPLE_RATE_HZ),
-        Common.PREFIX_FOR_PLAYER.length);
-
-    // Fill the sample.
-    for (int i = 0; i < pipNum * Common.REPETITIONS; i++) {
-      double[] pip = getPip(Common.WINDOW_FOR_PLAYER, Common.FREQUENCIES[i]);
-      System.arraycopy(pip, 0, sample,
-          prefixTotalLength + i * Util.toLength(
-              Common.PIP_DURATION_S + Common.PAUSE_DURATION_S, Common.PLAYING_SAMPLE_RATE_HZ),
-          pip.length);
-    }
-
-    // Convert sample to byte.
-    generatedSound = new byte[2 * sample.length];
-    int i = 0;
-    for (double dVal : sample) {
-      short val = (short) ((dVal * 32767));
-      generatedSound[i++] = (byte) (val & 0x00ff);
-      generatedSound[i++] = (byte) ((val & 0xff00) >>> 8);
-    }
-  }
-
-  public static SoundGenerator getInstance() {
-    if (instance == null) {
-      instance = new SoundGenerator();
-    }
-    return instance;
-  }
-
-  /**
-   * Gets a pip sample.
-   */
-  private static double[] getPip(double[] window, double frequency) {
-    int pipArrayLength = window.length;
-    double[] pipArray = new double[pipArrayLength];
-    double radPerSample = 2 * Math.PI / (Common.PLAYING_SAMPLE_RATE_HZ / frequency);
-    for (int i = 0; i < pipArrayLength; i++) {
-      pipArray[i] = window[i] * Math.sin(i * radPerSample);
-    }
-    return pipArray;
-  }
-
-  /**
-   * Get generated sound in byte[].
-   */
-  public byte[] getByte() {
-    return generatedSound;
-  }
-
-  /**
-   * Get sample in double[].
-   */
-  public double[] getSample() {
-    return sample;
-  }
-}
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/audio/Common.java b/apps/CtsVerifier/src/com/android/cts/verifier/audio/audiolib/AudioCommon.java
similarity index 90%
rename from apps/CtsVerifier/src/com/android/cts/verifier/audio/Common.java
rename to apps/CtsVerifier/src/com/android/cts/verifier/audio/audiolib/AudioCommon.java
index df7460a..ba5e39b2 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/audio/Common.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/audio/audiolib/AudioCommon.java
@@ -1,15 +1,18 @@
-package com.android.cts.verifier.audio;
+package com.android.cts.verifier.audio.audiolib;
 
 import android.media.AudioManager;
 import android.media.AudioTrack;
 
+import com.android.cts.verifier.audio.AudioRecordHelper;
+import com.android.cts.verifier.audio.Util;
+
 import java.util.ArrayList;
 import java.util.Random;
 
 /**
  * This class stores common constants and methods.
  */
-public class Common {
+public class AudioCommon {
 
   public static final int RECORDING_SAMPLE_RATE_HZ
       = AudioRecordHelper.getInstance().getSampleRate();
@@ -95,7 +98,7 @@
   private static double[] frequencies() {
     double[] originalFrequencies = originalFrequencies();
 
-    double[] randomFrequencies = new double[Common.REPETITIONS * originalFrequencies.length];
+    double[] randomFrequencies = new double[AudioCommon.REPETITIONS * originalFrequencies.length];
     for (int i = 0; i < REPETITIONS * originalFrequencies.length; i++) {
       randomFrequencies[i] = originalFrequencies[ORDER[i] % originalFrequencies.length];
     }
@@ -108,13 +111,13 @@
    */
   private static double[] originalFrequencies() {
     ArrayList<Double> frequencies = new ArrayList<Double>();
-    double frequency = Common.MIN_FREQUENCY_HZ;
-    while (frequency <= Common.MAX_FREQUENCY_HZ) {
+    double frequency = AudioCommon.MIN_FREQUENCY_HZ;
+    while (frequency <= AudioCommon.MAX_FREQUENCY_HZ) {
       frequencies.add(new Double(frequency));
       if ((frequency >= 18500) && (frequency < 20000)) {
-        frequency += Common.FREQUENCY_STEP_HZ;
+        frequency += AudioCommon.FREQUENCY_STEP_HZ;
       } else {
-        frequency += Common.FREQUENCY_STEP_HZ * 10;
+        frequency += AudioCommon.FREQUENCY_STEP_HZ * 10;
       }
     }
     Double[] frequenciesArray = frequencies.toArray(new Double[frequencies.size()]);
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/audio/soundio/SoundGenerator.java b/apps/CtsVerifier/src/com/android/cts/verifier/audio/soundio/SoundGenerator.java
new file mode 100644
index 0000000..3ea5790
--- /dev/null
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/audio/soundio/SoundGenerator.java
@@ -0,0 +1,105 @@
+/*
+ * Copyright (C) 2021 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.
+ */
+package com.android.cts.verifier.audio.soundio;
+
+import com.android.cts.verifier.audio.audiolib.AudioCommon;
+import com.android.cts.verifier.audio.Util;
+
+/**
+ * Sound generator.
+ */
+public class SoundGenerator {
+
+  private static SoundGenerator instance;
+
+  private final byte[] generatedSound;
+  private final double[] sample;
+
+  private SoundGenerator() {
+    // Initialize sample.
+    int pipNum = AudioCommon.PIP_NUM;
+    int prefixTotalLength =
+          Util.toLength(AudioCommon.PREFIX_LENGTH_S, AudioCommon.PLAYING_SAMPLE_RATE_HZ)
+        + Util.toLength(AudioCommon.PAUSE_BEFORE_PREFIX_DURATION_S,
+                    AudioCommon.PLAYING_SAMPLE_RATE_HZ)
+        + Util.toLength(AudioCommon.PAUSE_AFTER_PREFIX_DURATION_S,
+                    AudioCommon.PLAYING_SAMPLE_RATE_HZ);
+    int repetitionLength = pipNum * Util.toLength(
+        AudioCommon.PIP_DURATION_S + AudioCommon.PAUSE_DURATION_S,
+            AudioCommon.PLAYING_SAMPLE_RATE_HZ);
+    int sampleLength = prefixTotalLength + AudioCommon.REPETITIONS * repetitionLength;
+    sample = new double[sampleLength];
+
+    // Fill sample with prefix.
+    System.arraycopy(AudioCommon.PREFIX_FOR_PLAYER, 0, sample,
+        Util.toLength(AudioCommon.PAUSE_BEFORE_PREFIX_DURATION_S,
+                AudioCommon.PLAYING_SAMPLE_RATE_HZ),
+        AudioCommon.PREFIX_FOR_PLAYER.length);
+
+    // Fill the sample.
+    for (int i = 0; i < pipNum * AudioCommon.REPETITIONS; i++) {
+      double[] pip = getPip(AudioCommon.WINDOW_FOR_PLAYER, AudioCommon.FREQUENCIES[i]);
+      System.arraycopy(pip, 0, sample,
+          prefixTotalLength + i * Util.toLength(
+              AudioCommon.PIP_DURATION_S + AudioCommon.PAUSE_DURATION_S,
+                  AudioCommon.PLAYING_SAMPLE_RATE_HZ),
+          pip.length);
+    }
+
+    // Convert sample to byte.
+    generatedSound = new byte[2 * sample.length];
+    int i = 0;
+    for (double dVal : sample) {
+      short val = (short) ((dVal * 32767));
+      generatedSound[i++] = (byte) (val & 0x00ff);
+      generatedSound[i++] = (byte) ((val & 0xff00) >>> 8);
+    }
+  }
+
+  public static SoundGenerator getInstance() {
+    if (instance == null) {
+      instance = new SoundGenerator();
+    }
+    return instance;
+  }
+
+  /**
+   * Gets a pip sample.
+   */
+  private static double[] getPip(double[] window, double frequency) {
+    int pipArrayLength = window.length;
+    double[] pipArray = new double[pipArrayLength];
+    double radPerSample = 2 * Math.PI / (AudioCommon.PLAYING_SAMPLE_RATE_HZ / frequency);
+    for (int i = 0; i < pipArrayLength; i++) {
+      pipArray[i] = window[i] * Math.sin(i * radPerSample);
+    }
+    return pipArray;
+  }
+
+  /**
+   * Get generated sound in byte[].
+   */
+  public byte[] getByte() {
+    return generatedSound;
+  }
+
+  /**
+   * Get sample in double[].
+   */
+  public double[] getSample() {
+    return sample;
+  }
+}
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/audio/SoundPlayerObject.java b/apps/CtsVerifier/src/com/android/cts/verifier/audio/soundio/SoundPlayerObject.java
similarity index 99%
rename from apps/CtsVerifier/src/com/android/cts/verifier/audio/SoundPlayerObject.java
rename to apps/CtsVerifier/src/com/android/cts/verifier/audio/soundio/SoundPlayerObject.java
index 0d93dbb..156460b 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/audio/SoundPlayerObject.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/audio/soundio/SoundPlayerObject.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package com.android.cts.verifier.audio;
+package com.android.cts.verifier.audio.soundio;
 
 import android.content.Context;
 import android.media.AudioAttributes;
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/audio/SoundRecorderObject.java b/apps/CtsVerifier/src/com/android/cts/verifier/audio/soundio/SoundRecorderObject.java
similarity index 98%
rename from apps/CtsVerifier/src/com/android/cts/verifier/audio/SoundRecorderObject.java
rename to apps/CtsVerifier/src/com/android/cts/verifier/audio/soundio/SoundRecorderObject.java
index 8950ec5..d83a5dd 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/audio/SoundRecorderObject.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/audio/soundio/SoundRecorderObject.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package com.android.cts.verifier.audio;
+package com.android.cts.verifier.audio.soundio;
 
 import android.media.AudioFormat;
 import android.media.AudioRecord;
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/audio/wavelib/RmsHelper.java b/apps/CtsVerifier/src/com/android/cts/verifier/audio/wavelib/RmsHelper.java
new file mode 100644
index 0000000..71d3ec1
--- /dev/null
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/audio/wavelib/RmsHelper.java
@@ -0,0 +1,98 @@
+/*
+ * Copyright (C) 2021 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.
+ */
+package com.android.cts.verifier.audio.wavelib;
+
+public class RmsHelper {
+    private double mRmsCurrent;
+    public int mBlockSize;
+    private int mShoutCount;
+    public boolean mRunning = false;
+
+    private short[] mAudioShortArray;
+
+    private DspBufferDouble mRmsSnapshots;
+    private int mShotIndex;
+
+    private final float mMinRmsDb;
+    private final float mMinRmsVal;
+
+    private static final float MAX_VAL = (float)(1 << 15);
+
+    public RmsHelper(int blockSize, int shotCount, float minRmsDb, float minRmsVal) {
+        mBlockSize = blockSize;
+        mShoutCount = shotCount;
+        mMinRmsDb = minRmsDb;
+        mMinRmsVal = minRmsVal;
+
+        reset();
+    }
+
+    public void reset() {
+        mAudioShortArray = new short[mBlockSize];
+        mRmsSnapshots = new DspBufferDouble(mShoutCount);
+        mShotIndex = 0;
+        mRmsCurrent = 0;
+        mRunning = false;
+    }
+
+    public void captureShot() {
+        if (mShotIndex >= 0 && mShotIndex < mRmsSnapshots.getSize()) {
+            mRmsSnapshots.setValue(mShotIndex++, mRmsCurrent);
+        }
+    }
+
+    public void setRunning(boolean running) {
+        mRunning = running;
+    }
+
+    public double getRmsCurrent() {
+        return mRmsCurrent;
+    }
+
+    public DspBufferDouble getRmsSnapshots() {
+        return mRmsSnapshots;
+    }
+
+    public boolean updateRms(PipeShort pipe, int channelCount, int channel) {
+        if (mRunning) {
+            int samplesAvailable = pipe.availableToRead();
+            while (samplesAvailable >= mBlockSize) {
+                pipe.read(mAudioShortArray, 0, mBlockSize);
+
+                double rmsTempSum = 0;
+                int count = 0;
+                for (int i = channel; i < mBlockSize; i += channelCount) {
+                    float value = mAudioShortArray[i] / MAX_VAL;
+
+                    rmsTempSum += value * value;
+                    count++;
+                }
+                float rms = count > 0 ? (float)Math.sqrt(rmsTempSum / count) : 0f;
+                if (rms < mMinRmsVal) {
+                    rms = mMinRmsVal;
+                }
+
+                double alpha = 0.9;
+                double total_rms = rms * alpha + mRmsCurrent * (1.0f - alpha);
+                mRmsCurrent = total_rms;
+
+                samplesAvailable = pipe.availableToRead();
+            }
+            return true;
+        }
+        return false;
+    }
+}
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/audio/WavAnalyzer.java b/apps/CtsVerifier/src/com/android/cts/verifier/audio/wavelib/WavAnalyzer.java
similarity index 64%
rename from apps/CtsVerifier/src/com/android/cts/verifier/audio/WavAnalyzer.java
rename to apps/CtsVerifier/src/com/android/cts/verifier/audio/wavelib/WavAnalyzer.java
index b75c40b..6fdccb4 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/audio/WavAnalyzer.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/audio/wavelib/WavAnalyzer.java
@@ -1,4 +1,22 @@
-package com.android.cts.verifier.audio;
+/*
+ * Copyright (C) 2021 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.
+ */
+package com.android.cts.verifier.audio.wavlib;
+
+import com.android.cts.verifier.audio.audiolib.AudioCommon;
+import com.android.cts.verifier.audio.Util;
 
 import org.apache.commons.math.complex.Complex;
 
@@ -60,7 +78,7 @@
   /**
    * Check if the recording is clipped.
    */
-  boolean isClipped() {
+  public boolean isClipped() {
     for (int i = 1; i < data.length; i++) {
       if ((Math.abs(data[i]) >= Short.MAX_VALUE) && (Math.abs(data[i - 1]) >= Short.MAX_VALUE)) {
         listener.sendMessage("WARNING: Data is clipped."
@@ -74,11 +92,11 @@
   /**
    * Check if the result is consistant across trials.
    */
-  boolean isConsistent() {
-    double[] coeffOfVar = new double[Common.PIP_NUM];
-    for (int i = 0; i < Common.PIP_NUM; i++) {
-      double[] powerAtFreq = new double[Common.REPETITIONS];
-      for (int j = 0; j < Common.REPETITIONS; j++) {
+  public boolean isConsistent() {
+    double[] coeffOfVar = new double[AudioCommon.PIP_NUM];
+    for (int i = 0; i < AudioCommon.PIP_NUM; i++) {
+      double[] powerAtFreq = new double[AudioCommon.REPETITIONS];
+      for (int j = 0; j < AudioCommon.REPETITIONS; j++) {
         powerAtFreq[j] = power[i][j];
       }
       coeffOfVar[i] = Util.std(powerAtFreq) / Util.mean(powerAtFreq);
@@ -94,7 +112,7 @@
   /**
    * Determine test pass/fail using the frequency response. Package visible for unit testing.
    */
-  boolean responsePassesHifiTest(double[] dB) {
+  public boolean responsePassesHifiTest(double[] dB) {
     for (int i = 0; i < dB.length; i++) {
       // Precautionary; NaN should not happen.
       if (Double.isNaN(dB[i])) {
@@ -104,16 +122,16 @@
       }
     }
 
-    if (Util.mean(dB) - Util.mean(noiseDB) < Common.SIGNAL_MIN_STRENGTH_DB_ABOVE_NOISE) {
+    if (Util.mean(dB) - Util.mean(noiseDB) < AudioCommon.SIGNAL_MIN_STRENGTH_DB_ABOVE_NOISE) {
       listener.sendMessage("WARNING: Signal is too weak or background noise is too strong."
           + " Turn up the volume of the playback device or move to a quieter location.\n");
       return false;
     }
 
-    int indexOf2000Hz = Util.findClosest(Common.FREQUENCIES_ORIGINAL, 2000.0);
-    threshold = dB[indexOf2000Hz] + Common.PASSING_THRESHOLD_DB;
-    int indexOf18500Hz = Util.findClosest(Common.FREQUENCIES_ORIGINAL, 18500.0);
-    int indexOf20000Hz = Util.findClosest(Common.FREQUENCIES_ORIGINAL, 20000.0);
+    int indexOf2000Hz = Util.findClosest(AudioCommon.FREQUENCIES_ORIGINAL, 2000.0);
+    threshold = dB[indexOf2000Hz] + AudioCommon.PASSING_THRESHOLD_DB;
+    int indexOf18500Hz = Util.findClosest(AudioCommon.FREQUENCIES_ORIGINAL, 18500.0);
+    int indexOf20000Hz = Util.findClosest(AudioCommon.FREQUENCIES_ORIGINAL, 20000.0);
     double[] responseInRange = new double[indexOf20000Hz - indexOf18500Hz];
     System.arraycopy(dB, indexOf18500Hz, responseInRange, 0, responseInRange.length);
     if (Util.mean(responseInRange) < threshold) {
@@ -128,15 +146,15 @@
    * Calculate the Fourier Coefficient at the pip frequency to calculate the frequency response.
    * Package visible for unit testing.
    */
-  double[] measurePipStrength() {
+  public double[] measurePipStrength() {
     listener.sendMessage("Aligning data... Please wait...\n");
     final int dataStartI = alignData();
     final int prefixTotalLength = dataStartI
-        + Util.toLength(Common.PREFIX_LENGTH_S + Common.PAUSE_AFTER_PREFIX_DURATION_S, sampleRate);
+        + Util.toLength(AudioCommon.PREFIX_LENGTH_S + AudioCommon.PAUSE_AFTER_PREFIX_DURATION_S, sampleRate);
     listener.sendMessage("Done.\n");
     listener.sendMessage("Prefix starts at " + (double) dataStartI / sampleRate + " s \n");
-    if (dataStartI > Math.round(sampleRate * (Common.PREFIX_LENGTH_S
-            + Common.PAUSE_BEFORE_PREFIX_DURATION_S + Common.PAUSE_AFTER_PREFIX_DURATION_S))) {
+    if (dataStartI > Math.round(sampleRate * (AudioCommon.PREFIX_LENGTH_S
+            + AudioCommon.PAUSE_BEFORE_PREFIX_DURATION_S + AudioCommon.PAUSE_AFTER_PREFIX_DURATION_S))) {
       listener.sendMessage("WARNING: Unexpected prefix start time. May have missed the prefix.\n"
           + "PLAY button should be pressed on the playback device within one second"
           + " after RECORD is pressed on the recording device.\n"
@@ -145,17 +163,17 @@
     }
 
     listener.sendMessage("Analyzing noise strength... Please wait...\n");
-    noisePower = new double[Common.PIP_NUM][Common.NOISE_SAMPLES];
-    noiseDB = new double[Common.PIP_NUM];
-    for (int s = 0; s < Common.NOISE_SAMPLES; s++) {
-      double[] noisePoints = new double[Common.WINDOW_FOR_RECORDER.length];
+    noisePower = new double[AudioCommon.PIP_NUM][AudioCommon.NOISE_SAMPLES];
+    noiseDB = new double[AudioCommon.PIP_NUM];
+    for (int s = 0; s < AudioCommon.NOISE_SAMPLES; s++) {
+      double[] noisePoints = new double[AudioCommon.WINDOW_FOR_RECORDER.length];
       System.arraycopy(data, dataStartI - (s + 1) * noisePoints.length - 1,
           noisePoints, 0, noisePoints.length);
       for (int j = 0; j < noisePoints.length; j++) {
-        noisePoints[j] = noisePoints[j] * Common.WINDOW_FOR_RECORDER[j];
+        noisePoints[j] = noisePoints[j] * AudioCommon.WINDOW_FOR_RECORDER[j];
       }
-      for (int i = 0; i < Common.PIP_NUM; i++) {
-        double freq = Common.FREQUENCIES_ORIGINAL[i];
+      for (int i = 0; i < AudioCommon.PIP_NUM; i++) {
+        double freq = AudioCommon.FREQUENCIES_ORIGINAL[i];
         Complex fourierCoeff = new Complex(0, 0);
         final Complex rotator = new Complex(0,
             -2.0 * Math.PI * freq / sampleRate).exp();
@@ -168,48 +186,48 @@
         noisePower[i][s] = fourierCoeff.multiply(fourierCoeff.conjugate()).abs();
       }
     }
-    for (int i = 0; i < Common.PIP_NUM; i++) {
+    for (int i = 0; i < AudioCommon.PIP_NUM; i++) {
       double meanNoisePower = 0;
-      for (int j = 0; j < Common.NOISE_SAMPLES; j++) {
+      for (int j = 0; j < AudioCommon.NOISE_SAMPLES; j++) {
         meanNoisePower += noisePower[i][j];
       }
-      meanNoisePower /= Common.NOISE_SAMPLES;
+      meanNoisePower /= AudioCommon.NOISE_SAMPLES;
       noiseDB[i] = 10 * Math.log10(meanNoisePower);
     }
 
     listener.sendMessage("Analyzing pips... Please wait...\n");
-    power = new double[Common.PIP_NUM][Common.REPETITIONS];
-    for (int i = 0; i < Common.PIP_NUM * Common.REPETITIONS; i++) {
-      if (i % Common.PIP_NUM == 0) {
-        listener.sendMessage("#" + (i / Common.PIP_NUM + 1) + "\n");
+    power = new double[AudioCommon.PIP_NUM][AudioCommon.REPETITIONS];
+    for (int i = 0; i < AudioCommon.PIP_NUM * AudioCommon.REPETITIONS; i++) {
+      if (i % AudioCommon.PIP_NUM == 0) {
+        listener.sendMessage("#" + (i / AudioCommon.PIP_NUM + 1) + "\n");
       }
 
       int pipExpectedStartI;
       pipExpectedStartI = prefixTotalLength
-          + Util.toLength(i * (Common.PIP_DURATION_S + Common.PAUSE_DURATION_S), sampleRate);
+          + Util.toLength(i * (AudioCommon.PIP_DURATION_S + AudioCommon.PAUSE_DURATION_S), sampleRate);
       // Cut out the data points for the current pip.
-      double[] pipPoints = new double[Common.WINDOW_FOR_RECORDER.length];
+      double[] pipPoints = new double[AudioCommon.WINDOW_FOR_RECORDER.length];
       System.arraycopy(data, pipExpectedStartI, pipPoints, 0, pipPoints.length);
-      for (int j = 0; j < Common.WINDOW_FOR_RECORDER.length; j++) {
-        pipPoints[j] = pipPoints[j] * Common.WINDOW_FOR_RECORDER[j];
+      for (int j = 0; j < AudioCommon.WINDOW_FOR_RECORDER.length; j++) {
+        pipPoints[j] = pipPoints[j] * AudioCommon.WINDOW_FOR_RECORDER[j];
       }
       Complex fourierCoeff = new Complex(0, 0);
       final Complex rotator = new Complex(0,
-          -2.0 * Math.PI * Common.FREQUENCIES[i] / sampleRate).exp();
+          -2.0 * Math.PI * AudioCommon.FREQUENCIES[i] / sampleRate).exp();
       Complex phasor = new Complex(1, 0);
       for (int j = 0; j < pipPoints.length; j++) {
         fourierCoeff = fourierCoeff.add(phasor.multiply(pipPoints[j]));
         phasor = phasor.multiply(rotator);
       }
       fourierCoeff = fourierCoeff.multiply(1.0 / pipPoints.length);
-      int j = Common.ORDER[i];
-      power[j % Common.PIP_NUM][j / Common.PIP_NUM] =
+      int j = AudioCommon.ORDER[i];
+      power[j % AudioCommon.PIP_NUM][j / AudioCommon.PIP_NUM] =
           fourierCoeff.multiply(fourierCoeff.conjugate()).abs();
     }
 
     // Calculate median of trials.
-    double[] dB = new double[Common.PIP_NUM];
-    for (int i = 0; i < Common.PIP_NUM; i++) {
+    double[] dB = new double[AudioCommon.PIP_NUM];
+    for (int i = 0; i < AudioCommon.PIP_NUM; i++) {
       dB[i] = 10 * Math.log10(Util.median(power[i]));
     }
     return dB;
@@ -218,38 +236,40 @@
   /**
    * Align data using prefix. Package visible for unit testing.
    */
-  int alignData() {
+  public int alignData() {
     // Zeropadding samples to add in the correlation to avoid FFT wraparound.
-    final int zeroPad = Util.toLength(Common.PREFIX_LENGTH_S, Common.RECORDING_SAMPLE_RATE_HZ) - 1;
-    int fftSize = Util.nextPowerOfTwo((int) Math.round(sampleRate * (Common.PREFIX_LENGTH_S
-            + Common.PAUSE_BEFORE_PREFIX_DURATION_S + Common.PAUSE_AFTER_PREFIX_DURATION_S + 0.5))
+    final int zeroPad =
+            Util.toLength(AudioCommon.PREFIX_LENGTH_S, AudioCommon.RECORDING_SAMPLE_RATE_HZ) - 1;
+    int fftSize = Util.nextPowerOfTwo((int) Math.round(sampleRate * (AudioCommon.PREFIX_LENGTH_S
+              + AudioCommon.PAUSE_BEFORE_PREFIX_DURATION_S
+              + AudioCommon.PAUSE_AFTER_PREFIX_DURATION_S + 0.5))
         + zeroPad);
 
     double[] dataCut = new double[fftSize - zeroPad];
     System.arraycopy(data, 0, dataCut, 0, fftSize - zeroPad);
     double[] xCorrDataPrefix = Util.computeCrossCorrelation(
         Util.padZeros(Util.toComplex(dataCut), fftSize),
-        Util.padZeros(Util.toComplex(Common.PREFIX_FOR_RECORDER), fftSize));
+        Util.padZeros(Util.toComplex(AudioCommon.PREFIX_FOR_RECORDER), fftSize));
     return Util.findMaxIndex(xCorrDataPrefix);
   }
 
-  double[] getDB() {
+  public double[] getDB() {
     return dB;
   }
 
-  double[][] getPower() {
+  public double[][] getPower() {
     return power;
   }
 
-  double[] getNoiseDB() {
+  public double[] getNoiseDB() {
     return noiseDB;
   }
 
-  double getThreshold() {
+  public double getThreshold() {
     return threshold;
   }
 
-  boolean getResult() {
+  public boolean getResult() {
     return result;
   }