• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright 2018 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.Manifest;
20 import android.content.pm.PackageInfo;
21 import android.content.pm.PackageManager;
22 import android.os.Build;
23 import android.os.Bundle;
24 import android.os.Handler;
25 import android.os.Looper;
26 import android.support.annotation.NonNull;
27 import android.support.v4.app.ActivityCompat;
28 import android.support.v4.content.ContextCompat;
29 import android.util.Log;
30 import android.view.View;
31 import android.widget.Button;
32 import android.widget.TextView;
33 import android.widget.Toast;
34 
35 import java.io.File;
36 import java.io.FileOutputStream;
37 import java.io.IOException;
38 import java.io.OutputStreamWriter;
39 import java.io.Writer;
40 
41 /**
42  * Activity to measure latency on a full duplex stream.
43  */
44 public class AnalyzerActivity extends TestInputActivity {
45 
46     private static final int MY_PERMISSIONS_REQUEST_EXTERNAL_STORAGE = 1001;
47 
48     protected static final String KEY_FILE_NAME = "file";
49     protected static final String KEY_BUFFER_BURSTS = "buffer_bursts";
50 
51     public static final String VALUE_UNSPECIFIED = "unspecified";
52     public static final String KEY_IN_API = "in_api";
53     public static final String KEY_OUT_API = "out_api";
54     public static final String VALUE_API_AAUDIO = "aaudio";
55     public static final String VALUE_API_OPENSLES = "opensles";
56 
57     AudioOutputTester mAudioOutTester;
58     protected BufferSizeView mBufferSizeView;
59     protected String mResultFileName;
60     private String mTestResults;
61 
62     // Note that these string must match the enum result_code in LatencyAnalyzer.h
resultCodeToString(int resultCode)63     String resultCodeToString(int resultCode) {
64         switch (resultCode) {
65             case 0:
66                 return "OK";
67             case -99:
68                 return "ERROR_NOISY";
69             case -98:
70                 return "ERROR_VOLUME_TOO_LOW";
71             case -97:
72                 return "ERROR_VOLUME_TOO_HIGH";
73             case -96:
74                 return "ERROR_CONFIDENCE";
75             case -95:
76                 return "ERROR_INVALID_STATE";
77             case -94:
78                 return "ERROR_GLITCHES";
79             case -93:
80                 return "ERROR_NO_LOCK";
81             default:
82                 return "UNKNOWN";
83         }
84     }
85 
getAnalyzerState()86     public native int getAnalyzerState();
isAnalyzerDone()87     public native boolean isAnalyzerDone();
getMeasuredResult()88     public native int getMeasuredResult();
getResetCount()89     public native int getResetCount();
90 
91     @NonNull
getCommonTestReport()92     protected String getCommonTestReport() {
93         StringBuffer report = new StringBuffer();
94         // Add some extra information for the remote tester.
95         report.append("build.fingerprint = " + Build.FINGERPRINT + "\n");
96         try {
97             PackageInfo pinfo = getPackageManager().getPackageInfo(getPackageName(), 0);
98             report.append(String.format("test.version = %s\n", pinfo.versionName));
99             report.append(String.format("test.version.code = %d\n", pinfo.versionCode));
100         } catch (PackageManager.NameNotFoundException e) {
101         }
102         report.append("time.millis = " + System.currentTimeMillis() + "\n");
103 
104         // INPUT
105         report.append(mAudioInputTester.actualConfiguration.dump());
106         AudioStreamBase inStream = mAudioInputTester.getCurrentAudioStream();
107         report.append(String.format("in.burst.frames = %d\n", inStream.getFramesPerBurst()));
108         report.append(String.format("in.xruns = %d\n", inStream.getXRunCount()));
109 
110         // OUTPUT
111         report.append(mAudioOutTester.actualConfiguration.dump());
112         AudioStreamBase outStream = mAudioOutTester.getCurrentAudioStream();
113         report.append(String.format("out.burst.frames = %d\n", outStream.getFramesPerBurst()));
114         int bufferSize = outStream.getBufferSizeInFrames();
115         report.append(String.format("out.buffer.size.frames = %d\n", bufferSize));
116         int bufferCapacity = outStream.getBufferCapacityInFrames();
117         report.append(String.format("out.buffer.capacity.frames = %d\n", bufferCapacity));
118         report.append(String.format("out.xruns = %d\n", outStream.getXRunCount()));
119 
120         return report.toString();
121     }
122 
123     @Override
onCreate(Bundle savedInstanceState)124     protected void onCreate(Bundle savedInstanceState) {
125         super.onCreate(savedInstanceState);
126         mAudioOutTester = addAudioOutputTester();
127         mBufferSizeView = (BufferSizeView) findViewById(R.id.buffer_size_view);
128         if (mBufferSizeView != null) {
129             mBufferSizeView.setAudioOutTester(mAudioOutTester);
130         }
131     }
132 
133     @Override
resetConfiguration()134     protected void resetConfiguration() {
135         super.resetConfiguration();
136         mAudioOutTester.reset();
137 
138         StreamContext streamContext = getFirstInputStreamContext();
139         if (streamContext != null) {
140             if (streamContext.configurationView != null) {
141                 streamContext.configurationView.setFormat(StreamConfiguration.AUDIO_FORMAT_PCM_FLOAT);
142                 streamContext.configurationView.setFormatConversionAllowed(true);
143             }
144         }
145         streamContext = getFirstOutputStreamContext();
146         if (streamContext != null) {
147             if (streamContext.configurationView != null) {
148                 streamContext.configurationView.setFormat(StreamConfiguration.AUDIO_FORMAT_PCM_FLOAT);
149                 streamContext.configurationView.setFormatConversionAllowed(true);
150             }
151         }
152     }
153 
startAudio()154     public void startAudio() {
155         if (mBufferSizeView != null && mBufferSizeView.isEnabled()) {
156             mBufferSizeView.updateBufferSize();
157         }
158         super.startAudio();
159     }
160 
onStreamClosed()161     public void onStreamClosed() {
162         Toast.makeText(getApplicationContext(),
163                 "Stream was closed or disconnected!",
164                 Toast.LENGTH_SHORT)
165                 .show();
166         stopAudioTest();
167     }
168 
stopAudioTest()169     public void stopAudioTest() {
170     }
171 
getApiFromText(String text)172     private int getApiFromText(String text) {
173         if (VALUE_API_AAUDIO.equals(text)) {
174             return StreamConfiguration.NATIVE_API_AAUDIO;
175         } else if (VALUE_API_OPENSLES.equals(text)) {
176             return StreamConfiguration.NATIVE_API_OPENSLES;
177         } else {
178             return StreamConfiguration.NATIVE_API_UNSPECIFIED;
179         }
180     }
181 
configureStreamsFromBundleForApi(Bundle bundle)182     void configureStreamsFromBundleForApi(Bundle bundle) {
183         // Configure settings
184         StreamConfiguration requestedInConfig = mAudioInputTester.requestedConfiguration;
185         StreamConfiguration requestedOutConfig = mAudioOutTester.requestedConfiguration;
186 
187         // OpenSL ES or AAudio API
188         String text = bundle.getString(KEY_IN_API, VALUE_UNSPECIFIED);
189         int audioApi = getApiFromText(text);
190         requestedInConfig.setNativeApi(audioApi);
191         text = bundle.getString(KEY_OUT_API, VALUE_UNSPECIFIED);
192         audioApi = getApiFromText(text);
193         requestedOutConfig.setNativeApi(audioApi);
194     }
195 
writeTestResultIfPermitted(String resultString)196     void writeTestResultIfPermitted(String resultString) {
197         // Here, thisActivity is the current activity
198         if (ContextCompat.checkSelfPermission(this,
199                 Manifest.permission.WRITE_EXTERNAL_STORAGE)
200                 != PackageManager.PERMISSION_GRANTED) {
201             mTestResults = resultString;
202             ActivityCompat.requestPermissions(this,
203                     new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE},
204                     MY_PERMISSIONS_REQUEST_EXTERNAL_STORAGE);
205         } else {
206             // Permission has already been granted
207             writeTestResult(resultString);
208         }
209     }
210 
maybeWriteTestResult(String resultString)211     void maybeWriteTestResult(String resultString) {
212         if (mResultFileName == null) return;
213         writeTestResultIfPermitted(resultString);
214     }
215 
216     @Override
onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults)217     public void onRequestPermissionsResult(int requestCode,
218                                            String[] permissions,
219                                            int[] grantResults) {
220         switch (requestCode) {
221             case MY_PERMISSIONS_REQUEST_EXTERNAL_STORAGE: {
222                 // If request is cancelled, the result arrays are empty.
223                 if (grantResults.length > 0
224                         && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
225                     writeTestResult(mTestResults);
226                 } else {
227                     showToast("Writing external storage needed for test results.");
228                 }
229                 return;
230             }
231         }
232     }
233 
writeTestInBackground(final String resultString)234     private void writeTestInBackground(final String resultString) {
235         new Thread() {
236             public void run() {
237                 writeTestResult(resultString);
238             }
239         }.start();
240     }
241 
242     // Run this in a background thread.
writeTestResult(String resultString)243     private void writeTestResult(String resultString) {
244         File resultFile = new File(mResultFileName);
245         Writer writer = null;
246         try {
247             writer = new OutputStreamWriter(new FileOutputStream(resultFile));
248             writer.write(resultString);
249         } catch (
250                 IOException e) {
251             e.printStackTrace();
252             showErrorToast(" writing result file. " + e.getMessage());
253         } finally {
254             if (writer != null) {
255                 try {
256                     writer.close();
257                 } catch (IOException e) {
258                     e.printStackTrace();
259                 }
260             }
261         }
262 
263         mResultFileName = null;
264     }
265 
266 
267 }
268