WIP: support 64 samples frame size in the client

This commit is contained in:
Volker Fischer 2020-04-13 16:01:25 +02:00
parent f6ea80ca81
commit 5f85660cde
4 changed files with 150 additions and 118 deletions

View file

@ -51,7 +51,7 @@ CClient::CClient ( const quint16 iPortNumber,
CurOpusDecoder ( nullptr ), CurOpusDecoder ( nullptr ),
eAudioCompressionType ( CT_OPUS ), eAudioCompressionType ( CT_OPUS ),
iCeltNumCodedBytes ( OPUS_NUM_BYTES_MONO_LOW_QUALITY ), iCeltNumCodedBytes ( OPUS_NUM_BYTES_MONO_LOW_QUALITY ),
iOPUSFrameSizeSamples ( SYSTEM_FRAME_SIZE_SAMPLES ), iOPUSFrameSizeSamples ( DOUBLE_SYSTEM_FRAME_SIZE_SAMPLES ),
eAudioQuality ( AQ_NORMAL ), eAudioQuality ( AQ_NORMAL ),
eAudioChannelConf ( CC_MONO ), eAudioChannelConf ( CC_MONO ),
iNumAudioChannels ( 1 ), iNumAudioChannels ( 1 ),
@ -669,16 +669,16 @@ void CClient::Stop()
void CClient::Init() void CClient::Init()
{ {
// check if possible frame size factors are supported // check if possible frame size factors are supported
const int iFraSizePreffered = FRAME_SIZE_FACTOR_PREFERRED * SYSTEM_FRAME_SIZE_SAMPLES; const int iFraSizePreffered = SYSTEM_FRAME_SIZE_SAMPLES_SMALL * FRAME_SIZE_FACTOR_PREFERRED;
const int iFraSizeDefault = FRAME_SIZE_FACTOR_DEFAULT * SYSTEM_FRAME_SIZE_SAMPLES; const int iFraSizeDefault = SYSTEM_FRAME_SIZE_SAMPLES_SMALL * FRAME_SIZE_FACTOR_DEFAULT;
const int iFraSizeSafe = FRAME_SIZE_FACTOR_SAFE * SYSTEM_FRAME_SIZE_SAMPLES; const int iFraSizeSafe = SYSTEM_FRAME_SIZE_SAMPLES_SMALL * FRAME_SIZE_FACTOR_SAFE;
bFraSiFactPrefSupported = ( Sound.Init ( iFraSizePreffered ) == iFraSizePreffered ); bFraSiFactPrefSupported = ( Sound.Init ( iFraSizePreffered ) == iFraSizePreffered );
bFraSiFactDefSupported = ( Sound.Init ( iFraSizeDefault ) == iFraSizeDefault ); bFraSiFactDefSupported = ( Sound.Init ( iFraSizeDefault ) == iFraSizeDefault );
bFraSiFactSafeSupported = ( Sound.Init ( iFraSizeSafe ) == iFraSizeSafe ); bFraSiFactSafeSupported = ( Sound.Init ( iFraSizeSafe ) == iFraSizeSafe );
// translate block size index in actual block size // translate block size index in actual block size
const int iPrefMonoFrameSize = iSndCrdPrefFrameSizeFactor * SYSTEM_FRAME_SIZE_SAMPLES; const int iPrefMonoFrameSize = iSndCrdPrefFrameSizeFactor * SYSTEM_FRAME_SIZE_SAMPLES_SMALL;
// get actual sound card buffer size using preferred size // get actual sound card buffer size using preferred size
iMonoBlockSizeSam = Sound.Init ( iPrefMonoFrameSize ); iMonoBlockSizeSam = Sound.Init ( iPrefMonoFrameSize );
@ -686,12 +686,12 @@ void CClient::Init()
// Calculate the current sound card frame size factor. In case // Calculate the current sound card frame size factor. In case
// the current mono block size is not a multiple of the system // the current mono block size is not a multiple of the system
// frame size, we have to use a sound card conversion buffer. // frame size, we have to use a sound card conversion buffer.
if ( ( iMonoBlockSizeSam == ( SYSTEM_FRAME_SIZE_SAMPLES * FRAME_SIZE_FACTOR_PREFERRED ) ) || if ( ( iMonoBlockSizeSam == ( SYSTEM_FRAME_SIZE_SAMPLES_SMALL * FRAME_SIZE_FACTOR_PREFERRED ) ) ||
( iMonoBlockSizeSam == ( SYSTEM_FRAME_SIZE_SAMPLES * FRAME_SIZE_FACTOR_DEFAULT ) ) || ( iMonoBlockSizeSam == ( SYSTEM_FRAME_SIZE_SAMPLES_SMALL * FRAME_SIZE_FACTOR_DEFAULT ) ) ||
( iMonoBlockSizeSam == ( SYSTEM_FRAME_SIZE_SAMPLES * FRAME_SIZE_FACTOR_SAFE ) ) ) ( iMonoBlockSizeSam == ( SYSTEM_FRAME_SIZE_SAMPLES_SMALL * FRAME_SIZE_FACTOR_SAFE ) ) )
{ {
// regular case: one of our predefined buffer sizes is available // regular case: one of our predefined buffer sizes is available
iSndCrdFrameSizeFactor = iMonoBlockSizeSam / SYSTEM_FRAME_SIZE_SAMPLES; iSndCrdFrameSizeFactor = iMonoBlockSizeSam / SYSTEM_FRAME_SIZE_SAMPLES_SMALL;
// no sound card conversion buffer required // no sound card conversion buffer required
bSndCrdConversionBufferRequired = false; bSndCrdConversionBufferRequired = false;
@ -700,51 +700,49 @@ void CClient::Init()
{ {
// An unsupported sound card buffer size is currently used -> we have // An unsupported sound card buffer size is currently used -> we have
// to use a conversion buffer. Per definition we use the smallest buffer // to use a conversion buffer. Per definition we use the smallest buffer
// size as the current frame size // size as the current frame size.
// store actual sound card buffer size (stereo) // store actual sound card buffer size (stereo)
iSndCardMonoBlockSizeSamConvBuff = iMonoBlockSizeSam;
const int iSndCardStereoBlockSizeSamConvBuff = 2 * iMonoBlockSizeSam;
// overwrite block size by smallest supported buffer size
iSndCrdFrameSizeFactor = FRAME_SIZE_FACTOR_PREFERRED;
iMonoBlockSizeSam = SYSTEM_FRAME_SIZE_SAMPLES * FRAME_SIZE_FACTOR_PREFERRED;
iStereoBlockSizeSam = 2 * iMonoBlockSizeSam;
// inits for conversion buffer (the size of the conversion buffer must
// be the sum of input/output sizes which is the worst case fill level)
const int iConBufSize = iStereoBlockSizeSam + iSndCardStereoBlockSizeSamConvBuff;
SndCrdConversionBufferIn.Init ( iConBufSize );
SndCrdConversionBufferOut.Init ( iConBufSize );
vecDataConvBuf.Init ( iStereoBlockSizeSam );
// the output conversion buffer must be filled with the inner
// block size for initialization (this is the latency which is
// introduced by the conversion buffer) to avoid buffer underruns
const CVector<int16_t> vZeros ( iStereoBlockSizeSam, 0 );
SndCrdConversionBufferOut.Put ( vZeros, vZeros.Size() );
bSndCrdConversionBufferRequired = true; bSndCrdConversionBufferRequired = true;
iSndCardMonoBlockSizeSamConvBuff = iMonoBlockSizeSam;
// overwrite block size factor by using one frame
iSndCrdFrameSizeFactor = 1;
} }
// calculate stereo (two channels) buffer size // select the OPUS frame size mode depending on current mono block size samples
iStereoBlockSizeSam = 2 * iMonoBlockSizeSam; if ( bSndCrdConversionBufferRequired )
{
if ( iSndCardMonoBlockSizeSamConvBuff < DOUBLE_SYSTEM_FRAME_SIZE_SAMPLES )
{
iMonoBlockSizeSam = SYSTEM_FRAME_SIZE_SAMPLES_SMALL;
eAudioCompressionType = CT_OPUS64;
}
else
{
iMonoBlockSizeSam = DOUBLE_SYSTEM_FRAME_SIZE_SAMPLES;
eAudioCompressionType = CT_OPUS;
}
}
else
{
if ( iMonoBlockSizeSam < DOUBLE_SYSTEM_FRAME_SIZE_SAMPLES )
{
eAudioCompressionType = CT_OPUS64;
}
else
{
// since we use double size frame size for OPUS, we have to adjust the frame size factor
iSndCrdFrameSizeFactor /= 2;
eAudioCompressionType = CT_OPUS;
// init reverberation }
AudioReverbL.Init ( SYSTEM_SAMPLE_RATE_HZ ); }
AudioReverbR.Init ( SYSTEM_SAMPLE_RATE_HZ );
// inits for audio coding // inits for audio coding
// always use the OPUS codec if ( eAudioCompressionType == CT_OPUS )
#if ( SYSTEM_FRAME_SIZE_SAMPLES == 64 ) {
eAudioCompressionType = CT_OPUS64; iOPUSFrameSizeSamples = DOUBLE_SYSTEM_FRAME_SIZE_SAMPLES;
#else
eAudioCompressionType = CT_OPUS;
#endif
iOPUSFrameSizeSamples = SYSTEM_FRAME_SIZE_SAMPLES;
if ( eAudioChannelConf == CC_MONO ) if ( eAudioChannelConf == CC_MONO )
{ {
@ -752,6 +750,37 @@ void CClient::Init()
CurOpusDecoder = OpusDecoderMono; CurOpusDecoder = OpusDecoderMono;
iNumAudioChannels = 1; iNumAudioChannels = 1;
switch ( eAudioQuality )
{
case AQ_LOW: iCeltNumCodedBytes = OPUS_NUM_BYTES_MONO_LOW_QUALITY_DBLE_FRAMESIZE; break;
case AQ_NORMAL: iCeltNumCodedBytes = OPUS_NUM_BYTES_MONO_NORMAL_QUALITY_DBLE_FRAMESIZE; break;
case AQ_HIGH: iCeltNumCodedBytes = OPUS_NUM_BYTES_MONO_HIGH_QUALITY_DBLE_FRAMESIZE; break;
}
}
else
{
CurOpusEncoder = OpusEncoderStereo;
CurOpusDecoder = OpusDecoderStereo;
iNumAudioChannels = 2;
switch ( eAudioQuality )
{
case AQ_LOW: iCeltNumCodedBytes = OPUS_NUM_BYTES_STEREO_LOW_QUALITY_DBLE_FRAMESIZE; break;
case AQ_NORMAL: iCeltNumCodedBytes = OPUS_NUM_BYTES_STEREO_NORMAL_QUALITY_DBLE_FRAMESIZE; break;
case AQ_HIGH: iCeltNumCodedBytes = OPUS_NUM_BYTES_STEREO_HIGH_QUALITY_DBLE_FRAMESIZE; break;
}
}
}
else /* CT_OPUS64 */
{
iOPUSFrameSizeSamples = SYSTEM_FRAME_SIZE_SAMPLES_SMALL;
if ( eAudioChannelConf == CC_MONO )
{
CurOpusEncoder = Opus64EncoderMono;
CurOpusDecoder = Opus64DecoderMono;
iNumAudioChannels = 1;
switch ( eAudioQuality ) switch ( eAudioQuality )
{ {
case AQ_LOW: iCeltNumCodedBytes = OPUS_NUM_BYTES_MONO_LOW_QUALITY; break; case AQ_LOW: iCeltNumCodedBytes = OPUS_NUM_BYTES_MONO_LOW_QUALITY; break;
@ -761,8 +790,8 @@ void CClient::Init()
} }
else else
{ {
CurOpusEncoder = OpusEncoderStereo; CurOpusEncoder = Opus64EncoderStereo;
CurOpusDecoder = OpusDecoderStereo; CurOpusDecoder = Opus64DecoderStereo;
iNumAudioChannels = 2; iNumAudioChannels = 2;
switch ( eAudioQuality ) switch ( eAudioQuality )
@ -772,6 +801,10 @@ void CClient::Init()
case AQ_HIGH: iCeltNumCodedBytes = OPUS_NUM_BYTES_STEREO_HIGH_QUALITY; break; case AQ_HIGH: iCeltNumCodedBytes = OPUS_NUM_BYTES_STEREO_HIGH_QUALITY; break;
} }
} }
}
// calculate stereo (two channels) buffer size
iStereoBlockSizeSam = 2 * iMonoBlockSizeSam;
vecCeltData.Init ( iCeltNumCodedBytes ); vecCeltData.Init ( iCeltNumCodedBytes );
@ -789,6 +822,29 @@ void CClient::Init()
iSndCrdFrameSizeFactor, iSndCrdFrameSizeFactor,
iNumAudioChannels ); iNumAudioChannels );
// init reverberation
AudioReverbL.Init ( SYSTEM_SAMPLE_RATE_HZ );
AudioReverbR.Init ( SYSTEM_SAMPLE_RATE_HZ );
// init the sound card conversion buffers
if ( bSndCrdConversionBufferRequired )
{
// inits for conversion buffer (the size of the conversion buffer must
// be the sum of input/output sizes which is the worst case fill level)
const int iSndCardStereoBlockSizeSamConvBuff = 2 * iSndCardMonoBlockSizeSamConvBuff;
const int iConBufSize = iStereoBlockSizeSam + iSndCardStereoBlockSizeSamConvBuff;
SndCrdConversionBufferIn.Init ( iConBufSize );
SndCrdConversionBufferOut.Init ( iConBufSize );
vecDataConvBuf.Init ( iStereoBlockSizeSam );
// the output conversion buffer must be filled with the inner
// block size for initialization (this is the latency which is
// introduced by the conversion buffer) to avoid buffer underruns
const CVector<int16_t> vZeros ( iStereoBlockSizeSam, 0 );
SndCrdConversionBufferOut.Put ( vZeros, vZeros.Size() );
}
// reset initialization phase flag and mute flag // reset initialization phase flag and mute flag
bIsInitializationPhase = true; bIsInitializationPhase = true;
bMuteInputAndOutput = false; bMuteInputAndOutput = false;

View file

@ -83,23 +83,19 @@
// Fs: sampling rate (SYSTEM_SAMPLE_RATE_HZ) // Fs: sampling rate (SYSTEM_SAMPLE_RATE_HZ)
// L: number of samples per packet (SYSTEM_FRAME_SIZE_SAMPLES) // L: number of samples per packet (SYSTEM_FRAME_SIZE_SAMPLES)
// N: number of bytes per packet (values below) // N: number of bytes per packet (values below)
#if ( SYSTEM_FRAME_SIZE_SAMPLES == 64 )
#define OPUS_NUM_BYTES_MONO_LOW_QUALITY 12 #define OPUS_NUM_BYTES_MONO_LOW_QUALITY 12
#define OPUS_NUM_BYTES_MONO_NORMAL_QUALITY 22 #define OPUS_NUM_BYTES_MONO_NORMAL_QUALITY 22
#define OPUS_NUM_BYTES_MONO_HIGH_QUALITY 35 #define OPUS_NUM_BYTES_MONO_HIGH_QUALITY 35
#define OPUS_NUM_BYTES_MONO_LOW_QUALITY_DBLE_FRAMESIZE 25
#define OPUS_NUM_BYTES_MONO_NORMAL_QUALITY_DBLE_FRAMESIZE 45
#define OPUS_NUM_BYTES_MONO_HIGH_QUALITY_DBLE_FRAMESIZE 71
#define OPUS_NUM_BYTES_STEREO_LOW_QUALITY 24 #define OPUS_NUM_BYTES_STEREO_LOW_QUALITY 24
#define OPUS_NUM_BYTES_STEREO_NORMAL_QUALITY 35 #define OPUS_NUM_BYTES_STEREO_NORMAL_QUALITY 35
#define OPUS_NUM_BYTES_STEREO_HIGH_QUALITY 72 #define OPUS_NUM_BYTES_STEREO_HIGH_QUALITY 72
#else #define OPUS_NUM_BYTES_STEREO_LOW_QUALITY_DBLE_FRAMESIZE 47
# define OPUS_NUM_BYTES_MONO_LOW_QUALITY 25 #define OPUS_NUM_BYTES_STEREO_NORMAL_QUALITY_DBLE_FRAMESIZE 71
# define OPUS_NUM_BYTES_MONO_NORMAL_QUALITY 45 #define OPUS_NUM_BYTES_STEREO_HIGH_QUALITY_DBLE_FRAMESIZE 142
# define OPUS_NUM_BYTES_MONO_HIGH_QUALITY 71
# define OPUS_NUM_BYTES_STEREO_LOW_QUALITY 47
# define OPUS_NUM_BYTES_STEREO_NORMAL_QUALITY 71
# define OPUS_NUM_BYTES_STEREO_HIGH_QUALITY 142
#endif
/* Classes ********************************************************************/ /* Classes ********************************************************************/

View file

@ -128,21 +128,12 @@ CClientSettingsDlg::CClientSettingsDlg ( CClient* pNCliP, QWidget* parent,
"connection properties.<br>" "connection properties.<br>"
"Three buffer sizes are supported:" "Three buffer sizes are supported:"
"<ul>" "<ul>"
#if ( SYSTEM_FRAME_SIZE_SAMPLES == 64 )
"<li>64 samples: This is the preferred setting since it gives lowest " "<li>64 samples: This is the preferred setting since it gives lowest "
"latency but does not work with all sound cards.</li>" "latency but does not work with all sound cards.</li>"
"<li>128 samples: This setting should work on most of the available " "<li>128 samples: This setting should work on most of the available "
"sound cards.</li>" "sound cards.</li>"
"<li>256 samples: This setting should only be used if only a very slow " "<li>256 samples: This setting should only be used if only a very slow "
"computer or a slow internet connection is available.</li>" "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>" "</ul>"
"Some sound card driver do not allow the buffer delay to be changed " "Some sound card driver do not allow the buffer delay to be changed "
"from within the " ) + APP_NAME + "from within the " ) + APP_NAME +
@ -356,14 +347,14 @@ CClientSettingsDlg::CClientSettingsDlg ( CClient* pNCliP, QWidget* parent,
// set text for sound card buffer delay radio buttons // set text for sound card buffer delay radio buttons
rbtBufferDelayPreferred->setText ( GenSndCrdBufferDelayString ( rbtBufferDelayPreferred->setText ( GenSndCrdBufferDelayString (
FRAME_SIZE_FACTOR_PREFERRED * SYSTEM_FRAME_SIZE_SAMPLES, FRAME_SIZE_FACTOR_PREFERRED * SYSTEM_FRAME_SIZE_SAMPLES_SMALL,
", preferred" ) ); ", preferred" ) );
rbtBufferDelayDefault->setText ( GenSndCrdBufferDelayString ( rbtBufferDelayDefault->setText ( GenSndCrdBufferDelayString (
FRAME_SIZE_FACTOR_DEFAULT * SYSTEM_FRAME_SIZE_SAMPLES ) ); FRAME_SIZE_FACTOR_DEFAULT * SYSTEM_FRAME_SIZE_SAMPLES_SMALL ) );
rbtBufferDelaySafe->setText ( GenSndCrdBufferDelayString ( rbtBufferDelaySafe->setText ( GenSndCrdBufferDelayString (
FRAME_SIZE_FACTOR_SAFE * SYSTEM_FRAME_SIZE_SAMPLES ) ); FRAME_SIZE_FACTOR_SAFE * SYSTEM_FRAME_SIZE_SAMPLES_SMALL ) );
// sound card buffer delay inits // sound card buffer delay inits
SndCrdBufferDelayButtonGroup.addButton ( rbtBufferDelayPreferred ); SndCrdBufferDelayButtonGroup.addButton ( rbtBufferDelayPreferred );
@ -478,18 +469,12 @@ QString CClientSettingsDlg::GenSndCrdBufferDelayString ( const int iFrameSiz
void CClientSettingsDlg::UpdateSoundCardFrame() void CClientSettingsDlg::UpdateSoundCardFrame()
{ {
// get current actual buffer size value // get current actual buffer size value
const int iCurActualBufSize = const int iCurActualBufSize = pClient->GetSndCrdActualMonoBlSize();
pClient->GetSndCrdActualMonoBlSize();
// check which predefined size is used (it is possible that none is used) // check which predefined size is used (it is possible that none is used)
const bool bPreferredChecked = const bool bPreferredChecked = ( iCurActualBufSize == SYSTEM_FRAME_SIZE_SAMPLES_SMALL * FRAME_SIZE_FACTOR_PREFERRED );
( iCurActualBufSize == SYSTEM_FRAME_SIZE_SAMPLES * FRAME_SIZE_FACTOR_PREFERRED ); const bool bDefaultChecked = ( iCurActualBufSize == SYSTEM_FRAME_SIZE_SAMPLES_SMALL * FRAME_SIZE_FACTOR_DEFAULT );
const bool bSafeChecked = ( iCurActualBufSize == SYSTEM_FRAME_SIZE_SAMPLES_SMALL * FRAME_SIZE_FACTOR_SAFE );
const bool bDefaultChecked =
( iCurActualBufSize == SYSTEM_FRAME_SIZE_SAMPLES * FRAME_SIZE_FACTOR_DEFAULT );
const bool bSafeChecked =
( iCurActualBufSize == SYSTEM_FRAME_SIZE_SAMPLES * FRAME_SIZE_FACTOR_SAFE );
// Set radio buttons according to current value (To make it possible // Set radio buttons according to current value (To make it possible
// to have all radio buttons unchecked, we have to disable the // to have all radio buttons unchecked, we have to disable the
@ -504,14 +489,9 @@ void CClientSettingsDlg::UpdateSoundCardFrame()
SndCrdBufferDelayButtonGroup.setExclusive ( true ); SndCrdBufferDelayButtonGroup.setExclusive ( true );
// disable radio buttons which are not supported by audio interface // disable radio buttons which are not supported by audio interface
rbtBufferDelayPreferred->setEnabled ( rbtBufferDelayPreferred->setEnabled ( pClient->GetFraSiFactPrefSupported() );
pClient->GetFraSiFactPrefSupported() ); rbtBufferDelayDefault->setEnabled ( pClient->GetFraSiFactDefSupported() );
rbtBufferDelaySafe->setEnabled ( pClient->GetFraSiFactSafeSupported() );
rbtBufferDelayDefault->setEnabled (
pClient->GetFraSiFactDefSupported() );
rbtBufferDelaySafe->setEnabled (
pClient->GetFraSiFactSafeSupported() );
// If any of our predefined sizes is chosen, use the regular group box // If any of our predefined sizes is chosen, use the regular group box
// title text. If not, show the actual buffer size. Otherwise the user // title text. If not, show the actual buffer size. Otherwise the user