diff options
Diffstat (limited to 'apps/OboeTester/app/src/main/java/com/mobileer/oboetester/TestDataPathsActivity.java')
-rw-r--r-- | apps/OboeTester/app/src/main/java/com/mobileer/oboetester/TestDataPathsActivity.java | 901 |
1 files changed, 583 insertions, 318 deletions
diff --git a/apps/OboeTester/app/src/main/java/com/mobileer/oboetester/TestDataPathsActivity.java b/apps/OboeTester/app/src/main/java/com/mobileer/oboetester/TestDataPathsActivity.java index b0aea932..74879f14 100644 --- a/apps/OboeTester/app/src/main/java/com/mobileer/oboetester/TestDataPathsActivity.java +++ b/apps/OboeTester/app/src/main/java/com/mobileer/oboetester/TestDataPathsActivity.java @@ -17,49 +17,74 @@ package com.mobileer.oboetester; import static com.mobileer.oboetester.IntentBasedTestSupport.configureStreamsFromBundle; +import static com.mobileer.oboetester.StreamConfiguration.convertChannelMaskToText; -import android.app.Activity; -import android.content.Context; import android.media.AudioDeviceInfo; import android.media.AudioManager; +import android.os.Build; import android.os.Bundle; -import android.os.Handler; -import android.os.Looper; -import android.support.annotation.NonNull; import android.util.Log; import android.widget.CheckBox; +import android.widget.RadioButton; +import android.widget.RadioGroup; +import android.widget.TextView; + +import androidx.annotation.NonNull; import com.mobileer.audio_device.AudioDeviceInfoConverter; import java.lang.reflect.Field; +import java.util.ArrayList; +import java.util.Locale; /** - * Play a recognizable tone on each channel of each speaker device - * and listen for the result through a microphone. - * Also test each microphone channel and device. - * Try each InputPreset. + * Play a recognizable tone on each channel of an output device + * and listen for the result through an input. + * Test various channels, InputPresets, ChannelMasks and SampleRates. + * + * Select device types based on priority of attached peripherals. + * Print devices types being tested. * * The analysis is based on a cosine transform of a single * frequency. The magnitude indicates the level. * The variations in phase, "jitter" indicate how noisy the - * signal is or whether it is corrupted. A noisy room may have - * energy at the target frequency but the phase will be random. + * signal is or whether it is corrupted. A very noisy room may have + * lots of energy at the target frequency but the phase will be random. * - * This test requires a quiet room but no other hardware. + * This test requires a quiet room if you are testing speaker/mic pairs. + * It can also be used to test using analog loopback adapters + * or USB devices configured in loopback mode. */ public class TestDataPathsActivity extends BaseAutoGlitchActivity { public static final String KEY_USE_INPUT_PRESETS = "use_input_presets"; public static final boolean VALUE_DEFAULT_USE_INPUT_PRESETS = true; - public static final String KEY_USE_INPUT_DEVICES = "use_input_devices"; - public static final boolean VALUE_DEFAULT_USE_INPUT_DEVICES = true; + public static final String KEY_USE_ALL_SAMPLE_RATES = "use_all_sample_rates"; + public static final boolean VALUE_DEFAULT_USE_ALL_SAMPLE_RATES = false; + + public static final String KEY_SINGLE_TEST_INDEX = "single_test_index"; + public static final int VALUE_DEFAULT_SINGLE_TEST_INDEX = -1; + public static final String KEY_USE_ALL_CHANNEL_COUNTS = "use_all_channel_counts"; + public static final boolean VALUE_DEFAULT_USE_ALL_CHANNEL_COUNTS = true; + public static final String KEY_USE_INPUT_CHANNEL_MASKS = "use_input_channel_masks"; + public static final boolean VALUE_DEFAULT_USE_INPUT_CHANNEL_MASKS = false; + public static final String KEY_OUTPUT_CHANNEL_MASKS_LEVEL = "output_channel_masks_level"; + + // The following KEYs are for old deprecated commands. + public static final String KEY_USE_ALL_OUTPUT_CHANNEL_MASKS = "use_all_output_channel_masks"; + public static final boolean VALUE_DEFAULT_USE_ALL_OUTPUT_CHANNEL_MASKS = false; + + // How many tests should be run in a specific category, eg. channel masks? + private static final int COVERAGE_LEVEL_NONE = 0; + private static final int COVERAGE_LEVEL_SOME = 1; + private static final int COVERAGE_LEVEL_ALL = 2; + public static final String KEY_USE_INPUT_DEVICES = "use_input_devices"; + public static final boolean VALUE_DEFAULT_USE_INPUT_DEVICES = false; public static final String KEY_USE_OUTPUT_DEVICES = "use_output_devices"; public static final boolean VALUE_DEFAULT_USE_OUTPUT_DEVICES = true; - public static final String KEY_SINGLE_TEST_INDEX = "single_test_index"; - public static final int VALUE_DEFAULT_SINGLE_TEST_INDEX = -1; public static final int DURATION_SECONDS = 3; private final static double MIN_REQUIRED_MAGNITUDE = 0.001; @@ -70,6 +95,42 @@ public class TestDataPathsActivity extends BaseAutoGlitchActivity { private final static double MAX_ALLOWED_JITTER = 2.0 * PHASE_PER_BIN; private final static String MAGNITUDE_FORMAT = "%7.5f"; + // These define the values returned by the Java API deviceInfo.getChannelMasks(). + public static final int JAVA_CHANNEL_IN_LEFT = 1 << 2; // AudioFormat.CHANNEL_IN_LEFT + public static final int JAVA_CHANNEL_IN_RIGHT = 1 << 3; // AudioFormat.CHANNEL_IN_RIGHT + public static final int JAVA_CHANNEL_IN_FRONT = 1 << 4; // AudioFormat.CHANNEL_IN_FRONT + public static final int JAVA_CHANNEL_IN_BACK = 1 << 5; // AudioFormat.CHANNEL_IN_BACK + + // These do not have corresponding Java definitions. + // They match definitions in system/media/audio/include/system/audio-hal-enums.h + public static final int JAVA_CHANNEL_IN_BACK_LEFT = 1 << 16; + public static final int JAVA_CHANNEL_IN_BACK_RIGHT = 1 << 17; + public static final int JAVA_CHANNEL_IN_CENTER = 1 << 18; + public static final int JAVA_CHANNEL_IN_LOW_FREQUENCY = 1 << 20; + public static final int JAVA_CHANNEL_IN_TOP_LEFT = 1 << 21; + public static final int JAVA_CHANNEL_IN_TOP_RIGHT = 1 << 22; + + public static final int JAVA_CHANNEL_IN_MONO = JAVA_CHANNEL_IN_FRONT; + public static final int JAVA_CHANNEL_IN_STEREO = JAVA_CHANNEL_IN_LEFT | JAVA_CHANNEL_IN_RIGHT; + public static final int JAVA_CHANNEL_IN_FRONT_BACK = JAVA_CHANNEL_IN_FRONT | JAVA_CHANNEL_IN_BACK; + public static final int JAVA_CHANNEL_IN_2POINT0POINT2 = JAVA_CHANNEL_IN_LEFT | + JAVA_CHANNEL_IN_RIGHT | + JAVA_CHANNEL_IN_TOP_LEFT | + JAVA_CHANNEL_IN_TOP_RIGHT; + public static final int JAVA_CHANNEL_IN_2POINT1POINT2 = + JAVA_CHANNEL_IN_2POINT0POINT2 | JAVA_CHANNEL_IN_LOW_FREQUENCY; + public static final int JAVA_CHANNEL_IN_3POINT0POINT2 = + JAVA_CHANNEL_IN_2POINT0POINT2 | JAVA_CHANNEL_IN_CENTER; + public static final int JAVA_CHANNEL_IN_3POINT1POINT2 = + JAVA_CHANNEL_IN_3POINT0POINT2 | JAVA_CHANNEL_IN_LOW_FREQUENCY; + public static final int JAVA_CHANNEL_IN_5POINT1 = JAVA_CHANNEL_IN_LEFT | + JAVA_CHANNEL_IN_CENTER | + JAVA_CHANNEL_IN_RIGHT | + JAVA_CHANNEL_IN_BACK_LEFT | + JAVA_CHANNEL_IN_BACK_RIGHT | + JAVA_CHANNEL_IN_LOW_FREQUENCY; + public static final int JAVA_CHANNEL_UNDEFINED = -1; + final int TYPE_BUILTIN_SPEAKER_SAFE = 0x18; // API 30 private double mMagnitude; @@ -79,22 +140,73 @@ public class TestDataPathsActivity extends BaseAutoGlitchActivity { private double mPhaseErrorSum; private double mPhaseErrorCount; - AudioManager mAudioManager; private CheckBox mCheckBoxInputPresets; - private CheckBox mCheckBoxInputDevices; - private CheckBox mCheckBoxOutputDevices; + private CheckBox mCheckBoxAllChannels; + private CheckBox mCheckBoxInputChannelMasks; + private RadioGroup mRadioGroupOutputChannelMasks; + private RadioButton mRadioOutputChannelMasksNone; + private RadioButton mRadioOutputChannelMasksSome; + private RadioButton mRadioOutputChannelMasksAll; + private CheckBox mCheckBoxAllSampleRates; + private TextView mInstructionsTextView; private static final int[] INPUT_PRESETS = { - // VOICE_RECOGNITION gets tested in testInputs() - // StreamConfiguration.INPUT_PRESET_VOICE_RECOGNITION, StreamConfiguration.INPUT_PRESET_GENERIC, StreamConfiguration.INPUT_PRESET_CAMCORDER, - // TODO Resolve issue with echo cancellation killing the signal. - StreamConfiguration.INPUT_PRESET_VOICE_COMMUNICATION, StreamConfiguration.INPUT_PRESET_UNPROCESSED, + // Do not use INPUT_PRESET_VOICE_COMMUNICATION because AEC kills the signal. + StreamConfiguration.INPUT_PRESET_VOICE_RECOGNITION, StreamConfiguration.INPUT_PRESET_VOICE_PERFORMANCE, }; + private static final int[] SHORT_OUTPUT_CHANNEL_MASKS = { + StreamConfiguration.CHANNEL_MONO, + StreamConfiguration.CHANNEL_STEREO, + StreamConfiguration.CHANNEL_2POINT1, // Smallest mask with more than two channels. + StreamConfiguration.CHANNEL_5POINT1, // This mask is very common. + StreamConfiguration.CHANNEL_7POINT1POINT4, // More than 8 channels might break. + }; + + private static final int[] ALL_OUTPUT_CHANNEL_MASKS = { + StreamConfiguration.CHANNEL_MONO, + StreamConfiguration.CHANNEL_STEREO, + StreamConfiguration.CHANNEL_2POINT1, + StreamConfiguration.CHANNEL_TRI, + StreamConfiguration.CHANNEL_TRI_BACK, + StreamConfiguration.CHANNEL_3POINT1, + StreamConfiguration.CHANNEL_2POINT0POINT2, + StreamConfiguration.CHANNEL_2POINT1POINT2, + StreamConfiguration.CHANNEL_3POINT0POINT2, + StreamConfiguration.CHANNEL_3POINT1POINT2, + StreamConfiguration.CHANNEL_QUAD, + StreamConfiguration.CHANNEL_QUAD_SIDE, + StreamConfiguration.CHANNEL_SURROUND, + StreamConfiguration.CHANNEL_PENTA, + StreamConfiguration.CHANNEL_5POINT1, + StreamConfiguration.CHANNEL_5POINT1_SIDE, + StreamConfiguration.CHANNEL_6POINT1, + StreamConfiguration.CHANNEL_7POINT1, + StreamConfiguration.CHANNEL_5POINT1POINT2, + StreamConfiguration.CHANNEL_5POINT1POINT4, + StreamConfiguration.CHANNEL_7POINT1POINT2, + StreamConfiguration.CHANNEL_7POINT1POINT4, + }; + + private static final int[] SAMPLE_RATES = { + 8000, + 11025, + 12000, + 16000, + 22050, + 24000, + 32000, + 44100, + 48000, + 64000, + 88200, + 96000, + }; + @NonNull public static String comparePassedField(String prefix, Object failed, Object passed, String name) { try { @@ -109,16 +221,25 @@ public class TestDataPathsActivity extends BaseAutoGlitchActivity { return "ERROR - cannot access " + name; } } + public static String comparePassedInputPreset(String prefix, TestResult failed, TestResult passed) { + int failedValue = failed.inputPreset; + int passedValue = passed.inputPreset; + return (failedValue == passedValue) ? "" + : (prefix + " inPreset: passed = " + + StreamConfiguration.convertInputPresetToText(passedValue) + + ", failed = " + + StreamConfiguration.convertInputPresetToText(failedValue) + + "\n"); + } public static double calculatePhaseError(double p1, double p2) { - double diff = Math.abs(p1 - p2); + double diff = p1 - p2; // Wrap around the circle. - while (diff > (2 * Math.PI)) { - diff -= (2 * Math.PI); + while (diff > Math.PI) { + diff -= 2 * Math.PI; } - // A phase error close to 2*PI is actually a small phase error. - if (diff > Math.PI) { - diff = (2 * Math.PI) - diff; + while (diff < -Math.PI) { + diff += 2 * Math.PI; } return diff; } @@ -126,10 +247,6 @@ public class TestDataPathsActivity extends BaseAutoGlitchActivity { // Periodically query for magnitude and phase from the native detector. protected class DataPathSniffer extends NativeSniffer { - public DataPathSniffer(Activity activity) { - super(activity); - } - @Override public void startSniffer() { mMagnitude = -1.0; @@ -141,30 +258,28 @@ public class TestDataPathsActivity extends BaseAutoGlitchActivity { super.startSniffer(); } - @Override - public void run() { + private void gatherData() { mMagnitude = getMagnitude(); mMaxMagnitude = getMaxMagnitude(); - Log.d(TAG, String.format("magnitude = %7.4f, maxMagnitude = %7.4f", + Log.d(TAG, String.format(Locale.getDefault(), "magnitude = %7.4f, maxMagnitude = %7.4f", mMagnitude, mMaxMagnitude)); // Only look at the phase if we have a signal. if (mMagnitude >= MIN_REQUIRED_MAGNITUDE) { - double phase = getPhase(); + double phase = getPhaseDataPaths(); // Wait for the analyzer to get a lock on the signal. // Arbitrary number of phase measurements before we start measuring jitter. final int kMinPhaseMeasurementsRequired = 4; if (mPhaseCount >= kMinPhaseMeasurementsRequired) { - double phaseError = calculatePhaseError(phase, mPhase); - // low pass filter + double phaseError = Math.abs(calculatePhaseError(phase, mPhase)); + // collect average error mPhaseErrorSum += phaseError; mPhaseErrorCount++; - Log.d(TAG, String.format("phase = %7.4f, diff = %7.4f, jitter = %7.4f", - phase, phaseError, getAveragePhaseError())); + Log.d(TAG, String.format(Locale.getDefault(), "phase = %7.4f, mPhase = %7.4f, phaseError = %7.4f, jitter = %7.4f", + phase, mPhase, phaseError, getAveragePhaseError())); } mPhase = phase; mPhaseCount++; } - reschedule(); } public String getCurrentStatusReport() { @@ -179,7 +294,6 @@ public class TestDataPathsActivity extends BaseAutoGlitchActivity { return message.toString(); } - @Override public String getShortReport() { return "maxMag = " + getMagnitudeText(mMaxMagnitude) + ", jitter = " + getJitterText(); @@ -187,6 +301,7 @@ public class TestDataPathsActivity extends BaseAutoGlitchActivity { @Override public void updateStatusText() { + gatherData(); mLastGlitchReport = getCurrentStatusReport(); runOnUiThread(() -> { setAnalyzerText(mLastGlitchReport); @@ -194,18 +309,34 @@ public class TestDataPathsActivity extends BaseAutoGlitchActivity { } } + // Write to status and command view + private void setInstructionsText(final String text) { + runOnUiThread(new Runnable() { + @Override + public void run() { + mInstructionsTextView.setText(text); + } + }); + } + private String getJitterText() { return isPhaseJitterValid() ? getMagnitudeText(getAveragePhaseError()) : "?"; } @Override NativeSniffer createNativeSniffer() { - return new TestDataPathsActivity.DataPathSniffer(this); + return new TestDataPathsActivity.DataPathSniffer(); + } + + @Override + public String getShortReport() { + return ((DataPathSniffer) mNativeSniffer).getShortReport(); } native double getMagnitude(); native double getMaxMagnitude(); - native double getPhase(); + + native double getPhaseDataPaths(); @Override protected void inflateActivity() { @@ -215,10 +346,18 @@ public class TestDataPathsActivity extends BaseAutoGlitchActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); - mAudioManager = (AudioManager) getSystemService(Context.AUDIO_SERVICE); mCheckBoxInputPresets = (CheckBox)findViewById(R.id.checkbox_paths_input_presets); - mCheckBoxInputDevices = (CheckBox)findViewById(R.id.checkbox_paths_input_devices); - mCheckBoxOutputDevices = (CheckBox)findViewById(R.id.checkbox_paths_output_devices); + mCheckBoxAllChannels = (CheckBox)findViewById(R.id.checkbox_paths_all_channels); + mCheckBoxInputChannelMasks = (CheckBox)findViewById(R.id.checkbox_paths_in_channel_masks); + mCheckBoxAllSampleRates = + (CheckBox)findViewById(R.id.checkbox_paths_all_sample_rates); + + mInstructionsTextView = (TextView) findViewById(R.id.text_instructions); + + mRadioGroupOutputChannelMasks = (RadioGroup) findViewById(R.id.group_ch_mask_options); + mRadioOutputChannelMasksNone = (RadioButton) findViewById(R.id.radio_out_ch_masks_none); + mRadioOutputChannelMasksSome = (RadioButton) findViewById(R.id.radio_out_ch_masks_some); + mRadioOutputChannelMasksAll = (RadioButton) findViewById(R.id.radio_out_ch_masks_all); } @Override @@ -232,7 +371,7 @@ public class TestDataPathsActivity extends BaseAutoGlitchActivity { } static String getMagnitudeText(double value) { - return String.format(MAGNITUDE_FORMAT, value); + return String.format(Locale.getDefault(), MAGNITUDE_FORMAT, value); } protected String getConfigText(StreamConfiguration config) { @@ -244,35 +383,27 @@ public class TestDataPathsActivity extends BaseAutoGlitchActivity { } @Override - protected String shouldTestBeSkipped() { - String why = ""; + protected String whyShouldTestBeSkipped() { + String why = super.whyShouldTestBeSkipped(); StreamConfiguration requestedInConfig = mAudioInputTester.requestedConfiguration; StreamConfiguration requestedOutConfig = mAudioOutTester.requestedConfiguration; StreamConfiguration actualInConfig = mAudioInputTester.actualConfiguration; StreamConfiguration actualOutConfig = mAudioOutTester.actualConfiguration; - // No point running the test if we don't get the data path we requested. - if (actualInConfig.isMMap() != requestedInConfig.isMMap()) { - log("Did not get requested MMap input stream"); - why += "mmap"; - } - if (actualOutConfig.isMMap() != requestedOutConfig.isMMap()) { - log("Did not get requested MMap output stream"); - why += "mmap"; - } + // Did we request a device and not get that device? if (requestedInConfig.getDeviceId() != 0 && (requestedInConfig.getDeviceId() != actualInConfig.getDeviceId())) { - why += ", inDev(" + requestedInConfig.getDeviceId() - + "!=" + actualInConfig.getDeviceId() + ")"; + why += "inDev(" + requestedInConfig.getDeviceId() + + "!=" + actualInConfig.getDeviceId() + "),"; } if (requestedOutConfig.getDeviceId() != 0 && (requestedOutConfig.getDeviceId() != actualOutConfig.getDeviceId())) { why += ", outDev(" + requestedOutConfig.getDeviceId() - + "!=" + actualOutConfig.getDeviceId() + ")"; + + "!=" + actualOutConfig.getDeviceId() + "),"; } if ((requestedInConfig.getInputPreset() != actualInConfig.getInputPreset())) { why += ", inPre(" + requestedInConfig.getInputPreset() - + "!=" + actualInConfig.getInputPreset() + ")"; + + "!=" + actualInConfig.getInputPreset() + "),"; } return why; } @@ -288,10 +419,6 @@ public class TestDataPathsActivity extends BaseAutoGlitchActivity { @Override public String didTestFail() { String why = ""; - StreamConfiguration requestedInConfig = mAudioInputTester.requestedConfiguration; - StreamConfiguration requestedOutConfig = mAudioOutTester.requestedConfiguration; - StreamConfiguration actualInConfig = mAudioInputTester.actualConfiguration; - StreamConfiguration actualOutConfig = mAudioOutTester.actualConfiguration; if (mMaxMagnitude <= MIN_REQUIRED_MAGNITUDE) { why += ", mag"; } @@ -322,280 +449,387 @@ public class TestDataPathsActivity extends BaseAutoGlitchActivity { + ", IN" + (actualInConfig.isMMap() ? "-M" : "-L") + " D=" + actualInConfig.getDeviceId() + ", ch=" + channelText(getInputChannel(), actualInConfig.getChannelCount()) + + ", SR=" + actualInConfig.getSampleRate() + ", OUT" + (actualOutConfig.isMMap() ? "-M" : "-L") + " D=" + actualOutConfig.getDeviceId() + ", ch=" + channelText(getOutputChannel(), actualOutConfig.getChannelCount()) + + ", SR=" + actualOutConfig.getSampleRate() + ", mag = " + getMagnitudeText(mMaxMagnitude); } - void setupDeviceCombo(int numInputChannels, - int inputChannel, - int numOutputChannels, - int outputChannel) throws InterruptedException { - // Configure settings - StreamConfiguration requestedInConfig = mAudioInputTester.requestedConfiguration; - StreamConfiguration requestedOutConfig = mAudioOutTester.requestedConfiguration; - - requestedInConfig.reset(); - requestedOutConfig.reset(); - - requestedInConfig.setPerformanceMode(StreamConfiguration.PERFORMANCE_MODE_LOW_LATENCY); - requestedOutConfig.setPerformanceMode(StreamConfiguration.PERFORMANCE_MODE_LOW_LATENCY); - - requestedInConfig.setSharingMode(StreamConfiguration.SHARING_MODE_SHARED); - requestedOutConfig.setSharingMode(StreamConfiguration.SHARING_MODE_SHARED); - - requestedInConfig.setChannelCount(numInputChannels); - requestedOutConfig.setChannelCount(numOutputChannels); - - requestedInConfig.setMMap(false); - requestedOutConfig.setMMap(false); - - setInputChannel(inputChannel); - setOutputChannel(outputChannel); - } - - private TestResult testConfigurationsAddMagJitter() throws InterruptedException { - TestResult testResult = testConfigurations(); + @Override + protected TestResult testCurrentConfigurations() throws InterruptedException { + TestResult testResult = super.testCurrentConfigurations(); if (testResult != null) { testResult.addComment("mag = " + TestDataPathsActivity.getMagnitudeText(mMagnitude) + ", jitter = " + getJitterText()); - } - return testResult; - } - - void testPresetCombo(int inputPreset, - int numInputChannels, - int inputChannel, - int numOutputChannels, - int outputChannel, - boolean mmapEnabled - ) throws InterruptedException { - setupDeviceCombo(numInputChannels, inputChannel, numOutputChannels, outputChannel); - StreamConfiguration requestedInConfig = mAudioInputTester.requestedConfiguration; - requestedInConfig.setInputPreset(inputPreset); - requestedInConfig.setMMap(mmapEnabled); - - mMagnitude = -1.0; - TestResult testResult = testConfigurationsAddMagJitter(); - if (testResult != null) { + logOneLineSummary(testResult); int result = testResult.result; - String summary = getOneLineSummary() - + ", inPre = " - + StreamConfiguration.convertInputPresetToText(inputPreset) - + "\n"; - appendSummary(summary); if (result == TEST_RESULT_FAILED) { - if (getMagnitude() < 0.000001) { - testResult.addComment("The input is completely SILENT!"); - } else if (inputPreset == StreamConfiguration.INPUT_PRESET_VOICE_COMMUNICATION) { - testResult.addComment("Maybe sine wave blocked by Echo Cancellation!"); + int id = mAudioOutTester.actualConfiguration.getDeviceId(); + int deviceType = getDeviceInfoById(id).getType(); + int channelCount = mAudioOutTester.actualConfiguration.getChannelCount(); + if (deviceType == AudioDeviceInfo.TYPE_BUILTIN_EARPIECE + && channelCount == 2 + && getOutputChannel() == 1) { + testResult.addComment("Maybe EARPIECE does not mix stereo to mono!"); + } + if (deviceType == TYPE_BUILTIN_SPEAKER_SAFE + && channelCount == 2 + && getOutputChannel() == 0) { + testResult.addComment("Maybe SPEAKER_SAFE dropped channel zero!"); } } } + return testResult; } - void testPresetCombo(int inputPreset, - int numInputChannels, - int inputChannel, - int numOutputChannels, - int outputChannel - ) throws InterruptedException { - if (NativeEngine.isMMapSupported()) { - testPresetCombo(inputPreset, numInputChannels, inputChannel, - numOutputChannels, outputChannel, true); - } - testPresetCombo(inputPreset, numInputChannels, inputChannel, - numOutputChannels, outputChannel, false); - } - - void testPresetCombo(int inputPreset) throws InterruptedException { - setTestName("Test InPreset = " + StreamConfiguration.convertInputPresetToText(inputPreset)); - testPresetCombo(inputPreset, 1, 0, 1, 0); + private void logSection(String name) { + logBoth("\n#" + (getTestCount() + 1) + " ########### " + name + "\n"); } private void testInputPresets() throws InterruptedException { - logBoth("\nTest InputPreset -------"); - + logSection("InputPreset"); + StreamConfiguration requestedInConfig = mAudioInputTester.requestedConfiguration; + int originalPreset = requestedInConfig.getInputPreset(); for (int inputPreset : INPUT_PRESETS) { - testPresetCombo(inputPreset); + requestedInConfig.setInputPreset(inputPreset); + testPerformancePaths(); + } + requestedInConfig.setInputPreset(originalPreset); + } + + // The native out channel mask is its channel mask shifted right by 2 bits. + // See AudioFormat.convertChannelOutMaskToNativeMask() + int convertJavaOutChannelMaskToNativeChannelMask(int javaChannelMask) { + return javaChannelMask >> 2; + } + + // The native channel mask in AAudio and Oboe is different than the Java IN channel mask. + // See AAudioConvert_aaudioToAndroidChannelLayoutMask() + int convertJavaInChannelMaskToNativeChannelMask(int javaChannelMask) { + switch (javaChannelMask) { + case JAVA_CHANNEL_IN_MONO: + return StreamConfiguration.CHANNEL_MONO; + case JAVA_CHANNEL_IN_STEREO: + return StreamConfiguration.CHANNEL_STEREO; + case JAVA_CHANNEL_IN_FRONT_BACK: + return StreamConfiguration.CHANNEL_FRONT_BACK; + case JAVA_CHANNEL_IN_2POINT0POINT2: + return StreamConfiguration.CHANNEL_2POINT0POINT2; + case JAVA_CHANNEL_IN_2POINT1POINT2: + return StreamConfiguration.CHANNEL_2POINT1POINT2; + case JAVA_CHANNEL_IN_3POINT0POINT2: + return StreamConfiguration.CHANNEL_3POINT0POINT2; + case JAVA_CHANNEL_IN_3POINT1POINT2: + return StreamConfiguration.CHANNEL_3POINT1POINT2; + case JAVA_CHANNEL_IN_5POINT1: + return StreamConfiguration.CHANNEL_5POINT1; + default: + log("Unimplemented java channel mask: " + javaChannelMask + "\n"); + return JAVA_CHANNEL_UNDEFINED; } -// TODO Resolve issue with echo cancellation killing the signal. -// testPresetCombo(StreamConfiguration.INPUT_PRESET_VOICE_COMMUNICATION, -// 1, 0, 2, 0); -// testPresetCombo(StreamConfiguration.INPUT_PRESET_VOICE_COMMUNICATION, -// 1, 0, 2, 1); -// testPresetCombo(StreamConfiguration.INPUT_PRESET_VOICE_COMMUNICATION, -// 2, 0, 2, 0); -// testPresetCombo(StreamConfiguration.INPUT_PRESET_VOICE_COMMUNICATION, -// 2, 0, 2, 1); - } - - void testInputDeviceCombo(int deviceId, - int numInputChannels, - int inputChannel, - boolean mmapEnabled) throws InterruptedException { - final int numOutputChannels = 2; - setupDeviceCombo(numInputChannels, inputChannel, numOutputChannels, 0); + } - StreamConfiguration requestedInConfig = mAudioInputTester.requestedConfiguration; - requestedInConfig.setInputPreset(StreamConfiguration.INPUT_PRESET_VOICE_RECOGNITION); - requestedInConfig.setDeviceId(deviceId); - requestedInConfig.setMMap(mmapEnabled); + void logOneLineSummary(TestResult testResult) { + logOneLineSummary(testResult, ""); + } - mMagnitude = -1.0; - TestResult testResult = testConfigurationsAddMagJitter(); - if (testResult != null) { - appendSummary(getOneLineSummary() + "\n"); + void logOneLineSummary(TestResult testResult, String extra) { + int result = testResult.result; + String oneLineSummary; + if (result == TEST_RESULT_SKIPPED) { + oneLineSummary = "#" + mAutomatedTestRunner.getTestCount() + extra + ", SKIP"; + } else if (result == TEST_RESULT_FAILED) { + oneLineSummary = getOneLineSummary() + extra + ", FAIL"; + } else { + oneLineSummary = getOneLineSummary() + extra; } + appendSummary(oneLineSummary + "\n"); } - void testInputDeviceCombo(int deviceId, - int deviceType, - int numInputChannels, - int inputChannel) throws InterruptedException { + void logBoth(String text) { + log(text); + appendSummary(text + "\n"); + } - String typeString = AudioDeviceInfoConverter.typeToString(deviceType); - setTestName("Test InDev: #" + deviceId + " " + typeString - + "_" + inputChannel + "/" + numInputChannels); - if (NativeEngine.isMMapSupported()) { - testInputDeviceCombo(deviceId, numInputChannels, inputChannel, true); - } - testInputDeviceCombo(deviceId, numInputChannels, inputChannel, false); - } - - void testInputDevices() throws InterruptedException { - logBoth("\nTest Input Devices -------"); - - AudioDeviceInfo[] devices = mAudioManager.getDevices(AudioManager.GET_DEVICES_INPUTS); - int numTested = 0; - for (AudioDeviceInfo deviceInfo : devices) { - log("----\n" - + AudioDeviceInfoConverter.toString(deviceInfo) + "\n"); - if (!deviceInfo.isSource()) continue; // FIXME log as error?! - int deviceType = deviceInfo.getType(); - if (deviceType == AudioDeviceInfo.TYPE_BUILTIN_MIC) { - int id = deviceInfo.getId(); - int[] channelCounts = deviceInfo.getChannelCounts(); - numTested++; - // Always test mono and stereo. - testInputDeviceCombo(id, deviceType, 1, 0); - testInputDeviceCombo(id, deviceType, 2, 0); - testInputDeviceCombo(id, deviceType, 2, 1); - if (channelCounts.length > 0) { - for (int numChannels : channelCounts) { - // Test higher channel counts. - if (numChannels > 2) { - log("numChannels = " + numChannels + "\n"); - for (int channel = 0; channel < numChannels; channel++) { - testInputDeviceCombo(id, deviceType, numChannels, channel); - } - } - } - } - } else { - log("Device skipped for type."); - } + void logFailed(String text) { + log(text); + logAnalysis(text + "\n"); + } + + private void testDeviceOutputInfo(AudioDeviceInfo outputDeviceInfo) throws InterruptedException { + AudioDeviceInfo inputDeviceInfo = findCompatibleInputDevice(outputDeviceInfo.getType()); + showDeviceInfo(outputDeviceInfo, inputDeviceInfo); + if (inputDeviceInfo == null) { + return; + } + + StreamConfiguration requestedInConfig = mAudioInputTester.requestedConfiguration; + StreamConfiguration requestedOutConfig = mAudioOutTester.requestedConfiguration; + requestedInConfig.reset(); + requestedOutConfig.reset(); + requestedInConfig.setDeviceId(inputDeviceInfo.getId()); + requestedOutConfig.setDeviceId(outputDeviceInfo.getId()); + resetChannelConfigurations(requestedInConfig, requestedOutConfig); + + if (mCheckBoxAllChannels.isChecked()) { + runOnUiThread(() -> mCheckBoxAllChannels.setEnabled(false)); + testOutputChannelCounts(inputDeviceInfo, outputDeviceInfo); + } + + if (mCheckBoxInputPresets.isChecked()) { + runOnUiThread(() -> mCheckBoxInputPresets.setEnabled(false)); + testInputPresets(); + } + + if (mCheckBoxAllSampleRates.isChecked()) { + logSection("Sample Rates"); + runOnUiThread(() -> mCheckBoxAllSampleRates.setEnabled(false)); + for (int sampleRate : SAMPLE_RATES) { + requestedInConfig.setSampleRate(sampleRate); + requestedOutConfig.setSampleRate(sampleRate); + testPerformancePaths(); + } + } + requestedInConfig.setSampleRate(0); + requestedOutConfig.setSampleRate(0); + + // Channel Masks added to AAudio API in S_V2 + if (android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.S_V2 + && isDeviceTypeMixedForLoopback(outputDeviceInfo.getType())) { + + if (mCheckBoxInputChannelMasks.isChecked()) { // INPUT? + logSection("Input Channel Masks"); + runOnUiThread(() -> mCheckBoxInputChannelMasks.setEnabled(false)); + + resetChannelConfigurations(requestedInConfig, requestedOutConfig); + requestedInConfig.setChannelCount(0); + // Test the reported channel masks. + int[] channelMasks = inputDeviceInfo.getChannelMasks(); + if (channelMasks.length > 0) { + for (int channelMask : channelMasks) { + int nativeChannelMask = + convertJavaInChannelMaskToNativeChannelMask(channelMask); + if (nativeChannelMask == JAVA_CHANNEL_UNDEFINED) { + log("channelMask: " + channelMask + " not supported. Skipping.\n"); + continue; + } + log("\n#### nativeChannelMask = " + + convertChannelMaskToText(nativeChannelMask) + "\n"); + int channelCount = Integer.bitCount(nativeChannelMask); + requestedInConfig.setChannelMask(nativeChannelMask); + for (int channel = 0; channel < channelCount; channel++) { + setInputChannel(channel); + testPerformancePaths(); + } + } + } + resetChannelConfigurations(requestedInConfig, requestedOutConfig); + } + + runOnUiThread(() -> mRadioGroupOutputChannelMasks.setEnabled(false)); + if (!mRadioOutputChannelMasksNone.isChecked()) { // OUTPUT? + logSection("Output Channel Masks"); + requestedInConfig.setChannelCount(1); + for (int channelMask : mRadioOutputChannelMasksAll.isChecked() ? + ALL_OUTPUT_CHANNEL_MASKS : SHORT_OUTPUT_CHANNEL_MASKS) { + int channelCount = Integer.bitCount(channelMask); + requestedOutConfig.setChannelMask(channelMask); + for (int channel = 0; channel < channelCount; channel++) { + setOutputChannel(channel); + testPerformancePaths(); + } + } + resetChannelConfigurations(requestedInConfig, requestedOutConfig); + } + } + } + + private void resetChannelConfigurations(StreamConfiguration requestedInConfig, StreamConfiguration requestedOutConfig) { + requestedInConfig.setChannelMask(0); + requestedOutConfig.setChannelMask(0); + requestedInConfig.setChannelCount(1); + requestedOutConfig.setChannelCount(1); + setInputChannel(0); + setOutputChannel(0); + } + + private void showDeviceInfo(AudioDeviceInfo outputDeviceInfo, AudioDeviceInfo inputDeviceInfo) { + String deviceText = "OUT: type = " + + AudioDeviceInfoConverter.typeToString(outputDeviceInfo.getType()) + + ", #ch = " + findLargestChannelCount(outputDeviceInfo.getChannelCounts()); + + setInstructionsText(deviceText); + + if (inputDeviceInfo == null) { + deviceText += "ERROR - cannot find compatible device type for input!"; + } else { + deviceText = "IN: type = " + + AudioDeviceInfoConverter.typeToString(inputDeviceInfo.getType()) + + ", #ch = " + findLargestChannelCount(inputDeviceInfo.getChannelCounts()) + + "\n" + deviceText; } + setInstructionsText(deviceText); + } - if (numTested == 0) { - log("NO INPUT DEVICE FOUND!\n"); + public static int findLargestChannelCount(int[] arr) { + if (arr == null || arr.length == 0) { + return 2; } + return findLargestInt(arr); } - void testOutputDeviceCombo(int deviceId, - int deviceType, - int numOutputChannels, - int outputChannel, - boolean mmapEnabled) throws InterruptedException { - final int numInputChannels = 2; // TODO review, done because of mono problems on some devices - setupDeviceCombo(numInputChannels, 0, numOutputChannels, outputChannel); + public static int findLargestInt(int[] arr) { + if (arr == null || arr.length == 0) { + throw new IllegalArgumentException("Array cannot be empty"); + } + + int max = arr[0]; + for (int i = 1; i < arr.length; i++) { + if (arr[i] > max) { + max = arr[i]; + } + } + return max; + } + private void testOutputChannelCounts(AudioDeviceInfo inputDeviceInfo, AudioDeviceInfo outputDeviceInfo) throws InterruptedException { + logSection("Output Channel Counts"); + ArrayList<Integer> channelCountsTested =new ArrayList<Integer>(); + StreamConfiguration requestedInConfig = mAudioInputTester.requestedConfiguration; StreamConfiguration requestedOutConfig = mAudioOutTester.requestedConfiguration; - requestedOutConfig.setDeviceId(deviceId); - requestedOutConfig.setMMap(mmapEnabled); - mMagnitude = -1.0; - TestResult testResult = testConfigurationsAddMagJitter(); - if (testResult != null) { - int result = testResult.result; - appendSummary(getOneLineSummary() + "\n"); - if (result == TEST_RESULT_FAILED) { - if (deviceType == AudioDeviceInfo.TYPE_BUILTIN_EARPIECE - && numOutputChannels == 2 - && outputChannel == 1) { - testResult.addComment("Maybe EARPIECE does not mix stereo to mono!"); + int[] outputChannelCounts = outputDeviceInfo.getChannelCounts(); + if (isDeviceTypeMixedForLoopback(outputDeviceInfo.getType())) { + requestedInConfig.setChannelCount(1); + setInputChannel(0); + // test mono + requestedOutConfig.setChannelCount(1); + channelCountsTested.add(1); + setOutputChannel(0); + testPerformancePaths(); + // test stereo + requestedOutConfig.setChannelCount(2); + channelCountsTested.add(2); + setOutputChannel(0); + testPerformancePaths(); + setOutputChannel(1); + testPerformancePaths(); + // Test channels for each channelCount above 2 + for (int numChannels : outputChannelCounts) { + log("numChannels = " + numChannels); + if (numChannels > 4) { + log("numChannels forced to 4!"); } - if (deviceType == TYPE_BUILTIN_SPEAKER_SAFE - && numOutputChannels == 2 - && outputChannel == 0) { - testResult.addComment("Maybe SPEAKER_SAFE dropped channel zero!"); + if (!channelCountsTested.contains(numChannels)) { + requestedOutConfig.setChannelCount(numChannels); + channelCountsTested.add(numChannels); + for (int channel = 0; channel < numChannels; channel++) { + setOutputChannel(channel); + testPerformancePaths(); + } + } + } + } else { + // test mono + testMatchingChannels(1); + channelCountsTested.add(1); + // Test two matching stereo channels. + testMatchingChannels(2); + channelCountsTested.add(2); + // Test matching channels for each channelCount above 2 + for (int numChannels : outputChannelCounts) { + log("numChannels = " + numChannels); + if (numChannels > 4) { + log("numChannels forced to 4!"); + numChannels = 4; + } + if (!channelCountsTested.contains(numChannels)) { + testMatchingChannels(numChannels); + channelCountsTested.add(numChannels); } } } + // Restore defaults. + requestedInConfig.setChannelCount(1); + setInputChannel(0); + requestedOutConfig.setChannelCount(1); + setOutputChannel(0); + } + + private void testMatchingChannels(int numChannels) throws InterruptedException { + mAudioInputTester.requestedConfiguration.setChannelCount(numChannels); + mAudioOutTester.requestedConfiguration.setChannelCount(numChannels); + for (int channel = 0; channel < numChannels; channel++) { + setInputChannel(channel); + setOutputChannel(channel); + testPerformancePaths(); + } } - void testOutputDeviceCombo(int deviceId, - int deviceType, - int numOutputChannels, - int outputChannel) throws InterruptedException { - String typeString = AudioDeviceInfoConverter.typeToString(deviceType); - setTestName("Test OutDev: #" + deviceId + " " + typeString - + "_" + outputChannel + "/" + numOutputChannels); + private void testPerformancePaths() throws InterruptedException { + StreamConfiguration requestedInConfig = mAudioInputTester.requestedConfiguration; + StreamConfiguration requestedOutConfig = mAudioOutTester.requestedConfiguration; + + requestedInConfig.setSharingMode(StreamConfiguration.SHARING_MODE_SHARED); + requestedOutConfig.setSharingMode(StreamConfiguration.SHARING_MODE_SHARED); + + // Legacy NONE + requestedInConfig.setMMap(false); + requestedOutConfig.setMMap(false); + requestedInConfig.setPerformanceMode(StreamConfiguration.PERFORMANCE_MODE_NONE); + requestedOutConfig.setPerformanceMode(StreamConfiguration.PERFORMANCE_MODE_NONE); + testCurrentConfigurations(); + + // Legacy LOW_LATENCY + requestedInConfig.setPerformanceMode(StreamConfiguration.PERFORMANCE_MODE_LOW_LATENCY); + requestedOutConfig.setPerformanceMode(StreamConfiguration.PERFORMANCE_MODE_LOW_LATENCY); + testCurrentConfigurations(); + + // MMAP LowLatency if (NativeEngine.isMMapSupported()) { - testOutputDeviceCombo(deviceId, deviceType, numOutputChannels, outputChannel, true); + requestedInConfig.setMMap(true); + requestedOutConfig.setMMap(true); + testCurrentConfigurations(); } - testOutputDeviceCombo(deviceId, deviceType, numOutputChannels, outputChannel, false); - } - - void logBoth(String text) { - log(text); - appendSummary(text + "\n"); - } + requestedInConfig.setMMap(false); + requestedOutConfig.setMMap(false); - void logFailed(String text) { - log(text); - logAnalysis(text + "\n"); } - void testOutputDevices() throws InterruptedException { - logBoth("\nTest Output Devices -------"); - - AudioDeviceInfo[] devices = mAudioManager.getDevices(AudioManager.GET_DEVICES_OUTPUTS); - int numTested = 0; - for (AudioDeviceInfo deviceInfo : devices) { - log("----\n" - + AudioDeviceInfoConverter.toString(deviceInfo) + "\n"); - if (!deviceInfo.isSink()) continue; - int deviceType = deviceInfo.getType(); - if (deviceType == AudioDeviceInfo.TYPE_BUILTIN_SPEAKER - || deviceType == AudioDeviceInfo.TYPE_BUILTIN_EARPIECE - || deviceType == TYPE_BUILTIN_SPEAKER_SAFE) { - int id = deviceInfo.getId(); - int[] channelCounts = deviceInfo.getChannelCounts(); - numTested++; - // Always test mono and stereo. - testOutputDeviceCombo(id, deviceType, 1, 0); - testOutputDeviceCombo(id, deviceType, 2, 0); - testOutputDeviceCombo(id, deviceType, 2, 1); - if (channelCounts.length > 0) { - for (int numChannels : channelCounts) { - // Test higher channel counts. - if (numChannels > 2) { - log("numChannels = " + numChannels + "\n"); - for (int channel = 0; channel < numChannels; channel++) { - testOutputDeviceCombo(id, deviceType, numChannels, channel); - } - } - } - } - } else { - log("Device skipped for type."); - } + private void testOutputDeviceTypes() throws InterruptedException { + // Determine which output device type to test based on priorities. + AudioDeviceInfo info = getDeviceInfoByType(AudioDeviceInfo.TYPE_USB_DEVICE, + AudioManager.GET_DEVICES_OUTPUTS); + if (info != null) { + testDeviceOutputInfo(info); + return; + } + info = getDeviceInfoByType(AudioDeviceInfo.TYPE_USB_HEADSET, + AudioManager.GET_DEVICES_OUTPUTS); + if (info != null) { + testDeviceOutputInfo(info); + return; } - if (numTested == 0) { - log("NO OUTPUT DEVICE FOUND!\n"); + info = getDeviceInfoByType(AudioDeviceInfo.TYPE_WIRED_HEADSET, + AudioManager.GET_DEVICES_OUTPUTS); + if (info != null) { + testDeviceOutputInfo(info); + return; + } + // Test both SPEAKER and SPEAKER_SAFE + info = getDeviceInfoByType(AudioDeviceInfo.TYPE_BUILTIN_SPEAKER, + AudioManager.GET_DEVICES_OUTPUTS); + if (info != null) { + testDeviceOutputInfo(info); + // Continue on to SPEAKER_SAFE + } + info = getDeviceInfoByType(AudioDeviceInfo.TYPE_BUILTIN_SPEAKER_SAFE, + AudioManager.GET_DEVICES_OUTPUTS); + if (info != null) { + testDeviceOutputInfo(info); } } @@ -610,31 +844,25 @@ public class TestDataPathsActivity extends BaseAutoGlitchActivity { mTestResults.clear(); mDurationSeconds = DURATION_SECONDS; - if (mCheckBoxInputPresets.isChecked()) { - runOnUiThread(() -> mCheckBoxInputPresets.setEnabled(false)); - testInputPresets(); - } - if (mCheckBoxInputDevices.isChecked()) { - runOnUiThread(() -> mCheckBoxInputDevices.setEnabled(false)); - testInputDevices(); - } - if (mCheckBoxOutputDevices.isChecked()) { - runOnUiThread(() -> mCheckBoxOutputDevices.setEnabled(false)); - testOutputDevices(); - } + runOnUiThread(() -> keepScreenOn(true)); - analyzeTestResults(); + testOutputDeviceTypes(); + + compareFailedTestsWithNearestPassingTest(); } catch (InterruptedException e) { - analyzeTestResults(); + compareFailedTestsWithNearestPassingTest(); } catch (Exception e) { log(e.getMessage()); showErrorToast(e.getMessage()); } finally { runOnUiThread(() -> { mCheckBoxInputPresets.setEnabled(true); - mCheckBoxInputDevices.setEnabled(true); - mCheckBoxOutputDevices.setEnabled(true); + mCheckBoxAllChannels.setEnabled(true); + mCheckBoxInputChannelMasks.setEnabled(true); + mRadioGroupOutputChannelMasks.setEnabled(true); + mCheckBoxAllSampleRates.setEnabled(true); + keepScreenOn(false); }); } } @@ -645,22 +873,59 @@ public class TestDataPathsActivity extends BaseAutoGlitchActivity { StreamConfiguration requestedOutConfig = mAudioOutTester.requestedConfiguration; configureStreamsFromBundle(mBundleFromIntent, requestedInConfig, requestedOutConfig); - boolean shouldUseInputPresets = mBundleFromIntent.getBoolean(KEY_USE_INPUT_PRESETS, + // These are the current supported options. + final boolean shouldUseInputPresets = mBundleFromIntent.getBoolean(KEY_USE_INPUT_PRESETS, VALUE_DEFAULT_USE_INPUT_PRESETS); - boolean shouldUseInputDevices = mBundleFromIntent.getBoolean(KEY_USE_INPUT_DEVICES, - VALUE_DEFAULT_USE_INPUT_DEVICES); - boolean shouldUseOutputDevices = mBundleFromIntent.getBoolean(KEY_USE_OUTPUT_DEVICES, - VALUE_DEFAULT_USE_OUTPUT_DEVICES); - int singleTestIndex = mBundleFromIntent.getInt(KEY_SINGLE_TEST_INDEX, + final boolean shouldUseAllSampleRates = + mBundleFromIntent.getBoolean(KEY_USE_ALL_SAMPLE_RATES, + VALUE_DEFAULT_USE_ALL_SAMPLE_RATES); + + final int singleTestIndex = mBundleFromIntent.getInt(KEY_SINGLE_TEST_INDEX, VALUE_DEFAULT_SINGLE_TEST_INDEX); + // The old deprecated commands will get mapped to the closest new options. + final boolean shouldUseInputDevices = mBundleFromIntent.getBoolean(KEY_USE_INPUT_DEVICES, + VALUE_DEFAULT_USE_INPUT_CHANNEL_MASKS); + final boolean shouldUseInputChannelMasks = + mBundleFromIntent.getBoolean(KEY_USE_INPUT_CHANNEL_MASKS, + shouldUseInputDevices); + + final boolean shouldUseOutputDevices = mBundleFromIntent.getBoolean(KEY_USE_OUTPUT_DEVICES, + VALUE_DEFAULT_USE_ALL_CHANNEL_COUNTS); + final boolean shouldUseAllChannelCounts = + mBundleFromIntent.getBoolean(KEY_USE_ALL_CHANNEL_COUNTS, + shouldUseOutputDevices); + + final boolean shouldUseAllOutputChannelMasks = + mBundleFromIntent.getBoolean(KEY_USE_ALL_OUTPUT_CHANNEL_MASKS, + VALUE_DEFAULT_USE_ALL_OUTPUT_CHANNEL_MASKS); + final int defaultOutputChannelMasksLevel = shouldUseAllOutputChannelMasks + ? COVERAGE_LEVEL_ALL : COVERAGE_LEVEL_SOME; + final int outputChannelMasksLevel = mBundleFromIntent.getInt(KEY_OUTPUT_CHANNEL_MASKS_LEVEL, + defaultOutputChannelMasksLevel); + runOnUiThread(() -> { mCheckBoxInputPresets.setChecked(shouldUseInputPresets); - mCheckBoxInputDevices.setChecked(shouldUseInputDevices); - mCheckBoxOutputDevices.setChecked(shouldUseOutputDevices); + mCheckBoxAllSampleRates.setChecked(shouldUseAllSampleRates); mAutomatedTestRunner.setTestIndexText(singleTestIndex); + mCheckBoxAllChannels.setChecked(shouldUseAllChannelCounts); + mCheckBoxInputChannelMasks.setChecked(shouldUseInputChannelMasks); + switch(outputChannelMasksLevel) { + case COVERAGE_LEVEL_ALL: + mRadioOutputChannelMasksAll.setChecked(true); + break; + case COVERAGE_LEVEL_SOME: + mRadioOutputChannelMasksSome.setChecked(true); + break; + case COVERAGE_LEVEL_NONE: + default: + mRadioOutputChannelMasksNone.setChecked(true); + break; + } }); + // This will sync with the above checkbox code because it will log on the UI + // thread before running any tests. mAutomatedTestRunner.startTest(); } } |