|
|
/*==========================================================================;
* * Copyright (C) 1999 Microsoft Corporation. All Rights Reserved. * * File: dpvacmi.cpp * Content: Definition of object which implements ACM compression provider interface * * History: * Date By Reason * =========== =========== ==================== * 10/27/99 rodtoll created * 12/16/99 rodtoll Bug #123250 - Insert proper names/descriptions for codecs * Codec names now based on resource entries for format and * names are constructed using ACM names + bitrate * 01/20/00 rodtoll Removed dplay reference (DPERR_OUTOFMEMORY) * 03/03/2000 rodtoll Updated to handle alternative gamevoice build. * 03/16/2000 rodtoll Fixed problem w/GameVoice build -- always loaded dvoice provider * 04/21/2000 rodtoll Bug #32889 - Does not run on Win2k on non-admin account * 06/09/00 rmt Updates to split CLSID and allow whistler compat and support external create funcs * 08/28/2000 masonb Voice Merge: Removed OSAL_* and dvosal.h added STR_* and strutils.h * 08/31/2000 rodtoll Whistler Bug #171837, 171838 - Prefix Bug * 04/22/2001 rodtoll MANBUG #50058 DPVOICE: VoicePosition: No sound for couple of seconds when * positioning bars moved. Increased # of frames / buffer value for codecs. * 02/25/2002 rodtoll WINBUG #550063: Potential DOS by forcing server to allocate excessive amounts of memory. * Reduced upper bounds on individual sub-queues to 32 messages from 64. * rodtoll WINBUG #552283: Reduce attack surface / dead code removal * Removed ability to load arbitrary ACM codecs. * ***************************************************************************/
#include "dpvacmpch.h"
#define DPVACM_NUM_DEFAULT_TYPES 4
BYTE abTrueSpeechData[] = { 0x01, 0x00, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
BYTE abGSMData[] = { 0x40, 0x01 };
BYTE abADPCMData[] = { 0xF4, 0x01, 0x07, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xC0, 0x00, 0x40, 0x00, 0xF0, 0x00, 0x00, 0x00, 0xCC, 0x01, 0x30, 0xFF, 0x88, 0x01, 0x18, 0xFF };
VOID *s_pvExtras[DPVACM_NUM_DEFAULT_TYPES] = { &abTrueSpeechData, &abGSMData, &abADPCMData, NULL };
WAVEFORMATEX s_wfxFormats[DPVACM_NUM_DEFAULT_TYPES] = { // Tag, Chan, SamS, Avg, Align, Bits, size
{ 34, 0x01, 8000, 1067, 32, 1, sizeof( abTrueSpeechData ) }, { 49, 0x01, 8000, 1625, 65, 0, sizeof( abGSMData ) }, { 2, 0x01, 8000, 4096, 256, 4, sizeof( abADPCMData ) }, { 1, 0x01, 8000, 8000, 1, 8, 0 } };
DVFULLCOMPRESSIONINFO s_dvInfoDefault[DPVACM_NUM_DEFAULT_TYPES] = { { sizeof( DVFULLCOMPRESSIONINFO ), DPVCTGUID_TRUESPEECH.Data1, DPVCTGUID_TRUESPEECH.Data2, DPVCTGUID_TRUESPEECH.Data3, DPVCTGUID_TRUESPEECH.Data4[0], DPVCTGUID_TRUESPEECH.Data4[1], DPVCTGUID_TRUESPEECH.Data4[2], DPVCTGUID_TRUESPEECH.Data4[3], DPVCTGUID_TRUESPEECH.Data4[4], DPVCTGUID_TRUESPEECH.Data4[5], DPVCTGUID_TRUESPEECH.Data4[6], DPVCTGUID_TRUESPEECH.Data4[7], NULL, NULL, 0, 8536, NULL, 12, 1, 90, 96, 720, 993, 1986, 3972, 32, 22, 10, 1, 0, 0 }, { sizeof( DVFULLCOMPRESSIONINFO ), DPVCTGUID_GSM.Data1, DPVCTGUID_GSM.Data2, DPVCTGUID_GSM.Data3, DPVCTGUID_GSM.Data4[0], DPVCTGUID_GSM.Data4[1], DPVCTGUID_GSM.Data4[2], DPVCTGUID_GSM.Data4[3], DPVCTGUID_GSM.Data4[4], DPVCTGUID_GSM.Data4[5], DPVCTGUID_GSM.Data4[6], DPVCTGUID_GSM.Data4[7], NULL, NULL, 0, 13000, NULL, 13, 1, 80, 130, 640, 882, 1764, 3528, 32, 24, 10, 1, 0, 0 }, { sizeof( DVFULLCOMPRESSIONINFO ), DPVCTGUID_ADPCM.Data1, DPVCTGUID_ADPCM.Data2, DPVCTGUID_ADPCM.Data3, DPVCTGUID_ADPCM.Data4[0], DPVCTGUID_ADPCM.Data4[1], DPVCTGUID_ADPCM.Data4[2], DPVCTGUID_ADPCM.Data4[3], DPVCTGUID_ADPCM.Data4[4], DPVCTGUID_ADPCM.Data4[5], DPVCTGUID_ADPCM.Data4[6], DPVCTGUID_ADPCM.Data4[7], NULL, NULL, 0, 32768, NULL, 15, 1, 63, 256, 500, 690, 1380, 2760, 32, 31, 10, 1, 0, 0 }, { sizeof( DVFULLCOMPRESSIONINFO ), DPVCTGUID_NONE.Data1, DPVCTGUID_NONE.Data2, DPVCTGUID_NONE.Data3, DPVCTGUID_NONE.Data4[0], DPVCTGUID_NONE.Data4[1], DPVCTGUID_NONE.Data4[2], DPVCTGUID_NONE.Data4[3], DPVCTGUID_NONE.Data4[4], DPVCTGUID_NONE.Data4[5], DPVCTGUID_NONE.Data4[6], DPVCTGUID_NONE.Data4[7], NULL, NULL, 0, 64000, NULL, 20, 1, 50, 394, 394, 543, 1086, 2172, 32, 39, 10, 1, 0, 0 } };
const wchar_t * const s_wszInfoNames[DPVACM_NUM_DEFAULT_TYPES] = { L"DSP Group Truespeech(TM) (8.000 kHz, 1 Bit, Mono)", L"GSM 6.10 (8.000 kHz, Mono)", L"Microsoft ADPCM (8.000 kHz, 4 Bit, Mono)", L"PCM (8.000 kHz, 8 Bit, Mono" };
WAVEFORMATEX CDPVACMI::s_wfxInnerFormat= { WAVE_FORMAT_PCM, 1,8000,16000,2,16,0 };
#define MAX_RESOURCE_STRING_LENGTH 200
#undef DPF_MODNAME
#define DPF_MODNAME "CDPVACMI::LoadDefaultTypes"
HRESULT CDPVACMI::LoadDefaultTypes( HINSTANCE hInst ) { HRESULT hr = DV_OK; CompressionNode *pNewNode; CWaveFormat wfxFormat;
for( DWORD dwIndex = 0; dwIndex < DPVACM_NUM_DEFAULT_TYPES; dwIndex++ ) { pNewNode = new CompressionNode;
if( pNewNode == NULL ) { DPFX(DPFPREP, DVF_ERRORLEVEL, "Memory allocation failure" ); return DVERR_OUTOFMEMORY; } pNewNode->pdvfci = new DVFULLCOMPRESSIONINFO;
if( pNewNode->pdvfci == NULL ) { delete pNewNode; DPFX(DPFPREP, DVF_ERRORLEVEL, "Memory allocation failure" ); return DVERR_OUTOFMEMORY; }
// Copy main portion
memcpy( pNewNode->pdvfci, &s_dvInfoDefault[dwIndex], sizeof( DVFULLCOMPRESSIONINFO ) );
// Copy the waveformat
hr = wfxFormat.InitializeCPY( &s_wfxFormats[dwIndex], s_pvExtras[dwIndex] );
if( FAILED( hr ) ) { DPFX(DPFPREP, 0, "Unable to initialize built-in type %d", dwIndex ); CN_FreeItem( pNewNode ); continue; }
pNewNode->pdvfci->lpwfxFormat = wfxFormat.Disconnect();
DNASSERT( pNewNode->pdvfci->lpwfxFormat );
hr = GetCompressionNameAndDescription( hInst, pNewNode->pdvfci );
if( FAILED( hr ) ) { DPFX(DPFPREP, DVF_ERRORLEVEL, "Error building built-in type: %d hr=0x%x", dwIndex, hr ); DPFX(DPFPREP, DVF_ERRORLEVEL, "Type will not be available" ); CN_FreeItem( pNewNode );
continue; } AddEntry( pNewNode ); }
return DV_OK; }
#undef DPF_MODNAME
#define DPF_MODNAME "CDPVACMI::AddEntry"
void CDPVACMI::AddEntry( CompressionNode *pNewNode ) { CompressionNode *pcNode, *pcPrevNode;
pcPrevNode = NULL; pcNode = s_pcnList;
// Run the list and ensure an entry doesn't already exist
// If one does, over-ride it with this new one.
while( pcNode ) { // A node already exists for this type
if( pcNode->pdvfci->guidType == pNewNode->pdvfci->guidType ) { // We need to drop this count because we increment it below.
s_dwNumCompressionTypes--; if( pcPrevNode == NULL ) { s_pcnList = pcNode->pcnNext; } else { pcPrevNode->pcnNext = pcNode->pcnNext; } CN_FreeItem(pcNode); break; }
pcPrevNode = pcNode; pcNode = pcNode->pcnNext; }
pNewNode->pcnNext = s_pcnList; s_pcnList = pNewNode; s_dwNumCompressionTypes++; }
#undef DPF_MODNAME
#define DPF_MODNAME "CDPVACMI::InitCompressionList"
HRESULT CDPVACMI::InitCompressionList( HINSTANCE hInst, const wchar_t *szwRegistryBase ) { HRESULT hr;
hr = IsPCMConverterAvailable();
if( FAILED( hr ) ) { DPFX(DPFPREP, DVF_ERRORLEVEL, "PCM Converter is disabled hr=0x%x, no ACM compression types are available", hr ); return hr; }
hr = LoadDefaultTypes( hInst );
if( FAILED( hr ) ) { DPFX(DPFPREP, DVF_ERRORLEVEL, "Unable to load built-in types from registry." ); return E_FAIL; }
return DV_OK; }
#undef DPF_MODNAME
#define DPF_MODNAME "CDPVACMI::CreateCompressor"
HRESULT CDPVACMI::CreateCompressor( DPVCPIOBJECT *This, LPWAVEFORMATEX lpwfxSrcFormat, GUID guidTargetCT, PDPVCOMPRESSOR *ppCompressor, DWORD dwFlags ) { HRESULT hr;
hr = COM_CoCreateInstance( CLSID_DPVCPACM_CONVERTER, NULL, CLSCTX_INPROC_SERVER, IID_IDPVConverter, (void **) ppCompressor, FALSE );
if( FAILED( hr ) ) { DPFX(DPFPREP, DVF_ERRORLEVEL, "Failed to create converter, hr = 0x%x", hr ); return hr; }
hr = (*ppCompressor)->lpVtbl->InitCompress( (*ppCompressor), lpwfxSrcFormat, guidTargetCT );
if( FAILED( hr ) ) { DPFX(DPFPREP, DVF_ERRORLEVEL, "Failed to init compressor, hr = 0x%x", hr ); (*ppCompressor)->lpVtbl->Release((*ppCompressor)); *ppCompressor = NULL; return hr; }
return DV_OK; }
#undef DPF_MODNAME
#define DPF_MODNAME "CDPVACMI::CreateDeCompressor"
HRESULT CDPVACMI::CreateDeCompressor( DPVCPIOBJECT *This, GUID guidTargetCT, LPWAVEFORMATEX lpwfxSrcFormat, PDPVCOMPRESSOR *ppCompressor, DWORD dwFlags ) { HRESULT hr;
hr = COM_CoCreateInstance( CLSID_DPVCPACM_CONVERTER, NULL, CLSCTX_INPROC_SERVER, IID_IDPVConverter, (void **) ppCompressor, FALSE );
if( FAILED( hr ) ) { DPFX(DPFPREP, DVF_ERRORLEVEL, "Failed to create decompressor, hr = 0x%x", hr ); return hr; }
hr = (*ppCompressor)->lpVtbl->InitDeCompress( (*ppCompressor), guidTargetCT, lpwfxSrcFormat );
if( FAILED( hr ) ) { DPFX(DPFPREP, DVF_ERRORLEVEL, "Failed to init decompressor, hr = 0x%x", hr ); (*ppCompressor)->lpVtbl->Release((*ppCompressor)); *ppCompressor = NULL; return hr; }
return DV_OK; }
// # of chars of extra tacked on by description
// This is equivalent to "XXXXXXX.X kbit/s"
#define DVACMCP_EXTRACHARS 80
#undef DPF_MODNAME
#define DPF_MODNAME "CDPVACMI::GetDriverNameW"
HRESULT CDPVACMI::GetDriverNameW( HACMDRIVERID hadid, wchar_t *szwDriverName ) { ACMDRIVERDETAILSW acDriverDetails; MMRESULT mmr;
memset( &acDriverDetails, 0x00, sizeof( ACMDRIVERDETAILS ) ); acDriverDetails.cbStruct = sizeof( ACMDRIVERDETAILS );
mmr = acmDriverDetailsW( hadid, &acDriverDetails, 0 );
if( mmr != 0 ) { DPFX(DPFPREP, DVF_ERRORLEVEL, "Unable to get driver details mmr=0x%x", mmr ); return DVERR_COMPRESSIONNOTSUPPORTED; }
if( acDriverDetails.fdwSupport & ACMDRIVERDETAILS_SUPPORTF_DISABLED ) { DPFX(DPFPREP, DVF_ERRORLEVEL, "Driver is disabled!" ); return DVERR_COMPRESSIONNOTSUPPORTED; }
wcscpy( szwDriverName, acDriverDetails.szShortName );
return DV_OK; }
#undef DPF_MODNAME
#define DPF_MODNAME "CDPVACMI::GetDriverNameA"
HRESULT CDPVACMI::GetDriverNameA( HACMDRIVERID hadid, wchar_t *szwDriverName ) { ACMDRIVERDETAILSA acDriverDetails; MMRESULT mmr;
memset( &acDriverDetails, 0x00, sizeof( ACMDRIVERDETAILS ) ); acDriverDetails.cbStruct = sizeof( ACMDRIVERDETAILS );
mmr = acmDriverDetailsA( hadid, &acDriverDetails, 0 );
if( mmr != 0 ) { DPFX(DPFPREP, DVF_ERRORLEVEL, "Unable to get driver details mmr=0x%x", mmr ); return DVERR_COMPRESSIONNOTSUPPORTED; }
if( acDriverDetails.fdwSupport & ACMDRIVERDETAILS_SUPPORTF_DISABLED ) { DPFX(DPFPREP, DVF_ERRORLEVEL, "Driver is disabled!" ); return DVERR_COMPRESSIONNOTSUPPORTED; }
if( FAILED(STR_jkAnsiToWide( szwDriverName, acDriverDetails.szShortName, ACMDRIVERDETAILS_SHORTNAME_CHARS+1 )) ) { DPFX(DPFPREP, DVF_ERRORLEVEL, "Unable to convert driver name to UNICODE" ); return DVERR_COMPRESSIONNOTSUPPORTED; }
return DV_OK; }
#undef DPF_MODNAME
#define DPF_MODNAME "CDPVACMI::LoadAndAllocString"
HRESULT CDPVACMI::LoadAndAllocString( HINSTANCE hInstance, UINT uiResourceID, wchar_t **lpswzString ) { int length; HRESULT hr; #ifdef UNICODE
wchar_t wszTmpBuffer[MAX_RESOURCE_STRING_LENGTH]; length = LoadStringW( hInstance, uiResourceID, wszTmpBuffer, MAX_RESOURCE_STRING_LENGTH );
if( length == 0 ) { hr = GetLastError(); DPFX(DPFPREP, DVF_ERRORLEVEL, "Unable to load resource ID %d error 0x%x", uiResourceID, hr ); *lpswzString = NULL;
return hr; } else { *lpswzString = new wchar_t[length+1];
if( *lpswzString == NULL ) { DPFX(DPFPREP, DVF_ERRORLEVEL, "Alloc failure" ); return DVERR_OUTOFMEMORY; }
wcscpy( *lpswzString, wszTmpBuffer );
return DV_OK; } #else
char szTmpBuffer[MAX_RESOURCE_STRING_LENGTH]; length = LoadStringA( hInstance, uiResourceID, szTmpBuffer, MAX_RESOURCE_STRING_LENGTH );
if( length == 0 ) { hr = GetLastError(); DPFX(DPFPREP, DVF_ERRORLEVEL, "Unable to load resource ID %d error 0x%x", uiResourceID, hr ); *lpswzString = NULL;
return hr; } else { *lpswzString = new wchar_t[length+1];
if( *lpswzString == NULL ) { DPFX(DPFPREP, DVF_ERRORLEVEL, "Alloc failure" ); return DVERR_OUTOFMEMORY; }
if( FAILED(STR_jkAnsiToWide( *lpswzString, szTmpBuffer, length+1 )) ) { hr = GetLastError(); DPFX(DPFPREP, DVF_ERRORLEVEL, "Unable to upconvert from ansi to unicode hr=0x%x", hr ); return hr; }
return DV_OK; } #endif // UNICODE
}
#undef DPF_MODNAME
#define DPF_MODNAME "CDPVACMI::GetCompressionNameAndDescription"
HRESULT CDPVACMI::GetCompressionNameAndDescription( HINSTANCE hInst, DVFULLCOMPRESSIONINFO *pdvCompressionInfo ) { MMRESULT mmr; HACMSTREAM has = NULL; HACMDRIVERID acDriverID = NULL; wchar_t szwDriverName[ACMDRIVERDETAILS_SHORTNAME_CHARS+DVACMCP_EXTRACHARS]; wchar_t szExtraCharsBuild[DVACMCP_EXTRACHARS+1]; wchar_t *szwFormat; HRESULT hr; // Description is always NULL
pdvCompressionInfo->lpszDescription = NULL;
// Attempt to open a conversion using the parameters specified.
mmr = acmStreamOpen( &has, NULL, &s_wfxInnerFormat, pdvCompressionInfo->lpwfxFormat, NULL, 0, 0, ACM_STREAMOPENF_NONREALTIME );
if( mmr != 0 ) { DPFX(DPFPREP, DVF_ERRORLEVEL, "Failed testing compression type. mmr=0x%x", mmr ); hr = DVERR_COMPRESSIONNOTSUPPORTED; goto GETINFOERROR; }
mmr = acmDriverID( (HACMOBJ) has, &acDriverID, 0 );
if( mmr != 0 ) { DPFX(DPFPREP, DVF_ERRORLEVEL, "Unable to determine ACM driver for type mmr=0x%x", mmr ); hr = DVERR_COMPRESSIONNOTSUPPORTED; goto GETINFOERROR; }
#ifdef UNICODE
hr = GetDriverNameW( acDriverID, szwDriverName ); #else
hr = GetDriverNameA( acDriverID, szwDriverName ); #endif
if( FAILED( hr ) ) { DPFX(DPFPREP, DVF_ERRORLEVEL, "Failed getting driver name hr=0x%x", hr ); goto GETINFOERROR; }
if( pdvCompressionInfo->dwMaxBitsPerSecond % 1000 == 0 ) { if( FAILED( LoadAndAllocString( hInst, IDS_CODECNAME_KBITSPERSEC, &szwFormat ) ) ) { DPFX(DPFPREP, DVF_ERRORLEVEL, "Unable to load format for name" ); goto GETINFOERROR; } swprintf( szExtraCharsBuild, szwFormat, pdvCompressionInfo->dwMaxBitsPerSecond / 1000 ); delete [] szwFormat; } else { DWORD dwMajor, dwFraction;
dwMajor = pdvCompressionInfo->dwMaxBitsPerSecond / 1000; dwFraction = (pdvCompressionInfo->dwMaxBitsPerSecond % 1000) / 100;
if( (pdvCompressionInfo->dwMaxBitsPerSecond % 1000) > 500 ) { dwFraction++; }
if( dwFraction > 10 ) { dwMajor++; dwFraction -= 10; }
if( FAILED( LoadAndAllocString( hInst, IDS_CODECNAME_KBITSPERSEC_FULL, &szwFormat ) ) ) { DPFX(DPFPREP, DVF_ERRORLEVEL, "Unable to load format for name (full)" ); goto GETINFOERROR; }
swprintf( szExtraCharsBuild, szwFormat, dwMajor, dwFraction ); delete [] szwFormat; }
if( FAILED( LoadAndAllocString( hInst, IDS_CODECNAME_FORMAT, &szwFormat ) ) ) { DPFX(DPFPREP, DVF_ERRORLEVEL, "Unable to load format" ); goto GETINFOERROR; }
pdvCompressionInfo->lpszName = new wchar_t[wcslen(szwDriverName)+wcslen(szwFormat)+wcslen(szExtraCharsBuild)+1];
if( pdvCompressionInfo->lpszName == NULL ) { delete [] szwFormat; DPFX(DPFPREP, DVF_ERRORLEVEL, "Unable to allocate space for compression name" ); hr = DVERR_OUTOFMEMORY; goto GETINFOERROR; }
swprintf( pdvCompressionInfo->lpszName, szwFormat, szwDriverName, szExtraCharsBuild );
acmStreamClose( has, 0 );
if( szwFormat != NULL ) delete [] szwFormat;
return DV_OK;
GETINFOERROR:
if( has != NULL ) { acmStreamClose( has, 0 ); }
return hr; }
|