Galian
2007-05-22 16:02:18 UTC
Hi all. I need some help with GSM-PCM converter implementation.
This is my code, all ACM functions return MMSYSERR_NOERROR, but data,
that I receive from destination buffer is wrong ( I hear in earphone
only comfort noise, and some sibilant ).It's application under Windows
Mobile 5.0. I don't know what's wrong. If some body can help me, it
will be excellent.
Thanks.
GSMConverter.h
typedef unsigned char u8; /* Exactly one byte (8 bits) */
typedef unsigned short u16; /* Exactly 2 bytes (16 bits) */
typedef unsigned long u32; /* Exactly 4 bytes (32 bits) */
class CGSMConverter
{
public:
enum EConvertDirection { PCM_TO_GSM, GSM_TO_PCM };
CGSMConverter( void );
virtual ~CGSMConverter( void );
AudioError InitConverter( EConvertDirection eDirection );
void TermConverter( void );
// Return number of bytes converted, stored in m_pDestBuffer
u32 Convert( const u8* pData, u32 iDataLength );
inline const u8* GetDestBuffer() { return m_pDestBuffer; }
protected:
HACMSTREAM m_hAcmStream;
WAVEFORMATEX m_PCMStruct;
GSM610WAVEFORMAT m_GSMStruct;
PWAVEFORMATEX m_pSrcFormat;
LPWAVEFORMATEX m_pDstFormat;
private:
u8* m_pSrcBuffer;
u8* m_pDestBuffer;
u32 m_iSrcBufferLength;
u32 m_iDestBufferLength;
};
GSMConverter.cpp
#define PREFERRED_FRAMES_PER_PACKET 4
#define PCM_FRAME_SIZE 320
#define GSM_DOUBLE_FRAME_SIZE 65
#include "StdAfx.h"
#include "GSMConverter.h"
CGSMConverter::CGSMConverter( void )
: m_hAcmStream( NULL )
, m_pSrcFormat( NULL )
, m_pDstFormat( NULL )
, m_pSrcBuffer( NULL )
, m_pDestBuffer( NULL )
, m_iSrcBufferLength( 0 )
, m_iDestBufferLength( 0 )
{
// PCM struct initialization
m_PCMStruct.wFormatTag = WAVE_FORMAT_PCM;
m_PCMStruct.nChannels = 1;
m_PCMStruct.nSamplesPerSec = 8000;
m_PCMStruct.nAvgBytesPerSec = 16000;
m_PCMStruct.nBlockAlign = 2;
m_PCMStruct.wBitsPerSample = 16;
m_PCMStruct.cbSize = 0;
// GSM struct initialization
//m_GSMStruct
m_GSMStruct.wfx.wFormatTag = WAVE_FORMAT_GSM610;
m_GSMStruct.wfx.nChannels = 1;
m_GSMStruct.wfx.nSamplesPerSec = 8000;
m_GSMStruct.wfx.nAvgBytesPerSec = 1625;
m_GSMStruct.wfx.nBlockAlign = 65;
m_GSMStruct.wfx.wBitsPerSample = 0;
m_GSMStruct.wfx.cbSize = 2;
m_GSMStruct.wSamplesPerBlock = 320;
}
CGSMConverter::~CGSMConverter( void )
{
}
AudioError CGSMConverter::InitConverter( EConvertDirection
eDirection )
{
AudioError iInitRes = AudioErrorNone;
if ( PCM_TO_GSM == eDirection )
{
m_iSrcBufferLength = PCM_FRAME_SIZE * PREFERRED_FRAMES_PER_PACKET;
m_iDestBufferLength = GSM_DOUBLE_FRAME_SIZE *
( PREFERRED_FRAMES_PER_PACKET / 2 );
m_pSrcFormat = &m_PCMStruct;
m_pDstFormat = reinterpret_cast< LPWAVEFORMATEX >( &m_GSMStruct );
}
else
{
m_iSrcBufferLength = GSM_DOUBLE_FRAME_SIZE *
( PREFERRED_FRAMES_PER_PACKET / 2 );
m_iDestBufferLength = PCM_FRAME_SIZE * PREFERRED_FRAMES_PER_PACKET;
m_pSrcFormat = reinterpret_cast< LPWAVEFORMATEX >( &m_GSMStruct );
m_pDstFormat = &m_PCMStruct;
}
// Allocating memory for destination and source buffers
m_pSrcBuffer = new u8[ m_iSrcBufferLength ];
m_pDestBuffer = new u8[ m_iDestBufferLength ];
DWORD dwOpenFlags = ACM_STREAMOPENF_NONREALTIME;
MMRESULT openStreamResult = acmStreamOpen(
&m_hAcmStream // stream handle
, NULL // handle to ACM driver
, m_pSrcFormat // source WAVEFORMATEX struct
, m_pDstFormat // destination WAVEFORMATEX struct
, NULL // filter
, NULL // callback
, NULL // instance data
, dwOpenFlags // open flags
);
if ( MMSYSERR_NOERROR != openStreamResult )
{
iInitRes = AudioErrorInitConverter;
}
return iInitRes;
}
u32 CGSMConverter::Convert( const u8* pData, u32 iDataLength )
{
u32 iConvertResult = 0;
DWORD dwConvertFlags = 0;
ACMSTREAMHEADER streamHeader;
memset( &streamHeader, 0, sizeof( ACMSTREAMHEADER ) );
streamHeader.cbStruct = sizeof( ACMSTREAMHEADER );
streamHeader.pbSrc = m_pSrcBuffer;
streamHeader.cbSrcLength = m_iSrcBufferLength;
streamHeader.cbSrcLengthUsed = iDataLength;
streamHeader.dwSrcUser = 0;
streamHeader.pbDst = m_pDestBuffer;
streamHeader.cbDstLength = m_iDestBufferLength;
streamHeader.cbDstLengthUsed = 0;
streamHeader.dwDstUser = 0;
MMRESULT streamPrepareHeader = acmStreamPrepareHeader( m_hAcmStream,
&streamHeader, 0 );
if ( MMSYSERR_NOERROR == streamPrepareHeader )
{
MMRESULT streamConvertRes = acmStreamConvert( m_hAcmStream,
&streamHeader, dwConvertFlags );
if ( MMSYSERR_NOERROR == streamConvertRes )
{
iConvertResult = streamHeader.cbDstLengthUsed;
}
}
if ( streamHeader.fdwStatus & ACMSTREAMHEADER_STATUSF_PREPARED )
{
MMRESULT streamUnprepareHeader =
acmStreamUnprepareHeader( m_hAcmStream, &streamHeader, 0 );
}
return iConvertResult;
}
void CGSMConverter::TermConverter( void )
{
// Releasing memory allocated for destination and source buffers
delete [] m_pSrcBuffer;
delete [] m_pDestBuffer;
// Closing stream
MMRESULT closeStreamResult = acmStreamClose( m_hAcmStream, 0 );
}
This is my code, all ACM functions return MMSYSERR_NOERROR, but data,
that I receive from destination buffer is wrong ( I hear in earphone
only comfort noise, and some sibilant ).It's application under Windows
Mobile 5.0. I don't know what's wrong. If some body can help me, it
will be excellent.
Thanks.
GSMConverter.h
typedef unsigned char u8; /* Exactly one byte (8 bits) */
typedef unsigned short u16; /* Exactly 2 bytes (16 bits) */
typedef unsigned long u32; /* Exactly 4 bytes (32 bits) */
class CGSMConverter
{
public:
enum EConvertDirection { PCM_TO_GSM, GSM_TO_PCM };
CGSMConverter( void );
virtual ~CGSMConverter( void );
AudioError InitConverter( EConvertDirection eDirection );
void TermConverter( void );
// Return number of bytes converted, stored in m_pDestBuffer
u32 Convert( const u8* pData, u32 iDataLength );
inline const u8* GetDestBuffer() { return m_pDestBuffer; }
protected:
HACMSTREAM m_hAcmStream;
WAVEFORMATEX m_PCMStruct;
GSM610WAVEFORMAT m_GSMStruct;
PWAVEFORMATEX m_pSrcFormat;
LPWAVEFORMATEX m_pDstFormat;
private:
u8* m_pSrcBuffer;
u8* m_pDestBuffer;
u32 m_iSrcBufferLength;
u32 m_iDestBufferLength;
};
GSMConverter.cpp
#define PREFERRED_FRAMES_PER_PACKET 4
#define PCM_FRAME_SIZE 320
#define GSM_DOUBLE_FRAME_SIZE 65
#include "StdAfx.h"
#include "GSMConverter.h"
CGSMConverter::CGSMConverter( void )
: m_hAcmStream( NULL )
, m_pSrcFormat( NULL )
, m_pDstFormat( NULL )
, m_pSrcBuffer( NULL )
, m_pDestBuffer( NULL )
, m_iSrcBufferLength( 0 )
, m_iDestBufferLength( 0 )
{
// PCM struct initialization
m_PCMStruct.wFormatTag = WAVE_FORMAT_PCM;
m_PCMStruct.nChannels = 1;
m_PCMStruct.nSamplesPerSec = 8000;
m_PCMStruct.nAvgBytesPerSec = 16000;
m_PCMStruct.nBlockAlign = 2;
m_PCMStruct.wBitsPerSample = 16;
m_PCMStruct.cbSize = 0;
// GSM struct initialization
//m_GSMStruct
m_GSMStruct.wfx.wFormatTag = WAVE_FORMAT_GSM610;
m_GSMStruct.wfx.nChannels = 1;
m_GSMStruct.wfx.nSamplesPerSec = 8000;
m_GSMStruct.wfx.nAvgBytesPerSec = 1625;
m_GSMStruct.wfx.nBlockAlign = 65;
m_GSMStruct.wfx.wBitsPerSample = 0;
m_GSMStruct.wfx.cbSize = 2;
m_GSMStruct.wSamplesPerBlock = 320;
}
CGSMConverter::~CGSMConverter( void )
{
}
AudioError CGSMConverter::InitConverter( EConvertDirection
eDirection )
{
AudioError iInitRes = AudioErrorNone;
if ( PCM_TO_GSM == eDirection )
{
m_iSrcBufferLength = PCM_FRAME_SIZE * PREFERRED_FRAMES_PER_PACKET;
m_iDestBufferLength = GSM_DOUBLE_FRAME_SIZE *
( PREFERRED_FRAMES_PER_PACKET / 2 );
m_pSrcFormat = &m_PCMStruct;
m_pDstFormat = reinterpret_cast< LPWAVEFORMATEX >( &m_GSMStruct );
}
else
{
m_iSrcBufferLength = GSM_DOUBLE_FRAME_SIZE *
( PREFERRED_FRAMES_PER_PACKET / 2 );
m_iDestBufferLength = PCM_FRAME_SIZE * PREFERRED_FRAMES_PER_PACKET;
m_pSrcFormat = reinterpret_cast< LPWAVEFORMATEX >( &m_GSMStruct );
m_pDstFormat = &m_PCMStruct;
}
// Allocating memory for destination and source buffers
m_pSrcBuffer = new u8[ m_iSrcBufferLength ];
m_pDestBuffer = new u8[ m_iDestBufferLength ];
DWORD dwOpenFlags = ACM_STREAMOPENF_NONREALTIME;
MMRESULT openStreamResult = acmStreamOpen(
&m_hAcmStream // stream handle
, NULL // handle to ACM driver
, m_pSrcFormat // source WAVEFORMATEX struct
, m_pDstFormat // destination WAVEFORMATEX struct
, NULL // filter
, NULL // callback
, NULL // instance data
, dwOpenFlags // open flags
);
if ( MMSYSERR_NOERROR != openStreamResult )
{
iInitRes = AudioErrorInitConverter;
}
return iInitRes;
}
u32 CGSMConverter::Convert( const u8* pData, u32 iDataLength )
{
u32 iConvertResult = 0;
DWORD dwConvertFlags = 0;
ACMSTREAMHEADER streamHeader;
memset( &streamHeader, 0, sizeof( ACMSTREAMHEADER ) );
streamHeader.cbStruct = sizeof( ACMSTREAMHEADER );
streamHeader.pbSrc = m_pSrcBuffer;
streamHeader.cbSrcLength = m_iSrcBufferLength;
streamHeader.cbSrcLengthUsed = iDataLength;
streamHeader.dwSrcUser = 0;
streamHeader.pbDst = m_pDestBuffer;
streamHeader.cbDstLength = m_iDestBufferLength;
streamHeader.cbDstLengthUsed = 0;
streamHeader.dwDstUser = 0;
MMRESULT streamPrepareHeader = acmStreamPrepareHeader( m_hAcmStream,
&streamHeader, 0 );
if ( MMSYSERR_NOERROR == streamPrepareHeader )
{
MMRESULT streamConvertRes = acmStreamConvert( m_hAcmStream,
&streamHeader, dwConvertFlags );
if ( MMSYSERR_NOERROR == streamConvertRes )
{
iConvertResult = streamHeader.cbDstLengthUsed;
}
}
if ( streamHeader.fdwStatus & ACMSTREAMHEADER_STATUSF_PREPARED )
{
MMRESULT streamUnprepareHeader =
acmStreamUnprepareHeader( m_hAcmStream, &streamHeader, 0 );
}
return iConvertResult;
}
void CGSMConverter::TermConverter( void )
{
// Releasing memory allocated for destination and source buffers
delete [] m_pSrcBuffer;
delete [] m_pDestBuffer;
// Closing stream
MMRESULT closeStreamResult = acmStreamClose( m_hAcmStream, 0 );
}