From d15051c29288713ed46dc4929d5a43e9ca779949 Mon Sep 17 00:00:00 2001 From: Phil Burk Date: Mon, 12 Feb 2024 16:16:01 -0800 Subject: [PATCH 1/6] OboeTester: improve Data Paths for wired headsets --- .../src/main/cpp/analyzer/BaseSineAnalyzer.h | 3 +- .../src/main/cpp/analyzer/GlitchAnalyzer.h | 10 +- .../app/src/main/cpp/jni-bridge.cpp | 6 + .../oboetester/BaseAutoGlitchActivity.java | 145 ++++++++- .../oboetester/ManualGlitchActivity.java | 71 +++++ .../oboetester/TestDataPathsActivity.java | 285 ++++++++++++++---- .../res/layout/activity_manual_glitches.xml | 1 + 7 files changed, 440 insertions(+), 81 deletions(-) diff --git a/apps/OboeTester/app/src/main/cpp/analyzer/BaseSineAnalyzer.h b/apps/OboeTester/app/src/main/cpp/analyzer/BaseSineAnalyzer.h index 90836c0bc..7c7fc80f2 100644 --- a/apps/OboeTester/app/src/main/cpp/analyzer/BaseSineAnalyzer.h +++ b/apps/OboeTester/app/src/main/cpp/analyzer/BaseSineAnalyzer.h @@ -46,6 +46,7 @@ class BaseSineAnalyzer : public LoopbackProcessor { } double getPhaseOffset() { + ALOGD("%s(), mPhaseOffset = %f\n", __func__, mPhaseOffset); return mPhaseOffset; } @@ -129,7 +130,6 @@ class BaseSineAnalyzer : public LoopbackProcessor { double magnitude = 2.0 * sqrt((sinMean * sinMean) + (cosMean * cosMean)); if (phasePtr != nullptr) { double phase = atan2(cosMean, sinMean); - *phasePtr = phase; } return magnitude; @@ -153,6 +153,7 @@ class BaseSineAnalyzer : public LoopbackProcessor { if (mFramesAccumulated == mSinePeriod) { const double coefficient = 0.1; double magnitude = calculateMagnitudePhase(&mPhaseOffset); + ALOGD("%s(), mPhaseOffset = %f\n", __func__, mPhaseOffset); // One pole averaging filter. setMagnitude((mMagnitude * (1.0 - coefficient)) + (magnitude * coefficient)); resetAccumulator(); diff --git a/apps/OboeTester/app/src/main/cpp/analyzer/GlitchAnalyzer.h b/apps/OboeTester/app/src/main/cpp/analyzer/GlitchAnalyzer.h index dc06dec7a..583ac42b8 100644 --- a/apps/OboeTester/app/src/main/cpp/analyzer/GlitchAnalyzer.h +++ b/apps/OboeTester/app/src/main/cpp/analyzer/GlitchAnalyzer.h @@ -54,10 +54,6 @@ class GlitchAnalyzer : public BaseSineAnalyzer { return mSinePeriod; } - float getPhaseOffset() const { - return mPhaseOffset; - } - int32_t getGlitchCount() const { return mGlitchCount; } @@ -188,8 +184,8 @@ class GlitchAnalyzer : public BaseSineAnalyzer { // Must be a multiple of the period or the calculation will not be accurate. if (mFramesAccumulated == mSinePeriod * PERIODS_NEEDED_FOR_LOCK) { setMagnitude(calculateMagnitudePhase(&mPhaseOffset)); -// ALOGD("%s() mag = %f, offset = %f, prev = %f", -// __func__, mMagnitude, mPhaseOffset, mPreviousPhaseOffset); + ALOGD("%s() mag = %f, mPhaseOffset = %f", + __func__, mMagnitude, mPhaseOffset); if (mMagnitude > mThreshold) { if (fabs(mPhaseOffset) < kMaxPhaseError) { mState = STATE_LOCKED; @@ -232,7 +228,7 @@ class GlitchAnalyzer : public BaseSineAnalyzer { // Must be a multiple of the period or the calculation will not be accurate. if (transformSample(sample, mInputPhase)) { // Adjust phase to account for sample rate drift. - mInputPhase += mPhaseOffset; + // FIXME mInputPhase += mPhaseOffset; mMeanSquareNoise = mSumSquareNoise * mInverseSinePeriod; mMeanSquareSignal = mSumSquareSignal * mInverseSinePeriod; diff --git a/apps/OboeTester/app/src/main/cpp/jni-bridge.cpp b/apps/OboeTester/app/src/main/cpp/jni-bridge.cpp index faa1d3259..9cb9ffe6b 100644 --- a/apps/OboeTester/app/src/main/cpp/jni-bridge.cpp +++ b/apps/OboeTester/app/src/main/cpp/jni-bridge.cpp @@ -812,6 +812,12 @@ Java_com_mobileer_oboetester_TestDataPathsActivity_getMaxMagnitude(JNIEnv *env, return engine.mActivityDataPath.getDataPathAnalyzer()->getMaxMagnitude(); } +JNIEXPORT double JNICALL +Java_com_mobileer_oboetester_TestDataPathsActivity_getPhaseDataPaths(JNIEnv *env, + jobject instance) { + return engine.mActivityDataPath.getDataPathAnalyzer()->getPhaseOffset(); +} + JNIEXPORT void JNICALL Java_com_mobileer_oboetester_GlitchActivity_setTolerance(JNIEnv *env, jobject instance, diff --git a/apps/OboeTester/app/src/main/java/com/mobileer/oboetester/BaseAutoGlitchActivity.java b/apps/OboeTester/app/src/main/java/com/mobileer/oboetester/BaseAutoGlitchActivity.java index 012966cfa..1ea62dab6 100644 --- a/apps/OboeTester/app/src/main/java/com/mobileer/oboetester/BaseAutoGlitchActivity.java +++ b/apps/OboeTester/app/src/main/java/com/mobileer/oboetester/BaseAutoGlitchActivity.java @@ -16,11 +16,15 @@ package com.mobileer.oboetester; +import static com.mobileer.oboetester.StreamConfiguration.UNSPECIFIED; import static com.mobileer.oboetester.StreamConfiguration.convertChannelMaskToText; import android.content.Context; +import android.media.AudioDeviceInfo; import android.media.AudioManager; import android.os.Bundle; + +import androidx.annotation.NonNull; import androidx.annotation.Nullable; import java.io.IOException; @@ -40,6 +44,8 @@ public class BaseAutoGlitchActivity extends GlitchActivity { protected int mGapMillis = DEFAULT_GAP_MILLIS; private String mTestName = ""; + protected AudioManager mAudioManager; + protected ArrayList mTestResults = new ArrayList(); void logDeviceInfo() { @@ -56,7 +62,12 @@ void setTestName(String name) { mTestName = name; } - private static class TestDirection { + @Override + public int getDeviceId() { + return super.getDeviceId(); + } + + private static class TestStreamOptions { public final int channelUsed; public final int channelCount; public final int channelMask; @@ -65,7 +76,7 @@ private static class TestDirection { public final int performanceMode; public final int sharingMode; - public TestDirection(StreamConfiguration configuration, int channelUsed) { + public TestStreamOptions(StreamConfiguration configuration, int channelUsed) { this.channelUsed = channelUsed; channelCount = configuration.getChannelCount(); channelMask = configuration.getChannelMask(); @@ -75,7 +86,7 @@ public TestDirection(StreamConfiguration configuration, int channelUsed) { sharingMode = configuration.getSharingMode(); } - int countDifferences(TestDirection other) { + int countDifferences(TestStreamOptions other) { int count = 0; count += (channelUsed != other.channelUsed) ? 1 : 0; count += (channelCount != other.channelCount) ? 1 : 0; @@ -87,7 +98,7 @@ int countDifferences(TestDirection other) { return count; } - public String comparePassedDirection(String prefix, TestDirection passed) { + public String comparePassedDirection(String prefix, TestStreamOptions passed) { StringBuffer text = new StringBuffer(); text.append(TestDataPathsActivity.comparePassedField(prefix, this, passed, "channelUsed")); text.append(TestDataPathsActivity.comparePassedField(prefix,this, passed, "channelCount")); @@ -111,8 +122,8 @@ public String toString() { protected static class TestResult { final int testIndex; - final TestDirection input; - final TestDirection output; + final TestStreamOptions input; + final TestStreamOptions output; public final int inputPreset; public final int sampleRate; final String testName; // name or purpose of test @@ -128,8 +139,8 @@ public TestResult(int testIndex, int outputChannel) { this.testIndex = testIndex; this.testName = testName; - input = new TestDirection(inputConfiguration, inputChannel); - output = new TestDirection(outputConfiguration, outputChannel); + input = new TestStreamOptions(inputConfiguration, inputChannel); + output = new TestStreamOptions(outputConfiguration, outputChannel); sampleRate = outputConfiguration.getSampleRate(); this.inputPreset = inputConfiguration.getInputPreset(); } @@ -185,6 +196,7 @@ public int getResult(int result) { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); + mAudioManager = (AudioManager) getSystemService(Context.AUDIO_SERVICE); mAutomatedTestRunner = findViewById(R.id.auto_test_runner); mAutomatedTestRunner.setActivity(this); @@ -220,7 +232,7 @@ protected String getConfigText(StreamConfiguration config) { + ", SR = " + String.format(Locale.getDefault(), "%5d", config.getSampleRate()) + ", Perf = " + StreamConfiguration.convertPerformanceModeToText( config.getPerformanceMode()) - + ", " + StreamConfiguration.convertSharingModeToText(config.getSharingMode()) + + ",\n " + StreamConfiguration.convertSharingModeToText(config.getSharingMode()) + ", ch = " + channelText(channel, config.getChannelCount()) + ", cm = " + convertChannelMaskToText(config.getChannelMask()); } @@ -240,14 +252,41 @@ protected String getStreamText(AudioStreamBase stream) { // Run one test based on the requested input/output configurations. @Nullable protected TestResult testInOutConfigurations() throws InterruptedException { - int result = TEST_RESULT_SKIPPED; + +// +// StreamConfiguration requestedInConfig = mAudioInputTester.requestedConfiguration; +// StreamConfiguration requestedOutConfig = mAudioOutTester.requestedConfiguration; +// +// // Check to make sure the input output device types are compatible. +// if (requestedInConfig.getDeviceId() == UNSPECIFIED) { +// if (requestedOutConfig.getDeviceId() != UNSPECIFIED) { +// int compatibleDeviceId = findCompatibleDevice(requestedOutConfig.getDeviceId(), +// true /* isInput */); +// requestedInConfig.setDeviceId(compatibleDeviceId); +// } +// } else if (requestedOutConfig.getDeviceId() == UNSPECIFIED) { +// if (requestedInConfig.getDeviceId() != UNSPECIFIED) { +// int compatibleDeviceId = findCompatibleDevice(requestedInConfig.getDeviceId(), +// false /* isInput */); +// requestedOutConfig.setDeviceId(compatibleDeviceId); +// } +// } + + TestResult testResult = testCurrentConfigurations(); + + return testResult; + } + + + @NonNull + protected TestResult testCurrentConfigurations() throws InterruptedException { mAutomatedTestRunner.incrementTestCount(); if ((getSingleTestIndex() >= 0) && (mAutomatedTestRunner.getTestCount() != getSingleTestIndex())) { return null; } log("========================== #" + mAutomatedTestRunner.getTestCount()); - + int result = 0; StreamConfiguration requestedInConfig = mAudioInputTester.requestedConfiguration; StreamConfiguration requestedOutConfig = mAudioOutTester.requestedConfiguration; @@ -372,10 +411,92 @@ protected TestResult testInOutConfigurations() throws InterruptedException { testResult.setResult(result); mTestResults.add(testResult); } - return testResult; } + protected AudioDeviceInfo getDeviceInfoById(int deviceId) { + AudioDeviceInfo[] devices = mAudioManager.getDevices(AudioManager.GET_DEVICES_ALL); + for (AudioDeviceInfo deviceInfo : devices) { + if (deviceInfo.getId() == deviceId) { + return deviceInfo; + } + } + return null; + } + + protected AudioDeviceInfo getDeviceInfoByType(int deviceType, int flags) { + AudioDeviceInfo[] devices = mAudioManager.getDevices(flags); + for (AudioDeviceInfo deviceInfo : devices) { + if (deviceInfo.getType() == deviceType) { + return deviceInfo; + } + } + return null; + } + + protected boolean isDeviceTypeMixed(int type) { + switch(type) { + case AudioDeviceInfo.TYPE_BUILTIN_SPEAKER: + case AudioDeviceInfo.TYPE_BUILTIN_SPEAKER_SAFE: + case AudioDeviceInfo.TYPE_WIRED_HEADSET: + case AudioDeviceInfo.TYPE_USB_HEADSET: + return true; + case AudioDeviceInfo.TYPE_USB_DEVICE: + default: + return false; + } + } + + protected int getCompatibleDeviceType(int type) { + int compatibleType; + switch(type) { + case AudioDeviceInfo.TYPE_BUILTIN_SPEAKER: + case AudioDeviceInfo.TYPE_BUILTIN_SPEAKER_SAFE: + compatibleType = AudioDeviceInfo.TYPE_BUILTIN_MIC; + break; + case AudioDeviceInfo.TYPE_BUILTIN_MIC: + compatibleType = AudioDeviceInfo.TYPE_BUILTIN_SPEAKER; + break; + default: + compatibleType = type; + break; + } + return compatibleType; + } + + /** + * Scan available device for one with a compatible device type for loopback testing. + * @return deviceId + */ + private int findCompatibleDevice(int deviceId, boolean isLookingForInput) { + AudioDeviceInfo deviceInfo = getDeviceInfoById(deviceId); + if (deviceInfo == null) { + log("deviceInfo is NULL !!!!!!\n"); + return UNSPECIFIED; + } + int compatibleDeviceType = getCompatibleDeviceType(deviceInfo.getType()); + AudioDeviceInfo[] devices = mAudioManager.getDevices( + isLookingForInput ? AudioManager.GET_DEVICES_INPUTS : AudioManager.GET_DEVICES_OUTPUTS); + for (AudioDeviceInfo candidate : devices) { + if (candidate.getType() == compatibleDeviceType) { + return candidate.getId(); + } + } + return UNSPECIFIED; + } + + protected AudioDeviceInfo findCompatibleDevice(AudioDeviceInfo deviceInfo, boolean isLookingForInput) { + int compatibleDeviceType = getCompatibleDeviceType(deviceInfo.getType()); + AudioDeviceInfo[] devices = mAudioManager.getDevices( + isLookingForInput ? AudioManager.GET_DEVICES_INPUTS : AudioManager.GET_DEVICES_OUTPUTS); + for (AudioDeviceInfo candidate : devices) { + if (candidate.getType() == compatibleDeviceType) { + return candidate; + } + } + return null; + } + protected boolean isFinishedEarly() { return false; } diff --git a/apps/OboeTester/app/src/main/java/com/mobileer/oboetester/ManualGlitchActivity.java b/apps/OboeTester/app/src/main/java/com/mobileer/oboetester/ManualGlitchActivity.java index 0ab0cc75c..8a2414c1b 100644 --- a/apps/OboeTester/app/src/main/java/com/mobileer/oboetester/ManualGlitchActivity.java +++ b/apps/OboeTester/app/src/main/java/com/mobileer/oboetester/ManualGlitchActivity.java @@ -16,12 +16,16 @@ package com.mobileer.oboetester; +import android.content.Context; import android.os.Bundle; import android.os.Handler; import android.os.Looper; import android.util.Log; import android.view.View; import android.widget.CheckBox; +import android.widget.LinearLayout; +import android.widget.RadioButton; +import android.widget.RadioGroup; import android.widget.SeekBar; import android.widget.TextView; @@ -46,6 +50,11 @@ public class ManualGlitchActivity extends GlitchActivity { private CheckBox mForceGlitchesBox; private CheckBox mAutoScopeBox; private WaveformView mWaveformView; + private LinearLayout mLayoutGlitch; + + + private NumberedRadioButtons mInputChannelBoxes; + private NumberedRadioButtons mOutputChannelBoxes; private float[] mWaveform = new float[WAVEFORM_SIZE]; private long mLastDisplayTime; @@ -73,6 +82,55 @@ protected void setToleranceProgress(int progress) { mTextTolerance.setText("Tolerance = " + String.format(Locale.getDefault(), "%5.3f", tolerance)); } + static class NumberedRadioButtons { + LinearLayout mRow; + RadioButton[] mRadioButtons; + + public interface SelectionListener { + void onSelected(int index); + } + + NumberedRadioButtons(Context context, int numBoxes, SelectionListener listener) { + mRow = new LinearLayout(context); + mRow.setOrientation(LinearLayout.HORIZONTAL); + TextView textView = new TextView(context); + textView.setText("IN:"); + mRow.addView(textView); + RadioGroup rg = new RadioGroup(context); + rg.setOrientation(LinearLayout.HORIZONTAL); + mRadioButtons = new RadioButton[numBoxes]; + for (int i = 0; i < numBoxes; i++) { + mRadioButtons[i] = new RadioButton(context); + mRadioButtons[i].setText("" + i); + mRadioButtons[i].setId(i); + rg.addView(mRadioButtons[i]); + } + mRow.addView(rg); + + //set listener to radio button group + rg.setOnCheckedChangeListener(new RadioGroup.OnCheckedChangeListener() { + @Override + public void onCheckedChanged(RadioGroup group, int checkedId) { + listener.onSelected(checkedId); + } + }); + + mRadioButtons[0].setChecked(true); + } + + public View getView() { + return mRow; + } + + public void setMaxEnabled(int max) { + max = Math.min(max, mRadioButtons.length); + for (int i = 0; i < mRadioButtons.length; i++) { + mRadioButtons[i].setEnabled(i < max); + } + mRadioButtons[0].setChecked(true); + } + } + @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); @@ -86,6 +144,14 @@ protected void onCreate(Bundle savedInstanceState) { mForceGlitchesBox = (CheckBox) findViewById(R.id.boxForceGlitch); mAutoScopeBox = (CheckBox) findViewById(R.id.boxAutoScope); mWaveformView = (WaveformView) findViewById(R.id.waveview_audio); + + mLayoutGlitch = (LinearLayout) findViewById(R.id.layoutGlitch); + mInputChannelBoxes = new NumberedRadioButtons(this, 8, + (int index) -> setInputChannel(index)); + mLayoutGlitch.addView(mInputChannelBoxes.getView()); + mOutputChannelBoxes = new NumberedRadioButtons(this, 8, + (int index) -> setOutputChannel(index)); + mLayoutGlitch.addView(mOutputChannelBoxes.getView()); } private void setToleranceFader(float tolerance) { @@ -122,7 +188,12 @@ public void giveAdvice(String s) { public void startAudioTest() throws IOException { super.startAudioTest(); + setToleranceProgress(mFaderTolerance.getProgress()); + int inChannels = mAudioInputTester.getCurrentAudioStream().getChannelCount(); + mInputChannelBoxes.setMaxEnabled(inChannels); + int outChannels = mAudioOutTester.getCurrentAudioStream().getChannelCount(); + mOutputChannelBoxes.setMaxEnabled(outChannels); } @Override 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 49e66f4c7..ac6dbda51 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 @@ -19,8 +19,6 @@ 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; @@ -34,6 +32,23 @@ import java.lang.reflect.Field; import java.util.Locale; +/** + * TODO + * Select device types based on priority or maybe offer checkboxes. + * Print devices types being tested. + * Avoid mismatch such as mic input and USB output. + * Avoid duplicating tests by not using Unspecified (except for ch-mask) + * + * Find available device types. + * Decide which device types to test. + * For each type find partner type, then decide other options: + * channels for speaker/mic and wired headset usb headset get mixed to one + * so allow channel mask downmix test + * check each channelCount if specified + * channels for USB device are 1:1, so match channels directly, FFT per input? + * + */ + /** * Play a recognizable tone on each channel of each speaker device * and listen for the result through a microphone. @@ -46,7 +61,11 @@ * signal is or whether it is corrupted. A noisy room may have * 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 { @@ -122,7 +141,6 @@ public class TestDataPathsActivity extends BaseAutoGlitchActivity { private double mPhaseErrorSum; private double mPhaseErrorCount; - AudioManager mAudioManager; private CheckBox mCheckBoxInputPresets; private CheckBox mCheckBoxInputDevices; private CheckBox mCheckBoxOutputDevices; @@ -233,7 +251,7 @@ private void gatherData() { 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; @@ -294,6 +312,8 @@ public String getShortReport() { native double getMagnitude(); native double getMaxMagnitude(); + native double getPhaseDataPaths(); + @Override protected void inflateActivity() { setContentView(R.layout.activity_data_paths); @@ -302,7 +322,6 @@ protected void inflateActivity() { @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); @@ -463,8 +482,9 @@ void setupDeviceCombo(int inputChannelCount, setOutputChannel(outputChannel); } - private TestResult testConfigurationsAddMagJitter() throws InterruptedException { - TestResult testResult = testInOutConfigurations(); + @Override + protected TestResult testCurrentConfigurations() throws InterruptedException { + TestResult testResult = super.testCurrentConfigurations(); if (testResult != null) { testResult.addComment("mag = " + TestDataPathsActivity.getMagnitudeText(mMagnitude) + ", jitter = " + getJitterText()); @@ -487,7 +507,7 @@ void testPresetCombo(int inputPreset, requestedInConfig.setMMap(mmapEnabled); mMagnitude = -1.0; - TestResult testResult = testConfigurationsAddMagJitter(); + TestResult testResult = testCurrentConfigurations(); if (testResult != null) { int result = testResult.result; String extra = ", inPre = " @@ -557,7 +577,7 @@ void testInputDeviceCombo(int deviceId, requestedInConfig.setMMap(mmapEnabled); mMagnitude = -1.0; - TestResult testResult = testConfigurationsAddMagJitter(); + TestResult testResult = testCurrentConfigurations(); if (testResult != null) { logOneLineSummary(testResult); } @@ -718,7 +738,7 @@ void testOutputDeviceCombo(int deviceId, requestedOutConfig.setMMap(mmapEnabled); mMagnitude = -1.0; - TestResult testResult = testConfigurationsAddMagJitter(); + TestResult testResult = testCurrentConfigurations(); if (testResult != null) { logOneLineSummary(testResult); int result = testResult.result; @@ -772,54 +792,195 @@ void testOutputDevices() throws InterruptedException { if (!deviceInfo.isSink()) continue; int deviceType = deviceInfo.getType(); if (deviceType == AudioDeviceInfo.TYPE_BUILTIN_SPEAKER - || deviceType == TYPE_BUILTIN_SPEAKER_SAFE) { - int id = deviceInfo.getId(); - int[] channelCounts = deviceInfo.getChannelCounts(); + || deviceType == AudioDeviceInfo.TYPE_BUILTIN_SPEAKER_SAFE + || deviceType == AudioDeviceInfo.TYPE_WIRED_HEADSET + || deviceType == AudioDeviceInfo.TYPE_USB_HEADSET + || deviceType == AudioDeviceInfo.TYPE_USB_DEVICE + ) { numTested++; - // Always test mono and stereo. - testOutputDeviceCombo(id, deviceType, 1, 0, 0, 48000); - testOutputDeviceCombo(id, deviceType, 2, 0, 0, 48000); - testOutputDeviceCombo(id, deviceType, 2, 0, 1, 48000); - 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, 0, channel, - 48000); - } - } - } + testDeviceOutputInfo(deviceInfo); + } else { + log("Device skipped because DeviceType is not testable."); + } + } + if (numTested == 0) { + log("NO OUTPUT DEVICE FOUND!\n"); + } + } + + private void testDeviceOutputInfo(AudioDeviceInfo outputDeviceInfo) throws InterruptedException { + AudioDeviceInfo inputDeviceInfo = findCompatibleDevice( outputDeviceInfo, true); + if (inputDeviceInfo == null) { + log("ERROR - cannot find compatible device type!\n"); + return; + } + + log("=========== OUTPUT TYPE = " + + AudioDeviceInfoConverter.typeToString(outputDeviceInfo.getType()) + "\n"); + StreamConfiguration requestedInConfig = mAudioInputTester.requestedConfiguration; + StreamConfiguration requestedOutConfig = mAudioOutTester.requestedConfiguration; + requestedInConfig.reset(); + requestedOutConfig.reset(); + + requestedInConfig.setDeviceId(inputDeviceInfo.getId()); + requestedOutConfig.setDeviceId(outputDeviceInfo.getId()); + + testOutputChannelCounts(inputDeviceInfo, outputDeviceInfo); +/* + runOnUiThread(() -> mCheckBoxAllSampleRates.setEnabled(false)); + if (mCheckBoxAllSampleRates.isChecked()) { + for (int sampleRate : SAMPLE_RATES) { + testOutputDeviceCombo(id, deviceType, 1, 0, 0, sampleRate); + } + } + + if (android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.S_V2 + && deviceType == AudioDeviceInfo.TYPE_BUILTIN_SPEAKER) { + runOnUiThread(() -> mCheckBoxAllOutputChannelMasks.setEnabled(false)); + + for (int channelMask : mCheckBoxAllOutputChannelMasks.isChecked() ? + ALL_OUTPUT_CHANNEL_MASKS : SHORT_OUTPUT_CHANNEL_MASKS) { + log("channelMask = " + convertChannelMaskToText(channelMask) + "\n"); + int channelCount = Integer.bitCount(channelMask); + for (int channel = 0; channel < channelCount; channel++) { + testOutputDeviceCombo(id, deviceType, channelCount, channelMask, + channel, 48000); } + } + } + */ + } - runOnUiThread(() -> mCheckBoxAllSampleRates.setEnabled(false)); - if (mCheckBoxAllSampleRates.isChecked()) { - for (int sampleRate : SAMPLE_RATES) { - testOutputDeviceCombo(id, deviceType, 1, 0, 0, sampleRate); + private boolean arrayContains(int[] a, int b) { + for (int c: a) { + if (c == b) return true; + } + return false; + } + + private void testOutputChannelCounts(AudioDeviceInfo inputDeviceInfo, AudioDeviceInfo outputDeviceInfo) throws InterruptedException { + StreamConfiguration requestedInConfig = mAudioInputTester.requestedConfiguration; + StreamConfiguration requestedOutConfig = mAudioOutTester.requestedConfiguration; + // If not channels counts reported then test mono and stereo + int[] inputChannelCounts = inputDeviceInfo.getChannelCounts(); + int[] outputChannelCounts = outputDeviceInfo.getChannelCounts(); + if (isDeviceTypeMixed(outputDeviceInfo.getType())) { + requestedInConfig.setChannelCount(1); + setInputChannel(0); + if (outputChannelCounts.length == 0) { + requestedOutConfig.setChannelCount(1); + setOutputChannel(0); + testPerformancePaths(); + + requestedOutConfig.setChannelCount(2); + testPerformancePaths(); + + setOutputChannel(1); + testPerformancePaths(); + } else { + for (int numChannels : outputChannelCounts) { + log("numChannels = " + numChannels + "\n"); + requestedOutConfig.setChannelCount(numChannels); + for (int channel = 0; channel < numChannels; channel++) { + setOutputChannel(channel); + testPerformancePaths(); } } - - if (android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.S_V2 - && deviceType == AudioDeviceInfo.TYPE_BUILTIN_SPEAKER) { - runOnUiThread(() -> mCheckBoxAllOutputChannelMasks.setEnabled(false)); - - for (int channelMask : mCheckBoxAllOutputChannelMasks.isChecked() ? - ALL_OUTPUT_CHANNEL_MASKS : SHORT_OUTPUT_CHANNEL_MASKS) { - log("channelMask = " + convertChannelMaskToText(channelMask) + "\n"); - int channelCount = Integer.bitCount(channelMask); - for (int channel = 0; channel < channelCount; channel++) { - testOutputDeviceCombo(id, deviceType, channelCount, channelMask, - channel, 48000); + } + } else { + // Test two matching stereo channels. + if (outputChannelCounts.length == 0) { + requestedInConfig.setChannelCount(2); + requestedOutConfig.setChannelCount(2); + setInputChannel(0); + setOutputChannel(0); + log("test matching stereo channel[0]\n"); + testPerformancePaths(); + + setInputChannel(1); + setOutputChannel(1); + log("test matching stereo channel[1]\n"); + testPerformancePaths(); + } else { + // Test each matching channels for each channelCount + for (int numChannels : outputChannelCounts) { + log("numChannels = " + numChannels + "\n"); + if (arrayContains(inputChannelCounts, numChannels)) { + requestedInConfig.setChannelCount(numChannels); + requestedOutConfig.setChannelCount(numChannels); + for (int channel = 0; channel < numChannels; channel++) { + setInputChannel(channel); + setOutputChannel(channel); + log("test matching channel = " + channel + "\n"); + testPerformancePaths(); } } } - } else { - log("Device skipped because DeviceType is not testable."); } } - if (numTested == 0) { - log("NO OUTPUT DEVICE FOUND!\n"); + // Restore defaults. + requestedInConfig.setChannelCount(1); + setInputChannel(0); + requestedOutConfig.setChannelCount(1); + setOutputChannel(0); + } + + + private void testPerformancePaths() throws InterruptedException { + StreamConfiguration requestedInConfig = mAudioInputTester.requestedConfiguration; + StreamConfiguration requestedOutConfig = mAudioOutTester.requestedConfiguration; + + 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); + +// if (NativeEngine.isMMapSupported()) { +// requestedInConfig.setMMap(true); +// requestedOutConfig.setMMap(true); +// testCurrentConfigurations(); +// } + + requestedInConfig.setMMap(false); + requestedOutConfig.setMMap(false); + testCurrentConfigurations(); + + requestedInConfig.setPerformanceMode(StreamConfiguration.PERFORMANCE_MODE_NONE); + requestedOutConfig.setPerformanceMode(StreamConfiguration.PERFORMANCE_MODE_NONE); + testCurrentConfigurations(); + } + + 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; + } + 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); } } @@ -836,18 +997,20 @@ public void runTest() { runOnUiThread(() -> keepScreenOn(true)); - if (mCheckBoxInputPresets.isChecked()) { - runOnUiThread(() -> mCheckBoxInputPresets.setEnabled(false)); - testInputPresets(); - } - if (mCheckBoxInputDevices.isChecked()) { - runOnUiThread(() -> mCheckBoxInputDevices.setEnabled(false)); - testInputDevices(); - } - if (mCheckBoxOutputDevices.isChecked()) { - runOnUiThread(() -> mCheckBoxOutputDevices.setEnabled(false)); - testOutputDevices(); - } + testOutputDeviceTypes(); + +// if (mCheckBoxInputPresets.isChecked()) { +// runOnUiThread(() -> mCheckBoxInputPresets.setEnabled(false)); +// testInputPresets(); +// } +// if (mCheckBoxInputDevices.isChecked()) { +// runOnUiThread(() -> mCheckBoxInputDevices.setEnabled(false)); +// testInputDevices(); +// } +// if (mCheckBoxOutputDevices.isChecked()) { +// runOnUiThread(() -> mCheckBoxOutputDevices.setEnabled(false)); +// testOutputDevices(); +// } compareFailedTestsWithNearestPassingTest(); diff --git a/apps/OboeTester/app/src/main/res/layout/activity_manual_glitches.xml b/apps/OboeTester/app/src/main/res/layout/activity_manual_glitches.xml index 735a7b243..f470e01d8 100644 --- a/apps/OboeTester/app/src/main/res/layout/activity_manual_glitches.xml +++ b/apps/OboeTester/app/src/main/res/layout/activity_manual_glitches.xml @@ -44,6 +44,7 @@ android:orientation="horizontal" /> From 3099abb9fe07a524385e3f20c28b05671da78d6a Mon Sep 17 00:00:00 2001 From: Phil Burk Date: Thu, 15 Feb 2024 16:31:51 -0800 Subject: [PATCH 2/6] more data paths improvement Show up to 8 VU meters. Display types being tested. --- .../src/main/cpp/analyzer/GlitchAnalyzer.h | 2 +- .../oboetester/AutomatedGlitchActivity.java | 2 +- .../oboetester/BaseAutoGlitchActivity.java | 105 ++---- .../oboetester/ManualGlitchActivity.java | 8 +- .../oboetester/TestAudioActivity.java | 4 +- .../oboetester/TestDataPathsActivity.java | 341 ++++++++---------- .../oboetester/TestInputActivity.java | 7 +- .../main/res/layout/activity_test_input.xml | 24 ++ .../app/src/main/res/values/strings.xml | 2 +- 9 files changed, 228 insertions(+), 267 deletions(-) diff --git a/apps/OboeTester/app/src/main/cpp/analyzer/GlitchAnalyzer.h b/apps/OboeTester/app/src/main/cpp/analyzer/GlitchAnalyzer.h index 583ac42b8..747c5ea9a 100644 --- a/apps/OboeTester/app/src/main/cpp/analyzer/GlitchAnalyzer.h +++ b/apps/OboeTester/app/src/main/cpp/analyzer/GlitchAnalyzer.h @@ -228,7 +228,7 @@ class GlitchAnalyzer : public BaseSineAnalyzer { // Must be a multiple of the period or the calculation will not be accurate. if (transformSample(sample, mInputPhase)) { // Adjust phase to account for sample rate drift. - // FIXME mInputPhase += mPhaseOffset; + mInputPhase += mPhaseOffset; mMeanSquareNoise = mSumSquareNoise * mInverseSinePeriod; mMeanSquareSignal = mSumSquareSignal * mInverseSinePeriod; diff --git a/apps/OboeTester/app/src/main/java/com/mobileer/oboetester/AutomatedGlitchActivity.java b/apps/OboeTester/app/src/main/java/com/mobileer/oboetester/AutomatedGlitchActivity.java index faeba306e..ae53a7f62 100644 --- a/apps/OboeTester/app/src/main/java/com/mobileer/oboetester/AutomatedGlitchActivity.java +++ b/apps/OboeTester/app/src/main/java/com/mobileer/oboetester/AutomatedGlitchActivity.java @@ -99,7 +99,7 @@ private void testConfiguration(int perfMode, requestedInConfig.setChannelCount(inChannels); requestedOutConfig.setChannelCount(outChannels); - testInOutConfigurations(); + testCurrentConfigurations(); } private void testConfiguration(int performanceMode, diff --git a/apps/OboeTester/app/src/main/java/com/mobileer/oboetester/BaseAutoGlitchActivity.java b/apps/OboeTester/app/src/main/java/com/mobileer/oboetester/BaseAutoGlitchActivity.java index 1ea62dab6..3d345fc07 100644 --- a/apps/OboeTester/app/src/main/java/com/mobileer/oboetester/BaseAutoGlitchActivity.java +++ b/apps/OboeTester/app/src/main/java/com/mobileer/oboetester/BaseAutoGlitchActivity.java @@ -16,7 +16,6 @@ package com.mobileer.oboetester; -import static com.mobileer.oboetester.StreamConfiguration.UNSPECIFIED; import static com.mobileer.oboetester.StreamConfiguration.convertChannelMaskToText; import android.content.Context; @@ -48,6 +47,13 @@ public class BaseAutoGlitchActivity extends GlitchActivity { protected ArrayList mTestResults = new ArrayList(); + public static boolean arrayContains(int[] haystack, int needle) { + for (int n: haystack) { + if (n == needle) return true; + } + return false; + } + void logDeviceInfo() { log("\n############################"); log("\nDevice Info:"); @@ -228,12 +234,11 @@ protected String getConfigText(StreamConfiguration config) { ? getOutputChannel() : getInputChannel(); return ((config.getDirection() == StreamConfiguration.DIRECTION_OUTPUT) ? "OUT" : "INP") + (config.isMMap() ? "-M" : "-L") + + "-" + StreamConfiguration.convertSharingModeToText(config.getSharingMode()) + ", ID = " + String.format(Locale.getDefault(), "%2d", config.getDeviceId()) - + ", SR = " + String.format(Locale.getDefault(), "%5d", config.getSampleRate()) + ", Perf = " + StreamConfiguration.convertPerformanceModeToText( - config.getPerformanceMode()) - + ",\n " + StreamConfiguration.convertSharingModeToText(config.getSharingMode()) - + ", ch = " + channelText(channel, config.getChannelCount()) + config.getPerformanceMode()) + + ",\n ch = " + channelText(channel, config.getChannelCount()) + ", cm = " + convertChannelMaskToText(config.getChannelMask()); } @@ -251,34 +256,6 @@ protected String getStreamText(AudioStreamBase stream) { // Run one test based on the requested input/output configurations. @Nullable - protected TestResult testInOutConfigurations() throws InterruptedException { - -// -// StreamConfiguration requestedInConfig = mAudioInputTester.requestedConfiguration; -// StreamConfiguration requestedOutConfig = mAudioOutTester.requestedConfiguration; -// -// // Check to make sure the input output device types are compatible. -// if (requestedInConfig.getDeviceId() == UNSPECIFIED) { -// if (requestedOutConfig.getDeviceId() != UNSPECIFIED) { -// int compatibleDeviceId = findCompatibleDevice(requestedOutConfig.getDeviceId(), -// true /* isInput */); -// requestedInConfig.setDeviceId(compatibleDeviceId); -// } -// } else if (requestedOutConfig.getDeviceId() == UNSPECIFIED) { -// if (requestedInConfig.getDeviceId() != UNSPECIFIED) { -// int compatibleDeviceId = findCompatibleDevice(requestedInConfig.getDeviceId(), -// false /* isInput */); -// requestedOutConfig.setDeviceId(compatibleDeviceId); -// } -// } - - TestResult testResult = testCurrentConfigurations(); - - return testResult; - } - - - @NonNull protected TestResult testCurrentConfigurations() throws InterruptedException { mAutomatedTestRunner.incrementTestCount(); if ((getSingleTestIndex() >= 0) && (mAutomatedTestRunner.getTestCount() != getSingleTestIndex())) { @@ -294,6 +271,7 @@ protected TestResult testCurrentConfigurations() throws InterruptedException { StreamConfiguration actualOutConfig = mAudioOutTester.actualConfiguration; log("Requested:"); + log(" SR = " + requestedOutConfig.getSampleRate()); log(" " + getConfigText(requestedInConfig)); log(" " + getConfigText(requestedOutConfig)); @@ -302,6 +280,7 @@ protected TestResult testCurrentConfigurations() throws InterruptedException { try { openAudio(); // this will fill in actualConfig log("Actual:"); + log(" SR = " + actualOutConfig.getSampleRate()); // Set output size to a level that will avoid glitches. AudioStreamBase outStream = mAudioOutTester.getCurrentAudioStream(); int sizeFrames = outStream.getBufferCapacityInFrames() / 2; @@ -447,50 +426,38 @@ protected boolean isDeviceTypeMixed(int type) { } } - protected int getCompatibleDeviceType(int type) { - int compatibleType; + protected ArrayList getCompatibleDeviceTypes(int type) { + ArrayList compatibleTypes = new ArrayList(); switch(type) { case AudioDeviceInfo.TYPE_BUILTIN_SPEAKER: case AudioDeviceInfo.TYPE_BUILTIN_SPEAKER_SAFE: - compatibleType = AudioDeviceInfo.TYPE_BUILTIN_MIC; + compatibleTypes.add(AudioDeviceInfo.TYPE_BUILTIN_MIC); break; case AudioDeviceInfo.TYPE_BUILTIN_MIC: - compatibleType = AudioDeviceInfo.TYPE_BUILTIN_SPEAKER; + compatibleTypes.add(AudioDeviceInfo.TYPE_BUILTIN_SPEAKER); + break; + case AudioDeviceInfo.TYPE_USB_DEVICE: + compatibleTypes.add(AudioDeviceInfo.TYPE_USB_DEVICE); + // A USB Device is often mistaken for a headset. + compatibleTypes.add(AudioDeviceInfo.TYPE_USB_HEADSET); break; default: - compatibleType = type; + compatibleTypes.add(type); break; } - return compatibleType; + return compatibleTypes; } /** * Scan available device for one with a compatible device type for loopback testing. * @return deviceId */ - private int findCompatibleDevice(int deviceId, boolean isLookingForInput) { - AudioDeviceInfo deviceInfo = getDeviceInfoById(deviceId); - if (deviceInfo == null) { - log("deviceInfo is NULL !!!!!!\n"); - return UNSPECIFIED; - } - int compatibleDeviceType = getCompatibleDeviceType(deviceInfo.getType()); - AudioDeviceInfo[] devices = mAudioManager.getDevices( - isLookingForInput ? AudioManager.GET_DEVICES_INPUTS : AudioManager.GET_DEVICES_OUTPUTS); - for (AudioDeviceInfo candidate : devices) { - if (candidate.getType() == compatibleDeviceType) { - return candidate.getId(); - } - } - return UNSPECIFIED; - } - protected AudioDeviceInfo findCompatibleDevice(AudioDeviceInfo deviceInfo, boolean isLookingForInput) { - int compatibleDeviceType = getCompatibleDeviceType(deviceInfo.getType()); - AudioDeviceInfo[] devices = mAudioManager.getDevices( - isLookingForInput ? AudioManager.GET_DEVICES_INPUTS : AudioManager.GET_DEVICES_OUTPUTS); + protected AudioDeviceInfo findCompatibleInputDevice(int outputDeviceType) { + ArrayList compatibleDeviceTypes = getCompatibleDeviceTypes(outputDeviceType); + AudioDeviceInfo[] devices = mAudioManager.getDevices(AudioManager.GET_DEVICES_INPUTS); for (AudioDeviceInfo candidate : devices) { - if (candidate.getType() == compatibleDeviceType) { + if (compatibleDeviceTypes.contains(candidate.getType())) { return candidate; } } @@ -507,14 +474,22 @@ protected String shouldTestBeSkipped() { StreamConfiguration requestedOutConfig = mAudioOutTester.requestedConfiguration; StreamConfiguration actualInConfig = mAudioInputTester.actualConfiguration; StreamConfiguration actualOutConfig = mAudioOutTester.actualConfiguration; - // No point running the test if we don't get the sharing mode we requested. + // No point running the test if we don't get any of the sharing modes we requested. if (actualInConfig.getSharingMode() != requestedInConfig.getSharingMode() - || actualOutConfig.getSharingMode() != requestedOutConfig.getSharingMode()) { + && actualOutConfig.getSharingMode() != requestedOutConfig.getSharingMode()) { log("Did not get requested sharing mode."); - why += "share"; + why += "share,"; + } + if (actualInConfig.getPerformanceMode() != requestedInConfig.getPerformanceMode() + && actualOutConfig.getPerformanceMode() != requestedOutConfig.getPerformanceMode()) { + log("Did not get requested performance mode."); + why += "perf,"; + } + if (actualInConfig.isMMap() != requestedInConfig.isMMap() + && actualOutConfig.isMMap() != requestedOutConfig.isMMap()) { + log("Did not get requested MMAP data path."); + why += "mmap,"; } - // We don't skip based on performance mode because if you request LOW_LATENCY you might - // get a smaller burst than if you request NONE. return why; } diff --git a/apps/OboeTester/app/src/main/java/com/mobileer/oboetester/ManualGlitchActivity.java b/apps/OboeTester/app/src/main/java/com/mobileer/oboetester/ManualGlitchActivity.java index 8a2414c1b..9281cd592 100644 --- a/apps/OboeTester/app/src/main/java/com/mobileer/oboetester/ManualGlitchActivity.java +++ b/apps/OboeTester/app/src/main/java/com/mobileer/oboetester/ManualGlitchActivity.java @@ -90,11 +90,11 @@ public interface SelectionListener { void onSelected(int index); } - NumberedRadioButtons(Context context, int numBoxes, SelectionListener listener) { + NumberedRadioButtons(Context context, int numBoxes, SelectionListener listener, String prompt) { mRow = new LinearLayout(context); mRow.setOrientation(LinearLayout.HORIZONTAL); TextView textView = new TextView(context); - textView.setText("IN:"); + textView.setText(prompt); mRow.addView(textView); RadioGroup rg = new RadioGroup(context); rg.setOrientation(LinearLayout.HORIZONTAL); @@ -147,10 +147,10 @@ protected void onCreate(Bundle savedInstanceState) { mLayoutGlitch = (LinearLayout) findViewById(R.id.layoutGlitch); mInputChannelBoxes = new NumberedRadioButtons(this, 8, - (int index) -> setInputChannel(index)); + (int index) -> setInputChannel(index), "IN:"); mLayoutGlitch.addView(mInputChannelBoxes.getView()); mOutputChannelBoxes = new NumberedRadioButtons(this, 8, - (int index) -> setOutputChannel(index)); + (int index) -> setOutputChannel(index), "OUT:"); mLayoutGlitch.addView(mOutputChannelBoxes.getView()); } diff --git a/apps/OboeTester/app/src/main/java/com/mobileer/oboetester/TestAudioActivity.java b/apps/OboeTester/app/src/main/java/com/mobileer/oboetester/TestAudioActivity.java index 1f72efc6b..9043f28db 100644 --- a/apps/OboeTester/app/src/main/java/com/mobileer/oboetester/TestAudioActivity.java +++ b/apps/OboeTester/app/src/main/java/com/mobileer/oboetester/TestAudioActivity.java @@ -568,13 +568,13 @@ public void openAudio() throws IOException { applyConfigurationViewsToModels(); } - int sampleRate = 0; + int sampleRate = 0; // Use the OUTPUT sample rate for INPUT // Open output streams then open input streams. // This is so that the capacity of input stream can be expanded to // match the burst size of the output for full duplex. for (StreamContext streamContext : mStreamContexts) { - if (!streamContext.isInput()) { + if (!streamContext.isInput()) { // OUTPUT? openStreamContext(streamContext); int streamSampleRate = streamContext.tester.actualConfiguration.getSampleRate(); if (sampleRate == 0) { 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 ac6dbda51..55622ed19 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 @@ -25,11 +25,14 @@ import android.os.Bundle; import android.util.Log; import android.widget.CheckBox; +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; /** @@ -146,6 +149,7 @@ public class TestDataPathsActivity extends BaseAutoGlitchActivity { private CheckBox mCheckBoxOutputDevices; private CheckBox mCheckBoxAllOutputChannelMasks; private CheckBox mCheckBoxAllSampleRates; + private TextView mInstructionsTextView; private static final int[] INPUT_PRESETS = { StreamConfiguration.INPUT_PRESET_GENERIC, @@ -159,7 +163,7 @@ public class TestDataPathsActivity extends BaseAutoGlitchActivity { private static final int[] SHORT_OUTPUT_CHANNEL_MASKS = { StreamConfiguration.CHANNEL_MONO, StreamConfiguration.CHANNEL_STEREO, - StreamConfiguration.CHANNEL_2POINT1, + StreamConfiguration.CHANNEL_2POINT1, // TODO should this be 5.1?! StreamConfiguration.CHANNEL_7POINT1POINT4, }; @@ -295,6 +299,16 @@ public void updateStatusText() { } } + // 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()) : "?"; } @@ -329,6 +343,8 @@ protected void onCreate(Bundle savedInstanceState) { (CheckBox)findViewById(R.id.checkbox_paths_all_output_channel_masks); mCheckBoxAllSampleRates = (CheckBox)findViewById(R.id.checkbox_paths_all_sample_rates); + + mInstructionsTextView = (TextView) findViewById(R.id.text_instructions); } @Override @@ -355,34 +371,26 @@ protected String getConfigText(StreamConfiguration config) { @Override protected String shouldTestBeSkipped() { - String why = ""; + String why = super.shouldTestBeSkipped(); 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; } @@ -488,6 +496,24 @@ protected TestResult testCurrentConfigurations() throws InterruptedException { if (testResult != null) { testResult.addComment("mag = " + TestDataPathsActivity.getMagnitudeText(mMagnitude) + ", jitter = " + getJitterText()); + + logOneLineSummary(testResult); + int result = testResult.result; + if (result == TEST_RESULT_FAILED) { + 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; } @@ -713,64 +739,6 @@ void logOneLineSummary(TestResult testResult, String extra) { appendSummary(oneLineSummary + "\n"); } - void testOutputDeviceCombo(int deviceId, - int deviceType, - int channelCount, - int channelMask, - int outputChannel, - int outputSampleRate, - boolean mmapEnabled) throws InterruptedException { - String typeString = AudioDeviceInfoConverter.typeToString(deviceType); - if (channelMask != 0) { - setTestName("Test OutDev: #" + deviceId + " " + typeString - + " Mask:" + channelMask + "_" + outputChannel + "/" + channelCount + "_" + outputSampleRate); - } else { - setTestName("Test InDev: #" + deviceId + " " + typeString - + "_" + outputChannel + "/" + channelCount + "_" + outputSampleRate); - } - - final int numInputChannels = 2; // TODO review, done because of mono problems on some devices - setupDeviceCombo(numInputChannels, 0, 0, 48000, - channelCount, channelMask, outputChannel, outputSampleRate); - - StreamConfiguration requestedOutConfig = mAudioOutTester.requestedConfiguration; - requestedOutConfig.setDeviceId(deviceId); - requestedOutConfig.setMMap(mmapEnabled); - - mMagnitude = -1.0; - TestResult testResult = testCurrentConfigurations(); - if (testResult != null) { - logOneLineSummary(testResult); - int result = testResult.result; - if (result == TEST_RESULT_FAILED) { - if (deviceType == AudioDeviceInfo.TYPE_BUILTIN_EARPIECE - && channelCount == 2 - && outputChannel == 1) { - testResult.addComment("Maybe EARPIECE does not mix stereo to mono!"); - } - if (deviceType == TYPE_BUILTIN_SPEAKER_SAFE - && channelCount == 2 - && outputChannel == 0) { - testResult.addComment("Maybe SPEAKER_SAFE dropped channel zero!"); - } - } - } - } - - void testOutputDeviceCombo(int deviceId, - int deviceType, - int channelCount, - int channelMask, - int outputChannel, - int outputSampleRate) throws InterruptedException { - if (NativeEngine.isMMapSupported()) { - testOutputDeviceCombo(deviceId, deviceType, channelCount, channelMask, outputChannel, - outputSampleRate, true); - } - testOutputDeviceCombo(deviceId, deviceType, channelCount, channelMask, outputChannel, - outputSampleRate, false); - } - void logBoth(String text) { log(text); appendSummary(text + "\n"); @@ -781,106 +749,95 @@ void logFailed(String 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_SPEAKER_SAFE - || deviceType == AudioDeviceInfo.TYPE_WIRED_HEADSET - || deviceType == AudioDeviceInfo.TYPE_USB_HEADSET - || deviceType == AudioDeviceInfo.TYPE_USB_DEVICE - ) { - numTested++; - testDeviceOutputInfo(deviceInfo); - } else { - log("Device skipped because DeviceType is not testable."); - } - } - if (numTested == 0) { - log("NO OUTPUT DEVICE FOUND!\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()); + + testOutputChannelCounts(inputDeviceInfo, outputDeviceInfo); + + runOnUiThread(() -> mCheckBoxAllSampleRates.setEnabled(false)); + if (mCheckBoxAllSampleRates.isChecked()) { + for (int sampleRate : SAMPLE_RATES) { + requestedInConfig.setSampleRate(sampleRate); + requestedOutConfig.setSampleRate(sampleRate); + testPerformancePaths(); + } + } + requestedInConfig.setSampleRate(0); + requestedOutConfig.setSampleRate(0); + + if (android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.S_V2 + && isDeviceTypeMixed(outputDeviceInfo.getType())) { + runOnUiThread(() -> mCheckBoxAllOutputChannelMasks.setEnabled(false)); + + for (int channelMask : mCheckBoxAllOutputChannelMasks.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(); + } + } + } + } + + private void showDeviceInfo(AudioDeviceInfo outputDeviceInfo, AudioDeviceInfo inputDeviceInfo) { + String deviceText = "OUT type = " + + AudioDeviceInfoConverter.typeToString(outputDeviceInfo.getType()); + + setInstructionsText(deviceText); - private void testDeviceOutputInfo(AudioDeviceInfo outputDeviceInfo) throws InterruptedException { - AudioDeviceInfo inputDeviceInfo = findCompatibleDevice( outputDeviceInfo, true); if (inputDeviceInfo == null) { - log("ERROR - cannot find compatible device type!\n"); - return; - } - - log("=========== OUTPUT TYPE = " - + AudioDeviceInfoConverter.typeToString(outputDeviceInfo.getType()) + "\n"); - StreamConfiguration requestedInConfig = mAudioInputTester.requestedConfiguration; - StreamConfiguration requestedOutConfig = mAudioOutTester.requestedConfiguration; - requestedInConfig.reset(); - requestedOutConfig.reset(); - - requestedInConfig.setDeviceId(inputDeviceInfo.getId()); - requestedOutConfig.setDeviceId(outputDeviceInfo.getId()); - - testOutputChannelCounts(inputDeviceInfo, outputDeviceInfo); -/* - runOnUiThread(() -> mCheckBoxAllSampleRates.setEnabled(false)); - if (mCheckBoxAllSampleRates.isChecked()) { - for (int sampleRate : SAMPLE_RATES) { - testOutputDeviceCombo(id, deviceType, 1, 0, 0, sampleRate); - } - } - - if (android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.S_V2 - && deviceType == AudioDeviceInfo.TYPE_BUILTIN_SPEAKER) { - runOnUiThread(() -> mCheckBoxAllOutputChannelMasks.setEnabled(false)); - - for (int channelMask : mCheckBoxAllOutputChannelMasks.isChecked() ? - ALL_OUTPUT_CHANNEL_MASKS : SHORT_OUTPUT_CHANNEL_MASKS) { - log("channelMask = " + convertChannelMaskToText(channelMask) + "\n"); - int channelCount = Integer.bitCount(channelMask); - for (int channel = 0; channel < channelCount; channel++) { - testOutputDeviceCombo(id, deviceType, channelCount, channelMask, - channel, 48000); - } - } - } - */ - } - - private boolean arrayContains(int[] a, int b) { - for (int c: a) { - if (c == b) return true; + deviceText += "ERROR - cannot find compatible device type for input!"; + } else { + deviceText = "IN type = " + + AudioDeviceInfoConverter.typeToString(inputDeviceInfo.getType()) + + "\n" + deviceText; + setInstructionsText(deviceText); } - return false; } private void testOutputChannelCounts(AudioDeviceInfo inputDeviceInfo, AudioDeviceInfo outputDeviceInfo) throws InterruptedException { + ArrayList channelCountsTested =new ArrayList(); StreamConfiguration requestedInConfig = mAudioInputTester.requestedConfiguration; StreamConfiguration requestedOutConfig = mAudioOutTester.requestedConfiguration; - // If not channels counts reported then test mono and stereo - int[] inputChannelCounts = inputDeviceInfo.getChannelCounts(); + int[] outputChannelCounts = outputDeviceInfo.getChannelCounts(); if (isDeviceTypeMixed(outputDeviceInfo.getType())) { requestedInConfig.setChannelCount(1); setInputChannel(0); - if (outputChannelCounts.length == 0) { - requestedOutConfig.setChannelCount(1); - setOutputChannel(0); - testPerformancePaths(); - - requestedOutConfig.setChannelCount(2); - testPerformancePaths(); - - setOutputChannel(1); - testPerformancePaths(); - } else { - for (int numChannels : outputChannelCounts) { - log("numChannels = " + numChannels + "\n"); + // 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 (!channelCountsTested.contains(numChannels)) { requestedOutConfig.setChannelCount(numChannels); + channelCountsTested.add(numChannels); for (int channel = 0; channel < numChannels; channel++) { setOutputChannel(channel); testPerformancePaths(); @@ -888,33 +845,22 @@ private void testOutputChannelCounts(AudioDeviceInfo inputDeviceInfo, AudioDevic } } } else { + // test mono + testMatchingChannels(1); + channelCountsTested.add(1); // Test two matching stereo channels. - if (outputChannelCounts.length == 0) { - requestedInConfig.setChannelCount(2); - requestedOutConfig.setChannelCount(2); - setInputChannel(0); - setOutputChannel(0); - log("test matching stereo channel[0]\n"); - testPerformancePaths(); - - setInputChannel(1); - setOutputChannel(1); - log("test matching stereo channel[1]\n"); - testPerformancePaths(); - } else { - // Test each matching channels for each channelCount - for (int numChannels : outputChannelCounts) { - log("numChannels = " + numChannels + "\n"); - if (arrayContains(inputChannelCounts, numChannels)) { - requestedInConfig.setChannelCount(numChannels); - requestedOutConfig.setChannelCount(numChannels); - for (int channel = 0; channel < numChannels; channel++) { - setInputChannel(channel); - setOutputChannel(channel); - log("test matching channel = " + channel + "\n"); - testPerformancePaths(); - } - } + 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); } } } @@ -925,6 +871,15 @@ private void testOutputChannelCounts(AudioDeviceInfo inputDeviceInfo, AudioDevic 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(); + } + } private void testPerformancePaths() throws InterruptedException { StreamConfiguration requestedInConfig = mAudioInputTester.requestedConfiguration; @@ -935,16 +890,18 @@ private void testPerformancePaths() throws InterruptedException { requestedInConfig.setSharingMode(StreamConfiguration.SHARING_MODE_SHARED); requestedOutConfig.setSharingMode(StreamConfiguration.SHARING_MODE_SHARED); -// if (NativeEngine.isMMapSupported()) { -// requestedInConfig.setMMap(true); -// requestedOutConfig.setMMap(true); -// testCurrentConfigurations(); -// } - requestedInConfig.setMMap(false); requestedOutConfig.setMMap(false); testCurrentConfigurations(); + if (NativeEngine.isMMapSupported()) { + requestedInConfig.setMMap(true); + requestedOutConfig.setMMap(true); + testCurrentConfigurations(); + } + requestedInConfig.setMMap(false); + requestedOutConfig.setMMap(false); + requestedInConfig.setPerformanceMode(StreamConfiguration.PERFORMANCE_MODE_NONE); requestedOutConfig.setPerformanceMode(StreamConfiguration.PERFORMANCE_MODE_NONE); testCurrentConfigurations(); diff --git a/apps/OboeTester/app/src/main/java/com/mobileer/oboetester/TestInputActivity.java b/apps/OboeTester/app/src/main/java/com/mobileer/oboetester/TestInputActivity.java index b4f2449c9..a6c9bbd64 100644 --- a/apps/OboeTester/app/src/main/java/com/mobileer/oboetester/TestInputActivity.java +++ b/apps/OboeTester/app/src/main/java/com/mobileer/oboetester/TestInputActivity.java @@ -37,7 +37,8 @@ public class TestInputActivity extends TestAudioActivity { protected AudioInputTester mAudioInputTester; - private static final int NUM_VOLUME_BARS = 4; + // Note that this must match the number of volume bars defined in the layout file. + private static final int NUM_VOLUME_BARS = 8; private VolumeBarView[] mVolumeBars = new VolumeBarView[NUM_VOLUME_BARS]; private InputMarginView mInputMarginView; private int mInputMarginBursts = 0; @@ -64,6 +65,10 @@ protected void onCreate(Bundle savedInstanceState) { mVolumeBars[1] = (VolumeBarView) findViewById(R.id.volumeBar1); mVolumeBars[2] = (VolumeBarView) findViewById(R.id.volumeBar2); mVolumeBars[3] = (VolumeBarView) findViewById(R.id.volumeBar3); + mVolumeBars[4] = (VolumeBarView) findViewById(R.id.volumeBar4); + mVolumeBars[5] = (VolumeBarView) findViewById(R.id.volumeBar5); + mVolumeBars[6] = (VolumeBarView) findViewById(R.id.volumeBar6); + mVolumeBars[7] = (VolumeBarView) findViewById(R.id.volumeBar7); mInputMarginView = (InputMarginView) findViewById(R.id.input_margin_view); diff --git a/apps/OboeTester/app/src/main/res/layout/activity_test_input.xml b/apps/OboeTester/app/src/main/res/layout/activity_test_input.xml index 27c99eb7a..2685c2ae4 100644 --- a/apps/OboeTester/app/src/main/res/layout/activity_test_input.xml +++ b/apps/OboeTester/app/src/main/res/layout/activity_test_input.xml @@ -49,5 +49,29 @@ android:layout_marginBottom="4dp" android:layout_width="fill_parent" android:layout_height="20dp" /> + + + + + + + + diff --git a/apps/OboeTester/app/src/main/res/values/strings.xml b/apps/OboeTester/app/src/main/res/values/strings.xml index 3f96c0de4..da57ffe59 100644 --- a/apps/OboeTester/app/src/main/res/values/strings.xml +++ b/apps/OboeTester/app/src/main/res/values/strings.xml @@ -258,7 +258,7 @@ Average Fail Skip - Disconnect all headsets.\nIn quiet room, volume up, [START] + Attach peripherals\nVolume up, [START] Disconnect all headsets.\nPress [RUN] Analyze From 81438315810c4697f5347aeaa99f87ea73361ad5 Mon Sep 17 00:00:00 2001 From: Phil Burk Date: Thu, 15 Feb 2024 17:28:51 -0800 Subject: [PATCH 3/6] Change checkboxes. Remove some dead code. --- .../oboetester/BaseAutoGlitchActivity.java | 2 +- .../oboetester/TestDataPathsActivity.java | 122 +++++------------- .../main/res/layout/activity_data_paths.xml | 16 +-- 3 files changed, 35 insertions(+), 105 deletions(-) diff --git a/apps/OboeTester/app/src/main/java/com/mobileer/oboetester/BaseAutoGlitchActivity.java b/apps/OboeTester/app/src/main/java/com/mobileer/oboetester/BaseAutoGlitchActivity.java index 3d345fc07..fb71751cf 100644 --- a/apps/OboeTester/app/src/main/java/com/mobileer/oboetester/BaseAutoGlitchActivity.java +++ b/apps/OboeTester/app/src/main/java/com/mobileer/oboetester/BaseAutoGlitchActivity.java @@ -238,7 +238,7 @@ protected String getConfigText(StreamConfiguration config) { + ", ID = " + String.format(Locale.getDefault(), "%2d", config.getDeviceId()) + ", Perf = " + StreamConfiguration.convertPerformanceModeToText( config.getPerformanceMode()) - + ",\n ch = " + channelText(channel, config.getChannelCount()) + + ",\n ch = " + channelText(channel, config.getChannelCount()) + ", cm = " + convertChannelMaskToText(config.getChannelMask()); } 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 55622ed19..3af9de581 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 @@ -37,19 +37,11 @@ /** * TODO - * Select device types based on priority or maybe offer checkboxes. - * Print devices types being tested. - * Avoid mismatch such as mic input and USB output. * Avoid duplicating tests by not using Unspecified (except for ch-mask) - * - * Find available device types. - * Decide which device types to test. - * For each type find partner type, then decide other options: - * channels for speaker/mic and wired headset usb headset get mixed to one - * so allow channel mask downmix test - * check each channelCount if specified - * channels for USB device are 1:1, so match channels directly, FFT per input? - * + * Add input channel masks back in under an "InChans" checkbox. + * Cancel test and recalculate selected device types when device added or removed. + * Remove dead code. + * Add back "OneLineSummary" */ /** @@ -58,6 +50,9 @@ * Also test each microphone channel and device. * Try each InputPreset. * + * 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 @@ -145,8 +140,7 @@ public class TestDataPathsActivity extends BaseAutoGlitchActivity { private double mPhaseErrorCount; private CheckBox mCheckBoxInputPresets; - private CheckBox mCheckBoxInputDevices; - private CheckBox mCheckBoxOutputDevices; + private CheckBox mCheckBoxAllChannels; private CheckBox mCheckBoxAllOutputChannelMasks; private CheckBox mCheckBoxAllSampleRates; private TextView mInstructionsTextView; @@ -337,8 +331,7 @@ protected void inflateActivity() { protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); 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); mCheckBoxAllOutputChannelMasks = (CheckBox)findViewById(R.id.checkbox_paths_all_output_channel_masks); mCheckBoxAllSampleRates = @@ -406,10 +399,6 @@ protected boolean isFinishedEarly() { @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"; } @@ -518,62 +507,15 @@ && getOutputChannel() == 0) { return testResult; } - void testPresetCombo(int inputPreset, - int numInputChannels, - int inputChannel, - int numOutputChannels, - int outputChannel, - boolean mmapEnabled - ) throws InterruptedException { - setupDeviceCombo(numInputChannels, 0, inputChannel, 48000, - numOutputChannels, 0, outputChannel, 48000); - - StreamConfiguration requestedInConfig = mAudioInputTester.requestedConfiguration; - requestedInConfig.setInputPreset(inputPreset); - requestedInConfig.setMMap(mmapEnabled); - - mMagnitude = -1.0; - TestResult testResult = testCurrentConfigurations(); - if (testResult != null) { - int result = testResult.result; - String extra = ", inPre = " - + StreamConfiguration.convertInputPresetToText(inputPreset); - logOneLineSummary(testResult, extra); - 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!"); - } - } - } - } - - 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 testInputPresets() throws InterruptedException { - logBoth("\nTest InputPreset -------"); - + logBoth("\n########### InputPreset\n"); + StreamConfiguration requestedInConfig = mAudioInputTester.requestedConfiguration; + int defaultPreset = requestedInConfig.getInputPreset(); for (int inputPreset : INPUT_PRESETS) { - testPresetCombo(inputPreset); + requestedInConfig.setInputPreset(inputPreset); + testPerformancePaths(); } + requestedInConfig.setInputPreset(defaultPreset); } void testInputDeviceCombo(int deviceId, @@ -763,10 +705,18 @@ private void testDeviceOutputInfo(AudioDeviceInfo outputDeviceInfo) throws Inte requestedInConfig.setDeviceId(inputDeviceInfo.getId()); requestedOutConfig.setDeviceId(outputDeviceInfo.getId()); - testOutputChannelCounts(inputDeviceInfo, outputDeviceInfo); + if (mCheckBoxAllChannels.isChecked()) { + testOutputChannelCounts(inputDeviceInfo, outputDeviceInfo); + } + + if (mCheckBoxInputPresets.isChecked()) { + runOnUiThread(() -> mCheckBoxInputPresets.setEnabled(false)); + testInputPresets(); + } - runOnUiThread(() -> mCheckBoxAllSampleRates.setEnabled(false)); if (mCheckBoxAllSampleRates.isChecked()) { + logBoth("\n################ Sample Rates\n"); + runOnUiThread(() -> mCheckBoxAllSampleRates.setEnabled(false)); for (int sampleRate : SAMPLE_RATES) { requestedInConfig.setSampleRate(sampleRate); requestedOutConfig.setSampleRate(sampleRate); @@ -779,7 +729,7 @@ private void testDeviceOutputInfo(AudioDeviceInfo outputDeviceInfo) throws Inte if (android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.S_V2 && isDeviceTypeMixed(outputDeviceInfo.getType())) { runOnUiThread(() -> mCheckBoxAllOutputChannelMasks.setEnabled(false)); - + logBoth("\n################ Channel Masks\n"); for (int channelMask : mCheckBoxAllOutputChannelMasks.isChecked() ? ALL_OUTPUT_CHANNEL_MASKS : SHORT_OUTPUT_CHANNEL_MASKS) { int channelCount = Integer.bitCount(channelMask); @@ -809,6 +759,7 @@ private void showDeviceInfo(AudioDeviceInfo outputDeviceInfo, AudioDeviceInfo in } private void testOutputChannelCounts(AudioDeviceInfo inputDeviceInfo, AudioDeviceInfo outputDeviceInfo) throws InterruptedException { + logBoth("\n########### Output Channel Counts\n"); ArrayList channelCountsTested =new ArrayList(); StreamConfiguration requestedInConfig = mAudioInputTester.requestedConfiguration; StreamConfiguration requestedOutConfig = mAudioOutTester.requestedConfiguration; @@ -956,19 +907,6 @@ public void runTest() { testOutputDeviceTypes(); -// if (mCheckBoxInputPresets.isChecked()) { -// runOnUiThread(() -> mCheckBoxInputPresets.setEnabled(false)); -// testInputPresets(); -// } -// if (mCheckBoxInputDevices.isChecked()) { -// runOnUiThread(() -> mCheckBoxInputDevices.setEnabled(false)); -// testInputDevices(); -// } -// if (mCheckBoxOutputDevices.isChecked()) { -// runOnUiThread(() -> mCheckBoxOutputDevices.setEnabled(false)); -// testOutputDevices(); -// } - compareFailedTestsWithNearestPassingTest(); } catch (InterruptedException e) { @@ -979,8 +917,7 @@ public void runTest() { } finally { runOnUiThread(() -> { mCheckBoxInputPresets.setEnabled(true); - mCheckBoxInputDevices.setEnabled(true); - mCheckBoxOutputDevices.setEnabled(true); + mCheckBoxAllChannels.setEnabled(true); mCheckBoxAllOutputChannelMasks.setEnabled(true); mCheckBoxAllSampleRates.setEnabled(true); keepScreenOn(false); @@ -1011,8 +948,7 @@ public void startTestUsingBundle() { runOnUiThread(() -> { mCheckBoxInputPresets.setChecked(shouldUseInputPresets); - mCheckBoxInputDevices.setChecked(shouldUseInputDevices); - mCheckBoxOutputDevices.setChecked(shouldUseOutputDevices); + mCheckBoxAllChannels.setChecked(shouldUseOutputDevices); mCheckBoxAllOutputChannelMasks.setChecked(shouldUseAllOutputChannelMasks); mCheckBoxAllSampleRates.setChecked(shouldUseAllSampleRates); mAutomatedTestRunner.setTestIndexText(singleTestIndex); diff --git a/apps/OboeTester/app/src/main/res/layout/activity_data_paths.xml b/apps/OboeTester/app/src/main/res/layout/activity_data_paths.xml index 52d8da948..4299c8441 100644 --- a/apps/OboeTester/app/src/main/res/layout/activity_data_paths.xml +++ b/apps/OboeTester/app/src/main/res/layout/activity_data_paths.xml @@ -23,18 +23,18 @@ android:text="InPre" /> + android:text="AllChan" /> + android:checked="false" + android:text="AllSRs" /> - Date: Thu, 22 Feb 2024 18:33:25 -0800 Subject: [PATCH 4/6] Cleaned up Data Paths Addressed comments. --- .../oboetester/AutomatedTestRunner.java | 2 +- .../oboetester/BaseAutoGlitchActivity.java | 21 +- .../oboetester/TestDataPathsActivity.java | 290 ++++++------------ .../main/res/layout/activity_data_paths.xml | 13 +- 4 files changed, 122 insertions(+), 204 deletions(-) diff --git a/apps/OboeTester/app/src/main/java/com/mobileer/oboetester/AutomatedTestRunner.java b/apps/OboeTester/app/src/main/java/com/mobileer/oboetester/AutomatedTestRunner.java index 6d54f4574..27fc0456c 100644 --- a/apps/OboeTester/app/src/main/java/com/mobileer/oboetester/AutomatedTestRunner.java +++ b/apps/OboeTester/app/src/main/java/com/mobileer/oboetester/AutomatedTestRunner.java @@ -288,7 +288,7 @@ public void run() { mFailCount = 0; try { mActivity.runTest(); - log("Tests finished without exception."); + log("Tests finished."); } catch(Exception e) { log("EXCEPTION: " + e.getMessage()); } finally { diff --git a/apps/OboeTester/app/src/main/java/com/mobileer/oboetester/BaseAutoGlitchActivity.java b/apps/OboeTester/app/src/main/java/com/mobileer/oboetester/BaseAutoGlitchActivity.java index fb71751cf..1be2f00ea 100644 --- a/apps/OboeTester/app/src/main/java/com/mobileer/oboetester/BaseAutoGlitchActivity.java +++ b/apps/OboeTester/app/src/main/java/com/mobileer/oboetester/BaseAutoGlitchActivity.java @@ -23,7 +23,6 @@ import android.media.AudioManager; import android.os.Bundle; -import androidx.annotation.NonNull; import androidx.annotation.Nullable; import java.io.IOException; @@ -307,7 +306,7 @@ protected TestResult testCurrentConfigurations() throws InterruptedException { ); // The test will only be worth running if we got the configuration we requested on input or output. - String skipReason = shouldTestBeSkipped(); + String skipReason = whyShouldTestBeSkipped(); boolean skipped = skipReason.length() > 0; boolean valid = !openFailed && !skipped; boolean startFailed = false; @@ -413,16 +412,23 @@ protected AudioDeviceInfo getDeviceInfoByType(int deviceType, int flags) { return null; } - protected boolean isDeviceTypeMixed(int type) { + /** + * Are outputs mixed in the air or by a loopback plug? + * @param type device type, eg AudioDeviceInfo.TYPE_BUILTIN_SPEAKER + * @return true if stereo output channels get mixed to mono input + */ + protected boolean isDeviceTypeMixedForLoopback(int type) { switch(type) { + // Mixed in the air. case AudioDeviceInfo.TYPE_BUILTIN_SPEAKER: case AudioDeviceInfo.TYPE_BUILTIN_SPEAKER_SAFE: + // Mixed in the loopback fun-plug. case AudioDeviceInfo.TYPE_WIRED_HEADSET: case AudioDeviceInfo.TYPE_USB_HEADSET: return true; case AudioDeviceInfo.TYPE_USB_DEVICE: default: - return false; + return false; // channels are discrete } } @@ -468,7 +474,12 @@ protected boolean isFinishedEarly() { return false; } - protected String shouldTestBeSkipped() { + /** + * Figure out if a test should be skipped and return the reason. + * + * @return reason for skipping or an empty string + */ + protected String whyShouldTestBeSkipped() { String why = ""; StreamConfiguration requestedInConfig = mAudioInputTester.requestedConfiguration; StreamConfiguration requestedOutConfig = mAudioOutTester.requestedConfiguration; 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 3af9de581..17324a151 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 @@ -36,19 +36,9 @@ import java.util.Locale; /** - * TODO - * Avoid duplicating tests by not using Unspecified (except for ch-mask) - * Add input channel masks back in under an "InChans" checkbox. - * Cancel test and recalculate selected device types when device added or removed. - * Remove dead code. - * Add back "OneLineSummary" - */ - -/** - * 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. @@ -56,14 +46,12 @@ * 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 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 { @@ -141,7 +129,8 @@ public class TestDataPathsActivity extends BaseAutoGlitchActivity { private CheckBox mCheckBoxInputPresets; private CheckBox mCheckBoxAllChannels; - private CheckBox mCheckBoxAllOutputChannelMasks; + private CheckBox mCheckBoxInputChannelMasks; + private CheckBox mCheckBoxOutputChannelMasks; private CheckBox mCheckBoxAllSampleRates; private TextView mInstructionsTextView; @@ -157,8 +146,9 @@ public class TestDataPathsActivity extends BaseAutoGlitchActivity { private static final int[] SHORT_OUTPUT_CHANNEL_MASKS = { StreamConfiguration.CHANNEL_MONO, StreamConfiguration.CHANNEL_STEREO, - StreamConfiguration.CHANNEL_2POINT1, // TODO should this be 5.1?! - StreamConfiguration.CHANNEL_7POINT1POINT4, + 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 = { @@ -332,8 +322,9 @@ protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); mCheckBoxInputPresets = (CheckBox)findViewById(R.id.checkbox_paths_input_presets); mCheckBoxAllChannels = (CheckBox)findViewById(R.id.checkbox_paths_all_channels); - mCheckBoxAllOutputChannelMasks = - (CheckBox)findViewById(R.id.checkbox_paths_all_output_channel_masks); + mCheckBoxInputChannelMasks = (CheckBox)findViewById(R.id.checkbox_paths_in_channel_masks); + mCheckBoxOutputChannelMasks = + (CheckBox)findViewById(R.id.checkbox_paths_output_channel_masks); mCheckBoxAllSampleRates = (CheckBox)findViewById(R.id.checkbox_paths_all_sample_rates); @@ -363,8 +354,8 @@ protected String getConfigText(StreamConfiguration config) { } @Override - protected String shouldTestBeSkipped() { - String why = super.shouldTestBeSkipped(); + protected String whyShouldTestBeSkipped() { + String why = super.whyShouldTestBeSkipped(); StreamConfiguration requestedInConfig = mAudioInputTester.requestedConfiguration; StreamConfiguration requestedOutConfig = mAudioOutTester.requestedConfiguration; StreamConfiguration actualInConfig = mAudioInputTester.actualConfiguration; @@ -437,48 +428,6 @@ String getOneLineSummary() { + ", mag = " + getMagnitudeText(mMaxMagnitude); } - void setupDeviceCombo(int inputChannelCount, - int inputChannelMask, - int inputChannel, - int inputSampleRate, - int outputChannelCount, - int outputChannelMask, - int outputChannel, - int outputSampleRate) 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.setSampleRate(inputSampleRate); - requestedOutConfig.setSampleRate(outputSampleRate); - - if (inputChannelMask != 0) { - requestedInConfig.setChannelMask(inputChannelMask); - } else { - requestedInConfig.setChannelCount(inputChannelCount); - } - if (outputChannelMask != 0) { - requestedOutConfig.setChannelMask(outputChannelMask); - } else { - requestedOutConfig.setChannelCount(outputChannelCount); - } - - requestedInConfig.setMMap(false); - requestedOutConfig.setMMap(false); - - setInputChannel(inputChannel); - setOutputChannel(outputChannel); - } - @Override protected TestResult testCurrentConfigurations() throws InterruptedException { TestResult testResult = super.testCurrentConfigurations(); @@ -510,126 +459,12 @@ && getOutputChannel() == 0) { private void testInputPresets() throws InterruptedException { logBoth("\n########### InputPreset\n"); StreamConfiguration requestedInConfig = mAudioInputTester.requestedConfiguration; - int defaultPreset = requestedInConfig.getInputPreset(); + int originalPreset = requestedInConfig.getInputPreset(); for (int inputPreset : INPUT_PRESETS) { requestedInConfig.setInputPreset(inputPreset); testPerformancePaths(); } - requestedInConfig.setInputPreset(defaultPreset); - } - - void testInputDeviceCombo(int deviceId, - int deviceType, - int channelCount, - int channelMask, - int inputChannel, - int inputSampleRate, - boolean mmapEnabled) throws InterruptedException { - String typeString = AudioDeviceInfoConverter.typeToString(deviceType); - if (channelMask != 0) { - setTestName("Test InDev: #" + deviceId + " " + typeString + "_" + - convertChannelMaskToText(channelMask) + "_" + - inputChannel + "/" + channelCount + "_" + inputSampleRate); - } else { - setTestName("Test InDev: #" + deviceId + " " + typeString - + "_" + inputChannel + "/" + channelCount + "_" + inputSampleRate); - } - - final int numOutputChannels = 2; - setupDeviceCombo(channelCount, channelMask, inputChannel, inputSampleRate, - numOutputChannels, 0, 0, 48000); - - StreamConfiguration requestedInConfig = mAudioInputTester.requestedConfiguration; - requestedInConfig.setInputPreset(StreamConfiguration.INPUT_PRESET_VOICE_RECOGNITION); - requestedInConfig.setDeviceId(deviceId); - requestedInConfig.setMMap(mmapEnabled); - - mMagnitude = -1.0; - TestResult testResult = testCurrentConfigurations(); - if (testResult != null) { - logOneLineSummary(testResult); - } - } - - void testInputDeviceCombo(int deviceId, - int deviceType, - int channelCount, - int channelMask, - int inputChannel, - int inputSampleRate) throws InterruptedException { - if (NativeEngine.isMMapSupported()) { - testInputDeviceCombo(deviceId, deviceType, channelCount, channelMask, inputChannel, - inputSampleRate, true); - } - testInputDeviceCombo(deviceId, deviceType, channelCount, channelMask, inputChannel, - inputSampleRate, 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)); - 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, 0, 48000); - testInputDeviceCombo(id, deviceType, 2, 0, 0, 48000); - testInputDeviceCombo(id, deviceType, 2, 0, 1, 48000); - 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, 0, channel, - 48000); - } - } - } - } - - runOnUiThread(() -> mCheckBoxAllSampleRates.setEnabled(false)); - if (mCheckBoxAllSampleRates.isChecked()) { - for (int sampleRate : SAMPLE_RATES) { - testInputDeviceCombo(id, deviceType, 1, 0, 0, sampleRate); - } - } - - if (android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.S_V2) { - int[] channelMasks = deviceInfo.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("nativeChannelMask = " + convertChannelMaskToText(nativeChannelMask) + "\n"); - int channelCount = Integer.bitCount(nativeChannelMask); - for (int channel = 0; channel < channelCount; channel++) { - testInputDeviceCombo(id, deviceType, channelCount, nativeChannelMask, - channel, 48000); - } - } - } - } - } else { - log("Device skipped. Not BuiltIn Mic."); - } - } - - if (numTested == 0) { - log("NO INPUT DEVICE FOUND!\n"); - } + requestedInConfig.setInputPreset(originalPreset); } // The native out channel mask is its channel mask shifted right by 2 bits. @@ -704,8 +539,10 @@ private void testDeviceOutputInfo(AudioDeviceInfo outputDeviceInfo) throws Inte requestedOutConfig.reset(); requestedInConfig.setDeviceId(inputDeviceInfo.getId()); requestedOutConfig.setDeviceId(outputDeviceInfo.getId()); + resetChannelConfigurations(requestedInConfig, requestedOutConfig); if (mCheckBoxAllChannels.isChecked()) { + runOnUiThread(() -> mCheckBoxAllChannels.setEnabled(false)); testOutputChannelCounts(inputDeviceInfo, outputDeviceInfo); } @@ -727,10 +564,40 @@ private void testDeviceOutputInfo(AudioDeviceInfo outputDeviceInfo) throws Inte requestedOutConfig.setSampleRate(0); if (android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.S_V2 - && isDeviceTypeMixed(outputDeviceInfo.getType())) { - runOnUiThread(() -> mCheckBoxAllOutputChannelMasks.setEnabled(false)); - logBoth("\n################ Channel Masks\n"); - for (int channelMask : mCheckBoxAllOutputChannelMasks.isChecked() ? + && isDeviceTypeMixedForLoopback(outputDeviceInfo.getType())) { + + if (mCheckBoxInputChannelMasks.isChecked()) { + logBoth("\n################ Input Channel Masks\n"); + runOnUiThread(() -> mCheckBoxInputChannelMasks.setEnabled(false)); + if (android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.S_V2) { + int[] channelMasks = inputDeviceInfo.getChannelMasks(); + requestedOutConfig.setChannelMask(0); + requestedOutConfig.setChannelCount(1); + 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("nativeChannelMask = " + convertChannelMaskToText(nativeChannelMask) + "\n"); + int channelCount = Integer.bitCount(channelMask); + requestedInConfig.setChannelMask(channelMask); + for (int channel = 0; channel < channelCount; channel++) { + setInputChannel(channel); + testPerformancePaths(); + } + } + } + resetChannelConfigurations(requestedInConfig, requestedOutConfig); + } + } + + logBoth("\n################ Output Channel Masks\n"); + runOnUiThread(() -> mCheckBoxOutputChannelMasks.setEnabled(false)); + requestedInConfig.setChannelCount(1); + for (int channelMask : mCheckBoxOutputChannelMasks.isChecked() ? ALL_OUTPUT_CHANNEL_MASKS : SHORT_OUTPUT_CHANNEL_MASKS) { int channelCount = Integer.bitCount(channelMask); requestedOutConfig.setChannelMask(channelMask); @@ -739,23 +606,56 @@ && isDeviceTypeMixed(outputDeviceInfo.getType())) { 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()); + 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 = " + deviceText = "IN: type = " + AudioDeviceInfoConverter.typeToString(inputDeviceInfo.getType()) + + ", #ch = " + findLargestChannelCount(inputDeviceInfo.getChannelCounts()) + "\n" + deviceText; - setInstructionsText(deviceText); } + setInstructionsText(deviceText); + } + + public static int findLargestChannelCount(int[] arr) { + if (arr == null || arr.length == 0) { + return 2; + } + return findLargestInt(arr); + } + + 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 { @@ -765,7 +665,7 @@ private void testOutputChannelCounts(AudioDeviceInfo inputDeviceInfo, AudioDevic StreamConfiguration requestedOutConfig = mAudioOutTester.requestedConfiguration; int[] outputChannelCounts = outputDeviceInfo.getChannelCounts(); - if (isDeviceTypeMixed(outputDeviceInfo.getType())) { + if (isDeviceTypeMixedForLoopback(outputDeviceInfo.getType())) { requestedInConfig.setChannelCount(1); setInputChannel(0); // test mono @@ -917,8 +817,8 @@ public void runTest() { } finally { runOnUiThread(() -> { mCheckBoxInputPresets.setEnabled(true); - mCheckBoxAllChannels.setEnabled(true); - mCheckBoxAllOutputChannelMasks.setEnabled(true); + mCheckBoxInputChannelMasks.setEnabled(true); + mCheckBoxOutputChannelMasks.setEnabled(true); mCheckBoxAllSampleRates.setEnabled(true); keepScreenOn(false); }); @@ -948,8 +848,8 @@ public void startTestUsingBundle() { runOnUiThread(() -> { mCheckBoxInputPresets.setChecked(shouldUseInputPresets); - mCheckBoxAllChannels.setChecked(shouldUseOutputDevices); - mCheckBoxAllOutputChannelMasks.setChecked(shouldUseAllOutputChannelMasks); + mCheckBoxInputChannelMasks.setChecked(shouldUseOutputDevices); + mCheckBoxOutputChannelMasks.setChecked(shouldUseAllOutputChannelMasks); mCheckBoxAllSampleRates.setChecked(shouldUseAllSampleRates); mAutomatedTestRunner.setTestIndexText(singleTestIndex); }); diff --git a/apps/OboeTester/app/src/main/res/layout/activity_data_paths.xml b/apps/OboeTester/app/src/main/res/layout/activity_data_paths.xml index 4299c8441..40ef5ecc7 100644 --- a/apps/OboeTester/app/src/main/res/layout/activity_data_paths.xml +++ b/apps/OboeTester/app/src/main/res/layout/activity_data_paths.xml @@ -27,7 +27,7 @@ android:layout_width="wrap_content" android:layout_height="wrap_content" android:checked="true" - android:text="AllChan" /> + android:text="AllCh" /> + android:text="InChMasks" /> + + From 215b809fb67372e309e4e9101dc5faec0365c732 Mon Sep 17 00:00:00 2001 From: Phil Burk Date: Fri, 23 Feb 2024 17:53:38 -0800 Subject: [PATCH 5/6] Update automated test options. Use level for mask testing. --- .../oboetester/BaseAutoGlitchActivity.java | 18 +- .../oboetester/TestDataPathsActivity.java | 192 ++++++++++++------ .../main/res/layout/activity_data_paths.xml | 44 +++- 3 files changed, 176 insertions(+), 78 deletions(-) diff --git a/apps/OboeTester/app/src/main/java/com/mobileer/oboetester/BaseAutoGlitchActivity.java b/apps/OboeTester/app/src/main/java/com/mobileer/oboetester/BaseAutoGlitchActivity.java index 1be2f00ea..847dc5633 100644 --- a/apps/OboeTester/app/src/main/java/com/mobileer/oboetester/BaseAutoGlitchActivity.java +++ b/apps/OboeTester/app/src/main/java/com/mobileer/oboetester/BaseAutoGlitchActivity.java @@ -171,7 +171,7 @@ public String comparePassed(TestResult passed) { StringBuffer text = new StringBuffer(); text.append("Compare with passed test #" + passed.testIndex + "\n"); text.append(input.comparePassedDirection("IN", passed.input)); - text.append(TestDataPathsActivity.comparePassedField("IN", this, passed, "inputPreset")); + text.append(TestDataPathsActivity.comparePassedInputPreset("IN", this, passed)); text.append(output.comparePassedDirection("OUT", passed.output)); text.append(TestDataPathsActivity.comparePassedField("I/O",this, passed, "sampleRate")); @@ -257,11 +257,11 @@ protected String getStreamText(AudioStreamBase stream) { @Nullable protected TestResult testCurrentConfigurations() throws InterruptedException { mAutomatedTestRunner.incrementTestCount(); - if ((getSingleTestIndex() >= 0) && (mAutomatedTestRunner.getTestCount() != getSingleTestIndex())) { + if ((getSingleTestIndex() >= 0) && (getTestCount() != getSingleTestIndex())) { return null; } - log("========================== #" + mAutomatedTestRunner.getTestCount()); + log("========================== #" + getTestCount()); int result = 0; StreamConfiguration requestedInConfig = mAudioInputTester.requestedConfiguration; StreamConfiguration requestedOutConfig = mAudioOutTester.requestedConfiguration; @@ -278,6 +278,7 @@ protected TestResult testCurrentConfigurations() throws InterruptedException { boolean openFailed = false; try { openAudio(); // this will fill in actualConfig + log("Actual:"); log(" SR = " + actualOutConfig.getSampleRate()); // Set output size to a level that will avoid glitches. @@ -297,7 +298,7 @@ protected TestResult testCurrentConfigurations() throws InterruptedException { } TestResult testResult = new TestResult( - mAutomatedTestRunner.getTestCount(), + getTestCount(), mTestName, mAudioInputTester.actualConfiguration, getInputChannel(), @@ -350,7 +351,7 @@ protected TestResult testCurrentConfigurations() throws InterruptedException { } if (openFailed || startFailed) { - appendFailedSummary("------ #" + mAutomatedTestRunner.getTestCount() + "\n"); + appendFailedSummary("------ #" + getTestCount() + "\n"); appendFailedSummary(getConfigText(requestedInConfig) + "\n"); appendFailedSummary(getConfigText(requestedOutConfig) + "\n"); appendFailedSummary(reason + "\n"); @@ -368,7 +369,7 @@ protected TestResult testCurrentConfigurations() throws InterruptedException { resultText += reason; log(" " + resultText); if (!passed) { - appendFailedSummary("------ #" + mAutomatedTestRunner.getTestCount() + "\n"); + appendFailedSummary("------ #" + getTestCount() + "\n"); appendFailedSummary(" " + getConfigText(actualInConfig) + "\n"); appendFailedSummary(" " + getConfigText(actualOutConfig) + "\n"); appendFailedSummary(" " + resultText + "\n"); @@ -392,6 +393,10 @@ protected TestResult testCurrentConfigurations() throws InterruptedException { return testResult; } + protected int getTestCount() { + return mAutomatedTestRunner.getTestCount(); + } + protected AudioDeviceInfo getDeviceInfoById(int deviceId) { AudioDeviceInfo[] devices = mAudioManager.getDevices(AudioManager.GET_DEVICES_ALL); for (AudioDeviceInfo deviceInfo : devices) { @@ -426,6 +431,7 @@ protected boolean isDeviceTypeMixedForLoopback(int type) { case AudioDeviceInfo.TYPE_WIRED_HEADSET: case AudioDeviceInfo.TYPE_USB_HEADSET: return true; + case AudioDeviceInfo.TYPE_USB_DEVICE: default: return false; // channels are discrete 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 17324a151..feefcfde4 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 @@ -18,6 +18,7 @@ import static com.mobileer.oboetester.IntentBasedTestSupport.configureStreamsFromBundle; import static com.mobileer.oboetester.StreamConfiguration.convertChannelMaskToText; +import static com.mobileer.oboetester.StreamConfiguration.convertInputPresetToText; import android.media.AudioDeviceInfo; import android.media.AudioManager; @@ -25,6 +26,8 @@ import android.os.Bundle; import android.util.Log; import android.widget.CheckBox; +import android.widget.RadioButton; +import android.widget.RadioGroup; import android.widget.TextView; import androidx.annotation.NonNull; @@ -58,20 +61,26 @@ 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_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 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; - 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_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; @@ -130,7 +139,10 @@ public class TestDataPathsActivity extends BaseAutoGlitchActivity { private CheckBox mCheckBoxInputPresets; private CheckBox mCheckBoxAllChannels; private CheckBox mCheckBoxInputChannelMasks; - private CheckBox mCheckBoxOutputChannelMasks; + private RadioGroup mRadioGroutOutputChannelMasks; + private RadioButton mRadioOutputChannelMasksNone; + private RadioButton mRadioOutputChannelMasksSome; + private RadioButton mRadioOutputChannelMasksAll; private CheckBox mCheckBoxAllSampleRates; private TextView mInstructionsTextView; @@ -205,6 +217,16 @@ public static String comparePassedField(String prefix, Object failed, Object pas 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 = p1 - p2; @@ -323,12 +345,15 @@ protected void onCreate(Bundle savedInstanceState) { mCheckBoxInputPresets = (CheckBox)findViewById(R.id.checkbox_paths_input_presets); mCheckBoxAllChannels = (CheckBox)findViewById(R.id.checkbox_paths_all_channels); mCheckBoxInputChannelMasks = (CheckBox)findViewById(R.id.checkbox_paths_in_channel_masks); - mCheckBoxOutputChannelMasks = - (CheckBox)findViewById(R.id.checkbox_paths_output_channel_masks); mCheckBoxAllSampleRates = (CheckBox)findViewById(R.id.checkbox_paths_all_sample_rates); mInstructionsTextView = (TextView) findViewById(R.id.text_instructions); + + mRadioGroutOutputChannelMasks = (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 @@ -456,8 +481,12 @@ && getOutputChannel() == 0) { return testResult; } + private void logSection(String name) { + logBoth("\n#" + getTestCount() + " ########### " + name + "\n"); + } + private void testInputPresets() throws InterruptedException { - logBoth("\n########### InputPreset\n"); + logSection("InputPreset"); StreamConfiguration requestedInConfig = mAudioInputTester.requestedConfiguration; int originalPreset = requestedInConfig.getInputPreset(); for (int inputPreset : INPUT_PRESETS) { @@ -473,7 +502,7 @@ int convertJavaOutChannelMaskToNativeChannelMask(int javaChannelMask) { return javaChannelMask >> 2; } - // The native channel mask in AAudio is different than the Java in channel mask. + // 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) { @@ -552,7 +581,7 @@ private void testDeviceOutputInfo(AudioDeviceInfo outputDeviceInfo) throws Inte } if (mCheckBoxAllSampleRates.isChecked()) { - logBoth("\n################ Sample Rates\n"); + logSection("Sample Rates"); runOnUiThread(() -> mCheckBoxAllSampleRates.setEnabled(false)); for (int sampleRate : SAMPLE_RATES) { requestedInConfig.setSampleRate(sampleRate); @@ -563,50 +592,54 @@ private void testDeviceOutputInfo(AudioDeviceInfo outputDeviceInfo) throws Inte 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()) { - logBoth("\n################ Input Channel Masks\n"); + if (mCheckBoxInputChannelMasks.isChecked()) { // INPUT? + logSection("Input Channel Masks"); runOnUiThread(() -> mCheckBoxInputChannelMasks.setEnabled(false)); - if (android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.S_V2) { - int[] channelMasks = inputDeviceInfo.getChannelMasks(); - requestedOutConfig.setChannelMask(0); - requestedOutConfig.setChannelCount(1); - 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("nativeChannelMask = " + convertChannelMaskToText(nativeChannelMask) + "\n"); - int channelCount = Integer.bitCount(channelMask); - requestedInConfig.setChannelMask(channelMask); - for (int channel = 0; channel < channelCount; channel++) { - setInputChannel(channel); - testPerformancePaths(); - } + + 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); } + resetChannelConfigurations(requestedInConfig, requestedOutConfig); } - logBoth("\n################ Output Channel Masks\n"); - runOnUiThread(() -> mCheckBoxOutputChannelMasks.setEnabled(false)); - requestedInConfig.setChannelCount(1); - for (int channelMask : mCheckBoxOutputChannelMasks.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(); + runOnUiThread(() -> mRadioGroutOutputChannelMasks.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); } - resetChannelConfigurations(requestedInConfig, requestedOutConfig); } } @@ -659,7 +692,7 @@ public static int findLargestInt(int[] arr) { } private void testOutputChannelCounts(AudioDeviceInfo inputDeviceInfo, AudioDeviceInfo outputDeviceInfo) throws InterruptedException { - logBoth("\n########### Output Channel Counts\n"); + logSection("Output Channel Counts"); ArrayList channelCountsTested =new ArrayList(); StreamConfiguration requestedInConfig = mAudioInputTester.requestedConfiguration; StreamConfiguration requestedOutConfig = mAudioOutTester.requestedConfiguration; @@ -736,15 +769,22 @@ private void testPerformancePaths() throws InterruptedException { StreamConfiguration requestedInConfig = mAudioInputTester.requestedConfiguration; StreamConfiguration requestedOutConfig = mAudioOutTester.requestedConfiguration; - 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); + // 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()) { requestedInConfig.setMMap(true); requestedOutConfig.setMMap(true); @@ -753,9 +793,6 @@ private void testPerformancePaths() throws InterruptedException { requestedInConfig.setMMap(false); requestedOutConfig.setMMap(false); - requestedInConfig.setPerformanceMode(StreamConfiguration.PERFORMANCE_MODE_NONE); - requestedOutConfig.setPerformanceMode(StreamConfiguration.PERFORMANCE_MODE_NONE); - testCurrentConfigurations(); } private void testOutputDeviceTypes() throws InterruptedException { @@ -817,8 +854,9 @@ public void runTest() { } finally { runOnUiThread(() -> { mCheckBoxInputPresets.setEnabled(true); + mCheckBoxAllChannels.setEnabled(true); mCheckBoxInputChannelMasks.setEnabled(true); - mCheckBoxOutputChannelMasks.setEnabled(true); + mRadioGroutOutputChannelMasks.setEnabled(true); mCheckBoxAllSampleRates.setEnabled(true); keepScreenOn(false); }); @@ -831,29 +869,57 @@ public void startTestUsingBundle() { StreamConfiguration requestedOutConfig = mAudioOutTester.requestedConfiguration; configureStreamsFromBundle(mBundleFromIntent, requestedInConfig, requestedOutConfig); + // These are the current supported options. 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); - boolean shouldUseAllOutputChannelMasks = - mBundleFromIntent.getBoolean(KEY_USE_ALL_OUTPUT_CHANNEL_MASKS, - VALUE_DEFAULT_USE_ALL_OUTPUT_CHANNEL_MASKS); boolean shouldUseAllSampleRates = mBundleFromIntent.getBoolean(KEY_USE_ALL_SAMPLE_RATES, VALUE_DEFAULT_USE_ALL_SAMPLE_RATES); + 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. + boolean shouldUseInputDevices = mBundleFromIntent.getBoolean(KEY_USE_INPUT_DEVICES, + VALUE_DEFAULT_USE_INPUT_CHANNEL_MASKS); + boolean shouldUseInputChannelMasks = + mBundleFromIntent.getBoolean(KEY_USE_INPUT_CHANNEL_MASKS, + shouldUseInputDevices); + + boolean shouldUseOutputDevices = mBundleFromIntent.getBoolean(KEY_USE_OUTPUT_DEVICES, + VALUE_DEFAULT_USE_ALL_CHANNEL_COUNTS); + boolean shouldUseAllChannelCounts = + mBundleFromIntent.getBoolean(KEY_USE_ALL_CHANNEL_COUNTS, + shouldUseOutputDevices); + + boolean shouldUseAllOutputChannelMasks = + mBundleFromIntent.getBoolean(KEY_USE_ALL_OUTPUT_CHANNEL_MASKS, + VALUE_DEFAULT_USE_ALL_OUTPUT_CHANNEL_MASKS); + int defaultOutputChannelMasksLevel = shouldUseAllOutputChannelMasks ? 2 : 1; + final int outputChannelMasksLevel = mBundleFromIntent.getInt(KEY_OUTPUT_CHANNEL_MASKS_LEVEL, + defaultOutputChannelMasksLevel); + runOnUiThread(() -> { mCheckBoxInputPresets.setChecked(shouldUseInputPresets); - mCheckBoxInputChannelMasks.setChecked(shouldUseOutputDevices); - mCheckBoxOutputChannelMasks.setChecked(shouldUseAllOutputChannelMasks); mCheckBoxAllSampleRates.setChecked(shouldUseAllSampleRates); mAutomatedTestRunner.setTestIndexText(singleTestIndex); + mCheckBoxAllChannels.setChecked(shouldUseAllChannelCounts); + mCheckBoxInputChannelMasks.setChecked(shouldUseInputChannelMasks); + switch(outputChannelMasksLevel) { + case 2: + mRadioOutputChannelMasksAll.setChecked(true); + break; + case 1: + mRadioOutputChannelMasksSome.setChecked(true); + break; + 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(); } } diff --git a/apps/OboeTester/app/src/main/res/layout/activity_data_paths.xml b/apps/OboeTester/app/src/main/res/layout/activity_data_paths.xml index 40ef5ecc7..a3f27c071 100644 --- a/apps/OboeTester/app/src/main/res/layout/activity_data_paths.xml +++ b/apps/OboeTester/app/src/main/res/layout/activity_data_paths.xml @@ -35,6 +35,13 @@ android:layout_height="wrap_content" android:checked="false" android:text="AllSRs" /> + + - + android:text="OutChMasks:" /> - + android:orientation="horizontal"> + + + + + + Date: Wed, 28 Feb 2024 09:16:59 -0800 Subject: [PATCH 6/6] Add constants for mask test level Address some comments --- .../oboetester/TestDataPathsActivity.java | 40 +++++++++++-------- 1 file changed, 23 insertions(+), 17 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 feefcfde4..74879f145 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 @@ -18,7 +18,6 @@ import static com.mobileer.oboetester.IntentBasedTestSupport.configureStreamsFromBundle; import static com.mobileer.oboetester.StreamConfiguration.convertChannelMaskToText; -import static com.mobileer.oboetester.StreamConfiguration.convertInputPresetToText; import android.media.AudioDeviceInfo; import android.media.AudioManager; @@ -76,6 +75,11 @@ public class TestDataPathsActivity extends BaseAutoGlitchActivity { 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"; @@ -139,7 +143,7 @@ public class TestDataPathsActivity extends BaseAutoGlitchActivity { private CheckBox mCheckBoxInputPresets; private CheckBox mCheckBoxAllChannels; private CheckBox mCheckBoxInputChannelMasks; - private RadioGroup mRadioGroutOutputChannelMasks; + private RadioGroup mRadioGroupOutputChannelMasks; private RadioButton mRadioOutputChannelMasksNone; private RadioButton mRadioOutputChannelMasksSome; private RadioButton mRadioOutputChannelMasksAll; @@ -350,7 +354,7 @@ protected void onCreate(Bundle savedInstanceState) { mInstructionsTextView = (TextView) findViewById(R.id.text_instructions); - mRadioGroutOutputChannelMasks = (RadioGroup) findViewById(R.id.group_ch_mask_options); + 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); @@ -482,7 +486,7 @@ && getOutputChannel() == 0) { } private void logSection(String name) { - logBoth("\n#" + getTestCount() + " ########### " + name + "\n"); + logBoth("\n#" + (getTestCount() + 1) + " ########### " + name + "\n"); } private void testInputPresets() throws InterruptedException { @@ -625,7 +629,7 @@ && isDeviceTypeMixedForLoopback(outputDeviceInfo.getType())) { resetChannelConfigurations(requestedInConfig, requestedOutConfig); } - runOnUiThread(() -> mRadioGroutOutputChannelMasks.setEnabled(false)); + runOnUiThread(() -> mRadioGroupOutputChannelMasks.setEnabled(false)); if (!mRadioOutputChannelMasksNone.isChecked()) { // OUTPUT? logSection("Output Channel Masks"); requestedInConfig.setChannelCount(1); @@ -856,7 +860,7 @@ public void runTest() { mCheckBoxInputPresets.setEnabled(true); mCheckBoxAllChannels.setEnabled(true); mCheckBoxInputChannelMasks.setEnabled(true); - mRadioGroutOutputChannelMasks.setEnabled(true); + mRadioGroupOutputChannelMasks.setEnabled(true); mCheckBoxAllSampleRates.setEnabled(true); keepScreenOn(false); }); @@ -870,32 +874,33 @@ public void startTestUsingBundle() { configureStreamsFromBundle(mBundleFromIntent, requestedInConfig, requestedOutConfig); // These are the current supported options. - boolean shouldUseInputPresets = mBundleFromIntent.getBoolean(KEY_USE_INPUT_PRESETS, + final boolean shouldUseInputPresets = mBundleFromIntent.getBoolean(KEY_USE_INPUT_PRESETS, VALUE_DEFAULT_USE_INPUT_PRESETS); - boolean shouldUseAllSampleRates = + final boolean shouldUseAllSampleRates = mBundleFromIntent.getBoolean(KEY_USE_ALL_SAMPLE_RATES, VALUE_DEFAULT_USE_ALL_SAMPLE_RATES); - int singleTestIndex = mBundleFromIntent.getInt(KEY_SINGLE_TEST_INDEX, + 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. - boolean shouldUseInputDevices = mBundleFromIntent.getBoolean(KEY_USE_INPUT_DEVICES, + final boolean shouldUseInputDevices = mBundleFromIntent.getBoolean(KEY_USE_INPUT_DEVICES, VALUE_DEFAULT_USE_INPUT_CHANNEL_MASKS); - boolean shouldUseInputChannelMasks = + final boolean shouldUseInputChannelMasks = mBundleFromIntent.getBoolean(KEY_USE_INPUT_CHANNEL_MASKS, shouldUseInputDevices); - boolean shouldUseOutputDevices = mBundleFromIntent.getBoolean(KEY_USE_OUTPUT_DEVICES, + final boolean shouldUseOutputDevices = mBundleFromIntent.getBoolean(KEY_USE_OUTPUT_DEVICES, VALUE_DEFAULT_USE_ALL_CHANNEL_COUNTS); - boolean shouldUseAllChannelCounts = + final boolean shouldUseAllChannelCounts = mBundleFromIntent.getBoolean(KEY_USE_ALL_CHANNEL_COUNTS, shouldUseOutputDevices); - boolean shouldUseAllOutputChannelMasks = + final boolean shouldUseAllOutputChannelMasks = mBundleFromIntent.getBoolean(KEY_USE_ALL_OUTPUT_CHANNEL_MASKS, VALUE_DEFAULT_USE_ALL_OUTPUT_CHANNEL_MASKS); - int defaultOutputChannelMasksLevel = shouldUseAllOutputChannelMasks ? 2 : 1; + final int defaultOutputChannelMasksLevel = shouldUseAllOutputChannelMasks + ? COVERAGE_LEVEL_ALL : COVERAGE_LEVEL_SOME; final int outputChannelMasksLevel = mBundleFromIntent.getInt(KEY_OUTPUT_CHANNEL_MASKS_LEVEL, defaultOutputChannelMasksLevel); @@ -906,12 +911,13 @@ public void startTestUsingBundle() { mCheckBoxAllChannels.setChecked(shouldUseAllChannelCounts); mCheckBoxInputChannelMasks.setChecked(shouldUseInputChannelMasks); switch(outputChannelMasksLevel) { - case 2: + case COVERAGE_LEVEL_ALL: mRadioOutputChannelMasksAll.setChecked(true); break; - case 1: + case COVERAGE_LEVEL_SOME: mRadioOutputChannelMasksSome.setChecked(true); break; + case COVERAGE_LEVEL_NONE: default: mRadioOutputChannelMasksNone.setChecked(true); break;