You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
86 lines
3.3 KiB
86 lines
3.3 KiB
// test_radio_audio.cpp — тест аудио-движка рации (jitter + микшер). |
|
// |
|
// Проверяет сервисный слой src/radio/radio_audio.c без полного UTUN_INSTANCE: |
|
// 1. single-source: подаём кодированные Opus-кадры через radio_audio_on_frame, |
|
// radio_audio_pull_pcm выдаёт декодированный ненулевой PCM (jitter+decode). |
|
// 2. mixing: два источника с большими амплитудами — сумма насыщается (soft-clip), |
|
// что доказывает микширование нескольких источников. |
|
// |
|
// Сборка/запуск: через CMake (tools/chatgui), линкуется utun_voice + utun. |
|
|
|
#include "radio/radio_audio.h" |
|
|
|
extern "C" { |
|
#include "../../lib/opus_codec.h" |
|
} |
|
|
|
#include <cstdio> |
|
#include <cstring> |
|
#include <cstdlib> |
|
#include <cmath> |
|
|
|
#define GID 0x1234567890abcdefULL |
|
#define SRC_A 0xAAAAULL |
|
#define SRC_B 0xBBBBULL |
|
|
|
static int G_PASSED = 0, G_FAILED = 0, G_TOTAL = 0; |
|
#define TEST(n) do { G_TOTAL++; printf(" %-58s", n); fflush(stdout); } while(0) |
|
#define OK() do { G_PASSED++; printf("OK\n"); } while(0) |
|
#define FAIL(f,...) do { G_FAILED++; printf("FAIL: " f "\n", ##__VA_ARGS__); } while(0) |
|
|
|
/* закодировать N кадров постоянного PCM и подать через on_frame */ |
|
static void push_const(uint64_t src, uint16_t stream, int value, int nframes) { |
|
opus_codec_encoder_t* enc = opus_codec_encoder_create(48000, 1); |
|
if (!enc) { FAIL("encoder create failed"); return; } |
|
opus_codec_encoder_bitrate_set(enc, 32000); |
|
|
|
int16_t pcm[960]; |
|
for (int i = 0; i < 960; i++) pcm[i] = (int16_t)value; |
|
|
|
for (int f = 0; f < nframes; f++) { |
|
uint8_t opus[256]; |
|
int len = opus_codec_encode(enc, pcm, 960, opus, (int)sizeof(opus)); |
|
if (len <= 0) { FAIL("encode failed"); break; } |
|
radio_audio_on_frame(NULL, GID, src, stream, (uint16_t)f, 0, opus, len, NULL); |
|
} |
|
opus_codec_encoder_destroy(enc); |
|
} |
|
|
|
/* вытянуть pull-цикл, вернуть max |sample| */ |
|
static int pull_max_abs(int npulls) { |
|
int mx = 0; |
|
int16_t out[960]; |
|
for (int p = 0; p < npulls; p++) { |
|
int n = radio_audio_pull_pcm(GID, out, 960); |
|
(void)n; |
|
for (int i = 0; i < 960; i++) { |
|
int a = out[i] < 0 ? -out[i] : out[i]; |
|
if (a > mx) mx = a; |
|
} |
|
} |
|
return mx; |
|
} |
|
|
|
int main() { |
|
printf("=== test_radio_audio ===\n"); fflush(stdout); |
|
|
|
TEST("single-source: decode через jitter-буфер выдаёт ненулевой PCM"); { |
|
radio_audio_start(GID); |
|
push_const(SRC_A, 1, 10000, 5); |
|
int mx = pull_max_abs(10); |
|
radio_audio_stop(); |
|
if (mx > 1000) OK(); else FAIL("max|pcm|=%d (ожидали > 1000)", mx); |
|
} |
|
|
|
TEST("mixing: два источника складываются (soft-clip)"); { |
|
radio_audio_start(GID); |
|
push_const(SRC_A, 1, 20000, 5); |
|
push_const(SRC_B, 1, 20000, 5); |
|
int mx = pull_max_abs(10); |
|
radio_audio_stop(); |
|
if (mx > 30000) OK(); else FAIL("max|pcm|=%d (ожидали > 30000 — сумма двух источников)", mx); |
|
} |
|
|
|
printf("\n%d/%d passed, %d failed\n", G_PASSED, G_TOTAL, G_FAILED); |
|
return G_FAILED > 0 ? 1 : 0; |
|
}
|
|
|