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