diff --git a/tools/chatgui-android/app/src/main/java/com/utun/chat/data/NativeLib.kt b/tools/chatgui-android/app/src/main/java/com/utun/chat/data/NativeLib.kt index fab94f02..b94dd939 100644 --- a/tools/chatgui-android/app/src/main/java/com/utun/chat/data/NativeLib.kt +++ b/tools/chatgui-android/app/src/main/java/com/utun/chat/data/NativeLib.kt @@ -266,8 +266,11 @@ object NativeLib { /* ── P2P аудио-звонок (медиа) ── */ fun callAudioStart(callId: Long): Boolean = nativeCallAudioStart(callId) - fun callAudioFeed(callId: Long, samples: ShortArray): Boolean = nativeCallAudioFeed(callId, samples) + fun callAudioFeed(callId: Long, samples: ShortArray, capturePtsUs: Long): Boolean = nativeCallAudioFeed(callId, samples, capturePtsUs) fun callAudioPull(callId: Long, out: ShortArray): Int = nativeCallAudioPull(callId, out) + fun callAudioProgress(callId: Long, epoch: Long, position: Long, nowUs: Long) = nativeCallAudioProgress(callId, epoch, position, nowUs) + /** out: epoch, source_epoch, played, written, pts_us, valid, measured, held_back_us. */ + fun callAudioClock(callId: Long, nowUs: Long, out: LongArray): Boolean = nativeCallAudioClock(callId, nowUs, out) fun callAudioStop() { nativeCallAudioStop() } /* AEC (эхоподавление): включается по спикерфону; delay — измеренная задержка в кадрах. */ @@ -397,8 +400,10 @@ object NativeLib { private external fun nativeCallHangup(callId: Long) private external fun nativeCallIsOnline(channelId: String, peerNodeId: Long): Boolean private external fun nativeCallAudioStart(callId: Long): Boolean - private external fun nativeCallAudioFeed(callId: Long, samples: ShortArray): Boolean + private external fun nativeCallAudioFeed(callId: Long, samples: ShortArray, capturePtsUs: Long): Boolean private external fun nativeCallAudioPull(callId: Long, out: ShortArray): Int + private external fun nativeCallAudioProgress(callId: Long, epoch: Long, position: Long, nowUs: Long) + private external fun nativeCallAudioClock(callId: Long, nowUs: Long, out: LongArray): Boolean private external fun nativeCallAudioStop() private external fun nativeCallAudioSetAec(enabled: Boolean) private external fun nativeCallAudioSetAecDelay(frames: Int) diff --git a/tools/chatgui-android/jni_bridge/android_jni_bridge.c b/tools/chatgui-android/jni_bridge/android_jni_bridge.c index 6ca893ee..4548088d 100644 --- a/tools/chatgui-android/jni_bridge/android_jni_bridge.c +++ b/tools/chatgui-android/jni_bridge/android_jni_bridge.c @@ -1579,8 +1579,8 @@ int utun_bridge_call_audio_start(uint64_t call_id) { return call_audio_start(call_id); } -int utun_bridge_call_audio_feed(uint64_t call_id, const int16_t* pcm, int count) { - return call_audio_feed_pcm(call_id, pcm, count); +int utun_bridge_call_audio_feed(uint64_t call_id, const int16_t* pcm, int count, int64_t capture_pts_us) { + return call_audio_feed_pcm(call_id, pcm, count, capture_pts_us); } void utun_bridge_call_audio_stop(void) { @@ -2664,12 +2664,19 @@ JNIEXPORT jboolean JNICALL Java_com_utun_chat_data_NativeLib_nativeCallAudioStar } JNIEXPORT jboolean JNICALL Java_com_utun_chat_data_NativeLib_nativeCallAudioFeed( - JNIEnv* env, jobject thiz, jlong callId, jshortArray samples) { - (void)env; (void)thiz; - if (!samples) return JNI_FALSE; + JNIEnv* env, jobject thiz, jlong callId, jshortArray samples, jlong capturePtsUs) { + (void)thiz; + if (!samples) { + DEBUG_ERROR(DEBUG_CATEGORY_CALL, "call capture: null PCM"); + return JNI_FALSE; + } jsize len = (*env)->GetArrayLength(env, samples); jshort* data = (*env)->GetShortArrayElements(env, samples, NULL); - int rc = utun_bridge_call_audio_feed((uint64_t)callId, (const int16_t*)data, (int)len); + if (!data) { + DEBUG_ERROR(DEBUG_CATEGORY_CALL, "call capture: JNI PCM access failed"); + return JNI_FALSE; + } + int rc = utun_bridge_call_audio_feed((uint64_t)callId, (const int16_t*)data, (int)len, capturePtsUs); (*env)->ReleaseShortArrayElements(env, samples, data, JNI_ABORT); return (rc == 0) ? JNI_TRUE : JNI_FALSE; } @@ -2680,6 +2687,32 @@ JNIEXPORT void JNICALL Java_com_utun_chat_data_NativeLib_nativeCallAudioStop( utun_bridge_call_audio_stop(); } +JNIEXPORT void JNICALL Java_com_utun_chat_data_NativeLib_nativeCallAudioProgress( + JNIEnv* env, jobject thiz, jlong callId, jlong epoch, jlong position, jlong nowUs) { + (void)env; (void)thiz; + call_audio_playback_progress(callId, epoch, position, nowUs, nowUs, 0); +} + +/* Предвыделенный снимок: epoch, source_epoch, played, written, pts, valid, measured, held_back_us. */ +JNIEXPORT jboolean JNICALL Java_com_utun_chat_data_NativeLib_nativeCallAudioClock( + JNIEnv* env, jobject thiz, jlong callId, jlong nowUs, jlongArray out) { + (void)thiz; + if (!out || (*env)->GetArrayLength(env, out) != 8) { + DEBUG_ERROR(DEBUG_CATEGORY_CALL, "call clock: expected LongArray(8)"); + return JNI_FALSE; + } + struct call_clock_snapshot s; + if (call_audio_get_clock(callId, nowUs, &s) != 0) return JNI_FALSE; + jlong values[8] = {s.epoch, s.source_epoch, s.played_samples, s.written_samples, + s.pts_us, s.valid, s.measured, s.held_back_us}; + (*env)->SetLongArrayRegion(env, out, 0, 8, values); + if ((*env)->ExceptionCheck(env)) { + DEBUG_ERROR(DEBUG_CATEGORY_CALL, "call clock: JNI snapshot copy failed"); + return JNI_FALSE; + } + return JNI_TRUE; +} + /* ── nativeCallAudioPull(callId, out) → возвращает число сэмплов ── * out — предвыделенный ShortArray (960), заполняется из аудио-потока Kotlin. */ JNIEXPORT jint JNICALL Java_com_utun_chat_data_NativeLib_nativeCallAudioPull( diff --git a/tools/chatgui-android/jni_bridge/android_jni_bridge.h b/tools/chatgui-android/jni_bridge/android_jni_bridge.h index 7f23b9f3..5dca214c 100644 --- a/tools/chatgui-android/jni_bridge/android_jni_bridge.h +++ b/tools/chatgui-android/jni_bridge/android_jni_bridge.h @@ -132,7 +132,7 @@ int utun_bridge_call_is_online(const char* ch_id, uint64_t peer_node_id); /* Аудио-движок звонка (call_audio.c, единый голосовой стек): PCM из AudioRecord → * Opus → peer (feed); принятый Opus → джиттер+декод+stretch → PCM (pull). */ int utun_bridge_call_audio_start(uint64_t call_id); -int utun_bridge_call_audio_feed(uint64_t call_id, const int16_t* pcm, int count); +int utun_bridge_call_audio_feed(uint64_t call_id, const int16_t* pcm, int count, int64_t capture_pts_us); int utun_bridge_call_audio_pull(uint64_t call_id, int16_t* out, int max_samples); void utun_bridge_call_audio_stop(void);