135 lines
6.8 KiB
C
135 lines
6.8 KiB
C
// call — управление P2P аудио/видеозвонком одного узла.
|
||
// Начать вызов через start, ответить через accept/decline, завершить через hangup.
|
||
// Состояния и результаты приходят событиями CHAT_EVT_CALL_* из chat_event.h.
|
||
// Аудио подключается через call_audio.h, видеотрек — через call_video_transport.h или call_video_port.h.
|
||
//
|
||
// Модуль оперирует (group_id, peer_node_id): звонок можно инициировать из
|
||
// CHAT-группы или из DM (group_id — группа маршрутизации, как в dm_core).
|
||
// Сигналинг, аудио и видео идут через etcp_router с обязательными ROUTE_CRYPTO_SIGN|ENCRYPT; соединение
|
||
// оптимизируется через параллельные пробы conn_mgr (DIRECT/REVERSE/INDIRECT).
|
||
//
|
||
// Все функции, кроме явно отмеченных, — в uasync-потоке. GUI/headless вызывают через trampoline
|
||
// (gui_bridge_post_uasync_fn / uasync_post).
|
||
#ifndef CALL_H
|
||
#define CALL_H
|
||
|
||
#include <stdint.h>
|
||
#include "call_jitter.h"
|
||
#include "call_clock.h"
|
||
|
||
struct UTUN_INSTANCE;
|
||
|
||
#ifdef __cplusplus
|
||
extern "C" {
|
||
#endif
|
||
|
||
// ── жизненный цикл ──
|
||
|
||
int call_init(struct UTUN_INSTANCE* inst); /* из utun_instance.c после dm_core_init */
|
||
|
||
void call_destroy(struct UTUN_INSTANCE* inst); /* перед dm_core_destroy */
|
||
|
||
// ── сигналинг (uasync-поток) ──
|
||
|
||
/* Caller: ch_id — группа либо "dm:<conv_id>" (BGP-группа выбирается при запуске).
|
||
* out_call_id — случайный uint64, генерит вызывающий. */
|
||
void call_start (struct UTUN_INSTANCE* inst, const char* ch_id, uint64_t peer_node_id, uint64_t out_call_id);
|
||
|
||
// Callee: ответить/отклонить. hangup — любая сторона в любой момент.
|
||
void call_accept (struct UTUN_INSTANCE* inst, uint64_t call_id);
|
||
|
||
void call_decline(struct UTUN_INSTANCE* inst, uint64_t call_id);
|
||
|
||
void call_hangup (struct UTUN_INSTANCE* inst, uint64_t call_id);
|
||
|
||
// Проверка занятости обычным звонком; только uasync, включая входящий/исходящий.
|
||
int call_busy(struct UTUN_INSTANCE* inst);
|
||
|
||
// Продолжить исходящий вызов после предупреждения о телефонной занятости. Только uasync.
|
||
void call_continue(struct UTUN_INSTANCE* inst, uint64_t call_id);
|
||
|
||
// Независимые настройки входящих вызовов; запрет выбранного типа приоритетнее проверки занятости.
|
||
enum call_policy {
|
||
CALL_POLICY_PUBLISH_PHONE = 1, CALL_POLICY_WARN_PHONE = 2, CALL_POLICY_REJECT_PHONE = 4,
|
||
CALL_POLICY_BLOCK_CALLS = 8, CALL_POLICY_BLOCK_RADIO = 16
|
||
};
|
||
/* Живое состояние ОС: 0=неизвестно, 1=свободен, 2=занят; policy — маска call_policy.
|
||
* Только uasync. Изменение статуса публикуется в BGP, если включён PUBLISH_PHONE. */
|
||
void call_set_phone_state(struct UTUN_INSTANCE* inst, int state, unsigned policy);
|
||
|
||
/* Флаги BGP PHONE_KNOWN/BUSY с учётом звонка приложения и разрешения публикации.
|
||
* Desktop без звонка свободен; у mobile состояние ОС может быть неизвестно. Только uasync. */
|
||
uint8_t call_phone_status(struct UTUN_INSTANCE* inst);
|
||
|
||
// Read-only онлайн-проверка (GUI может звать из любого потока).
|
||
int call_is_online(struct UTUN_INSTANCE* inst, const char* ch_id, uint64_t peer_node_id);
|
||
|
||
// ── медиа (релей Opus-кадров, uasync-поток) ──
|
||
|
||
/* Отправить закодированный Opus-кадр пиру (оборачивает в CALL_MEDIA).
|
||
* Только когда звонок ACTIVE. seq/ts выставляются автоматически. */
|
||
int call_send_media(struct UTUN_INSTANCE* inst, uint64_t call_id, const uint8_t* opus, int len,
|
||
const struct call_capture_time* timing);
|
||
|
||
/* Коллбэк приёма медиа: вызывается в uasync-потоке на каждый Opus-кадр пира.
|
||
* Используется headless-аудиосокетом; opus заимствован до возврата callback. */
|
||
typedef void (*call_media_recv_fn)(struct UTUN_INSTANCE* inst, uint64_t call_id,
|
||
const uint8_t* opus, int len, void* arg);
|
||
|
||
void call_set_media_recv_cb(struct UTUN_INSTANCE* inst, call_media_recv_fn fn, void* arg);
|
||
|
||
/* ── аудио-движок (опционально, GUI-сборки) ──
|
||
* Сервисный аудио-контур (codec + джиттер-буфер + тоны) регистрируется через
|
||
* call_set_audio_ops. call.c зовёт on_media на каждый принятый медиа-кадр (с seq/ts)
|
||
* и get_stats для события CALL_STATS. Демон без аудио (headless) — ops не ставит. */
|
||
|
||
struct call_audio_ops {
|
||
// uasync-поток: принятый Opus-кадр пира (декод + jitter-буфер).
|
||
void (*on_media)(struct UTUN_INSTANCE* inst, uint64_t call_id,
|
||
uint16_t seq, uint32_t ts_ms, const uint8_t* opus, int len, const struct call_capture_time* timing);
|
||
/* uasync-поток: текущие метрики джиттер-буфера (buffer_ms, tempo_x100,
|
||
* dropped/underruns — опционально, NULL допустим). */
|
||
int (*get_stats)(uint64_t call_id, int* buffer_ms, int* tempo_x100,
|
||
uint32_t* dropped, uint32_t* underruns, struct call_jitter_range* range);
|
||
};
|
||
void call_set_audio_ops(struct UTUN_INSTANCE* inst, const struct call_audio_ops* ops);
|
||
|
||
// Отправить Opus-кадр из ДРУГОГО потока (GUI-аудио): post в uasync через trampoline.
|
||
struct call_media_arg {
|
||
struct UTUN_INSTANCE* inst;
|
||
uint64_t call_id;
|
||
uint16_t len;
|
||
struct call_capture_time timing;
|
||
uint8_t opus[256];
|
||
};
|
||
void call_send_media_trampoline(void* arg);
|
||
|
||
// ── trampoline-структуры для gui_bridge_post_uasync_fn / uasync_post ──
|
||
|
||
struct call_start_arg {
|
||
struct UTUN_INSTANCE* inst;
|
||
char ch_id[64];
|
||
uint64_t peer_node_id;
|
||
uint64_t call_id;
|
||
};
|
||
|
||
struct call_id_arg {
|
||
struct UTUN_INSTANCE* inst;
|
||
uint64_t call_id;
|
||
};
|
||
|
||
void call_start_trampoline (void* arg);
|
||
|
||
void call_accept_trampoline (void* arg);
|
||
|
||
void call_decline_trampoline(void* arg);
|
||
|
||
void call_hangup_trampoline (void* arg);
|
||
|
||
void call_continue_trampoline(void* arg);
|
||
|
||
#ifdef __cplusplus
|
||
}
|
||
#endif
|
||
#endif /* CALL_H */
|