This patch adds multiple sound card support to the ALSA driver.
My system shows 3 sound devices: a builtin sound card,
a builtin modem and a usb sound card.
The wave regression tests have problems with the modem.
I'm not sure it is an ALSA problem or a problem with this
patch.
Could someone familiar with ALSA look this patch over.
I would also like feedback from any brave testers that have
multiple sound cards.
Thanks.
Index: dlls/winmm/winealsa/audio.c
===================================================================
RCS file: /home/wine/wine/dlls/winmm/winealsa/audio.c,v
retrieving revision 1.65
diff -u -p -r1.65 audio.c
--- dlls/winmm/winealsa/audio.c 17 Mar 2005 18:54:20 -0000 1.65
+++ dlls/winmm/winealsa/audio.c 17 Mar 2005 20:51:58 -0000
@@ -74,8 +74,8 @@ WINE_DEFAULT_DEBUG_CHANNEL(wave);
snd_pcm_uframes_t _snd_pcm_mmap_hw_ptr(snd_pcm_t *pcm);
-#define MAX_WAVEOUTDRV (1)
-#define MAX_WAVEINDRV (1)
+#define MAX_WAVEOUTDRV (6)
+#define MAX_WAVEINDRV (6)
/* state diagram for waveOut writing:
*
@@ -389,6 +389,7 @@ static int ALSA_InitializeVolumeCtl(WINE
snd_hctl_elem_t * elem;
int nCtrls;
int i;
+ char device[8];
snd_ctl_card_info_alloca(&cardinfo);
memset(cardinfo,0,snd_ctl_card_info_sizeof());
@@ -416,13 +417,15 @@ static int ALSA_InitializeVolumeCtl(WINE
} \
} while(0)
- EXIT_ON_ERROR( snd_ctl_open(&ctl,"hw",0) , "ctl open failed" );
+ sprintf(device, "hw:%ld", ALSA_WodNumDevs);
+
+ EXIT_ON_ERROR( snd_ctl_open(&ctl,device,0) , "ctl open failed" );
EXIT_ON_ERROR( snd_ctl_card_info(ctl, cardinfo), "card info failed");
EXIT_ON_ERROR( snd_ctl_elem_list(ctl, elemlist), "elem list failed");
nCtrls = snd_ctl_elem_list_get_count(elemlist);
- EXIT_ON_ERROR( snd_hctl_open(&hctl,"hw",0), "hctl open failed");
+ EXIT_ON_ERROR( snd_hctl_open(&hctl,device,0), "hctl open failed");
EXIT_ON_ERROR( snd_hctl_load(hctl), "hctl load failed" );
elem=snd_hctl_first_elem(hctl);
@@ -636,21 +639,21 @@ static char* ALSA_strdup(char *s) {
/******************************************************************
* ALSA_GetDeviceFromReg
*
- * Returns either "default" or reads the registry so the user can
+ * Returns either "plug:hw" or reads the registry so the user can
* override the playback/record device used.
*/
static char *ALSA_GetDeviceFromReg(const char *value)
{
DWORD res;
DWORD type;
- HKEY playbackKey = 0;
+ HKEY key = 0;
char *result = NULL;
DWORD resultSize;
- res = RegOpenKeyExA(HKEY_LOCAL_MACHINE, "Software\\Wine\\Wine\\Config\\ALSA", 0, KEY_QUERY_VALUE, &playbackKey);
+ res = RegOpenKeyExA(HKEY_LOCAL_MACHINE, "Software\\Wine\\Wine\\Config\\ALSA", 0, KEY_QUERY_VALUE, &key);
if (res != ERROR_SUCCESS) goto end;
- res = RegQueryValueExA(playbackKey, value, NULL, &type, NULL, &resultSize);
+ res = RegQueryValueExA(key, value, NULL, &type, NULL, &resultSize);
if (res != ERROR_SUCCESS) goto end;
if (type != REG_SZ) {
@@ -659,11 +662,15 @@ static char *ALSA_GetDeviceFromReg(const
}
result = HeapAlloc(GetProcessHeap(), 0, resultSize);
- res = RegQueryValueExA(playbackKey, value, NULL, NULL, result, &resultSize);
+ res = RegQueryValueExA(key, value, NULL, NULL, result, &resultSize);
end:
- if (!result) result = ALSA_strdup("default");
- if (playbackKey) RegCloseKey(playbackKey);
+ if (!result)
+ result = ALSA_strdup("plug:hw");
+
+ if (key)
+ RegCloseKey(key);
+
return result;
}
@@ -685,24 +692,7 @@ LONG ALSA_WaveInit(void)
int err=0;
WINE_WAVEOUT* wwo;
WINE_WAVEIN* wwi;
- static const WCHAR init_out[] = {'S','B','1','6',' ','W','a','v','e',' ','O','u','t',0};
- static const WCHAR init_in [] = {'S','B','1','6',' ','W','a','v','e',' ','I','n',0};
-
- wwo = &WOutDev[0];
-
- /* FIXME: use better values */
- wwo->device = ALSA_GetDeviceFromReg("PlaybackDevice");
- TRACE("using waveout device \"%s\"\n", wwo->device);
-
- snprintf(wwo->interface_name, sizeof(wwo->interface_name), "winealsa: %s", wwo->device);
-
- wwo->caps.wMid = 0x0002;
- wwo->caps.wPid = 0x0104;
- strcpyW(wwo->caps.szPname, init_out);
- wwo->caps.vDriverVersion = 0x0100;
- wwo->caps.dwFormats = 0x00000000;
- wwo->caps.dwSupport = WAVECAPS_VOLUME;
- strcpy(wwo->ds_desc.szDrvname, "winealsa.drv");
+ int i;
if (!wine_dlopen("libasound.so.2", RTLD_LAZY|RTLD_GLOBAL, NULL, 0))
{
@@ -710,191 +700,226 @@ LONG ALSA_WaveInit(void)
return -1;
}
- snd_pcm_info_alloca(&info);
- snd_pcm_hw_params_alloca(&hw_params);
+ ALSA_WodNumDevs = 0;
-#define EXIT_ON_ERROR(f,txt) do { int err; if ( (err = (f) ) < 0) { ERR(txt ": %s\n", snd_strerror(err)); if (h) snd_pcm_close(h); return -1; } } while(0)
+ for (i = 0; i < MAX_WAVEOUTDRV; i++)
+ {
+ char device[64];
+ char * regdev;
+ WCHAR nameW[64];
+ snd_pcm_format_mask_t * fmask;
+ snd_pcm_access_mask_t * acmask;
- h = NULL;
- ALSA_WodNumDevs = 0;
- EXIT_ON_ERROR( snd_pcm_open(&h, wwo->device, SND_PCM_STREAM_PLAYBACK, SND_PCM_NONBLOCK) , "open pcm" );
- if (!h) return -1;
- ALSA_WodNumDevs++;
-
- EXIT_ON_ERROR( snd_pcm_info(h, info) , "pcm info" );
-
- TRACE("dev=%d id=%s name=%s subdev=%d subdev_name=%s subdev_avail=%d subdev_num=%d stream=%s subclass=%s \n",
- snd_pcm_info_get_device(info),
- snd_pcm_info_get_id(info),
- snd_pcm_info_get_name(info),
- snd_pcm_info_get_subdevice(info),
- snd_pcm_info_get_subdevice_name(info),
- snd_pcm_info_get_subdevices_avail(info),
- snd_pcm_info_get_subdevices_count(info),
- snd_pcm_stream_name(snd_pcm_info_get_stream(info)),
- (snd_pcm_info_get_subclass(info) == SND_PCM_SUBCLASS_GENERIC_MIX ? "GENERIC MIX": "MULTI MIX"));
+ wwo = &WOutDev[ALSA_WodNumDevs];
- strcpy(wwo->ds_desc.szDesc, snd_pcm_info_get_name(info));
- EXIT_ON_ERROR( snd_pcm_hw_params_any(h, hw_params) , "pcm hw params" );
-#undef EXIT_ON_ERROR
+ regdev = ALSA_GetDeviceFromReg("PlaybackDevice");
+ sprintf(device, "%s:%d", regdev, i);
+ HeapFree(GetProcessHeap(), 0, regdev);
+ wwo->device = HeapAlloc(GetProcessHeap(), 0, strlen(device));
+ strcpy(wwo->device, device);
+ TRACE("using waveout device \"%s\"\n", wwo->device);
+
+ snprintf(wwo->interface_name, sizeof(wwo->interface_name), "winealsa: %s", wwo->device);
+
+ wwo->caps.wMid = 0x0002;
+ wwo->caps.wPid = 0x0104;
+ wwo->caps.vDriverVersion = 0x0100;
+ wwo->caps.dwFormats = 0x00000000;
+ wwo->caps.dwSupport = WAVECAPS_VOLUME;
+ strcpy(wwo->ds_desc.szDrvname, "winealsa.drv");
- err = snd_pcm_hw_params_get_rate_min(hw_params, &ratemin, &dir);
- err = snd_pcm_hw_params_get_rate_max(hw_params, &ratemax, &dir);
- err = snd_pcm_hw_params_get_channels_min(hw_params, &chmin);
- err = snd_pcm_hw_params_get_channels_max(hw_params, &chmax);
- if (TRACE_ON(wave))
- ALSA_TraceParameters(hw_params, NULL, TRUE);
+ snd_pcm_info_alloca(&info);
+ snd_pcm_hw_params_alloca(&hw_params);
- {
- snd_pcm_format_mask_t * fmask;
+#define EXIT_ON_ERROR(f,txt) do { int err; if ( (err = (f) ) < 0) { ERR(txt ": %s\n", snd_strerror(err)); if (h) snd_pcm_close(h); return -1; } } while(0)
+
+ h = NULL;
+ snd_pcm_open(&h, wwo->device, SND_PCM_STREAM_PLAYBACK, SND_PCM_NONBLOCK);
+ if (!h)
+ break;
+
+ EXIT_ON_ERROR( snd_pcm_info(h, info) , "pcm info" );
+
+ TRACE("dev=%d id=%s name=%s subdev=%d subdev_name=%s subdev_avail=%d subdev_num=%d stream=%s subclass=%s \n",
+ snd_pcm_info_get_device(info),
+ snd_pcm_info_get_id(info),
+ snd_pcm_info_get_name(info),
+ snd_pcm_info_get_subdevice(info),
+ snd_pcm_info_get_subdevice_name(info),
+ snd_pcm_info_get_subdevices_avail(info),
+ snd_pcm_info_get_subdevices_count(info),
+ snd_pcm_stream_name(snd_pcm_info_get_stream(info)),
+ (snd_pcm_info_get_subclass(info) == SND_PCM_SUBCLASS_GENERIC_MIX ? "GENERIC MIX": "MULTI MIX"));
+
+ strcpy(wwo->ds_desc.szDesc, snd_pcm_info_get_name(info));
+ MultiByteToWideChar(CP_ACP, 0, wwo->ds_desc.szDesc, -1, nameW, sizeof(nameW)/sizeof(WCHAR));
+ strcpyW(wwo->caps.szPname, nameW);
+ EXIT_ON_ERROR( snd_pcm_hw_params_any(h, hw_params) , "pcm hw params" );
+#undef EXIT_ON_ERROR
+
+ err = snd_pcm_hw_params_get_rate_min(hw_params, &ratemin, &dir);
+ err = snd_pcm_hw_params_get_rate_max(hw_params, &ratemax, &dir);
+ err = snd_pcm_hw_params_get_channels_min(hw_params, &chmin);
+ err = snd_pcm_hw_params_get_channels_max(hw_params, &chmax);
+ if (TRACE_ON(wave))
+ ALSA_TraceParameters(hw_params, NULL, TRUE);
snd_pcm_format_mask_alloca(&fmask);
snd_pcm_hw_params_get_format_mask(hw_params, fmask);
#define X(r,v) \
- if ( (r) >= ratemin && ( (r) <= ratemax || ratemax == -1) ) \
- { \
- if (snd_pcm_format_mask_test( fmask, SND_PCM_FORMAT_U8)) \
- { \
+ if ( (r) >= ratemin && ( (r) <= ratemax || ratemax == -1) ) \
+ { \
+ if (snd_pcm_format_mask_test( fmask, SND_PCM_FORMAT_U8)) \
+ { \
if (chmin <= 1 && 1 <= chmax) \
wwo->caps.dwFormats |= WAVE_FORMAT_##v##M08; \
if (chmin <= 2 && 2 <= chmax) \
wwo->caps.dwFormats |= WAVE_FORMAT_##v##S08; \
- } \
- if (snd_pcm_format_mask_test( fmask, SND_PCM_FORMAT_S16_LE)) \
- { \
+ } \
+ if (snd_pcm_format_mask_test( fmask, SND_PCM_FORMAT_S16_LE)) \
+ { \
if (chmin <= 1 && 1 <= chmax) \
wwo->caps.dwFormats |= WAVE_FORMAT_##v##M16; \
if (chmin <= 2 && 2 <= chmax) \
wwo->caps.dwFormats |= WAVE_FORMAT_##v##S16; \
- } \
- }
- X(11025,1);
- X(22050,2);
- X(44100,4);
- X(48000,48);
- X(96000,96);
+ } \
+ }
+ X(11025,1);
+ X(22050,2);
+ X(44100,4);
+ X(48000,48);
+ X(96000,96);
#undef X
- }
- if ( chmin > 1) FIXME("-\n");
- wwo->caps.wChannels = chmax;
- if (chmin <= 2 && 2 <= chmax)
- wwo->caps.dwSupport |= WAVECAPS_LRVOLUME;
+ if (chmin > 1)
+ FIXME("-\n");
+ wwo->caps.wChannels = chmax;
+ if (chmin <= 2 && 2 <= chmax)
+ wwo->caps.dwSupport |= WAVECAPS_LRVOLUME;
- /* FIXME: always true ? */
- wwo->caps.dwSupport |= WAVECAPS_SAMPLEACCURATE;
+ /* FIXME: always true ? */
+ wwo->caps.dwSupport |= WAVECAPS_SAMPLEACCURATE;
- {
- snd_pcm_access_mask_t * acmask;
snd_pcm_access_mask_alloca(&acmask);
snd_pcm_hw_params_get_access_mask(hw_params, acmask);
/* FIXME: NONITERLEAVED and COMPLEX are not supported right now */
if ( snd_pcm_access_mask_test( acmask, SND_PCM_ACCESS_MMAP_INTERLEAVED ) )
wwo->caps.dwSupport |= WAVECAPS_DIRECTSOUND;
- }
- TRACE("Configured with dwFmts=%08lx dwSupport=%08lx\n",
- wwo->caps.dwFormats, wwo->caps.dwSupport);
+ TRACE("Configured with dwFmts=%08lx dwSupport=%08lx\n",
+ wwo->caps.dwFormats, wwo->caps.dwSupport);
- snd_pcm_close(h);
+ snd_pcm_close(h);
- ALSA_InitializeVolumeCtl(wwo);
+ ALSA_InitializeVolumeCtl(wwo);
- wwi = &WInDev[0];
+ ALSA_WodNumDevs++;
+ }
- /* FIXME: use better values */
- wwi->device = ALSA_GetDeviceFromReg("RecordDevice");
- TRACE("using wavein device \"%s\"\n", wwi->device);
+ ALSA_WidNumDevs = 0;
- snprintf(wwi->interface_name, sizeof(wwi->interface_name), "winealsa: %s", wwi->device);
+ for (i = 0; i < MAX_WAVEINDRV; i++)
+ {
+ char device[64];
+ char * regdev;
+ WCHAR nameW[64];
+ snd_pcm_format_mask_t * fmask;
+ snd_pcm_access_mask_t * acmask;
- wwi->caps.wMid = 0x0002;
- wwi->caps.wPid = 0x0104;
- strcpyW(wwi->caps.szPname, init_in);
- wwi->caps.vDriverVersion = 0x0100;
- wwi->caps.dwFormats = 0x00000000;
- wwi->caps.dwSupport = WAVECAPS_VOLUME;
- strcpy(wwi->ds_desc.szDrvname, "winealsa.drv");
+ wwi = &WInDev[ALSA_WidNumDevs];
- snd_pcm_info_alloca(&info);
- snd_pcm_hw_params_alloca(&hw_params);
+ regdev = ALSA_GetDeviceFromReg("CaptureDevice");
+ sprintf(device, "%s:%d", regdev, i);
+ HeapFree(GetProcessHeap(), 0, regdev);
+ wwi->device = HeapAlloc(GetProcessHeap(), 0, strlen(device));
+ strcpy(wwi->device, device);
+
+ TRACE("using wavein device \"%s\"\n", wwi->device);
+
+ snprintf(wwi->interface_name, sizeof(wwi->interface_name), "winealsa: %s", wwi->device);
+
+ wwi->caps.wMid = 0x0002;
+ wwi->caps.wPid = 0x0104;
+ wwi->caps.vDriverVersion = 0x0100;
+ wwi->caps.dwFormats = 0x00000000;
+ wwi->caps.dwSupport = WAVECAPS_VOLUME;
+ strcpy(wwi->ds_desc.szDrvname, "winealsa.drv");
-#define EXIT_ON_ERROR(f,txt) do { int err; if ( (err = (f) ) < 0) { ERR(txt ": %s\n", snd_strerror(err)); if (h) snd_pcm_close(h); return -1; } } while(0)
+ snd_pcm_info_alloca(&info);
+ snd_pcm_hw_params_alloca(&hw_params);
- h = NULL;
- ALSA_WidNumDevs = 0;
- EXIT_ON_ERROR( snd_pcm_open(&h, wwi->device, SND_PCM_STREAM_CAPTURE, SND_PCM_NONBLOCK) , "open pcm" );
- if (!h) return -1;
- ALSA_WidNumDevs++;
-
- EXIT_ON_ERROR( snd_pcm_info(h, info) , "pcm info" );
-
- TRACE("dev=%d id=%s name=%s subdev=%d subdev_name=%s subdev_avail=%d subdev_num=%d stream=%s subclass=%s \n",
- snd_pcm_info_get_device(info),
- snd_pcm_info_get_id(info),
- snd_pcm_info_get_name(info),
- snd_pcm_info_get_subdevice(info),
- snd_pcm_info_get_subdevice_name(info),
- snd_pcm_info_get_subdevices_avail(info),
- snd_pcm_info_get_subdevices_count(info),
- snd_pcm_stream_name(snd_pcm_info_get_stream(info)),
- (snd_pcm_info_get_subclass(info) == SND_PCM_SUBCLASS_GENERIC_MIX ? "GENERIC MIX": "MULTI MIX"));
+#define EXIT_ON_ERROR(f,txt) do { int err; if ( (err = (f) ) < 0) { ERR(txt ": %s\n", snd_strerror(err)); if (h) snd_pcm_close(h); return -1; } } while(0)
- strcpy(wwi->ds_desc.szDesc, snd_pcm_info_get_name(info));
- EXIT_ON_ERROR( snd_pcm_hw_params_any(h, hw_params) , "pcm hw params" );
+ h = NULL;
+ snd_pcm_open(&h, wwi->device, SND_PCM_STREAM_CAPTURE, SND_PCM_NONBLOCK);
+ if (!h)
+ break;
+
+ EXIT_ON_ERROR( snd_pcm_info(h, info) , "pcm info" );
+
+ TRACE("dev=%d id=%s name=%s subdev=%d subdev_name=%s subdev_avail=%d subdev_num=%d stream=%s subclass=%s \n",
+ snd_pcm_info_get_device(info),
+ snd_pcm_info_get_id(info),
+ snd_pcm_info_get_name(info),
+ snd_pcm_info_get_subdevice(info),
+ snd_pcm_info_get_subdevice_name(info),
+ snd_pcm_info_get_subdevices_avail(info),
+ snd_pcm_info_get_subdevices_count(info),
+ snd_pcm_stream_name(snd_pcm_info_get_stream(info)),
+ (snd_pcm_info_get_subclass(info) == SND_PCM_SUBCLASS_GENERIC_MIX ? "GENERIC MIX": "MULTI MIX"));
+
+ strcpy(wwi->ds_desc.szDesc, snd_pcm_info_get_name(info));
+ MultiByteToWideChar(CP_ACP, 0, wwi->ds_desc.szDesc, -1, nameW, sizeof(nameW)/sizeof(WCHAR));
+ strcpyW(wwi->caps.szPname, nameW);
+ EXIT_ON_ERROR( snd_pcm_hw_params_any(h, hw_params) , "pcm hw params" );
#undef EXIT_ON_ERROR
- err = snd_pcm_hw_params_get_rate_min(hw_params, &ratemin, &dir);
- err = snd_pcm_hw_params_get_rate_max(hw_params, &ratemax, &dir);
- err = snd_pcm_hw_params_get_channels_min(hw_params, &chmin);
- err = snd_pcm_hw_params_get_channels_max(hw_params, &chmax);
+ err = snd_pcm_hw_params_get_rate_min(hw_params, &ratemin, &dir);
+ err = snd_pcm_hw_params_get_rate_max(hw_params, &ratemax, &dir);
+ err = snd_pcm_hw_params_get_channels_min(hw_params, &chmin);
+ err = snd_pcm_hw_params_get_channels_max(hw_params, &chmax);
- if (TRACE_ON(wave))
- ALSA_TraceParameters(hw_params, NULL, TRUE);
-
- {
- snd_pcm_format_mask_t * fmask;
+ if (TRACE_ON(wave))
+ ALSA_TraceParameters(hw_params, NULL, TRUE);
snd_pcm_format_mask_alloca(&fmask);
snd_pcm_hw_params_get_format_mask(hw_params, fmask);
#define X(r,v) \
- if ( (r) >= ratemin && ( (r) <= ratemax || ratemax == -1) ) \
- { \
- if (snd_pcm_format_mask_test( fmask, SND_PCM_FORMAT_U8)) \
- { \
+ if ( (r) >= ratemin && ( (r) <= ratemax || ratemax == -1) ) \
+ { \
+ if (snd_pcm_format_mask_test( fmask, SND_PCM_FORMAT_U8)) \
+ { \
if (chmin <= 1 && 1 <= chmax) \
wwi->caps.dwFormats |= WAVE_FORMAT_##v##M08; \
if (chmin <= 2 && 2 <= chmax) \
wwi->caps.dwFormats |= WAVE_FORMAT_##v##S08; \
- } \
- if (snd_pcm_format_mask_test( fmask, SND_PCM_FORMAT_S16_LE)) \
- { \
+ } \
+ if (snd_pcm_format_mask_test( fmask, SND_PCM_FORMAT_S16_LE)) \
+ { \
if (chmin <= 1 && 1 <= chmax) \
wwi->caps.dwFormats |= WAVE_FORMAT_##v##M16; \
if (chmin <= 2 && 2 <= chmax) \
wwi->caps.dwFormats |= WAVE_FORMAT_##v##S16; \
- } \
- }
- X(11025,1);
- X(22050,2);
- X(44100,4);
- X(48000,48);
- X(96000,96);
+ } \
+ }
+ X(11025,1);
+ X(22050,2);
+ X(44100,4);
+ X(48000,48);
+ X(96000,96);
#undef X
- }
- if ( chmin > 1) FIXME("-\n");
- wwi->caps.wChannels = chmax;
- if (chmin <= 2 && 2 <= chmax)
- wwi->caps.dwSupport |= WAVECAPS_LRVOLUME;
+ if (chmin > 1)
+ FIXME("-\n");
+ wwi->caps.wChannels = chmax;
+ if (chmin <= 2 && 2 <= chmax)
+ wwi->caps.dwSupport |= WAVECAPS_LRVOLUME;
- /* FIXME: always true ? */
- wwi->caps.dwSupport |= WAVECAPS_SAMPLEACCURATE;
+ /* FIXME: always true ? */
+ wwi->caps.dwSupport |= WAVECAPS_SAMPLEACCURATE;
- {
- snd_pcm_access_mask_t * acmask;
snd_pcm_access_mask_alloca(&acmask);
snd_pcm_hw_params_get_access_mask(hw_params, acmask);
@@ -904,12 +929,14 @@ LONG ALSA_WaveInit(void)
wwi->caps.dwSupport |= WAVECAPS_DIRECTSOUND;
#endif
}
- }
- TRACE("Configured with dwFmts=%08lx dwSupport=%08lx\n",
- wwi->caps.dwFormats, wwi->caps.dwSupport);
+ TRACE("Configured with dwFmts=%08lx dwSupport=%08lx\n",
+ wwi->caps.dwFormats, wwi->caps.dwSupport);
- snd_pcm_close(h);
+ snd_pcm_close(h);
+
+ ALSA_WidNumDevs++;
+ }
return 0;
}