docs: update file inventory and module header contracts

Refresh both AGENTS guides and clarify module purpose, usage, ownership, threading, return values and wire formats in headers. Remove the unused timeout_heap freed_count field and unimplemented getter.
This commit is contained in:
evgeny committed 2026-10-04 13:10:01 +02:00
1 parent c19eff67f6
commit a97e8bcc1f
118 files changed
+628 -406

No files matched your search

+9 -1
View File
@@ -1,3 +1,9 @@
/* audio_compressor — адаптивное усиление int16 PCM (моно/стерео) с общей огибающей каналов.
* create → configure → обработка → destroy; объект использует один владелец, блокировок нет.
* Запись: push принимает произвольные порции, flush завершает хвост и lookahead; output принадлежит объекту.
* Поток: process_frame обрабатывает ровно sample_rate*block_duration_ms/1000*channels отсчётов,
* требует нулевого lookahead и пустого входного накопителя; in/out могут совпадать.
* count/output_size — interleaved отсчёты, не байты и не кадры на канал. Выключение даёт исходный PCM. */
#ifndef AUDIO_COMPRESSOR_H
#define AUDIO_COMPRESSOR_H
@@ -19,7 +25,7 @@ typedef struct {
float max_gain_db;
float rise_rate_per_sec;
float release_rate_per_sec; /* скорость плавного снижения gain (0 = авто: rise*5) */
float target_level;
float target_level; /* Линейная амплитуда огибающей, не дБ; 0 задаёт default 0.25. */
} audio_compressor_config_t;
struct audio_compressor* audio_compressor_create(void);
@@ -35,9 +41,11 @@ void audio_compressor_reset(struct audio_compressor* ac);
void audio_compressor_set_enabled(struct audio_compressor* ac, int enabled);
int audio_compressor_is_enabled(const struct audio_compressor* ac);
/* push копирует вход; push/flush возвращают 0 / -1. Ошибка накопления требует reset перед повтором. */
int audio_compressor_push(struct audio_compressor* ac, const int16_t* samples, size_t count);
int audio_compressor_flush(struct audio_compressor* ac);
/* Указатель действителен до изменения/освобождения выходного буфера; вызывающий его не освобождает. */
const int16_t* audio_compressor_output(const struct audio_compressor* ac);
size_t audio_compressor_output_size(const struct audio_compressor* ac);
+7 -6
View File
@@ -80,7 +80,7 @@ typedef int debug_category_t;
/* Debug configuration structure */
typedef struct {
debug_level_t level; // Global debug level (default: ERROR)
debug_level_t category_levels[DEBUG_CATEGORY_COUNT]; // Per-category levels (0 = disabled)
debug_level_t category_levels[DEBUG_CATEGORY_COUNT]; // Уровень категории: NONE наследует общий, DISABLED выключает
int timestamp_enabled; // Include timestamps in output
int function_name_enabled; // Include function names
int file_line_enabled; // Include file:line info
@@ -99,18 +99,19 @@ extern debug_config_t g_debug_config;
void debug_config_init(void);
/* Set debug level */
// итоговый level = max (global level - здесь задается, category level)
// Общий уровень применяется к категориям с уровнем NONE.
void debug_set_level(debug_level_t level);
/* Set debug level for specific category (0 = disabled, otherwise uses that level) */
/* Уровень категории заменяет общий; NONE наследует его, DISABLED подавляет вывод. */
void debug_set_category_level(debug_category_t category, debug_level_t level);
/* Enable/disable specific categories */
/* enable фиксирует текущий общий уровень; disable возвращает к наследованию (NONE).
* Для полного выключения использовать debug_set_category_level(cat, DEBUG_LEVEL_DISABLED). */
void debug_enable_category(debug_category_t category);
void debug_disable_category(debug_category_t category);
void debug_set_categories(debug_category_t categories);
/* Set masks directly */
/* Установка уровня одной категории (аргумент categories — индекс, не битовая маска). */
void debug_set_masks(debug_category_t categories, debug_level_t level);
/* Configure output options */
@@ -126,7 +127,7 @@ int debug_reopen_log(void);
void debug_enable_console(int enable);
// IP address to string (static buffer, single-threaded)
// IP/sockaddr в строку: результат возвращается по значению, освобождать не требуется.
typedef struct {
char str[54]; // INET6_ADDRSTRLEN(45) + 6chars (:port) + \0
} ip_str_t;
+4 -1
View File
@@ -2,7 +2,10 @@
* @file json_flat.h
* @brief Парсер плоского JSON без вложенности: {"key":"value",...}
*
* Только строковые значения. Callback получает полные строки без обрезания.
* Только строковые значения и обычные escapes; \uXXXX не поддерживается.
* Callback получает полные key/value, действительные только до его возврата.
* parse возвращает 0 при успехе/остановке callback, -1 при ошибке; остановка не проверяет остаток ввода.
* get ищет первый ключ и копирует значение с NUL, при малом буфере обрезает; 0 найден, -1 ошибка/нет ключа.
*/
#ifndef JSON_FLAT_H
+4 -2
View File
@@ -1,6 +1,10 @@
#ifndef LL_QUEUE_H
#define LL_QUEUE_H
/* Очередь одного uasync-потока; наличие pthread-заголовков не делает её межпоточной.
* put может синхронно вызвать consumer/waiter. Держать владельцев живыми до завершения callbacks,
* waiter handle обнулять целиком и отменять до освобождения; entry и dgram освобождаются отдельно. */
#ifdef __cplusplus
extern "C" {
#endif
@@ -306,7 +310,6 @@ void queue_waiter_cancel(struct ll_queue* q, struct queue_waiter_handle* h);
* @brief Добавляет элемент в конец очереди (FIFO).
* @param q очередь
* @param entry элемент
* @param id идентификатор для поиска
* @return 0 — успех, -1 — превышен лимит (элемент освобождён)
*/
int queue_data_put(struct ll_queue* q, struct ll_entry* entry);
@@ -315,7 +318,6 @@ int queue_data_put(struct ll_queue* q, struct ll_entry* entry);
* @brief Добавляет элемент в начало очереди (LIFO, высокий приоритет).
* @param q очередь
* @param entry элемент
* @param id идентификатор
* @return 0 — успех, -1 — превышен лимит (элемент освобождён)
*/
int queue_data_put_first(struct ll_queue* q, struct ll_entry* entry);
+5 -2
View File
@@ -1,6 +1,9 @@
/**
* Memory management layer
* Provides wrappers for malloc/realloc/calloc/free with error handling
* mem — выделение памяти с защитными полями, местом аллокации и учётом живых блоков.
* Использовать u_malloc/u_calloc/u_realloc/u_strdup и парный u_free; обычный free к этим блокам неприменим.
* Макросы передают LOCATION автоматически. OOM возвращает NULL; обнаруженное повреждение завершает процесс.
* realloc при ошибке сохраняет старый блок, при size=0 освобождает его.
* Отчёт u_report_unfreed_blocks вызывать после остановки потоков, меняющих список аллокаций.
*/
#ifndef MEM_H
#define MEM_H
+7 -1
View File
@@ -1,4 +1,9 @@
// memory_pool.h
/* memory_pool — повторное использование блоков фиксированного размера в одном потоке.
* init создаёт пустой пул; alloc выделяет блок по требованию или берёт свободный и обнуляет payload.
* free проверяет защитный хвост и возвращает не более MEMORY_POOL_MAX_FREE блоков в кеш.
* object_size должен вмещать void*: свободный блок хранит next в начале payload.
* Перед destroy вернуть все выданные блоки: destroy освобождает только кеш и сам пул.
* name заимствован до destroy; блок возвращать только своему пулу, внутренней синхронизации нет. */
#ifndef MEMORY_POOL_H
#define MEMORY_POOL_H
@@ -40,6 +45,7 @@ size_t memory_pool_get_total_free_blocks(void);
#define memory_pool_alloc(pool) memory_pool_alloc_impl(pool, PLOCATION)
#define memory_pool_free(pool, obj) memory_pool_free_impl(pool, obj, PLOCATION)
/* Проверяет присутствие в кеше свободных блоков; не определяет состояние уже освобождённого через u_free блока. */
int memory_pool_is_freed(struct memory_pool* pool, void* obj);
+6
View File
@@ -1,3 +1,9 @@
/* opus_codec — владеющие обёртки encoder/decoder libopus для int16 interleaved PCM.
* create принимает частоту и 1/2 канала; неположительная частота → 48000, неверные каналы → моно.
* Encoder/decoder имеют состояние потока; каждому нужен один последовательный владелец.
* frame_samples — отсчёты НА КАНАЛ: PCM вмещает frame_samples*channels элементов.
* encode возвращает байты Opus, decode — отсчёты на канал; отрицательное значение означает ошибку.
* out_cap — байты; decode с data=NULL/len=0 использует PLC libopus. Освобождение — соответствующим destroy. */
#ifndef OPUS_CODEC_H
#define OPUS_CODEC_H
+3 -1
View File
@@ -1,5 +1,7 @@
/**
* Platform compatibility layer for POSIX functions on Windows
* platform_compat — общие заголовки POSIX/Windows и адаптеры отсутствующих POSIX-функций.
* Также предоставляет криптографический random_bytes, адреса интерфейсов, выбор default route
* и классификацию публичных IPv4. Сокетные типы/ошибки и nonblocking API — в socket_compat.h.
*/
#ifndef PLATFORM_COMPAT_H
+7 -4
View File
@@ -22,17 +22,20 @@
* • Все динамические данные (строки, массивы, списки) выделяются через u_malloc.
* • При encode длина переменных полей кодируется всегда 2 байтами (uint16_t, big-endian).
* • Для linked list в буфере сохраняется только количество узлов + сырые данные узлов
* (next-указатели НЕ сериализуются, они восстанавливаются при decode).
* (включая байты next/padding; decode заменяет next восстановленными ссылками).
* • serialize_decode принимает буфер БЕЗ заголовка.
* • serialize_free освобождает ВСЮ структуру и все вложенные динамические объекты.
* • Поля в schema.fields должны идти в порядке возрастания offset.
* • max_size (если > 0) — жёсткий лимит размера выходного буфера.
* • Поля кодируются в порядке schema.fields; фиксированные данные копируются без смены endian.
* • max_size (если > 0) — лимит encode; header при header_len > 0 обязателен.
* • Переменные counts ограничены 65535; elem_size=1 добавляет NUL и для byte-массивов.
* • Linked nodes копируются целиком, без рекурсивного кодирования вложенных указателей.
* • Этот формат зависит от ABI сырых полей; сериализация не нормализует размер/выравнивание структур.
*
* @example
* // 1. Описание структуры
* typedef struct Node {
* uint32_t value;
* struct Node* next; // next по offset = 4
* struct Node* next; // положение задаётся offsetof(Node, next)
* } Node;
*
* typedef struct {
+1 -1
View File
@@ -3,7 +3,7 @@
*
* Запускает официальную стриминговую модель silero_vad.onnx (v5, ~2.3 МБ),
* которая по окну аудио возвращает вероятность наличия речи [0..1].
* Рекуррентное состояние (GRU) хранится внутри объекта и переносится между
* Рекуррентное состояние модели хранится внутри объекта и переносится между
* вызовами. Обёртка также хранит 64 последних отсчёта аудио и добавляет их
* перед новым окном: ONNX получает 576 отсчётов, публичный API принимает 512.
*
+3 -2
View File
@@ -1,6 +1,7 @@
/**
* Socket compatibility layer for cross-platform support (POSIX / Windows)
* MSYS2 UCRT64 compatible
* Единые socket_t, коды ошибок и wrappers сокетов POSIX/Windows (включая MSYS2 UCRT64).
* platform_init/cleanup обслуживают Winsock; UDP/nonblocking/options/sendto/recvfrom — операции ОС.
* Созданные сокеты закрывает владелец через socket_close_wrapper; event loop находится в u_async.h.
*/
#ifndef SOCKET_COMPAT_H
+3
View File
@@ -5,6 +5,9 @@
* перед кодированием. Работает на interleaved int16 PCM, 1/2 канала, частота 48000 (можно
* 8000/16000/32000/48000), кадр 20 мс (960 сэмплов @48 кГц).
*
* Объект не имеет внутренних блокировок: feed/process/reset/get_stats выполняет один владелец
* либо вызывающий сериализует их общей блокировкой. Аппаратные callbacks сами AEC не вызывают.
*
* Модель использования (duplex-контур звонка):
* - рендер (far-end, то что пошло в динамик) → speex_aec_feed_playback();
* - захват (near-end, микрофон) → speex_aec_process_capture().
+2 -1
View File
@@ -1,4 +1,5 @@
/* sliding_window_min.h */
/* swm_min — минимум последних window_size целых значений (окно по числу добавлений, не по времени).
* create → add/get_min → destroy; память окна выделяется при create, внутренняя синхронизация отсутствует. */
#ifndef SLIDING_WINDOW_MIN_H
#define SLIDING_WINDOW_MIN_H
-1
View File
@@ -28,7 +28,6 @@ TimeoutHeap *timeout_heap_create(size_t initial_capacity) {
DEBUG_DEBUG(DEBUG_CATEGORY_ETCP, "Creating TH3...");
h->size = 0;
h->capacity = initial_capacity;
h->freed_count = 0;
h->user_data = NULL;
h->free_callback = NULL;
return h;
+11 -11
View File
@@ -1,4 +1,9 @@
// timeout_heap.h
/* timeout_heap — min-heap таймеров для uasync; сам не измеряет время и не вызывает таймеры.
* Владелец задаёт абсолютные expiration в одной шкале и извлекает готовые записи через peek/pop.
* cancel помечает запись; её data передаётся free_callback при последующей очистке или destroy.
* Без free_callback data не освобождается. Успешный pop передаёт data вызывающему.
* index_ptr, если задан, должен жить до удаления записи; heap обновляет индекс при перестановках.
* Все операции одного heap выполняются в одном потоке, внутренней синхронизации нет. */
#ifndef TIMEOUT_HEAP_H
#define TIMEOUT_HEAP_H
@@ -11,7 +16,7 @@ extern "C" {
#include <stdint.h> // For uint64_t
#include <stddef.h> // For size_t
typedef uint64_t TimeoutTime; // e.g., milliseconds since epoch or from now
typedef uint64_t TimeoutTime; // Абсолютное время в шкале владельца (uasync использует timebase: 0.1 мс).
typedef struct {
TimeoutTime expiration; // Sort key (smaller = earlier)
@@ -26,7 +31,6 @@ struct TimeoutHeap {
TimeoutEntry *heap; // Dynamic array
size_t size; // Current number of elements
size_t capacity; // Allocated size
size_t freed_count; // Number of freed timer nodes
void* user_data; // User data for free callback
void (*free_callback)(void* user_data, void* data); // Callback to free data
};
@@ -48,7 +52,7 @@ void timeout_heap_destroy(TimeoutHeap *h);
* Set a callback function to free data when deleted nodes are removed.
* @param h The heap.
* @param user_data User data passed to callback.
* @param callback Callback function (if NULL, data is freed with free()).
* @param callback Освобождает data отменённых записей и всех записей при destroy; NULL оставляет data владельцу.
*/
void timeout_heap_set_free_callback(TimeoutHeap *h, void* user_data, void (*callback)(void* user_data, void* data));
@@ -57,6 +61,7 @@ void timeout_heap_set_free_callback(TimeoutHeap *h, void* user_data, void (*call
* @param h The heap.
* @param expiration The expiration time.
* @param data User data associated with the timeout.
* @param index_ptr Optional pointer to a live size_t updated with the entry's zero-based heap index.
* @return 0 on success, -1 on allocation failure.
*/
int timeout_heap_push(TimeoutHeap *h, TimeoutTime expiration, void *data, size_t *index_ptr);
@@ -88,15 +93,10 @@ int timeout_heap_pop(TimeoutHeap *h, TimeoutEntry *out);
*/
int timeout_heap_cancel(TimeoutHeap *h, TimeoutTime expiration, void *data);
/* Отмена по сохранённому индексу; data защищает от отмены чужой записи. 0 / -1, освобождение отложено. */
int timeout_heap_cancel_at(TimeoutHeap *h, size_t index, void *data);
/**
* Get the number of freed timer nodes.
* @param h The heap.
* @return Count of freed timer nodes.
*/
size_t timeout_heap_get_freed_count(TimeoutHeap *h);
/* Число записей, включая ещё не извлечённые отменённые; NULL → 0. */
size_t timeout_heap_get_size(TimeoutHeap *h);
+5 -3
View File
@@ -1,6 +1,8 @@
// uasync.h
// модуль асинхронных операций. добавляем сокеты и таймауты и mainloop их обслуживает.
/* Цикл событий одного потока: сокеты (epoll/poll/select), таймеры и FIFO call_soon.
* create → регистрация callbacks → poll/mainloop → destroy вне callbacks после остановки владельцев.
* Таймауты задаются в timebase 0.1мс; arg принадлежит вызывающему, освобождает его callback/владелец.
* API сокетов/таймеров используется в потоке loop. Из другого потока — post/post_reserved и wakeup;
* публикация не продлевает время жизни ua/arg, их освобождение нужно согласовать с остановкой producers. */
#ifndef UASYNC_H
#define UASYNC_H