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
24 #include <wine/port.h>
32 #elif defined(HAVE_GSM_H)
45 #include "wine/debug.h"
47 WINE_DEFAULT_DEBUG_CHANNEL(gsm
);
51 static void *libgsm_handle
;
52 #define FUNCPTR(f) static typeof(f) * p##f
59 #define LOAD_FUNCPTR(f) \
60 if((p##f = dlsym(libgsm_handle, #f)) == NULL) { \
61 dlclose(libgsm_handle); \
62 libgsm_handle = NULL; \
66 /***********************************************************************
69 static BOOL
GSM_drvLoad(void)
71 libgsm_handle
= dlopen(SONAME_LIBGSM
, RTLD_NOW
);
74 LOAD_FUNCPTR(gsm_create
);
75 LOAD_FUNCPTR(gsm_destroy
);
76 LOAD_FUNCPTR(gsm_option
);
77 LOAD_FUNCPTR(gsm_encode
);
78 LOAD_FUNCPTR(gsm_decode
);
83 ERR("Couldn't load " SONAME_LIBGSM
": %s\n", dlerror());
88 /***********************************************************************
91 static LRESULT
GSM_drvFree(void)
94 dlclose(libgsm_handle
);
100 static LRESULT
GSM_drvFree(void)
107 /***********************************************************************
111 static LRESULT
GSM_DriverDetails(PACMDRIVERDETAILSW add
)
113 add
->fccType
= ACMDRIVERDETAILS_FCCTYPE_AUDIOCODEC
;
114 add
->fccComp
= ACMDRIVERDETAILS_FCCCOMP_UNDEFINED
;
115 /* Details found from probing native msgsm32.acm */
116 add
->wMid
= MM_MICROSOFT
;
117 add
->wPid
= MM_MSFT_ACM_GSM610
;
118 add
->vdwACM
= 0x3320000;
119 add
->vdwDriver
= 0x4000000;
120 add
->fdwSupport
= ACMDRIVERDETAILS_SUPPORTF_CODEC
;
121 add
->cFormatTags
= 2;
122 add
->cFilterTags
= 0;
124 MultiByteToWideChar( CP_ACP
, 0, "Microsoft GSM 6.10", -1,
125 add
->szShortName
, ARRAY_SIZE( add
->szShortName
));
126 MultiByteToWideChar( CP_ACP
, 0, "Wine GSM 6.10 libgsm codec", -1,
127 add
->szLongName
, ARRAY_SIZE( add
->szLongName
));
128 MultiByteToWideChar( CP_ACP
, 0, "Brought to you by the Wine team...", -1,
129 add
->szCopyright
, ARRAY_SIZE( add
->szCopyright
));
130 MultiByteToWideChar( CP_ACP
, 0, "Refer to LICENSE file", -1,
131 add
->szLicensing
, ARRAY_SIZE( add
->szLicensing
));
132 add
->szFeatures
[0] = 0;
133 return MMSYSERR_NOERROR
;
136 /* Validate a WAVEFORMATEX structure */
137 static BOOL
GSM_FormatValidate(const WAVEFORMATEX
*wfx
)
139 if (wfx
->nChannels
!= 1)
142 switch (wfx
->wFormatTag
)
144 case WAVE_FORMAT_PCM
:
145 if (wfx
->wBitsPerSample
!= 16)
147 WARN("PCM wBitsPerSample %u\n", wfx
->wBitsPerSample
);
150 if (wfx
->nBlockAlign
!= 2)
152 WARN("PCM nBlockAlign %u\n", wfx
->nBlockAlign
);
155 if (wfx
->nAvgBytesPerSec
!= wfx
->nBlockAlign
* wfx
->nSamplesPerSec
)
157 WARN("PCM nAvgBytesPerSec %u/%u\n",
158 wfx
->nAvgBytesPerSec
,
159 wfx
->nBlockAlign
* wfx
->nSamplesPerSec
);
163 case WAVE_FORMAT_GSM610
:
164 if (wfx
->cbSize
< sizeof(WORD
))
166 WARN("GSM cbSize %u\n", wfx
->cbSize
);
169 if (wfx
->wBitsPerSample
!= 0)
171 WARN("GSM wBitsPerSample %u\n", wfx
->wBitsPerSample
);
174 if (wfx
->nBlockAlign
!= 65)
176 WARN("GSM nBlockAlign %u\n", wfx
->nBlockAlign
);
179 if (((const GSM610WAVEFORMAT
*)wfx
)->wSamplesPerBlock
!= 320)
181 WARN("GSM wSamplesPerBlock %u\n",
182 ((const GSM610WAVEFORMAT
*)wfx
)->wSamplesPerBlock
);
185 if (wfx
->nAvgBytesPerSec
!= wfx
->nSamplesPerSec
* 65 / 320)
187 WARN("GSM nAvgBytesPerSec %d / %d\n",
188 wfx
->nAvgBytesPerSec
, wfx
->nSamplesPerSec
* 65 / 320);
198 static const DWORD gsm_rates
[] = { 8000, 11025, 22050, 44100, 48000, 96000 };
200 /***********************************************************************
201 * GSM_FormatTagDetails
204 static LRESULT
GSM_FormatTagDetails(PACMFORMATTAGDETAILSW aftd
, DWORD dwQuery
)
206 static const WCHAR szPcm
[]={'P','C','M',0};
207 static const WCHAR szGsm
[]={'G','S','M',' ','6','.','1','0',0};
211 case ACM_FORMATTAGDETAILSF_INDEX
:
212 if (aftd
->dwFormatTagIndex
> 1) return ACMERR_NOTPOSSIBLE
;
214 case ACM_FORMATTAGDETAILSF_LARGESTSIZE
:
215 if (aftd
->dwFormatTag
== WAVE_FORMAT_UNKNOWN
)
217 aftd
->dwFormatTagIndex
= 1;
221 case ACM_FORMATTAGDETAILSF_FORMATTAG
:
222 switch (aftd
->dwFormatTag
)
224 case WAVE_FORMAT_PCM
: aftd
->dwFormatTagIndex
= 0; break;
225 case WAVE_FORMAT_GSM610
: aftd
->dwFormatTagIndex
= 1; break;
226 default: return ACMERR_NOTPOSSIBLE
;
230 WARN("Unsupported query %08x\n", dwQuery
);
231 return MMSYSERR_NOTSUPPORTED
;
234 aftd
->fdwSupport
= ACMDRIVERDETAILS_SUPPORTF_CODEC
;
235 switch (aftd
->dwFormatTagIndex
)
238 aftd
->dwFormatTag
= WAVE_FORMAT_PCM
;
239 aftd
->cbFormatSize
= sizeof(PCMWAVEFORMAT
);
240 aftd
->cStandardFormats
= ARRAY_SIZE(gsm_rates
);
241 lstrcpyW(aftd
->szFormatTag
, szPcm
);
244 aftd
->dwFormatTag
= WAVE_FORMAT_GSM610
;
245 aftd
->cbFormatSize
= sizeof(GSM610WAVEFORMAT
);
246 aftd
->cStandardFormats
= ARRAY_SIZE(gsm_rates
);
247 lstrcpyW(aftd
->szFormatTag
, szGsm
);
250 return MMSYSERR_NOERROR
;
253 /***********************************************************************
257 static LRESULT
GSM_FormatDetails(PACMFORMATDETAILSW afd
, DWORD dwQuery
)
261 case ACM_FORMATDETAILSF_FORMAT
:
262 if (!GSM_FormatValidate(afd
->pwfx
)) return ACMERR_NOTPOSSIBLE
;
264 case ACM_FORMATDETAILSF_INDEX
:
265 afd
->pwfx
->wFormatTag
= afd
->dwFormatTag
;
266 switch (afd
->dwFormatTag
)
268 case WAVE_FORMAT_PCM
:
269 if (afd
->dwFormatIndex
>= ARRAY_SIZE(gsm_rates
)) return ACMERR_NOTPOSSIBLE
;
270 afd
->pwfx
->nChannels
= 1;
271 afd
->pwfx
->nSamplesPerSec
= gsm_rates
[afd
->dwFormatIndex
];
272 afd
->pwfx
->wBitsPerSample
= 16;
273 afd
->pwfx
->nBlockAlign
= 2;
274 afd
->pwfx
->nAvgBytesPerSec
= afd
->pwfx
->nSamplesPerSec
* afd
->pwfx
->nBlockAlign
;
276 case WAVE_FORMAT_GSM610
:
277 if (afd
->dwFormatIndex
>= ARRAY_SIZE(gsm_rates
)) return ACMERR_NOTPOSSIBLE
;
278 afd
->pwfx
->nChannels
= 1;
279 afd
->pwfx
->nSamplesPerSec
= gsm_rates
[afd
->dwFormatIndex
];
280 afd
->pwfx
->wBitsPerSample
= 0;
281 afd
->pwfx
->nBlockAlign
= 65;
282 afd
->pwfx
->nAvgBytesPerSec
= afd
->pwfx
->nSamplesPerSec
* 65 / 320;
283 afd
->pwfx
->cbSize
= sizeof(WORD
);
284 ((GSM610WAVEFORMAT
*)afd
->pwfx
)->wSamplesPerBlock
= 320;
287 WARN("Unsupported tag %08x\n", afd
->dwFormatTag
);
288 return MMSYSERR_INVALPARAM
;
292 WARN("Unsupported query %08x\n", dwQuery
);
293 return MMSYSERR_NOTSUPPORTED
;
295 afd
->fdwSupport
= ACMDRIVERDETAILS_SUPPORTF_CODEC
;
296 afd
->szFormat
[0] = 0; /* let MSACM format this for us... */
298 return MMSYSERR_NOERROR
;
301 /***********************************************************************
305 static LRESULT
GSM_FormatSuggest(PACMDRVFORMATSUGGEST adfs
)
308 if (adfs
->cbwfxSrc
< sizeof(PCMWAVEFORMAT
) ||
309 adfs
->cbwfxDst
< sizeof(PCMWAVEFORMAT
) ||
310 !GSM_FormatValidate(adfs
->pwfxSrc
)) return ACMERR_NOTPOSSIBLE
;
311 /* FIXME: should do those tests against the real size (according to format tag */
313 /* If no suggestion for destination, then copy source value */
314 if (!(adfs
->fdwSuggest
& ACM_FORMATSUGGESTF_NCHANNELS
))
315 adfs
->pwfxDst
->nChannels
= adfs
->pwfxSrc
->nChannels
;
316 if (!(adfs
->fdwSuggest
& ACM_FORMATSUGGESTF_NSAMPLESPERSEC
))
317 adfs
->pwfxDst
->nSamplesPerSec
= adfs
->pwfxSrc
->nSamplesPerSec
;
319 if (!(adfs
->fdwSuggest
& ACM_FORMATSUGGESTF_WBITSPERSAMPLE
))
321 if (adfs
->pwfxSrc
->wFormatTag
== WAVE_FORMAT_PCM
)
322 adfs
->pwfxDst
->wBitsPerSample
= 0;
324 adfs
->pwfxDst
->wBitsPerSample
= 16;
326 if (!(adfs
->fdwSuggest
& ACM_FORMATSUGGESTF_WFORMATTAG
))
328 switch (adfs
->pwfxSrc
->wFormatTag
)
330 case WAVE_FORMAT_PCM
: adfs
->pwfxDst
->wFormatTag
= WAVE_FORMAT_GSM610
; break;
331 case WAVE_FORMAT_GSM610
: adfs
->pwfxDst
->wFormatTag
= WAVE_FORMAT_PCM
; break;
335 /* recompute other values */
336 switch (adfs
->pwfxDst
->wFormatTag
)
338 case WAVE_FORMAT_PCM
:
339 adfs
->pwfxDst
->nBlockAlign
= 2;
340 adfs
->pwfxDst
->nAvgBytesPerSec
= adfs
->pwfxDst
->nSamplesPerSec
* 2;
342 case WAVE_FORMAT_GSM610
:
343 if (adfs
->pwfxDst
->cbSize
< sizeof(WORD
))
344 return ACMERR_NOTPOSSIBLE
;
345 adfs
->pwfxDst
->nBlockAlign
= 65;
346 adfs
->pwfxDst
->nAvgBytesPerSec
= adfs
->pwfxDst
->nSamplesPerSec
* 65 / 320;
347 ((GSM610WAVEFORMAT
*)adfs
->pwfxDst
)->wSamplesPerBlock
= 320;
350 return ACMERR_NOTPOSSIBLE
;
353 /* check if result is ok */
354 if (!GSM_FormatValidate(adfs
->pwfxDst
)) return ACMERR_NOTPOSSIBLE
;
355 return MMSYSERR_NOERROR
;
359 /***********************************************************************
363 static LRESULT
GSM_StreamOpen(PACMDRVSTREAMINSTANCE adsi
)
367 if (!GSM_FormatValidate(adsi
->pwfxSrc
) || !GSM_FormatValidate(adsi
->pwfxDst
))
368 return MMSYSERR_NOTSUPPORTED
;
370 if (adsi
->pwfxSrc
->nSamplesPerSec
!= adsi
->pwfxDst
->nSamplesPerSec
)
371 return MMSYSERR_NOTSUPPORTED
;
373 if (!GSM_drvLoad()) return MMSYSERR_NOTSUPPORTED
;
377 return MMSYSERR_NOMEM
;
378 if (pgsm_option(r
, GSM_OPT_WAV49
, &used
) < 0)
380 FIXME("Your libgsm library doesn't support GSM_OPT_WAV49\n");
381 FIXME("Please recompile libgsm with WAV49 support\n");
383 return MMSYSERR_NOTSUPPORTED
;
385 adsi
->dwDriver
= (DWORD_PTR
)r
;
386 return MMSYSERR_NOERROR
;
389 /***********************************************************************
393 static LRESULT
GSM_StreamClose(PACMDRVSTREAMINSTANCE adsi
)
395 pgsm_destroy((gsm
)adsi
->dwDriver
);
396 return MMSYSERR_NOERROR
;
399 /***********************************************************************
403 static LRESULT
GSM_StreamSize(const ACMDRVSTREAMINSTANCE
*adsi
, PACMDRVSTREAMSIZE adss
)
405 switch (adss
->fdwSize
)
407 case ACM_STREAMSIZEF_DESTINATION
:
408 /* cbDstLength => cbSrcLength */
409 if (adsi
->pwfxSrc
->wFormatTag
== WAVE_FORMAT_PCM
&&
410 adsi
->pwfxDst
->wFormatTag
== WAVE_FORMAT_GSM610
)
412 adss
->cbSrcLength
= adss
->cbDstLength
/ 65 * 640;
414 else if (adsi
->pwfxSrc
->wFormatTag
== WAVE_FORMAT_GSM610
&&
415 adsi
->pwfxDst
->wFormatTag
== WAVE_FORMAT_PCM
)
417 adss
->cbSrcLength
= adss
->cbDstLength
/ 640 * 65;
421 return MMSYSERR_NOTSUPPORTED
;
423 return MMSYSERR_NOERROR
;
424 case ACM_STREAMSIZEF_SOURCE
:
425 /* cbSrcLength => cbDstLength */
426 if (adsi
->pwfxSrc
->wFormatTag
== WAVE_FORMAT_PCM
&&
427 adsi
->pwfxDst
->wFormatTag
== WAVE_FORMAT_GSM610
)
429 adss
->cbDstLength
= (adss
->cbSrcLength
+ 639) / 640 * 65;
431 else if (adsi
->pwfxSrc
->wFormatTag
== WAVE_FORMAT_GSM610
&&
432 adsi
->pwfxDst
->wFormatTag
== WAVE_FORMAT_PCM
)
434 adss
->cbDstLength
= adss
->cbSrcLength
/ 65 * 640;
438 return MMSYSERR_NOTSUPPORTED
;
440 return MMSYSERR_NOERROR
;
442 WARN("Unsupported query %08x\n", adss
->fdwSize
);
443 return MMSYSERR_NOTSUPPORTED
;
447 /***********************************************************************
451 static LRESULT
GSM_StreamConvert(PACMDRVSTREAMINSTANCE adsi
, PACMDRVSTREAMHEADER adsh
)
453 gsm r
= (gsm
)adsi
->dwDriver
;
456 BYTE
*src
= adsh
->pbSrc
;
457 BYTE
*dst
= adsh
->pbDst
;
460 if (adsh
->fdwConvert
&
461 ~(ACM_STREAMCONVERTF_BLOCKALIGN
|
462 ACM_STREAMCONVERTF_END
|
463 ACM_STREAMCONVERTF_START
))
465 FIXME("Unsupported fdwConvert (%08x), ignoring it\n", adsh
->fdwConvert
);
468 /* Reset the index to 0, just to be sure */
469 pgsm_option(r
, GSM_OPT_FRAME_INDEX
, &odd
);
471 /* The native ms codec writes 65 bytes, and this requires 2 libgsm calls.
472 * First 32 bytes are written, or 33 bytes read
473 * Second 33 bytes are written, or 32 bytes read
477 if (adsi
->pwfxSrc
->wFormatTag
== WAVE_FORMAT_GSM610
)
479 if (adsh
->cbSrcLength
/ 65 * 640 > adsh
->cbDstLength
)
481 return ACMERR_NOTPOSSIBLE
;
484 while (nsrc
+ 65 <= adsh
->cbSrcLength
)
487 if (pgsm_decode(r
, src
+ nsrc
, (gsm_signal
*)(dst
+ ndst
)) < 0)
488 FIXME("Couldn't decode data\n");
492 if (pgsm_decode(r
, src
+ nsrc
, (gsm_signal
*)(dst
+ ndst
)) < 0)
493 FIXME("Couldn't decode data\n");
500 /* Testing a little seems to reveal that despite being able to fit
501 * inside the buffer if ACM_STREAMCONVERTF_BLOCKALIGN is set
504 if ((adsh
->cbSrcLength
+ 639) / 640 * 65 > adsh
->cbDstLength
)
506 return ACMERR_NOTPOSSIBLE
;
509 /* The packing algorithm writes 32 bytes, then 33 bytes,
510 * and it seems to pad to align to 65 bytes always
511 * adding extra data where necessary
513 while (nsrc
+ 640 <= adsh
->cbSrcLength
)
516 pgsm_encode(r
, (gsm_signal
*)(src
+nsrc
), dst
+ndst
);
519 pgsm_encode(r
, (gsm_signal
*)(src
+nsrc
), dst
+ndst
);
524 /* If ACM_STREAMCONVERTF_BLOCKALIGN isn't set pad with zeros */
525 if (!(adsh
->fdwConvert
& ACM_STREAMCONVERTF_BLOCKALIGN
) &&
526 nsrc
< adsh
->cbSrcLength
)
529 int todo
= adsh
->cbSrcLength
- nsrc
;
533 pgsm_encode(r
, (gsm_signal
*)(src
+nsrc
), dst
+ndst
);
538 memcpy(emptiness
, src
+nsrc
, todo
);
539 memset(emptiness
+ todo
, 0, 320 - todo
);
540 pgsm_encode(r
, (gsm_signal
*)emptiness
, dst
+ndst
);
545 memcpy(emptiness
, src
+nsrc
, todo
);
546 memset(emptiness
+ todo
, 0, 320 - todo
);
547 pgsm_encode(r
, (gsm_signal
*)emptiness
, dst
+ndst
);
550 memset(emptiness
, 0, todo
);
551 pgsm_encode(r
, (gsm_signal
*)emptiness
, dst
+ndst
);
554 nsrc
= adsh
->cbSrcLength
;
558 adsh
->cbSrcLengthUsed
= nsrc
;
559 adsh
->cbDstLengthUsed
= ndst
;
560 TRACE("%d(%d) -> %d(%d)\n", nsrc
, adsh
->cbSrcLength
, ndst
, adsh
->cbDstLength
);
561 return MMSYSERR_NOERROR
;
566 /**************************************************************************
567 * GSM_DriverProc [exported]
569 LRESULT CALLBACK
GSM_DriverProc(DWORD_PTR dwDevID
, HDRVR hDriv
, UINT wMsg
,
570 LPARAM dwParam1
, LPARAM dwParam2
)
572 TRACE("(%08lx %p %04x %08lx %08lx);\n",
573 dwDevID
, hDriv
, wMsg
, dwParam1
, dwParam2
);
577 case DRV_LOAD
: return 1;
578 case DRV_FREE
: return GSM_drvFree();
579 case DRV_OPEN
: return 1;
580 case DRV_CLOSE
: return 1;
581 case DRV_ENABLE
: return 1;
582 case DRV_DISABLE
: return 1;
583 case DRV_QUERYCONFIGURE
: return 1;
584 case DRV_CONFIGURE
: MessageBoxA(0, "GSM 06.10 codec", "Wine Driver", MB_OK
); return 1;
585 case DRV_INSTALL
: return DRVCNF_RESTART
;
586 case DRV_REMOVE
: return DRVCNF_RESTART
;
588 case ACMDM_DRIVER_NOTIFY
:
589 /* no caching from other ACM drivers is done so far */
590 return MMSYSERR_NOERROR
;
592 case ACMDM_DRIVER_DETAILS
:
593 return GSM_DriverDetails((PACMDRIVERDETAILSW
)dwParam1
);
595 case ACMDM_FORMATTAG_DETAILS
:
596 return GSM_FormatTagDetails((PACMFORMATTAGDETAILSW
)dwParam1
, dwParam2
);
598 case ACMDM_FORMAT_DETAILS
:
599 return GSM_FormatDetails((PACMFORMATDETAILSW
)dwParam1
, dwParam2
);
601 case ACMDM_FORMAT_SUGGEST
:
602 return GSM_FormatSuggest((PACMDRVFORMATSUGGEST
)dwParam1
);
605 case ACMDM_STREAM_OPEN
:
606 return GSM_StreamOpen((PACMDRVSTREAMINSTANCE
)dwParam1
);
608 case ACMDM_STREAM_CLOSE
:
609 return GSM_StreamClose((PACMDRVSTREAMINSTANCE
)dwParam1
);
611 case ACMDM_STREAM_SIZE
:
612 return GSM_StreamSize((PACMDRVSTREAMINSTANCE
)dwParam1
, (PACMDRVSTREAMSIZE
)dwParam2
);
614 case ACMDM_STREAM_CONVERT
:
615 return GSM_StreamConvert((PACMDRVSTREAMINSTANCE
)dwParam1
, (PACMDRVSTREAMHEADER
)dwParam2
);
617 case ACMDM_STREAM_OPEN
: WARN("libgsm support not compiled in!\n");
618 case ACMDM_STREAM_CLOSE
:
619 case ACMDM_STREAM_SIZE
:
620 case ACMDM_STREAM_CONVERT
:
621 return MMSYSERR_NOTSUPPORTED
;
624 case ACMDM_HARDWARE_WAVE_CAPS_INPUT
:
625 case ACMDM_HARDWARE_WAVE_CAPS_OUTPUT
:
626 /* this converter is not a hardware driver */
627 case ACMDM_FILTERTAG_DETAILS
:
628 case ACMDM_FILTER_DETAILS
:
629 /* this converter is not a filter */
630 case ACMDM_STREAM_RESET
:
631 /* only needed for asynchronous driver... we aren't, so just say it */
632 return MMSYSERR_NOTSUPPORTED
;
633 case ACMDM_STREAM_PREPARE
:
634 case ACMDM_STREAM_UNPREPARE
:
635 /* nothing special to do here... so don't do anything */
636 return MMSYSERR_NOERROR
;
639 return DefDriverProc(dwDevID
, hDriv
, wMsg
, dwParam1
, dwParam2
);