support for OPUS codec

This commit is contained in:
Volker Fischer 2013-02-16 18:06:18 +00:00
parent 7bed33dab4
commit 0c4f22eaa2
4 changed files with 206 additions and 39 deletions

View file

@ -97,6 +97,11 @@ QObject::connect( &Protocol,
SIGNAL ( PingReceived ( int ) ), SIGNAL ( PingReceived ( int ) ),
SIGNAL ( PingReceived ( int ) ) ); SIGNAL ( PingReceived ( int ) ) );
// #### COMPATIBILITY OLD VERSION, TO BE REMOVED ####
QObject::connect ( &Protocol,
SIGNAL ( OpusSupported() ),
SIGNAL ( OpusSupported() ) );
QObject::connect ( &Protocol, QObject::connect ( &Protocol,
SIGNAL ( DetectedCLMessage ( CVector<uint8_t>, int ) ), SIGNAL ( DetectedCLMessage ( CVector<uint8_t>, int ) ),
SIGNAL ( DetectedCLMessage ( CVector<uint8_t>, int ) ) ); SIGNAL ( DetectedCLMessage ( CVector<uint8_t>, int ) ) );
@ -141,7 +146,8 @@ void CChannel::SetEnable ( const bool bNEnStat )
} }
} }
void CChannel::SetAudioStreamProperties ( const int iNewNetwFrameSize, void CChannel::SetAudioStreamProperties ( const EAudComprType eNewAudComprType,
const int iNewNetwFrameSize,
const int iNewNetwFrameSizeFact, const int iNewNetwFrameSizeFact,
const int iNewNumAudioChannels ) const int iNewNumAudioChannels )
{ {
@ -149,9 +155,10 @@ void CChannel::SetAudioStreamProperties ( const int iNewNetwFrameSize,
QMutexLocker locker ( &Mutex ); QMutexLocker locker ( &Mutex );
// store new values // store new values
iNumAudioChannels = iNewNumAudioChannels; eAudioCompressionType = eNewAudComprType;
iNetwFrameSize = iNewNetwFrameSize; iNumAudioChannels = iNewNumAudioChannels;
iNetwFrameSizeFact = iNewNetwFrameSizeFact; iNetwFrameSize = iNewNetwFrameSize;
iNetwFrameSizeFact = iNewNetwFrameSizeFact;
// init socket buffer // init socket buffer
SockBuf.Init ( iNetwFrameSize, iCurSockBufNumFrames ); SockBuf.Init ( iNetwFrameSize, iCurSockBufNumFrames );
@ -346,20 +353,30 @@ 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 )
{ {
QMutexLocker locker ( &Mutex ); Mutex.lock();
{
// store received parameters
eAudioCompressionType = NetworkTransportProps.eAudioCodingType;
iNumAudioChannels = NetworkTransportProps.iNumAudioChannels;
iNetwFrameSizeFact = NetworkTransportProps.iBlockSizeFact;
iNetwFrameSize =
NetworkTransportProps.iBaseNetworkPacketSize;
// store received parameters // update socket buffer (the network block size is a multiple of the
iNumAudioChannels = NetworkTransportProps.iNumAudioChannels; // minimum network frame size
iNetwFrameSizeFact = NetworkTransportProps.iBlockSizeFact; SockBuf.Init ( iNetwFrameSize, iCurSockBufNumFrames );
iNetwFrameSize =
NetworkTransportProps.iBaseNetworkPacketSize;
// update socket buffer (the network block size is a multiple of the // init conversion buffer
// minimum network frame size ConvBuf.Init ( iNetwFrameSize * iNetwFrameSizeFact );
SockBuf.Init ( iNetwFrameSize, iCurSockBufNumFrames ); }
Mutex.unlock();
// init conversion buffer // if old CELT codec is used, inform the client that the new OPUS codec
ConvBuf.Init ( iNetwFrameSize * iNetwFrameSizeFact ); // is supported
if ( eAudioCompressionType != CT_OPUS )
{
Protocol.CreateOpusSupportedMes();
}
} }
} }
@ -375,7 +392,7 @@ void CChannel::CreateNetTranspPropsMessFromCurrentSettings()
iNetwFrameSizeFact, iNetwFrameSizeFact,
iNumAudioChannels, iNumAudioChannels,
SYSTEM_SAMPLE_RATE_HZ, SYSTEM_SAMPLE_RATE_HZ,
CT_CELT, // always CELT coding eAudioCompressionType,
0, // version of the codec 0, // version of the codec
0 ); 0 );

