some more work for 64 samples frame size support

This commit is contained in:
Volker Fischer 2020-03-28 16:27:45 +01:00
parent 86d4c4033c
commit 53f50070a7
9 changed files with 139 additions and 88 deletions

View file

@ -276,11 +276,9 @@ void CNetBufWithStats::UpdateAutoSetting()
// the current jitter buffer size significantly.
// For the initialization phase, use lower weight values to get faster
// adaptation.
// Note that the following definitions of the weigh constants assume a block
// size of 128 samples at a sampling rate of 48 kHz.
double dWeightUp = 0.999995;
double dWeightDown = 0.9999;
const double dHysteresisValue = 0.1;
double dWeightUp = IIR_WEIGTH_UP_NORMAL;
double dWeightDown = IIR_WEIGTH_DOWN_NORMAL;
const double dHysteresisValue = FILTER_DECISION_HYSTERESIS;
bool bUseFastAdaptation = false;
// check for initialization phase
@ -304,8 +302,8 @@ void CNetBufWithStats::UpdateAutoSetting()
if ( bUseFastAdaptation )
{
// overwrite weigth values with lower values
dWeightUp = 0.9995;
dWeightDown = 0.999;
dWeightUp = IIR_WEIGTH_UP_FAST;
dWeightDown = IIR_WEIGTH_DOWN_FAST;
}
// apply non-linear IIR filter

View file

@ -29,9 +29,15 @@
/* Definitions ****************************************************************/
// each regular buffer access lead to a count for put and get, assuming 2.66 ms
// blocks we have 15 s / 2.66 ms * 2 = approx. 11000
#define MAX_STATISTIC_COUNT 11000
// number of simulation network jitter buffers for evaluating the statistic
// NOTE If you want to change this number, the code has to modified, too!
#define NUM_STAT_SIMULATION_BUFFERS 10
// hysteresis for buffer size decision to avoid fast changes if close to the bound
#define FILTER_DECISION_HYSTERESIS 0.1
// TODO the following values must be adjusted for 64 samples frame size:
// definition of the upper error bound of the jitter buffers
#define ERROR_RATE_BOUND 0.001
@ -41,8 +47,33 @@
// size state
#define UP_MAX_ERROR_BOUND 0.01
// number of simulation network jitter buffers for evaluating the statistic
#define NUM_STAT_SIMULATION_BUFFERS 10
// #if ( SYSTEM_FRAME_SIZE_SAMPLES == 64 )
// // each regular buffer access lead to a count for put and get, assuming 2.66 ms
// // blocks we have 15 s / 1.33 ms * 2 = approx. 22500
// #define MAX_STATISTIC_COUNT 22500
//
// // convert numbers from 128 samples case using http://www.tsdconseil.fr/tutos/tuto-iir1-en.pdf
// // and https://octave-online.net:
// // gamma = 1-exp(-Ts/tau)
// // after some calculations we get: x=0.999995;1-exp(64/128*log(1-x))
// // TEST x=0.999995;1-exp(128/64*log(1-x))
// # define IIR_WEIGTH_UP_NORMAL 0.999999999975 // 0.997763932022
// # define IIR_WEIGTH_DOWN_NORMAL 0.99999999 // 0.99
// # define IIR_WEIGTH_UP_FAST 0.99999975 // 0.97763932022
// # define IIR_WEIGTH_DOWN_FAST 0.999999 // 0.9683772233
// #else
// each regular buffer access lead to a count for put and get, assuming 2.66 ms
// blocks we have 15 s / 2.66 ms * 2 = approx. 11000
# define MAX_STATISTIC_COUNT 11000
// Note that the following definitions of the weigh constants assume a block
// size of 128 samples at a sampling rate of 48 kHz.
# define IIR_WEIGTH_UP_NORMAL 0.999995
# define IIR_WEIGTH_DOWN_NORMAL 0.9999
# define IIR_WEIGTH_UP_FAST 0.9995
# define IIR_WEIGTH_DOWN_FAST 0.999
// #endif
/* Classes ********************************************************************/

View file

