Modified source engine (2017) developed by valve and leaked in 2020. Not for commercial purporses
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

185 lines
4.3 KiB

//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
// $NoKeywords: $
//
//=============================================================================//
#include "ivoicecodec.h"
#include "iframeencoder.h"
#include <stdio.h>
#include <opus/opus.h>
#include <opus/opus_custom.h>
// NOTE: This has to be the last file included!
#include "tier0/memdbgon.h"
#include "tier0/dbg.h"
#define CHANNELS 1
struct opus_options
{
int iSampleRate;
int iRawFrameSize;
int iPacketSize;
};
opus_options g_OpusOpts[] =
{
{44100, 256, 120},
{22050, 120, 60},
{22050, 256, 60},
{22050, 512, 64},
};
class VoiceEncoder_Opus : public IFrameEncoder
{
public:
VoiceEncoder_Opus();
virtual ~VoiceEncoder_Opus();
// Interfaces IFrameDecoder
bool Init(int quality, int &rawFrameSize, int &encodedFrameSize);
void Release();
void DecodeFrame(const char *pCompressed, char *pDecompressedBytes);
void EncodeFrame(const char *pUncompressedBytes, char *pCompressed);
bool ResetState();
private:
bool InitStates();
void TermStates();
OpusCustomEncoder *m_EncoderState; // Celt internal encoder state
OpusCustomDecoder *m_DecoderState; // Celt internal decoder state
OpusCustomMode *m_Mode;
int m_iVersion;
};
extern IVoiceCodec* CreateVoiceCodec_Frame(IFrameEncoder *pEncoder);
void* CreateCeltVoiceCodec()
{
IFrameEncoder *pEncoder = new VoiceEncoder_Opus;
return CreateVoiceCodec_Frame( pEncoder );
}
EXPOSE_INTERFACE_FN(CreateCeltVoiceCodec, IVoiceCodec, "vaudio_opus")
//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////
VoiceEncoder_Opus::VoiceEncoder_Opus()
{
m_EncoderState = NULL;
m_DecoderState = NULL;
m_Mode = NULL;
m_iVersion = 0;
}
VoiceEncoder_Opus::~VoiceEncoder_Opus()
{
TermStates();
}
bool VoiceEncoder_Opus::Init( int quality, int &rawFrameSize, int &encodedFrameSize)
{
m_iVersion = quality;
rawFrameSize = g_OpusOpts[m_iVersion].iRawFrameSize * BYTES_PER_SAMPLE;
int iError = 0;
m_Mode = opus_custom_mode_create( g_OpusOpts[m_iVersion].iSampleRate, g_OpusOpts[m_iVersion].iRawFrameSize, &iError );
m_EncoderState = opus_custom_encoder_create( m_Mode, CHANNELS, NULL);
m_DecoderState = opus_custom_decoder_create( m_Mode, CHANNELS, NULL);
if ( !InitStates() )
return false;
encodedFrameSize = g_OpusOpts[m_iVersion].iPacketSize;
return true;
}
void VoiceEncoder_Opus::Release()
{
delete this;
}
void VoiceEncoder_Opus::EncodeFrame(const char *pUncompressedBytes, char *pCompressed)
{
unsigned char output[1024];
opus_custom_encode( m_EncoderState, (opus_int16*)pUncompressedBytes, g_OpusOpts[m_iVersion].iRawFrameSize, output, g_OpusOpts[m_iVersion].iPacketSize );
for ( int i = 0; i < g_OpusOpts[m_iVersion].iPacketSize; i++ )
{
*pCompressed = (char)output[i];
pCompressed++;
}
}
void VoiceEncoder_Opus::DecodeFrame(const char *pCompressed, char *pDecompressedBytes)
{
unsigned char output[1024];
char *out = (char *)pCompressed;
if ( !pCompressed )
{
int decoded = opus_custom_decode( m_DecoderState, NULL, g_OpusOpts[m_iVersion].iPacketSize, (opus_int16 *)pDecompressedBytes, g_OpusOpts[m_iVersion].iRawFrameSize );
return;
}
for ( int i = 0; i < g_OpusOpts[m_iVersion].iPacketSize; i++ )
{
output[i] = ( unsigned char ) ( ( *out < 0 ) ? (*out + 256) : *out );
out++;
}
//celt_decoder_ctl( m_DecoderState, CELT_RESET_STATE_REQUEST, NULL );
int decoded = opus_custom_decode( m_DecoderState, output, g_OpusOpts[m_iVersion].iPacketSize, (opus_int16 *)pDecompressedBytes, g_OpusOpts[m_iVersion].iRawFrameSize );
}
bool VoiceEncoder_Opus::ResetState()
{
opus_custom_encoder_ctl(m_EncoderState, OPUS_RESET_STATE );
opus_custom_decoder_ctl(m_DecoderState, OPUS_RESET_STATE );
return true;
}
bool VoiceEncoder_Opus::InitStates()
{
if ( !m_EncoderState || !m_DecoderState )
return false;
opus_custom_encoder_ctl(m_EncoderState, OPUS_RESET_STATE );
opus_custom_decoder_ctl(m_DecoderState, OPUS_RESET_STATE );
return true;
}
void VoiceEncoder_Opus::TermStates()
{
if( m_EncoderState )
{
opus_custom_encoder_destroy( m_EncoderState );
m_EncoderState = NULL;
}
if( m_DecoderState )
{
opus_custom_decoder_destroy( m_DecoderState );
m_DecoderState = NULL;
}
opus_custom_mode_destroy( m_Mode );
}