View file

@ -110,7 +110,8 @@ Protocol.CreateChanNameMes ( ChInfo.strName );
int GetUploadRateKbps(); int GetUploadRateKbps();
// set/get network out buffer size and size factor // set/get network out buffer size and size factor
void SetAudioStreamProperties ( const int iNewNetwFrameSize, void SetAudioStreamProperties ( const EAudComprType eNewAudComprType,
const int iNewNetwFrameSize,
const int iNewNetwFrameSizeFact, const int iNewNetwFrameSizeFact,
const int iNewNumAudioChannels ); const int iNewNumAudioChannels );
@ -122,6 +123,7 @@ Protocol.CreateChanNameMes ( ChInfo.strName );
int GetNetwFrameSizeFact() const { return iNetwFrameSizeFact; } int GetNetwFrameSizeFact() const { return iNetwFrameSizeFact; }
int GetNetwFrameSize() const { return iNetwFrameSize; } int GetNetwFrameSize() const { return iNetwFrameSize; }
EAudComprType GetAudioCompressionType() { return eAudioCompressionType; }
int GetNumAudioChannels() const { return iNumAudioChannels; } int GetNumAudioChannels() const { return iNumAudioChannels; }
// network protocol interface // network protocol interface
@ -153,10 +155,11 @@ protected:
{ {
// set it to a state were no decoding is ever possible (since we want // set it to a state were no decoding is ever possible (since we want
// only to decode data when a network transport property message is // only to decode data when a network transport property message is
// received with the correct values // received with the correct values)
iNetwFrameSizeFact = FRAME_SIZE_FACTOR_PREFERRED; eAudioCompressionType = CT_NONE;
iNetwFrameSize = CELT_MINIMUM_NUM_BYTES; iNetwFrameSizeFact = FRAME_SIZE_FACTOR_PREFERRED;
iNumAudioChannels = 1; // mono iNetwFrameSize = CELT_MINIMUM_NUM_BYTES;
iNumAudioChannels = 1; // mono
} }
// connection parameters // connection parameters
@ -188,6 +191,7 @@ protected:
int iNetwFrameSizeFact; int iNetwFrameSizeFact;
int iNetwFrameSize; int iNetwFrameSize;
EAudComprType eAudioCompressionType;
int iNumAudioChannels; int iNumAudioChannels;
QMutex Mutex; QMutex Mutex;
@ -212,6 +216,7 @@ signals:
void ConClientListMesReceived ( CVector<CChannelInfo> vecChanInfo ); void ConClientListMesReceived ( CVector<CChannelInfo> vecChanInfo );
void ChanInfoHasChanged(); void ChanInfoHasChanged();
void ReqChanInfo(); void ReqChanInfo();
void OpusSupported();
void ChatTextReceived ( QString strChatText ); void ChatTextReceived ( QString strChatText );
void PingReceived ( int iMs ); void PingReceived ( int iMs );
void ReqNetTranspProps(); void ReqNetTranspProps();

View file

