//========= Copyright Valve Corporation, All rights reserved. ============// // // Purpose: // // $NoKeywords: $ // //=============================================================================// #include "audio/public/ivoicecodec.h" #include #include "tier0/dbg.h" #include "iframeencoder.h" // memdbgon must be the last include file in a .cpp file!!! #include "tier0/memdbgon.h" #ifndef min #define min(a,b) ((a) < (b) ? (a) : (b)) #endif // VoiceCodec_Frame can be used to wrap a frame encoder for the engine. As it gets sound data, it will queue it // until it has enough for a frame, then it will compress it. Same thing for decompression. class VoiceCodec_Frame : public IVoiceCodec { public: enum {MAX_FRAMEBUFFER_SAMPLES=1024}; VoiceCodec_Frame(IFrameEncoder *pEncoder) { m_nEncodeBufferSamples = 0; m_nRawBytes = m_nRawSamples = m_nEncodedBytes = 0; m_pFrameEncoder = pEncoder; } virtual ~VoiceCodec_Frame() { if(m_pFrameEncoder) m_pFrameEncoder->Release(); } virtual bool Init( int quality ) { if(m_pFrameEncoder && m_pFrameEncoder->Init(quality, m_nRawBytes, m_nEncodedBytes)) { m_nRawSamples = m_nRawBytes >> 1; Assert(m_nRawBytes <= MAX_FRAMEBUFFER_SAMPLES && m_nEncodedBytes <= MAX_FRAMEBUFFER_SAMPLES); return true; } else { if(m_pFrameEncoder) m_pFrameEncoder->Release(); m_pFrameEncoder = NULL; return false; } } virtual void Release() { delete this; } virtual int Compress(const char *pUncompressedBytes, int nSamples, char *pCompressed, int maxCompressedBytes, bool bFinal) { if(!m_pFrameEncoder) return 0; const short *pUncompressed = (const short*)pUncompressedBytes; int nCompressedBytes = 0; while((nSamples + m_nEncodeBufferSamples) >= m_nRawSamples && (maxCompressedBytes - nCompressedBytes) >= m_nEncodedBytes) { // Get the data block out. short samples[MAX_FRAMEBUFFER_SAMPLES]; memcpy(samples, m_EncodeBuffer, m_nEncodeBufferSamples*BYTES_PER_SAMPLE); memcpy(&samples[m_nEncodeBufferSamples], pUncompressed, (m_nRawSamples - m_nEncodeBufferSamples) * BYTES_PER_SAMPLE); nSamples -= m_nRawSamples - m_nEncodeBufferSamples; pUncompressed += m_nRawSamples - m_nEncodeBufferSamples; m_nEncodeBufferSamples = 0; // Compress it. m_pFrameEncoder->EncodeFrame((const char*)samples, &pCompressed[nCompressedBytes]); nCompressedBytes += m_nEncodedBytes; } // Store the remaining samples. int nNewSamples = min(nSamples, min(m_nRawSamples-m_nEncodeBufferSamples, m_nRawSamples)); if(nNewSamples) { memcpy(&m_EncodeBuffer[m_nEncodeBufferSamples], &pUncompressed[nSamples - nNewSamples], nNewSamples*BYTES_PER_SAMPLE); m_nEncodeBufferSamples += nNewSamples; } // If it must get the last data, just pad with zeros.. if(bFinal && m_nEncodeBufferSamples && (maxCompressedBytes - nCompressedBytes) >= m_nEncodedBytes) { memset(&m_EncodeBuffer[m_nEncodeBufferSamples], 0, (m_nRawSamples - m_nEncodeBufferSamples) * BYTES_PER_SAMPLE); m_pFrameEncoder->EncodeFrame((const char*)m_EncodeBuffer, &pCompressed[nCompressedBytes]); nCompressedBytes += m_nEncodedBytes; m_nEncodeBufferSamples = 0; } return nCompressedBytes; } virtual int Decompress(const char *pCompressed, int compressedBytes, char *pUncompressed, int maxUncompressedBytes) { if(!m_pFrameEncoder) return 0; Assert((compressedBytes % m_nEncodedBytes) == 0); int nDecompressedBytes = 0; int curCompressedByte = 0; while((compressedBytes - curCompressedByte) >= m_nEncodedBytes && (maxUncompressedBytes - nDecompressedBytes) >= m_nRawBytes) { m_pFrameEncoder->DecodeFrame( pCompressed ? &pCompressed[curCompressedByte] : NULL, &pUncompressed[nDecompressedBytes]); curCompressedByte += m_nEncodedBytes; nDecompressedBytes += m_nRawBytes; } return nDecompressedBytes / BYTES_PER_SAMPLE; } virtual bool ResetState() { if(m_pFrameEncoder) return m_pFrameEncoder->ResetState(); else return false; } public: // The codec encodes and decodes samples in fixed-size blocks, so we queue up uncompressed and decompressed data // until we have blocks large enough to give to the codec. short m_EncodeBuffer[MAX_FRAMEBUFFER_SAMPLES]; int m_nEncodeBufferSamples; IFrameEncoder *m_pFrameEncoder; int m_nRawBytes, m_nRawSamples; int m_nEncodedBytes; }; IVoiceCodec* CreateVoiceCodec_Frame(IFrameEncoder *pEncoder) { return new VoiceCodec_Frame(pEncoder); }