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 ce7021be..12cbe8ef 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 @@ -207,6 +207,7 @@ object NativeLib { 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, videoCodec) fun streamTxStats(id: Long): LongArray? = nativeStreamTxStats(id) + fun streamSetAudioEnabled(id: Long, enabled: Boolean): Boolean = nativeStreamSetAudioEnabled(id, enabled) fun streamStop(id: Long) { nativeStreamStop(id) } fun streamPull(id: Long, positionUs: Long = -1, wantVideo: Boolean = true, audioAheadUs: Long = 80000): ByteArray? = nativeStreamPull(id, positionUs, wantVideo, audioAheadUs) @@ -231,6 +232,7 @@ object NativeLib { private external fun nativeStreamFeed(id: Long, video: Boolean, pts: Long, key: Boolean, data: ByteArray, revision: Long, width: Int, height: Int, rotation: Int, audio: Boolean, videoCodec: Int): Int private external fun nativeStreamTxStats(id: Long): LongArray? + private external fun nativeStreamSetAudioEnabled(id: Long, enabled: Boolean): Boolean private external fun nativeStreamStop(id: Long) private external fun nativeStreamPull(id: Long, position: Long, wantVideo: Boolean, audioAhead: Long): ByteArray? private external fun nativeStreamStatus(id: Long): LongArray? diff --git a/tools/chatgui-android/app/src/main/java/com/utun/chat/data/StreamCaptureEngine.kt b/tools/chatgui-android/app/src/main/java/com/utun/chat/data/StreamCaptureEngine.kt index 3e788175..b68ad3d2 100644 --- a/tools/chatgui-android/app/src/main/java/com/utun/chat/data/StreamCaptureEngine.kt +++ b/tools/chatgui-android/app/src/main/java/com/utun/chat/data/StreamCaptureEngine.kt @@ -44,6 +44,7 @@ class StreamCaptureEngine( private var audioCapture: MicrophoneCapture.Subscription? = null private var audioThread: Thread? = null @Volatile private var audioRunning = false + @Volatile private var audioMuted = false @Volatile var audioCompressorSettings = initialAudioCompressor @Volatile private var stopped = false private var stopping = false @@ -434,6 +435,21 @@ class StreamCaptureEngine( LogManager.addLog("DEBUG", "video", "video resources released id=$id closed=$closed revision=$generation") done(closed) } + /** Меняем только свою копию PCM; общий микрофон и рация продолжают работать. */ + fun setAudioEnabled(enabled: Boolean): Boolean { + if (!microphone || !audioRunning) { + LogManager.addLog("WARN", "stream", "audio change without capture id=$id enabled=$enabled"); return false + } + val previous = audioMuted + audioMuted = !enabled + if (!NativeLib.streamSetAudioEnabled(id, enabled)) { + audioMuted = previous + LogManager.addLog("ERROR", "stream", "audio change refused id=$id enabled=$enabled"); return false + } + LogManager.addLog("INFO", "stream", "source audio id=$id enabled=$enabled") + return true + } + @SuppressLint("MissingPermission") private fun startAudio() { val radio = RadioAudioEngine.instance() @@ -464,6 +480,7 @@ class StreamCaptureEngine( expected = frame.sequence + 960 val pts = (frame.timeNs - originNs) / 1000 check(pts >= 0 && pts > last) { "Audio timestamp discontinuity pts=$pts last=$last" }; last = pts + if (audioMuted) frame.pcm.fill(0) val packet = NativeLib.streamOpusEncode(opus, frame.pcm, audioCompressorSettings) ?: error("Stream compressor/Opus encode failed") check(NativeLib.streamFeed(id, false, pts, false, packet) >= 0) { "Stream audio publisher detached" } } diff --git a/tools/chatgui-android/app/src/main/java/com/utun/chat/data/StreamService.kt b/tools/chatgui-android/app/src/main/java/com/utun/chat/data/StreamService.kt index e6512931..76f33d84 100644 --- a/tools/chatgui-android/app/src/main/java/com/utun/chat/data/StreamService.kt +++ b/tools/chatgui-android/app/src/main/java/com/utun/chat/data/StreamService.kt @@ -108,6 +108,13 @@ class StreamService : Service() { capture!!.change(config) } + fun setAudioEnabled(enabled: Boolean): Boolean { + if (stopping || capture == null) { + LogManager.addLog("WARN", "stream", "service audio change rejected id=$id"); return false + } + return capture!!.setAudioEnabled(enabled) + } + /** Producers завершатся до FIN; при уничтожении ядра очередь не ждём. */ fun shutdown(abort: Boolean = false) { aborting = aborting || abort