dante_discovery.h 3.6 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788
  1. /*
  2. * SPDX-FileCopyrightText: 2026 Benjamin Harris
  3. * SPDX-License-Identifier: Apache-2.0
  4. *
  5. * Dante device discovery over mDNS / DNS-SD.
  6. *
  7. * CLEAN-ROOM: implemented from the behavioural notes in
  8. * docs/dante-protocol-notes.md (service types, ports, TXT keys), NOT from
  9. * any GPL/AGPL reference source. See CLAUDE.md.
  10. *
  11. * This is the read-only half of Dante discovery: it browses the network for
  12. * Dante devices and their transmit channels / multicast bundles and reports
  13. * what it finds. It does not advertise this device (that needs the ARC/CMC
  14. * servers behind it) and does not touch audio.
  15. *
  16. * Dante publishes these DNS-SD service types, all under _udp.local:
  17. * _netaudio-arc device control endpoint (ARC port, e.g. 4440)
  18. * _netaudio-cmc device announce endpoint (CMC port, e.g. 8800)
  19. * _netaudio-chan one instance per TX channel (flow-control port)
  20. * _netaudio-bund a multicast bundle other devices can join
  21. */
  22. #pragma once
  23. #include <stdint.h>
  24. #include <stdbool.h>
  25. #include "esp_err.h"
  26. #ifdef __cplusplus
  27. extern "C" {
  28. #endif
  29. /* Which Dante DNS-SD service a result came from. */
  30. typedef enum {
  31. DANTE_SVC_ARC = 0, /* _netaudio-arc — device control endpoint */
  32. DANTE_SVC_CMC, /* _netaudio-cmc — device announce endpoint */
  33. DANTE_SVC_CHAN, /* _netaudio-chan — a transmit channel */
  34. DANTE_SVC_BUND, /* _netaudio-bund — a multicast bundle */
  35. DANTE_SVC_COUNT
  36. } dante_service_type_t;
  37. /* One discovered service instance, flattened from an mDNS PTR+SRV+TXT+A set.
  38. * String fields are only valid for the duration of the callback. */
  39. typedef struct {
  40. dante_service_type_t service; /* which _netaudio-* type */
  41. const char *instance; /* DNS-SD instance name, e.g. "chanName@host" */
  42. const char *hostname; /* SRV target host */
  43. uint32_t ipv4; /* resolved IPv4 (host byte order), 0 if none */
  44. uint16_t port; /* SRV port */
  45. const char *const *txt_keys; /* TXT record keys (txt_count entries) */
  46. const char *const *txt_vals; /* TXT record values (txt_count entries) */
  47. size_t txt_count;
  48. } dante_discovery_result_t;
  49. /* Callback invoked once per discovered instance. `user` is passed through
  50. * from the scan/start call. Must not block for long. */
  51. typedef void (*dante_discovery_cb_t)(const dante_discovery_result_t *result,
  52. void *user);
  53. /*
  54. * One-shot synchronous scan of all Dante service types.
  55. *
  56. * Issues an mDNS PTR query per service type, waits up to `timeout_ms` for
  57. * each, and invokes `cb` for every instance found. If `cb` is NULL, results
  58. * are logged at INFO level instead. Safe to call whether or not the AES67
  59. * stack has already initialised mDNS (init is shared and idempotent).
  60. *
  61. * Returns ESP_OK if the scan ran (even if nothing was found).
  62. */
  63. esp_err_t dante_discovery_scan(uint32_t timeout_ms,
  64. dante_discovery_cb_t cb, void *user);
  65. /*
  66. * Start a background task that repeats dante_discovery_scan() every
  67. * `interval_ms`. `cb`/`user` are as above. Only one background scanner may
  68. * run at a time. Pin/priority follow project convention (core 0, low prio).
  69. */
  70. esp_err_t dante_discovery_start(uint32_t interval_ms,
  71. dante_discovery_cb_t cb, void *user);
  72. /* Stop the background scanner started by dante_discovery_start(). */
  73. void dante_discovery_stop(void);
  74. /* Human-readable name for a service type, e.g. "_netaudio-arc". */
  75. const char *dante_service_type_str(dante_service_type_t svc);
  76. #ifdef __cplusplus
  77. }
  78. #endif