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.util.Log; 21 import android.view.View; 22 import android.widget.Button; 23 import android.widget.RadioButton; 24 import android.widget.TextView; 25 26 import com.android.cts.verifier.PassFailButtons; 27 import com.android.cts.verifier.R; 28 29 import org.hyphonate.megaaudio.common.BuilderBase; 30 31 public abstract class AudioColdStartBaseActivity 32 extends PassFailButtons.Activity 33 implements View.OnClickListener { 34 private static final String TAG = "AudioColdStartBaseActivity"; 35 36 // JNI load 37 static { 38 try { 39 System.loadLibrary("megaaudio_jni"); 40 } catch (UnsatisfiedLinkError e) { 41 Log.e(TAG, "Error loading MegaAudio JNI library"); 42 Log.e(TAG, "e: " + e); 43 e.printStackTrace(); 44 } 45 46 /* TODO: gracefully fail/notify if the library can't be loaded */ 47 } 48 49 // Test State 50 protected boolean mIsTestRunning; 51 52 // Audio Attributes 53 protected static final int NUM_CHANNELS = 2; 54 protected int mSampleRate; 55 protected int mNumBufferFrames; 56 57 protected int mAudioApi = BuilderBase.TYPE_OBOE; 58 59 // (all times in nanoseconds) 60 protected long mPreOpenTime; 61 protected long mPostOpenTime; 62 protected long mPreStartTime; 63 protected long mPostStartTime; 64 65 protected double mColdStartlatencyMS; 66 67 // Widgets 68 Button mStartBtn; 69 Button mStopBtn; 70 71 TextView mAttributesTxt; 72 TextView mOpenTimeTxt; 73 TextView mStartTimeTxt; 74 TextView mLatencyTxt; 75 TextView mResultsTxt; 76 77 // Time-base conversions nanosToMs(double nanos)78 protected double nanosToMs(double nanos) { 79 return nanos / 1000000.0; 80 } 81 msToNanos(double ms)82 protected long msToNanos(double ms) { 83 return (long) (ms * 1000000.0); 84 } 85 86 // 87 // UI Helpers 88 // 89 private final String msFormat = "%.2f ms"; 90 makeMSString(double ms)91 protected String makeMSString(double ms) { 92 return String.format(msFormat, ms); 93 } 94 95 // 96 // UI 97 // showAttributes()98 void showAttributes() { 99 mAttributesTxt.setText("" + mSampleRate + " Hz " + mNumBufferFrames + " Frames"); 100 } 101 showOpenTime()102 void showOpenTime() { 103 double timeMs = nanosToMs(mPostOpenTime - mPreOpenTime); 104 mOpenTimeTxt.setText("Open: " + makeMSString(timeMs)); 105 } 106 showStartTime()107 void showStartTime() { 108 double timeMs = nanosToMs(mPostStartTime - mPreStartTime); 109 mStartTimeTxt.setText("Start: " + makeMSString(timeMs)); 110 } 111 showColdStartLatency()112 void showColdStartLatency() { 113 mLatencyTxt.setText("Latency: " + mColdStartlatencyMS); 114 115 if (mColdStartlatencyMS <= getRecommendedTimeMS()) { 116 mResultsTxt.setText("PASS. Meets RECOMMENDED latency of " 117 + getRecommendedTimeMS() + "ms"); 118 } else if (mColdStartlatencyMS <= getRequiredTimeMS()) { 119 mResultsTxt.setText("PASS. Meets REQUIRED latency of " + getRequiredTimeMS() + "ms"); 120 } else { 121 mResultsTxt.setText("FAIL. Did not meet REQUIRED latency of " + getRequiredTimeMS() 122 + "ms"); 123 } 124 } 125 clearResults()126 protected void clearResults() { 127 mAttributesTxt.setText(""); 128 mOpenTimeTxt.setText(""); 129 mStartTimeTxt.setText(""); 130 mLatencyTxt.setText(""); 131 mResultsTxt.setText(""); 132 } 133 134 @Override onCreate(Bundle savedInstanceState)135 protected void onCreate(Bundle savedInstanceState) { 136 super.onCreate(savedInstanceState); 137 138 ((RadioButton) findViewById(R.id.audioJavaApiBtn)).setOnClickListener(this); 139 RadioButton nativeApiRB = findViewById(R.id.audioNativeApiBtn); 140 nativeApiRB.setChecked(true); 141 nativeApiRB.setOnClickListener(this); 142 143 mStartBtn = (Button) findViewById(R.id.coldstart_start_btn); 144 mStartBtn.setOnClickListener(this); 145 mStopBtn = (Button) findViewById(R.id.coldstart_stop_btn); 146 mStopBtn.setOnClickListener(this); 147 mStopBtn.setEnabled(false); 148 149 mAttributesTxt = ((TextView) findViewById(R.id.coldstart_attributesTxt)); 150 mOpenTimeTxt = ((TextView) findViewById(R.id.coldstart_openTimeTxt)); 151 mStartTimeTxt = ((TextView) findViewById(R.id.coldstart_startTimeTxt)); 152 mLatencyTxt = (TextView) findViewById(R.id.coldstart_coldLatencyTxt); 153 mResultsTxt = (TextView) findViewById(R.id.coldstart_coldResultsTxt); 154 } 155 getRequiredTimeMS()156 abstract int getRequiredTimeMS(); getRecommendedTimeMS()157 abstract int getRecommendedTimeMS(); 158 startAudioTest()159 abstract boolean startAudioTest(); stopAudioTest()160 abstract void stopAudioTest(); 161 updateTestStateButtons()162 protected void updateTestStateButtons() { 163 mStartBtn.setEnabled(!mIsTestRunning); 164 mStopBtn.setEnabled(mIsTestRunning); 165 } 166 167 // 168 // View.OnClickListener overrides 169 // 170 @Override onClick(View v)171 public void onClick(View v) { 172 switch (v.getId()) { 173 case R.id.audioJavaApiBtn: 174 stopAudioTest(); 175 updateTestStateButtons(); 176 clearResults(); 177 mAudioApi = BuilderBase.TYPE_JAVA; 178 break; 179 180 case R.id.audioNativeApiBtn: 181 stopAudioTest(); 182 updateTestStateButtons(); 183 clearResults(); 184 mAudioApi = BuilderBase.TYPE_OBOE; 185 break; 186 187 case R.id.coldstart_start_btn: 188 startAudioTest(); 189 190 showAttributes(); 191 showOpenTime(); 192 showStartTime(); 193 194 updateTestStateButtons(); 195 break; 196 197 case R.id.coldstart_stop_btn: 198 stopAudioTest(); 199 200 updateTestStateButtons(); 201 break; 202 } 203 } 204 } 205