#include "aes67_tx.h" #include #include "aes67_cfg.h" #include "aes67_web.h" #include "lwip/inet.h" // Defaults follow the Riedel Director 4-wire AES67 output; channels 2 (core default). static const char AES67_DEFAULTS[] = "{\"name\":\"AES67\",\"enabled\":true,\"discovery\":\"sap\",\"mcast\":\"239.69.1.10\"," "\"port\":5004,\"ttl\":32,\"dscp\":34,\"channels\":2,\"mono_sum\":false,\"encoding\":\"L24\"," "\"rate\":48000,\"ptime\":1,\"pt\":96,\"ssrc\":0,\"clk_offset\":0," "\"session_id\":1,\"session_ver\":1}"; // RTP multicast range 224.0.2.0 - 239.255.255.255 (keeps clear of 224.0.0.x/224.0.1.x, where PTP lives). static bool check_mcast(const cJSON *g, char *err, size_t n) { const cJSON *v = cJSON_GetObjectItemCaseSensitive(g, "mcast"); struct in_addr a; if (cJSON_IsString(v) && inet_aton(v->valuestring, &a)) { uint32_t ip = ntohl(a.s_addr); if (ip >= 0xE0000200 && ip <= 0xEFFFFFFF) { return true; } } snprintf(err, n, "mcast: must be 224.0.2.0 - 239.255.255.255"); return false; } static bool aes67_validate(const cJSON *g, char *err, size_t n) { static const char *const discovery[] = { "manual", "sap", NULL }; static const char *const encodings[] = { "L16", "L24", NULL }; static const double rates[] = { 48000, 96000 }; static const double ptimes[] = { 0.125, 0.25, 0.333, 1, 4 }; bool ok = cfg_check_str(g, "name", 1, 63, err, n) && cfg_check_enum(g, "discovery", discovery, err, n) && check_mcast(g, err, n) && cfg_check_int(g, "port", 1024, 65535, err, n) && cfg_check_int(g, "ttl", 1, 255, err, n) && cfg_check_int(g, "dscp", 0, 63, err, n) && cfg_check_int(g, "channels", 1, 2, err, n) && cfg_check_enum(g, "encoding", encodings, err, n) && cfg_check_num_in(g, "rate", rates, 2, err, n) && cfg_check_num_in(g, "ptime", ptimes, 5, err, n) && cfg_check_int(g, "pt", 96, 127, err, n) && cfg_check_int(g, "ssrc", 0, 4294967295.0, err, n) && cfg_check_int(g, "clk_offset", 0, 4294967295.0, err, n) && cfg_check_int(g, "session_id", 0, 4294967295.0, err, n) && cfg_check_int(g, "session_ver", 0, 4294967295.0, err, n); if (ok && cJSON_IsTrue(cJSON_GetObjectItemCaseSensitive(g, "mono_sum")) && cJSON_GetObjectItemCaseSensitive(g, "channels")->valuedouble != 1) { snprintf(err, n, "channels: must be 1 with mono_sum"); ok = false; } return ok; } // Stub (build step 2): counters stay 0 until the RTP sender exists (step 4). static void tx_status(cJSON *st) { cJSON_AddNumberToObject(st, "tx_packets", 0); cJSON_AddNumberToObject(st, "underruns", 0); } esp_err_t aes67_tx_init(void) { esp_err_t err = cfg_register("aes67", AES67_DEFAULTS, aes67_validate, NULL); if (err != ESP_OK) { return err; } return status_register(tx_status); }