92 lines
5.6 KiB
C
92 lines
5.6 KiB
C
#ifndef CALL_AUDIO_H
|
|
#define CALL_AUDIO_H
|
|
|
|
// call_audio.h — сервисный аудио-движок P2P-звонка (единый для desktop/Android/headless).
|
|
//
|
|
// Владеет Opus codec, адаптивным джиттер-буфером (call_jitter: кодированные
|
|
// кадры + SoundTouch time-stretch на pull) и тонами (глитч при сталле / завершение).
|
|
// Излишек голоса держится до декодирования — декодируется только то, что готово
|
|
// к воспроизведению. Потребитель (desktop miniaudio / Android AudioTrack) получает
|
|
// финальный PCM через call_audio_pull_pcm и отдаёт захваченный PCM через
|
|
// call_audio_feed_pcm.
|
|
//
|
|
// Потоки:
|
|
// - call_audio_start / begin_end / release — GUI-поток (по ACCEPTED/ENDED);
|
|
// - call_audio_feed_pcm / pull_pcm — по одному аудио-потоку на направление;
|
|
// - call_audio_on_media / get_stats — uasync-поток (из call.c).
|
|
// Общие указатели (encoder/decoder/vj/tones) защищены мьютексом; encoder и
|
|
// decoder — только аудио-поток (decoder дёргается из call_jitter_pull через коллбэк),
|
|
// call_jitter_push — только uasync-поток.
|
|
|
|
#include <stdint.h>
|
|
#include "call_jitter.h"
|
|
|
|
struct UTUN_INSTANCE;
|
|
|
|
#ifdef __cplusplus
|
|
extern "C" {
|
|
#endif
|
|
|
|
#define CALL_AUDIO_SAMPLE_RATE 48000
|
|
#define CALL_AUDIO_FRAME_MS 20
|
|
#define CALL_AUDIO_FRAME_SAMPLES (CALL_AUDIO_SAMPLE_RATE * CALL_AUDIO_FRAME_MS / 1000) /* 960 */
|
|
|
|
/* Зарегистрировать аудио-движок в call.c (идемпотентно). */
|
|
int call_audio_init(struct UTUN_INSTANCE* inst);
|
|
void call_audio_destroy(struct UTUN_INSTANCE* inst);
|
|
|
|
/* GUI-поток: создать codec + jitter + tones. Старый API принимает raw PCM и использует core AEC.
|
|
* Для desktop нужен start_prepared: AEC и stereo reference принадлежат VoiceAudioIo. 0 = успех. */
|
|
int call_audio_start(uint64_t call_id);
|
|
/* AEC принадлежит платформенному захвату; pull больше не подаёт собственный референс. */
|
|
int call_audio_start_prepared(uint64_t call_id);
|
|
|
|
/* GUI-поток: по CALL_ENDED — начать тон завершения (pull_pcm выдаст 450мс тона). */
|
|
void call_audio_begin_end(uint64_t call_id);
|
|
|
|
/* GUI-поток (после остановки аудиоустройства): освободить все объекты. */
|
|
void call_audio_release(uint64_t call_id);
|
|
|
|
/* GUI-поток: остановить текущий активный звонок (удобная обёртка release). */
|
|
void call_audio_stop(void);
|
|
|
|
/* аудио-поток: закодировать PCM-кадр (ровно CALL_AUDIO_FRAME_SAMPLES) и отправить пиру. */
|
|
int call_audio_feed_pcm(uint64_t call_id, const int16_t* pcm, int count);
|
|
/* Mute после AEC/AGC: фильтр получает настоящий микрофон, Opus — нулевой PCM. */
|
|
/* Подготовленный PCM и маска mute (960 элементов); AEC уже выполнен до этого API. */
|
|
int call_audio_feed_prepared_pcm(uint64_t call_id, const int16_t* pcm, const uint8_t* mute_mask);
|
|
int call_audio_feed_pcm_muted(uint64_t call_id, const int16_t* pcm, int count, int muted);
|
|
|
|
/* аудио-поток: выдать до max_samples финального PCM (jitter + stretch + тоны).
|
|
* Возвращает число сэмплов (может быть < max — андерфлоу/конец тона). */
|
|
int call_audio_pull_pcm(uint64_t call_id, int16_t* out, int max_samples);
|
|
|
|
/* uasync-поток (из call.c): принятый Opus-кадр — кладём в джиттер-буфер (call_jitter_push,
|
|
* декодирование произойдёт на pull в аудио-потоке). */
|
|
void call_audio_on_media(struct UTUN_INSTANCE* inst, uint64_t call_id,
|
|
uint16_t seq, uint32_t ts_ms, const uint8_t* opus, int len);
|
|
|
|
/* uasync-поток: метрики джиттер-буфера для CALL_STATS (dropped/underruns — необязательные). */
|
|
int call_audio_get_stats(uint64_t call_id, int* buffer_ms, int* tempo_x100,
|
|
uint32_t* dropped, uint32_t* underruns, struct call_jitter_range* range);
|
|
|
|
/* После остановки указанного направления: сбросить AEC, для playback также устаревший jitter/PCM.
|
|
* Capture и playback могут работать в разных потоках, по одному writer на направление.
|
|
* Release допустим только после остановки обоих. */
|
|
void call_audio_reset_io(uint64_t call_id, int playback);
|
|
|
|
/* Core AEC для raw capture: Android — по спикерфону (route == SPEAKER).
|
|
* Prepared capture не создаёт core AEC; desktop передаёт настройку в VoiceAudioIo. */
|
|
void call_audio_set_aec_enabled(int enabled);
|
|
|
|
/* Задать задержку рендер→захват AEC в кадрах (20 мс). Android измеряет через
|
|
* AudioTrack/AudioRecord getTimestamp. Prepared desktop выравнивает референс по времени. Если core AEC уже
|
|
* активен — пересоздаётся с новой задержкой. */
|
|
void call_audio_set_aec_delay_frames(int frames);
|
|
|
|
#ifdef __cplusplus
|
|
}
|
|
#endif
|
|
|
|
#endif /* CALL_AUDIO_H */
|