@ -30,6 +30,7 @@ CClient::CClient ( const quint16 iPortNumber ) :
vstrIPAddress ( MAX_NUM_SERVER_ADDR_ITEMS, "" ), vstrIPAddress ( MAX_NUM_SERVER_ADDR_ITEMS, "" ),
ChannelInfo (), ChannelInfo (),
Channel ( false ), /* we need a client channel -> "false" */ Channel ( false ), /* we need a client channel -> "false" */
eAudioCompressionType ( CT_OPUS ),
iCeltNumCodedBytes ( CELT_NUM_BYTES_MONO_NORMAL_QUALITY ), iCeltNumCodedBytes ( CELT_NUM_BYTES_MONO_NORMAL_QUALITY ),
bCeltDoHighQuality ( false ), bCeltDoHighQuality ( false ),
bUseStereo ( false ), bUseStereo ( false ),
@ -75,6 +76,10 @@ CClient::CClient ( const quint16 iPortNumber ) :
1, 1,
&iOpusError ); &iOpusError );
// we require a constant bit rate
opus_encoder_ctl ( OpusEncoderMono,
OPUS_SET_VBR ( 0 ) );
#ifdef USE_LOW_COMPLEXITY_CELT_ENC #ifdef USE_LOW_COMPLEXITY_CELT_ENC
// set encoder low complexity // set encoder low complexity
opus_encoder_ctl ( OpusEncoderMono, opus_encoder_ctl ( OpusEncoderMono,
@ -103,6 +108,10 @@ CClient::CClient ( const quint16 iPortNumber ) :
2, 2,
&iOpusError ); &iOpusError );
// we require a constant bit rate
opus_encoder_ctl ( OpusEncoderStereo,
OPUS_SET_VBR ( 0 ) );
#ifdef USE_LOW_COMPLEXITY_CELT_ENC #ifdef USE_LOW_COMPLEXITY_CELT_ENC
// set encoder low complexity // set encoder low complexity
opus_encoder_ctl ( OpusEncoderStereo, opus_encoder_ctl ( OpusEncoderStereo,
@ -148,6 +157,12 @@ CClient::CClient ( const quint16 iPortNumber ) :
SIGNAL ( ChatTextReceived ( QString ) ), SIGNAL ( ChatTextReceived ( QString ) ),
SIGNAL ( ChatTextReceived ( QString ) ) ); SIGNAL ( ChatTextReceived ( QString ) ) );
// #### COMPATIBILITY OLD VERSION, TO BE REMOVED ####
QObject::connect ( &Channel, SIGNAL ( OpusSupported() ),
this, SLOT ( OnOpusSupported() ) );
QObject::connect ( &ConnLessProtocol, QObject::connect ( &ConnLessProtocol,
SIGNAL ( CLMessReadyForSending ( CHostAddress, CVector<uint8_t> ) ), SIGNAL ( CLMessReadyForSending ( CHostAddress, CVector<uint8_t> ) ),
this, SLOT ( OnSendCLProtMessage ( CHostAddress, CVector<uint8_t> ) ) ); this, SLOT ( OnSendCLProtMessage ( CHostAddress, CVector<uint8_t> ) ) );
@ -334,6 +349,36 @@ void CClient::SetSndCrdPrefFrameSizeFactor ( const int iNewFactor )
} }
} }
// #### COMPATIBILITY OLD VERSION, TO BE REMOVED ####
void CClient::OnOpusSupported()
{
if ( eAudioCompressionType != CT_OPUS )
{
SetAudoCompressiontype ( CT_OPUS );
}
}
// #### COMPATIBILITY OLD VERSION, TO BE REMOVED ####
void CClient::SetAudoCompressiontype ( const EAudComprType eNAudCompressionType )
{
// init with new parameter, if client was running then first
// stop it and restart again after new initialization
const bool bWasRunning = Sound.IsRunning();
if ( bWasRunning )
{
Sound.Stop();
}
// set new parameter
eAudioCompressionType = eNAudCompressionType;
Init();
if ( bWasRunning )
{
Sound.Start();
}
}
void CClient::SetCELTHighQuality ( const bool bNCeltHighQualityFlag ) void CClient::SetCELTHighQuality ( const bool bNCeltHighQualityFlag )
{ {
// init with new parameter, if client was running then first // init with new parameter, if client was running then first
@ -518,6 +563,11 @@ void CClient::OnSndCrdReinitRequest ( int iSndCrdResetType )
void CClient::Start() void CClient::Start()
{ {
// #### COMPATIBILITY OLD VERSION, TO BE REMOVED ####
// our first attempt is always to use the old code
eAudioCompressionType = CT_CELT;
// init object // init object
Init(); Init();
@ -674,6 +724,22 @@ void CClient::Init()
} }
vecCeltData.Init ( iCeltNumCodedBytes ); vecCeltData.Init ( iCeltNumCodedBytes );
// calculate and set the bit rate
const int iCeltBitRateBitsPerSec =
( SYSTEM_SAMPLE_RATE_HZ * iCeltNumCodedBytes * 8 ) /
SYSTEM_FRAME_SIZE_SAMPLES;
if ( bUseStereo )
{
opus_encoder_ctl ( OpusEncoderStereo,
OPUS_SET_BITRATE ( iCeltBitRateBitsPerSec ) );
}
else
{
opus_encoder_ctl ( OpusEncoderMono,
OPUS_SET_BITRATE ( iCeltBitRateBitsPerSec ) );
}
// inits for network and channel // inits for network and channel
vecbyNetwData.Init ( iCeltNumCodedBytes ); vecbyNetwData.Init ( iCeltNumCodedBytes );
if ( bUseStereo ) if ( bUseStereo )
@ -681,7 +747,8 @@ void CClient::Init()
vecsNetwork.Init ( iStereoBlockSizeSam ); vecsNetwork.Init ( iStereoBlockSizeSam );
// set the channel network properties // set the channel network properties
Channel.SetAudioStreamProperties ( iCeltNumCodedBytes, Channel.SetAudioStreamProperties ( eAudioCompressionType,
iCeltNumCodedBytes,
iSndCrdFrameSizeFactor, iSndCrdFrameSizeFactor,
2 ); 2 );
} }
@ -690,7 +757,8 @@ void CClient::Init()
vecsNetwork.Init ( iMonoBlockSizeSam ); vecsNetwork.Init ( iMonoBlockSizeSam );
// set the channel network properties // set the channel network properties
Channel.SetAudioStreamProperties ( iCeltNumCodedBytes, Channel.SetAudioStreamProperties ( eAudioCompressionType,
iCeltNumCodedBytes,
iSndCrdFrameSizeFactor, iSndCrdFrameSizeFactor,
1 ); 1 );
} }
@ -892,21 +960,43 @@ void CClient::ProcessAudioDataIntern ( CVector<int16_t>& vecsStereoSndCrd )
{ {
if ( bUseStereo ) if ( bUseStereo )
{ {
// encode current audio frame with CELT encoder // encode current audio frame
cc6_celt_encode ( CeltEncoderStereo, if ( eAudioCompressionType == CT_CELT )
{
cc6_celt_encode ( CeltEncoderStereo,
&vecsNetwork[i * 2 * SYSTEM_FRAME_SIZE_SAMPLES],
NULL,
&vecCeltData[0],
iCeltNumCodedBytes );
}
else
{
opus_encode ( OpusEncoderStereo,
&vecsNetwork[i * 2 * SYSTEM_FRAME_SIZE_SAMPLES], &vecsNetwork[i * 2 * SYSTEM_FRAME_SIZE_SAMPLES],
NULL, SYSTEM_FRAME_SIZE_SAMPLES,
&vecCeltData[0], &vecCeltData[0],
iCeltNumCodedBytes ); iCeltNumCodedBytes );
}
} }
else else
{ {
// encode current audio frame with CELT encoder // encode current audio frame
cc6_celt_encode ( CeltEncoderMono, if ( eAudioCompressionType == CT_CELT )
{
cc6_celt_encode ( CeltEncoderMono,
&vecsNetwork[i * SYSTEM_FRAME_SIZE_SAMPLES],
NULL,
&vecCeltData[0],
iCeltNumCodedBytes );
}
else
{
opus_encode ( OpusEncoderMono,
&vecsNetwork[i * SYSTEM_FRAME_SIZE_SAMPLES], &vecsNetwork[i * SYSTEM_FRAME_SIZE_SAMPLES],
NULL, SYSTEM_FRAME_SIZE_SAMPLES,
&vecCeltData[0], &vecCeltData[0],
iCeltNumCodedBytes ); iCeltNumCodedBytes );
}
} }
// send coded audio through the network // send coded audio through the network
@ -936,17 +1026,41 @@ void CClient::ProcessAudioDataIntern ( CVector<int16_t>& vecsStereoSndCrd )
{ {
if ( bUseStereo ) if ( bUseStereo )
{ {
cc6_celt_decode ( CeltDecoderStereo, if ( eAudioCompressionType == CT_CELT )
{
cc6_celt_decode ( CeltDecoderStereo,
&vecbyNetwData[0],
iCeltNumCodedBytes,
&vecsStereoSndCrd[i * 2 * SYSTEM_FRAME_SIZE_SAMPLES] );
}
else
{
opus_decode ( OpusDecoderStereo,
&vecbyNetwData[0], &vecbyNetwData[0],
iCeltNumCodedBytes, iCeltNumCodedBytes,
&vecsStereoSndCrd[i * 2 * SYSTEM_FRAME_SIZE_SAMPLES] ); &vecsStereoSndCrd[i * 2 * SYSTEM_FRAME_SIZE_SAMPLES],
SYSTEM_FRAME_SIZE_SAMPLES,
0 );
}
} }
else else
{ {
cc6_celt_decode ( CeltDecoderMono, if ( eAudioCompressionType == CT_CELT )
{
cc6_celt_decode ( CeltDecoderMono,
&vecbyNetwData[0],
iCeltNumCodedBytes,
&vecsAudioSndCrdMono[i * SYSTEM_FRAME_SIZE_SAMPLES] );
}
else
{
opus_decode ( OpusDecoderMono,
&vecbyNetwData[0], &vecbyNetwData[0],
iCeltNumCodedBytes, iCeltNumCodedBytes,
&vecsAudioSndCrdMono[i * SYSTEM_FRAME_SIZE_SAMPLES] ); &vecsAudioSndCrdMono[i * SYSTEM_FRAME_SIZE_SAMPLES],
SYSTEM_FRAME_SIZE_SAMPLES,
0 );
}
} }
} }
else else
@ -954,17 +1068,41 @@ void CClient::ProcessAudioDataIntern ( CVector<int16_t>& vecsStereoSndCrd )
// lost packet // lost packet
if ( bUseStereo ) if ( bUseStereo )
{ {
cc6_celt_decode ( CeltDecoderStereo, if ( eAudioCompressionType == CT_CELT )
{
cc6_celt_decode ( CeltDecoderStereo,
NULL,
0,
&vecsStereoSndCrd[i * 2 * SYSTEM_FRAME_SIZE_SAMPLES] );
}
else
{
opus_decode ( OpusDecoderStereo,
NULL, NULL,
0, iCeltNumCodedBytes,
&vecsStereoSndCrd[i * 2 * SYSTEM_FRAME_SIZE_SAMPLES] ); &vecsStereoSndCrd[i * 2 * SYSTEM_FRAME_SIZE_SAMPLES],
SYSTEM_FRAME_SIZE_SAMPLES,
0 );
}
} }
else else
{ {
cc6_celt_decode ( CeltDecoderMono, if ( eAudioCompressionType == CT_CELT )
{
cc6_celt_decode ( CeltDecoderMono,
NULL,
0,
&vecsAudioSndCrdMono[i * SYSTEM_FRAME_SIZE_SAMPLES] );
}
else
{
opus_decode ( OpusDecoderMono,
NULL, NULL,
0, iCeltNumCodedBytes,
&vecsAudioSndCrdMono[i * SYSTEM_FRAME_SIZE_SAMPLES] ); &vecsAudioSndCrdMono[i * SYSTEM_FRAME_SIZE_SAMPLES],
SYSTEM_FRAME_SIZE_SAMPLES,
0 );
}
} }
} }
} }

