1 /* 2 * Copyright (C) 2021 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.android.cts.verifier.audio; 18 19 import android.os.Bundle; 20 import android.view.View; 21 import android.widget.Button; 22 import android.widget.RadioButton; 23 import android.widget.TextView; 24 25 import com.android.compatibility.common.util.ResultType; 26 import com.android.compatibility.common.util.ResultUnit; 27 import com.android.cts.verifier.PassFailButtons; 28 import com.android.cts.verifier.R; 29 30 import org.hyphonate.megaaudio.common.BuilderBase; 31 import org.hyphonate.megaaudio.common.StreamBase; 32 33 public abstract class AudioColdStartBaseActivity 34 extends PassFailButtons.Activity 35 implements View.OnClickListener { 36 private static final String TAG = "AudioColdStartBaseActivity"; 37 38 // Test State 39 protected boolean mIsTestRunning; 40 41 // Audio Attributes 42 protected static final int NUM_CHANNELS = 2; 43 protected int mSampleRate; 44 protected int mNumExchangeFrames; 45 46 protected int mAudioApi = BuilderBase.TYPE_OBOE; 47 48 // (all times in nanoseconds) 49 protected long mPreOpenTime; 50 protected long mPostOpenTime; 51 protected long mPreStartTime; 52 protected long mPostStartTime; 53 54 protected double mColdStartlatencyMS; 55 private double mOpenTimeMS; 56 private double mStartTimeMS; 57 58 // Widgets 59 Button mStartBtn; 60 Button mStopBtn; 61 62 TextView mAttributesTxt; 63 TextView mOpenTimeTxt; 64 TextView mStartTimeTxt; 65 TextView mLatencyTxt; 66 TextView mResultsTxt; 67 68 // ReportLog Schema 69 private static final String KEY_AUDIO_API = "audio_api"; 70 private static final String KEY_LATENCY = "latency_ms"; 71 private static final String KEY_OPEN = "open_ms"; 72 private static final String KEY_START = "start_ms"; 73 74 // Time-base conversions nanosToMs(double nanos)75 protected double nanosToMs(double nanos) { 76 return nanos / 1000000.0; 77 } 78 msToNanos(double ms)79 protected long msToNanos(double ms) { 80 return (long) (ms * 1000000.0); 81 } 82 83 // 84 // UI Helpers 85 // 86 private final String msFormat = "%.2f ms"; 87 makeMSString(double ms)88 protected String makeMSString(double ms) { 89 return String.format(msFormat, ms); 90 } 91 92 // 93 // UI 94 // showAttributes()95 void showAttributes() { 96 mAttributesTxt.setText("" + mSampleRate + " Hz " + mNumExchangeFrames + " Frames"); 97 } 98 showOpenTime()99 private void showOpenTime() { 100 mOpenTimeMS = nanosToMs(mPostOpenTime - mPreOpenTime); 101 mOpenTimeTxt.setText("Open: " + makeMSString(mOpenTimeMS)); 102 103 reportOpenTime(); 104 } 105 showStartTime()106 private void showStartTime() { 107 mStartTimeMS = nanosToMs(mPostStartTime - mPreStartTime); 108 mStartTimeTxt.setText("Start: " + makeMSString(mStartTimeMS)); 109 110 reportStartTime(); 111 } 112 showColdStartLatency()113 protected void showColdStartLatency() { 114 mLatencyTxt.setText("Latency: " + mColdStartlatencyMS); 115 116 if (mColdStartlatencyMS < 0) { 117 mResultsTxt.setText("Invalid cold start latency."); 118 } else if (mColdStartlatencyMS <= getRecommendedTimeMS()) { 119 mResultsTxt.setText("PASS. Meets RECOMMENDED latency of " 120 + getRecommendedTimeMS() + "ms"); 121 } else if (mColdStartlatencyMS <= getRequiredTimeMS()) { 122 mResultsTxt.setText("PASS. Meets REQUIRED latency of " + getRequiredTimeMS() + "ms"); 123 } else { 124 mResultsTxt.setText("FAIL. Did not meet REQUIRED latency of " + getRequiredTimeMS() 125 + "ms"); 126 } 127 } 128 clearResults()129 protected void clearResults() { 130 mAttributesTxt.setText(""); 131 mOpenTimeTxt.setText(""); 132 mStartTimeTxt.setText(""); 133 mLatencyTxt.setText(""); 134 mResultsTxt.setText(""); 135 } 136 137 @Override onCreate(Bundle savedInstanceState)138 protected void onCreate(Bundle savedInstanceState) { 139 super.onCreate(savedInstanceState); 140 141 // MegaAudio Initialization 142 StreamBase.setup(this); 143 mSampleRate = StreamBase.getSystemSampleRate(); 144 mNumExchangeFrames = StreamBase.getNumBurstFrames(mAudioApi); 145 146 ((RadioButton) findViewById(R.id.audioJavaApiBtn)).setOnClickListener(this); 147 RadioButton nativeApiRB = findViewById(R.id.audioNativeApiBtn); 148 nativeApiRB.setChecked(true); 149 nativeApiRB.setOnClickListener(this); 150 151 mStartBtn = (Button) findViewById(R.id.coldstart_run_btn); 152 mStartBtn.setOnClickListener(this); 153 mStopBtn = (Button) findViewById(R.id.coldstart_cancel_btn); 154 mStopBtn.setOnClickListener(this); 155 mStopBtn.setEnabled(false); 156 157 mAttributesTxt = ((TextView) findViewById(R.id.coldstart_attributesTxt)); 158 mOpenTimeTxt = ((TextView) findViewById(R.id.coldstart_openTimeTxt)); 159 mStartTimeTxt = ((TextView) findViewById(R.id.coldstart_startTimeTxt)); 160 mLatencyTxt = (TextView) findViewById(R.id.coldstart_coldLatencyTxt); 161 mResultsTxt = (TextView) findViewById(R.id.coldstart_coldResultsTxt); 162 163 reportApi(); 164 } 165 getRequiredTimeMS()166 abstract int getRequiredTimeMS(); getRecommendedTimeMS()167 abstract int getRecommendedTimeMS(); 168 runAudioTest()169 abstract boolean runAudioTest(); stopAudio()170 abstract void stopAudio(); cancelTest()171 void cancelTest() { 172 stopAudio(); 173 updateTestStateButtons(); 174 175 mOpenTimeTxt.setText(""); 176 mStartTimeTxt.setText(""); 177 mLatencyTxt.setText(""); 178 mResultsTxt.setText(""); 179 180 getPassButton().setEnabled(false); 181 } 182 updateTestStateButtons()183 protected void updateTestStateButtons() { 184 mStartBtn.setEnabled(!mIsTestRunning); 185 mStopBtn.setEnabled(mIsTestRunning); 186 } 187 188 // 189 // PassFailButtons Overrides 190 // 191 @Override requiresReportLog()192 public boolean requiresReportLog() { 193 return true; 194 } 195 196 @Override getReportFileName()197 public String getReportFileName() { 198 return PassFailButtons.AUDIO_TESTS_REPORT_LOG_NAME; 199 } 200 201 @Override recordTestResults()202 public void recordTestResults() { 203 getReportLog().submit(); 204 } 205 reportApi()206 private void reportApi() { 207 getReportLog().addValue( 208 KEY_AUDIO_API, 209 mAudioApi, 210 ResultType.NEUTRAL, 211 ResultUnit.NONE); 212 } 213 reportOpenTime()214 private void reportOpenTime() { 215 getReportLog().addValue( 216 KEY_OPEN, 217 mOpenTimeMS, 218 ResultType.NEUTRAL, 219 ResultUnit.MS); 220 } 221 reportStartTime()222 private void reportStartTime() { 223 getReportLog().addValue( 224 KEY_START, 225 mStartTimeMS, 226 ResultType.NEUTRAL, 227 ResultUnit.MS); 228 } 229 reportLatency()230 protected void reportLatency() { 231 getReportLog().addValue( 232 KEY_LATENCY, 233 mColdStartlatencyMS, 234 ResultType.NEUTRAL, 235 ResultUnit.NONE); 236 } 237 238 // 239 // View.OnClickListener overrides 240 // 241 @Override onClick(View v)242 public void onClick(View v) { 243 int id = v.getId(); 244 if (id == R.id.audioJavaApiBtn) { 245 stopAudio(); 246 clearResults(); 247 updateTestStateButtons(); 248 mAudioApi = BuilderBase.TYPE_JAVA; 249 mNumExchangeFrames = StreamBase.getNumBurstFrames(mAudioApi); 250 } else if (id == R.id.audioNativeApiBtn) { 251 stopAudio(); 252 clearResults(); 253 updateTestStateButtons(); 254 mAudioApi = BuilderBase.TYPE_OBOE; 255 mNumExchangeFrames = StreamBase.getNumBurstFrames(mAudioApi); 256 } else if (id == R.id.coldstart_run_btn) { 257 runAudioTest(); 258 259 showAttributes(); 260 showOpenTime(); 261 showStartTime(); 262 263 updateTestStateButtons(); 264 } else if (id == R.id.coldstart_cancel_btn) { 265 cancelTest(); 266 } 267 } 268 } 269