Merge "Refactor CTSVerifier Loopback tests to use the common, Oboe-based, measurement." into rvc-dev
diff --git a/apps/CtsVerifier/jni/audio_loopback/NativeAudioAnalyzer.cpp b/apps/CtsVerifier/jni/audio_loopback/NativeAudioAnalyzer.cpp
index d8d6946..8a1c63f 100644
--- a/apps/CtsVerifier/jni/audio_loopback/NativeAudioAnalyzer.cpp
+++ b/apps/CtsVerifier/jni/audio_loopback/NativeAudioAnalyzer.cpp
@@ -202,6 +202,10 @@
return mPulseLatencyAnalyzer.getMeasuredConfidence();
}
+int NativeAudioAnalyzer::getSampleRate() {
+ return mOutputSampleRate;
+}
+
aaudio_result_t NativeAudioAnalyzer::openAudio() {
AAudioStreamBuilder *builder = nullptr;
@@ -234,13 +238,13 @@
int32_t outputFramesPerBurst = AAudioStream_getFramesPerBurst(mOutputStream);
(void) AAudioStream_setBufferSizeInFrames(mOutputStream, outputFramesPerBurst * kDefaultOutputSizeBursts);
- int32_t outputSampleRate = AAudioStream_getSampleRate(mOutputStream);
+ mOutputSampleRate = AAudioStream_getSampleRate(mOutputStream);
mActualOutputChannelCount = AAudioStream_getChannelCount(mOutputStream);
// Create the INPUT stream -----------------------
AAudioStreamBuilder_setDirection(builder, AAUDIO_DIRECTION_INPUT);
AAudioStreamBuilder_setFormat(builder, AAUDIO_FORMAT_UNSPECIFIED);
- AAudioStreamBuilder_setSampleRate(builder, outputSampleRate); // must match
+ AAudioStreamBuilder_setSampleRate(builder, mOutputSampleRate); // must match
AAudioStreamBuilder_setChannelCount(builder, 1); // mono
AAudioStreamBuilder_setDataCallback(builder, nullptr, nullptr);
AAudioStreamBuilder_setErrorCallback(builder, nullptr, nullptr);
diff --git a/apps/CtsVerifier/jni/audio_loopback/NativeAudioAnalyzer.h b/apps/CtsVerifier/jni/audio_loopback/NativeAudioAnalyzer.h
index 0d9c64b..3367226 100644
--- a/apps/CtsVerifier/jni/audio_loopback/NativeAudioAnalyzer.h
+++ b/apps/CtsVerifier/jni/audio_loopback/NativeAudioAnalyzer.h
@@ -80,6 +80,11 @@
double getLatencyMillis();
/**
+ * @return the sample rate (in Hz) used for the measurement signal
+ */
+ int getSampleRate();
+
+ /**
* The confidence is based on a normalized correlation.
* It ranges from 0.0 to 1.0. Higher is better.
*
@@ -96,6 +101,7 @@
aaudio_format_t mActualInputFormat = AAUDIO_FORMAT_INVALID;
int16_t *mInputShortData = nullptr;
float *mInputFloatData = nullptr;
+ int32_t mOutputSampleRate = 0;
aaudio_result_t mInputError = AAUDIO_OK;
aaudio_result_t mOutputError = AAUDIO_OK;
diff --git a/apps/CtsVerifier/jni/audio_loopback/jni-bridge.cpp b/apps/CtsVerifier/jni/audio_loopback/jni-bridge.cpp
index a851cbe..58908bd 100644
--- a/apps/CtsVerifier/jni/audio_loopback/jni-bridge.cpp
+++ b/apps/CtsVerifier/jni/audio_loopback/jni-bridge.cpp
@@ -113,4 +113,13 @@
return 0.0;
}
+JNIEXPORT jint JNICALL Java_com_android_cts_verifier_audio_NativeAnalyzerThread_getSampleRate
+ (JNIEnv *env __unused, jobject obj __unused, jlong pAnalyzer) {
+ NativeAudioAnalyzer * analyzer = (NativeAudioAnalyzer *) pAnalyzer;
+ if (analyzer != nullptr) {
+ return analyzer->getSampleRate();
+ }
+ return 0;
+}
+
}
diff --git a/apps/CtsVerifier/res/layout/audio_loopback_device_layout.xml b/apps/CtsVerifier/res/layout/audio_loopback_device_layout.xml
new file mode 100644
index 0000000..4d0ba8d
--- /dev/null
+++ b/apps/CtsVerifier/res/layout/audio_loopback_device_layout.xml
@@ -0,0 +1,37 @@
+<?xml version="1.0" encoding="utf-8"?>
+<LinearLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:orientation="vertical">
+
+ <TextView
+ android:text="@string/audioLoopbackInputLbl"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:textSize="18sp"/>
+
+ <TextView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:paddingLeft="10dp"
+ android:paddingRight="10dp"
+ android:id="@+id/audioLoopbackInputLbl"
+ android:textSize="18sp"/>
+
+ <TextView
+ android:text="@string/audioLoopbackOutputLbl"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:textSize="18sp"/>
+
+ <TextView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:paddingLeft="10dp"
+ android:paddingRight="10dp"
+ android:id="@+id/audioLoopbackOutputLbl"
+ android:textSize="18sp"/>
+
+
+</LinearLayout>
\ No newline at end of file
diff --git a/apps/CtsVerifier/res/layout/audio_loopback_footer_layout.xml b/apps/CtsVerifier/res/layout/audio_loopback_footer_layout.xml
new file mode 100644
index 0000000..f59afeb
--- /dev/null
+++ b/apps/CtsVerifier/res/layout/audio_loopback_footer_layout.xml
@@ -0,0 +1,18 @@
+<?xml version="1.0" encoding="utf-8"?>
+<LinearLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:orientation="vertical">
+
+ <ProgressBar
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:id="@+id/audio_loopback_progress_bar" />
+
+ <TextView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/audio_loopback_results_text"
+ android:id="@+id/audio_loopback_results_text" />
+</LinearLayout>
diff --git a/apps/CtsVerifier/res/layout/audio_loopback_layout.xml b/apps/CtsVerifier/res/layout/audio_loopback_header_layout.xml
similarity index 96%
rename from apps/CtsVerifier/res/layout/audio_loopback_layout.xml
rename to apps/CtsVerifier/res/layout/audio_loopback_header_layout.xml
index 40732d0..a738826 100644
--- a/apps/CtsVerifier/res/layout/audio_loopback_layout.xml
+++ b/apps/CtsVerifier/res/layout/audio_loopback_header_layout.xml
@@ -1,3 +1,4 @@
+<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
diff --git a/apps/CtsVerifier/res/layout/audio_loopback_latency_activity.xml b/apps/CtsVerifier/res/layout/audio_loopback_latency_activity.xml
index a9ad8a1..c8c7a69 100644
--- a/apps/CtsVerifier/res/layout/audio_loopback_latency_activity.xml
+++ b/apps/CtsVerifier/res/layout/audio_loopback_latency_activity.xml
@@ -30,7 +30,7 @@
android:layout_height="wrap_content"
android:orientation="vertical">
- <include layout="@layout/audio_loopback_layout"/>
+ <include layout="@layout/audio_loopback_header_layout"/>
<LinearLayout
android:layout_width="wrap_content"
@@ -38,53 +38,15 @@
android:orientation="vertical"
android:id="@+id/audio_loopback_headset_port">
- <TextView
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:scrollbars="vertical"
- android:gravity="bottom"
- android:id="@+id/info_text"
- android:text="@string/audio_loopback_instructions" />
+ <include layout="@layout/audio_loopback_volume_layout" />
- <Button
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:id="@+id/audio_loopback_plug_ready_btn"
- android:text="@string/audio_loopback_plug_ready_btn"
- android:nextFocusForward="@+id/audio_loopback_level_seekbar"
- android:nextFocusUp="@+id/audio_general_headset_yes"
- android:nextFocusDown="@+id/audio_loopback_level_seekbar"
- android:nextFocusLeft="@+id/audio_general_headset_yes"
- android:nextFocusRight="@+id/audio_loopback_level_seekbar" />
+ <include layout="@layout/audio_loopback_device_layout" />
<LinearLayout
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="@+id/audio_loopback_layout">
-
- <TextView
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:text="@string/audio_loopback_instructions2"
- android:id="@+id/audio_loopback_instructions2" />
-
- <SeekBar
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:id="@+id/audio_loopback_level_seekbar"
- android:nextFocusForward="@+id/audio_loopback_test_btn"
- android:nextFocusUp="@+id/audio_loopback_plug_ready_btn"
- android:nextFocusDown="@+id/audio_loopback_test_btn"
- android:nextFocusLeft="@+id/audio_loopback_plug_ready_btn"
- android:nextFocusRight="@+id/audio_loopback_test_btn" />
-
- <TextView
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:text="@string/audio_loopback_level_text"
- android:id="@+id/audio_loopback_level_text" />
-
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
@@ -96,18 +58,10 @@
android:nextFocusLeft="@+id/audio_loopback_level_seekbar"
android:nextFocusRight="@+id/pass_button" />
- <ProgressBar
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:id="@+id/audio_loopback_progress_bar" />
-
- <TextView
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:text="@string/audio_loopback_results_text"
- android:id="@+id/audio_loopback_results_text" />
</LinearLayout>
+ <include layout="@layout/audio_loopback_footer_layout"/>
+
</LinearLayout>
<include layout="@layout/pass_fail_buttons" />
</LinearLayout>
diff --git a/apps/CtsVerifier/res/layout/audio_loopback_volume_layout.xml b/apps/CtsVerifier/res/layout/audio_loopback_volume_layout.xml
new file mode 100644
index 0000000..b85985e
--- /dev/null
+++ b/apps/CtsVerifier/res/layout/audio_loopback_volume_layout.xml
@@ -0,0 +1,31 @@
+<?xml version="1.0" encoding="utf-8"?>
+<LinearLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:orientation="vertical"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:id="@+id/audio_loopback_layout">
+
+ <TextView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/audio_loopback_instructions2"
+ android:id="@+id/audio_loopback_instructions2" />
+
+ <SeekBar
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:id="@+id/audio_loopback_level_seekbar"
+ android:nextFocusForward="@+id/audio_loopback_test_btn"
+ android:nextFocusUp="@+id/audio_loopback_plug_ready_btn"
+ android:nextFocusDown="@+id/audio_loopback_test_btn"
+ android:nextFocusLeft="@+id/audio_loopback_plug_ready_btn"
+ android:nextFocusRight="@+id/audio_loopback_test_btn" />
+
+ <TextView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/audio_loopback_level_text"
+ android:id="@+id/audio_loopback_level_text" />
+
+</LinearLayout>
diff --git a/apps/CtsVerifier/res/layout/pro_audio.xml b/apps/CtsVerifier/res/layout/pro_audio.xml
index b07fbb9..e61ba01 100644
--- a/apps/CtsVerifier/res/layout/pro_audio.xml
+++ b/apps/CtsVerifier/res/layout/pro_audio.xml
@@ -9,7 +9,7 @@
android:layout_width="match_parent"
android:layout_height="wrap_content">
- <include layout="@layout/audio_loopback_layout"/>
+ <include layout="@layout/audio_loopback_header_layout"/>
<LinearLayout android:orientation="horizontal"
android:layout_width="match_parent"
@@ -125,33 +125,9 @@
android:textSize="18sp"/>
</LinearLayout>
- <TextView
- android:text="@string/proAudioInputLbl"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:textSize="18sp"/>
+ <include layout="@layout/audio_loopback_device_layout" />
- <TextView
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:paddingLeft="10dp"
- android:paddingRight="10dp"
- android:id="@+id/proAudioInputLbl"
- android:textSize="18sp"/>
-
- <TextView
- android:text="@string/proAudioOutputLbl"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:textSize="18sp"/>
-
- <TextView
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:paddingLeft="10dp"
- android:paddingRight="10dp"
- android:id="@+id/proAudioOutputLbl"
- android:textSize="18sp"/>
+ <include layout="@layout/audio_loopback_volume_layout" />
<Button
android:text="@string/audio_proaudio_roundtrip"
@@ -159,41 +135,7 @@
android:layout_height="wrap_content"
android:id="@+id/proAudio_runRoundtripBtn"/>
- <LinearLayout android:orientation="horizontal"
- android:layout_width="match_parent"
- android:layout_height="wrap_content">
- <TextView
- android:text="@string/proAudioRoundTripLbl"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:textSize="18sp"/>
-
- <TextView
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:paddingLeft="10dp"
- android:paddingRight="10dp"
- android:id="@+id/proAudioRoundTripLbl"
- android:textSize="18sp"/>
- </LinearLayout>
-
- <LinearLayout android:orientation="horizontal"
- android:layout_width="match_parent"
- android:layout_height="wrap_content">
- <TextView
- android:text="@string/proAudioConfidenceLbl"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:textSize="18sp"/>
-
- <TextView
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:paddingLeft="10dp"
- android:paddingRight="10dp"
- android:id="@+id/proAudioConfidenceLbl"
- android:textSize="18sp"/>
- </LinearLayout>
+ <include layout="@layout/audio_loopback_footer_layout"/>
<include layout="@layout/pass_fail_buttons"/>
</LinearLayout>
diff --git a/apps/CtsVerifier/res/values/strings.xml b/apps/CtsVerifier/res/values/strings.xml
index 54e89b0c..b1e0388 100755
--- a/apps/CtsVerifier/res/values/strings.xml
+++ b/apps/CtsVerifier/res/values/strings.xml
@@ -4830,10 +4830,8 @@
<string name="proAudioHasProAudiolbl">Has Pro Audio</string>
<string name="proAudioHasLLAlbl">Has Low-Latency Audio</string>
- <string name="proAudioInputLbl">Audio Input:</string>
- <string name="proAudioOutputLbl">Audio Output:</string>
- <string name="proAudioRoundTripLbl">Round Trip Latency:</string>
- <string name="proAudioConfidenceLbl">Confidence:</string>
+ <string name="audioLoopbackInputLbl">Audio Input:</string>
+ <string name="audioLoopbackOutputLbl">Audio Output:</string>
<string name="proAudioMidiHasMIDILbl">Has MIDI Support</string>
<string name="proAudioMIDIInputLbl">MIDI Input:</string>
@@ -4843,8 +4841,6 @@
<string name="proAudioHDMISupportLbl">HDMI Support:</string>
<string name="proAudioHasHDMICheckBox">Has HDMI Support</string>
- <string name="audio_proaudio_loopbackbtn">Start Loopback</string>
- <string name="audio_proaudio_loopbackInfoBtn">Loopback Instructions</string>
<string name="audio_proaudio_roundtrip">Round-Trip Test</string>
<string name="audio_proaudio_NA">N/A</string>
<string name="audio_proaudio_pending">pending...</string>
@@ -5341,11 +5337,12 @@
(not a headset) and that peripheral\'s audio outputs are connected to the peripherals\'s
audio inputs. Alternatively, for devices with an analog audio jack or USB-c Digital
to Analog dongle, a <a href="https://source.android.com/devices/audio/latency/loopback">Loopback Plug</a>
- can be used. Also, any if there is an input level
+ can be used. Also, if there is an input level
control on the peripheral, it must be set to a non-zero value. When the test has
verified support for a valid audio peripheral, press the \"Round-Trip Test\" button
- to complete the test. Note that it may be necessary to run the latency test more than
- once to get a sufficient confidence value.
+ to complete the test.
+ The latency measurement is generally accurate even when the volume is low. But you may
+ need to increase the volume to bring the confidence number above the threshold.
</string>
<string name="proaudio_hdmi_infotitle">HDMI Support</string>
<string name="proaudio_hdmi_message">Please connect an HDMI peripheral to validate
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/audio/AudioLoopbackBaseActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/audio/AudioLoopbackBaseActivity.java
index 671b545..7f96464 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/audio/AudioLoopbackBaseActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/audio/AudioLoopbackBaseActivity.java
@@ -18,18 +18,17 @@
import android.app.AlertDialog;
-import com.android.compatibility.common.util.ReportLog;
-import com.android.compatibility.common.util.ResultType;
-import com.android.compatibility.common.util.ResultUnit;
-import com.android.cts.verifier.R;
-import com.android.cts.verifier.PassFailButtons;
-
import android.content.Context;
+import android.media.AudioDeviceCallback;
+import android.media.AudioDeviceInfo;
import android.media.AudioManager;
import android.media.AudioTrack;
+import android.media.MediaRecorder;
import android.os.Bundle;
+import android.os.Handler;
+import android.os.Message;
import android.util.Log;
@@ -38,6 +37,16 @@
import android.view.ViewGroup;
import android.widget.Button;
+import android.widget.TextView;
+import android.widget.ProgressBar;
+import android.widget.SeekBar;
+
+import com.android.compatibility.common.util.ReportLog;
+import com.android.compatibility.common.util.ResultType;
+import com.android.compatibility.common.util.ResultUnit;
+
+import com.android.cts.verifier.PassFailButtons;
+import com.android.cts.verifier.R;
/**
* Base class for testing activitiees that require audio loopback hardware..
@@ -45,13 +54,45 @@
public class AudioLoopbackBaseActivity extends PassFailButtons.Activity {
private static final String TAG = "AudioLoopbackActivity";
+ protected AudioManager mAudioManager;
+
+ // UI
OnBtnClickListener mBtnClickListener = new OnBtnClickListener();
Button mLoopbackPortYesBtn;
Button mLoopbackPortNoBtn;
+ TextView mInputDeviceTxt;
+ TextView mOutputDeviceTxt;
+
+ TextView mAudioLevelText;
+ SeekBar mAudioLevelSeekbar;
+
+ TextView mResultText;
+ ProgressBar mProgressBar;
+ int mMaxLevel;
+
+ // Peripheral(s)
+ boolean mIsPeripheralAttached; // CDD ProAudio section C-1-3
+ AudioDeviceInfo mOutputDevInfo;
+ AudioDeviceInfo mInputDevInfo;
+
+ // Loopback Logic
+ NativeAnalyzerThread mNativeAnalyzerThread = null;
+
+ protected double mLatencyMillis = 0.0;
+ protected double mConfidence = 0.0;
+
+ protected static final double CONFIDENCE_THRESHOLD = 0.6;
+ protected static final double PROAUDIO_LATENCY_MS_LIMIT = 20.0;
+
+ // The audio stream callback threads should stop and close
+ // in less than a few hundred msec. This is a generous timeout value.
+ private static final int STOP_TEST_TIMEOUT_MSEC = 2 * 1000;
+
//
// Common UI Handling
+ //
void enableLayout(int layoutId, boolean enable) {
ViewGroup group = (ViewGroup)findViewById(layoutId);
for (int i = 0; i < group.getChildCount(); i++) {
@@ -68,12 +109,120 @@
mLoopbackPortNoBtn = (Button)findViewById(R.id.loopback_tests_no_btn);
mLoopbackPortNoBtn.setOnClickListener(mBtnClickListener);
+ // Connected Device
+ mInputDeviceTxt = ((TextView)findViewById(R.id.audioLoopbackInputLbl));
+ mOutputDeviceTxt = ((TextView)findViewById(R.id.audioLoopbackOutputLbl));
+
// Loopback Info
findViewById(R.id.loopback_tests_info_btn).setOnClickListener(mBtnClickListener);
+ mAudioLevelText = (TextView)findViewById(R.id.audio_loopback_level_text);
+ mAudioLevelSeekbar = (SeekBar)findViewById(R.id.audio_loopback_level_seekbar);
+ mMaxLevel = mAudioManager.getStreamMaxVolume(AudioManager.STREAM_MUSIC);
+ mAudioLevelSeekbar.setMax(mMaxLevel);
+ mAudioManager.setStreamVolume(AudioManager.STREAM_MUSIC, (int)(0.7 * mMaxLevel), 0);
+ refreshLevel();
+
+ mAudioLevelSeekbar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
+ @Override
+ public void onStopTrackingTouch(SeekBar seekBar) {}
+
+ @Override
+ public void onStartTrackingTouch(SeekBar seekBar) {}
+
+ @Override
+ public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
+ mAudioManager.setStreamVolume(AudioManager.STREAM_MUSIC,
+ progress, 0);
+ refreshLevel();
+ Log.i(TAG,"Changed stream volume to: " + progress);
+ }
+ });
+
+ mResultText = (TextView)findViewById(R.id.audio_loopback_results_text);
+ mProgressBar = (ProgressBar)findViewById(R.id.audio_loopback_progress_bar);
+ showWait(false);
+
enableTestUI(false);
}
+ //
+ // Peripheral Connection Logic
+ //
+ protected void scanPeripheralList(AudioDeviceInfo[] devices) {
+ // CDD Section C-1-3: USB port, host-mode support
+
+ // Can't just use the first record because then we will only get
+ // Source OR sink, not both even on devices that are both.
+ mOutputDevInfo = null;
+ mInputDevInfo = null;
+
+ // Any valid peripherals
+ // Do we leave in the Headset test to support a USB-Dongle?
+ for (AudioDeviceInfo devInfo : devices) {
+ if (devInfo.getType() == AudioDeviceInfo.TYPE_USB_DEVICE || // USB Peripheral
+ devInfo.getType() == AudioDeviceInfo.TYPE_USB_HEADSET || // USB dongle+LBPlug
+ devInfo.getType() == AudioDeviceInfo.TYPE_WIRED_HEADSET || // Loopback Plug?
+ devInfo.getType() == AudioDeviceInfo.TYPE_AUX_LINE) { // Aux-cable loopback?
+ if (devInfo.isSink()) {
+ mOutputDevInfo = devInfo;
+ }
+ if (devInfo.isSource()) {
+ mInputDevInfo = devInfo;
+ }
+ } else {
+ handleDeviceConnection(devInfo);
+ }
+ }
+
+ mIsPeripheralAttached = mOutputDevInfo != null || mInputDevInfo != null;
+ showConnectedAudioPeripheral();
+
+ }
+
+ protected void handleDeviceConnection(AudioDeviceInfo deviceInfo) {
+ // NOP
+ }
+
+ private class ConnectListener extends AudioDeviceCallback {
+ /*package*/ ConnectListener() {}
+
+ //
+ // AudioDevicesManager.OnDeviceConnectionListener
+ //
+ @Override
+ public void onAudioDevicesAdded(AudioDeviceInfo[] addedDevices) {
+ scanPeripheralList(mAudioManager.getDevices(AudioManager.GET_DEVICES_ALL));
+ }
+
+ @Override
+ public void onAudioDevicesRemoved(AudioDeviceInfo[] removedDevices) {
+ scanPeripheralList(mAudioManager.getDevices(AudioManager.GET_DEVICES_ALL));
+ }
+ }
+
+ protected void showConnectedAudioPeripheral() {
+ mInputDeviceTxt.setText(
+ mInputDevInfo != null ? mInputDevInfo.getProductName().toString()
+ : "");
+ mOutputDeviceTxt.setText(
+ mOutputDevInfo != null ? mOutputDevInfo.getProductName().toString()
+ : "");
+ }
+
+ /**
+ * refresh Audio Level seekbar and text
+ */
+ private void refreshLevel() {
+ int currentLevel = mAudioManager.getStreamVolume(AudioManager.STREAM_MUSIC);
+ mAudioLevelSeekbar.setProgress(currentLevel);
+
+ String levelText = String.format("%s: %d/%d",
+ getResources().getString(R.string.audio_loopback_level_text),
+ currentLevel, mMaxLevel);
+ mAudioLevelText.setText(levelText);
+ }
+
private void showLoopbackInfoDialog() {
new AlertDialog.Builder(this)
.setTitle(R.string.loopback_dlg_caption)
@@ -82,6 +231,18 @@
.show();
}
+ //
+ // show active progress bar
+ //
+ protected void showWait(boolean show) {
+ if (show) {
+ mProgressBar.setVisibility(View.VISIBLE) ;
+ } else {
+ mProgressBar.setVisibility(View.INVISIBLE) ;
+ }
+ }
+
+
private class OnBtnClickListener implements OnClickListener {
@Override
public void onClick(View v) {
@@ -108,10 +269,135 @@
}
}
+ //
+ // Common loging
+ //
+ protected void recordTestResults() {
+ ReportLog reportLog = getReportLog();
+ reportLog.addValue(
+ "Estimated Latency",
+ mLatencyMillis,
+ ResultType.LOWER_BETTER,
+ ResultUnit.MS);
+
+ reportLog.addValue(
+ "Confidence",
+ mConfidence,
+ ResultType.HIGHER_BETTER,
+ ResultUnit.NONE);
+
+ reportLog.addValue(
+ "Sample Rate",
+ mNativeAnalyzerThread.getSampleRate(),
+ ResultType.NEUTRAL,
+ ResultUnit.NONE);
+
+ reportLog.addValue(
+ "Is Peripheral Attached",
+ mIsPeripheralAttached,
+ ResultType.NEUTRAL,
+ ResultUnit.NONE);
+
+ if (mIsPeripheralAttached) {
+ reportLog.addValue(
+ "Input Device",
+ mInputDevInfo != null ? mInputDevInfo.getProductName().toString() : "None",
+ ResultType.NEUTRAL,
+ ResultUnit.NONE);
+
+ reportLog.addValue(
+ "Ouput Device",
+ mOutputDevInfo != null ? mOutputDevInfo.getProductName().toString() : "None",
+ ResultType.NEUTRAL,
+ ResultUnit.NONE);
+ }
+ }
+
+ //
+ // test logic
+ //
+ protected void startAudioTest(Handler messageHandler) {
+ getPassButton().setEnabled(false);
+ mLatencyMillis = 0.0;
+ mConfidence = 0.0;
+
+ mNativeAnalyzerThread = new NativeAnalyzerThread();
+ if (mNativeAnalyzerThread != null) {
+ mNativeAnalyzerThread.setMessageHandler(messageHandler);
+ // This value matches AAUDIO_INPUT_PRESET_VOICE_RECOGNITION
+ mNativeAnalyzerThread.setInputPreset(MediaRecorder.AudioSource.VOICE_RECOGNITION);
+ mNativeAnalyzerThread.startTest();
+
+ try {
+ Thread.sleep(200);
+ } catch (InterruptedException e) {
+ e.printStackTrace();
+ }
+ }
+ }
+
+ protected void handleTestCompletion() {
+ // Make sure the test thread is finished. It should already be done.
+ if (mNativeAnalyzerThread != null) {
+ try {
+ mNativeAnalyzerThread.stopTest(STOP_TEST_TIMEOUT_MSEC);
+ } catch (InterruptedException e) {
+ e.printStackTrace();
+ }
+ }
+ }
+
+ /**
+ * handler for messages from audio thread
+ */
+ protected Handler mMessageHandler = new Handler() {
+ public void handleMessage(Message msg) {
+ super.handleMessage(msg);
+ switch(msg.what) {
+ case NativeAnalyzerThread.NATIVE_AUDIO_THREAD_MESSAGE_REC_STARTED:
+ Log.v(TAG,"got message native rec started!!");
+ showWait(true);
+ mResultText.setText("Test Running...");
+ break;
+ case NativeAnalyzerThread.NATIVE_AUDIO_THREAD_MESSAGE_OPEN_ERROR:
+ Log.v(TAG,"got message native rec can't start!!");
+ mResultText.setText("Test Error opening streams.");
+ handleTestCompletion();
+ break;
+ case NativeAnalyzerThread.NATIVE_AUDIO_THREAD_MESSAGE_REC_ERROR:
+ Log.v(TAG,"got message native rec can't start!!");
+ mResultText.setText("Test Error while recording.");
+ handleTestCompletion();
+ break;
+ case NativeAnalyzerThread.NATIVE_AUDIO_THREAD_MESSAGE_REC_COMPLETE_ERRORS:
+ mResultText.setText("Test FAILED due to errors.");
+ handleTestCompletion();
+ break;
+ case NativeAnalyzerThread.NATIVE_AUDIO_THREAD_MESSAGE_REC_COMPLETE:
+ if (mNativeAnalyzerThread != null) {
+ mLatencyMillis = mNativeAnalyzerThread.getLatencyMillis();
+ mConfidence = mNativeAnalyzerThread.getConfidence();
+ }
+ mResultText.setText(String.format(
+ "Test Finished\nLatency:%.2f ms\nConfidence: %.2f",
+ mLatencyMillis,
+ mConfidence));
+ handleTestCompletion();
+ break;
+ default:
+ break;
+ }
+ }
+ };
+
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
+ mAudioManager = (AudioManager)getSystemService(AUDIO_SERVICE);
+
+ mAudioManager.registerAudioDeviceCallback(new ConnectListener(), new Handler());
+
connectLoopbackUI();
}
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/audio/AudioLoopbackLatencyActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/audio/AudioLoopbackLatencyActivity.java
index acb2272..ded5c1e 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/audio/AudioLoopbackLatencyActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/audio/AudioLoopbackLatencyActivity.java
@@ -16,21 +16,9 @@
package com.android.cts.verifier.audio;
-import com.android.cts.verifier.R;
-import com.android.compatibility.common.util.ReportLog;
-import com.android.compatibility.common.util.ResultType;
-import com.android.compatibility.common.util.ResultUnit;
import android.content.Context;
-import android.media.AudioDeviceCallback;
-import android.media.AudioDeviceInfo;
-import android.media.AudioManager;
-import android.media.AudioTrack;
-import android.media.MediaRecorder;
-
import android.os.Bundle;
-import android.os.Handler;
-import android.os.Message;
import android.util.Log;
@@ -39,8 +27,12 @@
import android.widget.Button;
import android.widget.TextView;
-import android.widget.SeekBar;
-import android.widget.ProgressBar;
+
+import com.android.compatibility.common.util.ReportLog;
+import com.android.compatibility.common.util.ResultType;
+import com.android.compatibility.common.util.ResultUnit;
+
+import com.android.cts.verifier.R;
/**
* Tests Audio Device roundtrip latency by using a loopback plug.
@@ -48,39 +40,18 @@
public class AudioLoopbackLatencyActivity extends AudioLoopbackBaseActivity {
private static final String TAG = "AudioLoopbackLatencyActivity";
- public static final int BYTES_PER_FRAME = 2;
+// public static final int BYTES_PER_FRAME = 2;
- NativeAnalyzerThread mNativeAnalyzerThread = null;
-
- private int mSamplingRate = 44100;
private int mMinBufferSizeInFrames = 0;
- private static final double CONFIDENCE_THRESHOLD = 0.6;
OnBtnClickListener mBtnClickListener = new OnBtnClickListener();
- Context mContext;
-
- TextView mAudioLevelText;
- SeekBar mAudioLevelSeekbar;
Button mTestButton;
- TextView mResultText;
- ProgressBar mProgressBar;
-
- private double mLatencyMillis = 0.0;
- private double mConfidence = 0.0;
-
- int mMaxLevel;
private class OnBtnClickListener implements OnClickListener {
@Override
public void onClick(View v) {
switch (v.getId()) {
- case R.id.audio_loopback_plug_ready_btn:
- Log.i(TAG, "audio loopback plug ready");
- //enable all the other views.
- enableLayout(R.id.audio_loopback_layout, true);
- break;
-
case R.id.audio_loopback_test_btn:
Log.i(TAG, "audio loopback test");
startAudioTest();
@@ -95,196 +66,52 @@
setContentView(R.layout.audio_loopback_latency_activity);
super.onCreate(savedInstanceState);
- mContext = this;
-
- mAudioLevelText = (TextView)findViewById(R.id.audio_loopback_level_text);
- mAudioLevelSeekbar = (SeekBar)findViewById(R.id.audio_loopback_level_seekbar);
- findViewById(R.id.audio_loopback_plug_ready_btn).setOnClickListener(mBtnClickListener);
mTestButton =(Button)findViewById(R.id.audio_loopback_test_btn);
mTestButton.setOnClickListener(mBtnClickListener);
- mResultText = (TextView)findViewById(R.id.audio_loopback_results_text);
- mProgressBar = (ProgressBar)findViewById(R.id.audio_loopback_progress_bar);
- showWait(false);
-
- enableLayout(R.id.audio_loopback_layout, false); //disabled all content
- AudioManager am = (AudioManager) getSystemService(Context.AUDIO_SERVICE);
- mMaxLevel = am.getStreamMaxVolume(AudioManager.STREAM_MUSIC);
- mAudioLevelSeekbar.setMax(mMaxLevel);
- am.setStreamVolume(AudioManager.STREAM_MUSIC, (int)(0.7 * mMaxLevel), 0);
- refreshLevel();
-
- mAudioLevelSeekbar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
- @Override
- public void onStopTrackingTouch(SeekBar seekBar) {
- }
-
- @Override
- public void onStartTrackingTouch(SeekBar seekBar) {
- }
-
- @Override
- public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
-
- AudioManager am = (AudioManager) getSystemService(Context.AUDIO_SERVICE);
- am.setStreamVolume(AudioManager.STREAM_MUSIC,
- progress, 0);
- refreshLevel();
- Log.i(TAG,"Changed stream volume to: " + progress);
- }
- });
setPassFailButtonClickListeners();
getPassButton().setEnabled(false);
setInfoResources(R.string.audio_loopback_latency_test, R.string.audio_loopback_info, -1);
}
- /**
- * refresh Audio Level seekbar and text
- */
- private void refreshLevel() {
- AudioManager am = (AudioManager) getSystemService(Context.AUDIO_SERVICE);
-
- int currentLevel = am.getStreamVolume(AudioManager.STREAM_MUSIC);
- mAudioLevelSeekbar.setProgress(currentLevel);
-
- String levelText = String.format("%s: %d/%d",
- getResources().getString(R.string.audio_loopback_level_text),
- currentLevel, mMaxLevel);
- mAudioLevelText.setText(levelText);
- }
-
- /**
- * show active progress bar
- */
- private void showWait(boolean show) {
- if (show) {
- mProgressBar.setVisibility(View.VISIBLE) ;
- } else {
- mProgressBar.setVisibility(View.INVISIBLE) ;
- }
- }
-
- /**
- * Start the loopback audio test
- */
- private void startAudioTest() {
- getPassButton().setEnabled(false);
+ protected void startAudioTest() {
mTestButton.setEnabled(false);
- mLatencyMillis = 0.0;
- mConfidence = 0.0;
-
- mNativeAnalyzerThread = new NativeAnalyzerThread();
- if (mNativeAnalyzerThread != null) {
- mNativeAnalyzerThread.setMessageHandler(mMessageHandler);
- // This value matches AAUDIO_INPUT_PRESET_VOICE_RECOGNITION
- mNativeAnalyzerThread.setInputPreset(MediaRecorder.AudioSource.VOICE_RECOGNITION);
- mNativeAnalyzerThread.startTest();
-
- try {
- Thread.sleep(200);
- } catch (InterruptedException e) {
- e.printStackTrace();
- }
- }
+ super.startAudioTest(mMessageHandler);
}
- private void handleTestCompletion() {
- recordTestResults();
+ protected void handleTestCompletion() {
+ super.handleTestCompletion();
+
boolean resultValid = mConfidence >= CONFIDENCE_THRESHOLD
&& mLatencyMillis > 1.0;
getPassButton().setEnabled(resultValid);
- // Make sure the test thread is finished. It should already be done.
- if (mNativeAnalyzerThread != null) {
- try {
- mNativeAnalyzerThread.stopTest(2 * 1000);
- } catch (InterruptedException e) {
- e.printStackTrace();
- }
- }
+ recordTestResults();
+
showWait(false);
mTestButton.setEnabled(true);
}
/**
- * handler for messages from audio thread
- */
- private Handler mMessageHandler = new Handler() {
- public void handleMessage(Message msg) {
- super.handleMessage(msg);
- switch(msg.what) {
- case NativeAnalyzerThread.NATIVE_AUDIO_THREAD_MESSAGE_REC_STARTED:
- Log.v(TAG,"got message native rec started!!");
- showWait(true);
- mResultText.setText("Test Running...");
- break;
- case NativeAnalyzerThread.NATIVE_AUDIO_THREAD_MESSAGE_OPEN_ERROR:
- Log.v(TAG,"got message native rec can't start!!");
- mResultText.setText("Test Error opening streams.");
- handleTestCompletion();
- break;
- case NativeAnalyzerThread.NATIVE_AUDIO_THREAD_MESSAGE_REC_ERROR:
- Log.v(TAG,"got message native rec can't start!!");
- mResultText.setText("Test Error while recording.");
- handleTestCompletion();
- break;
- case NativeAnalyzerThread.NATIVE_AUDIO_THREAD_MESSAGE_REC_COMPLETE_ERRORS:
- mResultText.setText("Test FAILED due to errors.");
- handleTestCompletion();
- break;
- case NativeAnalyzerThread.NATIVE_AUDIO_THREAD_MESSAGE_REC_COMPLETE:
- if (mNativeAnalyzerThread != null) {
- mLatencyMillis = mNativeAnalyzerThread.getLatencyMillis();
- mConfidence = mNativeAnalyzerThread.getConfidence();
- }
- mResultText.setText(String.format(
- "Test Finished\nLatency:%.2f ms\nConfidence: %.2f",
- mLatencyMillis,
- mConfidence));
- handleTestCompletion();
- break;
- default:
- break;
- }
- }
- };
-
- /**
* Store test results in log
*/
- private void recordTestResults() {
+ protected void recordTestResults() {
+ super.recordTestResults();
- getReportLog().addValue(
- "Estimated Latency",
- mLatencyMillis,
- ResultType.LOWER_BETTER,
- ResultUnit.MS);
-
- getReportLog().addValue(
- "Confidence",
- mConfidence,
- ResultType.HIGHER_BETTER,
- ResultUnit.NONE);
-
+ ReportLog reportLog = getReportLog();
int audioLevel = mAudioLevelSeekbar.getProgress();
- getReportLog().addValue(
+ reportLog.addValue(
"Audio Level",
audioLevel,
ResultType.NEUTRAL,
ResultUnit.NONE);
- getReportLog().addValue(
+ reportLog.addValue(
"Frames Buffer Size",
mMinBufferSizeInFrames,
ResultType.NEUTRAL,
ResultUnit.NONE);
- getReportLog().addValue(
- "Sampling Rate",
- mSamplingRate,
- ResultType.NEUTRAL,
- ResultUnit.NONE);
-
Log.v(TAG,"Results Recorded");
}
}
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/audio/NativeAnalyzerThread.java b/apps/CtsVerifier/src/com/android/cts/verifier/audio/NativeAnalyzerThread.java
index 42f22aa..2f74074 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/audio/NativeAnalyzerThread.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/audio/NativeAnalyzerThread.java
@@ -38,6 +38,8 @@
private volatile boolean mEnabled = false;
private volatile double mLatencyMillis = 0.0;
private volatile double mConfidence = 0.0;
+ private volatile int mSampleRate = 0;
+
private int mInputPreset = 0;
static final int NATIVE_AUDIO_THREAD_MESSAGE_REC_STARTED = 892;
@@ -74,6 +76,7 @@
private native int analyze(long audio_context);
private native double getLatencyMillis(long audio_context);
private native double getConfidence(long audio_context);
+ private native int getSampleRate(long audio_context);
public double getLatencyMillis() {
return mLatencyMillis;
@@ -83,6 +86,8 @@
return mConfidence;
}
+ public int getSampleRate() { return mSampleRate; }
+
public synchronized void startTest() {
if (mThread == null) {
mEnabled = true;
@@ -111,6 +116,8 @@
private Runnable mBackGroundTask = () -> {
mLatencyMillis = 0.0;
mConfidence = 0.0;
+ mSampleRate = 0;
+
boolean analysisComplete = false;
log(" Started capture test");
@@ -155,6 +162,7 @@
}
mLatencyMillis = getLatencyMillis(audioContext);
mConfidence = getConfidence(audioContext);
+ mSampleRate = getSampleRate(audioContext);
break;
} else {
try {
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/audio/ProAudioActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/audio/ProAudioActivity.java
index c952e3b..c1714cc 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/audio/ProAudioActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/audio/ProAudioActivity.java
@@ -17,23 +17,26 @@
package com.android.cts.verifier.audio;
import android.app.AlertDialog;
-import android.content.ComponentName;
import android.content.DialogInterface;
-import android.content.Intent;
import android.content.pm.PackageManager;
-import android.media.AudioDeviceCallback;
import android.media.AudioDeviceInfo;
import android.media.AudioFormat;
-import android.media.AudioManager;
+
import android.os.Bundle;
import android.os.Handler;
+
import android.util.Log;
+
import android.view.View;
+
+import android.widget.Button;
import android.widget.CheckBox;
import android.widget.TextView;
-import android.widget.Toast;
-import com.android.cts.verifier.PassFailButtons;
+import com.android.compatibility.common.util.ReportLog;
+import com.android.compatibility.common.util.ResultType;
+import com.android.compatibility.common.util.ResultUnit;
+
import com.android.cts.verifier.R; // needed to access resource in CTSVerifier project namespace.
public class ProAudioActivity
@@ -50,29 +53,15 @@
private boolean mClaimsUSBPeripheralMode; // CDD ProAudio section C-1-3
private boolean mClaimsHDMI; // CDD ProAudio section C-1-3
- // Values
- private static final double LATENCY_MS_LIMIT = 20.0; // CDD ProAudio section C-1-2
- private double mRoundTripLatency;
- private static final double CONFIDENCE_LIMIT = 0.75; // TBD
- private double mRoundTripConfidence;
-
- // Peripheral(s)
- AudioManager mAudioManager;
- private boolean mIsPeripheralAttached; // CDD ProAudio section C-1-3
- private AudioDeviceInfo mOutputDevInfo;
- private AudioDeviceInfo mInputDevInfo;
-
- private AudioDeviceInfo mHDMIDeviceInfo;
+ AudioDeviceInfo mHDMIDeviceInfo;
// Widgets
- TextView mInputDeviceTxt;
- TextView mOutputDeviceTxt;
- TextView mRoundTripLatencyTxt;
- TextView mRoundTripConfidenceTxt;
TextView mHDMISupportLbl;
CheckBox mClaimsHDMICheckBox;
+ Button mRoundTripTestButton;
+
// Borrowed from PassFailButtons.java
private static final int INFO_DIALOG_ID = 1337;
private static final String INFO_DIALOG_TITLE_ID = "infoDialogTitleId";
@@ -104,15 +93,6 @@
return getPackageManager().hasSystemFeature(PackageManager.FEATURE_USB_ACCESSORY);
}
- private void showConnectedAudioPeripheral() {
- mInputDeviceTxt.setText(
- mInputDevInfo != null ? mInputDevInfo.getProductName().toString()
- : "");
- mOutputDeviceTxt.setText(
- mOutputDevInfo != null ? mOutputDevInfo.getProductName().toString()
- : "");
- }
-
// HDMI Stuff
private boolean isHDMIValid() {
if (mHDMIDeviceInfo == null) {
@@ -164,107 +144,37 @@
return true;
}
+ protected void handleDeviceConnection(AudioDeviceInfo devInfo) {
+ if (devInfo.isSink() && devInfo.getType() == AudioDeviceInfo.TYPE_HDMI) {
+ mHDMIDeviceInfo = devInfo;
+ }
+
+ if (mHDMIDeviceInfo != null) {
+ mClaimsHDMICheckBox.setChecked(true);
+ mHDMISupportLbl.setText(getResources().getString(
+ isHDMIValid() ? R.string.pass_button_text : R.string.fail_button_text));
+ }
+ mHDMISupportLbl.setText(getResources().getString(R.string.audio_proaudio_NA));
+
+ calculatePass();
+ }
+
private void calculatePass() {
boolean hasPassed = !mClaimsProAudio ||
(mClaimsLowLatencyAudio && mClaimsMIDI &&
mClaimsUSBHostMode && mClaimsUSBPeripheralMode &&
(!mClaimsHDMI || isHDMIValid()) &&
mOutputDevInfo != null && mInputDevInfo != null &&
- mRoundTripLatency != 0.0 && mRoundTripLatency <= LATENCY_MS_LIMIT &&
- mRoundTripConfidence >= CONFIDENCE_LIMIT);
+ mConfidence >= CONFIDENCE_THRESHOLD && mLatencyMillis <= PROAUDIO_LATENCY_MS_LIMIT);
getPassButton().setEnabled(hasPassed);
}
- //
- // Loopback App Stuff
- //
- private final static String LOOPBACK_PACKAGE_NAME = "org.drrickorang.loopback";
-
- // Test Intents
- // From Loopback App LoobackActivity.java
- private static final String INTENT_TEST_TYPE = "TestType";
-
- // from Loopback App Constant.java
- public static final int LOOPBACK_PLUG_AUDIO_THREAD_TEST_TYPE_LATENCY = 222;
-
- public boolean isLoopbackAppInstalled() {
- try {
- getPackageManager().getPackageInfo(
- LOOPBACK_PACKAGE_NAME, PackageManager.GET_ACTIVITIES);
- return true;
- } catch (PackageManager.NameNotFoundException e) {
- // This indicates that the specified app (Loopback in this case) is NOT installed
- // fall through...
- }
- return false;
- }
-
- // arbitrary request code
- private static final int LATENCY_RESULTS_REQUEST_CODE = 1;
- private static final String KEY_CTSINVOCATION = "CTS-Test";
- private static final String KEY_ROUND_TRIP_TIME = "RoundTripTime";
- private static final String KEY_ROUND_TRIP_CONFIDENCE = "Confidence";
-
- // We may need to iterate and average round-trip measurements
- // So add this plumbing though NOT USED.
- private static final String KEY_NUMITERATIONS = "NumIterations";
- private static final int NUM_ROUNDTRIPITERATIONS = 3;
-
- private void runRoundTripTest() {
- if (!isLoopbackAppInstalled()) {
- Toast.makeText(this, "Loopback App not installed", Toast.LENGTH_SHORT).show();
- return;
- }
-
- if (!mIsPeripheralAttached) {
- Toast.makeText(this, "Please connect a USB audio peripheral with loopback cables" +
- " before running the latency test.",
- Toast.LENGTH_SHORT).show();
- return;
- }
-
- mRoundTripLatency = 0.0;
- mRoundTripConfidence = 0.0;
- Intent intent = new Intent(Intent.CATEGORY_LAUNCHER);
- intent.setComponent(
- new ComponentName(LOOPBACK_PACKAGE_NAME,LOOPBACK_PACKAGE_NAME + ".LoopbackActivity"));
-
- intent.putExtra(KEY_CTSINVOCATION, "CTS-Verifier Invocation");
- intent.putExtra(INTENT_TEST_TYPE, LOOPBACK_PLUG_AUDIO_THREAD_TEST_TYPE_LATENCY);
- intent.putExtra(KEY_NUMITERATIONS, NUM_ROUNDTRIPITERATIONS);
-
- startActivityForResult(intent, LATENCY_RESULTS_REQUEST_CODE);
- }
-
- @Override
- protected void onActivityResult(int requestCode, int resultCode, Intent data) {
- // Check which request we're responding to
- if (resultCode == RESULT_OK) {
- Toast.makeText(this, "Round Trip Test Complete.", Toast.LENGTH_SHORT).show();
- if (requestCode == LATENCY_RESULTS_REQUEST_CODE) {
- Bundle extras = data != null ? data.getExtras() : null;
- if (extras != null) {
- mRoundTripLatency = extras.getDouble(KEY_ROUND_TRIP_TIME);
- mRoundTripLatencyTxt.setText(String.format("%.2f ms", mRoundTripLatency));
- mRoundTripConfidence = extras.getDouble(KEY_ROUND_TRIP_CONFIDENCE);
- mRoundTripConfidenceTxt.setText(String.format("%.2f", mRoundTripConfidence));
- }
- }
- calculatePass();
- } else {
- Toast.makeText(this, "Round Trip Test Canceled.", Toast.LENGTH_SHORT).show();
- }
- }
-
@Override
protected void onCreate(Bundle savedInstanceState) {
setContentView(R.layout.pro_audio);
super.onCreate(savedInstanceState);
- mAudioManager = (AudioManager)getSystemService(AUDIO_SERVICE);
- mAudioManager.registerAudioDeviceCallback(new ConnectListener(), new Handler());
-
setPassFailButtonClickListeners();
setInfoResources(R.string.proaudio_test, R.string.proaudio_info, -1);
@@ -291,14 +201,8 @@
((TextView)findViewById(
R.id.proAudioMidiHasUSBPeripheralLbl)).setText("" + mClaimsUSBPeripheralMode);
- // Connected Device
- mInputDeviceTxt = ((TextView)findViewById(R.id.proAudioInputLbl));
- mOutputDeviceTxt = ((TextView)findViewById(R.id.proAudioOutputLbl));
-
- // Round-trip Latency
- mRoundTripLatencyTxt = (TextView)findViewById(R.id.proAudioRoundTripLbl);
- mRoundTripConfidenceTxt = (TextView)findViewById(R.id.proAudioConfidenceLbl);
- findViewById(R.id.proAudio_runRoundtripBtn).setOnClickListener(this);
+ mRoundTripTestButton = (Button)findViewById(R.id.proAudio_runRoundtripBtn);
+ mRoundTripTestButton.setOnClickListener(this);
// HDMI
mHDMISupportLbl = (TextView)findViewById(R.id.proAudioHDMISupportLbl);
@@ -308,68 +212,72 @@
calculatePass();
}
- private void scanPeripheralList(AudioDeviceInfo[] devices) {
- // CDD Section C-1-3: USB port, host-mode support
+ protected void startAudioTest() {
+ mRoundTripTestButton.setEnabled(false);
+ super.startAudioTest(mMessageHandler);
+ }
- // Can't just use the first record because then we will only get
- // Source OR sink, not both even on devices that are both.
- mOutputDevInfo = null;
- mInputDevInfo = null;
-
- // Any valid peripherals
- // Do we leave in the Headset test to support a USB-Dongle?
- for (AudioDeviceInfo devInfo : devices) {
- if (devInfo.getType() == AudioDeviceInfo.TYPE_USB_DEVICE || // USB Peripheral
- devInfo.getType() == AudioDeviceInfo.TYPE_USB_HEADSET || // USB dongle+LBPlug
- devInfo.getType() == AudioDeviceInfo.TYPE_WIRED_HEADSET || // Loopback Plug?
- devInfo.getType() == AudioDeviceInfo.TYPE_AUX_LINE) { // Aux-cable loopback?
- if (devInfo.isSink()) {
- mOutputDevInfo = devInfo;
- }
- if (devInfo.isSource()) {
- mInputDevInfo = devInfo;
- }
- } else if (devInfo.isSink() && devInfo.getType() == AudioDeviceInfo.TYPE_HDMI) {
- mHDMIDeviceInfo = devInfo;
- }
- }
-
- mIsPeripheralAttached = mOutputDevInfo != null || mInputDevInfo != null;
- showConnectedAudioPeripheral();
-
- if (mHDMIDeviceInfo != null) {
- mClaimsHDMICheckBox.setChecked(true);
- mHDMISupportLbl.setText(getResources().getString(
- isHDMIValid() ? R.string.pass_button_text : R.string.fail_button_text));
- }
- mHDMISupportLbl.setText(getResources().getString(R.string.audio_proaudio_NA));
+ protected void handleTestCompletion() {
+ super.handleTestCompletion();
calculatePass();
+
+ recordTestResults();
+
+ showWait(false);
+ mRoundTripTestButton.setEnabled(true);
}
- private class ConnectListener extends AudioDeviceCallback {
- /*package*/ ConnectListener() {}
+ /**
+ * Store test results in log
+ */
+ protected void recordTestResults() {
+ super.recordTestResults();
- //
- // AudioDevicesManager.OnDeviceConnectionListener
- //
- @Override
- public void onAudioDevicesAdded(AudioDeviceInfo[] addedDevices) {
- scanPeripheralList(mAudioManager.getDevices(AudioManager.GET_DEVICES_ALL));
- }
+ ReportLog reportLog = getReportLog();
+ reportLog.addValue(
+ "Claims Pro Audio",
+ mClaimsProAudio,
+ ResultType.NEUTRAL,
+ ResultUnit.NONE);
- @Override
- public void onAudioDevicesRemoved(AudioDeviceInfo[] removedDevices) {
- scanPeripheralList(mAudioManager.getDevices(AudioManager.GET_DEVICES_ALL));
- }
+ reportLog.addValue(
+ "Claims Low-Latency Audio",
+ mClaimsLowLatencyAudio,
+ ResultType.NEUTRAL,
+ ResultUnit.NONE);
+
+ reportLog.addValue(
+ "Claims MIDI",
+ mClaimsMIDI,
+ ResultType.NEUTRAL,
+ ResultUnit.NONE);
+
+ reportLog.addValue(
+ "Claims USB Host Mode",
+ mClaimsUSBHostMode,
+ ResultType.NEUTRAL,
+ ResultUnit.NONE);
+
+ reportLog.addValue(
+ "Claims USB Peripheral Mode",
+ mClaimsUSBPeripheralMode,
+ ResultType.NEUTRAL,
+ ResultUnit.NONE);
+
+ reportLog.addValue(
+ "Claims HDMI",
+ mClaimsHDMI,
+ ResultType.NEUTRAL,
+ ResultUnit.NONE);
}
- @Override
+ @Override
public void onClick(View view) {
switch (view.getId()) {
case R.id.proAudio_runRoundtripBtn:
- runRoundTripTest();
- break;
+ startAudioTest();
+ break;
case R.id.proAudioHasHDMICheckBox:
if (mClaimsHDMICheckBox.isChecked()) {