Files
utun2/src/stream/stream_viewer.h
T

62 lines
5.1 KiB
C

/* Общие viewers desktop/Android: независимый media cursor и ограниченный батч на session ID.
* create/destroy — uasync вне callbacks; внешний bridge защищает destroy от параллельных callers.
* Остальные API потокобезопасны. Один manager занимает stream event callback ядра.
* stop снимает только своего reader; медленные/остановленные viewers не задерживают остальных.
* pull передаёт владение цепочкой records вызывающему: освобождать records_free(). Кольца RS остаются общими. */
#ifndef STREAM_VIEWER_H
#define STREAM_VIEWER_H
#include "stream_media_buffer.h"
#ifdef __cplusplus
extern "C" {
#endif
struct UTUN_INSTANCE;
struct stream_viewers;
#define STREAM_VIEWER_BATCH_RECORDS 16u
enum stream_viewer_kind {
STREAM_VIEWER_VIDEO = 1, STREAM_VIEWER_AUDIO, STREAM_VIEWER_GAP,
STREAM_VIEWER_OPENED, STREAM_VIEWER_END, STREAM_VIEWER_CLOSED,
STREAM_VIEWER_VIDEO_END, STREAM_VIEWER_AUDIO_END
};
struct stream_viewer_record {
struct stream_viewer_record *next; /* Следующая запись батча; NULL завершает цепочку. */
enum stream_viewer_kind kind;
struct stream_media_format format;
uint64_t pts; /* PTS только этого источника, микросекунды. */
size_t length; /* Длина owned payload после структуры. */
int flags, reason; /* VIDEO: KEY; CLOSED: stream_close_reason. */
uint8_t data[];
};
/* 0 — успех, -1 — ошибка; out заранее NULL. */
int stream_viewers_create(struct stream_viewers **out, struct UTUN_INSTANCE *inst);
void stream_viewers_destroy(struct stream_viewers *viewers);
/* Уникальный ненулевой ID принадлежит caller до stop, включая завершённый/ошибочный сеанс.
* Открытие асинхронно: OPENED/CLOSED возвращается через pull. tracks — VIDEO или VIDEO|AUDIO. */
int stream_viewer_open(struct stream_viewers *viewers, uint64_t id, uint64_t group, uint64_t source, uint64_t epoch, unsigned tracks);
void stream_viewer_stop(struct stream_viewers *viewers, uint64_t id);
/* Owned батч или NULL. Выдача батча погашает demand, включая повторный request до pull.
* NULL сохраняет ожидающий запрос. Следующие данные требуют нового request; idle не копирует кольцо.
* VIDEO_END/AUDIO_END следуют за последней записью своего трека; другой трек их не задерживает.
* END завершает оба входа. GAP/CLOSED отменяют старый батч и требуют немедленного сброса frontend. */
struct stream_viewer_record *stream_viewer_pull(struct stream_viewers *viewers, uint64_t id);
/* Освобождает всю owned цепочку и payload каждой записи; NULL допустим. */
void stream_viewer_records_free(struct stream_viewer_record *records);
/* Позиция и audio_ahead относятся только к этому reader; повторный demand заменяет прежний.
* video — максимум видеокадров; records — максимум всех записей, 1..STREAM_VIEWER_BATCH_RECORDS.
* Батч отдаётся сразу при WAIT/MORE или после бюджета 2ms/256KiB, без ожидания заполнения.
* Последняя запись может пересечь порог байтов, но не превышает STREAM_MEDIA_MAX_FRAME.
* 0 — принято, -1 — неизвестный/закрытый ID или ошибка scheduling. */
int stream_viewer_request(struct stream_viewers *viewers, uint64_t id, int64_t position, unsigned video,
int64_t audio_ahead, unsigned records);
/* Уведомление о готовом батче/закрытии, под lock manager: только разбудить worker, API ядра не вызывать.
* arg живёт до stop/destroy или снятия callback (notify=NULL); после возврата старый callback уже не выполняется.
* Уже готовый батч уведомляет сразу. 0 — установлен, -1 — ID отсутствует/остановлен. */
int stream_viewer_set_notify(struct stream_viewers *viewers, uint64_t id, void (*notify)(void *), void *arg);
/* Последний снимок сохраняется после END до stop. 0 — получен, -1 — ID отсутствует. */
int stream_viewer_status(struct stream_viewers *viewers, uint64_t id, struct stream_media_status *status);
/* Очистить ответ и искать ближайший KEY только этого reader. 0 — принято, -1 — отказ. */
int stream_viewer_resync(struct stream_viewers *viewers, uint64_t id);
#ifdef __cplusplus
}
#endif
#endif