Skip to content

[Proposal] SE-00004: SAP Announcement Support for libAES67 #17

@N3v1

Description

@N3v1

Proposal Title

SAP Announcement Support for libAES67

Proposal ID

SE-00004

Author

Nevio Hirani

Motivation

While the SDP subsystem enables libAES67 to generate and interpret stream metadata, many AES67 systems rely on SAP (Session Announcement Protocol) to broadcast the availability of RTP streams over multicast. SAP is defined in RFC 2974 and is commonly used in AES67 deployments for automatic stream discovery in unmanaged or loosely coordinated networks.

Without SAP support, libAES67-based transmitters cannot advertise their presence on the network, and receivers cannot discover streams automatically without out-of-band mechanisms. Adding native SAP support will improve zero-configuration interoperability with devices from Dante, Ravenna, Livewire, and other AES67-compliant vendors.

Specification

This proposal introduces SAP as a transmission mechanism for SDP-formatted stream announcements. The SAP sender will periodically multicast SDP packets to a defined group address and port (239.255.255.255:9875 by default). The SAP receiver will listen for announcements on the same multicast group and parse received SAP messages to extract SDP payloads.

Proposed Design

The SAP support in libAES67 will be implemented as a lightweight, modular subsystem that interfaces directly with the existing SDP core. It is designed to allow applications built on top of libAES67 to announce and discover AES67-compliant RTP streams using multicast SAP packets, without requiring any additional configuration or external tools.

On the transmitter side, the library will periodically generate a SAP packet embedding an SDP payload that describes the current stream. The SDP content will be obtained using the existing aes67_sdp_generate() function and encapsulated into a SAP-compliant message format. This packet will then be transmitted over UDP to a well-known multicast address (by default 239.255.255.255) on port 9875, as defined in RFC 2974. The transmission interval will be configurable, with a typical default of 5 seconds. Only SAP version 1 will be supported, and encryption or authentication features will be excluded from the initial implementation to reduce complexity and remain compatible with typical AES67 environments.

Each SAP packet consists of a fixed-length header, followed by a UTF-8 encoded SDP payload. The header includes metadata such as the version, message type (announcement or deletion), address type (IPv4 or IPv6), encryption flag, authentication header length (unused), and a 16-bit message ID hash used for duplicate suppression. In our case, the address type will always be IPv4, the encryption bit will be set to 0 (plaintext), and authentication will be disabled (Auth Len = 0).

SAP Packet Format

SAP messages are defined by the following structure, where the first 4 bytes represent the fixed-length header:

  0                   1                   2                   3
  0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
 |V=1|A|R|T|E|  Auth Len |      Message ID Hash                  |
 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
Fields
  • V (3 bits): SAP version, always 001.
  • A (1 bit): Address type, 0 for IPv4 (used here), 1 for IPv6.
  • R (1 bit): Reserved, must be zero.
  • T (1 bit): Message type: 0 for announcement, 1 for deletion.
  • E (1 bit): Encryption bit. Set to 0 (plaintext).
  • Auth Length (6 bits): Authentication header length in 32-bit words. Always 0 in this proposal.
  • Message ID Hash (16 bits): Computed CRC16 or hash of the SDP payload to identify duplicates.

Immediately after the header, the payload begins with the SDP data, encoded as UTF-8 text. No null terminator is required, but the message must not exceed the typical UDP MTU. In libAES67, the SAP message will be constructed in memory and sent over UDP using a dedicated socket. No authentication, source filtering, or encryption will be supported in the initial version.

On the receiver side, libAES67 will provide a SAP listener interface that opens a UDP socket and joins the designated SAP multicast group. This listener will continuously monitor incoming SAP packets on the socket and attempt to extract embedded SDP messages. When a valid SAP packet is received, the listener will verify the version and address type, check the header fields for conformity, and extract the SDP text payload. The payload is passed to aes67_sdp_parse() and then validated using aes67_sdp_validate(). If the result is AES67-compliant, a user-defined callback is invoked with the parsed aes67_sdp_session_t structure for further processing (e.g., joining a stream or updating a UI).

To support this architecture, the SAP subsystem will define two core public structures. The first is aes67_sap_announcement_t, which holds metadata for outgoing announcements, including the SDP string, announcement interval, and source address. The second is aes67_sap_listener_t, which encapsulates state for the UDP listener socket, callback function, and any internal buffering or filtering logic.

The sender side will expose functions to initialize, start, and stop periodic SAP announcements. Internally, this will be implemented using a timer or thread that calls aes67_sdp_generate() and wraps the result into a SAP header before transmitting it via a raw socket to the configured group address. The receiver will offer APIs to start listening, register callbacks, and stop reception cleanly.

The packet construction, parsing, and validation logic will be strictly compliant with RFC 2974, with allowances made for AES67-specific payload contents and constraints (e.g., payloads will always be SDP, and announcements will never use encryption or authentication headers).

