blob: 697c28b1f14fed71aa00c6223cfb31a7395cc4d9 [file] [log] [blame]
/*
* Copyright 2015 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.google.sample.oboe.manualtest;
import java.io.IOException;
/**
* Base class for any audio input or output.
*/
public abstract class AudioStreamBase {
private StreamConfiguration mRequestedStreamConfiguration;
private StreamConfiguration mActualStreamConfiguration;
AudioStreamBase.DoubleStatistics mLatencyStatistics;
private int mBufferSizeInFrames;
public StreamStatus getStreamStatus() {
StreamStatus status = new StreamStatus();
status.bufferSize = getBufferSizeInFrames();
status.xRunCount = getXRunCount();
status.framesRead = getFramesRead();
status.framesWritten = getFramesWritten();
status.callbackCount = getCallbackCount();
status.latency = getLatency();
mLatencyStatistics.add(status.latency);
status.cpuLoad = getCpuLoad();
status.state = getState();
return status;
}
public DoubleStatistics getLatencyStatistics() {
return mLatencyStatistics;
}
public static class DoubleStatistics {
private double sum;
private int count;
private double minimum = Double.MAX_VALUE;
private double maximum = Double.MIN_VALUE;
void add(double latency) {
if (latency <= 0.0) return;
sum += latency;
count++;
minimum = Math.min(latency, minimum);
maximum = Math.max(latency, maximum);
}
double getAverage() {
return sum / count;
}
public String dump() {
if (count == 0) return "?";
return String.format("%3.1f/%3.1f/%3.1f ms", minimum, getAverage(), maximum);
}
}
/**
* Changes dynamic at run-time.
*/
public static class StreamStatus {
public int bufferSize;
public int xRunCount;
public long framesWritten;
public long framesRead;
public double latency; // msec
public int state;
public long callbackCount;
public int framesPerCallback;
public double cpuLoad;
// These are constantly changing.
String dump(int framesPerBurst) {
if (bufferSize < 0 || framesWritten < 0) {
return "idle";
}
StringBuffer buffer = new StringBuffer();
buffer.append("frames written " + framesWritten + " - read " + framesRead
+ " = " + (framesWritten - framesRead) + "\n");
String cpuLoadText = String.format("%2d%c", (int)(cpuLoad * 100), '%');
buffer.append(
convertStateToString(state)
+ ", #cb=" + callbackCount
+ ", f/cb=" + String.format("%3d", framesPerCallback)
+ ", " + cpuLoadText + " cpu"
+ "\n");
buffer.append("buffer size = ");
if (bufferSize < 0) {
buffer.append("?");
} else {
int numBuffers = bufferSize / framesPerBurst;
int remainder = bufferSize - (numBuffers * framesPerBurst);
buffer.append(bufferSize + " = (" + numBuffers + " * " + framesPerBurst + ") + " + remainder);
}
buffer.append(", xRun# = " + ((xRunCount < 0) ? "?" : xRunCount) + "\n");
return buffer.toString();
}
/**
* Converts ints from Oboe index to human-readable stream state
*/
private String convertStateToString(int stateId) {
final String[] STATE_ARRAY = {"Uninit.", "Unknown", "Open", "Starting", "Started",
"Pausing", "Paused", "Flushing", "Flushed",
"Stopping", "Stopped", "Closing", "Closed", "Disconn."};
if (stateId < 0 || stateId >= STATE_ARRAY.length) {
return "Invalid - " + stateId;
}
return STATE_ARRAY[stateId];
}
}
/**
*
* @param requestedConfiguration
* @param actualConfiguration
* @param bufferSizeInFrames
* @throws IOException
*/
public void open(StreamConfiguration requestedConfiguration,
StreamConfiguration actualConfiguration,
int bufferSizeInFrames) throws IOException {
mRequestedStreamConfiguration = requestedConfiguration;
mActualStreamConfiguration = actualConfiguration;
mBufferSizeInFrames = bufferSizeInFrames;
mLatencyStatistics = new AudioStreamBase.DoubleStatistics();
}
public abstract boolean isInput();
public void startPlayback() throws IOException {}
public void stopPlayback() throws IOException {}
public abstract int write(float[] buffer, int offset, int length);
public abstract void close();
public int getChannelCount() {
return mActualStreamConfiguration.getChannelCount();
}
public int getSampleRate() {
return mActualStreamConfiguration.getSampleRate();
}
public int getFramesPerBurst() {
return mActualStreamConfiguration.getFramesPerBurst();
}
public int getBufferCapacityInFrames() {
return mBufferSizeInFrames;
}
public int getBufferSizeInFrames() {
return mBufferSizeInFrames;
}
public int setBufferSizeInFrames(int bufferSize) {
throw new UnsupportedOperationException("bufferSize cannot be changed");
}
public long getCallbackCount() { return -1; }
public int getLastErrorCallbackResult() { return 0; }
public long getFramesWritten() { return -1; }
public long getFramesRead() { return -1; }
public double getLatency() { return -1.0; }
public double getCpuLoad() { return 0.0; }
public int getState() { return -1; }
public boolean isThresholdSupported() {
return false;
}
public void setWorkload(double workload) {}
public abstract int getXRunCount();
}