From a45adedf7a00a13aab5a3cda638ea18e03da8f4c Mon Sep 17 00:00:00 2001 From: Nils Brederlow <62596379+dingodoppelt@users.noreply.github.com> Date: Fri, 17 Apr 2026 19:59:27 +0200 Subject: [PATCH 01/27] Introduce raw audio setting in UI. Opus encoding in client now depends on audio quality --- src/client.cpp | 27 +++++++++++++++------------ src/clientsettingsdlg.cpp | 1 + src/util.h | 3 ++- 3 files changed, 18 insertions(+), 13 deletions(-) diff --git a/src/client.cpp b/src/client.cpp index 417f08a404..874c5dfc2e 100644 --- a/src/client.cpp +++ b/src/client.cpp @@ -1389,23 +1389,26 @@ void CClient::ProcessAudioDataIntern ( CVector& vecsStereoSndCrd ) } } - for ( i = 0, j = 0; i < iSndCrdFrameSizeFactor; i++, j += iNumAudioChannels * iOPUSFrameSizeSamples ) + if ( eAudioQuality != AQ_RAW ) { - // OPUS encoding - if ( CurOpusEncoder != nullptr ) + for ( i = 0, j = 0; i < iSndCrdFrameSizeFactor; i++, j += iNumAudioChannels * iOPUSFrameSizeSamples ) { - if ( bMuteOutStream ) - { - iUnused = opus_custom_encode ( CurOpusEncoder, &vecZeros[j], iOPUSFrameSizeSamples, &vecCeltData[0], iCeltNumCodedBytes ); - } - else + // OPUS encoding + if ( CurOpusEncoder != nullptr ) { - iUnused = opus_custom_encode ( CurOpusEncoder, &vecsStereoSndCrd[j], iOPUSFrameSizeSamples, &vecCeltData[0], iCeltNumCodedBytes ); + if ( bMuteOutStream ) + { + iUnused = opus_custom_encode ( CurOpusEncoder, &vecZeros[j], iOPUSFrameSizeSamples, &vecCeltData[0], iCeltNumCodedBytes ); + } + else + { + iUnused = opus_custom_encode ( CurOpusEncoder, &vecsStereoSndCrd[j], iOPUSFrameSizeSamples, &vecCeltData[0], iCeltNumCodedBytes ); + } } - } - // send coded audio through the network - Channel.PrepAndSendPacket ( &Socket, vecCeltData, iCeltNumCodedBytes ); + // send coded audio through the network + Channel.PrepAndSendPacket ( &Socket, vecCeltData, iCeltNumCodedBytes ); + } } // Receive signal ---------------------------------------------------------- diff --git a/src/clientsettingsdlg.cpp b/src/clientsettingsdlg.cpp index d9f2e6ad11..61468ca2cf 100644 --- a/src/clientsettingsdlg.cpp +++ b/src/clientsettingsdlg.cpp @@ -494,6 +494,7 @@ CClientSettingsDlg::CClientSettingsDlg ( CClient* pNCliP, CClientSettings* pNSet cbxAudioQuality->addItem ( tr ( "Low" ) ); // AQ_LOW cbxAudioQuality->addItem ( tr ( "Normal" ) ); // AQ_NORMAL cbxAudioQuality->addItem ( tr ( "High" ) ); // AQ_HIGH + cbxAudioQuality->addItem ( tr ( "Raw" ) ); // AQ_RAW cbxAudioQuality->setCurrentIndex ( static_cast ( pClient->GetAudioQuality() ) ); // GUI design (skin) combo box diff --git a/src/util.h b/src/util.h index e83e1f764a..ac13d8c37d 100644 --- a/src/util.h +++ b/src/util.h @@ -505,7 +505,8 @@ enum EAudioQuality // used for settings and the comobo box index -> enum values must be fixed! AQ_LOW = 0, AQ_NORMAL = 1, - AQ_HIGH = 2 + AQ_HIGH = 2, + AQ_RAW = 3 }; // Get data status enum -------------------------------------------------------- From 73d983fea45fdfa3176f9b3f0cfe97754a3631fa Mon Sep 17 00:00:00 2001 From: Nils Brederlow <62596379+dingodoppelt@users.noreply.github.com> Date: Fri, 17 Apr 2026 20:02:33 +0200 Subject: [PATCH 02/27] addition to last commit --- src/client.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/client.cpp b/src/client.cpp index 874c5dfc2e..ff46c1aceb 100644 --- a/src/client.cpp +++ b/src/client.cpp @@ -1410,6 +1410,10 @@ void CClient::ProcessAudioDataIntern ( CVector& vecsStereoSndCrd ) Channel.PrepAndSendPacket ( &Socket, vecCeltData, iCeltNumCodedBytes ); } } + else + { + + } // Receive signal ---------------------------------------------------------- // in case of mute stream, store local data From 03f7ab3719d7dbce24b48e43b1124d7f52a6a722 Mon Sep 17 00:00:00 2001 From: Nils Brederlow <62596379+dingodoppelt@users.noreply.github.com> Date: Fri, 17 Apr 2026 20:14:17 +0200 Subject: [PATCH 03/27] client still sends raw audio to stock servers and causes garbled sound but works --- src/client.cpp | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/src/client.cpp b/src/client.cpp index ff46c1aceb..940851d905 100644 --- a/src/client.cpp +++ b/src/client.cpp @@ -1156,6 +1156,9 @@ void CClient::Init() case AQ_HIGH: iCeltNumCodedBytes = OPUS_NUM_BYTES_MONO_HIGH_QUALITY_DBLE_FRAMESIZE; break; + case AQ_RAW: + iCeltNumCodedBytes = iNumAudioChannels * iOPUSFrameSizeSamples * sizeof(int16_t); + break; } } else @@ -1175,6 +1178,9 @@ void CClient::Init() case AQ_HIGH: iCeltNumCodedBytes = OPUS_NUM_BYTES_STEREO_HIGH_QUALITY_DBLE_FRAMESIZE; break; + case AQ_RAW: + iCeltNumCodedBytes = iNumAudioChannels * iOPUSFrameSizeSamples * sizeof(int16_t); + break; } } } @@ -1199,6 +1205,9 @@ void CClient::Init() case AQ_HIGH: iCeltNumCodedBytes = OPUS_NUM_BYTES_MONO_HIGH_QUALITY; break; + case AQ_RAW: + iCeltNumCodedBytes = iNumAudioChannels * iOPUSFrameSizeSamples * sizeof(int16_t); + break; } } else @@ -1218,6 +1227,9 @@ void CClient::Init() case AQ_HIGH: iCeltNumCodedBytes = OPUS_NUM_BYTES_STEREO_HIGH_QUALITY; break; + case AQ_RAW: + iCeltNumCodedBytes = iNumAudioChannels * iOPUSFrameSizeSamples * sizeof(int16_t); + break; } } } @@ -1412,7 +1424,9 @@ void CClient::ProcessAudioDataIntern ( CVector& vecsStereoSndCrd ) } else { - + // Send raw samples instead of OPUS + memcpy ( &vecCeltData[0], &vecsStereoSndCrd[0], iCeltNumCodedBytes ); + Channel.PrepAndSendPacket ( &Socket, vecCeltData, iCeltNumCodedBytes ); } // Receive signal ---------------------------------------------------------- From 9a05dd1a28af31ccf56776bacfbc88e2c7f62426 Mon Sep 17 00:00:00 2001 From: Nils Brederlow <62596379+dingodoppelt@users.noreply.github.com> Date: Fri, 17 Apr 2026 20:33:49 +0200 Subject: [PATCH 04/27] make client opus decoding depend on audio quality (raw audio) --- src/client.cpp | 33 +++++++++++++++++++++++++-------- 1 file changed, 25 insertions(+), 8 deletions(-) diff --git a/src/client.cpp b/src/client.cpp index 940851d905..8441f15bc4 100644 --- a/src/client.cpp +++ b/src/client.cpp @@ -1444,24 +1444,41 @@ void CClient::ProcessAudioDataIntern ( CVector& vecsStereoSndCrd ) // get pointer to coded data and manage the flags if ( bReceiveDataOk ) { - pCurCodedData = &vecbyNetwData[0]; - + if ( eAudioQuality == AQ_RAW ) + { + memcpy ( &vecsStereoSndCrd[0], &vecbyNetwData[0], iCeltNumCodedBytes ); + pCurCodedData = nullptr; + } + else + { + pCurCodedData = &vecbyNetwData[0]; + } // on any valid received packet, we clear the initialization phase flag bIsInitializationPhase = false; } else { - // for lost packets use null pointer as coded input data - pCurCodedData = nullptr; - + if ( eAudioQuality == AQ_RAW ) + { + memset ( &vecsStereoSndCrd[0], 0, iCeltNumCodedBytes ); + pCurCodedData = nullptr; + } + else + { + // for lost packets use null pointer as coded input data + pCurCodedData = nullptr; + } // invalidate the buffer OK status flag bJitterBufferOK = false; } - // OPUS decoding - if ( CurOpusDecoder != nullptr ) + if ( eAudioQuality != AQ_RAW ) { - iUnused = opus_custom_decode ( CurOpusDecoder, pCurCodedData, iCeltNumCodedBytes, &vecsStereoSndCrd[j], iOPUSFrameSizeSamples ); + // OPUS decoding + if ( CurOpusDecoder != nullptr ) + { + iUnused = opus_custom_decode ( CurOpusDecoder, pCurCodedData, iCeltNumCodedBytes, &vecsStereoSndCrd[j], iOPUSFrameSizeSamples ); + } } } From 0f22ee96aef61647b4f0d50121f4b91f94534305 Mon Sep 17 00:00:00 2001 From: Nils Brederlow <62596379+dingodoppelt@users.noreply.github.com> Date: Fri, 17 Apr 2026 22:29:02 +0200 Subject: [PATCH 05/27] no crashes but bad noise on raw audio setting --- src/server.cpp | 87 +++++++++++++++++++++++++++++++++++--------------- 1 file changed, 62 insertions(+), 25 deletions(-) diff --git a/src/server.cpp b/src/server.cpp index a477771fde..fc33d419a9 100644 --- a/src/server.cpp +++ b/src/server.cpp @@ -23,6 +23,9 @@ \******************************************************************************/ #include "server.h" +#include "global.h" +#include "util.h" +#include // CServer implementation ****************************************************** CServer::CServer ( const int iNewMaxNumChan, @@ -874,27 +877,46 @@ void CServer::DecodeReceiveData ( const int iChanCnt, const int iNumClients ) return; } + const int iOffset = iB * SYSTEM_FRAME_SIZE_SAMPLES * vecNumAudioChannels[iChanCnt]; + const bool bIsRawAudio = ( iCeltNumCodedBytes == iClientFrameSizeSamples * vecNumAudioChannels[iChanCnt] * sizeof(int16_t) ); + // get pointer to coded data if ( eGetStat == GS_BUFFER_OK ) { - pCurCodedData = &vecvecbyCodedData[iChanCnt][0]; + if ( bIsRawAudio ) + { + memcpy ( &vecvecsData[iChanCnt][iOffset], &vecvecbyCodedData[iChanCnt], iCeltNumCodedBytes ); + } + else + { + pCurCodedData = &vecvecbyCodedData[iChanCnt][0]; + } } else { - // for lost packets use null pointer as coded input data - pCurCodedData = nullptr; + if ( bIsRawAudio ) + { + memset ( &vecvecsData[iChanCnt][iOffset], 0, iCeltNumCodedBytes ); + } + else + { + // for lost packets use null pointer as coded input data + pCurCodedData = nullptr; + } } - // OPUS decode received data stream - if ( CurOpusDecoder != nullptr ) + if ( !bIsRawAudio ) { - const int iOffset = iB * SYSTEM_FRAME_SIZE_SAMPLES * vecNumAudioChannels[iChanCnt]; + // OPUS decode received data stream + if ( CurOpusDecoder != nullptr ) + { - iUnused = opus_custom_decode ( CurOpusDecoder, - pCurCodedData, - iCeltNumCodedBytes, - &vecvecsData[iChanCnt][iOffset], - iClientFrameSizeSamples ); + iUnused = opus_custom_decode ( CurOpusDecoder, + pCurCodedData, + iCeltNumCodedBytes, + &vecvecsData[iChanCnt][iOffset], + iClientFrameSizeSamples ); + } } } @@ -1154,30 +1176,45 @@ void CServer::MixEncodeTransmitData ( const int iChanCnt, const int iNumClients DoubleFrameSizeConvBufOut[iCurChanID].GetAll ( vecsSendData, DOUBLE_SYSTEM_FRAME_SIZE_SAMPLES * vecNumAudioChannels[iChanCnt] ); } - // OPUS encoding - if ( pCurOpusEncoder != nullptr ) + if ( iCeltNumCodedBytes != iClientFrameSizeSamples * vecNumAudioChannels[iChanCnt] * sizeof(int16_t)) { - //### TODO: BEGIN ###// - // find a better place than this: the setting does not change all the time so for speed - // optimization it would be better to set it only if the network frame size is changed - opus_custom_encoder_ctl ( pCurOpusEncoder, - OPUS_SET_BITRATE ( CalcBitRateBitsPerSecFromCodedBytes ( iCeltNumCodedBytes, iClientFrameSizeSamples ) ) ); - //### TODO: END ###// + // OPUS encoding + if ( pCurOpusEncoder != nullptr ) + { + //### TODO: BEGIN ###// + // find a better place than this: the setting does not change all the time so for speed + // optimization it would be better to set it only if the network frame size is changed + opus_custom_encoder_ctl ( pCurOpusEncoder, + OPUS_SET_BITRATE ( CalcBitRateBitsPerSecFromCodedBytes ( iCeltNumCodedBytes, iClientFrameSizeSamples ) ) ); + //### TODO: END ###// + + for ( int iB = 0; iB < vecNumFrameSizeConvBlocks[iChanCnt]; iB++ ) + { + const int iOffset = iB * SYSTEM_FRAME_SIZE_SAMPLES * vecNumAudioChannels[iChanCnt]; + + iUnused = opus_custom_encode ( pCurOpusEncoder, + &vecsSendData[iOffset], + iClientFrameSizeSamples, + &vecvecbyCodedData[iChanCnt][0], + iCeltNumCodedBytes ); + // send separate mix to current clients + vecChannels[iCurChanID].PrepAndSendPacket ( &Socket, vecvecbyCodedData[iChanCnt], iCeltNumCodedBytes ); + } + } + } + else + { for ( int iB = 0; iB < vecNumFrameSizeConvBlocks[iChanCnt]; iB++ ) { const int iOffset = iB * SYSTEM_FRAME_SIZE_SAMPLES * vecNumAudioChannels[iChanCnt]; - iUnused = opus_custom_encode ( pCurOpusEncoder, - &vecsSendData[iOffset], - iClientFrameSizeSamples, - &vecvecbyCodedData[iChanCnt][0], - iCeltNumCodedBytes ); + memcpy ( &vecvecbyCodedData[iChanCnt][0], &vecsSendData[iOffset], iCeltNumCodedBytes ); - // send separate mix to current clients vecChannels[iCurChanID].PrepAndSendPacket ( &Socket, vecvecbyCodedData[iChanCnt], iCeltNumCodedBytes ); } } + } Q_UNUSED ( iUnused ) From 7f47dd8a4d47d7635fd57718eca3b036bc26f59d Mon Sep 17 00:00:00 2001 From: Nils Brederlow <62596379+dingodoppelt@users.noreply.github.com> Date: Fri, 17 Apr 2026 23:08:26 +0200 Subject: [PATCH 06/27] first working version (needs testing) --- src/server.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/server.cpp b/src/server.cpp index fc33d419a9..63c87ad26b 100644 --- a/src/server.cpp +++ b/src/server.cpp @@ -885,7 +885,7 @@ void CServer::DecodeReceiveData ( const int iChanCnt, const int iNumClients ) { if ( bIsRawAudio ) { - memcpy ( &vecvecsData[iChanCnt][iOffset], &vecvecbyCodedData[iChanCnt], iCeltNumCodedBytes ); + memcpy ( &vecvecsData[iChanCnt][iOffset], &vecvecbyCodedData[iChanCnt][0], iCeltNumCodedBytes ); } else { From 7734d7531e42357426ab4aa3e36170e2de55c388 Mon Sep 17 00:00:00 2001 From: Nils Brederlow <62596379+dingodoppelt@users.noreply.github.com> Date: Sat, 18 Apr 2026 00:04:17 +0200 Subject: [PATCH 07/27] fix style --- src/client.cpp | 8 ++++---- src/clientsettingsdlg.cpp | 2 +- src/server.cpp | 25 ++++++++++++------------- 3 files changed, 17 insertions(+), 18 deletions(-) diff --git a/src/client.cpp b/src/client.cpp index 8441f15bc4..0d338d28bd 100644 --- a/src/client.cpp +++ b/src/client.cpp @@ -1157,7 +1157,7 @@ void CClient::Init() iCeltNumCodedBytes = OPUS_NUM_BYTES_MONO_HIGH_QUALITY_DBLE_FRAMESIZE; break; case AQ_RAW: - iCeltNumCodedBytes = iNumAudioChannels * iOPUSFrameSizeSamples * sizeof(int16_t); + iCeltNumCodedBytes = iNumAudioChannels * iOPUSFrameSizeSamples * sizeof ( int16_t ); break; } } @@ -1179,7 +1179,7 @@ void CClient::Init() iCeltNumCodedBytes = OPUS_NUM_BYTES_STEREO_HIGH_QUALITY_DBLE_FRAMESIZE; break; case AQ_RAW: - iCeltNumCodedBytes = iNumAudioChannels * iOPUSFrameSizeSamples * sizeof(int16_t); + iCeltNumCodedBytes = iNumAudioChannels * iOPUSFrameSizeSamples * sizeof ( int16_t ); break; } } @@ -1206,7 +1206,7 @@ void CClient::Init() iCeltNumCodedBytes = OPUS_NUM_BYTES_MONO_HIGH_QUALITY; break; case AQ_RAW: - iCeltNumCodedBytes = iNumAudioChannels * iOPUSFrameSizeSamples * sizeof(int16_t); + iCeltNumCodedBytes = iNumAudioChannels * iOPUSFrameSizeSamples * sizeof ( int16_t ); break; } } @@ -1228,7 +1228,7 @@ void CClient::Init() iCeltNumCodedBytes = OPUS_NUM_BYTES_STEREO_HIGH_QUALITY; break; case AQ_RAW: - iCeltNumCodedBytes = iNumAudioChannels * iOPUSFrameSizeSamples * sizeof(int16_t); + iCeltNumCodedBytes = iNumAudioChannels * iOPUSFrameSizeSamples * sizeof ( int16_t ); break; } } diff --git a/src/clientsettingsdlg.cpp b/src/clientsettingsdlg.cpp index 61468ca2cf..c82c236996 100644 --- a/src/clientsettingsdlg.cpp +++ b/src/clientsettingsdlg.cpp @@ -494,7 +494,7 @@ CClientSettingsDlg::CClientSettingsDlg ( CClient* pNCliP, CClientSettings* pNSet cbxAudioQuality->addItem ( tr ( "Low" ) ); // AQ_LOW cbxAudioQuality->addItem ( tr ( "Normal" ) ); // AQ_NORMAL cbxAudioQuality->addItem ( tr ( "High" ) ); // AQ_HIGH - cbxAudioQuality->addItem ( tr ( "Raw" ) ); // AQ_RAW + cbxAudioQuality->addItem ( tr ( "Raw" ) ); // AQ_RAW cbxAudioQuality->setCurrentIndex ( static_cast ( pClient->GetAudioQuality() ) ); // GUI design (skin) combo box diff --git a/src/server.cpp b/src/server.cpp index 63c87ad26b..fe18436949 100644 --- a/src/server.cpp +++ b/src/server.cpp @@ -877,8 +877,8 @@ void CServer::DecodeReceiveData ( const int iChanCnt, const int iNumClients ) return; } - const int iOffset = iB * SYSTEM_FRAME_SIZE_SAMPLES * vecNumAudioChannels[iChanCnt]; - const bool bIsRawAudio = ( iCeltNumCodedBytes == iClientFrameSizeSamples * vecNumAudioChannels[iChanCnt] * sizeof(int16_t) ); + const int iOffset = iB * SYSTEM_FRAME_SIZE_SAMPLES * vecNumAudioChannels[iChanCnt]; + const bool bIsRawAudio = ( iCeltNumCodedBytes == iClientFrameSizeSamples * vecNumAudioChannels[iChanCnt] * sizeof ( int16_t ) ); // get pointer to coded data if ( eGetStat == GS_BUFFER_OK ) @@ -912,10 +912,10 @@ void CServer::DecodeReceiveData ( const int iChanCnt, const int iNumClients ) { iUnused = opus_custom_decode ( CurOpusDecoder, - pCurCodedData, - iCeltNumCodedBytes, - &vecvecsData[iChanCnt][iOffset], - iClientFrameSizeSamples ); + pCurCodedData, + iCeltNumCodedBytes, + &vecvecsData[iChanCnt][iOffset], + iClientFrameSizeSamples ); } } } @@ -1176,7 +1176,7 @@ void CServer::MixEncodeTransmitData ( const int iChanCnt, const int iNumClients DoubleFrameSizeConvBufOut[iCurChanID].GetAll ( vecsSendData, DOUBLE_SYSTEM_FRAME_SIZE_SAMPLES * vecNumAudioChannels[iChanCnt] ); } - if ( iCeltNumCodedBytes != iClientFrameSizeSamples * vecNumAudioChannels[iChanCnt] * sizeof(int16_t)) + if ( iCeltNumCodedBytes != iClientFrameSizeSamples * vecNumAudioChannels[iChanCnt] * sizeof( int16_t ) ) { // OPUS encoding if ( pCurOpusEncoder != nullptr ) @@ -1185,7 +1185,7 @@ void CServer::MixEncodeTransmitData ( const int iChanCnt, const int iNumClients // find a better place than this: the setting does not change all the time so for speed // optimization it would be better to set it only if the network frame size is changed opus_custom_encoder_ctl ( pCurOpusEncoder, - OPUS_SET_BITRATE ( CalcBitRateBitsPerSecFromCodedBytes ( iCeltNumCodedBytes, iClientFrameSizeSamples ) ) ); + OPUS_SET_BITRATE ( CalcBitRateBitsPerSecFromCodedBytes ( iCeltNumCodedBytes, iClientFrameSizeSamples ) ) ); //### TODO: END ###// for ( int iB = 0; iB < vecNumFrameSizeConvBlocks[iChanCnt]; iB++ ) @@ -1193,10 +1193,10 @@ void CServer::MixEncodeTransmitData ( const int iChanCnt, const int iNumClients const int iOffset = iB * SYSTEM_FRAME_SIZE_SAMPLES * vecNumAudioChannels[iChanCnt]; iUnused = opus_custom_encode ( pCurOpusEncoder, - &vecsSendData[iOffset], - iClientFrameSizeSamples, - &vecvecbyCodedData[iChanCnt][0], - iCeltNumCodedBytes ); + &vecsSendData[iOffset], + iClientFrameSizeSamples, + &vecvecbyCodedData[iChanCnt][0], + iCeltNumCodedBytes ); // send separate mix to current clients vecChannels[iCurChanID].PrepAndSendPacket ( &Socket, vecvecbyCodedData[iChanCnt], iCeltNumCodedBytes ); @@ -1214,7 +1214,6 @@ void CServer::MixEncodeTransmitData ( const int iChanCnt, const int iNumClients vecChannels[iCurChanID].PrepAndSendPacket ( &Socket, vecvecbyCodedData[iChanCnt], iCeltNumCodedBytes ); } } - } Q_UNUSED ( iUnused ) From fa61b5513fa4f2f6ecd73f023ea1ac1083ff485a Mon Sep 17 00:00:00 2001 From: Nils Brederlow <62596379+dingodoppelt@users.noreply.github.com> Date: Sat, 18 Apr 2026 00:06:12 +0200 Subject: [PATCH 08/27] fix style --- src/server.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/server.cpp b/src/server.cpp index fe18436949..e1cb67e548 100644 --- a/src/server.cpp +++ b/src/server.cpp @@ -1176,7 +1176,7 @@ void CServer::MixEncodeTransmitData ( const int iChanCnt, const int iNumClients DoubleFrameSizeConvBufOut[iCurChanID].GetAll ( vecsSendData, DOUBLE_SYSTEM_FRAME_SIZE_SAMPLES * vecNumAudioChannels[iChanCnt] ); } - if ( iCeltNumCodedBytes != iClientFrameSizeSamples * vecNumAudioChannels[iChanCnt] * sizeof( int16_t ) ) + if ( iCeltNumCodedBytes != iClientFrameSizeSamples * vecNumAudioChannels[iChanCnt] * sizeof ( int16_t ) ) { // OPUS encoding if ( pCurOpusEncoder != nullptr ) From 5a467e02eef5227ddd11613655cf89b6bc3ec503 Mon Sep 17 00:00:00 2001 From: Nils Brederlow <62596379+dingodoppelt@users.noreply.github.com> Date: Sat, 18 Apr 2026 00:34:39 +0200 Subject: [PATCH 09/27] fix mute myself --- src/client.cpp | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/src/client.cpp b/src/client.cpp index 0d338d28bd..164e2ca13e 100644 --- a/src/client.cpp +++ b/src/client.cpp @@ -1424,8 +1424,15 @@ void CClient::ProcessAudioDataIntern ( CVector& vecsStereoSndCrd ) } else { - // Send raw samples instead of OPUS - memcpy ( &vecCeltData[0], &vecsStereoSndCrd[0], iCeltNumCodedBytes ); + if ( !bMuteOutStream ) + { + // Send raw samples instead of OPUS + memcpy ( &vecCeltData[0], &vecsStereoSndCrd[0], iCeltNumCodedBytes ); + } + else + { + memset ( &vecCeltData[0], 0, iCeltNumCodedBytes ); + } Channel.PrepAndSendPacket ( &Socket, vecCeltData, iCeltNumCodedBytes ); } From 8f53817797295a7b8fb47750bf52dc539fc5ac4a Mon Sep 17 00:00:00 2001 From: Nils Brederlow <62596379+dingodoppelt@users.noreply.github.com> Date: Sun, 19 Apr 2026 11:16:12 +0200 Subject: [PATCH 10/27] remove redundant include --- src/server.cpp | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/server.cpp b/src/server.cpp index e1cb67e548..ff85cd472b 100644 --- a/src/server.cpp +++ b/src/server.cpp @@ -23,9 +23,6 @@ \******************************************************************************/ #include "server.h" -#include "global.h" -#include "util.h" -#include // CServer implementation ****************************************************** CServer::CServer ( const int iNewMaxNumChan, From c77029dcdb7961673043ae7879cefddbae2a0db6 Mon Sep 17 00:00:00 2001 From: Nils Brederlow <62596379+dingodoppelt@users.noreply.github.com> Date: Mon, 20 Apr 2026 15:47:07 +0200 Subject: [PATCH 11/27] Change audio quality option from 'Raw' to 'Max' --- src/clientsettingsdlg.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/clientsettingsdlg.cpp b/src/clientsettingsdlg.cpp index c82c236996..f1c6af5dbe 100644 --- a/src/clientsettingsdlg.cpp +++ b/src/clientsettingsdlg.cpp @@ -494,7 +494,7 @@ CClientSettingsDlg::CClientSettingsDlg ( CClient* pNCliP, CClientSettings* pNSet cbxAudioQuality->addItem ( tr ( "Low" ) ); // AQ_LOW cbxAudioQuality->addItem ( tr ( "Normal" ) ); // AQ_NORMAL cbxAudioQuality->addItem ( tr ( "High" ) ); // AQ_HIGH - cbxAudioQuality->addItem ( tr ( "Raw" ) ); // AQ_RAW + cbxAudioQuality->addItem ( tr ( "Max" ) ); // AQ_RAW cbxAudioQuality->setCurrentIndex ( static_cast ( pClient->GetAudioQuality() ) ); // GUI design (skin) combo box From d36448a5b8bbd708bd6413c360bf4b2a444d05e4 Mon Sep 17 00:00:00 2001 From: Nils Brederlow <62596379+dingodoppelt@users.noreply.github.com> Date: Mon, 20 Apr 2026 17:51:05 +0200 Subject: [PATCH 12/27] Only send raw audio if the server supports it (checked by version number) --- src/channel.cpp | 2 ++ src/channel.h | 3 +++ src/client.cpp | 44 ++++++++++++++++++++++++++++++++++++-------- 3 files changed, 41 insertions(+), 8 deletions(-) diff --git a/src/channel.cpp b/src/channel.cpp index 9bd409889a..ccba180486 100644 --- a/src/channel.cpp +++ b/src/channel.cpp @@ -135,6 +135,7 @@ void CChannel::SetEnable ( const bool bNEnStat ) // since the SetEnable(true) is set AFTER the Init() in the client -> we // simply set it regardless of the state which does not hurt. bUseSequenceNumber = false; + bRawAudioIsSupported = false; // if channel is not enabled, reset time out count and protocol if ( !bNEnStat ) @@ -148,6 +149,7 @@ void CChannel::OnVersionAndOSReceived ( COSUtil::EOpSystemType eOSType, QString { // check if audio packet counter is supported by the server (minimum version is 3.6.0) #if QT_VERSION >= QT_VERSION_CHECK( 5, 6, 0 ) + bRawAudioIsSupported = ( QVersionNumber::compare ( QVersionNumber::fromString ( strVersion ), QVersionNumber ( 4, 0, 0 ) ) >= 0 ) ? true : false; if ( QVersionNumber::compare ( QVersionNumber::fromString ( strVersion ), QVersionNumber ( 3, 6, 0 ) ) >= 0 ) { // activate sequence counter and update the audio stream properties (which diff --git a/src/channel.h b/src/channel.h index 1567268307..fc9589c624 100644 --- a/src/channel.h +++ b/src/channel.h @@ -169,6 +169,9 @@ class CChannel : public QObject double UpdateAndGetLevelForMeterdB ( const CVector& vecsAudio, const int iInSize, const bool bIsStereoIn ); + bool bRawAudioIsSupported = false; + + protected: bool ProtocolIsEnabled(); diff --git a/src/client.cpp b/src/client.cpp index 164e2ca13e..543b99aea1 100644 --- a/src/client.cpp +++ b/src/client.cpp @@ -1157,7 +1157,14 @@ void CClient::Init() iCeltNumCodedBytes = OPUS_NUM_BYTES_MONO_HIGH_QUALITY_DBLE_FRAMESIZE; break; case AQ_RAW: - iCeltNumCodedBytes = iNumAudioChannels * iOPUSFrameSizeSamples * sizeof ( int16_t ); + if ( Channel.bRawAudioIsSupported ) + { + iCeltNumCodedBytes = iNumAudioChannels * iOPUSFrameSizeSamples * sizeof ( int16_t ); + } + else + { + iCeltNumCodedBytes = OPUS_NUM_BYTES_MONO_HIGH_QUALITY_DBLE_FRAMESIZE; + } break; } } @@ -1179,7 +1186,14 @@ void CClient::Init() iCeltNumCodedBytes = OPUS_NUM_BYTES_STEREO_HIGH_QUALITY_DBLE_FRAMESIZE; break; case AQ_RAW: - iCeltNumCodedBytes = iNumAudioChannels * iOPUSFrameSizeSamples * sizeof ( int16_t ); + if ( Channel.bRawAudioIsSupported ) + { + iCeltNumCodedBytes = iNumAudioChannels * iOPUSFrameSizeSamples * sizeof ( int16_t ); + } + else + { + iCeltNumCodedBytes = OPUS_NUM_BYTES_STEREO_HIGH_QUALITY_DBLE_FRAMESIZE; + } break; } } @@ -1206,7 +1220,14 @@ void CClient::Init() iCeltNumCodedBytes = OPUS_NUM_BYTES_MONO_HIGH_QUALITY; break; case AQ_RAW: - iCeltNumCodedBytes = iNumAudioChannels * iOPUSFrameSizeSamples * sizeof ( int16_t ); + if ( Channel.bRawAudioIsSupported ) + { + iCeltNumCodedBytes = iNumAudioChannels * iOPUSFrameSizeSamples * sizeof ( int16_t ); + } + else + { + iCeltNumCodedBytes = OPUS_NUM_BYTES_MONO_HIGH_QUALITY; + } break; } } @@ -1228,7 +1249,14 @@ void CClient::Init() iCeltNumCodedBytes = OPUS_NUM_BYTES_STEREO_HIGH_QUALITY; break; case AQ_RAW: - iCeltNumCodedBytes = iNumAudioChannels * iOPUSFrameSizeSamples * sizeof ( int16_t ); + if ( Channel.bRawAudioIsSupported ) + { + iCeltNumCodedBytes = iNumAudioChannels * iOPUSFrameSizeSamples * sizeof ( int16_t ); + } + else + { + iCeltNumCodedBytes = OPUS_NUM_BYTES_STEREO_HIGH_QUALITY; + } break; } } @@ -1401,7 +1429,7 @@ void CClient::ProcessAudioDataIntern ( CVector& vecsStereoSndCrd ) } } - if ( eAudioQuality != AQ_RAW ) + if ( eAudioQuality != AQ_RAW || !Channel.bRawAudioIsSupported ) { for ( i = 0, j = 0; i < iSndCrdFrameSizeFactor; i++, j += iNumAudioChannels * iOPUSFrameSizeSamples ) { @@ -1451,7 +1479,7 @@ void CClient::ProcessAudioDataIntern ( CVector& vecsStereoSndCrd ) // get pointer to coded data and manage the flags if ( bReceiveDataOk ) { - if ( eAudioQuality == AQ_RAW ) + if ( eAudioQuality == AQ_RAW && Channel.bRawAudioIsSupported ) { memcpy ( &vecsStereoSndCrd[0], &vecbyNetwData[0], iCeltNumCodedBytes ); pCurCodedData = nullptr; @@ -1465,7 +1493,7 @@ void CClient::ProcessAudioDataIntern ( CVector& vecsStereoSndCrd ) } else { - if ( eAudioQuality == AQ_RAW ) + if ( eAudioQuality == AQ_RAW && Channel.bRawAudioIsSupported ) { memset ( &vecsStereoSndCrd[0], 0, iCeltNumCodedBytes ); pCurCodedData = nullptr; @@ -1479,7 +1507,7 @@ void CClient::ProcessAudioDataIntern ( CVector& vecsStereoSndCrd ) bJitterBufferOK = false; } - if ( eAudioQuality != AQ_RAW ) + if ( eAudioQuality != AQ_RAW || !Channel.bRawAudioIsSupported ) { // OPUS decoding if ( CurOpusDecoder != nullptr ) From 8079eed3ef032bb86d98769e010e340f98a24348 Mon Sep 17 00:00:00 2001 From: Nils Brederlow <62596379+dingodoppelt@users.noreply.github.com> Date: Mon, 20 Apr 2026 18:12:46 +0200 Subject: [PATCH 13/27] fix style --- src/channel.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/channel.cpp b/src/channel.cpp index ccba180486..5d6a979c01 100644 --- a/src/channel.cpp +++ b/src/channel.cpp @@ -134,7 +134,7 @@ void CChannel::SetEnable ( const bool bNEnStat ) // function. NOTE that it is important to reset this parameter on SetEnable(false) // since the SetEnable(true) is set AFTER the Init() in the client -> we // simply set it regardless of the state which does not hurt. - bUseSequenceNumber = false; + bUseSequenceNumber = false; bRawAudioIsSupported = false; // if channel is not enabled, reset time out count and protocol From 5c73b6a9c7d418b36a595b64e03663be3eafd346 Mon Sep 17 00:00:00 2001 From: Nils Brederlow <62596379+dingodoppelt@users.noreply.github.com> Date: Mon, 20 Apr 2026 18:26:32 +0200 Subject: [PATCH 14/27] fix style --- src/channel.h | 1 - 1 file changed, 1 deletion(-) diff --git a/src/channel.h b/src/channel.h index fc9589c624..29114b28bd 100644 --- a/src/channel.h +++ b/src/channel.h @@ -171,7 +171,6 @@ class CChannel : public QObject bool bRawAudioIsSupported = false; - protected: bool ProtocolIsEnabled(); From a59784324d46a0dbe8d3456a90d41cee3c91bd1b Mon Sep 17 00:00:00 2001 From: Nils Brederlow <62596379+dingodoppelt@users.noreply.github.com> Date: Mon, 20 Apr 2026 18:40:19 +0200 Subject: [PATCH 15/27] change version --- Jamulus.pro | 2 +- src/channel.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Jamulus.pro b/Jamulus.pro index 28f3bacd74..e20ecd3da6 100644 --- a/Jamulus.pro +++ b/Jamulus.pro @@ -1,4 +1,4 @@ -VERSION = 3.11.0dev +VERSION = 3.11.1rawaudio # Using lrelease and embed_translations only works for Qt 5.12 or later. # See https://github.com/jamulussoftware/jamulus/pull/3288 for these changes. diff --git a/src/channel.cpp b/src/channel.cpp index 5d6a979c01..1d08ad07d2 100644 --- a/src/channel.cpp +++ b/src/channel.cpp @@ -149,7 +149,7 @@ void CChannel::OnVersionAndOSReceived ( COSUtil::EOpSystemType eOSType, QString { // check if audio packet counter is supported by the server (minimum version is 3.6.0) #if QT_VERSION >= QT_VERSION_CHECK( 5, 6, 0 ) - bRawAudioIsSupported = ( QVersionNumber::compare ( QVersionNumber::fromString ( strVersion ), QVersionNumber ( 4, 0, 0 ) ) >= 0 ) ? true : false; + bRawAudioIsSupported = ( QVersionNumber::compare ( QVersionNumber::fromString ( strVersion ), QVersionNumber ( 3, 11, 1 ) ) >= 0 ) ? true : false; if ( QVersionNumber::compare ( QVersionNumber::fromString ( strVersion ), QVersionNumber ( 3, 6, 0 ) ) >= 0 ) { // activate sequence counter and update the audio stream properties (which From 7fa20b7014d7ed2a491cfe8e5c23fa1e729aaba0 Mon Sep 17 00:00:00 2001 From: Nils Brederlow <62596379+dingodoppelt@users.noreply.github.com> Date: Mon, 20 Apr 2026 18:49:27 +0200 Subject: [PATCH 16/27] Update changelog --- ChangeLog | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/ChangeLog b/ChangeLog index 3013fac972..e92a5afe00 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,7 @@ +### 3.11.1rawaudio + +- Add uncompressed audio transmission, improves latency by 2ms + ### 3.11.0dev <- NOTE: the release version number will be 3.12.0 ### - Extended SRV record support (#3556). From b602efac3f4de14abd826534ddd2b198836266c9 Mon Sep 17 00:00:00 2001 From: Nils Brederlow <62596379+dingodoppelt@users.noreply.github.com> Date: Mon, 20 Apr 2026 19:04:10 +0200 Subject: [PATCH 17/27] fix changelog --- ChangeLog | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ChangeLog b/ChangeLog index e92a5afe00..718d4daf94 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,4 +1,4 @@ -### 3.11.1rawaudio +### 3.11.1rawaudio ### - Add uncompressed audio transmission, improves latency by 2ms From 42af9ab7d3cd011847a14da2f8ae803309bca649 Mon Sep 17 00:00:00 2001 From: Nils Brederlow <62596379+dingodoppelt@users.noreply.github.com> Date: Mon, 20 Apr 2026 20:27:54 +0200 Subject: [PATCH 18/27] Fix noise issue with rawaudio servers when Max audio quality is selected --- src/channel.cpp | 2 -- src/channel.h | 2 -- src/client.cpp | 27 +++++++++++++++++++-------- src/client.h | 2 ++ 4 files changed, 21 insertions(+), 12 deletions(-) diff --git a/src/channel.cpp b/src/channel.cpp index 5d6a979c01..8641d5a50b 100644 --- a/src/channel.cpp +++ b/src/channel.cpp @@ -135,7 +135,6 @@ void CChannel::SetEnable ( const bool bNEnStat ) // since the SetEnable(true) is set AFTER the Init() in the client -> we // simply set it regardless of the state which does not hurt. bUseSequenceNumber = false; - bRawAudioIsSupported = false; // if channel is not enabled, reset time out count and protocol if ( !bNEnStat ) @@ -149,7 +148,6 @@ void CChannel::OnVersionAndOSReceived ( COSUtil::EOpSystemType eOSType, QString { // check if audio packet counter is supported by the server (minimum version is 3.6.0) #if QT_VERSION >= QT_VERSION_CHECK( 5, 6, 0 ) - bRawAudioIsSupported = ( QVersionNumber::compare ( QVersionNumber::fromString ( strVersion ), QVersionNumber ( 4, 0, 0 ) ) >= 0 ) ? true : false; if ( QVersionNumber::compare ( QVersionNumber::fromString ( strVersion ), QVersionNumber ( 3, 6, 0 ) ) >= 0 ) { // activate sequence counter and update the audio stream properties (which diff --git a/src/channel.h b/src/channel.h index 29114b28bd..1567268307 100644 --- a/src/channel.h +++ b/src/channel.h @@ -169,8 +169,6 @@ class CChannel : public QObject double UpdateAndGetLevelForMeterdB ( const CVector& vecsAudio, const int iInSize, const bool bIsStereoIn ); - bool bRawAudioIsSupported = false; - protected: bool ProtocolIsEnabled(); diff --git a/src/client.cpp b/src/client.cpp index 543b99aea1..e2165cea5a 100644 --- a/src/client.cpp +++ b/src/client.cpp @@ -395,6 +395,17 @@ void CClient::OnConClientListMesReceived ( CVector vecChanInfo ) emit ConClientListMesReceived ( vecChanInfo ); } +void CClient::OnVersionAndOSReceived ( COSUtil::EOpSystemType eOSType, QString strVersion ) +{ +#if QT_VERSION >= QT_VERSION_CHECK( 5, 6, 0 ) + if ( QVersionNumber::compare ( QVersionNumber::fromString ( strVersion ), QVersionNumber ( 3, 11, 1 ) ) >= 0 ) + { + bRawAudioIsSupported = true; + Init(); + } +#endif +} + void CClient::CreateServerJitterBufferMessage() { // per definition in the client: if auto jitter buffer is enabled, both, @@ -1157,7 +1168,7 @@ void CClient::Init() iCeltNumCodedBytes = OPUS_NUM_BYTES_MONO_HIGH_QUALITY_DBLE_FRAMESIZE; break; case AQ_RAW: - if ( Channel.bRawAudioIsSupported ) + if ( bRawAudioIsSupported ) { iCeltNumCodedBytes = iNumAudioChannels * iOPUSFrameSizeSamples * sizeof ( int16_t ); } @@ -1186,7 +1197,7 @@ void CClient::Init() iCeltNumCodedBytes = OPUS_NUM_BYTES_STEREO_HIGH_QUALITY_DBLE_FRAMESIZE; break; case AQ_RAW: - if ( Channel.bRawAudioIsSupported ) + if ( bRawAudioIsSupported ) { iCeltNumCodedBytes = iNumAudioChannels * iOPUSFrameSizeSamples * sizeof ( int16_t ); } @@ -1220,7 +1231,7 @@ void CClient::Init() iCeltNumCodedBytes = OPUS_NUM_BYTES_MONO_HIGH_QUALITY; break; case AQ_RAW: - if ( Channel.bRawAudioIsSupported ) + if ( bRawAudioIsSupported ) { iCeltNumCodedBytes = iNumAudioChannels * iOPUSFrameSizeSamples * sizeof ( int16_t ); } @@ -1249,7 +1260,7 @@ void CClient::Init() iCeltNumCodedBytes = OPUS_NUM_BYTES_STEREO_HIGH_QUALITY; break; case AQ_RAW: - if ( Channel.bRawAudioIsSupported ) + if ( bRawAudioIsSupported ) { iCeltNumCodedBytes = iNumAudioChannels * iOPUSFrameSizeSamples * sizeof ( int16_t ); } @@ -1429,7 +1440,7 @@ void CClient::ProcessAudioDataIntern ( CVector& vecsStereoSndCrd ) } } - if ( eAudioQuality != AQ_RAW || !Channel.bRawAudioIsSupported ) + if ( eAudioQuality != AQ_RAW || !bRawAudioIsSupported ) { for ( i = 0, j = 0; i < iSndCrdFrameSizeFactor; i++, j += iNumAudioChannels * iOPUSFrameSizeSamples ) { @@ -1479,7 +1490,7 @@ void CClient::ProcessAudioDataIntern ( CVector& vecsStereoSndCrd ) // get pointer to coded data and manage the flags if ( bReceiveDataOk ) { - if ( eAudioQuality == AQ_RAW && Channel.bRawAudioIsSupported ) + if ( eAudioQuality == AQ_RAW && bRawAudioIsSupported ) { memcpy ( &vecsStereoSndCrd[0], &vecbyNetwData[0], iCeltNumCodedBytes ); pCurCodedData = nullptr; @@ -1493,7 +1504,7 @@ void CClient::ProcessAudioDataIntern ( CVector& vecsStereoSndCrd ) } else { - if ( eAudioQuality == AQ_RAW && Channel.bRawAudioIsSupported ) + if ( eAudioQuality == AQ_RAW && bRawAudioIsSupported ) { memset ( &vecsStereoSndCrd[0], 0, iCeltNumCodedBytes ); pCurCodedData = nullptr; @@ -1507,7 +1518,7 @@ void CClient::ProcessAudioDataIntern ( CVector& vecsStereoSndCrd ) bJitterBufferOK = false; } - if ( eAudioQuality != AQ_RAW || !Channel.bRawAudioIsSupported ) + if ( eAudioQuality != AQ_RAW || !bRawAudioIsSupported ) { // OPUS decoding if ( CurOpusDecoder != nullptr ) diff --git a/src/client.h b/src/client.h index 6139ef599e..dce919c675 100644 --- a/src/client.h +++ b/src/client.h @@ -403,6 +403,7 @@ class CClient : public QObject EMeterStyle eMeterStyle; bool bEnableAudioAlerts; bool bEnableOPUS64; + bool bRawAudioIsSupported; bool bJitterBufferOK; bool bEnableIPv6; @@ -456,6 +457,7 @@ protected slots: void OnMuteStateHasChangedReceived ( int iServerChanID, bool bIsMuted ); void OnCLChannelLevelListReceived ( CHostAddress InetAddr, CVector vecLevelList ); void OnConClientListMesReceived ( CVector vecChanInfo ); + void OnVersionAndOSReceived ( COSUtil::EOpSystemType eOSType, QString strVersion ); signals: void ConClientListMesReceived ( CVector vecChanInfo ); From c3b47fd93370a36d6423c44ea3e2571b8ea6269a Mon Sep 17 00:00:00 2001 From: Nils Brederlow <62596379+dingodoppelt@users.noreply.github.com> Date: Mon, 20 Apr 2026 20:40:25 +0200 Subject: [PATCH 19/27] fix style (I'll never learn) --- src/channel.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/channel.cpp b/src/channel.cpp index 8641d5a50b..9bd409889a 100644 --- a/src/channel.cpp +++ b/src/channel.cpp @@ -134,7 +134,7 @@ void CChannel::SetEnable ( const bool bNEnStat ) // function. NOTE that it is important to reset this parameter on SetEnable(false) // since the SetEnable(true) is set AFTER the Init() in the client -> we // simply set it regardless of the state which does not hurt. - bUseSequenceNumber = false; + bUseSequenceNumber = false; // if channel is not enabled, reset time out count and protocol if ( !bNEnStat ) From 1544eb7b8c72f01d9795a4e5d855d3a82c413964 Mon Sep 17 00:00:00 2001 From: Nils Brederlow <62596379+dingodoppelt@users.noreply.github.com> Date: Mon, 20 Apr 2026 21:35:01 +0200 Subject: [PATCH 20/27] fix last commit --- src/client.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/client.cpp b/src/client.cpp index e2165cea5a..2d77a3ba3c 100644 --- a/src/client.cpp +++ b/src/client.cpp @@ -137,6 +137,8 @@ CClient::CClient ( const quint16 iPortNumber, QObject::connect ( &Channel, &CChannel::VersionAndOSReceived, this, &CClient::VersionAndOSReceived ); + QObject::connect ( &Channel, &CChannel::VersionAndOSReceived, this, &CClient::OnVersionAndOSReceived ); + QObject::connect ( &Channel, &CChannel::RecorderStateReceived, this, &CClient::RecorderStateReceived ); QObject::connect ( &ConnLessProtocol, &CProtocol::CLMessReadyForSending, this, &CClient::OnSendCLProtMessage ); From 23399c5a3cab4fb4e5d366345993cdde742bed1c Mon Sep 17 00:00:00 2001 From: Nils Brederlow <62596379+dingodoppelt@users.noreply.github.com> Date: Tue, 21 Apr 2026 13:29:25 +0200 Subject: [PATCH 21/27] Disable bRawAudioIsSupported when leaving a server --- src/client.cpp | 5 +++++ src/client.h | 1 + 2 files changed, 6 insertions(+) diff --git a/src/client.cpp b/src/client.cpp index 2d77a3ba3c..5fe06f65ff 100644 --- a/src/client.cpp +++ b/src/client.cpp @@ -405,6 +405,11 @@ void CClient::OnVersionAndOSReceived ( COSUtil::EOpSystemType eOSType, QString s bRawAudioIsSupported = true; Init(); } + else + { + bRawAudioIsSupported = false; + Init(); + } #endif } diff --git a/src/client.h b/src/client.h index dce919c675..1f4c23bc83 100644 --- a/src/client.h +++ b/src/client.h @@ -438,6 +438,7 @@ protected slots: { if ( InetAddr == Channel.GetAddress() ) { + bRawAudioIsSupported = false; emit Disconnected(); } } From 5b8a7093c3868901a7d7618746e6c180988826c3 Mon Sep 17 00:00:00 2001 From: Nils Brederlow <62596379+dingodoppelt@users.noreply.github.com> Date: Tue, 21 Apr 2026 13:38:51 +0200 Subject: [PATCH 22/27] limit rawaudio to server version 3.11.1 only --- src/client.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/client.cpp b/src/client.cpp index 5fe06f65ff..667de2be91 100644 --- a/src/client.cpp +++ b/src/client.cpp @@ -400,7 +400,7 @@ void CClient::OnConClientListMesReceived ( CVector vecChanInfo ) void CClient::OnVersionAndOSReceived ( COSUtil::EOpSystemType eOSType, QString strVersion ) { #if QT_VERSION >= QT_VERSION_CHECK( 5, 6, 0 ) - if ( QVersionNumber::compare ( QVersionNumber::fromString ( strVersion ), QVersionNumber ( 3, 11, 1 ) ) >= 0 ) + if ( QVersionNumber::compare ( QVersionNumber::fromString ( strVersion ), QVersionNumber ( 3, 11, 1 ) ) == 0 ) { bRawAudioIsSupported = true; Init(); From 2aad9b545254f36c3487af80a0f6cd2dddb25516 Mon Sep 17 00:00:00 2001 From: Nils Brederlow <62596379+dingodoppelt@users.noreply.github.com> Date: Tue, 21 Apr 2026 16:37:57 +0200 Subject: [PATCH 23/27] opus fallback on disconnect --- src/client.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/client.cpp b/src/client.cpp index 667de2be91..188e8823e8 100644 --- a/src/client.cpp +++ b/src/client.cpp @@ -1035,6 +1035,10 @@ void CClient::Stop() // disable channel Channel.SetEnable ( false ); + // Fall back to opus in case raw was used + bRawAudioIsSupported = false; + Init(); + // wait for approx. 100 ms to make sure no audio packet is still in the // network queue causing the channel to be reconnected right after having // received the disconnect message (seems not to gain much, disconnect is From 754d7b086f7c49b7c29742b7cd026040d0645826 Mon Sep 17 00:00:00 2001 From: Nils Brederlow <62596379+dingodoppelt@users.noreply.github.com> Date: Tue, 21 Apr 2026 19:35:11 +0200 Subject: [PATCH 24/27] disable raw setting when unconnected to join a new server with forced opus --- src/client.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/client.cpp b/src/client.cpp index 188e8823e8..4b333f8bc6 100644 --- a/src/client.cpp +++ b/src/client.cpp @@ -1179,7 +1179,7 @@ void CClient::Init() iCeltNumCodedBytes = OPUS_NUM_BYTES_MONO_HIGH_QUALITY_DBLE_FRAMESIZE; break; case AQ_RAW: - if ( bRawAudioIsSupported ) + if ( bRawAudioIsSupported && Channel.IsEnabled() ) { iCeltNumCodedBytes = iNumAudioChannels * iOPUSFrameSizeSamples * sizeof ( int16_t ); } @@ -1208,7 +1208,7 @@ void CClient::Init() iCeltNumCodedBytes = OPUS_NUM_BYTES_STEREO_HIGH_QUALITY_DBLE_FRAMESIZE; break; case AQ_RAW: - if ( bRawAudioIsSupported ) + if ( bRawAudioIsSupported && Channel.IsEnabled() ) { iCeltNumCodedBytes = iNumAudioChannels * iOPUSFrameSizeSamples * sizeof ( int16_t ); } @@ -1242,7 +1242,7 @@ void CClient::Init() iCeltNumCodedBytes = OPUS_NUM_BYTES_MONO_HIGH_QUALITY; break; case AQ_RAW: - if ( bRawAudioIsSupported ) + if ( bRawAudioIsSupported && Channel.IsEnabled() ) { iCeltNumCodedBytes = iNumAudioChannels * iOPUSFrameSizeSamples * sizeof ( int16_t ); } @@ -1271,7 +1271,7 @@ void CClient::Init() iCeltNumCodedBytes = OPUS_NUM_BYTES_STEREO_HIGH_QUALITY; break; case AQ_RAW: - if ( bRawAudioIsSupported ) + if ( bRawAudioIsSupported && Channel.IsEnabled() ) { iCeltNumCodedBytes = iNumAudioChannels * iOPUSFrameSizeSamples * sizeof ( int16_t ); } From 14d83ed2e5964c2210a48cad5339d86568e2338a Mon Sep 17 00:00:00 2001 From: Nils Brederlow <62596379+dingodoppelt@users.noreply.github.com> Date: Wed, 22 Apr 2026 01:34:17 +0200 Subject: [PATCH 25/27] stop sound before calling client init --- src/client.cpp | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/client.cpp b/src/client.cpp index 4b333f8bc6..50dd40c7d7 100644 --- a/src/client.cpp +++ b/src/client.cpp @@ -400,6 +400,11 @@ void CClient::OnConClientListMesReceived ( CVector vecChanInfo ) void CClient::OnVersionAndOSReceived ( COSUtil::EOpSystemType eOSType, QString strVersion ) { #if QT_VERSION >= QT_VERSION_CHECK( 5, 6, 0 ) + const bool bWasRunning = Sound.IsRunning(); + if ( bWasRunning ) + { + Sound.Stop(); + } if ( QVersionNumber::compare ( QVersionNumber::fromString ( strVersion ), QVersionNumber ( 3, 11, 1 ) ) == 0 ) { bRawAudioIsSupported = true; @@ -410,6 +415,10 @@ void CClient::OnVersionAndOSReceived ( COSUtil::EOpSystemType eOSType, QString s bRawAudioIsSupported = false; Init(); } + if ( bWasRunning ) + { + Sound.Start(); + } #endif } From d630234162017afd18af2defe39f2158cf487c09 Mon Sep 17 00:00:00 2001 From: Nils Brederlow <62596379+dingodoppelt@users.noreply.github.com> Date: Wed, 22 Apr 2026 11:09:44 +0200 Subject: [PATCH 26/27] make raw audio quality setting persistent in config file --- src/settings.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/settings.cpp b/src/settings.cpp index af594c8bbe..daa2fd5736 100644 --- a/src/settings.cpp +++ b/src/settings.cpp @@ -605,7 +605,7 @@ void CClientSettings::ReadSettingsFromXML ( const QDomDocument& IniXMLDocument, } // audio quality - if ( GetNumericIniSet ( IniXMLDocument, "client", "audioquality", 0, 2 /* AQ_HIGH */, iValue ) ) + if ( GetNumericIniSet ( IniXMLDocument, "client", "audioquality", 0, 3 /* AQ_RAW */, iValue ) ) { pClient->SetAudioQuality ( static_cast ( iValue ) ); } From 32fca21dfbb3c8923efdcb2583121f8783864789 Mon Sep 17 00:00:00 2001 From: Nils Brederlow <62596379+dingodoppelt@users.noreply.github.com> Date: Wed, 22 Apr 2026 11:10:21 +0200 Subject: [PATCH 27/27] remove redundant setting of bRawAudioIsSupported --- src/client.h | 1 - 1 file changed, 1 deletion(-) diff --git a/src/client.h b/src/client.h index 1f4c23bc83..dce919c675 100644 --- a/src/client.h +++ b/src/client.h @@ -438,7 +438,6 @@ protected slots: { if ( InetAddr == Channel.GetAddress() ) { - bRawAudioIsSupported = false; emit Disconnected(); } }