|
|
|
|
@ -13,6 +13,7 @@ struct Probe {
|
|
|
|
|
int channels = 0; |
|
|
|
|
std::atomic<int> error{0}, callbacks{0}, callbackFrames{0}; |
|
|
|
|
int previousError = 0; |
|
|
|
|
int previousBuffer = -1; |
|
|
|
|
}; |
|
|
|
|
static Probe probe; |
|
|
|
|
|
|
|
|
|
@ -60,6 +61,7 @@ extern "C" JNIEXPORT jboolean JNICALL Java_com_utun_audioprobe_ProbeActivity_ope
|
|
|
|
|
return JNI_FALSE; |
|
|
|
|
} |
|
|
|
|
probe.channels = channels; probe.error = 0; probe.callbacks = 0; probe.callbackFrames = 0; probe.previousError = 0; |
|
|
|
|
probe.previousBuffer = -1; |
|
|
|
|
AAudioStreamBuilder* builder = nullptr; |
|
|
|
|
if (!check_result("builder", AAudio_createStreamBuilder(&builder))) return JNI_FALSE; |
|
|
|
|
AAudioStreamBuilder_setDirection(builder, AAUDIO_DIRECTION_OUTPUT); |
|
|
|
|
@ -100,9 +102,12 @@ extern "C" JNIEXPORT jboolean JNICALL Java_com_utun_audioprobe_ProbeActivity_ope
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
extern "C" JNIEXPORT jint JNICALL Java_com_utun_audioprobe_ProbeActivity_writeNative(JNIEnv* env, jclass, jshortArray input) { |
|
|
|
|
int64_t queued = AAudioStream_getFramesWritten(probe.stream) - AAudioStream_getFramesRead(probe.stream); |
|
|
|
|
int available = int(std::max<int64_t>(0, AAudioStream_getBufferSizeInFrames(probe.stream) - queued)); |
|
|
|
|
if (!available) return AAudioStream_getState(probe.stream) == AAUDIO_STREAM_STATE_DISCONNECTED ? AAUDIO_ERROR_DISCONNECTED : 0; |
|
|
|
|
int16_t samples[960]{}; |
|
|
|
|
env->GetShortArrayRegion(input, 0, 960, samples); |
|
|
|
|
return AAudioStream_write(probe.stream, samples, 960 / probe.channels, 0); |
|
|
|
|
return AAudioStream_write(probe.stream, samples, std::min(available, 960 / probe.channels), 0); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/* Timestamp опрашивается вне realtime callback. Java одинаково агрегирует AAudio и AudioTrack. */ |
|
|
|
|
@ -111,6 +116,12 @@ extern "C" JNIEXPORT void JNICALL Java_com_utun_audioprobe_ProbeActivity_sampleN
|
|
|
|
|
DEBUG_ERROR(DEBUG_CATEGORY_CALL, "probe invalid sample"); return; |
|
|
|
|
} |
|
|
|
|
auto* s = probe.stream; |
|
|
|
|
int buffer = AAudioStream_getBufferSizeInFrames(s); |
|
|
|
|
if (buffer != probe.previousBuffer) { |
|
|
|
|
DEBUG_INFO(DEBUG_CATEGORY_CALL, "probe buffer=%d capacity=%d written=%lld read=%lld", buffer, |
|
|
|
|
AAudioStream_getBufferCapacityInFrames(s), (long long)AAudioStream_getFramesWritten(s), (long long)AAudioStream_getFramesRead(s)); |
|
|
|
|
probe.previousBuffer = buffer; |
|
|
|
|
} |
|
|
|
|
int64_t frame = -1, stamp = -1; |
|
|
|
|
int64_t written = AAudioStream_getFramesWritten(s); |
|
|
|
|
int result = AAudioStream_getTimestamp(s, CLOCK_MONOTONIC, &frame, &stamp); |
|
|
|
|
|