Browse Source

Pass call audio timing across Android JNI

master
evgeny 5 days ago
parent
commit
023f3a335e
  1. 9
      tools/chatgui-android/app/src/main/java/com/utun/chat/data/NativeLib.kt
  2. 45
      tools/chatgui-android/jni_bridge/android_jni_bridge.c
  3. 2
      tools/chatgui-android/jni_bridge/android_jni_bridge.h

9
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)

45
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(

2
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);

Loading…
Cancel
Save