Send coalesced per-hop telemetry every 200 ms ahead of video DATA using the shared ETCP transport. Measure pending frames before ETCP handoff, retain stale and unavailable node values, and display the worst path with playback tempo. Bump stream wire protocol to v7. Validate with 187 core tests, 21 desktop player tests, two Android indicator tests, and an Android APK build.
51 lines
3.4 KiB
C++
51 lines
3.4 KiB
C++
/* Desktop live media: attach/detach в uasync до destroy ядра; остальные вызовы потокобезопасны.
|
|
* Один общий publisher и независимые viewers; команды содержат IDs, не borrowed pointers ядра.
|
|
* Плеер запрашивает ограниченный батч; каждый трек имеет свой бюджет, новые данные будят worker.
|
|
* Watch до attach запоминает выбранную группу. Каталог идёт через CHAT_EVT_STREAM_SOURCES,
|
|
* media pull читает ближайшие кадры из общего RS-кольца; копия нужна только для передачи между потоками. */
|
|
#pragma once
|
|
|
|
#include <QByteArray>
|
|
#include <cstdint>
|
|
#include <deque>
|
|
#include "../../../src/stream/stream_media.h"
|
|
#include "../../../src/stream/stream_media_buffer.h"
|
|
#include "../../../src/stream/stream_publisher.h"
|
|
#include "../../../src/stream/stream_viewer.h"
|
|
|
|
struct UTUN_INSTANCE;
|
|
enum class StreamRecordKind { Video, Audio, Gap, Opened, End, Closed, VideoEnd, AudioEnd };
|
|
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);
|
|
/* owner=0 — выбранный чат; окно многопросмотра держит свой ненулевой owner. group=0 снимает только его. */
|
|
bool gui_stream_watch(uint64_t group, uint64_t owner = 0);
|
|
/* notify только будит worker; arg живёт до gui_stream_stop/detach. Callback не вызывает bridge/API ядра. */
|
|
bool gui_stream_open(uint64_t id, uint64_t group, uint64_t source, uint64_t epoch,
|
|
void (*notify)(void*) = nullptr, void* arg = nullptr);
|
|
void gui_stream_stop(uint64_t id);
|
|
bool gui_stream_pull(uint64_t id, StreamRecord& record, int64_t position = -1,
|
|
bool wantVideo = true, int64_t audioAhead = STREAM_MEDIA_READ_AHEAD_US);
|
|
/* Добавляет готовый батч в records; при пустом ответе запрашивает до videoBudget кадров и audioAhead звука.
|
|
* Вызывать после расходования нужного трека: удерживаемые видеокадры не мешают запросить только звук. */
|
|
bool gui_stream_pull_batch(uint64_t id, std::deque<StreamRecord>& records, int64_t position,
|
|
unsigned videoBudget, int64_t audioAhead);
|
|
bool gui_stream_status(uint64_t id, stream_media_status& status);
|
|
bool gui_stream_telemetry(uint64_t id, stream_viewer_telemetry& telemetry);
|
|
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);
|
|
bool gui_stream_publish_audio(uint64_t id, bool enabled);
|
|
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);
|