From 97f1eaa0487b0e70d88b47ae42508ea0f3cd425b Mon Sep 17 00:00:00 2001 From: evgeny Date: Thu, 29 Oct 2026 00:43:59 +0100 Subject: [PATCH] Clarify stream grid and PCM timeline contracts without per-record allocations --- .../src/main/java/com/utun/chat/data/StreamAudioMix.kt | 9 +++++++-- .../src/main/java/com/utun/chat/data/StreamGridLayout.kt | 4 +++- .../src/main/java/com/utun/chat/data/StreamReadQueue.kt | 3 ++- 3 files changed, 12 insertions(+), 4 deletions(-) diff --git a/tools/chatgui-android/app/src/main/java/com/utun/chat/data/StreamAudioMix.kt b/tools/chatgui-android/app/src/main/java/com/utun/chat/data/StreamAudioMix.kt index 3e28cafd..23e602d4 100644 --- a/tools/chatgui-android/app/src/main/java/com/utun/chat/data/StreamAudioMix.kt +++ b/tools/chatgui-android/app/src/main/java/com/utun/chat/data/StreamAudioMix.kt @@ -5,7 +5,9 @@ import kotlin.math.max import kotlin.math.min import kotlin.math.roundToInt -/** Начало отдельного источника на шкале общего AudioTrack. PTS источников здесь не сравниваются. */ +/** Worker-локальное начало источника на шкале AudioTrack, позиции/count — PCM frames, не stereo samples. + * append требует непрерывные порции, включая тишину источника; первый append фиксирует origin. + * played переводит общий head в локальные [0, frames]. Новая шкала требует нового экземпляра, PTS здесь не сравниваются. */ internal class StreamMixTimeline { var origin = -1L private set @@ -23,7 +25,10 @@ internal class StreamMixTimeline { } /** Одна порция stereo 48k. Тихий новый участник не снижает громкость остальных. - * Буфер output переиспользуется только после полной записи предыдущей порции устройством. */ + * frames=480 по умолчанию (10 мс), count у add — только подготовленный prefix PCM. + * fadeFrames=0..480 задаёт фазу 10 мс fade-in; add возвращает обновлённую фазу. + * clear очищает сумму, сохраняя состояние stereo limiter; finish возвращает переиспользуемый буфер, + * который разрешено менять только после полной записи предыдущей порции устройством. */ internal class StreamMixBuffer(val frames: Int = 480) { private val sum = FloatArray(frames * 2) private val output = ShortArray(frames * 2) diff --git a/tools/chatgui-android/app/src/main/java/com/utun/chat/data/StreamGridLayout.kt b/tools/chatgui-android/app/src/main/java/com/utun/chat/data/StreamGridLayout.kt index 1754835d..a9645f80 100644 --- a/tools/chatgui-android/app/src/main/java/com/utun/chat/data/StreamGridLayout.kt +++ b/tools/chatgui-android/app/src/main/java/com/utun/chat/data/StreamGridLayout.kt @@ -4,7 +4,9 @@ import kotlin.math.min internal data class StreamGridShape(val columns: Int, val rows: Int) -/** Максимизирует видимую площадь видео; портретный экран не принуждается к квадратной сетке. */ +/** Выбрать сетку для count одинаковых видео: максимальная суммарная площадь при заданном aspect. + * При равной площади выбирает меньше пустых ячеек; размеры/aspect — конечные, aspect > 0. + * Неположительные count/размеры дают 1x1. Возвращает только форму, без UI размеров/зазоров. */ internal fun streamGridShape(count: Int, width: Double, height: Double, aspect: Double = 16.0 / 9): StreamGridShape { if (count <= 0 || width <= 0 || height <= 0) return StreamGridShape(1, 1) var best = StreamGridShape(1, count) diff --git a/tools/chatgui-android/app/src/main/java/com/utun/chat/data/StreamReadQueue.kt b/tools/chatgui-android/app/src/main/java/com/utun/chat/data/StreamReadQueue.kt index 42a91e56..84ed1d9d 100644 --- a/tools/chatgui-android/app/src/main/java/com/utun/chat/data/StreamReadQueue.kt +++ b/tools/chatgui-android/app/src/main/java/com/utun/chat/data/StreamReadQueue.kt @@ -29,7 +29,8 @@ internal class StreamReadQueue { input.position(start + 28 + length) } for (record in parsed) { - if (record[0].toInt() in listOf(3, 6)) records.clear() + val kind = record[0].toInt() + if (kind == 3 || kind == 6) records.clear() records.add(record) } return parsed.size