2 * GSM 06.10 codec handling
3 * Copyright (C) 2009 Maarten Lankhorst
6 * Copyright (C) 2002 Eric Pouech
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
10 * License as published by the Free Software Foundation; either
11 * version 2.1 of the License, or (at your option) any later version.
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Lesser General Public License for more details.
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with this library; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
38 #include "wine/debug.h"
40 WINE_DEFAULT_DEBUG_CHANNEL(gsm
);
43 /***********************************************************************
47 static LRESULT
GSM_DriverDetails(PACMDRIVERDETAILSW add
)
49 add
->fccType
= ACMDRIVERDETAILS_FCCTYPE_AUDIOCODEC
;
50 add
->fccComp
= ACMDRIVERDETAILS_FCCCOMP_UNDEFINED
;
51 /* Details found from probing native msgsm32.acm */
52 add
->wMid
= MM_MICROSOFT
;
53 add
->wPid
= MM_MSFT_ACM_GSM610
;
54 add
->vdwACM
= 0x3320000;
55 add
->vdwDriver
= 0x4000000;
56 add
->fdwSupport
= ACMDRIVERDETAILS_SUPPORTF_CODEC
;
60 MultiByteToWideChar( CP_ACP
, 0, "Microsoft GSM 6.10", -1,
61 add
->szShortName
, ARRAY_SIZE( add
->szShortName
));
62 MultiByteToWideChar( CP_ACP
, 0, "Wine GSM 6.10 libgsm codec", -1,
63 add
->szLongName
, ARRAY_SIZE( add
->szLongName
));
64 MultiByteToWideChar( CP_ACP
, 0, "Brought to you by the Wine team...", -1,
65 add
->szCopyright
, ARRAY_SIZE( add
->szCopyright
));
66 MultiByteToWideChar( CP_ACP
, 0, "Refer to LICENSE file", -1,
67 add
->szLicensing
, ARRAY_SIZE( add
->szLicensing
));
68 add
->szFeatures
[0] = 0;
69 return MMSYSERR_NOERROR
;
72 /* Validate a WAVEFORMATEX structure */
73 static BOOL
GSM_FormatValidate(const WAVEFORMATEX
*wfx
)
75 if (wfx
->nChannels
!= 1)
78 switch (wfx
->wFormatTag
)
81 if (wfx
->wBitsPerSample
!= 16)
83 WARN("PCM wBitsPerSample %u\n", wfx
->wBitsPerSample
);
86 if (wfx
->nBlockAlign
!= 2)
88 WARN("PCM nBlockAlign %u\n", wfx
->nBlockAlign
);
91 if (wfx
->nAvgBytesPerSec
!= wfx
->nBlockAlign
* wfx
->nSamplesPerSec
)
93 WARN("PCM nAvgBytesPerSec %lu/%lu\n",
95 wfx
->nBlockAlign
* wfx
->nSamplesPerSec
);
99 case WAVE_FORMAT_GSM610
:
100 if (wfx
->cbSize
< sizeof(WORD
))
102 WARN("GSM cbSize %u\n", wfx
->cbSize
);
105 if (wfx
->wBitsPerSample
!= 0)
107 WARN("GSM wBitsPerSample %u\n", wfx
->wBitsPerSample
);
110 if (wfx
->nBlockAlign
!= 65)
112 WARN("GSM nBlockAlign %u\n", wfx
->nBlockAlign
);
115 if (((const GSM610WAVEFORMAT
*)wfx
)->wSamplesPerBlock
!= 320)
117 WARN("GSM wSamplesPerBlock %u\n",
118 ((const GSM610WAVEFORMAT
*)wfx
)->wSamplesPerBlock
);
121 if (wfx
->nAvgBytesPerSec
!= wfx
->nSamplesPerSec
* 65 / 320)
123 WARN("GSM nAvgBytesPerSec %ld / %ld\n",
124 wfx
->nAvgBytesPerSec
, wfx
->nSamplesPerSec
* 65 / 320);
134 static const DWORD gsm_rates
[] = { 8000, 11025, 22050, 44100, 48000, 96000 };
136 /***********************************************************************
137 * GSM_FormatTagDetails
140 static LRESULT
GSM_FormatTagDetails(PACMFORMATTAGDETAILSW aftd
, DWORD dwQuery
)
142 static const WCHAR szPcm
[]={'P','C','M',0};
143 static const WCHAR szGsm
[]={'G','S','M',' ','6','.','1','0',0};
147 case ACM_FORMATTAGDETAILSF_INDEX
:
148 if (aftd
->dwFormatTagIndex
> 1) return ACMERR_NOTPOSSIBLE
;
150 case ACM_FORMATTAGDETAILSF_LARGESTSIZE
:
151 if (aftd
->dwFormatTag
== WAVE_FORMAT_UNKNOWN
)
153 aftd
->dwFormatTagIndex
= 1;
157 case ACM_FORMATTAGDETAILSF_FORMATTAG
:
158 switch (aftd
->dwFormatTag
)
160 case WAVE_FORMAT_PCM
: aftd
->dwFormatTagIndex
= 0; break;
161 case WAVE_FORMAT_GSM610
: aftd
->dwFormatTagIndex
= 1; break;
162 default: return ACMERR_NOTPOSSIBLE
;
166 WARN("Unsupported query %08lx\n", dwQuery
);
167 return MMSYSERR_NOTSUPPORTED
;
170 aftd
->fdwSupport
= ACMDRIVERDETAILS_SUPPORTF_CODEC
;
171 switch (aftd
->dwFormatTagIndex
)
174 aftd
->dwFormatTag
= WAVE_FORMAT_PCM
;
175 aftd
->cbFormatSize
= sizeof(PCMWAVEFORMAT
);
176 aftd
->cStandardFormats
= ARRAY_SIZE(gsm_rates
);
177 lstrcpyW(aftd
->szFormatTag
, szPcm
);
180 aftd
->dwFormatTag
= WAVE_FORMAT_GSM610
;
181 aftd
->cbFormatSize
= sizeof(GSM610WAVEFORMAT
);
182 aftd
->cStandardFormats
= ARRAY_SIZE(gsm_rates
);
183 lstrcpyW(aftd
->szFormatTag
, szGsm
);
186 return MMSYSERR_NOERROR
;
189 /***********************************************************************
193 static LRESULT
GSM_FormatDetails(PACMFORMATDETAILSW afd
, DWORD dwQuery
)
197 case ACM_FORMATDETAILSF_FORMAT
:
198 if (!GSM_FormatValidate(afd
->pwfx
)) return ACMERR_NOTPOSSIBLE
;
200 case ACM_FORMATDETAILSF_INDEX
:
201 afd
->pwfx
->wFormatTag
= afd
->dwFormatTag
;
202 switch (afd
->dwFormatTag
)
204 case WAVE_FORMAT_PCM
:
205 if (afd
->dwFormatIndex
>= ARRAY_SIZE(gsm_rates
)) return ACMERR_NOTPOSSIBLE
;
206 afd
->pwfx
->nChannels
= 1;
207 afd
->pwfx
->nSamplesPerSec
= gsm_rates
[afd
->dwFormatIndex
];
208 afd
->pwfx
->wBitsPerSample
= 16;
209 afd
->pwfx
->nBlockAlign
= 2;
210 afd
->pwfx
->nAvgBytesPerSec
= afd
->pwfx
->nSamplesPerSec
* afd
->pwfx
->nBlockAlign
;
212 case WAVE_FORMAT_GSM610
:
213 if (afd
->dwFormatIndex
>= ARRAY_SIZE(gsm_rates
)) return ACMERR_NOTPOSSIBLE
;
214 afd
->pwfx
->nChannels
= 1;
215 afd
->pwfx
->nSamplesPerSec
= gsm_rates
[afd
->dwFormatIndex
];
216 afd
->pwfx
->wBitsPerSample
= 0;
217 afd
->pwfx
->nBlockAlign
= 65;
218 afd
->pwfx
->nAvgBytesPerSec
= afd
->pwfx
->nSamplesPerSec
* 65 / 320;
219 afd
->pwfx
->cbSize
= sizeof(WORD
);
220 ((GSM610WAVEFORMAT
*)afd
->pwfx
)->wSamplesPerBlock
= 320;
223 WARN("Unsupported tag %08lx\n", afd
->dwFormatTag
);
224 return MMSYSERR_INVALPARAM
;
228 WARN("Unsupported query %08lx\n", dwQuery
);
229 return MMSYSERR_NOTSUPPORTED
;
231 afd
->fdwSupport
= ACMDRIVERDETAILS_SUPPORTF_CODEC
;
232 afd
->szFormat
[0] = 0; /* let MSACM format this for us... */
234 return MMSYSERR_NOERROR
;
237 /***********************************************************************
241 static LRESULT
GSM_FormatSuggest(PACMDRVFORMATSUGGEST adfs
)
244 if (adfs
->cbwfxSrc
< sizeof(PCMWAVEFORMAT
) ||
245 adfs
->cbwfxDst
< sizeof(PCMWAVEFORMAT
) ||
246 !GSM_FormatValidate(adfs
->pwfxSrc
)) return ACMERR_NOTPOSSIBLE
;
247 /* FIXME: should do those tests against the real size (according to format tag */
249 /* If no suggestion for destination, then copy source value */
250 if (!(adfs
->fdwSuggest
& ACM_FORMATSUGGESTF_NCHANNELS
))
251 adfs
->pwfxDst
->nChannels
= adfs
->pwfxSrc
->nChannels
;
252 if (!(adfs
->fdwSuggest
& ACM_FORMATSUGGESTF_NSAMPLESPERSEC
))
253 adfs
->pwfxDst
->nSamplesPerSec
= adfs
->pwfxSrc
->nSamplesPerSec
;
255 if (!(adfs
->fdwSuggest
& ACM_FORMATSUGGESTF_WBITSPERSAMPLE
))
257 if (adfs
->pwfxSrc
->wFormatTag
== WAVE_FORMAT_PCM
)
258 adfs
->pwfxDst
->wBitsPerSample
= 0;
260 adfs
->pwfxDst
->wBitsPerSample
= 16;
262 if (!(adfs
->fdwSuggest
& ACM_FORMATSUGGESTF_WFORMATTAG
))
264 switch (adfs
->pwfxSrc
->wFormatTag
)
266 case WAVE_FORMAT_PCM
: adfs
->pwfxDst
->wFormatTag
= WAVE_FORMAT_GSM610
; break;
267 case WAVE_FORMAT_GSM610
: adfs
->pwfxDst
->wFormatTag
= WAVE_FORMAT_PCM
; break;
271 /* recompute other values */
272 switch (adfs
->pwfxDst
->wFormatTag
)
274 case WAVE_FORMAT_PCM
:
275 adfs
->pwfxDst
->nBlockAlign
= 2;
276 adfs
->pwfxDst
->nAvgBytesPerSec
= adfs
->pwfxDst
->nSamplesPerSec
* 2;
278 case WAVE_FORMAT_GSM610
:
279 if (adfs
->pwfxDst
->cbSize
< sizeof(WORD
))
280 return ACMERR_NOTPOSSIBLE
;
281 adfs
->pwfxDst
->nBlockAlign
= 65;
282 adfs
->pwfxDst
->nAvgBytesPerSec
= adfs
->pwfxDst
->nSamplesPerSec
* 65 / 320;
283 ((GSM610WAVEFORMAT
*)adfs
->pwfxDst
)->wSamplesPerBlock
= 320;
286 return ACMERR_NOTPOSSIBLE
;
289 /* check if result is ok */
290 if (!GSM_FormatValidate(adfs
->pwfxDst
)) return ACMERR_NOTPOSSIBLE
;
291 return MMSYSERR_NOERROR
;
294 /***********************************************************************
298 static LRESULT
GSM_StreamOpen(PACMDRVSTREAMINSTANCE adsi
)
302 if (adsi
->pwfxSrc
->wFormatTag
!= WAVE_FORMAT_GSM610
&& adsi
->pwfxDst
->wFormatTag
!= WAVE_FORMAT_GSM610
)
303 return MMSYSERR_NOTSUPPORTED
;
305 if (!GSM_FormatValidate(adsi
->pwfxSrc
) || !GSM_FormatValidate(adsi
->pwfxDst
))
306 return MMSYSERR_NOTSUPPORTED
;
308 if (adsi
->pwfxSrc
->nSamplesPerSec
!= adsi
->pwfxDst
->nSamplesPerSec
)
309 return MMSYSERR_NOTSUPPORTED
;
313 return MMSYSERR_NOMEM
;
314 if (gsm_option(r
, GSM_OPT_WAV49
, &used
) < 0)
316 FIXME("Your libgsm library doesn't support GSM_OPT_WAV49\n");
317 FIXME("Please recompile libgsm with WAV49 support\n");
319 return MMSYSERR_NOTSUPPORTED
;
321 adsi
->dwDriver
= (DWORD_PTR
)r
;
322 return MMSYSERR_NOERROR
;
325 /***********************************************************************
329 static LRESULT
GSM_StreamClose(PACMDRVSTREAMINSTANCE adsi
)
331 gsm_destroy((gsm
)adsi
->dwDriver
);
332 return MMSYSERR_NOERROR
;
335 /***********************************************************************
339 static LRESULT
GSM_StreamSize(const ACMDRVSTREAMINSTANCE
*adsi
, PACMDRVSTREAMSIZE adss
)
341 switch (adss
->fdwSize
)
343 case ACM_STREAMSIZEF_DESTINATION
:
344 /* cbDstLength => cbSrcLength */
345 if (adsi
->pwfxSrc
->wFormatTag
== WAVE_FORMAT_PCM
&&
346 adsi
->pwfxDst
->wFormatTag
== WAVE_FORMAT_GSM610
)
348 adss
->cbSrcLength
= adss
->cbDstLength
/ 65 * 640;
350 else if (adsi
->pwfxSrc
->wFormatTag
== WAVE_FORMAT_GSM610
&&
351 adsi
->pwfxDst
->wFormatTag
== WAVE_FORMAT_PCM
)
353 adss
->cbSrcLength
= adss
->cbDstLength
/ 640 * 65;
357 return MMSYSERR_NOTSUPPORTED
;
359 return MMSYSERR_NOERROR
;
360 case ACM_STREAMSIZEF_SOURCE
:
361 /* cbSrcLength => cbDstLength */
362 if (adsi
->pwfxSrc
->wFormatTag
== WAVE_FORMAT_PCM
&&
363 adsi
->pwfxDst
->wFormatTag
== WAVE_FORMAT_GSM610
)
365 adss
->cbDstLength
= (adss
->cbSrcLength
+ 639) / 640 * 65;
367 else if (adsi
->pwfxSrc
->wFormatTag
== WAVE_FORMAT_GSM610
&&
368 adsi
->pwfxDst
->wFormatTag
== WAVE_FORMAT_PCM
)
370 adss
->cbDstLength
= adss
->cbSrcLength
/ 65 * 640;
374 return MMSYSERR_NOTSUPPORTED
;
376 return MMSYSERR_NOERROR
;
378 WARN("Unsupported query %08lx\n", adss
->fdwSize
);
379 return MMSYSERR_NOTSUPPORTED
;
383 /***********************************************************************
387 static LRESULT
GSM_StreamConvert(PACMDRVSTREAMINSTANCE adsi
, PACMDRVSTREAMHEADER adsh
)
389 gsm r
= (gsm
)adsi
->dwDriver
;
392 BYTE
*src
= adsh
->pbSrc
;
393 BYTE
*dst
= adsh
->pbDst
;
396 if (adsh
->fdwConvert
&
397 ~(ACM_STREAMCONVERTF_BLOCKALIGN
|
398 ACM_STREAMCONVERTF_END
|
399 ACM_STREAMCONVERTF_START
))
401 FIXME("Unsupported fdwConvert (%08lx), ignoring it\n", adsh
->fdwConvert
);
404 /* Reset the index to 0, just to be sure */
405 gsm_option(r
, GSM_OPT_FRAME_INDEX
, &odd
);
407 /* The native ms codec writes 65 bytes, and this requires 2 libgsm calls.
408 * First 32 bytes are written, or 33 bytes read
409 * Second 33 bytes are written, or 32 bytes read
413 if (adsi
->pwfxSrc
->wFormatTag
== WAVE_FORMAT_GSM610
)
415 if (adsh
->cbSrcLength
/ 65 * 640 > adsh
->cbDstLength
)
417 return ACMERR_NOTPOSSIBLE
;
420 while (nsrc
+ 65 <= adsh
->cbSrcLength
)
423 if (gsm_decode(r
, src
+ nsrc
, (gsm_signal
*)(dst
+ ndst
)) < 0)
424 FIXME("Couldn't decode data\n");
428 if (gsm_decode(r
, src
+ nsrc
, (gsm_signal
*)(dst
+ ndst
)) < 0)
429 FIXME("Couldn't decode data\n");
436 /* Testing a little seems to reveal that despite being able to fit
437 * inside the buffer if ACM_STREAMCONVERTF_BLOCKALIGN is set
440 if ((adsh
->cbSrcLength
+ 639) / 640 * 65 > adsh
->cbDstLength
)
442 return ACMERR_NOTPOSSIBLE
;
445 /* The packing algorithm writes 32 bytes, then 33 bytes,
446 * and it seems to pad to align to 65 bytes always
447 * adding extra data where necessary
449 while (nsrc
+ 640 <= adsh
->cbSrcLength
)
452 gsm_encode(r
, (gsm_signal
*)(src
+nsrc
), dst
+ndst
);
455 gsm_encode(r
, (gsm_signal
*)(src
+nsrc
), dst
+ndst
);
460 /* If ACM_STREAMCONVERTF_BLOCKALIGN isn't set pad with zeros */
461 if (!(adsh
->fdwConvert
& ACM_STREAMCONVERTF_BLOCKALIGN
) &&
462 nsrc
< adsh
->cbSrcLength
)
465 int todo
= adsh
->cbSrcLength
- nsrc
;
469 gsm_encode(r
, (gsm_signal
*)(src
+nsrc
), dst
+ndst
);
474 memcpy(emptiness
, src
+nsrc
, todo
);
475 memset(emptiness
+ todo
, 0, 320 - todo
);
476 gsm_encode(r
, (gsm_signal
*)emptiness
, dst
+ndst
);
481 memcpy(emptiness
, src
+nsrc
, todo
);
482 memset(emptiness
+ todo
, 0, 320 - todo
);
483 gsm_encode(r
, (gsm_signal
*)emptiness
, dst
+ndst
);
486 memset(emptiness
, 0, todo
);
487 gsm_encode(r
, (gsm_signal
*)emptiness
, dst
+ndst
);
490 nsrc
= adsh
->cbSrcLength
;
494 adsh
->cbSrcLengthUsed
= nsrc
;
495 adsh
->cbDstLengthUsed
= ndst
;
496 TRACE("%ld(%ld) -> %ld(%ld)\n", nsrc
, adsh
->cbSrcLength
, ndst
, adsh
->cbDstLength
);
497 return MMSYSERR_NOERROR
;
500 /**************************************************************************
501 * GSM_DriverProc [exported]
503 LRESULT CALLBACK
GSM_DriverProc(DWORD_PTR dwDevID
, HDRVR hDriv
, UINT wMsg
,
504 LPARAM dwParam1
, LPARAM dwParam2
)
506 TRACE("(%08Ix %p %04x %08Ix %08Ix);\n",
507 dwDevID
, hDriv
, wMsg
, dwParam1
, dwParam2
);
511 case DRV_LOAD
: return 1;
512 case DRV_FREE
: return 1;
513 case DRV_OPEN
: return 1;
514 case DRV_CLOSE
: return 1;
515 case DRV_ENABLE
: return 1;
516 case DRV_DISABLE
: return 1;
517 case DRV_QUERYCONFIGURE
: return 1;
518 case DRV_CONFIGURE
: MessageBoxA(0, "GSM 06.10 codec", "Wine Driver", MB_OK
); return 1;
519 case DRV_INSTALL
: return DRVCNF_RESTART
;
520 case DRV_REMOVE
: return DRVCNF_RESTART
;
522 case ACMDM_DRIVER_NOTIFY
:
523 /* no caching from other ACM drivers is done so far */
524 return MMSYSERR_NOERROR
;
526 case ACMDM_DRIVER_DETAILS
:
527 return GSM_DriverDetails((PACMDRIVERDETAILSW
)dwParam1
);
529 case ACMDM_FORMATTAG_DETAILS
:
530 return GSM_FormatTagDetails((PACMFORMATTAGDETAILSW
)dwParam1
, dwParam2
);
532 case ACMDM_FORMAT_DETAILS
:
533 return GSM_FormatDetails((PACMFORMATDETAILSW
)dwParam1
, dwParam2
);
535 case ACMDM_FORMAT_SUGGEST
:
536 return GSM_FormatSuggest((PACMDRVFORMATSUGGEST
)dwParam1
);
538 case ACMDM_STREAM_OPEN
:
539 return GSM_StreamOpen((PACMDRVSTREAMINSTANCE
)dwParam1
);
541 case ACMDM_STREAM_CLOSE
:
542 return GSM_StreamClose((PACMDRVSTREAMINSTANCE
)dwParam1
);
544 case ACMDM_STREAM_SIZE
:
545 return GSM_StreamSize((PACMDRVSTREAMINSTANCE
)dwParam1
, (PACMDRVSTREAMSIZE
)dwParam2
);
547 case ACMDM_STREAM_CONVERT
:
548 return GSM_StreamConvert((PACMDRVSTREAMINSTANCE
)dwParam1
, (PACMDRVSTREAMHEADER
)dwParam2
);
550 case ACMDM_HARDWARE_WAVE_CAPS_INPUT
:
551 case ACMDM_HARDWARE_WAVE_CAPS_OUTPUT
:
552 /* this converter is not a hardware driver */
553 case ACMDM_FILTERTAG_DETAILS
:
554 case ACMDM_FILTER_DETAILS
:
555 /* this converter is not a filter */
556 case ACMDM_STREAM_RESET
:
557 /* only needed for asynchronous driver... we aren't, so just say it */
558 return MMSYSERR_NOTSUPPORTED
;
559 case ACMDM_STREAM_PREPARE
:
560 case ACMDM_STREAM_UNPREPARE
:
561 /* nothing special to do here... so don't do anything */
562 return MMSYSERR_NOERROR
;
565 return DefDriverProc(dwDevID
, hDriv
, wMsg
, dwParam1
, dwParam2
);