Intel 8x0 and ALSA sound driver

Nikolay Stefanov nstefanov at cs.man.ac.uk
Sun Dec 8 09:24:40 CST 2002


Hi,

I have a SIS SI7012 (Intel 810 chipset) built-in audio card, which turns out 
to be capable of only 48000Hz sample rate in hardware. The ALSA winmm driver 
in Wine is hardcoded to use the first hardware pcm device ("hw:0") directly, 
and therefore fails for any wave format request with a sample rate different 
than 48000Hz. I have lifted some code from dsound and put together a patch 
which adds the option to read the device name from the Wine configuration 
file. As a result I have now got Winamp working (hurray for me!).

HOWEVER there are still issues - the "default" ALSA device doesn't like the 
way Wine accesses it through mmap, and also it seems that it is not possible 
to set the buffer size and period size the way it is done now. Other programs 
that use ALSA, like aplay and mplayer, don't have this problem. My knowledge 
of Wine and ALSA is pretty meagre, so can anyone can provide any insight as 
to how to fix this issue?

My config file now looks like this
[alsa]
;"Device" = "hw:0"
"Device" = "default"
"UseMMAP" = "N"

And this is the patch, not really useful for anyone else but me right now:

---- Patch start -----

diff -u -r wine-20021125-orig/dlls/winmm/winealsa/Makefile.in 
wine-20021125/dlls/winmm/winealsa/Makefile.in
--- wine-20021125-orig/dlls/winmm/winealsa/Makefile.in	2002-06-28 
19:31:01.000000000 +0100
+++ wine-20021125/dlls/winmm/winealsa/Makefile.in	2002-12-08 
14:06:03.000000000 +0000
@@ -3,7 +3,7 @@
 SRCDIR    = @srcdir@
 VPATH     = @srcdir@
 MODULE    = winealsa.drv
-IMPORTS   = winmm user32 kernel32 ntdll
+IMPORTS   = winmm user32 kernel32 ntdll advapi32
 EXTRALIBS = @ALSALIBS@
 
 LDDLLFLAGS = @LDDLLFLAGS@
diff -u -r wine-20021125-orig/dlls/winmm/winealsa/alsa.c 
wine-20021125/dlls/winmm/winealsa/alsa.c
--- wine-20021125-orig/dlls/winmm/winealsa/alsa.c	2002-07-19 
01:30:16.000000000 +0100
+++ wine-20021125/dlls/winmm/winealsa/alsa.c	2002-12-08 14:52:38.000000000 
+0000
@@ -25,12 +25,93 @@
 #include "winbase.h"
 #include "wingdi.h"
 #include "winuser.h"
+#include "winreg.h"
 #include "mmddk.h"
 #include "alsa.h"
+#include "wine/debug.h"
 
 #ifdef HAVE_ALSA
 
+WINE_DEFAULT_DEBUG_CHANNEL(wave);
+
 static	struct WINE_ALSA* alsa = NULL;