View file

@ -261,6 +261,9 @@ protected:
int EvaluatePingMessage ( const int iMs ); int EvaluatePingMessage ( const int iMs );
void CreateServerJitterBufferMessage(); void CreateServerJitterBufferMessage();
// #### COMPATIBILITY OLD VERSION, TO BE REMOVED ####
void SetAudoCompressiontype ( const EAudComprType eNAudCompressionType );
// only one channel is needed for client application // only one channel is needed for client application
CChannel Channel; CChannel Channel;
CProtocol ConnLessProtocol; CProtocol ConnLessProtocol;
@ -276,6 +279,7 @@ protected:
OpusDecoder* OpusDecoderMono; OpusDecoder* OpusDecoderMono;
OpusEncoder* OpusEncoderStereo; OpusEncoder* OpusEncoderStereo;
OpusDecoder* OpusDecoderStereo; OpusDecoder* OpusDecoderStereo;
EAudComprType eAudioCompressionType;
int iCeltNumCodedBytes; int iCeltNumCodedBytes;
bool bCeltDoHighQuality; bool bCeltDoHighQuality;
bool bUseStereo; bool bUseStereo;
@ -342,6 +346,9 @@ public slots:
void OnSndCrdReinitRequest ( int iSndCrdResetType ); void OnSndCrdReinitRequest ( int iSndCrdResetType );
// #### COMPATIBILITY OLD VERSION, TO BE REMOVED ####
void OnOpusSupported();
signals: signals:
void ConClientListNameMesReceived ( CVector<CChannelInfo> vecChanInfo ); void ConClientListNameMesReceived ( CVector<CChannelInfo> vecChanInfo );
void ConClientListMesReceived ( CVector<CChannelInfo> vecChanInfo ); void ConClientListMesReceived ( CVector<CChannelInfo> vecChanInfo );