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.widget.SeekBar;
24 import android.widget.TextView;
25 
26 import java.io.IOException;
27 
28 public class ManualGlitchActivity extends GlitchActivity {
29 
30     public static final String KEY_IN_PRESET = "in_preset";
31 
32     public static final String KEY_DURATION = "duration";
33     public static final int VALUE_DEFAULT_DURATION = 10;
34 
35     public static final String KEY_BUFFER_BURSTS = "buffer_bursts";
36     public static final int VALUE_DEFAULT_BUFFER_BURSTS = 2;
37 
38     public static final String KEY_TOLERANCE = "tolerance";
39     private static final float DEFAULT_TOLERANCE = 0.1f;
40 
41     private TextView mTextTolerance;
42     private SeekBar mFaderTolerance;
43     protected ExponentialTaper mTaperTolerance;
44     private WaveformView mWaveformView;
45     private float[] mWaveform = new float[256];
46     private boolean mTestRunningByIntent;
47     private Bundle mBundleFromIntent;
48 
49     private float   mTolerance = DEFAULT_TOLERANCE;
50 
51     private SeekBar.OnSeekBarChangeListener mToleranceListener = new SeekBar.OnSeekBarChangeListener() {
52         @Override
53         public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
54             setToleranceProgress(progress);
55         }
56 
57         @Override
58         public void onStartTrackingTouch(SeekBar seekBar) {
59         }
60 
61         @Override
62         public void onStopTrackingTouch(SeekBar seekBar) {
63         }
64     };
65 
setToleranceProgress(int progress)66     protected void setToleranceProgress(int progress) {
67         float tolerance = (float) mTaperTolerance.linearToExponential(
68                 ((double)progress) / FADER_PROGRESS_MAX);
69         setTolerance(tolerance);
70         mTextTolerance.setText("Tolerance = " + String.format("%5.3f", tolerance));
71     }
72 
73     @Override
onCreate(Bundle savedInstanceState)74     protected void onCreate(Bundle savedInstanceState) {
75         super.onCreate(savedInstanceState);
76         mBundleFromIntent = getIntent().getExtras();
77 
78         mTextTolerance = (TextView) findViewById(R.id.textTolerance);
79         mFaderTolerance = (SeekBar) findViewById(R.id.faderTolerance);
80         mTaperTolerance = new ExponentialTaper(0.0, 0.5, 100.0);
81         mFaderTolerance.setOnSeekBarChangeListener(mToleranceListener);
82         setToleranceFader(DEFAULT_TOLERANCE);
83 
84         mWaveformView = (WaveformView) findViewById(R.id.waveview_audio);
85     }
86 
setToleranceFader(float tolerance)87     private void setToleranceFader(float tolerance) {
88         int progress = (int) Math.round((mTaperTolerance.exponentialToLinear(
89                 tolerance) * FADER_PROGRESS_MAX));
90         mFaderTolerance.setProgress(progress);
91     }
92 
93     @Override
inflateActivity()94     protected void inflateActivity() {
95         setContentView(R.layout.activity_manual_glitches);
96     }
97 
98     @Override
onResume()99     public void onResume(){
100         super.onResume();
101         processBundleFromIntent();
102     }
103 
104     @Override
onNewIntent(Intent intent)105     public void onNewIntent(Intent intent) {
106         mBundleFromIntent = intent.getExtras();
107     }
108 
processBundleFromIntent()109     private void processBundleFromIntent() {
110         if (mBundleFromIntent == null) {
111             return;
112         }
113         if (mTestRunningByIntent) {
114             return;
115         }
116 
117         mResultFileName = null;
118         if (mBundleFromIntent.containsKey(KEY_FILE_NAME)) {
119             mTestRunningByIntent = true;
120             mResultFileName = mBundleFromIntent.getString(KEY_FILE_NAME);
121 
122             // Delay the test start to avoid race conditions.
123             Handler handler = new Handler(Looper.getMainLooper()); // UI thread
124             handler.postDelayed(new Runnable() {
125                 @Override
126                 public void run() {
127                     startAutomaticTest();
128                 }
129             }, 500); // TODO where is the race, close->open?
130 
131         }
132     }
133 
configureStreamsFromBundle(Bundle bundle)134     void configureStreamsFromBundle(Bundle bundle) {
135         // Extract common parameters
136         super.configureStreamsFromBundle(bundle);
137 
138         StreamConfiguration requestedInConfig = mAudioInputTester.requestedConfiguration;
139         StreamConfiguration requestedOutConfig = mAudioOutTester.requestedConfiguration;
140 
141         // Extract custom parameters from the bundle.
142         float tolerance = bundle.getFloat(KEY_TOLERANCE, DEFAULT_TOLERANCE);
143         setToleranceFader(tolerance);
144         setTolerance(tolerance);
145         mTolerance = tolerance;
146 
147         String defaultText = StreamConfiguration.convertInputPresetToText(
148                 StreamConfiguration.INPUT_PRESET_VOICE_RECOGNITION);
149         String text = bundle.getString(KEY_IN_PRESET, defaultText);
150         int inputPreset = StreamConfiguration.convertTextToInputPreset(text);
151         requestedInConfig.setInputPreset(inputPreset);
152     }
153 
startAudioTest()154     public void startAudioTest() throws IOException {
155         super.startAudioTest();
156         setToleranceProgress(mFaderTolerance.getProgress());
157     }
158 
startAutomaticTest()159     void startAutomaticTest() {
160         configureStreamsFromBundle(mBundleFromIntent);
161 
162         int durationSeconds = mBundleFromIntent.getInt(KEY_DURATION, VALUE_DEFAULT_DURATION);
163         int numBursts = mBundleFromIntent.getInt(KEY_BUFFER_BURSTS, VALUE_DEFAULT_BUFFER_BURSTS);
164         mBundleFromIntent = null;
165 
166         try {
167             onStartAudioTest(null);
168             int sizeFrames = mAudioOutTester.getCurrentAudioStream().getFramesPerBurst() * numBursts;
169             mAudioOutTester.getCurrentAudioStream().setBufferSizeInFrames(sizeFrames);
170 
171             // Schedule the end of the test.
172             Handler handler = new Handler(Looper.getMainLooper()); // UI thread
173             handler.postDelayed(new Runnable() {
174                 @Override
175                 public void run() {
176                     stopAutomaticTest();
177                 }
178             }, durationSeconds * 1000);
179         } catch (IOException e) {
180             String report = "Open failed: " + e.getMessage();
181             maybeWriteTestResult(report);
182             mTestRunningByIntent = false;
183         }
184 
185     }
186 
stopAutomaticTest()187     void stopAutomaticTest() {
188         String report = getCommonTestReport()
189                 + String.format("tolerance = %5.3f\n", mTolerance)
190                 + mLastGlitchReport;
191         onStopAudioTest(null);
192         maybeWriteTestResult(report);
193         mTestRunningByIntent = false;
194     }
195 
196     // Only call from UI thread.
197     @Override
onTestFinished()198     public void onTestFinished() {
199         super.onTestFinished();
200     }
201     // Only call from UI thread.
202     @Override
onTestBegan()203     public void onTestBegan() {
204         mWaveformView.clearSampleData();
205         mWaveformView.postInvalidate();
206         super.onTestBegan();
207     }
208 
209     // Called on UI thread
210     @Override
onGlitchDetected()211     protected void onGlitchDetected() {
212         int numSamples = getGlitch(mWaveform);
213         mWaveformView.setSampleData(mWaveform, 0, numSamples);
214         mWaveformView.postInvalidate();
215     }
216 
getGlitchWaveform()217     private float[] getGlitchWaveform() {
218         return mWaveform;
219     }
220 
getGlitch(float[] mWaveform)221     private native int getGlitch(float[] mWaveform);
222 
223 }
224