1 /* 2 * Copyright 2019 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.google.sample.oboe.manualtest; 18 19 import android.content.Intent; 20 import android.os.Bundle; 21 import android.os.Handler; 22 import android.os.Looper; 23 import android.util.Log; 24 import android.widget.SeekBar; 25 import android.widget.TextView; 26 27 import java.io.IOException; 28 29 public class ManualGlitchActivity extends GlitchActivity { 30 31 public static final String KEY_IN_PERF = "in_perf"; 32 public static final String KEY_OUT_PERF = "out_perf"; 33 public static final String VALUE_PERF_LOW_LATENCY = "lowlat"; 34 public static final String VALUE_PERF_POWERSAVE = "powersave"; 35 public static final String VALUE_PERF_NONE = "none"; 36 37 public static final String KEY_IN_SHARING = "in_sharing"; 38 public static final String KEY_OUT_SHARING = "out_sharing"; 39 public static final String VALUE_SHARING_EXCLUSIVE = "exclusive"; 40 public static final String VALUE_SHARING_SHARED = "shared"; 41 42 public static final String KEY_SAMPLE_RATE = "sample_rate"; 43 public static final int VALUE_DEFAULT_SAMPLE_RATE = 48000; 44 45 public static final String KEY_IN_PRESET = "in_preset"; 46 47 public static final String KEY_IN_CHANNELS = "in_channels"; 48 public static final String KEY_OUT_CHANNELS = "out_channels"; 49 public static final int VALUE_DEFAULT_CHANNELS = 2; 50 51 public static final String KEY_DURATION = "duration"; 52 public static final int VALUE_DEFAULT_DURATION = 10; 53 54 public static final String KEY_BUFFER_BURSTS = "buffer_bursts"; 55 public static final int VALUE_DEFAULT_BUFFER_BURSTS = 2; 56 57 public static final String KEY_TOLERANCE = "tolerance"; 58 private static final float DEFAULT_TOLERANCE = 0.1f; 59 60 private TextView mTextTolerance; 61 private SeekBar mFaderTolerance; 62 protected ExponentialTaper mTaperTolerance; 63 private WaveformView mWaveformView; 64 private float[] mWaveform = new float[256]; 65 private boolean mTestRunningByIntent; 66 private Bundle mBundleFromIntent; 67 68 private float mTolerance = DEFAULT_TOLERANCE; 69 70 private SeekBar.OnSeekBarChangeListener mToleranceListener = new SeekBar.OnSeekBarChangeListener() { 71 @Override 72 public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) { 73 setToleranceProgress(progress); 74 } 75 76 @Override 77 public void onStartTrackingTouch(SeekBar seekBar) { 78 } 79 80 @Override 81 public void onStopTrackingTouch(SeekBar seekBar) { 82 } 83 }; 84 setToleranceProgress(int progress)85 protected void setToleranceProgress(int progress) { 86 float tolerance = (float) mTaperTolerance.linearToExponential( 87 ((double)progress) / FADER_PROGRESS_MAX); 88 setTolerance(tolerance); 89 mTextTolerance.setText("Tolerance = " + String.format("%5.3f", tolerance)); 90 } 91 92 @Override onCreate(Bundle savedInstanceState)93 protected void onCreate(Bundle savedInstanceState) { 94 super.onCreate(savedInstanceState); 95 mBundleFromIntent = getIntent().getExtras(); 96 97 mTextTolerance = (TextView) findViewById(R.id.textTolerance); 98 mFaderTolerance = (SeekBar) findViewById(R.id.faderTolerance); 99 mTaperTolerance = new ExponentialTaper(0.0, 0.5, 100.0); 100 mFaderTolerance.setOnSeekBarChangeListener(mToleranceListener); 101 setToleranceFader(DEFAULT_TOLERANCE); 102 103 mWaveformView = (WaveformView) findViewById(R.id.waveview_audio); 104 } 105 setToleranceFader(float tolerance)106 private void setToleranceFader(float tolerance) { 107 int progress = (int) Math.round((mTaperTolerance.exponentialToLinear( 108 tolerance) * FADER_PROGRESS_MAX)); 109 mFaderTolerance.setProgress(progress); 110 } 111 112 @Override inflateActivity()113 protected void inflateActivity() { 114 setContentView(R.layout.activity_manual_glitches); 115 } 116 117 @Override onResume()118 public void onResume(){ 119 super.onResume(); 120 processBundleFromIntent(); 121 } 122 123 @Override onNewIntent(Intent intent)124 public void onNewIntent(Intent intent) { 125 mBundleFromIntent = intent.getExtras(); 126 } 127 processBundleFromIntent()128 private void processBundleFromIntent() { 129 if (mBundleFromIntent == null) { 130 return; 131 } 132 if (mTestRunningByIntent) { 133 return; 134 } 135 136 mResultFileName = null; 137 if (mBundleFromIntent.containsKey(KEY_FILE_NAME)) { 138 mTestRunningByIntent = true; 139 mResultFileName = mBundleFromIntent.getString(KEY_FILE_NAME); 140 141 // Delay the test start to avoid race conditions. 142 Handler handler = new Handler(Looper.getMainLooper()); // UI thread 143 handler.postDelayed(new Runnable() { 144 @Override 145 public void run() { 146 startAutomaticTest(); 147 } 148 }, 500); // TODO where is the race, close->open? 149 150 } 151 } 152 getPerfFromText(String text)153 private int getPerfFromText(String text) { 154 if (VALUE_PERF_NONE.equals(text)) { 155 return StreamConfiguration.PERFORMANCE_MODE_NONE; 156 } else if (VALUE_PERF_POWERSAVE.equals(text)) { 157 return StreamConfiguration.PERFORMANCE_MODE_POWER_SAVING; 158 } else { 159 return StreamConfiguration.PERFORMANCE_MODE_LOW_LATENCY; 160 } 161 } 162 getSharingFromText(String text)163 private int getSharingFromText(String text) { 164 if (VALUE_SHARING_SHARED.equals(text)) { 165 return StreamConfiguration.SHARING_MODE_SHARED; 166 } else { 167 return StreamConfiguration.SHARING_MODE_EXCLUSIVE; 168 } 169 } 170 configureStreamsFromBundle(Bundle bundle)171 void configureStreamsFromBundle(Bundle bundle) { 172 173 // Configure settings 174 StreamConfiguration requestedInConfig = mAudioInputTester.requestedConfiguration; 175 StreamConfiguration requestedOutConfig = mAudioOutTester.requestedConfiguration; 176 177 requestedInConfig.reset(); 178 requestedOutConfig.reset(); 179 180 configureStreamsFromBundleForApi(bundle); 181 182 // Extract parameters from the bundle. 183 String text = bundle.getString(KEY_IN_PERF, VALUE_PERF_LOW_LATENCY); 184 int perfMode = getPerfFromText(text); 185 requestedInConfig.setPerformanceMode(perfMode); 186 187 text = bundle.getString(KEY_OUT_PERF, VALUE_PERF_LOW_LATENCY); 188 perfMode = getPerfFromText(text); 189 requestedOutConfig.setPerformanceMode(perfMode); 190 191 text = bundle.getString(KEY_IN_SHARING, VALUE_SHARING_EXCLUSIVE); 192 int sharingMode = getSharingFromText(text); 193 requestedInConfig.setSharingMode(sharingMode); 194 text = bundle.getString(KEY_OUT_SHARING, VALUE_SHARING_EXCLUSIVE); 195 sharingMode = getSharingFromText(text); 196 requestedOutConfig.setSharingMode(sharingMode); 197 198 int sampleRate = bundle.getInt(KEY_SAMPLE_RATE, VALUE_DEFAULT_SAMPLE_RATE); 199 requestedInConfig.setSampleRate(sampleRate); 200 requestedOutConfig.setSampleRate(sampleRate); 201 202 float tolerance = bundle.getFloat(KEY_TOLERANCE, DEFAULT_TOLERANCE); 203 setToleranceFader(tolerance); 204 setTolerance(tolerance); 205 mTolerance = tolerance; 206 207 int inChannels = bundle.getInt(KEY_IN_CHANNELS, VALUE_DEFAULT_CHANNELS); 208 requestedInConfig.setChannelCount(inChannels); 209 int outChannels = bundle.getInt(KEY_OUT_CHANNELS, VALUE_DEFAULT_CHANNELS); 210 requestedOutConfig.setChannelCount(outChannels); 211 212 String defaultText = StreamConfiguration.convertInputPresetToText( 213 StreamConfiguration.INPUT_PRESET_VOICE_RECOGNITION); 214 text = bundle.getString(KEY_IN_PRESET, defaultText); 215 int inputPreset = StreamConfiguration.convertTextToInputPreset(text); 216 requestedInConfig.setInputPreset(inputPreset); 217 } 218 startAudioTest()219 public void startAudioTest() throws IOException { 220 super.startAudioTest(); 221 setToleranceProgress(mFaderTolerance.getProgress()); 222 } 223 startAutomaticTest()224 void startAutomaticTest() { 225 configureStreamsFromBundle(mBundleFromIntent); 226 227 int durationSeconds = mBundleFromIntent.getInt(KEY_DURATION, VALUE_DEFAULT_DURATION); 228 int numBursts = mBundleFromIntent.getInt(KEY_BUFFER_BURSTS, VALUE_DEFAULT_BUFFER_BURSTS); 229 mBundleFromIntent = null; 230 231 try { 232 onStartAudioTest(null); 233 int sizeFrames = mAudioOutTester.getCurrentAudioStream().getFramesPerBurst() * numBursts; 234 mAudioOutTester.getCurrentAudioStream().setBufferSizeInFrames(sizeFrames); 235 236 // Schedule the end of the test. 237 Handler handler = new Handler(Looper.getMainLooper()); // UI thread 238 handler.postDelayed(new Runnable() { 239 @Override 240 public void run() { 241 stopAutomaticTest(); 242 } 243 }, durationSeconds * 1000); 244 } catch (IOException e) { 245 String report = "Open failed: " + e.getMessage(); 246 maybeWriteTestResult(report); 247 mTestRunningByIntent = false; 248 } 249 250 } 251 stopAutomaticTest()252 void stopAutomaticTest() { 253 String report = getCommonTestReport() 254 + String.format("tolerance = %5.3f\n", mTolerance) 255 + mLastGlitchReport; 256 onStopAudioTest(null); 257 maybeWriteTestResult(report); 258 mTestRunningByIntent = false; 259 } 260 261 // Only call from UI thread. 262 @Override onTestFinished()263 public void onTestFinished() { 264 super.onTestFinished(); 265 } 266 // Only call from UI thread. 267 @Override onTestBegan()268 public void onTestBegan() { 269 mWaveformView.clearSampleData(); 270 mWaveformView.postInvalidate(); 271 super.onTestBegan(); 272 } 273 274 // Called on UI thread 275 @Override onGlitchDetected()276 protected void onGlitchDetected() { 277 int numSamples = getGlitch(mWaveform); 278 mWaveformView.setSampleData(mWaveform, 0, numSamples); 279 mWaveformView.postInvalidate(); 280 } 281 getGlitchWaveform()282 private float[] getGlitchWaveform() { 283 return mWaveform; 284 } 285 getGlitch(float[] mWaveform)286 private native int getGlitch(float[] mWaveform); 287 288 } 289