aboutsummaryrefslogtreecommitdiff
path: root/apps/OboeTester/app/src/main/java/com/mobileer/oboetester/TestDisconnectActivity.java
diff options
context:
space:
mode:
Diffstat (limited to 'apps/OboeTester/app/src/main/java/com/mobileer/oboetester/TestDisconnectActivity.java')
-rw-r--r--apps/OboeTester/app/src/main/java/com/mobileer/oboetester/TestDisconnectActivity.java209
1 files changed, 181 insertions, 28 deletions
diff --git a/apps/OboeTester/app/src/main/java/com/mobileer/oboetester/TestDisconnectActivity.java b/apps/OboeTester/app/src/main/java/com/mobileer/oboetester/TestDisconnectActivity.java
index 2f3c78c5..b74c3b10 100644
--- a/apps/OboeTester/app/src/main/java/com/mobileer/oboetester/TestDisconnectActivity.java
+++ b/apps/OboeTester/app/src/main/java/com/mobileer/oboetester/TestDisconnectActivity.java
@@ -20,9 +20,16 @@ import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
+import android.hardware.usb.UsbConstants;
+import android.hardware.usb.UsbDevice;
+import android.hardware.usb.UsbEndpoint;
+import android.hardware.usb.UsbInterface;
+import android.hardware.usb.UsbManager;
import android.os.Bundle;
+import android.util.Log;
import android.view.View;
import android.widget.Button;
+import android.widget.CheckBox;
import android.widget.TextView;
import java.io.IOException;
@@ -47,9 +54,14 @@ public class TestDisconnectActivity extends TestAudioActivity {
private volatile boolean mTestFailed;
private volatile boolean mSkipTest;
private volatile int mPlugCount;
+ private volatile int mUsbDeviceAttachedCount;
+ private volatile int mPlugState;
+ private volatile int mPlugMicrophone;
private BroadcastReceiver mPluginReceiver = new PluginBroadcastReceiver();
private Button mFailButton;
private Button mSkipButton;
+ private CheckBox mCheckBoxInputs;
+ private CheckBox mCheckBoxOutputs;
protected AutomatedTestRunner mAutomatedTestRunner;
@@ -58,15 +70,68 @@ public class TestDisconnectActivity extends TestAudioActivity {
public class PluginBroadcastReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
- mPlugCount++;
+ switch (intent.getAction()) {
+ case Intent.ACTION_HEADSET_PLUG: {
+ mPlugMicrophone = intent.getIntExtra("microphone", -1);
+ mPlugState = intent.getIntExtra("state", -1);
+ mPlugCount++;
+ } break;
+ case UsbManager.ACTION_USB_DEVICE_ATTACHED:
+ case UsbManager.ACTION_USB_DEVICE_DETACHED: {
+ UsbDevice device = intent.getParcelableExtra(UsbManager.EXTRA_DEVICE);
+ final boolean hasAudioPlayback =
+ containsAudioStreamingInterface(device, UsbConstants.USB_DIR_OUT);
+ final boolean hasAudioCapture =
+ containsAudioStreamingInterface(device, UsbConstants.USB_DIR_IN);
+ if (hasAudioPlayback || hasAudioCapture) {
+ mPlugState =
+ intent.getAction() == UsbManager.ACTION_USB_DEVICE_ATTACHED ? 1 : 0;
+ mUsbDeviceAttachedCount++;
+ mPlugMicrophone = hasAudioCapture ? 1 : 0;
+ }
+ } break;
+ default:
+ break;
+ }
runOnUiThread(new Runnable() {
@Override
public void run() {
- String message = "Intent.HEADSET_PLUG #" + mPlugCount;
+ String message = "HEADSET_PLUG #" + mPlugCount
+ + ", USB_DEVICE_DE/ATTACHED #" + mUsbDeviceAttachedCount
+ + ", mic = " + mPlugMicrophone
+ + ", state = " + mPlugState;
mPlugTextView.setText(message);
+ log(message);
}
});
}
+
+ private static final int AUDIO_STREAMING_SUB_CLASS = 2;
+
+ /**
+ * Figure out if an UsbDevice contains audio input/output streaming interface or not.
+ *
+ * @param device the given UsbDevice
+ * @param direction the direction of the audio streaming interface
+ * @return true if the UsbDevice contains the audio input/output streaming interface.
+ */
+ private boolean containsAudioStreamingInterface(UsbDevice device, int direction) {
+ final int interfaceCount = device.getInterfaceCount();
+ for (int i = 0; i < interfaceCount; ++i) {
+ UsbInterface usbInterface = device.getInterface(i);
+ if (usbInterface.getInterfaceClass() != UsbConstants.USB_CLASS_AUDIO
+ && usbInterface.getInterfaceSubclass() != AUDIO_STREAMING_SUB_CLASS) {
+ continue;
+ }
+ final int endpointCount = usbInterface.getEndpointCount();
+ for (int j = 0; j < endpointCount; ++j) {
+ if (usbInterface.getEndpoint(j).getDirection() == direction) {
+ return true;
+ }
+ }
+ }
+ return false;
+ }
}
@Override
@@ -85,6 +150,9 @@ public class TestDisconnectActivity extends TestAudioActivity {
mStatusTextView = (TextView) findViewById(R.id.text_status);
mPlugTextView = (TextView) findViewById(R.id.text_plug_events);
+ mCheckBoxInputs = (CheckBox)findViewById(R.id.checkbox_disco_inputs);
+ mCheckBoxOutputs = (CheckBox)findViewById(R.id.checkbox_disco_outputs);
+
mFailButton = (Button) findViewById(R.id.button_fail);
mSkipButton = (Button) findViewById(R.id.button_skip);
updateFailSkipButton(false);
@@ -138,6 +206,8 @@ public class TestDisconnectActivity extends TestAudioActivity {
public void onResume() {
super.onResume();
IntentFilter filter = new IntentFilter(Intent.ACTION_HEADSET_PLUG);
+ filter.addAction(UsbManager.ACTION_USB_DEVICE_ATTACHED);
+ filter.addAction(UsbManager.ACTION_USB_DEVICE_DETACHED);
this.registerReceiver(mPluginReceiver, filter);
}
@@ -185,15 +255,25 @@ public class TestDisconnectActivity extends TestAudioActivity {
private String getConfigText(StreamConfiguration config) {
return ((config.getDirection() == StreamConfiguration.DIRECTION_OUTPUT) ? "OUT" : "IN")
+ ", Perf = " + StreamConfiguration.convertPerformanceModeToText(
- config.getPerformanceMode())
+ config.getPerformanceMode())
+ ", " + StreamConfiguration.convertSharingModeToText(config.getSharingMode())
- + ", " + config.getSampleRate();
+ + ", " + config.getSampleRate()
+ + ", SRC = " + StreamConfiguration.convertRateConversionQualityToText(config.getRateConversionQuality());
+ }
+
+ private void log(Exception e) {
+ Log.e(TestAudioActivity.TAG, "Caught ", e);
+ mAutomatedTestRunner.log("Caught " + e);
}
private void log(String text) {
mAutomatedTestRunner.log(text);
}
+ private void flushLog() {
+ mAutomatedTestRunner.flushLog();
+ }
+
private void appendFailedSummary(String text) {
mAutomatedTestRunner.appendFailedSummary(text);
}
@@ -202,14 +282,36 @@ public class TestDisconnectActivity extends TestAudioActivity {
int perfMode,
int sharingMode,
int sampleRate,
+ int sampleRateConversionQuality,
boolean requestPlugin) throws InterruptedException {
if ((getSingleTestIndex() >= 0) && (mAutomatedTestRunner.getTestCount() != getSingleTestIndex())) {
mAutomatedTestRunner.incrementTestCount();
return;
}
+ if (!isInput && !mCheckBoxOutputs.isChecked()) {
+ return;
+ }
+ if (isInput && !mCheckBoxInputs.isChecked()) {
+ return;
+ }
+
+ updateFailSkipButton(true);
+
String actualConfigText = "none";
mSkipTest = false;
+ mTestFailed = false;
+
+ // Try to synchronize with the current headset state, IN or OUT.
+ while (mAutomatedTestRunner.isThreadEnabled() && !mSkipTest && !mTestFailed) {
+ if (requestPlugin != (mPlugState == 0)) {
+ String message = "SYNC: " + (requestPlugin ? "UNplug" : "Plug IN") + " headset now!";
+ setInstructionsText(message);
+ Thread.sleep(POLL_DURATION_MILLIS);
+ } else {
+ break;
+ }
+ }
AudioInputTester mAudioInTester = null;
AudioOutputTester mAudioOutTester = null;
@@ -234,8 +336,9 @@ public class TestDisconnectActivity extends TestAudioActivity {
requestedConfig.setPerformanceMode(perfMode);
requestedConfig.setSharingMode(sharingMode);
requestedConfig.setSampleRate(sampleRate);
+
if (sampleRate != 0) {
- requestedConfig.setRateConversionQuality(StreamConfiguration.RATE_CONVERSION_QUALITY_MEDIUM);
+ requestedConfig.setRateConversionQuality(sampleRateConversionQuality);
}
log("========================== #" + mAutomatedTestRunner.getTestCount());
@@ -246,20 +349,24 @@ public class TestDisconnectActivity extends TestAudioActivity {
Thread.sleep(SETTLING_TIME_MILLIS);
if (!mAutomatedTestRunner.isThreadEnabled()) return;
boolean openFailed = false;
+ boolean hasMicFailed = false;
AudioStreamBase stream = null;
try {
openAudio();
log("Actual:");
actualConfigText = getConfigText(actualConfig)
- + ", " + (actualConfig.isMMap() ? "MMAP" : "Legacy");
+ + ", " + ((actualConfig.isMMap() ? "MMAP" : "Legacy")
+ + ", Dev = " + actualConfig.getDeviceId()
+ );
log(actualConfigText);
+ flushLog();
stream = (isInput)
? mAudioInTester.getCurrentAudioStream()
: mAudioOutTester.getCurrentAudioStream();
} catch (IOException e) {
openFailed = true;
- log(e.getMessage());
+ log(e);
}
// The test is only worth running if we got the configuration we requested.
@@ -285,14 +392,13 @@ public class TestDisconnectActivity extends TestAudioActivity {
} catch (IOException e) {
e.printStackTrace();
valid = false;
- log(e.getMessage());
+ log(e);
}
}
int oldPlugCount = mPlugCount;
if (!openFailed && valid) {
mTestFailed = false;
- updateFailSkipButton(true);
// poll until stream started
while (!mTestFailed && mAutomatedTestRunner.isThreadEnabled() && !mSkipTest &&
stream.getState() == StreamConfiguration.STREAM_STATE_STARTING) {
@@ -305,15 +411,18 @@ public class TestDisconnectActivity extends TestAudioActivity {
// Wait for Java plug count to change or stream to disconnect.
while (!mTestFailed && mAutomatedTestRunner.isThreadEnabled() && !mSkipTest &&
stream.getState() == StreamConfiguration.STREAM_STATE_STARTED) {
+ flushLog();
Thread.sleep(POLL_DURATION_MILLIS);
if (mPlugCount > oldPlugCount) {
timeoutCount = TIME_TO_FAILURE_MILLIS / POLL_DURATION_MILLIS;
break;
}
}
+
// Wait for timeout or stream to disconnect.
while (!mTestFailed && mAutomatedTestRunner.isThreadEnabled() && !mSkipTest && (timeoutCount > 0) &&
stream.getState() == StreamConfiguration.STREAM_STATE_STARTED) {
+ flushLog();
Thread.sleep(POLL_DURATION_MILLIS);
timeoutCount--;
if (timeoutCount == 0) {
@@ -322,15 +431,26 @@ public class TestDisconnectActivity extends TestAudioActivity {
setStatusText("Plug detected by Java.\nCounting down to Oboe failure: " + timeoutCount);
}
}
- if (!mTestFailed) {
- int error = stream.getLastErrorCallbackResult();
- if (error != StreamConfiguration.ERROR_DISCONNECTED) {
- log("onEerrorCallback error = " + error
- + ", expected " + StreamConfiguration.ERROR_DISCONNECTED);
- mTestFailed = true;
+
+ if (mSkipTest) {
+ setStatusText("Skipped");
+ } else {
+ if (mTestFailed) {
+ // Check whether the peripheral has a microphone.
+ // Sometimes the microphones does not appear on the first HEADSET_PLUG event.
+ if (isInput && (mPlugMicrophone == 0)) {
+ hasMicFailed = true;
+ }
+ } else {
+ int error = stream.getLastErrorCallbackResult();
+ if (error != StreamConfiguration.ERROR_DISCONNECTED) {
+ log("onErrorCallback error = " + error
+ + ", expected " + StreamConfiguration.ERROR_DISCONNECTED);
+ mTestFailed = true;
+ }
}
+ setStatusText(mTestFailed ? "Failed" : "Passed - detected");
}
- setStatusText(mTestFailed ? "Failed" : "Passed - detected");
}
updateFailSkipButton(false);
setInstructionsText("Wait...");
@@ -352,6 +472,9 @@ public class TestDisconnectActivity extends TestAudioActivity {
boolean passed = !mTestFailed;
String resultText = requestPlugin ? "plugIN" : "UNplug";
resultText += ", " + (passed ? TEXT_PASS : TEXT_FAIL);
+ if (hasMicFailed) {
+ resultText += ", Headset has no mic!";
+ }
log(resultText);
if (!passed) {
appendFailedSummary("------ #" + mAutomatedTestRunner.getTestCount() + "\n");
@@ -365,17 +488,27 @@ public class TestDisconnectActivity extends TestAudioActivity {
} else {
log(TEXT_SKIP);
}
+ flushLog();
// Give hardware time to settle between tests.
Thread.sleep(1000);
mAutomatedTestRunner.incrementTestCount();
}
private void testConfiguration(boolean isInput, int performanceMode,
- int sharingMode, int sampleRate) throws InterruptedException {
+ int sharingMode, int sampleRate,
+ int sampleRateConversionQuality) throws InterruptedException {
boolean requestPlugin = true; // plug IN
- testConfiguration(isInput, performanceMode, sharingMode, sampleRate, requestPlugin);
+ testConfiguration(isInput, performanceMode, sharingMode, sampleRate,
+ sampleRateConversionQuality, requestPlugin);
requestPlugin = false; // UNplug
- testConfiguration(isInput, performanceMode, sharingMode, sampleRate, requestPlugin);
+ testConfiguration(isInput, performanceMode, sharingMode, sampleRate,
+ sampleRateConversionQuality, requestPlugin);
+ }
+
+ private void testConfiguration(boolean isInput, int performanceMode,
+ int sharingMode, int sampleRate) throws InterruptedException {
+ testConfiguration(isInput, performanceMode, sharingMode, sampleRate,
+ StreamConfiguration.RATE_CONVERSION_QUALITY_NONE);
}
private void testConfiguration(boolean isInput, int performanceMode,
@@ -390,25 +523,45 @@ public class TestDisconnectActivity extends TestAudioActivity {
testConfiguration(true, performanceMode, sharingMode);
}
+ private void testConfiguration(int performanceMode,
+ int sharingMode, int sampleRate,
+ int sampleRateConversionQuality) throws InterruptedException {
+ testConfiguration(false, performanceMode, sharingMode, sampleRate, sampleRateConversionQuality);
+ testConfiguration(true, performanceMode, sharingMode, sampleRate, sampleRateConversionQuality);
+ }
+
@Override
public void runTest() {
+
+ runOnUiThread(() -> keepScreenOn(true));
+
mPlugCount = 0;
+
// Try several different configurations.
try {
- testConfiguration(false, StreamConfiguration.PERFORMANCE_MODE_LOW_LATENCY,
- StreamConfiguration.SHARING_MODE_EXCLUSIVE, 44100);
- testConfiguration(StreamConfiguration.PERFORMANCE_MODE_LOW_LATENCY,
- StreamConfiguration.SHARING_MODE_EXCLUSIVE);
- testConfiguration(StreamConfiguration.PERFORMANCE_MODE_LOW_LATENCY,
- StreamConfiguration.SHARING_MODE_SHARED);
testConfiguration(StreamConfiguration.PERFORMANCE_MODE_NONE,
StreamConfiguration.SHARING_MODE_SHARED);
+ if (NativeEngine.isMMapExclusiveSupported()){
+ testConfiguration(StreamConfiguration.PERFORMANCE_MODE_LOW_LATENCY,
+ StreamConfiguration.SHARING_MODE_EXCLUSIVE);
+ }
+ testConfiguration(StreamConfiguration.PERFORMANCE_MODE_LOW_LATENCY,
+ StreamConfiguration.SHARING_MODE_SHARED);
+ testConfiguration(StreamConfiguration.PERFORMANCE_MODE_LOW_LATENCY,
+ StreamConfiguration.SHARING_MODE_SHARED, 44100,
+ StreamConfiguration.RATE_CONVERSION_QUALITY_NONE);
+ testConfiguration(StreamConfiguration.PERFORMANCE_MODE_LOW_LATENCY,
+ StreamConfiguration.SHARING_MODE_SHARED, 44100,
+ StreamConfiguration.RATE_CONVERSION_QUALITY_MEDIUM);
} catch (InterruptedException e) {
- log(e.getMessage());
- showErrorToast(e.getMessage());
+ log("Test CANCELLED - INVALID!");
+ } catch (Exception e) {
+ log(e);
+ showErrorToast("Caught " + e);
} finally {
- setInstructionsText("Test completed.");
+ setInstructionsText("Test finished.");
updateFailSkipButton(false);
+ runOnUiThread(() -> keepScreenOn(false));
}
}
}