/* * integration.c — PulseAudio connection and volume I/O tests * * Requires a live PulseAudio / PipeWire session. * Set ZEBRA_TEST_SINK to a sink-input index (from ./tx -l) before running. * If unset, PA connection tests still run; volume tests are skipped. * * Compile: gcc -Wall -O2 -Iinclude $(pkg-config --cflags libpulse) \ * -o test/integration test/integration.c src/pulse.c \ * $(pkg-config --libs libpulse) -lrt -lpthread */ #include #include #include #include "zebra.h" #include "modem.h" #include "test.h" static zebra_pulse_t z; static uint32_t test_sink = (uint32_t)-1; static int have_sink = 0; /* ------------------------------------------------------------------ * * PA connection * * ------------------------------------------------------------------ */ static void t_connect(void) { int r = zebra_pulse_connect(&z, "zebra-test"); T_EQ(r, 0); } static void t_list_sinks(void) { zebra_sink_t buf[64]; int n = zebra_list_sinks(&z, buf, 64); T_GE(n, 0); if (n > 0) { /* every entry must have a valid channel count */ for (int i = 0; i < n; i++) T_GE((int)buf[i].channels, 1); } } static void t_find_sink_miss(void) { zebra_sink_t s; int r = zebra_find_sink(&z, "____no_such_sink_xyzzy____", &s); T_EQ(r, -1); } /* ------------------------------------------------------------------ * * volume I/O (needs ZEBRA_TEST_SINK) * * ------------------------------------------------------------------ */ static void t_get_volume(void) { if (!have_sink) { fprintf(stderr, " (skip — ZEBRA_TEST_SINK not set)\n"); return; } uint8_t vol = 255; int r = zebra_get_volume(&z, test_sink, &vol); T_EQ(r, 0); T_LE((int)vol, 100); } static void t_set_get_roundtrip(void) { if (!have_sink) { fprintf(stderr, " (skip — ZEBRA_TEST_SINK not set)\n"); return; } uint8_t original = 255; zebra_get_volume(&z, test_sink, &original); /* set to MARK, read back */ zebra_set_volume(&z, test_sink, ZEBRA_VOL_MARK); uint8_t got = 0; int r = zebra_get_volume(&z, test_sink, &got); T_EQ(r, 0); /* PA quantises to PA_VOLUME_NORM steps — allow ±2% tolerance */ T_GE((int)got, (int)ZEBRA_VOL_MARK - 2); T_LE((int)got, (int)ZEBRA_VOL_MARK + 2); /* restore */ zebra_set_volume(&z, test_sink, original); } static void t_set_get_space(void) { if (!have_sink) { fprintf(stderr, " (skip — ZEBRA_TEST_SINK not set)\n"); return; } uint8_t original = 255; zebra_get_volume(&z, test_sink, &original); zebra_set_volume(&z, test_sink, ZEBRA_VOL_SPACE); uint8_t got = 0; zebra_get_volume(&z, test_sink, &got); T_GE((int)got, (int)ZEBRA_VOL_SPACE - 2); T_LE((int)got, (int)ZEBRA_VOL_SPACE + 2); zebra_set_volume(&z, test_sink, original); } static void t_vol_clamp_over_100(void) { if (!have_sink) { fprintf(stderr, " (skip — ZEBRA_TEST_SINK not set)\n"); return; } uint8_t original = 255; zebra_get_volume(&z, test_sink, &original); /* pct > 100 should be clamped, not crash */ int r = zebra_set_volume(&z, test_sink, 200); T_EQ(r, 0); uint8_t got = 0; zebra_get_volume(&z, test_sink, &got); T_LE((int)got, 100); zebra_set_volume(&z, test_sink, original); } /* ------------------------------------------------------------------ * * benchmark sanity * * ------------------------------------------------------------------ */ static void t_benchmark_range(void) { if (!have_sink) { fprintf(stderr, " (skip — ZEBRA_TEST_SINK not set)\n"); return; } int baud = zebra_benchmark_baud(&z, test_sink); T_GE(baud, ZEBRA_BAUD_MIN); T_LE(baud, ZEBRA_BAUD_MAX); fprintf(stderr, " measured: %d baud\n", baud); } /* ------------------------------------------------------------------ * * main * * ------------------------------------------------------------------ */ int main(void) { const char *sink_env = getenv("ZEBRA_TEST_SINK"); if (sink_env) { test_sink = (uint32_t)atoi(sink_env); have_sink = 1; fprintf(stderr, "ZEBRA_TEST_SINK=%u\n", test_sink); } else { fprintf(stderr, "ZEBRA_TEST_SINK not set — volume tests will skip\n"); fprintf(stderr, " run: ./tx -l to list sinks, then set the env var\n"); } T_SECTION("PA connection"); T_RUN(t_connect); T_RUN(t_list_sinks); T_RUN(t_find_sink_miss); T_SECTION("volume I/O"); T_RUN(t_get_volume); T_RUN(t_set_get_roundtrip); T_RUN(t_set_get_space); T_RUN(t_vol_clamp_over_100); T_SECTION("benchmark"); T_RUN(t_benchmark_range); zebra_pulse_disconnect(&z); T_SUMMARY(); }