Ultimately, this subsystem allows any libAES67 application to participate in multicast-based discovery workflows by broadcasting or passively receiving stream descriptions. This significantly improves interoperability in AoIP environments, particularly in zero-config scenarios, and provides a foundation for integrating with directory services or control protocols such as SIP or RTSP.

Required Types and Functions

To support this specification, the following public and internal APIs must be introduced in libAES67 to implement full SAP support for AES67 SDP stream advertisement and discovery.

Core Data Types

  • aes67_sap_announcement_t: Struct representing a local SDP announcement, including metadata like interval, source address, and SDP payload.
  • typedef void (*aes67_sap_callback_t)(const aes67_sdp_session_t* session, const struct sockaddr_in* from, void* user_ctx): Callback type invoked when a valid SAP packet with SDP content is received.
  • aes67_sap_listener_t: Opaque struct representing the state of a multicast SAP receiver (socket, callback, buffers).

SAP Lifecycle Functions

  • aes67_sap_start_announcement(const aes67_sap_announcement_t* ann): Starts periodic SAP announcement of the given SDP session.
  • aes67_sap_stop_announcement(void): Stops the current SAP announcement loop.
  • aes67_sap_start_listener(aes67_sap_listener_t* listener, aes67_sap_callback_t callback, void* user_ctx): Starts a SAP listener that invokes the callback on each valid announcement.
  • aes67_sap_stop_listener(aes67_sap_listener_t* listener): Stops the listener socket and background receiver logic.

Internal Packet Utilities

  • aes67_sap_build_packet(const char* sdp_text, size_t len, uint8_t* out_buf, size_t max_len): Builds a SAP-compliant packet header and appends SDP payload.
  • aes67_sap_parse_packet(const uint8_t* data, size_t len, char* out_sdp, size_t max_len): Extracts the SDP payload from a received SAP packet.
  • aes67_sap_hash(const char* sdp_text, size_t len): Computes the 16-bit Message ID Hash used for duplicate suppression.

Error Handling

  • aes67_sap_result_t: Enum representing the result of SAP operations (OK, INVALID_HEADER, SOCKET_ERROR, etc.).
  • aes67_sap_strerror(aes67_sap_result_t result): Converts a result code into a human-readable string.

Constants and Macros

  • AES67_SAP_PORT: Default port number (9875) for SAP messages.
  • AES67_SAP_GROUP_IPV4: Default IPv4 multicast address (239.255.255.255) for SAP.
  • AES67_SAP_VERSION: SAP version used (1).
  • AES67_SAP_HEADER_LEN: Length of the SAP packet header (4 bytes minimum).
  • AES67_SAP_MAX_PACKET_SIZE: Maximum size of a full SAP packet (typically 1400 bytes).
  • AES67_SAP_MAX_SDP_LEN: Maximum allowed size of the embedded SDP payload.
  • AES67_SAP_MSG_TYPE_ANNOUNCE: SAP message type constant for "announce" (0).
  • AES67_SAP_MSG_TYPE_DELETE: SAP message type constant for "delete" (1).
  • AES67_SAP_DEFAULT_INTERVAL: Default interval between announcements (e.g., 5000 ms).

Debugging and Diagnostics

  • aes67_sap_dump_packet(const uint8_t* packet, size_t len, FILE* out): Dumps the contents of a SAP packet for debug logging.
  • aes67_sap_dump_announcement(const aes67_sap_announcement_t* ann, FILE* out): Prints the metadata of an active SAP announcement.

Configuration Functions

  • aes67_sap_set_multicast_group(const char* ip): Sets the multicast group IP address used for SAP transmission/reception.
  • aes67_sap_set_multicast_port(uint16_t port): Sets the UDP port used for SAP.

Announcement Management

  • aes67_sap_register_announcement(const aes67_sap_announcement_t* ann): Registers an SDP stream for periodic SAP broadcast.
  • aes67_sap_unregister_by_id(uint16_t message_id_hash): Unregisters a specific SAP announcement by hash.

Discovery Utilities

  • aes67_sap_get_active_sessions(aes67_sdp_session_t* out_list[], size_t max_sessions)
    Returns a list of parsed and validated SDP sessions from recently received SAP packets.

Affected Layer

sdp

Alternatives Considered

None

Impact

This change will not break backward compatibility, has minimal performance impact, and will require updated documentation for the new SAP API.

References

Additional Notes

This proposal is part of a larger effort to enhance AES67 interoperability; feedback and contributions are welcome.

Is there an existing proposal for this?

  • I have searched the existing proposals

Metadata

Metadata

Assignees

Labels

P3Blocking or urgentcompilance: interopWorks with third-party AES67 systemscompilance: sdpSDP-related spec conformancelayer: apiPublic-facing C API (headers, symbols)layer: networkRTP, UDP, IP-level communicationlayer: sdpSDP parsing, generationplatform: crossAffects all or multiple platformsplatform: linuxAffects Linux-specific codeplatform: macosAffects macOS-specific codeplatform: windowsAffects Windows-specific codetype: featureNew functionality to be added

Projects

No projects

Milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions