WIP on support of 64/128 samples frame size in the server

This commit is contained in:
Volker Fischer 2020-04-04 19:03:19 +02:00
parent 0bdf6a45ae
commit 57f203502c
5 changed files with 170 additions and 175 deletions

View file

@ -346,18 +346,12 @@ void CChannel::OnNetTranspPropsReceived ( CNetworkTransportProps NetworkTranspor
// only the server shall act on network transport properties message // only the server shall act on network transport properties message
if ( bIsServer ) if ( bIsServer )
{ {
// OPUS codec is the only supported codec right now // OPUS and OPUS64 codecs are the only supported codecs right now
#if ( SYSTEM_FRAME_SIZE_SAMPLES == 64 ) if ( ( NetworkTransportProps.eAudioCodingType != CT_OPUS ) &&
if ( NetworkTransportProps.eAudioCodingType != CT_OPUS64 ) ( NetworkTransportProps.eAudioCodingType != CT_OPUS64 ) )
{ {
return; return;
} }
#else
if ( NetworkTransportProps.eAudioCodingType != CT_OPUS )
{
return;
}
#endif
Mutex.lock(); Mutex.lock();
{ {

View file

@ -98,6 +98,8 @@ LED bar: lbr
// System block size, this is the block size on which the audio coder works. // 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. // All other block sizes must be a multiple of this size.
// Note that the UpdateAutoSetting() function assumes a value of 128. // Note that the UpdateAutoSetting() function assumes a value of 128.
#define SYSTEM_FRAME_SIZE_SAMPLES_SMALL 64 // TODO this is temporary and shall be replaced by SYSTEM_FRAME_SIZE_SAMPLES later on
#define DOUBLE_SYSTEM_FRAME_SIZE_SAMPLES ( 2 * SYSTEM_FRAME_SIZE_SAMPLES_SMALL )
#define SYSTEM_FRAME_SIZE_SAMPLES 128 #define SYSTEM_FRAME_SIZE_SAMPLES 128
// default server address // default server address

View file

@ -513,6 +513,10 @@ int main ( int argc, char** argv )
} }
else else
{ {
// TODO
const bool bUseDoubleSystemFrameSize = true; // TODO for now this value is fixed but has to be changeable by command line argument
// Server: // Server:
// actual server object // actual server object
CServer Server ( iNumServerChannels, CServer Server ( iNumServerChannels,
@ -528,6 +532,7 @@ int main ( int argc, char** argv )
strRecordingDirName, strRecordingDirName,
bCentServPingServerInList, bCentServPingServerInList,
bDisconnectAllClients, bDisconnectAllClients,
bUseDoubleSystemFrameSize,
eLicenceType ); eLicenceType );
if ( bUseGUI ) if ( bUseGUI )
{ {

View file

@ -27,11 +27,12 @@
// CHighPrecisionTimer implementation ****************************************** // CHighPrecisionTimer implementation ******************************************
#ifdef _WIN32 #ifdef _WIN32
CHighPrecisionTimer::CHighPrecisionTimer() CHighPrecisionTimer::CHighPrecisionTimer ( const bool bNewUseDoubleSystemFrameSize ) :
bUseDoubleSystemFrameSize ( bNewUseDoubleSystemFrameSize )
{ {
// add some error checking, the high precision timer implementation only // add some error checking, the high precision timer implementation only
// supports 64 and 128 samples frame size at 48 kHz sampling rate // supports 64 and 128 samples frame size at 48 kHz sampling rate
#if ( SYSTEM_FRAME_SIZE_SAMPLES != 64 ) && ( SYSTEM_FRAME_SIZE_SAMPLES != 128 ) #if ( SYSTEM_FRAME_SIZE_SAMPLES_SMALL != 64 ) && ( DOUBLE_SYSTEM_FRAME_SIZE_SAMPLES != 128 )
# error "Only system frame size of 64 and 128 samples is supported by this module" # error "Only system frame size of 64 and 128 samples is supported by this module"
#endif #endif
#if ( SYSTEM_SAMPLE_RATE_HZ != 48000 ) #if ( SYSTEM_SAMPLE_RATE_HZ != 48000 )
@ -68,13 +69,16 @@ void CHighPrecisionTimer::Start()
iCurPosInVector = 0; iCurPosInVector = 0;
iIntervalCounter = 0; iIntervalCounter = 0;
#if ( SYSTEM_FRAME_SIZE_SAMPLES == 64 ) if ( bUseDoubleSystemFrameSize )
// 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 // start internal timer with 2 ms resolution for 128 samples frame size
Timer.start ( 2 ); Timer.start ( 2 );
#endif }
else
{
// start internal timer with 1 ms resolution for 64 samples frame size
Timer.start ( 1 );
}
} }
void CHighPrecisionTimer::Stop() void CHighPrecisionTimer::Stop()
@ -110,13 +114,22 @@ void CHighPrecisionTimer::OnTimer()
} }
} }
#else // Mac and Linux #else // Mac and Linux
CHighPrecisionTimer::CHighPrecisionTimer() : CHighPrecisionTimer::CHighPrecisionTimer ( const bool bUseDoubleSystemFrameSize ) :
bRun ( false ) bRun ( false )
{ {
// calculate delay in ns // calculate delay in ns
const uint64_t iNsDelay = const uint64_t iNsDelay;
( (uint64_t) SYSTEM_FRAME_SIZE_SAMPLES * 1000000000 ) /
if ( bUseDoubleSystemFrameSize )
{
iNsDelay = ( (uint64_t) DOUBLE_SYSTEM_FRAME_SIZE_SAMPLES * 1000000000 ) /
(uint64_t) SYSTEM_SAMPLE_RATE_HZ; // in ns (uint64_t) SYSTEM_SAMPLE_RATE_HZ; // in ns
}
else
{
iNsDelay = ( (uint64_t) SYSTEM_FRAME_SIZE_SAMPLES_SMALL * 1000000000 ) /
(uint64_t) SYSTEM_SAMPLE_RATE_HZ; // in ns
}
#if defined ( __APPLE__ ) || defined ( __MACOSX ) #if defined ( __APPLE__ ) || defined ( __MACOSX )
// calculate delay in mach absolute time // calculate delay in mach absolute time
@ -219,13 +232,16 @@ CServer::CServer ( const int iNewMaxNumChan,
const QString& strRecordingDirName, const QString& strRecordingDirName,
const bool bNCentServPingServerInList, const bool bNCentServPingServerInList,
const bool bNDisconnectAllClients, const bool bNDisconnectAllClients,
const bool bNUseDoubleSystemFrameSize,
const ELicenceType eNLicenceType ) : const ELicenceType eNLicenceType ) :
bUseDoubleSystemFrameSize ( bNUseDoubleSystemFrameSize ),
iMaxNumChannels ( iNewMaxNumChan ), iMaxNumChannels ( iNewMaxNumChan ),
Socket ( this, iPortNumber ), Socket ( this, iPortNumber ),
Logging ( iMaxDaysHistory ), Logging ( iMaxDaysHistory ),
JamRecorder ( strRecordingDirName ), JamRecorder ( strRecordingDirName ),
bEnableRecording ( !strRecordingDirName.isEmpty() ), bEnableRecording ( !strRecordingDirName.isEmpty() ),
bWriteStatusHTMLFile ( false ), bWriteStatusHTMLFile ( false ),
HighPrecisionTimer ( bNUseDoubleSystemFrameSize ),
ServerListManager ( iPortNumber, ServerListManager ( iPortNumber,
strCentralServer, strCentralServer,
strServerInfo, strServerInfo,
@ -240,60 +256,45 @@ CServer::CServer ( const int iNewMaxNumChan,
int iOpusError; int iOpusError;
int i; int i;
// create CELT encoder/decoder for each channel (must be done before // create OPUS encoder/decoder for each channel (must be done before
// enabling the channels), create a mono and stereo encoder/decoder // enabling the channels), create a mono and stereo encoder/decoder
// for each channel // for each channel
for ( i = 0; i < iMaxNumChannels; i++ ) for ( i = 0; i < iMaxNumChannels; i++ )
{ {
// init audio endocder/decoder (mono) // init OPUS -----------------------------------------------------------
OpusMode[i] = opus_custom_mode_create ( SYSTEM_SAMPLE_RATE_HZ, OpusMode[i] = opus_custom_mode_create ( SYSTEM_SAMPLE_RATE_HZ,
SYSTEM_FRAME_SIZE_SAMPLES, DOUBLE_SYSTEM_FRAME_SIZE_SAMPLES,
&iOpusError ); &iOpusError );
OpusEncoderMono[i] = opus_custom_encoder_create ( OpusMode[i], Opus64Mode[i] = opus_custom_mode_create ( SYSTEM_SAMPLE_RATE_HZ,
1, SYSTEM_FRAME_SIZE_SAMPLES_SMALL,
&iOpusError ); &iOpusError );
OpusDecoderMono[i] = opus_custom_decoder_create ( OpusMode[i], // init audio encoders and decoders
1, OpusEncoderMono[i] = opus_custom_encoder_create ( OpusMode[i], 1, &iOpusError ); // mono encoder legacy
&iOpusError ); OpusDecoderMono[i] = opus_custom_decoder_create ( OpusMode[i], 1, &iOpusError ); // mono decoder legacy
OpusEncoderStereo[i] = opus_custom_encoder_create ( OpusMode[i], 2, &iOpusError ); // stereo encoder legacy
OpusDecoderStereo[i] = opus_custom_decoder_create ( OpusMode[i], 2, &iOpusError ); // stereo decoder legacy
Opus64EncoderMono[i] = opus_custom_encoder_create ( Opus64Mode[i], 1, &iOpusError ); // mono encoder OPUS64
Opus64DecoderMono[i] = opus_custom_decoder_create ( Opus64Mode[i], 1, &iOpusError ); // mono decoder OPUS64
Opus64EncoderStereo[i] = opus_custom_encoder_create ( Opus64Mode[i], 2, &iOpusError ); // stereo encoder OPUS64
Opus64DecoderStereo[i] = opus_custom_decoder_create ( Opus64Mode[i], 2, &iOpusError ); // stereo decoder OPUS64
// we require a constant bit rate // we require a constant bit rate
opus_custom_encoder_ctl ( OpusEncoderMono[i], opus_custom_encoder_ctl ( OpusEncoderMono[i], OPUS_SET_VBR ( 0 ) );
OPUS_SET_VBR ( 0 ) ); opus_custom_encoder_ctl ( OpusEncoderStereo[i], OPUS_SET_VBR ( 0 ) );
opus_custom_encoder_ctl ( Opus64EncoderMono[i], OPUS_SET_VBR ( 0 ) );
opus_custom_encoder_ctl ( Opus64EncoderStereo[i], OPUS_SET_VBR ( 0 ) );
// we want as low delay as possible // we want as low delay as possible
opus_custom_encoder_ctl ( OpusEncoderMono[i], opus_custom_encoder_ctl ( OpusEncoderMono[i], OPUS_SET_APPLICATION ( OPUS_APPLICATION_RESTRICTED_LOWDELAY ) );
OPUS_SET_APPLICATION ( OPUS_APPLICATION_RESTRICTED_LOWDELAY ) ); opus_custom_encoder_ctl ( OpusEncoderStereo[i], OPUS_SET_APPLICATION ( OPUS_APPLICATION_RESTRICTED_LOWDELAY ) );
opus_custom_encoder_ctl ( Opus64EncoderMono[i], OPUS_SET_APPLICATION ( OPUS_APPLICATION_RESTRICTED_LOWDELAY ) );
opus_custom_encoder_ctl ( Opus64EncoderStereo[i], OPUS_SET_APPLICATION ( OPUS_APPLICATION_RESTRICTED_LOWDELAY ) );
#if ( SYSTEM_FRAME_SIZE_SAMPLES == 128 )
// set encoder low complexity for legacy 128 samples frame size // set encoder low complexity for legacy 128 samples frame size
opus_custom_encoder_ctl ( OpusEncoderMono[i], opus_custom_encoder_ctl ( OpusEncoderMono[i], OPUS_SET_COMPLEXITY ( 1 ) );
OPUS_SET_COMPLEXITY ( 1 ) ); opus_custom_encoder_ctl ( OpusEncoderStereo[i], OPUS_SET_COMPLEXITY ( 1 ) );
#endif
// init audio endocder/decoder (stereo)
OpusEncoderStereo[i] = opus_custom_encoder_create ( OpusMode[i],
2,
&iOpusError );
OpusDecoderStereo[i] = opus_custom_decoder_create ( OpusMode[i],
2,
&iOpusError );
// we require a constant bit rate
opus_custom_encoder_ctl ( OpusEncoderStereo[i],
OPUS_SET_VBR ( 0 ) );
// we want as low delay as possible
opus_custom_encoder_ctl ( OpusEncoderStereo[i],
OPUS_SET_APPLICATION ( OPUS_APPLICATION_RESTRICTED_LOWDELAY ) );
#if ( SYSTEM_FRAME_SIZE_SAMPLES == 128 )
// set encoder low complexity for legacy 128 samples frame size
opus_custom_encoder_ctl ( OpusEncoderStereo[i],
OPUS_SET_COMPLEXITY ( 1 ) );
#endif
} }
// define colors for chat window identifiers // define colors for chat window identifiers
@ -312,7 +313,7 @@ CServer::CServer ( const int iNewMaxNumChan,
// the worst case here: // the worst case here:
// we always use stereo audio buffers (which is the worst case) // we always use stereo audio buffers (which is the worst case)
vecsSendData.Init ( 2 * SYSTEM_FRAME_SIZE_SAMPLES ); vecsSendData.Init ( 2 /* stereo */ * DOUBLE_SYSTEM_FRAME_SIZE_SAMPLES /* worst case buffer size */ );
// allocate worst case memory for the temporary vectors // allocate worst case memory for the temporary vectors
vecChanIDsCurConChan.Init ( iMaxNumChannels ); vecChanIDsCurConChan.Init ( iMaxNumChannels );
@ -326,7 +327,7 @@ CServer::CServer ( const int iNewMaxNumChan,
vecvecdGains[i].Init ( iMaxNumChannels ); vecvecdGains[i].Init ( iMaxNumChannels );
// we always use stereo audio buffers (see "vecsSendData") // we always use stereo audio buffers (see "vecsSendData")
vecvecsData[i].Init ( 2 * SYSTEM_FRAME_SIZE_SAMPLES ); vecvecsData[i].Init ( 2 /* stereo */ * DOUBLE_SYSTEM_FRAME_SIZE_SAMPLES /* worst case buffer size */ );
} }
// allocate worst case memory for the coded data // allocate worst case memory for the coded data
@ -846,6 +847,9 @@ void CServer::Stop()
void CServer::OnTimer() void CServer::OnTimer()
{ {
int i, j; int i, j;
OpusCustomDecoder* CurOpusDecoder;
OpusCustomEncoder* CurOpusEncoder;
unsigned char* pCurCodedData;
/* /*
// TEST do a timer jitter measurement // TEST do a timer jitter measurement
@ -882,9 +886,17 @@ JitterMeas.Measure();
// get actual ID of current channel // get actual ID of current channel
const int iCurChanID = vecChanIDsCurConChan[i]; const int iCurChanID = vecChanIDsCurConChan[i];
// get and store number of audio channels // get and store number of audio channels and select the opus decoder
const int iCurNumAudChan = vecChannels[iCurChanID].GetNumAudioChannels(); vecNumAudioChannels[i] = vecChannels[iCurChanID].GetNumAudioChannels();
vecNumAudioChannels[i] = iCurNumAudChan;
if ( vecNumAudioChannels[i] == 1 )
{
CurOpusDecoder = OpusDecoderMono[iCurChanID];
}
else
{
CurOpusDecoder = OpusDecoderStereo[iCurChanID];
}
// get gains of all connected channels // get gains of all connected channels
for ( j = 0; j < iNumClients; j++ ) for ( j = 0; j < iNumClients; j++ )
@ -902,10 +914,21 @@ JitterMeas.Measure();
// get current number of CELT coded bytes // get current number of CELT coded bytes
const int iCeltNumCodedBytes = vecChannels[iCurChanID].GetNetwFrameSize(); const int iCeltNumCodedBytes = vecChannels[iCurChanID].GetNetwFrameSize();
// TODO
const bool bIsServerDoubleFrameSize = bUseDoubleSystemFrameSize && ( vecChannels[iCurChanID].GetAudioCompressionType() == CT_OPUS64 );
const bool bIsClientDoubleFrameSize = !bUseDoubleSystemFrameSize && ( vecChannels[iCurChanID].GetAudioCompressionType() == CT_OPUS );
const bool bIsCompatibleFramesSize = !( bIsServerDoubleFrameSize || bIsClientDoubleFrameSize );
//bUseDoubleSystemFrameSize
//ConvBuf
CConvBuf<uint8_t> ConvBufIn; // TEST NOT WORKING!!!!
//ConvBufIn.Put ( );
int iNumInBlocks = 1;
for ( int iB = 0; iB < iNumInBlocks; iB++ )
{
// get data // get data
const EGetDataStat eGetStat = const EGetDataStat eGetStat = vecChannels[iCurChanID].GetData ( vecbyCodedData, iCeltNumCodedBytes );
vecChannels[iCurChanID].GetData ( vecbyCodedData,
iCeltNumCodedBytes );
// if channel was just disconnected, set flag that connected // if channel was just disconnected, set flag that connected
// client list is sent to all other clients // client list is sent to all other clients
@ -920,57 +943,30 @@ JitterMeas.Measure();
bChannelIsNowDisconnected = true; bChannelIsNowDisconnected = true;
} }
// OPUS decode received data stream // get pointer to coded data
if ( eGetStat == GS_BUFFER_OK ) if ( eGetStat == GS_BUFFER_OK )
{ {
pCurCodedData = &vecbyCodedData[0];
}
else
{
// for lost packets use null pointer as coded input data
pCurCodedData = nullptr;
}
// OPUS decode received data stream
// SYSTEM_FRAME_SIZE_SAMPLES_SMALL
// DOUBLE_SYSTEM_FRAME_SIZE_SAMPLES
if ( ( vecChannels[iCurChanID].GetAudioCompressionType() == CT_OPUS ) || if ( ( vecChannels[iCurChanID].GetAudioCompressionType() == CT_OPUS ) ||
( vecChannels[iCurChanID].GetAudioCompressionType() == CT_OPUS64 ) ) ( vecChannels[iCurChanID].GetAudioCompressionType() == CT_OPUS64 ) )
{ {
if ( iCurNumAudChan == 1 ) opus_custom_decode ( CurOpusDecoder,
{ pCurCodedData,
// mono
opus_custom_decode ( OpusDecoderMono[iCurChanID],
&vecbyCodedData[0],
iCeltNumCodedBytes, iCeltNumCodedBytes,
&vecvecsData[i][0], &vecvecsData[i][0],
SYSTEM_FRAME_SIZE_SAMPLES ); SYSTEM_FRAME_SIZE_SAMPLES );
} }
else
{
// stereo
opus_custom_decode ( OpusDecoderStereo[iCurChanID],
&vecbyCodedData[0],
iCeltNumCodedBytes,
&vecvecsData[i][0],
SYSTEM_FRAME_SIZE_SAMPLES );
}
}
}
else
{
// lost packet
if ( ( vecChannels[iCurChanID].GetAudioCompressionType() == CT_OPUS ) ||
( vecChannels[iCurChanID].GetAudioCompressionType() == CT_OPUS64 ) )
{
if ( iCurNumAudChan == 1 )
{
// mono
opus_custom_decode ( OpusDecoderMono[iCurChanID],
nullptr,
iCeltNumCodedBytes,
&vecvecsData[i][0],
SYSTEM_FRAME_SIZE_SAMPLES );
}
else
{
// stereo
opus_custom_decode ( OpusDecoderStereo[iCurChanID],
nullptr,
iCeltNumCodedBytes,
&vecvecsData[i][0],
SYSTEM_FRAME_SIZE_SAMPLES );
}
}
} }
} }
@ -1017,46 +1013,34 @@ JitterMeas.Measure();
iNumClients ); iNumClients );
// get current number of CELT coded bytes // get current number of CELT coded bytes
const int iCeltNumCodedBytes = const int iCeltNumCodedBytes = vecChannels[iCurChanID].GetNetwFrameSize();
vecChannels[iCurChanID].GetNetwFrameSize();
// select the opus encoder
if ( vecChannels[iCurChanID].GetNumAudioChannels() == 1 )
{
CurOpusEncoder = OpusEncoderMono[iCurChanID];
}
else
{
CurOpusEncoder = OpusEncoderStereo[iCurChanID];
}
// OPUS encoding // OPUS encoding
if ( ( vecChannels[iCurChanID].GetAudioCompressionType() == CT_OPUS ) || if ( ( vecChannels[iCurChanID].GetAudioCompressionType() == CT_OPUS ) ||
( vecChannels[iCurChanID].GetAudioCompressionType() == CT_OPUS64 ) ) ( vecChannels[iCurChanID].GetAudioCompressionType() == CT_OPUS64 ) )
{ {
if ( vecChannels[iCurChanID].GetNumAudioChannels() == 1 )
{
// mono:
// TODO find a better place than this: the setting does not change all the time // 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 // so for speed optimization it would be better to set it only if the network
// frame size is changed // frame size is changed
opus_custom_encoder_ctl ( OpusEncoderMono[iCurChanID], opus_custom_encoder_ctl ( CurOpusEncoder,
OPUS_SET_BITRATE ( CalcBitRateBitsPerSecFromCodedBytes ( iCeltNumCodedBytes ) ) ); OPUS_SET_BITRATE ( CalcBitRateBitsPerSecFromCodedBytes ( iCeltNumCodedBytes ) ) );
opus_custom_encode ( OpusEncoderMono[iCurChanID], opus_custom_encode ( CurOpusEncoder,
&vecsSendData[0], &vecsSendData[0],
SYSTEM_FRAME_SIZE_SAMPLES, SYSTEM_FRAME_SIZE_SAMPLES,
&vecbyCodedData[0], &vecbyCodedData[0],
iCeltNumCodedBytes ); iCeltNumCodedBytes );
} }
else
{
// stereo:
// 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
// frame size is changed
opus_custom_encoder_ctl ( OpusEncoderStereo[iCurChanID],
OPUS_SET_BITRATE ( CalcBitRateBitsPerSecFromCodedBytes ( iCeltNumCodedBytes ) ) );
opus_custom_encode ( OpusEncoderStereo[iCurChanID],
&vecsSendData[0],
SYSTEM_FRAME_SIZE_SAMPLES,
&vecbyCodedData[0],
iCeltNumCodedBytes );
}
}
// send separate mix to current clients // send separate mix to current clients
vecChannels[iCurChanID].PrepAndSendPacket ( &Socket, vecChannels[iCurChanID].PrepAndSendPacket ( &Socket,

View file

@ -55,7 +55,7 @@ class CHighPrecisionTimer : public QObject
Q_OBJECT Q_OBJECT
public: public:
CHighPrecisionTimer(); CHighPrecisionTimer ( const bool bNewUseDoubleSystemFrameSize );
void Start(); void Start();
void Stop(); void Stop();
@ -66,6 +66,7 @@ protected:
CVector<int> veciTimeOutIntervals; CVector<int> veciTimeOutIntervals;
int iCurPosInVector; int iCurPosInVector;
int iIntervalCounter; int iIntervalCounter;
bool bUseDoubleSystemFrameSize;
public slots: public slots:
void OnTimer(); void OnTimer();
@ -88,7 +89,7 @@ class CHighPrecisionTimer : public QThread
Q_OBJECT Q_OBJECT
public: public:
CHighPrecisionTimer(); CHighPrecisionTimer ( const bool bUseDoubleSystemFrameSize );
void Start(); void Start();
void Stop(); void Stop();
@ -131,6 +132,7 @@ public:
const QString& strRecordingDirName, const QString& strRecordingDirName,
const bool bNCentServPingServerInList, const bool bNCentServPingServerInList,
const bool bNDisconnectAllClients, const bool bNDisconnectAllClients,
const bool bNUseDoubleSystemFrameSize,
const ELicenceType eNLicenceType ); const ELicenceType eNLicenceType );
void Start(); void Start();
@ -220,6 +222,9 @@ protected:
virtual void customEvent ( QEvent* pEvent ); virtual void customEvent ( QEvent* pEvent );
// if server mode is normal or double system frame size
bool bUseDoubleSystemFrameSize;
// do not use the vector class since CChannel does not have appropriate // do not use the vector class since CChannel does not have appropriate
// copy constructor/operator // copy constructor/operator
CChannel vecChannels[MAX_NUM_CHANNELS]; CChannel vecChannels[MAX_NUM_CHANNELS];
@ -228,6 +233,11 @@ protected:
QMutex Mutex; QMutex Mutex;
// audio encoder/decoder // audio encoder/decoder
OpusCustomMode* Opus64Mode[MAX_NUM_CHANNELS];
OpusCustomEncoder* Opus64EncoderMono[MAX_NUM_CHANNELS];
OpusCustomDecoder* Opus64DecoderMono[MAX_NUM_CHANNELS];
OpusCustomEncoder* Opus64EncoderStereo[MAX_NUM_CHANNELS];
OpusCustomDecoder* Opus64DecoderStereo[MAX_NUM_CHANNELS];
OpusCustomMode* OpusMode[MAX_NUM_CHANNELS]; OpusCustomMode* OpusMode[MAX_NUM_CHANNELS];
OpusCustomEncoder* OpusEncoderMono[MAX_NUM_CHANNELS]; OpusCustomEncoder* OpusEncoderMono[MAX_NUM_CHANNELS];
OpusCustomDecoder* OpusDecoderMono[MAX_NUM_CHANNELS]; OpusCustomDecoder* OpusDecoderMono[MAX_NUM_CHANNELS];