From a24721edc795e64e069f57fbfda2e921e76a4cfd Mon Sep 17 00:00:00 2001 From: Nils Brederlow <62596379+dingodoppelt@users.noreply.github.com> Date: Wed, 13 May 2026 14:53:58 +0200 Subject: [PATCH 1/3] add rpc methods and notifications - jamulusclient/setMuted - jamulusserver/broadcastChatMessage - jamulusserver/chatMessageReceived - jamulusserver/clientConnected - jamulusserver/clientDisconnected --- docs/JSON-RPC.md | 69 +++++++++++++++++++++++++++++++++++++++++++++++ src/client.h | 1 + src/clientrpc.cpp | 17 ++++++++++++ src/server.cpp | 8 +++--- src/server.h | 2 ++ src/serverrpc.cpp | 51 +++++++++++++++++++++++++++++++++++ 6 files changed, 144 insertions(+), 4 deletions(-) diff --git a/docs/JSON-RPC.md b/docs/JSON-RPC.md index cfe8dfbe3e..bff0bfc92e 100644 --- a/docs/JSON-RPC.md +++ b/docs/JSON-RPC.md @@ -291,6 +291,23 @@ Results: | result | string | Always "ok". | +### jamulusclient/setMuted + +Mutes or unmutes the client. + +Parameters: + +| Name | Type | Description | +| --- | --- | --- | +| params.muted | boolean | muted (true or false). | + +Results: + +| Name | Type | Description | +| --- | --- | --- | +| result | string | Always "ok". | + + ### jamulusclient/setName Sets your name. @@ -325,6 +342,23 @@ Results: | result | string | Always "ok". | +### jamulusserver/broadcastChatMessage + +Sends a message (as the server) to all connected clients. This can be used to broadcast messages from external sources (e.g. scripts or monitoring tools). + +Parameters: + +| Name | Type | Description | +| --- | --- | --- | +| params.chatMessage | string | The chat message text. | + +Results: + +| Name | Type | Description | +| --- | --- | --- | +| result | string | Always "ok". | + + ### jamulusserver/getClients Returns the list of connected clients along with details about them. @@ -621,3 +655,38 @@ Parameters: | params.servers[*].city | string | Server city. | +### jamulusserver/chatMessageReceived + +Emitted when a chat message is received from either a Jamulus or RPC client and to be broadcast to all connected clients. + +Parameters: + +| Name | Type | Description | +| --- | --- | --- | +| params.chatMessage | string | Chat message text. | + + +### jamulusserver/clientConnected + +Emitted when a client has connected to the server. + +Parameters: + +| Name | Type | Description | +| --- | --- | --- | +| params.id | number | The channel ID assigned to the client. | +| params.address | string | The client's address. | +| params.totalChannels | number | Number of total channels connected to the server. | + + +### jamulusserver/clientDisconnected + +Emitted when a client has disconnected from the server. + +Parameters: + +| Name | Type | Description | +| --- | --- | --- | +| params.id | number | The channel ID assigned to the client. | + + diff --git a/src/client.h b/src/client.h index 06847dc6d4..fb77930723 100644 --- a/src/client.h +++ b/src/client.h @@ -328,6 +328,7 @@ class CClient : public QObject // settings CChannelCoreInfo ChannelInfo; QString strClientName; + void OnRPCInMuteMyself ( bool bMute ) { OnControllerInMuteMyself ( bMute ); } public: void SetSettings ( CClientSettings* settings ); diff --git a/src/clientrpc.cpp b/src/clientrpc.cpp index 02324121e3..9ba7060a1d 100644 --- a/src/clientrpc.cpp +++ b/src/clientrpc.cpp @@ -497,6 +497,23 @@ CClientRpc::CClientRpc ( CClient* pClient, CClientSettings* pSettings, CRpcServe response["result"] = jsonDevices; Q_UNUSED ( params ); } ); + + /// @rpc_method jamulusclient/setMuted + /// @brief Mutes or unmutes the client. + /// @param {boolean} params.muted - muted (true or false). + /// @result {string} result - Always "ok". + pRpcServer->HandleMethod ( "jamulusclient/setMuted", [=] ( const QJsonObject& params, QJsonObject& response ) { + auto muted = params["muted"]; + if ( !muted.isBool() ) + { + response["error"] = CRpcServer::CreateJsonRpcError ( CRpcServer::iErrInvalidParams, "Invalid params: muted is not a boolean" ); + return; + } + + pClient->OnRPCInMuteMyself ( muted.toBool() ); + + response["result"] = "ok"; + } ); } QJsonValue CClientRpc::SerializeSkillLevel ( ESkillLevel eSkillLevel ) diff --git a/src/server.cpp b/src/server.cpp index 4325e7dce5..104244b8c8 100644 --- a/src/server.cpp +++ b/src/server.cpp @@ -473,6 +473,8 @@ void CServer::OnNewConnection ( int iChID, int iTotChans, CHostAddress RecHostAd // logging of new connected channel Logging.AddNewConnection ( RecHostAddr.InetAddr, iTotChans ); + + emit ClientConnected ( iChID, RecHostAddr.InetAddr, iTotChans ); } void CServer::OnCLReqServerFeatures ( CHostAddress RecHostAddr ) @@ -929,10 +931,7 @@ void CServer::DecodeReceiveData ( const int iChanCnt, const int iNumClients ) // and emit the client disconnected signal if ( eGetStat == GS_CHAN_NOW_DISCONNECTED ) { - if ( JamController.GetRecordingEnabled() ) - { - emit ClientDisconnected ( iCurChanID ); // TODO do this outside the mutex lock? - } + emit ClientDisconnected ( iCurChanID ); // TODO do this outside the mutex lock? FreeChannel ( iCurChanID ); // note that the channel is now not in use @@ -1368,6 +1367,7 @@ void CServer::SendChatTextToAllConChannels ( const QString& strChatText ) vecChannels[i].CreateChatTextMes ( strChatText ); } } + emit sentChatMessage ( strChatText ); } void CServer::SendChatTextToConChannel ( const int iCurChanID, const QString& strChatText ) diff --git a/src/server.h b/src/server.h index 5819012bda..a64fd867c9 100644 --- a/src/server.h +++ b/src/server.h @@ -331,6 +331,8 @@ class CServer : public QObject, public CServerSlots void Started(); void Stopped(); void ClientDisconnected ( const int iChID ); + void ClientConnected ( const int iChID, const QHostAddress RecHostAddr, const int iTotChans ); + void sentChatMessage ( const QString& strChatText ); void SvrRegStatusChanged(); void AudioFrame ( const int iChID, const QString stChName, diff --git a/src/serverrpc.cpp b/src/serverrpc.cpp index 315a3e262c..198b769ebb 100644 --- a/src/serverrpc.cpp +++ b/src/serverrpc.cpp @@ -56,6 +56,57 @@ CServerRpc::CServerRpc ( CServer* pServer, CRpcServer* pRpcServer, QObject* pare Q_UNUSED ( params ); } ); + /// @rpc_notification jamulusserver/clientConnected + /// @brief Emitted when a client has connected to the server. + /// @param {number} params.id - The channel ID assigned to the client. + /// @param {string} params.address - The client's address. + /// @param {number} params.totalChannels - Number of total channels connected to the server. + connect ( pServer, &CServer::ClientConnected, [=] ( const int iChanID, const QHostAddress RecHostAddr, const int iTotChans ) { + pRpcServer->BroadcastNotification ( "jamulusserver/clientConnected", + QJsonObject{ + { "id", iChanID }, + { "address", RecHostAddr.toString() }, + { "totalChannels", iTotChans }, + } ); + } ); + + /// @rpc_notification jamulusserver/clientDisconnected + /// @brief Emitted when a client has disconnected from the server. + /// @param {number} params.id - The channel ID assigned to the client. + connect ( pServer, &CServer::ClientDisconnected, [=] ( const int iChanID ) { + pRpcServer->BroadcastNotification ( "jamulusserver/clientDisconnected", + QJsonObject{ + { "id", iChanID }, + } ); + } ); + + /// @rpc_notification jamulusserver/chatMessageReceived + /// @brief Emitted when a chat message is received from either a Jamulus or RPC client and to be broadcast to all connected clients. + /// @param {string} params.chatMessage - Chat message text. + connect ( pServer, &CServer::sentChatMessage, [=] ( const QString& strChatText ) { + pRpcServer->BroadcastNotification ( "jamulusserver/chatMessageReceived", + QJsonObject{ + { "chatMessage", strChatText }, + } ); + } ); + + /// @rpc_method jamulusserver/broadcastChatMessage + /// @brief Sends a message (as the server) to all connected clients. This can be used to broadcast messages from external sources (e.g. scripts or + /// monitoring tools). + /// @param {string} params.chatMessage - The chat message text. + /// @result {string} result - Always "ok". + pRpcServer->HandleMethod ( "jamulusserver/broadcastChatMessage", [=] ( const QJsonObject& params, QJsonObject& response ) { + auto jsonChatMessage = params["chatMessage"]; + if ( !jsonChatMessage.isString() ) + { + response["error"] = CRpcServer::CreateJsonRpcError ( CRpcServer::iErrInvalidParams, "Invalid params: chatMessage is not a string" ); + return; + } + + pServer->SendChatTextToAllConChannels ( jsonChatMessage.toString() ); + response["result"] = "ok"; + } ); + /// @rpc_method jamulusserver/getRecorderStatus /// @brief Returns the recorder state. /// @param {object} params - No parameters (empty object). From 3732f3917311b79dc67e7c812cfb163560daabc4 Mon Sep 17 00:00:00 2001 From: Nils Brederlow <62596379+dingodoppelt@users.noreply.github.com> Date: Mon, 22 Jun 2026 14:35:29 +0200 Subject: [PATCH 2/3] Include channel ID of sending client in RPC chat message notification --- docs/JSON-RPC.md | 1 + src/server.cpp | 7 ++++--- src/server.h | 4 ++-- src/serverrpc.cpp | 7 +++++-- 4 files changed, 12 insertions(+), 7 deletions(-) diff --git a/docs/JSON-RPC.md b/docs/JSON-RPC.md index bff0bfc92e..0fc16dc352 100644 --- a/docs/JSON-RPC.md +++ b/docs/JSON-RPC.md @@ -663,6 +663,7 @@ Parameters: | Name | Type | Description | | --- | --- | --- | +| params.id | number | Channel ID of sending client or -1 for RPC sent messages. | | params.chatMessage | string | Chat message text. | diff --git a/src/server.cpp b/src/server.cpp index 104244b8c8..5b434acb2c 100644 --- a/src/server.cpp +++ b/src/server.cpp @@ -1354,10 +1354,10 @@ void CServer::CreateAndSendChatTextForAllConChannels ( const int iCurChanID, con ChanName.toHtmlEscaped() + " " + strChatText.toHtmlEscaped(); // Send chat text to all connected clients --------------------------------- - SendChatTextToAllConChannels ( strActualMessageText ); + SendChatTextToAllConChannels ( iCurChanID, strActualMessageText ); } -void CServer::SendChatTextToAllConChannels ( const QString& strChatText ) +void CServer::SendChatTextToAllConChannels ( const int iSendingChanID, const QString& strChatText ) { // Send chat text to all connected clients --------------------------------- for ( int i = 0; i < iMaxNumChannels; i++ ) @@ -1367,7 +1367,8 @@ void CServer::SendChatTextToAllConChannels ( const QString& strChatText ) vecChannels[i].CreateChatTextMes ( strChatText ); } } - emit sentChatMessage ( strChatText ); + // forward the message to the RPC server + emit sentChatMessage ( iSendingChanID, strChatText ); } void CServer::SendChatTextToConChannel ( const int iCurChanID, const QString& strChatText ) diff --git a/src/server.h b/src/server.h index a64fd867c9..c8d74dcfb4 100644 --- a/src/server.h +++ b/src/server.h @@ -191,7 +191,7 @@ class CServer : public QObject, public CServerSlots void SetEnableDelayPanning ( bool bDelayPanningOn ) { bDelayPan = bDelayPanningOn; } bool IsDelayPanningEnabled() { return bDelayPan; } - void SendChatTextToAllConChannels ( const QString& strChatText ); + void SendChatTextToAllConChannels ( const int iSendingChanID, const QString& strChatText ); void SendChatTextToConChannel ( const int iCurChanID, const QString& strChatText ); protected: @@ -332,7 +332,7 @@ class CServer : public QObject, public CServerSlots void Stopped(); void ClientDisconnected ( const int iChID ); void ClientConnected ( const int iChID, const QHostAddress RecHostAddr, const int iTotChans ); - void sentChatMessage ( const QString& strChatText ); + void sentChatMessage ( const int iSendingChanID, const QString& strChatText ); void SvrRegStatusChanged(); void AudioFrame ( const int iChID, const QString stChName, diff --git a/src/serverrpc.cpp b/src/serverrpc.cpp index 198b769ebb..95a5db6aa8 100644 --- a/src/serverrpc.cpp +++ b/src/serverrpc.cpp @@ -82,10 +82,12 @@ CServerRpc::CServerRpc ( CServer* pServer, CRpcServer* pRpcServer, QObject* pare /// @rpc_notification jamulusserver/chatMessageReceived /// @brief Emitted when a chat message is received from either a Jamulus or RPC client and to be broadcast to all connected clients. + /// @param {number} params.id - Channel ID of sending client or -1 for RPC sent messages. /// @param {string} params.chatMessage - Chat message text. - connect ( pServer, &CServer::sentChatMessage, [=] ( const QString& strChatText ) { + connect ( pServer, &CServer::sentChatMessage, [=] ( const int iSendingChanID, const QString& strChatText ) { pRpcServer->BroadcastNotification ( "jamulusserver/chatMessageReceived", QJsonObject{ + { "id", iSendingChanID }, { "chatMessage", strChatText }, } ); } ); @@ -103,7 +105,8 @@ CServerRpc::CServerRpc ( CServer* pServer, CRpcServer* pRpcServer, QObject* pare return; } - pServer->SendChatTextToAllConChannels ( jsonChatMessage.toString() ); + // set invalid channel ID to make clear this message was not sent by a Jamulus client + pServer->SendChatTextToAllConChannels ( -1, jsonChatMessage.toString() ); response["result"] = "ok"; } ); From ec919fc122f990ac98befe605910d4a1bcf23bd7 Mon Sep 17 00:00:00 2001 From: Nils Brederlow <62596379+dingodoppelt@users.noreply.github.com> Date: Mon, 22 Jun 2026 19:38:56 +0200 Subject: [PATCH 3/3] define INVALID_CLIENT_ID for use with RPC sent chat messages --- src/serverrpc.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/serverrpc.cpp b/src/serverrpc.cpp index 95a5db6aa8..2511a88549 100644 --- a/src/serverrpc.cpp +++ b/src/serverrpc.cpp @@ -47,6 +47,9 @@ #include "serverrpc.h" +/* Definitions ****************************************************************/ +#define INVALID_CLIENT_ID -1 + CServerRpc::CServerRpc ( CServer* pServer, CRpcServer* pRpcServer, QObject* parent ) : QObject ( parent ) { // API doc already part of CClientRpc @@ -106,7 +109,7 @@ CServerRpc::CServerRpc ( CServer* pServer, CRpcServer* pRpcServer, QObject* pare } // set invalid channel ID to make clear this message was not sent by a Jamulus client - pServer->SendChatTextToAllConChannels ( -1, jsonChatMessage.toString() ); + pServer->SendChatTextToAllConChannels ( INVALID_CLIENT_ID, jsonChatMessage.toString() ); response["result"] = "ok"; } );