1 /* 2 * Copyright 2015 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.mobileer.oboetester; 18 19 import java.io.IOException; 20 21 /** 22 * Base class for any audio input or output. 23 */ 24 public abstract class AudioStreamBase { 25 26 private StreamConfiguration mRequestedStreamConfiguration; 27 private StreamConfiguration mActualStreamConfiguration; 28 AudioStreamBase.DoubleStatistics mLatencyStatistics; 29 30 private int mBufferSizeInFrames; 31 getStreamStatus()32 public StreamStatus getStreamStatus() { 33 StreamStatus status = new StreamStatus(); 34 status.bufferSize = getBufferSizeInFrames(); 35 status.xRunCount = getXRunCount(); 36 status.framesRead = getFramesRead(); 37 status.framesWritten = getFramesWritten(); 38 status.callbackCount = getCallbackCount(); 39 status.latency = getLatency(); 40 mLatencyStatistics.add(status.latency); 41 status.callbackTimeStr = getCallbackTimeStr(); 42 status.cpuLoad = getCpuLoad(); 43 status.state = getState(); 44 return status; 45 } 46 getLatencyStatistics()47 public DoubleStatistics getLatencyStatistics() { 48 return mLatencyStatistics; 49 } 50 51 public static class DoubleStatistics { 52 private double sum; 53 private int count; 54 private double minimum = Double.MAX_VALUE; 55 private double maximum = Double.MIN_VALUE; 56 add(double statistic)57 void add(double statistic) { 58 if (statistic <= 0.0) return; 59 sum += statistic; 60 count++; 61 minimum = Math.min(statistic, minimum); 62 maximum = Math.max(statistic, maximum); 63 } 64 getAverage()65 double getAverage() { 66 return sum / count; 67 } 68 dump()69 public String dump() { 70 if (count == 0) return "?"; 71 return String.format("%3.1f/%3.1f/%3.1f ms", minimum, getAverage(), maximum); 72 } 73 } 74 75 /** 76 * Changes dynamic at run-time. 77 */ 78 public static class StreamStatus { 79 public int bufferSize; 80 public int xRunCount; 81 public long framesWritten; 82 public long framesRead; 83 public double latency; // msec 84 public int state; 85 public long callbackCount; 86 public int framesPerCallback; 87 public double cpuLoad; 88 public String callbackTimeStr; 89 90 // These are constantly changing. dump(int framesPerBurst)91 String dump(int framesPerBurst) { 92 if (bufferSize < 0 || framesWritten < 0) { 93 return "idle"; 94 } 95 StringBuffer buffer = new StringBuffer(); 96 97 buffer.append("time between callbacks = " + callbackTimeStr + "\n"); 98 99 buffer.append("written " 100 + String.format("0x%08X", framesWritten) 101 + " - read " + String.format("0x%08X", framesRead) 102 + " = " + (framesWritten - framesRead) + " frames\n"); 103 104 String cpuLoadText = String.format("%2d%c", (int)(cpuLoad * 100), '%'); 105 buffer.append( 106 convertStateToString(state) 107 + ", #cb=" + callbackCount 108 + ", f/cb=" + String.format("%3d", framesPerCallback) 109 + ", " + cpuLoadText + " cpu" 110 + "\n"); 111 112 buffer.append("buffer size = "); 113 if (bufferSize < 0) { 114 buffer.append("?"); 115 } else { 116 int numBuffers = bufferSize / framesPerBurst; 117 int remainder = bufferSize - (numBuffers * framesPerBurst); 118 buffer.append(bufferSize + " = (" + numBuffers + " * " + framesPerBurst + ") + " + remainder); 119 } 120 buffer.append(", xRun# = " + ((xRunCount < 0) ? "?" : xRunCount)); 121 122 return buffer.toString(); 123 } 124 /** 125 * Converts ints from Oboe index to human-readable stream state 126 */ convertStateToString(int stateId)127 private String convertStateToString(int stateId) { 128 final String[] STATE_ARRAY = {"Uninit.", "Unknown", "Open", "Starting", "Started", 129 "Pausing", "Paused", "Flushing", "Flushed", 130 "Stopping", "Stopped", "Closing", "Closed", "Disconn."}; 131 if (stateId < 0 || stateId >= STATE_ARRAY.length) { 132 return "Invalid - " + stateId; 133 } 134 return STATE_ARRAY[stateId]; 135 } 136 } 137 138 /** 139 * 140 * @param requestedConfiguration 141 * @param actualConfiguration 142 * @param bufferSizeInFrames 143 * @throws IOException 144 */ open(StreamConfiguration requestedConfiguration, StreamConfiguration actualConfiguration, int bufferSizeInFrames)145 public void open(StreamConfiguration requestedConfiguration, 146 StreamConfiguration actualConfiguration, 147 int bufferSizeInFrames) throws IOException { 148 mRequestedStreamConfiguration = requestedConfiguration; 149 mActualStreamConfiguration = actualConfiguration; 150 mBufferSizeInFrames = bufferSizeInFrames; 151 mLatencyStatistics = new AudioStreamBase.DoubleStatistics(); 152 } 153 isInput()154 public abstract boolean isInput(); 155 startPlayback()156 public void startPlayback() throws IOException {} 157 stopPlayback()158 public void stopPlayback() throws IOException {} 159 write(float[] buffer, int offset, int length)160 public abstract int write(float[] buffer, int offset, int length); 161 close()162 public abstract void close(); 163 getChannelCount()164 public int getChannelCount() { 165 return mActualStreamConfiguration.getChannelCount(); 166 } 167 getSampleRate()168 public int getSampleRate() { 169 return mActualStreamConfiguration.getSampleRate(); 170 } 171 getFramesPerBurst()172 public int getFramesPerBurst() { 173 return mActualStreamConfiguration.getFramesPerBurst(); 174 } 175 getBufferCapacityInFrames()176 public int getBufferCapacityInFrames() { 177 return mBufferSizeInFrames; 178 } 179 getBufferSizeInFrames()180 public int getBufferSizeInFrames() { 181 return mBufferSizeInFrames; 182 } 183 setBufferSizeInFrames(int bufferSize)184 public int setBufferSizeInFrames(int bufferSize) { 185 throw new UnsupportedOperationException("bufferSize cannot be changed"); 186 } 187 getCallbackCount()188 public long getCallbackCount() { return -1; } 189 getLastErrorCallbackResult()190 public int getLastErrorCallbackResult() { return 0; } 191 getFramesWritten()192 public long getFramesWritten() { return -1; } 193 getFramesRead()194 public long getFramesRead() { return -1; } 195 getLatency()196 public double getLatency() { return -1.0; } 197 getCpuLoad()198 public double getCpuLoad() { return 0.0; } 199 getCallbackTimeStr()200 public String getCallbackTimeStr() { return "?"; }; 201 getState()202 public int getState() { return -1; } 203 isThresholdSupported()204 public boolean isThresholdSupported() { 205 return false; 206 } 207 setWorkload(double workload)208 public void setWorkload(double workload) {} 209 getXRunCount()210 public abstract int getXRunCount(); 211 212 } 213