Probe AAudio nonblocking writes alongside callback output
This commit is contained in:
1 parent
43522936ff
commit
9d422dd798
2 files changed
+34
-6
No files matched your search
@@ -54,7 +54,7 @@ extern "C" JNIEXPORT void JNICALL Java_com_utun_audioprobe_ProbeActivity_closeNa
|
||||
}
|
||||
|
||||
extern "C" JNIEXPORT jboolean JNICALL Java_com_utun_audioprobe_ProbeActivity_openNative(
|
||||
JNIEnv*, jclass, jboolean exclusive, jint channels) {
|
||||
JNIEnv*, jclass, jboolean exclusive, jint channels, jboolean callback) {
|
||||
if (probe.stream || (channels != 1 && channels != 2)) {
|
||||
DEBUG_ERROR(DEBUG_CATEGORY_CALL, "probe invalid open stream=%p channels=%d", probe.stream, channels);
|
||||
return JNI_FALSE;
|
||||
@@ -70,7 +70,7 @@ extern "C" JNIEXPORT jboolean JNICALL Java_com_utun_audioprobe_ProbeActivity_ope
|
||||
AAudioStreamBuilder_setChannelCount(builder, channels);
|
||||
AAudioStreamBuilder_setSharingMode(builder, exclusive ? AAUDIO_SHARING_MODE_EXCLUSIVE : AAUDIO_SHARING_MODE_SHARED);
|
||||
AAudioStreamBuilder_setPerformanceMode(builder, AAUDIO_PERFORMANCE_MODE_LOW_LATENCY);
|
||||
AAudioStreamBuilder_setDataCallback(builder, data_callback, &probe);
|
||||
if (callback) AAudioStreamBuilder_setDataCallback(builder, data_callback, &probe);
|
||||
AAudioStreamBuilder_setErrorCallback(builder, error_callback, &probe);
|
||||
aaudio_result_t opened = AAudioStreamBuilder_openStream(builder, &probe.stream);
|
||||
check_result("delete builder", AAudioStreamBuilder_delete(builder));
|
||||
@@ -99,6 +99,12 @@ extern "C" JNIEXPORT jboolean JNICALL Java_com_utun_audioprobe_ProbeActivity_ope
|
||||
return JNI_TRUE;
|
||||
}
|
||||
|
||||
extern "C" JNIEXPORT jint JNICALL Java_com_utun_audioprobe_ProbeActivity_writeNative(JNIEnv* env, jclass, jshortArray input) {
|
||||
int16_t samples[960]{};
|
||||
env->GetShortArrayRegion(input, 0, 960, samples);
|
||||
return AAudioStream_write(probe.stream, samples, 960 / probe.channels, 0);
|
||||
}
|
||||
|
||||
/* Timestamp опрашивается вне realtime callback. Java одинаково агрегирует AAudio и AudioTrack. */
|
||||
extern "C" JNIEXPORT void JNICALL Java_com_utun_audioprobe_ProbeActivity_sampleNative(JNIEnv* env, jclass, jlongArray output) {
|
||||
if (!probe.stream || env->GetArrayLength(output) != 10) {
|
||||
|
||||
+26
-4
@@ -24,7 +24,8 @@ import java.util.concurrent.atomic.AtomicLong;
|
||||
public final class ProbeActivity extends Activity {
|
||||
private static final String TAG = "AudioProbe";
|
||||
static { System.loadLibrary("call_audio_probe"); }
|
||||
private static native boolean openNative(boolean exclusive, int channels);
|
||||
private static native boolean openNative(boolean exclusive, int channels, boolean callback);
|
||||
private static native int writeNative(short[] input);
|
||||
private static native void sampleNative(long[] out);
|
||||
private static native void closeNative();
|
||||
private volatile boolean cancelled;
|
||||
@@ -143,10 +144,31 @@ public final class ProbeActivity extends Activity {
|
||||
|
||||
private Output open(int mode, int channels) {
|
||||
if (mode == 0) return new TrackOutput();
|
||||
if (!openNative(mode == 2, channels)) throw new IllegalStateException("AAudio open rejected");
|
||||
boolean callback = getIntent().getBooleanExtra("callback", true);
|
||||
if (!openNative(mode == 2, channels, callback)) throw new IllegalStateException("AAudio open rejected");
|
||||
AtomicInteger writeError = new AtomicInteger();
|
||||
java.util.concurrent.atomic.AtomicBoolean writing = new java.util.concurrent.atomic.AtomicBoolean(!callback);
|
||||
Thread writer = new Thread(() -> {
|
||||
short[] silence = new short[960];
|
||||
try {
|
||||
while (writing.get() && !cancelled) {
|
||||
int n = writeNative(silence);
|
||||
if (n < 0) { writeError.set(n); Log.e(TAG, "AAudio write=" + n); break; }
|
||||
if (n == 0) Thread.sleep(2);
|
||||
}
|
||||
} catch (InterruptedException e) { Thread.currentThread().interrupt(); }
|
||||
}, "audio-probe-aaudio-write");
|
||||
if (!callback) writer.start();
|
||||
return new Output() {
|
||||
public void sample(long[] out) { sampleNative(out); }
|
||||
public void close() { closeNative(); }
|
||||
public void sample(long[] out) { sampleNative(out); if (writeError.get() != 0) out[7] = writeError.get(); }
|
||||
public void close() {
|
||||
writing.set(false);
|
||||
if (!callback) {
|
||||
writer.interrupt();
|
||||
try { writer.join(); } catch (InterruptedException e) { Thread.currentThread().interrupt(); Log.e(TAG, "AAudio join", e); }
|
||||
}
|
||||
closeNative();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
Reference in new issue
Block a user