Browse Source

Expose source codec selection and aggregate send telemetry through JNI

master
evgeny 6 days ago
parent
commit
cd8a5392d5
  1. 2
      src/Makefile.am
  2. 14
      tools/chatgui-android/app/src/main/java/com/utun/chat/data/NativeLib.kt
  3. 23
      tools/chatgui-android/jni_bridge/android_stream_jni.c

2
src/Makefile.am

@ -186,6 +186,8 @@ utun_CORE_SOURCES = \
# libutun: all core sources except main() # libutun: all core sources except main()
libutun_a_SOURCES = \ libutun_a_SOURCES = \
transport_layer/etcp_tx_stats.c \
transport_layer/etcp_tx_stats.h \
$(stream_core_files) \ $(stream_core_files) \
utun_instance.c \ utun_instance.c \
config_parser.c \ config_parser.c \

14
tools/chatgui-android/app/src/main/java/com/utun/chat/data/NativeLib.kt

@ -200,12 +200,13 @@ object NativeLib {
/* Live media используют отдельную ограниченную очередь, минуя чатовый event bus. */ /* Live media используют отдельную ограниченную очередь, минуя чатовый event bus. */
fun streamOpen(id: Long, group: Long, source: Long = 0, width: Int = 0, height: Int = 0, fun streamOpen(id: Long, group: Long, source: Long = 0, width: Int = 0, height: Int = 0,
rotation: Int = 0, audio: Boolean = true, epoch: Long = 0): Boolean = rotation: Int = 0, audio: Boolean = true, epoch: Long = 0, videoCodec: Int = 1): Boolean =
nativeStreamOpen(id, group, source, width, height, rotation, audio, epoch) nativeStreamOpen(id, group, source, width, height, rotation, audio, epoch, videoCodec)
fun streamWatch(group: Long): Boolean = nativeStreamWatch(group) fun streamWatch(group: Long): Boolean = nativeStreamWatch(group)
fun streamFeed(id: Long, video: Boolean, pts: Long, key: Boolean, data: ByteArray, revision: Long = 0, fun streamFeed(id: Long, video: Boolean, pts: Long, key: Boolean, data: ByteArray, revision: Long = 0,
width: Int = 0, height: Int = 0, rotation: Int = 0, audio: Boolean = true): Int = width: Int = 0, height: Int = 0, rotation: Int = 0, audio: Boolean = true, videoCodec: Int = 1): Int =
nativeStreamFeed(id, video, pts, key, data, revision, width, height, rotation, audio) nativeStreamFeed(id, video, pts, key, data, revision, width, height, rotation, audio, videoCodec)
fun streamTxStats(id: Long): LongArray? = nativeStreamTxStats(id)
fun streamStop(id: Long) { nativeStreamStop(id) } fun streamStop(id: Long) { nativeStreamStop(id) }
fun streamPull(id: Long, positionUs: Long = -1, videoAheadUs: Long = 80000, audioAheadUs: Long = 80000): ByteArray? = fun streamPull(id: Long, positionUs: Long = -1, videoAheadUs: Long = 80000, audioAheadUs: Long = 80000): ByteArray? =
nativeStreamPull(id, positionUs, videoAheadUs, audioAheadUs) nativeStreamPull(id, positionUs, videoAheadUs, audioAheadUs)
@ -225,10 +226,11 @@ object NativeLib {
fun streamOpusDecode(handle: Long, packet: ByteArray): ShortArray? = nativeStreamOpusDecode(handle, packet) fun streamOpusDecode(handle: Long, packet: ByteArray): ShortArray? = nativeStreamOpusDecode(handle, packet)
fun streamOpusClose(handle: Long) { nativeStreamOpusClose(handle) } fun streamOpusClose(handle: Long) { nativeStreamOpusClose(handle) }
private external fun nativeStreamOpen(id: Long, group: Long, source: Long, width: Int, height: Int, rotation: Int, private external fun nativeStreamOpen(id: Long, group: Long, source: Long, width: Int, height: Int, rotation: Int,
audio: Boolean, epoch: Long): Boolean audio: Boolean, epoch: Long, videoCodec: Int): Boolean
private external fun nativeStreamWatch(group: Long): Boolean private external fun nativeStreamWatch(group: Long): Boolean
private external fun nativeStreamFeed(id: Long, video: Boolean, pts: Long, key: Boolean, data: ByteArray, private external fun nativeStreamFeed(id: Long, video: Boolean, pts: Long, key: Boolean, data: ByteArray,
revision: Long, width: Int, height: Int, rotation: Int, audio: Boolean): Int revision: Long, width: Int, height: Int, rotation: Int, audio: Boolean, videoCodec: Int): Int
private external fun nativeStreamTxStats(id: Long): LongArray?
private external fun nativeStreamStop(id: Long) private external fun nativeStreamStop(id: Long)
private external fun nativeStreamPull(id: Long, position: Long, videoAhead: Long, audioAhead: Long): ByteArray? private external fun nativeStreamPull(id: Long, position: Long, videoAhead: Long, audioAhead: Long): ByteArray?
private external fun nativeStreamStatus(id: Long): LongArray? private external fun nativeStreamStatus(id: Long): LongArray?

23
tools/chatgui-android/jni_bridge/android_stream_jni.c

@ -26,9 +26,9 @@ struct android_stream_opus {
}; };
JNIEXPORT jboolean JNICALL Java_com_utun_chat_data_NativeLib_nativeStreamOpen( JNIEXPORT jboolean JNICALL Java_com_utun_chat_data_NativeLib_nativeStreamOpen(
JNIEnv *env, jobject obj, jlong id, jlong group, jlong source, jint width, jint height, jint rotation, jboolean audio, jlong epoch) { JNIEnv *env, jobject obj, jlong id, jlong group, jlong source, jint width, jint height, jint rotation, jboolean audio, jlong epoch, jint codec) {
(void)env; (void)obj; (void)env; (void)obj;
return android_stream_open((uint64_t)id, (uint64_t)group, (uint64_t)source, width, height, rotation, audio, (uint64_t)epoch) == 0; return android_stream_open((uint64_t)id, (uint64_t)group, (uint64_t)source, width, height, rotation, audio, (uint64_t)epoch, codec) == 0;
} }
JNIEXPORT jboolean JNICALL Java_com_utun_chat_data_NativeLib_nativeStreamWatch(JNIEnv *env, jobject obj, jlong group) { JNIEXPORT jboolean JNICALL Java_com_utun_chat_data_NativeLib_nativeStreamWatch(JNIEnv *env, jobject obj, jlong group) {
@ -38,7 +38,7 @@ JNIEXPORT jboolean JNICALL Java_com_utun_chat_data_NativeLib_nativeStreamWatch(J
JNIEXPORT jint JNICALL Java_com_utun_chat_data_NativeLib_nativeStreamFeed( JNIEXPORT jint JNICALL Java_com_utun_chat_data_NativeLib_nativeStreamFeed(
JNIEnv *env, jobject obj, jlong id, jboolean video, jlong pts, jboolean key, jbyteArray data, JNIEnv *env, jobject obj, jlong id, jboolean video, jlong pts, jboolean key, jbyteArray data,
jlong revision, jint width, jint height, jint rotation, jboolean audio) { jlong revision, jint width, jint height, jint rotation, jboolean audio, jint video_codec) {
(void)obj; (void)obj;
if (!data || pts < 0 || (video && (revision <= 0 || revision > UINT32_MAX || width <= 0 || width > 4096 if (!data || pts < 0 || (video && (revision <= 0 || revision > UINT32_MAX || width <= 0 || width > 4096
|| height <= 0 || height > 4096 || rotation < 0 || rotation > 270 || rotation % 90))) { DEBUG_ERROR(DEBUG_CATEGORY_STREAM, "JNI stream feed missing data/invalid PTS"); return -1; } || height <= 0 || height > 4096 || rotation < 0 || rotation > 270 || rotation % 90))) { DEBUG_ERROR(DEBUG_CATEGORY_STREAM, "JNI stream feed missing data/invalid PTS"); return -1; }
@ -46,7 +46,11 @@ JNIEXPORT jint JNICALL Java_com_utun_chat_data_NativeLib_nativeStreamFeed(
jbyte *bytes = (*env)->GetByteArrayElements(env, data, NULL); jbyte *bytes = (*env)->GetByteArrayElements(env, data, NULL);
if (!bytes) { DEBUG_ERROR(DEBUG_CATEGORY_STREAM, "JNI stream feed array access failed"); return -1; } if (!bytes) { DEBUG_ERROR(DEBUG_CATEGORY_STREAM, "JNI stream feed array access failed"); return -1; }
struct stream_media_format format = {(uint16_t)width, (uint16_t)height, (uint16_t)rotation, struct stream_media_format format = {(uint16_t)width, (uint16_t)height, (uint16_t)rotation,
STREAM_MEDIA_H264, audio ? STREAM_MEDIA_OPUS_STEREO : 0, (uint32_t)revision}; (uint8_t)video_codec, audio ? STREAM_MEDIA_OPUS_STEREO : 0, (uint32_t)revision};
if (video && (video_codec < STREAM_MEDIA_H264 || video_codec > STREAM_MEDIA_H266)) {
DEBUG_ERROR(DEBUG_CATEGORY_STREAM, "JNI video codec invalid id=%d", video_codec);
(*env)->ReleaseByteArrayElements(env, data, bytes, JNI_ABORT); return -1;
}
int result = android_stream_feed((uint64_t)id, video, (uint64_t)pts, key, (const uint8_t *)bytes, (size_t)length, video ? &format : NULL); int result = android_stream_feed((uint64_t)id, video, (uint64_t)pts, key, (const uint8_t *)bytes, (size_t)length, video ? &format : NULL);
(*env)->ReleaseByteArrayElements(env, data, bytes, JNI_ABORT); (*env)->ReleaseByteArrayElements(env, data, bytes, JNI_ABORT);
return result; return result;
@ -56,6 +60,17 @@ JNIEXPORT void JNICALL Java_com_utun_chat_data_NativeLib_nativeStreamStop(JNIEnv
(void)env; (void)obj; android_stream_stop((uint64_t)id); (void)env; (void)obj; android_stream_stop((uint64_t)id);
} }
JNIEXPORT jlongArray JNICALL Java_com_utun_chat_data_NativeLib_nativeStreamTxStats(JNIEnv *env, jobject obj, jlong id) {
(void)obj; struct android_stream_tx_stats s;
if (android_stream_tx_snapshot((uint64_t)id, &s) < 0) return NULL;
jlong values[] = {s.sample_us, s.video_bytes, s.audio_bytes, s.stream_bytes, s.transport_bytes,
s.inflight_bytes, s.acked_1s, s.total_bytes, s.connections};
jlongArray result = (*env)->NewLongArray(env, 9);
if (result) (*env)->SetLongArrayRegion(env, result, 0, 9, values);
else DEBUG_ERROR(DEBUG_CATEGORY_STREAM, "JNI TX stats allocation failed");
return result;
}
JNIEXPORT jbyteArray JNICALL Java_com_utun_chat_data_NativeLib_nativeStreamPull( JNIEXPORT jbyteArray JNICALL Java_com_utun_chat_data_NativeLib_nativeStreamPull(
JNIEnv *env, jobject obj, jlong id, jlong position, jlong video_ahead, jlong audio_ahead) { JNIEnv *env, jobject obj, jlong id, jlong position, jlong video_ahead, jlong audio_ahead) {
(void)obj; (void)obj;

Loading…
Cancel
Save