+	
+/* configuration variables for the ALSA driver */
+#define ALSA_DEVICE_NAME_DEFAULT "hw:0"
+#define ALSA_USE_MMAP_DEFAULT    1
+char  alsa_device_name[MAX_PATH+1];
+int   alsa_use_mmap = 1;
+
+/*
+ * Get a config key from either the app-specific or the default config
+ */
+inline static DWORD get_config_key( HKEY defkey, HKEY appkey, const char 
*name,
+                                    char *buffer, DWORD size )
+{
+    if (appkey && !RegQueryValueExA( appkey, name, 0, NULL, buffer, &size )) 
return 0;
+    return RegQueryValueExA( defkey, name, 0, NULL, buffer, &size );
+}
+
+
+/*
+ * Setup the alsa options.
+ */
+inline static void setup_alsa_options(void)
+{
+    char buffer[MAX_PATH+1];
+    HKEY hkey, appkey = 0;
+
+    buffer[MAX_PATH]='\0';
+
+    if (RegCreateKeyExA( HKEY_LOCAL_MACHINE, 
"Software\\Wine\\Wine\\Config\\alsa", 0, NULL,
+                         REG_OPTION_VOLATILE, KEY_ALL_ACCESS, NULL, &hkey, 
NULL ))
+    {
+        ERR("Cannot create config registry key\n" );
+        ExitProcess(1);
+    }
+
+    if (GetModuleFileNameA( 0, buffer, MAX_PATH ))
+    {
+        HKEY tmpkey;
+
+        if (!RegOpenKeyA( HKEY_LOCAL_MACHINE, 
"Software\\Wine\\Wine\\Config\\AppDefaults", &tmpkey ))
+        {
+           char appname[MAX_PATH+16];
+           char *p = strrchr( buffer, '\\' );
+           if (p!=NULL) {
+                   appname[MAX_PATH]='\0';
+                   strncpy(appname,p+1,MAX_PATH);
+                   strcat(appname,"\\alsa");
+                   TRACE("appname = [%s] \n",appname);
+                   if (RegOpenKeyA( tmpkey, appname, &appkey )) appkey = 0;
+                       RegCloseKey( tmpkey );
+           }
+        }
+    }
+
+    /* get options */
+    strncpy(alsa_device_name, ALSA_DEVICE_NAME_DEFAULT, MAX_PATH);
+    if (!get_config_key( hkey, appkey, "Device", buffer, MAX_PATH )) {
+	alsa_device_name[MAX_PATH] = '\0';
+        strncpy(alsa_device_name, buffer, MAX_PATH);
+	if (strncmp(alsa_device_name, ALSA_DEVICE_NAME_DEFAULT, MAX_PATH)) {
+	   WARN("alsa_device_name = %s (default=" ALSA_DEVICE_NAME_DEFAULT ")\n",
+	       alsa_device_name);
+	}
+    }
+
+    alsa_use_mmap = ALSA_USE_MMAP_DEFAULT;
+    if (!get_config_key( hkey, appkey, "UseMMAP", buffer, MAX_PATH )) {
+        alsa_use_mmap = strcmp(buffer, "N");
+	if (alsa_use_mmap != ALSA_USE_MMAP_DEFAULT) {
+	   WARN("alsa_use_mmap = %d (default=%d)\n", alsa_use_mmap,
+		ALSA_USE_MMAP_DEFAULT);
+	}
+    }
+
+    if (appkey) RegCloseKey( appkey );
+    RegCloseKey( hkey );
+}
 
 /**************************************************************************
  * 				ALSA_drvOpen			[internal]
@@ -39,7 +120,7 @@
 {
     if (alsa)
 	return 0;
-
+    
     /* I know, this is ugly, but who cares... */
     alsa = (struct WINE_ALSA*)1;
     return 1;
@@ -71,7 +152,8 @@
 
     switch(wMsg) {
 #ifdef HAVE_ALSA
-    case DRV_LOAD:		ALSA_WaveInit();
+    case DRV_LOAD:		setup_alsa_options();
+				ALSA_WaveInit();
 				return 1;
     case DRV_FREE:		return 1;
     case DRV_OPEN:		return ALSA_drvOpen((LPSTR)dwParam1);
diff -u -r wine-20021125-orig/dlls/winmm/winealsa/alsa.h 
wine-20021125/dlls/winmm/winealsa/alsa.h
--- wine-20021125-orig/dlls/winmm/winealsa/alsa.h	2002-08-29 
02:51:32.000000000 +0100
+++ wine-20021125/dlls/winmm/winealsa/alsa.h	2002-12-08 14:19:06.000000000 
+0000
@@ -29,3 +29,6 @@
 #endif
 
 extern LONG ALSA_WaveInit(void);
+/* config options */
+extern char alsa_device_name[];
+extern int  alsa_use_mmap;
Only in wine-20021125/dlls/winmm/winealsa: alsa.o
diff -u -r wine-20021125-orig/dlls/winmm/winealsa/audio.c 
wine-20021125/dlls/winmm/winealsa/audio.c
--- wine-20021125-orig/dlls/winmm/winealsa/audio.c	2002-10-25 
20:09:02.000000000 +0100
+++ wine-20021125/dlls/winmm/winealsa/audio.c	2002-12-08 14:32:16.000000000 
+0000
@@ -217,13 +217,13 @@
     } \
 } while(0)
 
