/* Desktop live media: attach/detach в uasync до destroy ядра; остальные вызовы потокобезопасны. * Один общий publisher и один viewer; команды содержат IDs, не borrowed pointers ядра. * Подготовлено не более двух media records, общий предел RX 4MiB/16 записей. * Watch до attach запоминает выбранную группу. Каталог идёт через CHAT_EVT_STREAM_SOURCES, * media pull читает ближайшие кадры из общего RS-кольца; копия нужна только для передачи между потоками. */ #pragma once #include #include #include "../../../src/stream/stream_media.h" #include "../../../src/stream/stream_media_buffer.h" #include "../../../src/stream/stream_publisher.h" struct UTUN_INSTANCE; enum class StreamRecordKind { Video, Audio, Gap, Opened, End, Closed }; struct StreamRecord { uint64_t id = 0, pts = 0; StreamRecordKind kind = StreamRecordKind::Gap; stream_media_format format{}; int flags = 0, reason = 0; QByteArray data; }; bool gui_stream_attach(UTUN_INSTANCE* inst); void gui_stream_detach(UTUN_INSTANCE* inst); bool gui_stream_watch(uint64_t group); bool gui_stream_open(uint64_t id, uint64_t group, uint64_t source, uint64_t epoch); void gui_stream_stop(uint64_t id); bool gui_stream_pull(uint64_t id, StreamRecord& record, int64_t position = -1, int64_t videoAhead = STREAM_MEDIA_READ_AHEAD_US, int64_t audioAhead = STREAM_MEDIA_READ_AHEAD_US); bool gui_stream_status(uint64_t id, stream_media_status& status); bool gui_stream_resync(uint64_t id); bool gui_stream_ready(); /* Publisher независим от viewer; lifetime ядра ограничивает общий bridge mutex. */ bool gui_stream_publish_open(uint64_t id, uint64_t group, const stream_media_format& format); int gui_stream_publish_feed(uint64_t id, bool video, uint64_t pts, bool key, const QByteArray& data, const stream_media_format* format = nullptr); void gui_stream_publish_stop(uint64_t id); bool gui_stream_publish_status(uint64_t id, stream_publisher_status& status);