/* * server/media_relay.h — UDP SFU relay for M2 voice. * * Design: docs/architecture.md §5, docs/voice.md §2. * Receives encrypted UDP voice frames from clients, decrypts+authenticates them, * re-encrypts for each channel member, and forwards. * * Flow: * 1. Client sends kFrameUdpBinding UDP packet (plaintext) → MediaRelay looks up * the 16-byte token in SessionRegistry, associates the sender endpoint with * the ConnSession, and calls session->set_udp_endpoint(). * 2. Client sends kFrameVoice UDP packets → MediaRelay decrypts via recv_crypto(), * finds channel members via find_channel_sessions(), re-encrypts via send_crypto(), * and sends to each member's UDP endpoint. */ #ifndef VOICECAT_SERVER_MEDIA_RELAY_H #define VOICECAT_SERVER_MEDIA_RELAY_H #ifdef VOICECAT_HAS_NET #include #define ASIO_STANDALONE 1 #include #include "net/transport.h" namespace voicecat::server { class SessionRegistry; class MediaRelay { public: MediaRelay(asio::io_context& io, std::shared_ptr registry); ~MediaRelay(); // Bind the UDP socket. port=0 lets the OS pick. Must be called before start(). bool bind(uint16_t port = 0); // Begin async receive loop. Call once after bind(). void start(); // Stop receiving and close the socket. void stop(); // Actual bound port (after bind()). uint16_t media_port() const; private: void on_udp_frame(const uint8_t* data, size_t len, asio::ip::udp::endpoint sender); asio::io_context& io_; std::shared_ptr registry_; voicecat::net::UdpMediaChannel udp_; // Scratch buffer for re-encrypted payloads (size = max_frame + 16 MAC) static constexpr size_t kMaxPayload = 1500; std::vector seal_buf_ = std::vector(kMaxPayload + 16, uint8_t{0}); std::vector plain_buf_ = std::vector(kMaxPayload, uint8_t{0}); }; } // namespace voicecat::server #endif // VOICECAT_HAS_NET #endif // VOICECAT_SERVER_MEDIA_RELAY_H