Files
utun2/src/stream/stream.h1
T

126 lines
8.9 KiB
Plaintext
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/* Стриминг CHAT-сервиса: локальные handles владеют общим экземпляром трансляции.
* Все API — uasync-поток. Последний reader close освобождает экземпляр; publisher close после FIN
* сохраняет кольцо для локальных readers, без FIN отсоединяет их. Отсоединённый handle также закрывает вызывающий.
* DATA/GAP/END/CLOSED/AVAILABLE callback отложен, data/описание заимствованы до его возврата.
* Close handles из callback допустим; остановка сервиса/группы и destroy ядра — вне callbacks.
* Источник и локальные подписки публикуются атомарно через опции собственного мембера. */
#ifndef STREAM_H
#define STREAM_H
#include "stream_buffer.h"
#include "stream_media_buffer.h"
#ifdef __cplusplus
extern "C" {
#endif
struct UTUN_INSTANCE;
struct STREAM_HANDLE;
struct stream_service;
struct stream_parameters { uint8_t n, r; uint16_t block_size; }; /* block_size — максимум RS-части. */
enum stream_event_type { STREAM_EVENT_DATA, STREAM_EVENT_GAP, STREAM_EVENT_END, STREAM_EVENT_CLOSED, STREAM_EVENT_AVAILABLE };
enum stream_close_reason {
STREAM_CLOSE_STOPPED, STREAM_CLOSE_GROUP, STREAM_CLOSE_SERVICE, STREAM_CLOSE_SOURCE_CHANGED,
STREAM_CLOSE_MEMBER, STREAM_CLOSE_FAILED
};
struct stream_event {
struct stream_descriptor descriptor;
enum stream_event_type type;
uint64_t first_seq, last_seq;
const uint8_t *data;
size_t length;
int reason;
};
typedef void (*stream_event_fn)(struct UTUN_INSTANCE *inst, const struct stream_event *event, void *arg);
struct stream_info {
struct stream_descriptor descriptor;
struct stream_buffer_stats buffer;
unsigned owners;
int publisher;
int finished;
};
struct stream_candidate {
uint64_t node_id;
uint8_t client_type;
uint8_t source;
};
struct stream_selection_settings { uint32_t migration_confirm_ms, minimum_hold_ms, score_hysteresis_ms; };
struct stream_selection_info {
uint64_t probes_started, cycles, migrations, failures, restarts;
unsigned candidates, probes_active, subflows, overlaps, providers;
int automatic, protected_by_fec;
};
int stream_service_init(struct UTUN_INSTANCE *inst);
void stream_service_destroy(struct UTUN_INSTANCE *inst);
void stream_cancel_group(struct UTUN_INSTANCE *inst, uint64_t group_id);
void stream_set_event_callback(struct UTUN_INSTANCE *inst, stream_event_fn callback, void *arg);
/* Проверенные online-публикации: JSON с id(decimal string), epoch(hex string), name, self.
* Только uasync; *out заранее NULL, результат освобождается u_free(). WAIT — группа недоступна. */
int stream_sources_json(struct UTUN_INSTANCE *inst, uint64_t group_id, char **out);
/* Независимое наблюдение owner: начальный снимок и изменения через CHAT_EVT_STREAM_SOURCES.
* group_id=0 снимает только этого owner; owner=0 разрешён для выбранного канала frontend.
* Недоступный каталог имеет valid=0 и не означает завершение источников.
* Не создаёт подписку/буфер и не удерживает ACTIVE. Только uasync. */
int stream_watch_sources(struct UTUN_INSTANCE *inst, uint64_t group_id, uint64_t owner);
/* Локальный owner удерживает эффективный ACTIVE; желаемый frontend-режим ядро восстанавливает после последнего close. */
int stream_service_needs_activity(const struct UTUN_INSTANCE *inst);
/* Только локальный viewer этой группы/эпохи подавляет рацию источника со включённым звуком. */
int stream_radio_muted(struct UTUN_INSTANCE *inst, uint64_t group_id, uint64_t source_id);
/* out заранее NULL. parameters=NULL — 6+2, часть до 1300 байт и одна подпись пачки внутри RS.
* Одна публикация этого узла в группе; новый запуск получает новый source_epoch. */
int stream_publish_open(struct UTUN_INSTANCE *inst, uint64_t group_id, const struct stream_parameters *parameters,
struct STREAM_HANDLE **out);
/* Меняет подписанное состояние звука, не формат медиатреков. Только uasync; raw publisher начинает с 0. */
int stream_publish_set_audio_enabled(struct STREAM_HANDLE *handle, int enabled);
/* Параметры берутся из подписанного профиля источника; дубликаты локальных владельцев делят один буфер.
* WAIT — источник ещё не объявил/не подтвердил трансляцию. Offline не создаёт ложного онлайн-кандидата. */
int stream_subscribe_open(struct UTUN_INSTANCE *inst, uint64_t group_id, uint64_t source_id, struct STREAM_HANDLE **out);
/* Ручные выдачи для диагностики/явного управления; режим общий для всех owners экземпляра и не смешивается с automatic. */
int stream_subscribe_manual_open(struct UTUN_INSTANCE *inst, uint64_t group_id, uint64_t source_id, struct STREAM_HANDLE **out);
/* По умолчанию: подтверждение улучшения 2000 мс, удержание 5000 мс, гистерезис интегральной оценки 20 мс. */
int stream_selection_configure(struct STREAM_HANDLE *handle, const struct stream_selection_settings *settings);
int stream_selection_get_info(const struct STREAM_HANDLE *handle, struct stream_selection_info *info);
void stream_close(struct STREAM_HANDLE *handle);
int stream_handle_active(const struct STREAM_HANDLE *handle);
int stream_handle_reason(const struct STREAM_HANDLE *handle);
int stream_get_info(const struct STREAM_HANDLE *handle, struct stream_info *info);
/* Медиаплеер использует тот же RS-buffer, но собственные позиции чтения.
* tracks=0 включает только общий индекс; VIDEO или VIDEO|AUDIO создаёт cursor этого handle.
* Все вызовы — uasync. Заимствованный packet действует до следующего read/close.
* LIVE DATA/GAP/END callbacks описывают сетевой прогресс; конец отложенного просмотра получает media_read. */
int stream_media_enable(struct STREAM_HANDLE *handle, unsigned tracks);
/* Атомарно открыть viewer выбранной эпохи с собственным cursor. CONFLICT означает смену источника.
* tracks=VIDEO или VIDEO|AUDIO; out заранее NULL, при отказе остаётся NULL. Закрытие через stream_close. */
int stream_media_open(struct UTUN_INSTANCE *inst, uint64_t group_id, uint64_t source_id, uint64_t epoch,
unsigned tracks, struct STREAM_HANDLE **out);
/* Один следующий видеокадр при want_video=1; звук ограничен position_us+audio_ahead_us. */
int stream_media_read(struct STREAM_HANDLE *handle, int64_t position_us, int want_video, int64_t audio_ahead_us,
struct stream_media_packet *packet);
int stream_media_get_status(struct STREAM_HANDLE *handle, struct stream_media_status *status);
int stream_media_resync(struct STREAM_HANDLE *handle);
size_t stream_publish_capacity(const struct STREAM_HANDLE *handle);
int stream_publish_write(struct STREAM_HANDLE *handle, const uint8_t *data, size_t length, size_t *accepted);
/* Публикует одну непустую FEC-пачку, без склейки/таймера. Не смешивать с publish_write в одном запуске. */
int stream_publish_block(struct STREAM_HANDLE *handle, const uint8_t *data, size_t length);
/* Сбросить остаток, снять статус публикации; DATA перед END. Буфер живёт до close. */
int stream_publish_finish(struct STREAM_HANDLE *handle);
/* Только подходящие online-подписчики этой группы/эпохи; мобильные relay исключены, источник допускается.
* out заранее NULL; массив освобождается u_free(). Наличие кандидата не гарантирует прямой транспорт. */
int stream_get_candidates(const struct STREAM_HANDLE *handle, struct stream_candidate **out, size_t *count);
#ifdef __cplusplus
}
#endif
#endif