-    EXIT_ON_ERROR( snd_ctl_open(&ctl,"hw:0",0) , "ctl open failed" );
+    EXIT_ON_ERROR( snd_ctl_open(&ctl,alsa_device_name,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",0), "hctl open failed");
+    EXIT_ON_ERROR( snd_hctl_open(&hctl,alsa_device_name,0), "hctl open 
failed");
     EXIT_ON_ERROR( snd_hctl_load(hctl), "hctl load failed" );
 
     elem=snd_hctl_first_elem(hctl);
@@ -404,8 +404,9 @@
 
     wwo = &WOutDev[0];
 
+    TRACE("ALSA_WaveInit device name = %s", alsa_device_name);
     /* FIXME: use better values */
-    wwo->device = "hw:0,0";
+    wwo->device = alsa_device_name;
     wwo->caps.wMid = 0x0002;
     wwo->caps.wPid = 0x0104;
     strcpy(wwo->caps.szPname, "SB16 Wave Out");
@@ -495,7 +496,7 @@
 	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 ) )
+	if ( alsa_use_mmap && snd_pcm_access_mask_test( acmask, 
SND_PCM_ACCESS_MMAP_INTERLEAVED ) )
             wwo->caps.dwSupport |= WAVECAPS_DIRECTSOUND;
     }
 
@@ -1114,7 +1115,7 @@
 } while(0)
 
     access = SND_PCM_ACCESS_MMAP_INTERLEAVED;
-    if ( ( err = snd_pcm_hw_params_set_access(pcm, hw_params, access ) ) < 0) 
{
+    if (!alsa_use_mmap || ((err = snd_pcm_hw_params_set_access(pcm, 
hw_params, access)) < 0)) {
         WARN("mmap not available. switching to standard write.\n");
         access = SND_PCM_ACCESS_RW_INTERLEAVED;
 	EXIT_ON_ERROR( snd_pcm_hw_params_set_access(pcm, hw_params, access ), 
MMSYSERR_INVALPARAM, "unable to set access for playback");
@@ -1128,11 +1129,13 @@
     format = (wwo->format.wBitsPerSample == 16) ? SND_PCM_FORMAT_S16_LE : 
SND_PCM_FORMAT_U8;
     EXIT_ON_ERROR( snd_pcm_hw_params_set_format(pcm, hw_params, format), 
MMSYSERR_INVALPARAM, "unable to set required format");
 
+#if 0
     EXIT_ON_ERROR( snd_pcm_hw_params_set_buffer_size_near(pcm, hw_params, 
buffer_size), MMSYSERR_NOMEM, "unable to get required buffer");
     buffer_size = snd_pcm_hw_params_get_buffer_size(hw_params);
 
     EXIT_ON_ERROR( snd_pcm_hw_params_set_period_size_near(pcm, hw_params, 
buffer_size/num_periods, 0), MMSYSERR_ERROR, "unable to set required period 
size");
     period_size = snd_pcm_hw_params_get_period_size(hw_params, 0);
+#endif
 
     rate = snd_pcm_hw_params_set_rate_near(pcm, hw_params, 
wwo->format.wf.nSamplesPerSec, 0);
     if (rate < 0) {
@@ -1147,6 +1150,11 @@
     }
 
     EXIT_ON_ERROR( snd_pcm_hw_params(pcm, hw_params), MMSYSERR_INVALPARAM, 
"unable to set hw params for playback");
+    
+#if 1
+    buffer_size = snd_pcm_hw_params_get_buffer_size(hw_params);
+    period_size = snd_pcm_hw_params_get_period_size(hw_params, 0);
+#endif    
 
     snd_pcm_sw_params_current(pcm, sw_params);
     EXIT_ON_ERROR( snd_pcm_sw_params_set_start_threshold(pcm, sw_params, 
dwFlags & WAVE_DIRECTSOUND ? INT_MAX : 1 ), MMSYSERR_ERROR, "unable to set 
start threshold");




More information about the wine-devel mailing list