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.os.Bundle;
20 
21 import java.io.IOException;
22 
23 public class BaseAutoGlitchActivity extends GlitchActivity {
24 
25     private static final int SETUP_TIME_SECONDS = 4; // Time for the stream to settle.
26     protected static final int DEFAULT_DURATION_SECONDS = 8; // Run time for each test.
27     private static final int DEFAULT_GAP_MILLIS = 400; // Idle time between each test.
28     private static final String TEXT_SKIP = "SKIP";
29     public static final String TEXT_PASS = "PASS";
30     public static final String TEXT_FAIL = "FAIL !!!!";
31 
32     protected int mDurationSeconds = DEFAULT_DURATION_SECONDS;
33     protected int mGapMillis = DEFAULT_GAP_MILLIS;
34 
35     protected AutomatedTestRunner mAutomatedTestRunner;
36 
37     @Override
onCreate(Bundle savedInstanceState)38     protected void onCreate(Bundle savedInstanceState) {
39         super.onCreate(savedInstanceState);
40 
41         mAutomatedTestRunner = findViewById(R.id.auto_test_runner);
42         mAutomatedTestRunner.setActivity(this);
43     }
44 
log(String text)45     protected void log(String text) {
46         mAutomatedTestRunner.log(text);
47     }
48 
appendFailedSummary(String text)49     protected void appendFailedSummary(String text) {
50         mAutomatedTestRunner.appendFailedSummary(text);
51     }
52 
appendSummary(String text)53     protected void appendSummary(String text) {
54         mAutomatedTestRunner.appendSummary(text);
55     }
56 
57     @Override
onStopTest()58     public void onStopTest() {
59         mAutomatedTestRunner.stopTest();
60     }
61 
getConfigText(StreamConfiguration config)62     protected String getConfigText(StreamConfiguration config) {
63         int channel = (config.getDirection() == StreamConfiguration.DIRECTION_OUTPUT)
64                 ? getOutputChannel() : getInputChannel();
65         return ((config.getDirection() == StreamConfiguration.DIRECTION_OUTPUT) ? "OUT" : "INP")
66                 + (config.isMMap() ? "-M" : "-L")
67                 + ", ID = " + String.format("%2d", config.getDeviceId())
68                 + ", SR = " + String.format("%5d", config.getSampleRate())
69                 + ", Perf = " + StreamConfiguration.convertPerformanceModeToText(
70                 config.getPerformanceMode())
71                 + ", " + StreamConfiguration.convertSharingModeToText(config.getSharingMode())
72                 + ", ch = " + config.getChannelCount() + "[" + channel + "]";
73     }
74 
75     public final static int TEST_RESULT_FAILED = -2;
76     public final static int TEST_RESULT_WARNING = -1;
77     public final static int TEST_RESULT_SKIPPED = 0;
78     public final static int TEST_RESULT_PASSED = 1;
79 
80     // Run test based on the requested input/output configurations.
testConfigurations()81     protected int testConfigurations() throws InterruptedException {
82         int result = TEST_RESULT_SKIPPED;
83         mAutomatedTestRunner.incrementTestCount();
84         if ((getSingleTestIndex() >= 0) && (mAutomatedTestRunner.getTestCount() != getSingleTestIndex())) {
85             return result;
86         }
87 
88         log("========================== #" + mAutomatedTestRunner.getTestCount());
89 
90         StreamConfiguration requestedInConfig = mAudioInputTester.requestedConfiguration;
91         StreamConfiguration requestedOutConfig = mAudioOutTester.requestedConfiguration;
92 
93         StreamConfiguration actualInConfig = mAudioInputTester.actualConfiguration;
94         StreamConfiguration actualOutConfig = mAudioOutTester.actualConfiguration;
95 
96         log("Requested:");
97         log("  " + getConfigText(requestedInConfig));
98         log("  " + getConfigText(requestedOutConfig));
99 
100         String reason = "";
101         boolean openFailed = false;
102         try {
103             openAudio(); // this will fill in actualConfig
104             log("Actual:");
105             log("  " + getConfigText(actualInConfig));
106             log("  " + getConfigText(actualOutConfig));
107             // Set output size to a level that will avoid glitches.
108             AudioStreamBase stream = mAudioOutTester.getCurrentAudioStream();
109             int sizeFrames = stream.getBufferCapacityInFrames() / 2;
110             stream.setBufferSizeInFrames(sizeFrames);
111         } catch (Exception e) {
112             openFailed = true;
113             log(e.getMessage());
114             reason = e.getMessage();
115         }
116 
117         // The test would only be worth running if we got the configuration we requested on input or output.
118         String skipReason = shouldTestBeSkipped();
119         boolean skipped = skipReason.length() > 0;
120         boolean valid = !openFailed && !skipped;
121         boolean startFailed = false;
122         if (valid) {
123             try {
124                 startAudioTest();
125             } catch (IOException e) {
126                 e.printStackTrace();
127                 valid = false;
128                 startFailed = true;
129                 log(e.getMessage());
130                 reason = e.getMessage();
131             }
132         }
133         mAutomatedTestRunner.flushLog();
134 
135         if (valid) {
136             // Check for early return until we reach full duration.
137             long now = System.currentTimeMillis();
138             long startedAt = now;
139             long endTime = System.currentTimeMillis() + (mDurationSeconds * 1000);
140             boolean finishedEarly = false;
141             while (now < endTime && !finishedEarly) {
142                 Thread.sleep(100); // Let test run.
143                 now = System.currentTimeMillis();
144                 finishedEarly = isFinishedEarly();
145                 if (finishedEarly) {
146                     log("Finished early after " + (now - startedAt) + " msec.");
147                 }
148             }
149         }
150         int inXRuns = 0;
151         int outXRuns = 0;
152 
153         if (!openFailed) {
154             // get xRuns before closing the streams.
155             inXRuns = mAudioInputTester.getCurrentAudioStream().getXRunCount();
156             outXRuns = mAudioOutTester.getCurrentAudioStream().getXRunCount();
157 
158             super.stopAudioTest();
159         }
160 
161         if (openFailed || startFailed) {
162             appendFailedSummary("------ #" + mAutomatedTestRunner.getTestCount() + "\n");
163             appendFailedSummary(getConfigText(requestedInConfig) + "\n");
164             appendFailedSummary(getConfigText(requestedOutConfig) + "\n");
165             appendFailedSummary(reason + "\n");
166             mAutomatedTestRunner.incrementFailCount();
167         } else if (skipped) {
168             log(TEXT_SKIP + " - " + skipReason);
169         } else {
170             log("Result:");
171             reason += didTestFail();
172             boolean passed = reason.length() == 0;
173 
174             String resultText = getShortReport();
175             resultText += ", xruns = " + inXRuns + "/" + outXRuns;
176             resultText += ", " + (passed ? TEXT_PASS : TEXT_FAIL);
177             resultText += reason;
178             log("  " + resultText);
179             if (!passed) {
180                 appendFailedSummary("------ #" + mAutomatedTestRunner.getTestCount() + "\n");
181                 appendFailedSummary("  " + getConfigText(actualInConfig) + "\n");
182                 appendFailedSummary("  " + getConfigText(actualOutConfig) + "\n");
183                 appendFailedSummary("    " + resultText + "\n");
184                 mAutomatedTestRunner.incrementFailCount();
185                 result = TEST_RESULT_FAILED;
186             } else {
187                 mAutomatedTestRunner.incrementPassCount();
188                 result = TEST_RESULT_PASSED;
189             }
190         }
191         mAutomatedTestRunner.flushLog();
192 
193         // Give hardware time to settle between tests.
194         Thread.sleep(mGapMillis);
195         return result;
196     }
197 
isFinishedEarly()198     protected boolean isFinishedEarly() {
199         return false;
200     }
201 
shouldTestBeSkipped()202     protected String shouldTestBeSkipped() {
203         String why = "";
204         StreamConfiguration requestedInConfig = mAudioInputTester.requestedConfiguration;
205         StreamConfiguration requestedOutConfig = mAudioOutTester.requestedConfiguration;
206         StreamConfiguration actualInConfig = mAudioInputTester.actualConfiguration;
207         StreamConfiguration actualOutConfig = mAudioOutTester.actualConfiguration;
208         // No point running the test if we don't get the sharing mode we requested.
209         if (actualInConfig.getSharingMode() != requestedInConfig.getSharingMode()
210                 || actualOutConfig.getSharingMode() != requestedOutConfig.getSharingMode()) {
211             log("Did not get requested sharing mode.");
212             why += "share";
213         }
214         // We don't skip based on performance mode because if you request LOW_LATENCY you might
215         // get a smaller burst than if you request NONE.
216         return why;
217     }
218 
didTestFail()219     public String didTestFail() {
220         String why = "";
221         if (getMaxSecondsWithNoGlitch() <= (mDurationSeconds - SETUP_TIME_SECONDS)) {
222             why += ", glitch";
223         }
224         return why;
225     }
226 
227 }
228