blob: 258dc067c85c47cb8b75ff2f63d327f4d9130b17 [file] [log] [blame]
/*
* Copyright (C) 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.
*/
package com.android.cts.verifier.audio;
import com.android.cts.verifier.R;
import com.android.cts.verifier.audio.wavelib.*;
import com.android.compatibility.common.util.ResultType;
import com.android.compatibility.common.util.ResultUnit;
import android.content.Context;
import android.media.AudioRecord;
import android.media.MediaRecorder;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.util.Log;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.TextView;
import android.widget.ProgressBar;
/**
* Tests Audio built in Microphone response for Voice Recognition audio source feature.
*/
public class AudioFrequencyVoiceRecognitionActivity extends AudioFrequencyActivity {
private static final String TAG = "VoiceRecognition";
private static final int TEST_STARTED = 900;
private static final int TEST_MESSAGE = 903;
private static final int TEST_ENDED = 904;
private static final int TEST_ENDED_ERROR = 905;
private static final double MIN_FRACTION_POINTS_IN_BAND = 0.5;
private static final double TONE_RMS_EXPECTED = -22.35; //VOICE_RECOGNITION levels
private static final double TONE_RMS_MAX_ERROR = 3.0;
private static final double RMS_SMOOTHING_PARAM = 0.9;
private static final double MAX_VAL = Math.pow(2, 15);
private static final int SOURCE_TONE = 0;
private static final int SOURCE_NOISE = 1;
private static final int TEST_NONE = -1;
private static final int TEST_TONE = 0;
private static final int TEST_NOISE = 1;
private static final int TEST_USB_BACKGROUND = 2;
private static final int TEST_USB_NOISE = 3;
private static final int TEST_COUNT = 4;
private static final int TEST_DURATION_DEFAULT_MS = 2000;
private static final int TEST_DURATION_TONE_MS = TEST_DURATION_DEFAULT_MS;
private static final int TEST_DURATION_NOISE_MS = TEST_DURATION_DEFAULT_MS;
private static final int TEST_DURATION_USB_BACKGROUND_MS = TEST_DURATION_DEFAULT_MS;
private static final int TEST_DURATION_USB_NOISE_MS = TEST_DURATION_DEFAULT_MS;
private static final int BLOCK_SIZE_SAMPLES = 4096;
private static final int SAMPLING_RATE = 48000;
private static final int RECORD_SOURCE = MediaRecorder.AudioSource.VOICE_RECOGNITION;
private static final int BANDS_MIC = 3;
private static final int BANDS_TONE = 3;
private static final int BANDS_BACKGROUND = 3;
private int mCurrentTest = TEST_NONE;
private boolean mTestsDone[] = new boolean[TEST_COUNT];
final OnBtnClickListener mBtnClickListener = new OnBtnClickListener();
private Context mContext;
private Button mButtonTestTone;
private ProgressBar mProgressTone;
private TextView mResultTestTone;
private Button mButtonPlayTone;
private Button mButtonTestNoise;
private ProgressBar mProgressNoise;
private TextView mResultTestNoise;
private Button mButtonPlayNoise;
private Button mButtonTestUsbBackground;
private ProgressBar mProgressUsbBackground;
private TextView mResultTestUsbBackground;
private Button mButtonTestUsbNoise;
private ProgressBar mProgressUsbNoise;
private TextView mResultTestUsbNoise;
private Button mButtonPlayUsbNoise;
private TextView mGlobalResultText;
private short[] mAudioShortArray2;
private SoundPlayerObject mSPlayer;
private SoundRecorderObject mSRecorder;
private DspBufferComplex mC;
private DspBufferDouble mData;
private DspWindow mWindow;
private DspFftServer mFftServer;
private VectorAverage mFreqAverageTone = new VectorAverage();
private VectorAverage mFreqAverageNoise = new VectorAverage();
private VectorAverage mFreqAverageUsbBackground = new VectorAverage();
private VectorAverage mFreqAverageUsbNoise = new VectorAverage();
//RMS for tone:
private double mRMS;
private double mRMSMax;
private double mRMSTone;
private double mRMSMaxTone;
private AudioBandSpecs[] mBandSpecsMic = new AudioBandSpecs[BANDS_MIC];
private AudioBandSpecs[] mBandSpecsTone = new AudioBandSpecs[BANDS_TONE];
private AudioBandSpecs[] mBandSpecsBack = new AudioBandSpecs[BANDS_BACKGROUND];
private Results mResultsMic;
private Results mResultsTone;
private Results mResultsBack;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.audio_frequency_voice_recognition_activity);
mContext = this;
mSPlayer = new SoundPlayerObject();
playerSetSource(SOURCE_TONE);
mSRecorder = new SoundRecorderObject(SAMPLING_RATE, BLOCK_SIZE_SAMPLES,
RECORD_SOURCE) {
@Override
public void periodicNotification(AudioRecord recorder) {
int samplesAvailable = mPipe.availableToRead();
int samplesNeeded = BLOCK_SIZE_SAMPLES;
if (samplesAvailable >= samplesNeeded) {
mPipe.read(mAudioShortArray2, 0, samplesNeeded);
//compute
double maxabs = 0;
int i;
double rmsTempSum = 0;
for (i = 0; i < samplesNeeded; i++) {
double value = mAudioShortArray2[i] / MAX_VAL;
double valueabs = Math.abs(value);
if (valueabs > maxabs) {
maxabs = valueabs;
}
rmsTempSum += value * value;
mData.mData[i] = value;
}
double rms = Math.sqrt(rmsTempSum / samplesNeeded);
double total_rms = rms * RMS_SMOOTHING_PARAM + mRMS * (1 - RMS_SMOOTHING_PARAM);
mRMS = total_rms;
if (mRMS > mRMSMax) {
mRMSMax = mRMS;
}
//for the current frame, compute FFT and send to the viewer.
//apply window and pack as complex for now.
DspBufferMath.mult(mData, mData, mWindow.mBuffer);
DspBufferMath.set(mC, mData);
mFftServer.fft(mC, 1);
double[] magnitude = new double[BLOCK_SIZE_SAMPLES / 2];
for (i = 0; i < BLOCK_SIZE_SAMPLES / 2; i++) {
magnitude[i] = Math.sqrt(mC.mReal[i] * mC.mReal[i] +
mC.mImag[i] * mC.mImag[i]);
}
switch (mCurrentTest) {
case TEST_TONE: {
mFreqAverageTone.setData(magnitude, false);
//Update realtime info on screen
mRMSTone = mRMS;
mRMSMaxTone = mRMSMax;
showToneRMS();
}
break;
case TEST_NOISE:
mFreqAverageNoise.setData(magnitude, false);
break;
case TEST_USB_BACKGROUND:
mFreqAverageUsbBackground.setData(magnitude, false);
break;
case TEST_USB_NOISE:
mFreqAverageUsbNoise.setData(magnitude, false);
break;
}
}
}
@Override
public void markerReached(AudioRecord track) {
}
};
// Test tone
mButtonTestTone = (Button) findViewById(R.id.vr_button_test_tone);
mButtonTestTone.setOnClickListener(mBtnClickListener);
mProgressTone = (ProgressBar) findViewById(R.id.vr_test_tone_progress_bar);
mResultTestTone = (TextView) findViewById(R.id.vr_test_tone_result);
mButtonPlayTone = (Button) findViewById(R.id.vr_button_play_tone);
mButtonPlayTone.setOnClickListener(mBtnClickListener);
showWait(mProgressTone, false);
//Test Noise
mButtonTestNoise = (Button) findViewById(R.id.vr_button_test_noise);
mButtonTestNoise.setOnClickListener(mBtnClickListener);
mProgressNoise = (ProgressBar) findViewById(R.id.vr_test_noise_progress_bar);
mResultTestNoise = (TextView) findViewById(R.id.vr_test_noise_result);
mButtonPlayNoise = (Button) findViewById(R.id.vr_button_play_noise);
mButtonPlayNoise.setOnClickListener(mBtnClickListener);
showWait(mProgressNoise, false);
//USB Background
mButtonTestUsbBackground = (Button) findViewById(R.id.vr_button_test_usb_background);
mButtonTestUsbBackground.setOnClickListener(mBtnClickListener);
mProgressUsbBackground = (ProgressBar)
findViewById(R.id.vr_test_usb_background_progress_bar);
mResultTestUsbBackground = (TextView)
findViewById(R.id.vr_test_usb_background_result);
showWait(mProgressUsbBackground, false);
mButtonTestUsbNoise = (Button) findViewById(R.id.vr_button_test_usb_noise);
mButtonTestUsbNoise.setOnClickListener(mBtnClickListener);
mProgressUsbNoise = (ProgressBar)findViewById(R.id.vr_test_usb_noise_progress_bar);
mResultTestUsbNoise = (TextView) findViewById(R.id.vr_test_usb_noise_result);
mButtonPlayUsbNoise = (Button) findViewById(R.id.vr_button_play_usb_noise);
mButtonPlayUsbNoise.setOnClickListener(mBtnClickListener);
showWait(mProgressUsbNoise, false);
setButtonPlayStatus(-1);
mGlobalResultText = (TextView) findViewById(R.id.vr_test_global_result);
//Init FFT stuff
mAudioShortArray2 = new short[BLOCK_SIZE_SAMPLES *2];
mData = new DspBufferDouble(BLOCK_SIZE_SAMPLES);
mC = new DspBufferComplex(BLOCK_SIZE_SAMPLES);
mFftServer = new DspFftServer(BLOCK_SIZE_SAMPLES);
int overlap = BLOCK_SIZE_SAMPLES / 2;
mWindow = new DspWindow(DspWindow.WINDOW_HANNING, BLOCK_SIZE_SAMPLES, overlap);
setPassFailButtonClickListeners();
getPassButton().setEnabled(false);
setInfoResources(R.string.audio_frequency_voice_recognition_test,
R.string.audio_frequency_voice_recognition_info, -1);
//Init bands for Mic test
mBandSpecsMic[0] = new AudioBandSpecs(
5, 100, /* frequency start,stop */
20.0, -20.0, /* start top,bottom value */
20.0, -20.0 /* stop top,bottom value */);
mBandSpecsMic[1] = new AudioBandSpecs(
100, 4000, /* frequency start,stop */
6.0, -6.0, /* start top,bottom value */
6.0, -6.0 /* stop top,bottom value */);
mBandSpecsMic[2] = new AudioBandSpecs(
4000, 20000, /* frequency start,stop */
30.0, -30.0, /* start top,bottom value */
30.0, -30.0 /* stop top,bottom value */);
//Init bands for Tone test
mBandSpecsTone[0] = new AudioBandSpecs(
5, 900, /* frequency start,stop */
-10.0, -100.0, /* start top,bottom value */
-10.0, -100.0 /* stop top,bottom value */);
mBandSpecsTone[1] = new AudioBandSpecs(
900, 1100, /* frequency start,stop */
10.0, -50.0, /* start top,bottom value */
10.0, -10.0 /* stop top,bottom value */);
mBandSpecsTone[2] = new AudioBandSpecs(
1100, 20000, /* frequency start,stop */
-30.0, -120.0, /* start top,bottom value */
-30.0, -120.0 /* stop top,bottom value */);
//Init bands for Background test
mBandSpecsBack[0] = new AudioBandSpecs(
5, 100, /* frequency start,stop */
10.0, -120.0, /* start top,bottom value */
-10.0, -120.0 /* stop top,bottom value */);
mBandSpecsBack[1] = new AudioBandSpecs(
100, 7000, /* frequency start,stop */
-10.0, -120.0, /* start top,bottom value */
-50.0, -120.0 /* stop top,bottom value */);
mBandSpecsBack[2] = new AudioBandSpecs(
7000, 20000, /* frequency start,stop */
-50.0, -120.0, /* start top,bottom value */
-50.0, -120.0 /* stop top,bottom value */);
mResultsMic = new Results("mic_response", BANDS_MIC);
mResultsTone = new Results("tone_response", BANDS_TONE);
mResultsBack = new Results("background_response", BANDS_BACKGROUND);
connectRefMicUI();
}
//
// Overrides
//
void enableTestUI(boolean enable) {
mButtonTestTone.setEnabled(enable);
mButtonPlayTone.setEnabled(enable);
mButtonTestNoise.setEnabled(enable);
mButtonPlayNoise.setEnabled(enable);
mButtonTestUsbBackground.setEnabled(enable);
mButtonTestUsbNoise.setEnabled(enable);
mButtonPlayUsbNoise.setEnabled(enable);
}
private void playerToggleButton(int buttonId, int sourceId) {
if (playerIsPlaying()) {
playerStopAll();
} else {
playerSetSource(sourceId);
playerTransport(true);
setButtonPlayStatus(buttonId);
}
}
private class OnBtnClickListener implements OnClickListener {
@Override
public void onClick(View v) {
int id = v.getId();
switch (id) {
case R.id.vr_button_test_tone:
startTest(TEST_TONE);
break;
case R.id.vr_button_play_tone:
playerToggleButton(id, SOURCE_TONE);
break;
case R.id.vr_button_test_noise:
startTest(TEST_NOISE);
break;
case R.id.vr_button_play_noise:
playerToggleButton(id, SOURCE_NOISE);
break;
case R.id.vr_button_test_usb_background:
startTest(TEST_USB_BACKGROUND);
break;
case R.id.vr_button_test_usb_noise:
startTest(TEST_USB_NOISE);
break;
case R.id.vr_button_play_usb_noise:
playerToggleButton(id, SOURCE_NOISE);
break;
}
}
}
private void setButtonPlayStatus(int playResId) {
String play = getResources().getText(R.string.af_button_play).toString();
String stop = getResources().getText(R.string.af_button_stop).toString();
mButtonPlayTone.setText(playResId == R.id.vr_button_play_tone ? stop : play);
mButtonPlayNoise.setText(playResId == R.id.vr_button_play_noise ? stop : play);
mButtonPlayUsbNoise.setText(playResId ==
R.id.vr_button_play_usb_noise ? stop : play);
}
private void playerSetSource(int sourceIndex) {
switch (sourceIndex) {
case SOURCE_TONE:
mSPlayer.setSoundWithResId(getApplicationContext(), R.raw.onekhztone);
break;
default:
case SOURCE_NOISE:
mSPlayer.setSoundWithResId(getApplicationContext(),
R.raw.stereo_mono_white_noise_48);
break;
}
}
private void playerTransport(boolean play) {
if (!mSPlayer.isAlive()) {
mSPlayer.start();
}
mSPlayer.play(play);
}
private boolean playerIsPlaying() {
return mSPlayer.isPlaying();
}
private void playerStopAll() {
if (mSPlayer.isAlive() && mSPlayer.isPlaying()) {
mSPlayer.play(false);
setButtonPlayStatus(-1);
}
}
private void showWait(ProgressBar pb, boolean show) {
pb.setVisibility(show ? View.VISIBLE : View.INVISIBLE);
}
private String getTestString(int testId) {
String name = "undefined";
switch(testId) {
case TEST_TONE:
name = "BuiltIn_tone";
break;
case TEST_NOISE:
name = "BuiltIn_noise";
break;
case TEST_USB_BACKGROUND:
name = "USB_background";
break;
case TEST_USB_NOISE:
name = "USB_noise";
break;
}
return name;
}
private void showWait(int testId, boolean show) {
switch(testId) {
case TEST_TONE:
showWait(mProgressTone, show);
break;
case TEST_NOISE:
showWait(mProgressNoise, show);
break;
case TEST_USB_BACKGROUND:
showWait(mProgressUsbBackground, show);
break;
case TEST_USB_NOISE:
showWait(mProgressUsbNoise, show);
break;
}
}
private void showMessage(int testId, String msg) {
if (msg != null && msg.length() > 0) {
switch(testId) {
case TEST_TONE:
mResultTestTone.setText(msg);
break;
case TEST_NOISE:
mResultTestNoise.setText(msg);
break;
case TEST_USB_BACKGROUND:
mResultTestUsbBackground.setText(msg);
break;
case TEST_USB_NOISE:
mResultTestUsbNoise.setText(msg);
break;
}
}
}
private void computeAllResults() {
StringBuilder sb = new StringBuilder();
boolean allDone = true;
for (int i = 0; i < TEST_COUNT; i++) {
allDone = allDone & mTestsDone[i];
sb.append(String.format("%s : %s\n", getTestString(i),
mTestsDone[i] ? "DONE" :" NOT DONE"));
}
if (allDone) {
sb.append(computeResults());
} else {
sb.append("Please execute all tests for results\n");
}
mGlobalResultText.setText(sb.toString());
}
private void processSpectrum(Results results, AudioBandSpecs[] bandsSpecs, int anchorBand) {
int points = results.mValuesLog.length;
int bandCount = bandsSpecs.length;
int currentBand = 0;
for (int i = 0; i < points; i++) {
double freq = (double) SAMPLING_RATE * i / (double) BLOCK_SIZE_SAMPLES;
if (freq > bandsSpecs[currentBand].mFreqStop) {
currentBand++;
if (currentBand >= bandCount)
break;
}
if (freq >= bandsSpecs[currentBand].mFreqStart) {
results.mAverageEnergyPerBand[currentBand] += results.mValuesLog[i];
results.mPointsPerBand[currentBand]++;
}
}
for (int b = 0; b < bandCount; b++) {
if (results.mPointsPerBand[b] > 0) {
results.mAverageEnergyPerBand[b] =
results.mAverageEnergyPerBand[b] / results.mPointsPerBand[b];
}
}
//set offset relative to band anchor band level
double offset = anchorBand > -1 && anchorBand < bandCount ?
results.mAverageEnergyPerBand[anchorBand] : 0;
for (int b = 0; b < bandCount; b++) {
bandsSpecs[b].setOffset(offset);
}
//test points in band.
currentBand = 0;
for (int i = 0; i < points; i++) {
double freq = (double) SAMPLING_RATE * i / (double) BLOCK_SIZE_SAMPLES;
if (freq > bandsSpecs[currentBand].mFreqStop) {
currentBand++;
if (currentBand >= bandCount)
break;
}
if (freq >= bandsSpecs[currentBand].mFreqStart) {
double value = results.mValuesLog[i];
if (bandsSpecs[currentBand].isInBounds(freq, value)) {
results.mInBoundPointsPerBand[currentBand]++;
}
}
}
}
private String computeResults() {
StringBuilder sb = new StringBuilder();
int points = mFreqAverageNoise.getSize();
//mFreqAverageNoise size is determined by the latest data written to it.
//Currently, this data is always BLOCK_SIZE_SAMPLES/2.
if (points < 1) {
return "error: not enough points";
}
double[] tone = new double[points];
double[] noise = new double[points];
double[] reference = new double[points];
double[] background = new double[points];
mFreqAverageTone.getData(tone, false);
mFreqAverageNoise.getData(noise, false);
mFreqAverageUsbNoise.getData(reference, false);
mFreqAverageUsbBackground.getData(background, false);
//Convert to dB
double[] toneDb = new double[points];
double[] noiseDb = new double[points];
double[] referenceDb = new double[points];
double[] backgroundDb = new double[points];
double[] compensatedNoiseDb = new double[points];
for (int i = 0; i < points; i++) {
toneDb[i] = 20 * Math.log10(tone[i]);
noiseDb[i] = 20 * Math.log10(noise[i]);
referenceDb[i] = 20 * Math.log10(reference[i]);
backgroundDb[i] = 20 * Math.log10(background[i]);
//Use reference measurement to compensate for speaker response.
compensatedNoiseDb[i] = noiseDb[i] - referenceDb[i];
}
mResultsMic.reset();
mResultsTone.reset();
mResultsBack.reset();
mResultsMic.mValuesLog = compensatedNoiseDb;
mResultsTone.mValuesLog = toneDb;
mResultsBack.mValuesLog = backgroundDb;
processSpectrum(mResultsMic, mBandSpecsMic, 1);
processSpectrum(mResultsTone, mBandSpecsTone, 1);
processSpectrum(mResultsBack, mBandSpecsBack, -1); //no reference for offset
//Tone test
boolean toneTestSuccess = true;
{
//rms level should be -36 dbfs +/- 3 db?
double rmsMaxDb = 20 * Math.log10(mRMSMaxTone);
sb.append(String.format("RMS level of tone: %.2f dBFS\n", rmsMaxDb));
sb.append(String.format("Target RMS level: %.2f dBFS +/- %.2f dB\n",
TONE_RMS_EXPECTED,
TONE_RMS_MAX_ERROR));
//check that the spectrum is really a tone around 1 khz
if (Math.abs(rmsMaxDb - TONE_RMS_EXPECTED) > TONE_RMS_MAX_ERROR) {
toneTestSuccess = false;
sb.append("RMS level test FAILED\n");
} else {
sb.append(" RMS level test SUCCESSFUL\n");
}
}
sb.append("\n");
sb.append(mResultsTone.toString());
if (mResultsTone.testAll()) {
sb.append(" 1 Khz Tone Frequency Response Test SUCCESSFUL\n");
} else {
sb.append(" 1 Khz Tone Frequency Response Test FAILED\n");
}
sb.append("\n");
sb.append("\n");
sb.append(mResultsBack.toString());
if (mResultsBack.testAll()) {
sb.append(" Background environment Test SUCCESSFUL\n");
} else {
sb.append(" Background environment Test FAILED\n");
}
sb.append("\n");
sb.append(mResultsMic.toString());
if (mResultsMic.testAll()) {
sb.append(" Frequency Response Test SUCCESSFUL\n");
} else {
sb.append(" Frequency Response Test FAILED\n");
}
sb.append("\n");
recordTestResults(mResultsTone);
recordTestResults(mResultsMic);
boolean allTestsPassed = false;
if (mResultsMic.testAll() && mResultsTone.testAll() && toneTestSuccess &&
mResultsBack.testAll()) {
allTestsPassed = true;
String strSuccess = getResources().getString(R.string.audio_general_test_passed);
sb.append(strSuccess);
} else {
String strFailed = getResources().getString(R.string.audio_general_test_failed);
sb.append(strFailed);
}
sb.append("\n");
getPassButton().setEnabled(allTestsPassed);
return sb.toString();
}
Thread mTestThread;
private void startTest(int testId) {
if (mTestThread != null && mTestThread.isAlive()) {
Log.v(TAG, "test Thread already running.");
return;
}
mRMS = 0;
mRMSMax = 0;
Log.v(TAG,"Executing test Thread");
switch(testId) {
case TEST_TONE:
mTestThread = new Thread(new TestRunnable(TEST_TONE) {
public void run() {
super.run();
if (!mUsbMicConnected) {
sendMessage(mTestId, TEST_MESSAGE,
"Testing Built in Microphone: Tone");
mRMSTone = 0;
mRMSMaxTone = 0;
mFreqAverageTone.reset();
mFreqAverageTone.setCaptureType(VectorAverage.CAPTURE_TYPE_MAX);
record(TEST_DURATION_TONE_MS);
sendMessage(mTestId, TEST_ENDED, "Testing Completed");
mTestsDone[mTestId] = true;
} else {
sendMessage(mTestId, TEST_ENDED_ERROR,
"Please Unplug USB Microphone");
mTestsDone[mTestId] = false;
}
}
});
break;
case TEST_NOISE:
mTestThread = new Thread(new TestRunnable(TEST_NOISE) {
public void run() {
super.run();
if (!mUsbMicConnected) {
sendMessage(mTestId, TEST_MESSAGE,
"Testing Built in Microphone: Noise");
mFreqAverageNoise.reset();
mFreqAverageNoise.setCaptureType(VectorAverage.CAPTURE_TYPE_MAX);
record(TEST_DURATION_NOISE_MS);
sendMessage(mTestId, TEST_ENDED, "Testing Completed");
mTestsDone[mTestId] = true;
} else {
sendMessage(mTestId, TEST_ENDED_ERROR,
"Please Unplug USB Microphone");
mTestsDone[mTestId] = false;
}
}
});
break;
case TEST_USB_BACKGROUND:
playerStopAll();
mTestThread = new Thread(new TestRunnable(TEST_USB_BACKGROUND) {
public void run() {
super.run();
if (mUsbMicConnected) {
sendMessage(mTestId, TEST_MESSAGE,
"Testing USB Microphone: background");
mFreqAverageUsbBackground.reset();
mFreqAverageUsbBackground.setCaptureType(
VectorAverage.CAPTURE_TYPE_AVERAGE);
record(TEST_DURATION_USB_BACKGROUND_MS);
sendMessage(mTestId, TEST_ENDED, "Testing Completed");
mTestsDone[mTestId] = true;
} else {
sendMessage(mTestId, TEST_ENDED_ERROR,
"USB Microphone not detected.");
mTestsDone[mTestId] = false;
}
}
});
break;
case TEST_USB_NOISE:
mTestThread = new Thread(new TestRunnable(TEST_USB_NOISE) {
public void run() {
super.run();
if (mUsbMicConnected) {
sendMessage(mTestId, TEST_MESSAGE, "Testing USB Microphone: Noise");
mFreqAverageUsbNoise.reset();
mFreqAverageUsbNoise.setCaptureType(VectorAverage.CAPTURE_TYPE_MAX);
record(TEST_DURATION_USB_NOISE_MS);
sendMessage(mTestId, TEST_ENDED, "Testing Completed");
mTestsDone[mTestId] = true;
} else {
sendMessage(mTestId, TEST_ENDED_ERROR,
"USB Microphone not detected.");
mTestsDone[mTestId] = false;
}
}
});
break;
}
mTestThread.start();
}
public class TestRunnable implements Runnable {
public int mTestId;
public boolean mUsbMicConnected;
TestRunnable(int testId) {
Log.v(TAG,"New TestRunnable");
mTestId = testId;
}
public void run() {
mCurrentTest = mTestId;
sendMessage(mTestId, TEST_STARTED,"");
mUsbMicConnected =
UsbMicrophoneTester.getIsMicrophoneConnected(getApplicationContext());
};
public void record(int durationMs) {
mSRecorder.startRecording();
try {
Thread.sleep(durationMs);
} catch (InterruptedException e) {
e.printStackTrace();
//restore interrupted status
Thread.currentThread().interrupt();
}
mSRecorder.stopRecording();
}
public void sendMessage(int testId, int msgType, String str) {
Message msg = Message.obtain();
msg.what = msgType;
msg.obj = str;
msg.arg1 = testId;
mMessageHandler.sendMessage(msg);
}
}
private Handler mMessageHandler = new Handler() {
public void handleMessage(Message msg) {
super.handleMessage(msg);
int testId = msg.arg1; //testId
String str = (String) msg.obj;
switch (msg.what) {
case TEST_STARTED:
showWait(testId, true);
break;
case TEST_MESSAGE:
showMessage(testId, str);
break;
case TEST_ENDED:
showWait(testId, false);
playerStopAll();
showMessage(testId, str);
appendResultsToScreen(testId, "test finished");
computeAllResults();
break;
case TEST_ENDED_ERROR:
showWait(testId, false);
playerStopAll();
showMessage(testId, str);
computeAllResults();
default:
Log.e(TAG, String.format("Unknown message: %d", msg.what));
}
}
};
private class Results {
private int mBandCount;
private String mLabel;
public double[] mValuesLog;
int[] mPointsPerBand; // = new int[mBands];
double[] mAverageEnergyPerBand;// = new double[mBands];
int[] mInBoundPointsPerBand;// = new int[mBands];
public Results(String label, int bandCount) {
mLabel = label;
mBandCount = bandCount;
mPointsPerBand = new int[mBandCount];
mAverageEnergyPerBand = new double[mBandCount];
mInBoundPointsPerBand = new int[mBandCount];
}
public void reset() {
for (int i = 0; i < mBandCount; i++) {
mPointsPerBand[i] = 0;
mAverageEnergyPerBand[i] = 0;
mInBoundPointsPerBand[i] = 0;
}
}
//append results
public String toString() {
StringBuilder sb = new StringBuilder();
sb.append(String.format("Channel %s\n", mLabel));
for (int b = 0; b < mBandCount; b++) {
double percent = 0;
if (mPointsPerBand[b] > 0) {
percent = 100.0 * (double) mInBoundPointsPerBand[b] / mPointsPerBand[b];
}
sb.append(String.format(
" Band %d: Av. Level: %.1f dB InBand: %d/%d (%.1f%%) %s\n",
b, mAverageEnergyPerBand[b],
mInBoundPointsPerBand[b],
mPointsPerBand[b],
percent,
(testInBand(b) ? "OK" : "Not Optimal")));
}
return sb.toString();
}
public boolean testInBand(int b) {
if (b >= 0 && b < mBandCount && mPointsPerBand[b] > 0) {
if ((double) mInBoundPointsPerBand[b] / mPointsPerBand[b] >
MIN_FRACTION_POINTS_IN_BAND) {
return true;
}
}
return false;
}
public boolean testAll() {
for (int b = 0; b < mBandCount; b++) {
if (!testInBand(b)) {
return false;
}
}
return true;
}
}
//append results
private void appendResultsToScreen(String str, TextView text) {
String currentText = text.getText().toString();
text.setText(currentText + "\n" + str);
}
private void appendResultsToScreen(int testId, String str) {
switch(testId) {
case TEST_TONE:
appendResultsToScreen(str, mResultTestTone);
showToneRMS();
break;
case TEST_NOISE:
appendResultsToScreen(str, mResultTestNoise);
break;
case TEST_USB_BACKGROUND:
appendResultsToScreen(str, mResultTestUsbBackground);
break;
case TEST_USB_NOISE:
appendResultsToScreen(str, mResultTestUsbNoise);
break;
}
}
/**
* Store test results in log
*/
private void recordTestResults(Results results) {
String channelLabel = "channel_" + results.mLabel;
for (int b = 0; b < results.mBandCount; b++) {
String bandLabel = String.format(channelLabel + "_%d", b);
getReportLog().addValue(
bandLabel + "_Level",
results.mAverageEnergyPerBand[b],
ResultType.HIGHER_BETTER,
ResultUnit.NONE);
getReportLog().addValue(
bandLabel + "_pointsinbound",
results.mInBoundPointsPerBand[b],
ResultType.HIGHER_BETTER,
ResultUnit.COUNT);
getReportLog().addValue(
bandLabel + "_pointstotal",
results.mPointsPerBand[b],
ResultType.NEUTRAL,
ResultUnit.COUNT);
}
getReportLog().addValues(channelLabel + "_magnitudeSpectrumLog",
results.mValuesLog,
ResultType.NEUTRAL,
ResultUnit.NONE);
Log.v(TAG, "Results Recorded");
}
private void recordHeasetPortFound(boolean found) {
getReportLog().addValue(
"User Reported Headset Port",
found ? 1.0 : 0,
ResultType.NEUTRAL,
ResultUnit.NONE);
}
private void showToneRMS() {
String str = String.format("RMS: %.3f dBFS. Max RMS: %.3f dBFS",
20 * Math.log10(mRMSTone),
20 * Math.log10(mRMSMaxTone));
showMessage(TEST_TONE, str);
}
}