wintrust: Add a helper function to initialize chain creation parameters.
[wine] / dlls / winealsa.drv / waveinit.c
1 /*
2  * Sample Wine Driver for Advanced Linux Sound System (ALSA)
3  *      Based on version <final> of the ALSA API
4  *
5  * This file performs the initialisation and scanning of the sound subsystem.
6  *
7  * Copyright    2002 Eric Pouech
8  *              2002 Marco Pietrobono
9  *              2003 Christian Costa : WaveIn support
10  *              2006-2007 Maarten Lankhorst
11  *
12  * This library is free software; you can redistribute it and/or
13  * modify it under the terms of the GNU Lesser General Public
14  * License as published by the Free Software Foundation; either
15  * version 2.1 of the License, or (at your option) any later version.
16  *
17  * This library is distributed in the hope that it will be useful,
18  * but WITHOUT ANY WARRANTY; without even the implied warranty of
19  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
20  * Lesser General Public License for more details.
21  *
22  * You should have received a copy of the GNU Lesser General Public
23  * License along with this library; if not, write to the Free Software
24  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
25  */
26
27 #include "config.h"
28 #include "wine/port.h"
29
30 #include <stdlib.h>
31 #include <stdarg.h>
32 #include <stdio.h>
33 #include <string.h>
34 #ifdef HAVE_UNISTD_H
35 # include <unistd.h>
36 #endif
37 #include <errno.h>
38 #include <limits.h>
39 #include <fcntl.h>
40 #ifdef HAVE_SYS_IOCTL_H
41 # include <sys/ioctl.h>
42 #endif
43 #ifdef HAVE_SYS_MMAN_H
44 # include <sys/mman.h>
45 #endif
46 #include "windef.h"
47 #include "winbase.h"
48 #include "wingdi.h"
49 #include "winerror.h"
50 #include "winuser.h"
51 #include "winnls.h"
52 #include "winreg.h"
53 #include "mmddk.h"
54
55 /* ksmedia.h defines KSDATAFORMAT_SUBTYPE_PCM and KSDATAFORMAT_SUBTYPE_IEEE_FLOAT
56  * However either all files that use it will define it, or no files will
57  * The only way to solve this is by adding initguid.h here, and include the guid that way
58  */
59 #include "initguid.h"
60 #include "alsa.h"
61
62 #include "wine/library.h"
63 #include "wine/unicode.h"
64 #include "wine/debug.h"
65
66 WINE_DEFAULT_DEBUG_CHANNEL(wave);
67
68 #ifdef HAVE_ALSA
69
70 /*----------------------------------------------------------------------------
71 **  ALSA_TestDeviceForWine
72 **
73 **      Test to see if a given device is sufficient for Wine.
74 */
75 static int ALSA_TestDeviceForWine(int card, int device,  snd_pcm_stream_t streamtype)
76 {
77     snd_pcm_t *pcm = NULL;
78     char pcmname[256];
79     int retcode;
80     snd_pcm_hw_params_t *hwparams;
81     const char *reason = NULL;
82     unsigned int rrate;
83
84     /* Note that the plug: device masks out a lot of info, we want to avoid that */
85     sprintf(pcmname, "hw:%d,%d", card, device);
86     retcode = snd_pcm_open(&pcm, pcmname, streamtype, SND_PCM_NONBLOCK);
87     if (retcode < 0)
88     {
89         /* Note that a busy device isn't automatically disqualified */
90         if (retcode == (-1 * EBUSY))
91             retcode = 0;
92         goto exit;
93     }
94
95     snd_pcm_hw_params_alloca(&hwparams);
96
97     retcode = snd_pcm_hw_params_any(pcm, hwparams);
98     if (retcode < 0)
99     {
100         reason = "Could not retrieve hw_params";
101         goto exit;
102     }
103
104     /* set the count of channels */
105     retcode = snd_pcm_hw_params_set_channels(pcm, hwparams, 2);
106     if (retcode < 0)
107     {
108         reason = "Could not set channels";
109         goto exit;
110     }
111
112     rrate = 44100;
113     retcode = snd_pcm_hw_params_set_rate_near(pcm, hwparams, &rrate, 0);
114     if (retcode < 0)
115     {
116         reason = "Could not set rate";
117         goto exit;
118     }
119
120     if (rrate == 0)
121     {
122         reason = "Rate came back as 0";
123         goto exit;
124     }
125
126     /* write the parameters to device */
127     retcode = snd_pcm_hw_params(pcm, hwparams);
128     if (retcode < 0)
129     {
130         reason = "Could not set hwparams";
131         goto exit;
132     }
133
134     retcode = 0;
135
136 exit:
137     if (pcm)
138         snd_pcm_close(pcm);
139
140     if (retcode != 0 && retcode != (-1 * ENOENT))
141         TRACE("Discarding card %d/device %d:  %s [%d(%s)]\n", card, device, reason, retcode, snd_strerror(retcode));
142
143     return retcode;
144 }
145
146 /*----------------------------------------------------------------------------
147 ** ALSA_RegGetString
148 **  Retrieve a string from a registry key
149 */
150 static int ALSA_RegGetString(HKEY key, const char *value, char **bufp)
151 {
152     DWORD rc;
153     DWORD type;
154     DWORD bufsize;
155
156     *bufp = NULL;
157     rc = RegQueryValueExA(key, value, NULL, &type, NULL, &bufsize);
158     if (rc != ERROR_SUCCESS)
159         return(rc);
160
161     if (type != REG_SZ)
162         return 1;
163
164     *bufp = HeapAlloc(GetProcessHeap(), 0, bufsize);
165     if (! *bufp)
166         return 1;
167
168     rc = RegQueryValueExA(key, value, NULL, NULL, (LPBYTE)*bufp, &bufsize);
169     return rc;
170 }
171
172 /*----------------------------------------------------------------------------
173 ** ALSA_RegGetBoolean
174 **  Get a string and interpret it as a boolean
175 */
176
177 /* Possible truths:
178    Y(es), T(rue), 1, E(nabled) */
179
180 #define IS_OPTION_TRUE(ch) ((ch) == 'y' || (ch) == 'Y' || (ch) == 't' || (ch) == 'T' || (ch) == '1' || (ch) == 'e' || (ch) == 'E')
181 static int ALSA_RegGetBoolean(HKEY key, const char *value, BOOL *answer)
182 {
183     DWORD rc;
184     char *buf = NULL;
185
186     rc = ALSA_RegGetString(key, value, &buf);
187     if (buf)
188     {
189         *answer = FALSE;
190         if (IS_OPTION_TRUE(*buf))
191             *answer = TRUE;
192
193         HeapFree(GetProcessHeap(), 0, buf);
194     }
195
196     return rc;
197 }
198
199 /*----------------------------------------------------------------------------
200 ** ALSA_RegGetBoolean
201 **  Get a string and interpret it as a DWORD
202 */
203 static int ALSA_RegGetInt(HKEY key, const char *value, DWORD *answer)
204 {
205     DWORD rc;
206     char *buf = NULL;
207
208     rc = ALSA_RegGetString(key, value, &buf);
209     if (buf)
210     {
211         *answer = atoi(buf);
212         HeapFree(GetProcessHeap(), 0, buf);
213     }
214
215     return rc;
216 }
217
218 /* return a string duplicated on the win32 process heap, free with HeapFree */
219 static char* ALSA_strdup(const char *s) {
220     char *result = HeapAlloc(GetProcessHeap(), 0, strlen(s)+1);
221     if (!result)
222         return NULL;
223     strcpy(result, s);
224     return result;
225 }
226
227 #define ALSA_RETURN_ONFAIL(mycall)                                      \
228 {                                                                       \
229     int rc;                                                             \
230     {rc = mycall;}                                                      \
231     if ((rc) < 0)                                                       \
232     {                                                                   \
233         ERR("%s failed:  %s(%d)\n", #mycall, snd_strerror(rc), rc);     \
234         return(rc);                                                     \
235     }                                                                   \
236 }
237
238 /*----------------------------------------------------------------------------
239 **  ALSA_ComputeCaps
240 **
241 **      Given an ALSA PCM, figure out our HW CAPS structure info.
242 **  ctl can be null, pcm is required, as is all output parms.
243 **
244 */
245 static int ALSA_ComputeCaps(snd_ctl_t *ctl, snd_pcm_t *pcm,
246         WORD *channels, DWORD *flags, DWORD *formats, DWORD *supports)
247 {
248     snd_pcm_hw_params_t *hw_params;
249     snd_pcm_format_mask_t *fmask;
250     snd_pcm_access_mask_t *acmask;
251     unsigned int ratemin = 0;
252     unsigned int ratemax = 0;
253     unsigned int chmin = 0;
254     unsigned int chmax = 0;
255     int dir = 0;
256
257     snd_pcm_hw_params_alloca(&hw_params);
258     ALSA_RETURN_ONFAIL(snd_pcm_hw_params_any(pcm, hw_params));
259
260     snd_pcm_format_mask_alloca(&fmask);
261     snd_pcm_hw_params_get_format_mask(hw_params, fmask);
262
263     snd_pcm_access_mask_alloca(&acmask);
264     ALSA_RETURN_ONFAIL(snd_pcm_hw_params_get_access_mask(hw_params, acmask));
265
266     ALSA_RETURN_ONFAIL(snd_pcm_hw_params_get_rate_min(hw_params, &ratemin, &dir));
267     ALSA_RETURN_ONFAIL(snd_pcm_hw_params_get_rate_max(hw_params, &ratemax, &dir));
268     ALSA_RETURN_ONFAIL(snd_pcm_hw_params_get_channels_min(hw_params, &chmin));
269     ALSA_RETURN_ONFAIL(snd_pcm_hw_params_get_channels_max(hw_params, &chmax));
270
271 #define X(r,v) \
272     if ( (r) >= ratemin && ( (r) <= ratemax || ratemax == -1) ) \
273     { \
274        if (snd_pcm_format_mask_test( fmask, SND_PCM_FORMAT_U8)) \
275        { \
276           if (chmin <= 1 && 1 <= chmax) \
277               *formats |= WAVE_FORMAT_##v##M08; \
278           if (chmin <= 2 && 2 <= chmax) \
279               *formats |= WAVE_FORMAT_##v##S08; \
280        } \
281        if (snd_pcm_format_mask_test( fmask, SND_PCM_FORMAT_S16_LE)) \
282        { \
283           if (chmin <= 1 && 1 <= chmax) \
284               *formats |= WAVE_FORMAT_##v##M16; \
285           if (chmin <= 2 && 2 <= chmax) \
286               *formats |= WAVE_FORMAT_##v##S16; \
287        } \
288     }
289     X(11025,1);
290     X(22050,2);
291     X(44100,4);
292     X(48000,48);
293     X(96000,96);
294 #undef X
295
296     if (chmin > 1)
297         FIXME("Device has a minimum of %d channels\n", chmin);
298     *channels = chmax;
299
300     /* FIXME: is sample accurate always true ?
301     ** Can we do WAVECAPS_PITCH, WAVECAPS_SYNC, or WAVECAPS_PLAYBACKRATE? */
302     *supports |= WAVECAPS_SAMPLEACCURATE;
303
304     /* FIXME: NONITERLEAVED and COMPLEX are not supported right now */
305     if ( snd_pcm_access_mask_test( acmask, SND_PCM_ACCESS_MMAP_INTERLEAVED ) )
306         *supports |= WAVECAPS_DIRECTSOUND;
307
308     /* check for volume control support */
309     if (ctl) {
310         if (snd_ctl_name(ctl))
311         {
312             snd_hctl_t *hctl;
313             if (snd_hctl_open(&hctl, snd_ctl_name(ctl), 0) >= 0)
314             {
315                 snd_hctl_load(hctl);
316                 if (!ALSA_CheckSetVolume( hctl, NULL, NULL, NULL, NULL, NULL, NULL, NULL ))
317                 {
318                     *supports |= WAVECAPS_VOLUME;
319                     if (chmin <= 2 && 2 <= chmax)
320                         *supports |= WAVECAPS_LRVOLUME;
321                 }
322                 snd_hctl_free(hctl);
323                 snd_hctl_close(hctl);
324             }
325         }
326     }
327
328     *flags = DSCAPS_CERTIFIED | DSCAPS_CONTINUOUSRATE;
329     *flags |= DSCAPS_SECONDARYMONO | DSCAPS_SECONDARYSTEREO;
330     *flags |= DSCAPS_SECONDARY8BIT | DSCAPS_SECONDARY16BIT;
331
332     if (*formats & (WAVE_FORMAT_1M08  | WAVE_FORMAT_2M08  |
333                                WAVE_FORMAT_4M08  | WAVE_FORMAT_48M08 |
334                                WAVE_FORMAT_96M08 | WAVE_FORMAT_1M16  |
335                                WAVE_FORMAT_2M16  | WAVE_FORMAT_4M16  |
336                                WAVE_FORMAT_48M16 | WAVE_FORMAT_96M16) )
337         *flags |= DSCAPS_PRIMARYMONO;
338
339     if (*formats & (WAVE_FORMAT_1S08  | WAVE_FORMAT_2S08  |
340                                WAVE_FORMAT_4S08  | WAVE_FORMAT_48S08 |
341                                WAVE_FORMAT_96S08 | WAVE_FORMAT_1S16  |
342                                WAVE_FORMAT_2S16  | WAVE_FORMAT_4S16  |
343                                WAVE_FORMAT_48S16 | WAVE_FORMAT_96S16) )
344         *flags |= DSCAPS_PRIMARYSTEREO;
345
346     if (*formats & (WAVE_FORMAT_1M08  | WAVE_FORMAT_2M08  |
347                                WAVE_FORMAT_4M08  | WAVE_FORMAT_48M08 |
348                                WAVE_FORMAT_96M08 | WAVE_FORMAT_1S08  |
349                                WAVE_FORMAT_2S08  | WAVE_FORMAT_4S08  |
350                                WAVE_FORMAT_48S08 | WAVE_FORMAT_96S08) )
351         *flags |= DSCAPS_PRIMARY8BIT;
352
353     if (*formats & (WAVE_FORMAT_1M16  | WAVE_FORMAT_2M16  |
354                                WAVE_FORMAT_4M16  | WAVE_FORMAT_48M16 |
355                                WAVE_FORMAT_96M16 | WAVE_FORMAT_1S16  |
356                                WAVE_FORMAT_2S16  | WAVE_FORMAT_4S16  |
357                                WAVE_FORMAT_48S16 | WAVE_FORMAT_96S16) )
358         *flags |= DSCAPS_PRIMARY16BIT;
359
360     return(0);
361 }
362
363 /*----------------------------------------------------------------------------
364 **  ALSA_AddCommonDevice
365 **
366 **      Perform Alsa initialization common to both capture and playback
367 **
368 **  Side Effect:  ww->pcname and ww->ctlname may need to be freed.
369 **
370 **  Note:  this was originally coded by using snd_pcm_name(pcm), until
371 **         I discovered that with at least one version of alsa lib,
372 **         the use of a pcm named default:0 would cause snd_pcm_name() to fail.
373 **         So passing the name in is logically extraneous.  Sigh.
374 */
375 static int ALSA_AddCommonDevice(snd_ctl_t *ctl, snd_pcm_t *pcm, const char *pcmname, WINE_WAVEDEV *ww)
376 {
377     snd_pcm_info_t *infop;
378
379     snd_pcm_info_alloca(&infop);
380     ALSA_RETURN_ONFAIL(snd_pcm_info(pcm, infop));
381
382     if (pcm && pcmname)
383         ww->pcmname = ALSA_strdup(pcmname);
384     else
385         return -1;
386
387     if (ctl && snd_ctl_name(ctl))
388         ww->ctlname = ALSA_strdup(snd_ctl_name(ctl));
389
390     strcpy(ww->interface_name, "winealsa: ");
391     memcpy(ww->interface_name + strlen(ww->interface_name),
392             ww->pcmname,
393             min(strlen(ww->pcmname), sizeof(ww->interface_name) - strlen("winealsa:   ")));
394
395     strcpy(ww->ds_desc.szDrvname, "winealsa.drv");
396
397     memcpy(ww->ds_desc.szDesc, snd_pcm_info_get_name(infop),
398             min( (sizeof(ww->ds_desc.szDesc) - 1), strlen(snd_pcm_info_get_name(infop))) );
399
400     ww->ds_caps.dwMinSecondarySampleRate = DSBFREQUENCY_MIN;
401     ww->ds_caps.dwMaxSecondarySampleRate = DSBFREQUENCY_MAX;
402     ww->ds_caps.dwPrimaryBuffers = 1;
403
404     return 0;
405 }
406
407 /*----------------------------------------------------------------------------
408 ** ALSA_FreeDevice
409 */
410 static void ALSA_FreeDevice(WINE_WAVEDEV *ww)
411 {
412     HeapFree(GetProcessHeap(), 0, ww->pcmname);
413     ww->pcmname = NULL;
414
415     HeapFree(GetProcessHeap(), 0, ww->ctlname);
416     ww->ctlname = NULL;
417 }
418
419 /*----------------------------------------------------------------------------
420 **  ALSA_AddDeviceToArray
421 **
422 **      Dynamically size one of the wavein or waveout arrays of devices,
423 **  and add a fully configured device node to the array.
424 **
425 */
426 static int ALSA_AddDeviceToArray(WINE_WAVEDEV *ww, WINE_WAVEDEV **array,
427         DWORD *count, DWORD *alloced, int isdefault)
428 {
429     int i = *count;
430
431     if (*count >= *alloced)
432     {
433         (*alloced) += WAVEDEV_ALLOC_EXTENT_SIZE;
434         if (! (*array))
435             *array = HeapAlloc(GetProcessHeap(), 0, sizeof(*ww) * (*alloced));
436         else
437             *array = HeapReAlloc(GetProcessHeap(), 0, *array, sizeof(*ww) * (*alloced));
438
439         if (!*array)
440         {
441             return -1;
442         }
443     }
444
445     /* If this is the default, arrange for it to be the first element */
446     if (isdefault && i > 0)
447     {
448         (*array)[*count] = (*array)[0];
449         i = 0;
450     }
451
452     (*array)[i] = *ww;
453
454     (*count)++;
455     return 0;
456 }
457
458 /*----------------------------------------------------------------------------
459 **  ALSA_AddPlaybackDevice
460 **
461 **      Add a given Alsa device to Wine's internal list of Playback
462 **  devices.
463 */
464 static int ALSA_AddPlaybackDevice(snd_ctl_t *ctl, snd_pcm_t *pcm, const char *pcmname, int isdefault)
465 {
466     WINE_WAVEDEV    wwo;
467     int rc;
468
469     memset(&wwo, '\0', sizeof(wwo));
470
471     rc = ALSA_AddCommonDevice(ctl, pcm, pcmname, &wwo);
472     if (rc)
473         return(rc);
474
475     MultiByteToWideChar(CP_ACP, 0, wwo.ds_desc.szDesc, -1,
476                         wwo.outcaps.szPname, sizeof(wwo.outcaps.szPname)/sizeof(WCHAR));
477     wwo.outcaps.szPname[sizeof(wwo.outcaps.szPname)/sizeof(WCHAR) - 1] = '\0';
478
479     wwo.outcaps.wMid = MM_CREATIVE;
480     wwo.outcaps.wPid = MM_CREATIVE_SBP16_WAVEOUT;
481     wwo.outcaps.vDriverVersion = 0x0100;
482
483     rc = ALSA_ComputeCaps(ctl, pcm, &wwo.outcaps.wChannels, &wwo.ds_caps.dwFlags,
484             &wwo.outcaps.dwFormats, &wwo.outcaps.dwSupport);
485     if (rc)
486     {
487         WARN("Error calculating device caps for pcm [%s]\n", wwo.pcmname);
488         ALSA_FreeDevice(&wwo);
489         return(rc);
490     }
491
492     rc = ALSA_AddDeviceToArray(&wwo, &WOutDev, &ALSA_WodNumDevs, &ALSA_WodNumMallocedDevs, isdefault);
493     if (rc)
494         ALSA_FreeDevice(&wwo);
495     return (rc);
496 }
497
498 /*----------------------------------------------------------------------------
499 **  ALSA_AddCaptureDevice
500 **
501 **      Add a given Alsa device to Wine's internal list of Capture
502 **  devices.
503 */
504 static int ALSA_AddCaptureDevice(snd_ctl_t *ctl, snd_pcm_t *pcm, const char *pcmname, int isdefault)
505 {
506     WINE_WAVEDEV    wwi;
507     int rc;
508
509     memset(&wwi, '\0', sizeof(wwi));
510
511     rc = ALSA_AddCommonDevice(ctl, pcm, pcmname, &wwi);
512     if (rc)
513         return(rc);
514
515     MultiByteToWideChar(CP_ACP, 0, wwi.ds_desc.szDesc, -1,
516                         wwi.incaps.szPname, sizeof(wwi.incaps.szPname) / sizeof(WCHAR));
517     wwi.incaps.szPname[sizeof(wwi.incaps.szPname)/sizeof(WCHAR) - 1] = '\0';
518
519     wwi.incaps.wMid = MM_CREATIVE;
520     wwi.incaps.wPid = MM_CREATIVE_SBP16_WAVEOUT;
521     wwi.incaps.vDriverVersion = 0x0100;
522
523     rc = ALSA_ComputeCaps(ctl, pcm, &wwi.incaps.wChannels, &wwi.ds_caps.dwFlags,
524             &wwi.incaps.dwFormats, &wwi.dwSupport);
525     if (rc)
526     {
527         WARN("Error calculating device caps for pcm [%s]\n", wwi.pcmname);
528         ALSA_FreeDevice(&wwi);
529         return(rc);
530     }
531
532     rc = ALSA_AddDeviceToArray(&wwi, &WInDev, &ALSA_WidNumDevs, &ALSA_WidNumMallocedDevs, isdefault);
533     if (rc)
534         ALSA_FreeDevice(&wwi);
535     return(rc);
536 }
537
538 /*----------------------------------------------------------------------------
539 **  ALSA_CheckEnvironment
540 **
541 **      Given an Alsa style configuration node, scan its subitems
542 **  for environment variable names, and use them to find an override,
543 **  if appropriate.
544 **      This is essentially a long and convolunted way of doing:
545 **          getenv("ALSA_CARD")
546 **          getenv("ALSA_CTL_CARD")
547 **          getenv("ALSA_PCM_CARD")
548 **          getenv("ALSA_PCM_DEVICE")
549 **
550 **  The output value is set with the atoi() of the first environment
551 **  variable found to be set, if any; otherwise, it is left alone
552 */
553 static void ALSA_CheckEnvironment(snd_config_t *node, int *outvalue)
554 {
555     snd_config_iterator_t iter;
556
557     for (iter = snd_config_iterator_first(node);
558          iter != snd_config_iterator_end(node);
559          iter = snd_config_iterator_next(iter))
560     {
561         snd_config_t *leaf = snd_config_iterator_entry(iter);
562         if (snd_config_get_type(leaf) == SND_CONFIG_TYPE_STRING)
563         {
564             const char *value;
565             if (snd_config_get_string(leaf, &value) >= 0)
566             {
567                 char *p = getenv(value);
568                 if (p)
569                 {
570                     *outvalue = atoi(p);
571                     return;
572                 }
573             }
574         }
575     }
576 }
577
578 /*----------------------------------------------------------------------------
579 **  ALSA_DefaultDevices
580 **
581 **      Jump through Alsa style hoops to (hopefully) properly determine
582 **  Alsa defaults for CTL Card #, as well as for PCM Card + Device #.
583 **  We'll also find out if the user has set any of the environment
584 **  variables that specify we're to use a specific card or device.
585 **
586 **  Parameters:
587 **      directhw        Whether to use a direct hardware device or not;
588 **                      essentially switches the pcm device name from
589 **                      one of 'default:X' or 'plughw:X' to "hw:X"
590 **      defctlcard      If !NULL, will hold the ctl card number given
591 **                      by the ALSA config as the default
592 **      defpcmcard      If !NULL, default pcm card #
593 **      defpcmdev       If !NULL, default pcm device #
594 **      fixedctlcard    If !NULL, and the user set the appropriate
595 **                          environment variable, we'll set to the
596 **                          card the user specified.
597 **      fixedpcmcard    If !NULL, and the user set the appropriate
598 **                          environment variable, we'll set to the
599 **                          card the user specified.
600 **      fixedpcmdev     If !NULL, and the user set the appropriate
601 **                          environment variable, we'll set to the
602 **                          device the user specified.
603 **
604 **  Returns:  0 on success, < 0 on failiure
605 */
606 static int ALSA_DefaultDevices(int directhw,
607             long *defctlcard,
608             long *defpcmcard, long *defpcmdev,
609             int *fixedctlcard,
610             int *fixedpcmcard, int *fixedpcmdev)
611 {
612     snd_config_t   *configp;
613     char pcmsearch[256];
614
615     ALSA_RETURN_ONFAIL(snd_config_update());
616
617     if (defctlcard)
618         if (snd_config_search(snd_config, "defaults.ctl.card", &configp) >= 0)
619             snd_config_get_integer(configp, defctlcard);
620
621     if (defpcmcard)
622         if (snd_config_search(snd_config, "defaults.pcm.card", &configp) >= 0)
623             snd_config_get_integer(configp, defpcmcard);
624
625     if (defpcmdev)
626         if (snd_config_search(snd_config, "defaults.pcm.device", &configp) >= 0)
627             snd_config_get_integer(configp, defpcmdev);
628
629
630     if (fixedctlcard)
631     {
632         if (snd_config_search(snd_config, "ctl.hw.@args.CARD.default.vars", &configp) >= 0)
633             ALSA_CheckEnvironment(configp, fixedctlcard);
634     }
635
636     if (fixedpcmcard)
637     {
638         sprintf(pcmsearch, "pcm.%s.@args.CARD.default.vars", directhw ? "hw" : "plughw");
639         if (snd_config_search(snd_config, pcmsearch, &configp) >= 0)
640             ALSA_CheckEnvironment(configp, fixedpcmcard);
641     }
642
643     if (fixedpcmdev)
644     {
645         sprintf(pcmsearch, "pcm.%s.@args.DEV.default.vars", directhw ? "hw" : "plughw");
646         if (snd_config_search(snd_config, pcmsearch, &configp) >= 0)
647             ALSA_CheckEnvironment(configp, fixedpcmdev);
648     }
649
650     return 0;
651 }
652
653
654 /*----------------------------------------------------------------------------
655 **  ALSA_ScanDevices
656 **
657 **      Iterate through all discoverable ALSA cards, searching
658 **  for usable PCM devices.
659 **
660 **  Parameters:
661 **      directhw        Whether to use a direct hardware device or not;
662 **                      essentially switches the pcm device name from
663 **                      one of 'default:X' or 'plughw:X' to "hw:X"
664 **      defctlcard      Alsa's notion of the default ctl card.
665 **      defpcmcard         . pcm card
666 **      defpcmdev          . pcm device
667 **      fixedctlcard    If not -1, then gives the value of ALSA_CTL_CARD
668 **                          or equivalent environment variable
669 **      fixedpcmcard    If not -1, then gives the value of ALSA_PCM_CARD
670 **                          or equivalent environment variable
671 **      fixedpcmdev     If not -1, then gives the value of ALSA_PCM_DEVICE
672 **                          or equivalent environment variable
673 **
674 **  Returns:  0 on success, < 0 on failiure
675 */
676 static int ALSA_ScanDevices(int directhw,
677         long defctlcard, long defpcmcard, long defpcmdev,
678         int fixedctlcard, int fixedpcmcard, int fixedpcmdev)
679 {
680     int card = fixedpcmcard;
681     int scan_devices = (fixedpcmdev == -1);
682
683     /*------------------------------------------------------------------------
684     ** Loop through all available cards
685     **----------------------------------------------------------------------*/
686     if (card == -1)
687         snd_card_next(&card);
688
689     for (; card != -1; snd_card_next(&card))
690     {
691         char ctlname[256];
692         snd_ctl_t *ctl;
693         int rc;
694         int device;
695
696         /*--------------------------------------------------------------------
697         ** Try to open a ctl handle; Wine doesn't absolutely require one,
698         **  but it does allow for volume control and for device scanning
699         **------------------------------------------------------------------*/
700         sprintf(ctlname, "default:%d", fixedctlcard == -1 ? card : fixedctlcard);
701         rc = snd_ctl_open(&ctl, ctlname, SND_CTL_NONBLOCK);
702         if (rc < 0)
703         {
704             sprintf(ctlname, "hw:%d", fixedctlcard == -1 ? card : fixedctlcard);
705             rc = snd_ctl_open(&ctl, ctlname, SND_CTL_NONBLOCK);
706         }
707         if (rc < 0)
708         {
709             ctl = NULL;
710             WARN("Unable to open an alsa ctl for [%s] (pcm card %d): %s; not scanning devices\n",
711                     ctlname, card, snd_strerror(rc));
712             if (fixedpcmdev == -1)
713                 fixedpcmdev = 0;
714         }
715
716         /*--------------------------------------------------------------------
717         ** Loop through all available devices on this card
718         **------------------------------------------------------------------*/
719         device = fixedpcmdev;
720         if (device == -1)
721             snd_ctl_pcm_next_device(ctl, &device);
722
723         for (; device != -1; snd_ctl_pcm_next_device(ctl, &device))
724         {
725             char defaultpcmname[256];
726             char plugpcmname[256];
727             char hwpcmname[256];
728             char *pcmname = NULL;
729             snd_pcm_t *pcm;
730
731             sprintf(defaultpcmname, "default:%d", card);
732             sprintf(plugpcmname,    "plughw:%d,%d", card, device);
733             sprintf(hwpcmname,      "hw:%d,%d", card, device);
734
735             /*----------------------------------------------------------------
736             ** See if it's a valid playback device
737             **--------------------------------------------------------------*/
738             if (ALSA_TestDeviceForWine(card, device, SND_PCM_STREAM_PLAYBACK) == 0)
739             {
740                 /* If we can, try the default:X device name first */
741                 if (! scan_devices && ! directhw)
742                 {
743                     pcmname = defaultpcmname;
744                     rc = snd_pcm_open(&pcm, pcmname, SND_PCM_STREAM_PLAYBACK, SND_PCM_NONBLOCK);
745                 }
746                 else
747                     rc = -1;
748
749                 if (rc < 0)
750                 {
751                     pcmname = directhw ? hwpcmname : plugpcmname;
752                     rc = snd_pcm_open(&pcm, pcmname, SND_PCM_STREAM_PLAYBACK, SND_PCM_NONBLOCK);
753                 }
754
755                 if (rc >= 0)
756                 {
757                     if (defctlcard == card && defpcmcard == card && defpcmdev == device)
758                         ALSA_AddPlaybackDevice(ctl, pcm, pcmname, TRUE);
759                     else
760                         ALSA_AddPlaybackDevice(ctl, pcm, pcmname, FALSE);
761                     snd_pcm_close(pcm);
762                 }
763                 else
764                 {
765                     TRACE("Device [%s/%s] failed to open for playback: %s\n",
766                         directhw || scan_devices ? "(N/A)" : defaultpcmname,
767                         directhw ? hwpcmname : plugpcmname,
768                         snd_strerror(rc));
769                 }
770             }
771
772             /*----------------------------------------------------------------
773             ** See if it's a valid capture device
774             **--------------------------------------------------------------*/
775             if (ALSA_TestDeviceForWine(card, device, SND_PCM_STREAM_CAPTURE) == 0)
776             {
777                 /* If we can, try the default:X device name first */
778                 if (! scan_devices && ! directhw)
779                 {
780                     pcmname = defaultpcmname;
781                     rc = snd_pcm_open(&pcm, pcmname, SND_PCM_STREAM_CAPTURE, SND_PCM_NONBLOCK);
782                 }
783                 else
784                     rc = -1;
785
786                 if (rc < 0)
787                 {
788                     pcmname = directhw ? hwpcmname : plugpcmname;
789                     rc = snd_pcm_open(&pcm, pcmname, SND_PCM_STREAM_CAPTURE, SND_PCM_NONBLOCK);
790                 }
791
792                 if (rc >= 0)
793                 {
794                     if (defctlcard == card && defpcmcard == card && defpcmdev == device)
795                         ALSA_AddCaptureDevice(ctl, pcm, pcmname, TRUE);
796                     else
797                         ALSA_AddCaptureDevice(ctl, pcm, pcmname, FALSE);
798
799                     snd_pcm_close(pcm);
800                 }
801                 else
802                 {
803                     TRACE("Device [%s/%s] failed to open for capture: %s\n",
804                         directhw || scan_devices ? "(N/A)" : defaultpcmname,
805                         directhw ? hwpcmname : plugpcmname,
806                         snd_strerror(rc));
807                 }
808             }
809
810             if (! scan_devices)
811                 break;
812         }
813
814         if (ctl)
815             snd_ctl_close(ctl);
816
817         /*--------------------------------------------------------------------
818         ** If the user has set env variables such that we're pegged to
819         **  a specific card, then break after we've examined it
820         **------------------------------------------------------------------*/
821         if (fixedpcmcard != -1)
822             break;
823     }
824
825     return 0;
826
827 }
828
829 /*----------------------------------------------------------------------------
830 ** ALSA_PerformDefaultScan
831 **  Perform the basic default scanning for devices within ALSA.
832 **  The hope is that this routine implements a 'correct'
833 **  scanning algorithm from the Alsalib point of view.
834 **
835 **      Note that Wine, overall, has other mechanisms to
836 **  override and specify exact CTL and PCM device names,
837 **  but this routine is imagined as the default that
838 **  99% of users will use.
839 **
840 **      The basic algorithm is simple:
841 **  Use snd_card_next to iterate cards; within cards, use
842 **  snd_ctl_pcm_next_device to iterate through devices.
843 **
844 **      We add a little complexity by taking into consideration
845 **  environment variables such as ALSA_CARD (et all), and by
846 **  detecting when a given device matches the default specified
847 **  by Alsa.
848 **
849 **  Parameters:
850 **      directhw        If !0, indicates we should use the hw:X
851 **                      PCM interface, rather than first try
852 **                      the 'default' device followed by the plughw
853 **                      device.  (default and plughw do fancy mixing
854 **                      and audio scaling, if they are available).
855 **      devscan         If TRUE, we should scan all devices, not
856 **                      juse use device 0 on each card
857 **
858 **  Returns:
859 **      0   on success
860 **
861 **  Effects:
862 **      Invokes the ALSA_AddXXXDevice functions on valid
863 **  looking devices
864 */
865 static int ALSA_PerformDefaultScan(int directhw, BOOL devscan)
866 {
867     long defctlcard = -1, defpcmcard = -1, defpcmdev = -1;
868     int fixedctlcard = -1, fixedpcmcard = -1, fixedpcmdev = -1;
869     int rc;
870
871     /* FIXME:  We should dlsym the new snd_names_list/snd_names_list_free 1.0.9 apis,
872     **          and use them instead of this scan mechanism if they are present         */
873
874     rc = ALSA_DefaultDevices(directhw, &defctlcard, &defpcmcard, &defpcmdev,
875             &fixedctlcard, &fixedpcmcard, &fixedpcmdev);
876     if (rc)
877         return(rc);
878
879     if (fixedpcmdev == -1 && ! devscan)
880         fixedpcmdev = 0;
881
882     return(ALSA_ScanDevices(directhw, defctlcard, defpcmcard, defpcmdev, fixedctlcard, fixedpcmcard, fixedpcmdev));
883 }
884
885
886 /*----------------------------------------------------------------------------
887 ** ALSA_AddUserSpecifiedDevice
888 **  Add a device given from the registry
889 */
890 static int ALSA_AddUserSpecifiedDevice(const char *ctlname, const char *pcmname)
891 {
892     int rc;
893     int okay = 0;
894     snd_ctl_t *ctl = NULL;
895     snd_pcm_t *pcm = NULL;
896
897     if (ctlname)
898     {
899         rc = snd_ctl_open(&ctl, ctlname, SND_CTL_NONBLOCK);
900         if (rc < 0)
901             ctl = NULL;
902     }
903
904     rc = snd_pcm_open(&pcm, pcmname, SND_PCM_STREAM_PLAYBACK, SND_PCM_NONBLOCK);
905     if (rc >= 0)
906     {
907         ALSA_AddPlaybackDevice(ctl, pcm, pcmname, FALSE);
908         okay++;
909         snd_pcm_close(pcm);
910     }
911
912     rc = snd_pcm_open(&pcm, pcmname, SND_PCM_STREAM_CAPTURE, SND_PCM_NONBLOCK);
913     if (rc >= 0)
914     {
915         ALSA_AddCaptureDevice(ctl, pcm, pcmname, FALSE);
916         okay++;
917         snd_pcm_close(pcm);
918     }
919
920     if (ctl)
921         snd_ctl_close(ctl);
922
923     return (okay == 0);
924 }
925
926
927 /*----------------------------------------------------------------------------
928 ** ALSA_WaveInit
929 **  Initialize the Wine Alsa sub system.
930 ** The main task is to probe for and store a list of all appropriate playback
931 ** and capture devices.
932 **  Key control points are from the registry key:
933 **  [Software\Wine\Alsa Driver]
934 **  AutoScanCards           Whether or not to scan all known sound cards
935 **                          and add them to Wine's list (default yes)
936 **  AutoScanDevices         Whether or not to scan all known PCM devices
937 **                          on each card (default no)
938 **  UseDirectHW             Whether or not to use the hw:X device,
939 **                          instead of the fancy default:X or plughw:X device.
940 **                          The hw:X device goes straight to the hardware
941 **                          without any fancy mixing or audio scaling in between.
942 **  DeviceCount             If present, specifies the number of hard coded
943 **                          Alsa devices to add to Wine's list; default 0
944 **  DevicePCMn              Specifies the Alsa PCM devices to open for
945 **                          Device n (where n goes from 1 to DeviceCount)
946 **  DeviceCTLn              Specifies the Alsa control devices to open for
947 **                          Device n (where n goes from 1 to DeviceCount)
948 **
949 **                          Using AutoScanCards no, and then Devicexxx info
950 **                          is a way to exactly specify the devices used by Wine.
951 **
952 */
953 LONG ALSA_WaveInit(void)
954 {
955     DWORD rc;
956     BOOL  AutoScanCards = TRUE;
957     BOOL  AutoScanDevices = FALSE;
958     BOOL  UseDirectHW = FALSE;
959     DWORD DeviceCount = 0;
960     HKEY  key = 0;
961     int   i;
962
963     if (!wine_dlopen("libasound.so.2", RTLD_LAZY|RTLD_GLOBAL, NULL, 0))
964     {
965         ERR("Error: ALSA lib needs to be loaded with flags RTLD_LAZY and RTLD_GLOBAL.\n");
966         return -1;
967     }
968
969     /* @@ Wine registry key: HKCU\Software\Wine\Alsa Driver */
970     rc = RegOpenKeyExA(HKEY_CURRENT_USER, "Software\\Wine\\Alsa Driver", 0, KEY_QUERY_VALUE, &key);
971     if (rc == ERROR_SUCCESS)
972     {
973         ALSA_RegGetBoolean(key, "AutoScanCards", &AutoScanCards);
974         ALSA_RegGetBoolean(key, "AutoScanDevices", &AutoScanDevices);
975         ALSA_RegGetBoolean(key, "UseDirectHW", &UseDirectHW);
976         ALSA_RegGetInt(key, "DeviceCount", &DeviceCount);
977     }
978
979     if (AutoScanCards)
980         rc = ALSA_PerformDefaultScan(UseDirectHW, AutoScanDevices);
981
982     for (i = 0; i < DeviceCount; i++)
983     {
984         char *ctl_name = NULL;
985         char *pcm_name = NULL;
986         char value[30];
987
988         sprintf(value, "DevicePCM%d", i + 1);
989         if (ALSA_RegGetString(key, value, &pcm_name) == ERROR_SUCCESS)
990         {
991             sprintf(value, "DeviceCTL%d", i + 1);
992             ALSA_RegGetString(key, value, &ctl_name);
993             ALSA_AddUserSpecifiedDevice(ctl_name, pcm_name);
994         }
995
996         HeapFree(GetProcessHeap(), 0, ctl_name);
997         HeapFree(GetProcessHeap(), 0, pcm_name);
998     }
999
1000     if (key)
1001         RegCloseKey(key);
1002
1003     return (rc);
1004 }
1005
1006 #endif /* HAVE_ALSA */