@ -346,10 +346,17 @@ void CChannel::OnNetTranspPropsReceived ( CNetworkTransportProps NetworkTranspor
if ( bIsServer )
{
// OPUS codec is the only supported codec right now
#if ( SYSTEM_FRAME_SIZE_SAMPLES == 64 )
if ( NetworkTransportProps.eAudioCodingType != CT_OPUS64 )
{
return;
}
#else
if ( NetworkTransportProps.eAudioCodingType != CT_OPUS )
{
return;
}
#endif
Mutex.lock();
{

View file

@ -600,7 +600,11 @@ void CClient::OnSndCrdReinitRequest ( int iSndCrdResetType )
void CClient::Start()
{
// always use the OPUS codec
#if ( SYSTEM_FRAME_SIZE_SAMPLES == 64 )
eAudioCompressionType = CT_OPUS64;
#else
eAudioCompressionType = CT_OPUS;
#endif
// init object
Init();
@ -995,11 +999,12 @@ void CClient::ProcessAudioDataIntern ( CVector<int16_t>& vecsStereoSndCrd )
}
for ( i = 0; i < iSndCrdFrameSizeFactor; i++ )
{
if ( eAudioChannelConf == CC_MONO )
{
// encode current audio frame
if ( eAudioCompressionType == CT_OPUS )
if ( ( eAudioCompressionType == CT_OPUS ) ||
( eAudioCompressionType == CT_OPUS64 ) )
{
if ( eAudioChannelConf == CC_MONO )
{
opus_custom_encode ( OpusEncoderMono,
&vecsStereoSndCrd[i * SYSTEM_FRAME_SIZE_SAMPLES],
@ -1007,11 +1012,7 @@ void CClient::ProcessAudioDataIntern ( CVector<int16_t>& vecsStereoSndCrd )
&vecCeltData[0],
iCeltNumCodedBytes );
}
}
else
{
// encode current audio frame
if ( eAudioCompressionType == CT_OPUS )
{
opus_custom_encode ( OpusEncoderStereo,
&vecsStereoSndCrd[i * 2 * SYSTEM_FRAME_SIZE_SAMPLES],
@ -1048,9 +1049,10 @@ void CClient::ProcessAudioDataIntern ( CVector<int16_t>& vecsStereoSndCrd )
// flag
bIsInitializationPhase = false;
if ( eAudioChannelConf == CC_MONO )
if ( ( eAudioCompressionType == CT_OPUS ) ||
( eAudioCompressionType == CT_OPUS64 ) )
{
if ( eAudioCompressionType == CT_OPUS )
if ( eAudioChannelConf == CC_MONO )
{
opus_custom_decode ( OpusDecoderMono,
&vecbyNetwData[0],
@ -1058,10 +1060,7 @@ void CClient::ProcessAudioDataIntern ( CVector<int16_t>& vecsStereoSndCrd )
&vecsAudioSndCrdMono[i * SYSTEM_FRAME_SIZE_SAMPLES],
SYSTEM_FRAME_SIZE_SAMPLES );
}
}
else
{
if ( eAudioCompressionType == CT_OPUS )
{
opus_custom_decode ( OpusDecoderStereo,
&vecbyNetwData[0],
@ -1074,9 +1073,10 @@ void CClient::ProcessAudioDataIntern ( CVector<int16_t>& vecsStereoSndCrd )
else
{
// lost packet
if ( eAudioChannelConf == CC_MONO )
if ( ( eAudioCompressionType == CT_OPUS ) ||
( eAudioCompressionType == CT_OPUS64 ) )
{
if ( eAudioCompressionType == CT_OPUS )
if ( eAudioChannelConf == CC_MONO )
{
opus_custom_decode ( OpusDecoderMono,
nullptr,
@ -1084,10 +1084,7 @@ void CClient::ProcessAudioDataIntern ( CVector<int16_t>& vecsStereoSndCrd )
&vecsAudioSndCrdMono[i * SYSTEM_FRAME_SIZE_SAMPLES],
SYSTEM_FRAME_SIZE_SAMPLES );
}
}
else
{
if ( eAudioCompressionType == CT_OPUS )
{
opus_custom_decode ( OpusDecoderStereo,
nullptr,

View file

@ -128,12 +128,21 @@ CClientSettingsDlg::CClientSettingsDlg ( CClient* pNCliP, QWidget* parent,
"connection properties.<br>"
"Three buffer sizes are supported:"
"<ul>"
#if ( SYSTEM_FRAME_SIZE_SAMPLES == 64 )
"<li>64 samples: This is the preferred setting since it gives lowest "
"latency but does not work with all sound cards.</li>"
"<li>128 samples: This setting should work on most of the available "
"sound cards.</li>"
"<li>256 samples: This setting should only be used if only a very slow "
"computer or a slow internet connection is available.</li>"
#else
"<li>128 samples: This is the preferred setting since it gives lowest "
"latency but does not work with all sound cards.</li>"
"<li>256 samples: This setting should work on most of the available "
"sound cards.</li>"
"<li>512 samples: This setting should only be used if only a very slow "
"computer or a slow internet connection is available.</li>"
#endif
"</ul>"
"Some sound card driver do not allow the buffer delay to be changed "
"from within the " ) + APP_NAME +

View file

@ -95,6 +95,11 @@ LED bar: lbr
// default oldest item to draw in history graph (days ago)
#define DEFAULT_DAYS_HISTORY 60
// System block size, this is the block size on which the audio coder works.
// All other block sizes must be a multiple of this size.
// Note that the UpdateAutoSetting() function assumes a value of 128.
#define SYSTEM_FRAME_SIZE_SAMPLES 128
// default server address
#define DEFAULT_SERVER_ADDRESS "jamulus.fischvolk.de"
#define DEFAULT_SERVER_NAME "Central Server"
@ -104,16 +109,15 @@ LED bar: lbr
#define LLCON_DOWNLOAD_URL "http://sourceforge.net/projects/llcon/files"
// defined port number for client and server
#define LLCON_DEFAULT_PORT_NUMBER 22124
#if ( SYSTEM_FRAME_SIZE_SAMPLES == 64 )
# define LLCON_DEFAULT_PORT_NUMBER 22064 // different port number for 64 samples frame size version
#else
# define LLCON_DEFAULT_PORT_NUMBER 22124
#endif
// system sample rate (the sound card and audio coder works on this sample rate)
#define SYSTEM_SAMPLE_RATE_HZ 48000 // Hz
// System block size, this is the block size on which the audio coder works.
// All other block sizes must be a multiple of this size.
// Note that the UpdateAutoSetting() function assumes a value of 128.
#define SYSTEM_FRAME_SIZE_SAMPLES 128
#define SYSTEM_BLOCK_DURATION_MS_FLOAT \
( static_cast<double> ( SYSTEM_FRAME_SIZE_SAMPLES ) / \
SYSTEM_SAMPLE_RATE_HZ * 1000 )
@ -121,9 +125,9 @@ LED bar: lbr
// define the allowed audio frame size factors (since the
// "SYSTEM_FRAME_SIZE_SAMPLES" is quite small, it may be that on some
// computers a larger value is required)
#define FRAME_SIZE_FACTOR_PREFERRED 1 // 128 (for frame size 128)
#define FRAME_SIZE_FACTOR_DEFAULT 2 // 256 (for frame size 128)
#define FRAME_SIZE_FACTOR_SAFE 4 // 512 (for frame size 128)
#define FRAME_SIZE_FACTOR_PREFERRED 1 // 128 (for frame size 128), 64 (for frame size 64)
#define FRAME_SIZE_FACTOR_DEFAULT 2 // 256 (for frame size 128), 128 (for frame size 64)
#define FRAME_SIZE_FACTOR_SAFE 4 // 512 (for frame size 128), 256 (for frame size 64)
// low complexity CELT encoder (if defined)
#define USE_LOW_COMPLEXITY_CELT_ENC

View file

@ -1148,7 +1148,8 @@ bool CProtocol::EvaluateNetwTranspPropsMes ( const CVector<uint8_t>& vecData )
// note that CT_NONE is not a valid setting but only used for server
// initialization
if ( ( iRecCodingType != CT_CELT ) &&
( iRecCodingType != CT_OPUS ) )
( iRecCodingType != CT_OPUS ) &&
( iRecCodingType != CT_OPUS64 ) )
{
return true;
}

View file

@ -30,9 +30,9 @@
CHighPrecisionTimer::CHighPrecisionTimer()
{
// add some error checking, the high precision timer implementation only
// supports 128 samples frame size at 48 kHz sampling rate
#if ( SYSTEM_FRAME_SIZE_SAMPLES != 128 )
# error "Only system frame size of 128 samples is supported by this module"
// supports 64 and 128 samples frame size at 48 kHz sampling rate
#if ( SYSTEM_FRAME_SIZE_SAMPLES != 64 ) && ( SYSTEM_FRAME_SIZE_SAMPLES != 128 )
# error "Only system frame size of 64 and 128 samples is supported by this module"
#endif
#if ( SYSTEM_SAMPLE_RATE_HZ != 48000 )
# error "Only a system sample rate of 48 kHz is supported by this module"
@ -41,14 +41,18 @@ CHighPrecisionTimer::CHighPrecisionTimer()
// Since QT only supports a minimum timer resolution of 1 ms but for our
// server we require a timer interval of 2.333 ms for 128 samples
// frame size at 48 kHz sampling rate.
// To support this interval, we use a timer with 2 ms
// resolution and fire the actual frame timer if the error to the actual
// To support this interval, we use a timer with 2 ms resolution for 128
// samples frame size and 1 ms resolution for 64 samples frame size.
// Then we fire the actual frame timer if the error to the actual
// required interval is minimum.
veciTimeOutIntervals.Init ( 3 );
// for 128 sample frame size at 48 kHz sampling rate:
// for 128 sample frame size at 48 kHz sampling rate with 2 ms timer resolution:
// actual intervals: 0.0 2.666 5.333 8.0
// quantized to 2 ms: 0 2 6 8 (0)
// for 64 sample frame size at 48 kHz sampling rate with 1 ms timer resolution:
// actual intervals: 0.0 1.333 2.666 4.0
// quantized to 2 ms: 0 1 3 4 (0)
veciTimeOutIntervals[0] = 0;
veciTimeOutIntervals[1] = 1;
veciTimeOutIntervals[2] = 0;
@ -64,8 +68,13 @@ void CHighPrecisionTimer::Start()
iCurPosInVector = 0;
iIntervalCounter = 0;
// start internal timer with 2 ms resolution
#if ( SYSTEM_FRAME_SIZE_SAMPLES == 64 )
// start internal timer with 1 ms resolution for 64 samples frame size
Timer.start ( 1 );
#else
// start internal timer with 2 ms resolution for 128 samples frame size
Timer.start ( 2 );
#endif
}
void CHighPrecisionTimer::Stop()
@ -762,26 +771,24 @@ JitterMeas.Measure();
bChannelIsNowDisconnected = true;
}
// CELT decode received data stream
// OPUS decode received data stream
if ( eGetStat == GS_BUFFER_OK )
{
if ( ( vecChannels[iCurChanID].GetAudioCompressionType() == CT_OPUS ) ||
( vecChannels[iCurChanID].GetAudioCompressionType() == CT_OPUS64 ) )
{
if ( iCurNumAudChan == 1 )
{
// mono
if ( vecChannels[iCurChanID].GetAudioCompressionType() == CT_OPUS )
{
opus_custom_decode ( OpusDecoderMono[iCurChanID],
&vecbyCodedData[0],
iCeltNumCodedBytes,
&vecvecsData[i][0],
SYSTEM_FRAME_SIZE_SAMPLES );
}
}
else
{
// stereo
if ( vecChannels[iCurChanID].GetAudioCompressionType() == CT_OPUS )
{
opus_custom_decode ( OpusDecoderStereo[iCurChanID],
&vecbyCodedData[0],
iCeltNumCodedBytes,
@ -793,23 +800,21 @@ JitterMeas.Measure();
else
{
// lost packet
if ( ( vecChannels[iCurChanID].GetAudioCompressionType() == CT_OPUS ) ||
( vecChannels[iCurChanID].GetAudioCompressionType() == CT_OPUS64 ) )
{
if ( iCurNumAudChan == 1 )
{
// mono
if ( vecChannels[iCurChanID].GetAudioCompressionType() == CT_OPUS )
{
opus_custom_decode ( OpusDecoderMono[iCurChanID],
nullptr,
iCeltNumCodedBytes,
&vecvecsData[i][0],
SYSTEM_FRAME_SIZE_SAMPLES );
}
}
else
{
// stereo
if ( vecChannels[iCurChanID].GetAudioCompressionType() == CT_OPUS )
{
opus_custom_decode ( OpusDecoderStereo[iCurChanID],
nullptr,
iCeltNumCodedBytes,
@ -866,12 +871,13 @@ JitterMeas.Measure();
const int iCeltNumCodedBytes =
vecChannels[iCurChanID].GetNetwFrameSize();
// OPUS/CELT encoding
// OPUS encoding
if ( ( vecChannels[iCurChanID].GetAudioCompressionType() == CT_OPUS ) ||
( vecChannels[iCurChanID].GetAudioCompressionType() == CT_OPUS64 ) )
{
if ( vecChannels[iCurChanID].GetNumAudioChannels() == 1 )
{
// mono:
if ( vecChannels[iCurChanID].GetAudioCompressionType() == CT_OPUS )
{
// TODO 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
@ -885,12 +891,9 @@ opus_custom_encoder_ctl ( OpusEncoderMono[iCurChanID],
&vecbyCodedData[0],
iCeltNumCodedBytes );
}
}
else
{
// stereo:
if ( vecChannels[iCurChanID].GetAudioCompressionType() == CT_OPUS )
{
// TODO 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

View file

@ -517,7 +517,8 @@ enum EAudComprType
// used for protocol -> enum values must be fixed!
CT_NONE = 0,
CT_CELT = 1,
CT_OPUS = 2
CT_OPUS = 2,
CT_OPUS64 = 3 // using OPUS with 64 samples frame size
};