From 37a89ff0733f7c33b10a486e9f07b62dbf8a24ce Mon Sep 17 00:00:00 2001 From: Maarten Lankhorst Date: Mon, 3 Aug 2009 15:59:19 +0200 Subject: [PATCH] msgsm32.acm: Add support for format enumeration. --- dlls/msgsm32.acm/msgsm32.c | 230 ++++++++++++++++++++++++++++++++++++- 1 file changed, 229 insertions(+), 1 deletion(-) diff --git a/dlls/msgsm32.acm/msgsm32.c b/dlls/msgsm32.acm/msgsm32.c index 09dd72d4327..7231fc35597 100644 --- a/dlls/msgsm32.acm/msgsm32.c +++ b/dlls/msgsm32.acm/msgsm32.c @@ -139,6 +139,229 @@ static LRESULT GSM_DriverDetails(PACMDRIVERDETAILSW add) return MMSYSERR_NOERROR; } +/* Validate a WAVEFORMATEX structure */ +static DWORD GSM_FormatValidate(const WAVEFORMATEX *wfx) +{ + if (wfx->nChannels != 1) + return 0; + + switch (wfx->wFormatTag) + { + case WAVE_FORMAT_PCM: + if (wfx->wBitsPerSample != 16) + { + WARN("PCM wBitsPerSample %u\n", wfx->wBitsPerSample); + return 0; + } + if (wfx->nBlockAlign != 2) + { + WARN("PCM nBlockAlign %u\n", wfx->nBlockAlign); + return 0; + } + if (wfx->nAvgBytesPerSec != wfx->nBlockAlign * wfx->nSamplesPerSec) + { + WARN("PCM nAvgBytesPerSec %u/%u\n", + wfx->nAvgBytesPerSec, + wfx->nBlockAlign * wfx->nSamplesPerSec); + return 0; + } + return 1; + case WAVE_FORMAT_GSM610: + if (wfx->cbSize < sizeof(WORD)) + { + WARN("GSM cbSize %u\n", wfx->cbSize); + return 0; + } + if (wfx->wBitsPerSample != 0) + { + WARN("GSM wBitsPerSample %u\n", wfx->wBitsPerSample); + return 0; + } + if (wfx->nBlockAlign != 65) + { + WARN("GSM nBlockAlign %u\n", wfx->nBlockAlign); + return 0; + } + if (((GSM610WAVEFORMAT*)wfx)->wSamplesPerBlock != 320) + { + WARN("GSM wSamplesPerBlock %u\n", + ((GSM610WAVEFORMAT*)wfx)->wSamplesPerBlock); + return 0; + } + if (wfx->nAvgBytesPerSec != wfx->nSamplesPerSec * 65 / 320) + { + WARN("GSM nAvgBytesPerSec %d / %d\n", + wfx->nAvgBytesPerSec, wfx->nSamplesPerSec * 65 / 320); + return 0; + } + return 1; + default: + return 0; + } + return 0; +} + +static const DWORD gsm_rates[] = { 8000, 11025, 22050, 44100, 48000, 96000 }; +#define NUM_RATES (sizeof(gsm_rates)/sizeof(*gsm_rates)) + +/*********************************************************************** + * GSM_FormatTagDetails + * + */ +static LRESULT GSM_FormatTagDetails(PACMFORMATTAGDETAILSW aftd, DWORD dwQuery) +{ + static const WCHAR szPcm[]={'P','C','M',0}; + static const WCHAR szGsm[]={'G','S','M',' ','6','.','1','0',0}; + + switch (dwQuery) + { + case ACM_FORMATTAGDETAILSF_INDEX: + if (aftd->dwFormatTagIndex > 1) return ACMERR_NOTPOSSIBLE; + break; + case ACM_FORMATTAGDETAILSF_LARGESTSIZE: + if (aftd->dwFormatTag == WAVE_FORMAT_UNKNOWN) + { + aftd->dwFormatTagIndex = 1; + break; + } + /* fall thru */ + case ACM_FORMATTAGDETAILSF_FORMATTAG: + switch (aftd->dwFormatTag) + { + case WAVE_FORMAT_PCM: aftd->dwFormatTagIndex = 0; break; + case WAVE_FORMAT_GSM610: aftd->dwFormatTagIndex = 1; break; + default: return ACMERR_NOTPOSSIBLE; + } + break; + default: + WARN("Unsupported query %08x\n", dwQuery); + return MMSYSERR_NOTSUPPORTED; + } + + aftd->fdwSupport = ACMDRIVERDETAILS_SUPPORTF_CODEC; + switch (aftd->dwFormatTagIndex) + { + case 0: + aftd->dwFormatTag = WAVE_FORMAT_PCM; + aftd->cbFormatSize = sizeof(PCMWAVEFORMAT); + aftd->cStandardFormats = NUM_RATES; + lstrcpyW(aftd->szFormatTag, szPcm); + break; + case 1: + aftd->dwFormatTag = WAVE_FORMAT_GSM610; + aftd->cbFormatSize = sizeof(GSM610WAVEFORMAT); + aftd->cStandardFormats = NUM_RATES; + lstrcpyW(aftd->szFormatTag, szGsm); + break; + } + return MMSYSERR_NOERROR; +} + +/*********************************************************************** + * GSM_FormatDetails + * + */ +static LRESULT GSM_FormatDetails(PACMFORMATDETAILSW afd, DWORD dwQuery) +{ + switch (dwQuery) + { + case ACM_FORMATDETAILSF_FORMAT: + if (!GSM_FormatValidate(afd->pwfx)) return ACMERR_NOTPOSSIBLE; + break; + case ACM_FORMATDETAILSF_INDEX: + afd->pwfx->wFormatTag = afd->dwFormatTag; + switch (afd->dwFormatTag) + { + case WAVE_FORMAT_PCM: + if (afd->dwFormatIndex >= NUM_RATES) return ACMERR_NOTPOSSIBLE; + afd->pwfx->nChannels = 1; + afd->pwfx->nSamplesPerSec = gsm_rates[afd->dwFormatIndex]; + afd->pwfx->wBitsPerSample = 16; + afd->pwfx->nBlockAlign = 2; + afd->pwfx->nAvgBytesPerSec = afd->pwfx->nSamplesPerSec * afd->pwfx->nBlockAlign; + break; + case WAVE_FORMAT_GSM610: + if (afd->dwFormatIndex >= NUM_RATES) return ACMERR_NOTPOSSIBLE; + afd->pwfx->nChannels = 1; + afd->pwfx->nSamplesPerSec = gsm_rates[afd->dwFormatIndex]; + afd->pwfx->wBitsPerSample = 0; + afd->pwfx->nBlockAlign = 65; + afd->pwfx->nAvgBytesPerSec = afd->pwfx->nSamplesPerSec * 65 / 320; + afd->pwfx->cbSize = sizeof(WORD); + ((GSM610WAVEFORMAT*)afd->pwfx)->wSamplesPerBlock = 320; + break; + default: + WARN("Unsupported tag %08x\n", afd->dwFormatTag); + return MMSYSERR_INVALPARAM; + } + break; + default: + WARN("Unsupported query %08x\n", dwQuery); + return MMSYSERR_NOTSUPPORTED; + } + afd->fdwSupport = ACMDRIVERDETAILS_SUPPORTF_CODEC; + afd->szFormat[0] = 0; /* let MSACM format this for us... */ + + return MMSYSERR_NOERROR; +} + +/*********************************************************************** + * GSM_FormatSuggest + * + */ +static LRESULT GSM_FormatSuggest(PACMDRVFORMATSUGGEST adfs) +{ + /* some tests ... */ + if (adfs->cbwfxSrc < sizeof(PCMWAVEFORMAT) || + adfs->cbwfxDst < sizeof(PCMWAVEFORMAT) || + !GSM_FormatValidate(adfs->pwfxSrc)) return ACMERR_NOTPOSSIBLE; + /* FIXME: should do those tests against the real size (according to format tag */ + + /* If no suggestion for destination, then copy source value */ + if (!(adfs->fdwSuggest & ACM_FORMATSUGGESTF_NCHANNELS)) + adfs->pwfxDst->nChannels = adfs->pwfxSrc->nChannels; + if (!(adfs->fdwSuggest & ACM_FORMATSUGGESTF_NSAMPLESPERSEC)) + adfs->pwfxDst->nSamplesPerSec = adfs->pwfxSrc->nSamplesPerSec; + + if (!(adfs->fdwSuggest & ACM_FORMATSUGGESTF_WBITSPERSAMPLE)) + { + if (adfs->pwfxSrc->wFormatTag == WAVE_FORMAT_PCM) + adfs->pwfxDst->wBitsPerSample = 0; + else + adfs->pwfxDst->wBitsPerSample = 16; + } + if (!(adfs->fdwSuggest & ACM_FORMATSUGGESTF_WFORMATTAG)) + { + switch (adfs->pwfxSrc->wFormatTag) + { + case WAVE_FORMAT_PCM: adfs->pwfxDst->wFormatTag = WAVE_FORMAT_GSM610; break; + case WAVE_FORMAT_GSM610: adfs->pwfxDst->wFormatTag = WAVE_FORMAT_PCM; break; + } + } + + /* recompute other values */ + switch (adfs->pwfxDst->wFormatTag) + { + case WAVE_FORMAT_PCM: + adfs->pwfxDst->nBlockAlign = 2; + adfs->pwfxDst->nAvgBytesPerSec = adfs->pwfxDst->nSamplesPerSec * 2; + break; + case WAVE_FORMAT_GSM610: + if (adfs->pwfxDst->cbSize < sizeof(WORD)) + return ACMERR_NOTPOSSIBLE; + adfs->pwfxDst->nBlockAlign = 65; + adfs->pwfxDst->nAvgBytesPerSec = adfs->pwfxDst->nSamplesPerSec * 65 / 320; + ((GSM610WAVEFORMAT*)adfs->pwfxDst)->wSamplesPerBlock = 320; + break; + default: + return ACMERR_NOTPOSSIBLE; + } + + /* check if result is ok */ + if (!GSM_FormatValidate(adfs->pwfxDst)) return ACMERR_NOTPOSSIBLE; + return MMSYSERR_NOERROR; +} + /************************************************************************** * GSM_DriverProc [exported] */ @@ -168,10 +391,15 @@ LRESULT CALLBACK GSM_DriverProc(DWORD_PTR dwDevID, HDRVR hDriv, UINT wMsg, case ACMDM_DRIVER_DETAILS: return GSM_DriverDetails((PACMDRIVERDETAILSW)dwParam1); - /* Not implemented yet */ case ACMDM_FORMATTAG_DETAILS: + return GSM_FormatTagDetails((PACMFORMATTAGDETAILSW)dwParam1, dwParam2); + case ACMDM_FORMAT_DETAILS: + return GSM_FormatDetails((PACMFORMATDETAILSW)dwParam1, dwParam2); + case ACMDM_FORMAT_SUGGEST: + return GSM_FormatSuggest((PACMDRVFORMATSUGGEST)dwParam1); + case ACMDM_STREAM_OPEN: case ACMDM_STREAM_CLOSE: case ACMDM_STREAM_SIZE: