From 22b62699ac0ecf47d4127880f06c9e8c59056bd6 Mon Sep 17 00:00:00 2001 From: evgeny Date: Tue, 13 Oct 2026 14:14:24 +0200 Subject: [PATCH] Describe stereo Opus in live media blocks --- src/stream/stream_media.c | 4 ++-- src/stream/stream_media.h | 3 ++- tools/chatgui-android/libutun_lite/stream_bridge.c | 2 +- 3 files changed, 5 insertions(+), 4 deletions(-) diff --git a/src/stream/stream_media.c b/src/stream/stream_media.c index ed5a8a58..6ac28bea 100644 --- a/src/stream/stream_media.c +++ b/src/stream/stream_media.c @@ -19,7 +19,7 @@ struct stream_media_receiver { static int media_validate(const struct stream_media_block *b, size_t *video_size, size_t *audio_size, uint32_t *first) { if (!b || b->video_count > STREAM_MEDIA_MAX_ENTRIES || b->audio_count > STREAM_MEDIA_MAX_ENTRIES || !b->format.revision || (!b->video_count && !b->audio_count) || b->format.video_codec != STREAM_MEDIA_H264 - || b->format.audio_codec > STREAM_MEDIA_OPUS || !b->format.width || b->format.width > 4096 + || b->format.audio_codec > STREAM_MEDIA_OPUS_STEREO || !b->format.width || b->format.width > 4096 || !b->format.height || b->format.height > 4096 || b->format.rotation > 270 || b->format.rotation % 90) { DEBUG_ERROR(DEBUG_CATEGORY_STREAM, "media format/count invalid present=%d video=%u audio=%u codecs=%u/%u dimensions=%ux%u rotation=%u", b != NULL, b ? b->video_count : 0, b ? b->audio_count : 0, b ? b->format.video_codec : 0, @@ -54,7 +54,7 @@ static int media_validate(const struct stream_media_block *b, size_t *video_size } for (unsigned i = 0; i < b->audio_count; i++) { const struct stream_media_audio *a = &b->audio[i]; - if (b->format.audio_codec != STREAM_MEDIA_OPUS || !a->data || !a->length || a->length > STREAM_MEDIA_MAX_OPUS + if (!b->format.audio_codec || !a->data || !a->length || a->length > STREAM_MEDIA_MAX_OPUS || a->samples != 960 || a->pts_us > INT64_MAX || (i && a->pts_us <= b->audio[i - 1].pts_us)) { DEBUG_ERROR(DEBUG_CATEGORY_STREAM, "media audio invalid entry=%u length=%u samples=%u", i, a->length, a->samples); return STREAM_ERR_FORMAT; diff --git a/src/stream/stream_media.h b/src/stream/stream_media.h index 7466212c..a8d0728c 100644 --- a/src/stream/stream_media.h +++ b/src/stream/stream_media.h @@ -1,7 +1,7 @@ /* Медиаблок внутри одной FEC-пачки: big-endian, uAV1, fixed header(32), * video descriptors(32 each), audio descriptors(16 each), video bytes, audio bytes. * video descriptor: frame_id:8, PTS_us:8, frame_size:4, fragment_offset:4, length:4, flags:1, reserved:3. - * audio descriptor: PTS_us:8, length:4, samples:2, reserved:2. Opus: 48kHz mono, 960 samples. + * audio descriptor: PTS_us:8, length:4, samples:2, reserved:2. Opus: 48kHz mono/stereo, 960 frames/channel. * H.264 Annex B; полный ключевой кадр включает SPS/PPS. Видео меняется по revision; аудиотрек фиксирован на source_epoch. * first_frame_offset относится к video bytes; UINT32_MAX означает отсутствие начала кадра. * Parser проверяет весь блок до публикации view. Receiver собирает один кадр, после GAP ждёт KEY. @@ -25,6 +25,7 @@ extern "C" { #define STREAM_MEDIA_KEY 1 #define STREAM_MEDIA_H264 1 #define STREAM_MEDIA_OPUS 1 +#define STREAM_MEDIA_OPUS_STEREO 2 struct stream_media_format { uint16_t width, height, rotation; uint8_t video_codec, audio_codec; uint32_t revision; }; struct stream_media_video { diff --git a/tools/chatgui-android/libutun_lite/stream_bridge.c b/tools/chatgui-android/libutun_lite/stream_bridge.c index dc9eb07e..3abae87e 100644 --- a/tools/chatgui-android/libutun_lite/stream_bridge.c +++ b/tools/chatgui-android/libutun_lite/stream_bridge.c @@ -328,7 +328,7 @@ int android_stream_open(uint64_t id, uint64_t group, uint64_t source, unsigned w } else if (media_schedule() == 0) { *s = (struct android_media_session){.id = id, .group = group, .source = source, .expected_epoch = expected_epoch, .opening = 1, .need_key = 1, - .format = {(uint16_t)width, (uint16_t)height, (uint16_t)rotation, STREAM_MEDIA_H264, audio ? STREAM_MEDIA_OPUS : 0, 1}}; + .format = {(uint16_t)width, (uint16_t)height, (uint16_t)rotation, STREAM_MEDIA_H264, audio ? STREAM_MEDIA_OPUS_STEREO : 0, 1}}; result = 0; } pthread_mutex_unlock(&media_lock); return result;