From c9c1bb7cf149f02f8295132ea450568713eeefa3 Mon Sep 17 00:00:00 2001 From: evgeny Date: Fri, 16 Oct 2026 01:48:07 +0200 Subject: [PATCH] Publish live audio toggles through the shared stream actor --- src/stream/stream_publisher.c | 22 +++++++++++++++++++++- src/stream/stream_publisher.h | 3 +++ 2 files changed, 24 insertions(+), 1 deletion(-) diff --git a/src/stream/stream_publisher.c b/src/stream/stream_publisher.c index 10f711ba..210d40e9 100644 --- a/src/stream/stream_publisher.c +++ b/src/stream/stream_publisher.c @@ -32,7 +32,7 @@ struct stream_publisher { struct stream_publisher_status status; struct publisher_queue video, audio; uint64_t group, next_frame, last_pts[2], drain_until, report_us; - int seen[2], stopping; + int seen[2], stopping, audio_enabled, audio_dirty; }; static void publisher_process(void *arg); @@ -180,6 +180,10 @@ static void publisher_process(void *arg) { } uint64_t now = get_time_us(); if (p->handle && !stream_handle_active(p->handle)) publisher_close(p, stream_handle_reason(p->handle)); + if (p->handle && p->audio_dirty && p->status.state == STREAM_PUBLISHER_LIVE) { + if (stream_publish_set_audio_enabled(p->handle, p->audio_enabled) != STREAM_OK) publisher_close(p, STREAM_CLOSE_FAILED); + else { p->status.audio_enabled = p->audio_enabled; p->audio_dirty = 0; } + } if (p->video.head && now - p->video.head->created > MEDIA_AGE_US) { DEBUG_WARN(DEBUG_CATEGORY_STREAM, "publisher video expired bytes=%zu records=%u; require KEY", p->video.bytes, p->video.count); records_clear(&p->video); p->status.need_key = 1; @@ -246,11 +250,27 @@ int stream_publisher_open(struct stream_publisher *p, uint64_t id, uint64_t grou DEBUG_WARN(DEBUG_CATEGORY_STREAM, "publisher open busy id=%llu owner=%llu", (unsigned long long)id, (unsigned long long)p->status.id); } else if (publisher_schedule(p) == 0) { p->status = (struct stream_publisher_status){.id = id, .state = STREAM_PUBLISHER_OPENING, .need_key = 1}; + p->audio_enabled = f->audio_codec != 0; p->audio_dirty = 1; p->group = group; p->format = *f; p->next_frame = 0; p->stopping = 0; memset(p->seen, 0, sizeof(p->seen)); result = 0; } pthread_mutex_unlock(&p->lock); return result; } +int stream_publisher_set_audio_enabled(struct stream_publisher *p, uint64_t id, int enabled) { + if (!p || !id || (enabled != 0 && enabled != 1)) { + DEBUG_ERROR(DEBUG_CATEGORY_STREAM, "publisher audio change invalid arguments"); return -1; + } + pthread_mutex_lock(&p->lock); int result = -1; + if (p->status.id != id || p->stopping || (enabled && !p->format.audio_codec) + || (p->status.state != STREAM_PUBLISHER_OPENING && p->status.state != STREAM_PUBLISHER_LIVE)) { + DEBUG_WARN(DEBUG_CATEGORY_STREAM, "publisher audio change refused id=%llu owner=%llu state=%d enabled=%d codec=%u", + (unsigned long long)id, (unsigned long long)p->status.id, p->status.state, enabled, p->format.audio_codec); + } else if (publisher_schedule(p) == 0) { + p->audio_enabled = enabled; p->audio_dirty = 1; result = 0; + } + pthread_mutex_unlock(&p->lock); return result; +} + /* Admission сохраняет PTS только принятого кадра; новая revision коммитится атомарно с KEY. */ int stream_publisher_feed(struct stream_publisher *p, uint64_t id, int video, uint64_t pts, int key, const uint8_t *data, size_t length, const struct stream_media_format *f) { diff --git a/src/stream/stream_publisher.h b/src/stream/stream_publisher.h index ad7f78cf..f225faca 100644 --- a/src/stream/stream_publisher.h +++ b/src/stream/stream_publisher.h @@ -18,10 +18,13 @@ struct stream_publisher_status { unsigned connections; int state, reason, need_key; int compressor_enabled, compressor_max_gain_db, compressor_rise_rate; + int audio_enabled; }; int stream_publisher_create(struct stream_publisher **out, struct UTUN_INSTANCE *inst); void stream_publisher_destroy(struct stream_publisher *publisher); int stream_publisher_open(struct stream_publisher *publisher, uint64_t id, uint64_t group, const struct stream_media_format *format); +/* Producer заглушает свою копию PCM; actor публикует состояние без смены аудиотрека/эпохи. */ +int stream_publisher_set_audio_enabled(struct stream_publisher *publisher, uint64_t id, int enabled); /* 1 принято, 0 требуется KEY/перегрузка, -1 ошибка или старый/закрытый session ID. */ int stream_publisher_feed(struct stream_publisher *publisher, uint64_t id, int video, uint64_t pts, int key, const uint8_t *data, size_t length, const struct stream_media_format *format);