docs(media): clarify preparation ownership and active protocol commands

This commit is contained in:
evgeny committed 2026-10-24 17:26:11 +02:00
1 parent 28bbd62d74
commit f331d177ca
3 files changed
+32 -23

No files matched your search

+23 -17
View File
@@ -1,10 +1,15 @@
/* attachment_send — подготовить голос/видео и отправить в зафиксированный канал или DM. Вызывать trampoline
* через uasync_post. Request и PCM/compressor переходят во владение задачи;
* pcm_release освобождает pcm_owner, NULL означает PCM из u_malloc.
/* attachment_send — подготовить вложение и передать его публикации в зафиксированный канал или DM.
* Trampoline вызывается в uasync (обычно через uasync_post), забирает req и PCM/compressor, включая отказ запуска.
* Если сам uasync_post не принят, request и его ресурсы остаются у вызывающего.
* pcm_release освобождает pcm_owner, NULL означает PCM из u_malloc; release может быть в worker
* или в uasync при отказе/отмене без work. Нельзя использовать GUI-объекты, требующие освобождения в UI-потоке.
* Qt/Android используют общий результат подготовки, доставка остаётся в chat/dm.
* req выделяется u_calloc; caller заполняет target/is_dm, info и source либо PCM. inst должен жить до done.
* req выделяется u_calloc; caller заполняет target/is_dm, info и source либо PCM/compressor, строки NUL-терминированы.
* inst/config/media_async/uasync живут до завершения задачи. После вызова req нельзя читать или освобождать.
* Исходник не изменять во время подготовки; temporary_source разрешает удалить только собственный временный source.
* Подготовка выполняется в media_async worker, публикация и attachment-события — в uasync.
* output/id/error заполняет задача; temporary_source разрешает удалить принадлежащий приложению source. */
* Attachment-события 0/1/2 означают начало/готовность/ошибку подготовки, не подтверждение доставки сообщения.
* Подготовленный output затем забирает chat/dm; собственные пути и PCM освобождаются также при отмене. */
#ifndef ATTACHMENT_SEND_H
#define ATTACHMENT_SEND_H
#include "attachment.h"
@@ -18,22 +23,23 @@ struct attachment_send_req {
char target[64]; /* Десятичный channel_id либо conv_id без префикса dm:, зафиксированный до подготовки. */
int is_dm;
int encrypted; /* Отдельный случайный ключ группового вложения с ручной выдачей. */
char content_type[32]; /* Необязательный исходный MIME (например image/png). */
uint64_t dm_generation; /* Захватывается до подготовки и сохраняется во всех её стадиях. */
unsigned dm_paths_held;
char content_type[32]; /* Исходный MIME только для encrypted channel; пусто → MIME по kind. */
uint64_t dm_generation; /* Поколение беседы до подготовки; 0 → захват в trampoline. Удалённое поколение не публикуется. */
unsigned dm_paths_held; /* Внутренние holds output/source; caller оставляет 0. */
uint8_t reply_to[32]; /* Оригинал канального ответа, зафиксированный до подготовки. */
uint64_t request_id; /* CHAT_EVT_MSG_SUBMITTED после публикации либо ошибки. */
struct attachment_info info;
uint8_t id[16];
char source[1024], output[1024];
int transcode, temporary_source;
uint64_t request_id; /* Только канал: CHAT_EVT_MSG_SUBMITTED после публикации либо ошибки. Для DM — 0. */
struct attachment_info info; /* kind обязателен; пустое name заменяется UUID.opus/mp4; для copy нужны готовые метаданные. */
uint8_t id[16]; /* Внутренний UUID подготовки для attachment-событий; не UUID конечного media_index/DM. */
char source[1024], output[1024]; /* source задаёт caller; output — внутреннее случайное назначение задачи. */
int transcode, temporary_source; /* transcode только VIDEO: отдельный FFmpeg worker; иначе файл копируется. */
const int16_t* pcm;
size_t pcm_count; /* Для voice: int16, 48 кГц моно, число отсчётов. */
void* pcm_owner;
void (*pcm_release)(void* owner);
struct audio_compressor* compressor;
int preset, error;
void* pcm_owner; /* Аргумент собственного pcm_release. */
void (*pcm_release)(void* owner); /* NULL → u_free(pcm); задача вызывает не более одного раза. */
struct audio_compressor* compressor; /* Альтернатива PCM: задача flush/читает output/destroy, внешние обращения прекращены. */
int preset, error; /* preset: 0..2 для voice; error заполняет worker. */
};
/* arg — собственный struct attachment_send_req; завершается событиями chat/dm и освобождением req. NULL — no-op. */
void attachment_send_trampoline(void* arg);
#ifdef __cplusplus
}
+1 -1
View File
@@ -27,7 +27,7 @@ struct UTUN_INSTANCE;
#define MEDIA_REPL_POLL_TB 300000 // периодическая сверка 30s, включая потерю CHANGED
#define MEDIA_REPL_WATCHDOG_TB 2000 // контроль дедлайна/очереди/CM каждые 200ms
#define MEDIA_QUERY_TIMEOUT_TB 20000 // таймаут QUERY 2s
#define MEDIA_HAVE_BLOCK_TIMEOUT_TB 20000 // таймаут HAVE_BLOCK_ACK 2s
#define MEDIA_HAVE_BLOCK_TIMEOUT_TB 20000 // объявлен 2s; текущий HAVE_BLOCK не ждёт ACK и не ставит этот таймер
#define MEDIA_DL_STALL_TIMEOUT_TB 20000 // таймаут простоя загрузки 2s (0.1ms)
#define MEDIA_DL_MAX_ATTEMPTS 3 // попыток на блок до ошибки
+8 -5
View File
@@ -1,6 +1,9 @@
/* media_delivery_proto — wire-структуры и подкоманды доставки блоков медиа CHAT-группы.
* Описывает запросы держателей, чанки, подтверждения наличия и репликацию между суперузлами.
* Это формат payload сервиса router, без группового маршрутизационного заголовка; обработчики — media_delivery/download. */
* Это формат payload сервиса router, без группового маршрутизационного заголовка; обработчики — media_delivery/download.
* Числа SYNC кодируются little endian; остальные packed-поля — native byte order текущего формата.
* SERVE_REG/LEAVE меняют только вспомогательный served_nodes; текущий загрузчик их не посылает.
* SERVE_ACK сейчас не отправляется, входящие SERVE_ACK/HAVE_BLOCK_ACK игнорируются; ожидания ACK и его retry нет. */
#ifndef MEDIA_DELIVERY_PROTO_H
#define MEDIA_DELIVERY_PROTO_H
@@ -13,9 +16,9 @@ extern "C" {
/* ── подкоманды (первый байт данных после etcp_router) ── */
enum {
MEDIA_SUBCMD_SERVE_REG = 0x01, // req-узел→суперузел: обслуживай меня
MEDIA_SUBCMD_SERVE_ACK = 0x02, // суперузел→req-узел: подтверждение
MEDIA_SUBCMD_SERVE_LEAVE = 0x03, // req-узел→суперузел: отключение
MEDIA_SUBCMD_SERVE_REG = 0x01, // вспомогательный учёт узла в served_nodes
MEDIA_SUBCMD_SERVE_ACK = 0x02, // объявлен, но не отправляется; приём игнорируется
MEDIA_SUBCMD_SERVE_LEAVE = 0x03, // удалить вспомогательную запись served_nodes
MEDIA_SUBCMD_QUERY = 0x04, // req-узел→суперузел: кто имеет блоки?
MEDIA_SUBCMD_QUERY_RESP = 0x05, // суперузел→req-узел: список узлов
MEDIA_SUBCMD_HAVE_BLOCK = 0x06, // узел→суперузел: у меня есть блок
@@ -34,7 +37,7 @@ enum {
/* ── ответные статусы ── */
#define MEDIA_ERR_NOT_SUPERNODE 0xFE
#define MEDIA_ERR_NOT_SUPERNODE 0xFE /* Объявлен, в текущих ответах не используется. */
/* Один QUERY — одна полная пачка результатов, включая блоки без держателей.
* Группу и end-to-end отправителя задаёт router. Пределы общие для обеих сторон. */