From 47d41f8643e609f6ca3063b1f9f3266415efe74f Mon Sep 17 00:00:00 2001 From: jrd Date: Fri, 17 Jul 2026 21:32:34 +0000 Subject: [PATCH 1/4] docs/JAMULUS_PROTOCOL.md: message reference, directory flows, small fixes - Explain how receivers classify datagrams (protocol frame vs audio) and specify the CRC and the acknowledge/retransmit mechanism - Add a complete message-ID reference for connection-based and connectionless messages - Add a section on directory registration, server lists and NAT hole punching (registration refresh/timeout intervals, CLM message flows) - Fix message names to match protocol.h (REQ_CHANNEL_INFOS, CHANNEL_INFOS, REQ_CONN_CLIENTS_LIST) Co-Authored-By: Claude Fable 5 --- docs/JAMULUS_PROTOCOL.md | 87 ++++++++++++++++++++++++++++++++++++---- 1 file changed, 80 insertions(+), 7 deletions(-) diff --git a/docs/JAMULUS_PROTOCOL.md b/docs/JAMULUS_PROTOCOL.md index 20fc0438f0..1add08b5e8 100644 --- a/docs/JAMULUS_PROTOCOL.md +++ b/docs/JAMULUS_PROTOCOL.md @@ -45,7 +45,7 @@ along with this program. If not, see [](https:// # The Jamulus Audio Protocol Jamulus uses connectionless UDP packets to communicate between the client and server, and additionally for directory server registration. The `src/protocol.cpp` file contains much of the details of the packets themselves, whereas this document is intended to form a higher-level view of the protocol interactions. -Some of the messages need to be acknowledged, some do not. If a message ID is less than 1000, the message must be acknowledged in under `SEND_MESS_TIMEOUT_MS` ms. +Messages with an ID below 1000 are connection-based: each one is acknowledged by an `ACKN (1)` message carrying the same sequence counter, and the sender retransmits it every `SEND_MESS_TIMEOUT_MS` ms until the acknowledgement arrives. Messages with an ID of 1000 or above (`CLM_*`) are connectionless: they work without an established audio connection and are never acknowledged. All of this information can be discovered from reading the code, but hopefully is quicker to digest when available in one location. There is a wireshark dissector available too, [here](https://github.com/softins/jamulus-wireshark), if you would like to inspect the packet flow. @@ -68,6 +68,10 @@ LENgth of the data precedes the data and is followed by a CRC for the packet. Data is sent little-endian, i.e. not network byte-order. +The CRC is 16 bits, generator polynomial x¹⁶ + x¹² + x⁵ + 1 (CCITT), initial state all ones, calculated over the entire message and transmitted inverted. + +Audio and protocol messages share one UDP port. A receiver classifies every incoming datagram by attempting to parse it as a protocol frame — zero TAG bytes, consistent length, valid CRC. Anything that fails this parse is treated as an audio packet (see `CSocket::ProcessPacket()` in `src/socket.cpp`). + Where a message will not fit into the maximum packet size before fragmentation, a split message container is used. ``` @@ -83,6 +87,64 @@ DATA is the fragment data to be re-assembled This forms the data component of the packet above. +## Message Reference + +Connection-based messages (acknowledged; `PROTMESSID_` prefix omitted). Full payload layouts are in the header comment of `src/protocol.cpp`. + +| ID | Name | Purpose | +|---|---|---| +| 1 | `ACKN` | Acknowledges the message ID/counter it carries | +| 10 | `JITT_BUF_SIZE` | Set jitter buffer size | +| 11 | `REQ_JITT_BUF_SIZE` | Request jitter buffer size | +| 13 | `CHANNEL_GAIN` | Set a channel's gain in your mix | +| 16 | `REQ_CONN_CLIENTS_LIST` | Request connected-clients list | +| 18 | `CHAT_TEXT` | Chat text | +| 20 | `NETW_TRANSPORT_PROPS` | Audio transport properties | +| 21 | `REQ_NETW_TRANSPORT_PROPS` | Request audio transport properties | +| 23 | `REQ_CHANNEL_INFOS` | Request channel info (name, instrument, …) | +| 24 | `CONN_CLIENTS_LIST` | Channel info of all connected clients | +| 25 | `CHANNEL_INFOS` | Set own channel info | +| 26 | `OPUS_SUPPORTED` | OPUS codec is supported | +| 27 | `LICENCE_REQUIRED` | Server requires licence agreement | +| 29 | `VERSION_AND_OS` | Version and operating system | +| 30 | `CHANNEL_PAN` | Set a channel's pan in your mix | +| 31 | `MUTE_STATE_CHANGED` | Your signal was (un)muted at another client | +| 32 | `CLIENT_ID` | Your channel ID on the server | +| 33 | `RECORDER_STATE` | Jam recorder state | +| 34 | `REQ_SPLIT_MESS_SUPPORT` | Request split-message support | +| 35 | `SPLIT_MESS_SUPPORTED` | Split messages are supported | +| 36 | `RAWAUDIO_SUPPORTED` | Raw (uncompressed) audio is supported | +| 2001 | `SPECIAL_SPLIT_MESSAGE` | Container for split messages | + +IDs 12, 14, 15, 17, 19, 22 and 28 are legacy messages no longer sent (28, `REQ_CHANNEL_LEVEL_LIST`, is still understood for compatibility with servers 3.4.6–3.5.12). + +Connectionless messages (never acknowledged): + +| ID | Name | Purpose | +|---|---|---| +| 1001 | `CLM_PING_MS` | Ping time measurement | +| 1002 | `CLM_PING_MS_WITHNUMCLIENTS` | Ping plus number of connected clients | +| 1003 | `CLM_SERVER_FULL` | Server is full | +| 1004 | `CLM_REGISTER_SERVER` | Register with a directory | +| 1005 | `CLM_UNREGISTER_SERVER` | Unregister from a directory | +| 1006 | `CLM_SERVER_LIST` | Full server list | +| 1007 | `CLM_REQ_SERVER_LIST` | Request server list | +| 1008 | `CLM_SEND_EMPTY_MESSAGE` | Ask recipient to send `CLM_EMPTY_MESSAGE` to the carried address | +| 1009 | `CLM_EMPTY_MESSAGE` | Empty message (NAT hole punching) | +| 1010 | `CLM_DISCONNECTION` | Disconnect from server | +| 1011 | `CLM_VERSION_AND_OS` | Version and operating system | +| 1012 | `CLM_REQ_VERSION_AND_OS` | Request version and operating system | +| 1013 | `CLM_CONN_CLIENTS_LIST` | Connected-clients info | +| 1014 | `CLM_REQ_CONN_CLIENTS_LIST` | Request connected-clients info | +| 1015 | `CLM_CHANNEL_LEVEL_LIST` | Channel level list | +| 1016 | `CLM_REGISTER_SERVER_RESP` | Registration result | +| 1017 | `CLM_REGISTER_SERVER_EX` | Register with extended information | +| 1018 | `CLM_RED_SERVER_LIST` | Reduced server list (less UDP fragmentation) | +| 1019 | `CLM_SERVER_FEATURES` | Server features | +| 1020 | `CLM_REQ_SERVER_FEATURES` | Request server features | +| 1021 | `CLM_WELCOME_MESSAGE` | Server welcome message | +| 1022 | `CLM_REQ_WELCOME_MESSAGE` | Request server welcome message | + ## Client Session with a Server As the protocol is connectionless, the message flow at session start up can happen out of order. @@ -95,20 +157,20 @@ The server on a new client connection will: - Determine if the client supports split messages, with a `REQ_SPLIT_MESSAGE_SUPPORT (34, 0x2200)` message. - Request the details of the audio packets from the client with a `REQ_NETW_TRANSPORT_PROPS (21, 0x1500)` message, - Request the number of jitter buffer value to use, with a `REQ_JITT_BUF_SIZE (11, 0x0B00)` message. -- Request the details of the channel info, with a `REQ_CHANNELS_INFOS (23, 0x1700)` message. +- Request the details of the channel info, with a `REQ_CHANNEL_INFOS (23, 0x1700)` message. - Send the version and OS of the server, with a `VERSION_AND_OS (29, 0x1d00)` message. This is defined in `CServer::OnNewConnection()` The client on a new connection will: -- Send its channel info with a `CHANNELS_INFO (25, 0x1900)` message -- Request the list of connected clients with a `REQ_CONN_CLIENT_LIST (16, 0x1000)` message +- Send its channel info with a `CHANNEL_INFOS (25, 0x1900)` message +- Request the list of connected clients with a `REQ_CONN_CLIENTS_LIST (16, 0x1000)` message - Set the server-side jitter buffer value with a `JITT_BUF_SIZE (10, 0x0a00)` message This is defined in `CClient::OnNewConnection()` -At the end of the session, the client calls the `CLM_DISCONNECTION (1010, 0xf203)` message, until the server stops streaming audio to it. +At the end of the session, the client repeatedly sends a `CLM_DISCONNECTION (1010, 0xf203)` message, until the server stops streaming audio to it. A typical flow would be: @@ -156,8 +218,8 @@ A typical flow would be: ACK(RECORDER_STATE) -------------------> - REQ_CONNECTED_CLIENTS_LIST (16, 0x1000) ----> - <------------------------------------ ACK(REQ_CONNECTED_CLIENTS_LIST) + REQ_CONN_CLIENTS_LIST (16, 0x1000) --------> + <------------------------------------ ACK(REQ_CONN_CLIENTS_LIST) REQ_CHANNEL_LEVEL_LIST (28, 0x1c00) --------> @@ -205,6 +267,17 @@ Some typical messages could be: --- +## Directory Registration and Server Lists + +A directory is a Jamulus server acting as a registry (implemented in `src/serverlist.cpp`, both roles). All directory traffic uses connectionless messages: + +- A server registers with `CLM_REGISTER_SERVER_EX (1017)` (older versions: `CLM_REGISTER_SERVER (1004)`) and receives `CLM_REGISTER_SERVER_RESP (1016)` carrying the result (registered, list full, version too old, requirements not fulfilled). If no response arrives, registration is retried every 500 ms, up to 5 times. +- Registration is refreshed every 15 minutes; the directory drops a server it has not heard from for 33 minutes. `CLM_UNREGISTER_SERVER (1005)` removes the entry immediately at shutdown. +- A client requests the list with `CLM_REQ_SERVER_LIST (1007)`. The directory answers with both `CLM_RED_SERVER_LIST (1018)` (a reduced form that avoids UDP fragmentation) and `CLM_SERVER_LIST (1006)`. The client then pings each listed server with `CLM_PING_MS_WITHNUMCLIENTS (1002)` to display latency and occupancy. +- NAT hole punching: when it answers a list request, the directory also sends every registered server a `CLM_SEND_EMPTY_MESSAGE (1008)` carrying the client's public address; each server responds by sending `CLM_EMPTY_MESSAGE (1009)` to that address, opening its own NAT/firewall for the client's subsequent packets. The directory and its registered servers also ping each other about once a minute to keep their NAT mappings alive. + +--- + ## Audio Packet Structure The OPUS codec is used to compress the audio over the network and the packets are documented [here](https://datatracker.ietf.org/doc/html/rfc6716). From 8f8e9299d16f65485d12d6c3bb9dcddc8654c8e1 Mon Sep 17 00:00:00 2001 From: John Dempsey <1750243+mcfnord@users.noreply.github.com> Date: Sat, 18 Jul 2026 12:46:57 -0700 Subject: [PATCH 2/4] Update docs/JAMULUS_PROTOCOL.md Co-authored-by: Peter L Jones --- docs/JAMULUS_PROTOCOL.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/JAMULUS_PROTOCOL.md b/docs/JAMULUS_PROTOCOL.md index 1add08b5e8..71d002e4cc 100644 --- a/docs/JAMULUS_PROTOCOL.md +++ b/docs/JAMULUS_PROTOCOL.md @@ -272,7 +272,7 @@ Some typical messages could be: A directory is a Jamulus server acting as a registry (implemented in `src/serverlist.cpp`, both roles). All directory traffic uses connectionless messages: - A server registers with `CLM_REGISTER_SERVER_EX (1017)` (older versions: `CLM_REGISTER_SERVER (1004)`) and receives `CLM_REGISTER_SERVER_RESP (1016)` carrying the result (registered, list full, version too old, requirements not fulfilled). If no response arrives, registration is retried every 500 ms, up to 5 times. -- Registration is refreshed every 15 minutes; the directory drops a server it has not heard from for 33 minutes. `CLM_UNREGISTER_SERVER (1005)` removes the entry immediately at shutdown. +- Registration is refreshed every 15 minutes; the directory drops a server it has not heard from for 33 minutes. `CLM_UNREGISTER_SERVER (1005)` removes the entry immediately at shutdown or when changing Directory through the Server UI. - A client requests the list with `CLM_REQ_SERVER_LIST (1007)`. The directory answers with both `CLM_RED_SERVER_LIST (1018)` (a reduced form that avoids UDP fragmentation) and `CLM_SERVER_LIST (1006)`. The client then pings each listed server with `CLM_PING_MS_WITHNUMCLIENTS (1002)` to display latency and occupancy. - NAT hole punching: when it answers a list request, the directory also sends every registered server a `CLM_SEND_EMPTY_MESSAGE (1008)` carrying the client's public address; each server responds by sending `CLM_EMPTY_MESSAGE (1009)` to that address, opening its own NAT/firewall for the client's subsequent packets. The directory and its registered servers also ping each other about once a minute to keep their NAT mappings alive. From 9e5408c3ca5a98718856a6fb21b3728cee996825 Mon Sep 17 00:00:00 2001 From: jrd Date: Sat, 18 Jul 2026 19:59:54 +0000 Subject: [PATCH 3/4] docs/JAMULUS_PROTOCOL.md: apply style guide capitalisation Per review: Client, Server and Directory capitalised when referring to Jamulus in that role, per https://jamulus.io/contribute/Style-and-Tone. Also applies the guide's other defined terms present here (Channel, Jitter Buffer), sentence-case headings, and unit spacing (48 kHz). Code identifiers, message names and file paths unchanged. Co-Authored-By: Claude Fable 5 --- docs/JAMULUS_PROTOCOL.md | 104 +++++++++++++++++++-------------------- 1 file changed, 52 insertions(+), 52 deletions(-) diff --git a/docs/JAMULUS_PROTOCOL.md b/docs/JAMULUS_PROTOCOL.md index 71d002e4cc..c9e20ff10d 100644 --- a/docs/JAMULUS_PROTOCOL.md +++ b/docs/JAMULUS_PROTOCOL.md @@ -42,12 +42,12 @@ GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see [](https://www.gnu.org/licenses/). -# The Jamulus Audio Protocol +# The Jamulus audio protocol -Jamulus uses connectionless UDP packets to communicate between the client and server, and additionally for directory server registration. The `src/protocol.cpp` file contains much of the details of the packets themselves, whereas this document is intended to form a higher-level view of the protocol interactions. +Jamulus uses connectionless UDP packets to communicate between the Client and Server, and additionally for registration with a Directory. The `src/protocol.cpp` file contains much of the details of the packets themselves, whereas this document is intended to form a higher-level view of the protocol interactions. Messages with an ID below 1000 are connection-based: each one is acknowledged by an `ACKN (1)` message carrying the same sequence counter, and the sender retransmits it every `SEND_MESS_TIMEOUT_MS` ms until the acknowledgement arrives. Messages with an ID of 1000 or above (`CLM_*`) are connectionless: they work without an established audio connection and are never acknowledged. -All of this information can be discovered from reading the code, but hopefully is quicker to digest when available in one location. There is a wireshark dissector available too, [here](https://github.com/softins/jamulus-wireshark), if you would like to inspect the packet flow. +All of this information can be discovered from reading the code, but hopefully is quicker to digest when available in one location. There is a Wireshark dissector available too, [here](https://github.com/softins/jamulus-wireshark), if you would like to inspect the packet flow. --- @@ -87,90 +87,90 @@ DATA is the fragment data to be re-assembled This forms the data component of the packet above. -## Message Reference +## Message reference Connection-based messages (acknowledged; `PROTMESSID_` prefix omitted). Full payload layouts are in the header comment of `src/protocol.cpp`. | ID | Name | Purpose | |---|---|---| | 1 | `ACKN` | Acknowledges the message ID/counter it carries | -| 10 | `JITT_BUF_SIZE` | Set jitter buffer size | -| 11 | `REQ_JITT_BUF_SIZE` | Request jitter buffer size | -| 13 | `CHANNEL_GAIN` | Set a channel's gain in your mix | -| 16 | `REQ_CONN_CLIENTS_LIST` | Request connected-clients list | +| 10 | `JITT_BUF_SIZE` | Set Jitter Buffer size | +| 11 | `REQ_JITT_BUF_SIZE` | Request Jitter Buffer size | +| 13 | `CHANNEL_GAIN` | Set a Channel's gain in your mix | +| 16 | `REQ_CONN_CLIENTS_LIST` | Request list of connected Clients | | 18 | `CHAT_TEXT` | Chat text | | 20 | `NETW_TRANSPORT_PROPS` | Audio transport properties | | 21 | `REQ_NETW_TRANSPORT_PROPS` | Request audio transport properties | -| 23 | `REQ_CHANNEL_INFOS` | Request channel info (name, instrument, …) | -| 24 | `CONN_CLIENTS_LIST` | Channel info of all connected clients | -| 25 | `CHANNEL_INFOS` | Set own channel info | +| 23 | `REQ_CHANNEL_INFOS` | Request Channel info (name, instrument, …) | +| 24 | `CONN_CLIENTS_LIST` | Channel info of all connected Clients | +| 25 | `CHANNEL_INFOS` | Set own Channel info | | 26 | `OPUS_SUPPORTED` | OPUS codec is supported | | 27 | `LICENCE_REQUIRED` | Server requires licence agreement | | 29 | `VERSION_AND_OS` | Version and operating system | -| 30 | `CHANNEL_PAN` | Set a channel's pan in your mix | -| 31 | `MUTE_STATE_CHANGED` | Your signal was (un)muted at another client | -| 32 | `CLIENT_ID` | Your channel ID on the server | +| 30 | `CHANNEL_PAN` | Set a Channel's pan in your mix | +| 31 | `MUTE_STATE_CHANGED` | Your signal was (un)muted at another Client | +| 32 | `CLIENT_ID` | Your Channel ID on the Server | | 33 | `RECORDER_STATE` | Jam recorder state | | 34 | `REQ_SPLIT_MESS_SUPPORT` | Request split-message support | | 35 | `SPLIT_MESS_SUPPORTED` | Split messages are supported | | 36 | `RAWAUDIO_SUPPORTED` | Raw (uncompressed) audio is supported | | 2001 | `SPECIAL_SPLIT_MESSAGE` | Container for split messages | -IDs 12, 14, 15, 17, 19, 22 and 28 are legacy messages no longer sent (28, `REQ_CHANNEL_LEVEL_LIST`, is still understood for compatibility with servers 3.4.6–3.5.12). +IDs 12, 14, 15, 17, 19, 22 and 28 are legacy messages no longer sent (28, `REQ_CHANNEL_LEVEL_LIST`, is still understood for compatibility with Servers 3.4.6–3.5.12). Connectionless messages (never acknowledged): | ID | Name | Purpose | |---|---|---| | 1001 | `CLM_PING_MS` | Ping time measurement | -| 1002 | `CLM_PING_MS_WITHNUMCLIENTS` | Ping plus number of connected clients | +| 1002 | `CLM_PING_MS_WITHNUMCLIENTS` | Ping plus number of connected Clients | | 1003 | `CLM_SERVER_FULL` | Server is full | -| 1004 | `CLM_REGISTER_SERVER` | Register with a directory | -| 1005 | `CLM_UNREGISTER_SERVER` | Unregister from a directory | -| 1006 | `CLM_SERVER_LIST` | Full server list | -| 1007 | `CLM_REQ_SERVER_LIST` | Request server list | +| 1004 | `CLM_REGISTER_SERVER` | Register with a Directory | +| 1005 | `CLM_UNREGISTER_SERVER` | Unregister from a Directory | +| 1006 | `CLM_SERVER_LIST` | Full Server list | +| 1007 | `CLM_REQ_SERVER_LIST` | Request Server list | | 1008 | `CLM_SEND_EMPTY_MESSAGE` | Ask recipient to send `CLM_EMPTY_MESSAGE` to the carried address | | 1009 | `CLM_EMPTY_MESSAGE` | Empty message (NAT hole punching) | -| 1010 | `CLM_DISCONNECTION` | Disconnect from server | +| 1010 | `CLM_DISCONNECTION` | Disconnect from Server | | 1011 | `CLM_VERSION_AND_OS` | Version and operating system | | 1012 | `CLM_REQ_VERSION_AND_OS` | Request version and operating system | -| 1013 | `CLM_CONN_CLIENTS_LIST` | Connected-clients info | -| 1014 | `CLM_REQ_CONN_CLIENTS_LIST` | Request connected-clients info | +| 1013 | `CLM_CONN_CLIENTS_LIST` | Connected Clients info | +| 1014 | `CLM_REQ_CONN_CLIENTS_LIST` | Request connected Clients info | | 1015 | `CLM_CHANNEL_LEVEL_LIST` | Channel level list | | 1016 | `CLM_REGISTER_SERVER_RESP` | Registration result | | 1017 | `CLM_REGISTER_SERVER_EX` | Register with extended information | -| 1018 | `CLM_RED_SERVER_LIST` | Reduced server list (less UDP fragmentation) | +| 1018 | `CLM_RED_SERVER_LIST` | Reduced Server list (less UDP fragmentation) | | 1019 | `CLM_SERVER_FEATURES` | Server features | -| 1020 | `CLM_REQ_SERVER_FEATURES` | Request server features | +| 1020 | `CLM_REQ_SERVER_FEATURES` | Request Server features | | 1021 | `CLM_WELCOME_MESSAGE` | Server welcome message | -| 1022 | `CLM_REQ_WELCOME_MESSAGE` | Request server welcome message | +| 1022 | `CLM_REQ_WELCOME_MESSAGE` | Request Server welcome message | -## Client Session with a Server +## Client session with a Server As the protocol is connectionless, the message flow at session start up can happen out of order. -When a client starts a session with a server, it sends valid audio packets to the server port, to which the server will respond with the audio mix for that client. +When a Client starts a session with a Server, it sends valid audio packets to the Server port, to which the Server will respond with the audio mix for that Client. -The server on a new client connection will: +The Server on a new Client connection will: -- Tell the client connection its ID, with a `CLIENT_ID (32, 0x2000)` message. -- Reset the connected client list with a `CONN_CLIENTS_LIST (24, 0x1800)` message. -- Determine if the client supports split messages, with a `REQ_SPLIT_MESSAGE_SUPPORT (34, 0x2200)` message. -- Request the details of the audio packets from the client with a `REQ_NETW_TRANSPORT_PROPS (21, 0x1500)` message, -- Request the number of jitter buffer value to use, with a `REQ_JITT_BUF_SIZE (11, 0x0B00)` message. -- Request the details of the channel info, with a `REQ_CHANNEL_INFOS (23, 0x1700)` message. -- Send the version and OS of the server, with a `VERSION_AND_OS (29, 0x1d00)` message. +- Tell the Client connection its ID, with a `CLIENT_ID (32, 0x2000)` message. +- Reset the connected Client list with a `CONN_CLIENTS_LIST (24, 0x1800)` message. +- Determine if the Client supports split messages, with a `REQ_SPLIT_MESSAGE_SUPPORT (34, 0x2200)` message. +- Request the details of the audio packets from the Client with a `REQ_NETW_TRANSPORT_PROPS (21, 0x1500)` message, +- Request the Jitter Buffer value to use, with a `REQ_JITT_BUF_SIZE (11, 0x0B00)` message. +- Request the details of the Channel info, with a `REQ_CHANNEL_INFOS (23, 0x1700)` message. +- Send the version and OS of the Server, with a `VERSION_AND_OS (29, 0x1d00)` message. This is defined in `CServer::OnNewConnection()` -The client on a new connection will: +The Client on a new connection will: -- Send its channel info with a `CHANNEL_INFOS (25, 0x1900)` message -- Request the list of connected clients with a `REQ_CONN_CLIENTS_LIST (16, 0x1000)` message -- Set the server-side jitter buffer value with a `JITT_BUF_SIZE (10, 0x0a00)` message +- Send its Channel info with a `CHANNEL_INFOS (25, 0x1900)` message +- Request the list of connected Clients with a `REQ_CONN_CLIENTS_LIST (16, 0x1000)` message +- Set the Server-side Jitter Buffer value with a `JITT_BUF_SIZE (10, 0x0a00)` message This is defined in `CClient::OnNewConnection()` -At the end of the session, the client repeatedly sends a `CLM_DISCONNECTION (1010, 0xf203)` message, until the server stops streaming audio to it. +At the end of the session, the Client repeatedly sends a `CLM_DISCONNECTION (1010, 0xf203)` message, until the Server stops streaming audio to it. A typical flow would be: @@ -237,7 +237,7 @@ A typical flow would be: ACK(CONN_CLIENTS_LIST) ----------------> ``` -## General Streaming Messages +## General streaming messages During streaming, some control messages are used. Some typical messages could be: @@ -267,22 +267,22 @@ Some typical messages could be: --- -## Directory Registration and Server Lists +## Directory registration and Server lists -A directory is a Jamulus server acting as a registry (implemented in `src/serverlist.cpp`, both roles). All directory traffic uses connectionless messages: +A Directory is a Jamulus Server acting as a registry (implemented in `src/serverlist.cpp`, both roles). All Directory traffic uses connectionless messages: -- A server registers with `CLM_REGISTER_SERVER_EX (1017)` (older versions: `CLM_REGISTER_SERVER (1004)`) and receives `CLM_REGISTER_SERVER_RESP (1016)` carrying the result (registered, list full, version too old, requirements not fulfilled). If no response arrives, registration is retried every 500 ms, up to 5 times. -- Registration is refreshed every 15 minutes; the directory drops a server it has not heard from for 33 minutes. `CLM_UNREGISTER_SERVER (1005)` removes the entry immediately at shutdown or when changing Directory through the Server UI. -- A client requests the list with `CLM_REQ_SERVER_LIST (1007)`. The directory answers with both `CLM_RED_SERVER_LIST (1018)` (a reduced form that avoids UDP fragmentation) and `CLM_SERVER_LIST (1006)`. The client then pings each listed server with `CLM_PING_MS_WITHNUMCLIENTS (1002)` to display latency and occupancy. -- NAT hole punching: when it answers a list request, the directory also sends every registered server a `CLM_SEND_EMPTY_MESSAGE (1008)` carrying the client's public address; each server responds by sending `CLM_EMPTY_MESSAGE (1009)` to that address, opening its own NAT/firewall for the client's subsequent packets. The directory and its registered servers also ping each other about once a minute to keep their NAT mappings alive. +- A Server registers with `CLM_REGISTER_SERVER_EX (1017)` (older versions: `CLM_REGISTER_SERVER (1004)`) and receives `CLM_REGISTER_SERVER_RESP (1016)` carrying the result (registered, list full, version too old, requirements not fulfilled). If no response arrives, registration is retried every 500 ms, up to 5 times. +- Registration is refreshed every 15 minutes; the Directory drops a Server it has not heard from for 33 minutes. `CLM_UNREGISTER_SERVER (1005)` removes the entry immediately at shutdown or when changing Directory through the Server UI. +- A Client requests the list with `CLM_REQ_SERVER_LIST (1007)`. The Directory answers with both `CLM_RED_SERVER_LIST (1018)` (a reduced form that avoids UDP fragmentation) and `CLM_SERVER_LIST (1006)`. The Client then pings each listed Server with `CLM_PING_MS_WITHNUMCLIENTS (1002)` to display latency and occupancy. +- NAT hole punching: when it answers a list request, the Directory also sends every registered Server a `CLM_SEND_EMPTY_MESSAGE (1008)` carrying the Client's public address; each Server responds by sending `CLM_EMPTY_MESSAGE (1009)` to that address, opening its own NAT/firewall for the Client's subsequent packets. The Directory and its registered Servers also ping each other about once a minute to keep their NAT mappings alive. --- -## Audio Packet Structure +## Audio packet structure The OPUS codec is used to compress the audio over the network and the packets are documented [here](https://datatracker.ietf.org/doc/html/rfc6716). -Jamulus uses a custom OPUS encoder / decoder, giving some different frame sizes, but always uses a 48kHz sample rate. OPUS and OPUS64 codecs are the only supported options currently. +Jamulus uses a custom OPUS encoder / decoder, giving some different frame sizes, but always uses a 48 kHz sample rate. OPUS and OPUS64 codecs are the only supported options currently. The packet size will vary based on: @@ -290,6 +290,6 @@ The packet size will vary based on: - Buffer size (64/128/256 samples) - Use of frame sequence number (from v3.6.0 onwards) -These values are wrapped up into the `NETW_TRANSPORT_PROPS` messages, which the client sends to the server to tell it which values to use. +These values are wrapped up into the `NETW_TRANSPORT_PROPS` messages, which the Client sends to the Server to tell it which values to use. -Both client and server use a jitter buffer for received audio data to prevent audio drop-out. This is configurable. +Both Client and Server use a Jitter Buffer for received audio data to prevent audio drop-out. This is configurable. From 18b248fbeabc0d294b3c2d1daa85b9fc4fedd9c7 Mon Sep 17 00:00:00 2001 From: jrd Date: Sat, 18 Jul 2026 20:14:29 +0000 Subject: [PATCH 4/4] =?UTF-8?q?docs/JAMULUS=5FPROTOCOL.md:=20address=20rev?= =?UTF-8?q?iew=20=E2=80=94=202001=20out=20of=20message=20table,=20unregist?= =?UTF-8?q?er=20wording?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit SPECIAL_SPLIT_MESSAGE (2001) moved out of the connection-based table into its own paragraph explaining it is a transport container, not a message type, though each fragment frame is acknowledged/retransmitted (per CProtocol::ParseMessageBody). Connectionless range stated as 1000-1999. Unregister line takes pljones's suggested wording. Co-Authored-By: Claude Fable 5 --- docs/JAMULUS_PROTOCOL.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/docs/JAMULUS_PROTOCOL.md b/docs/JAMULUS_PROTOCOL.md index c9e20ff10d..96522b71c2 100644 --- a/docs/JAMULUS_PROTOCOL.md +++ b/docs/JAMULUS_PROTOCOL.md @@ -45,7 +45,7 @@ along with this program. If not, see [](https:// # The Jamulus audio protocol Jamulus uses connectionless UDP packets to communicate between the Client and Server, and additionally for registration with a Directory. The `src/protocol.cpp` file contains much of the details of the packets themselves, whereas this document is intended to form a higher-level view of the protocol interactions. -Messages with an ID below 1000 are connection-based: each one is acknowledged by an `ACKN (1)` message carrying the same sequence counter, and the sender retransmits it every `SEND_MESS_TIMEOUT_MS` ms until the acknowledgement arrives. Messages with an ID of 1000 or above (`CLM_*`) are connectionless: they work without an established audio connection and are never acknowledged. +Messages with an ID below 1000 are connection-based: each one is acknowledged by an `ACKN (1)` message carrying the same sequence counter, and the sender retransmits it every `SEND_MESS_TIMEOUT_MS` ms until the acknowledgement arrives. Messages with an ID from 1000 to 1999 (`CLM_*`) are connectionless: they work without an established audio connection and are never acknowledged. All of this information can be discovered from reading the code, but hopefully is quicker to digest when available in one location. There is a Wireshark dissector available too, [here](https://github.com/softins/jamulus-wireshark), if you would like to inspect the packet flow. @@ -114,10 +114,11 @@ Connection-based messages (acknowledged; `PROTMESSID_` prefix omitted). Full pay | 34 | `REQ_SPLIT_MESS_SUPPORT` | Request split-message support | | 35 | `SPLIT_MESS_SUPPORTED` | Split messages are supported | | 36 | `RAWAUDIO_SUPPORTED` | Raw (uncompressed) audio is supported | -| 2001 | `SPECIAL_SPLIT_MESSAGE` | Container for split messages | IDs 12, 14, 15, 17, 19, 22 and 28 are legacy messages no longer sent (28, `REQ_CHANNEL_LEVEL_LIST`, is still understood for compatibility with Servers 3.4.6–3.5.12). +`SPECIAL_SPLIT_MESSAGE (2001)` sits outside both ID ranges because it is not a message in its own right: it is the transport container for the fragments of an oversized connection-based message (see the split message container above), with the original message ID carried inside the container. Each fragment frame has its own sequence counter and is acknowledged and retransmitted like any connection-based message. + Connectionless messages (never acknowledged): | ID | Name | Purpose |