Commit c4b94b1b authored by Andrew Eikum's avatar Andrew Eikum Committed by Alexandre Julliard

mmdevapi: Automatically select the correct driver.

parent f6890ef0
......@@ -53,7 +53,22 @@ static HINSTANCE instance;
DriverFuncs drvs;
static BOOL load_driver(const WCHAR *name)
static const char *get_priority_string(int prio)
{
switch(prio){
case Priority_Unavailable:
return "Unavailable";
case Priority_Low:
return "Low";
case Priority_Neutral:
return "Neutral";
case Priority_Preferred:
return "Preferred";
}
return "Invalid";
}
static BOOL load_driver(const WCHAR *name, DriverFuncs *driver)
{
WCHAR driver_module[264];
static const WCHAR wineW[] = {'w','i','n','e',0};
......@@ -65,75 +80,89 @@ static BOOL load_driver(const WCHAR *name)
TRACE("Attempting to load %s\n", wine_dbgstr_w(driver_module));
drvs.module = LoadLibraryW(driver_module);
if(!drvs.module){
driver->module = LoadLibraryW(driver_module);
if(!driver->module){
TRACE("Unable to load %s: %u\n", wine_dbgstr_w(driver_module),
GetLastError());
return FALSE;
}
#define LDFC(n) do { drvs.p##n = (void*)GetProcAddress(drvs.module, #n);\
if(!drvs.p##n) { FreeLibrary(drvs.module); return FALSE; } } while(0)
#define LDFC(n) do { driver->p##n = (void*)GetProcAddress(driver->module, #n);\
if(!driver->p##n) { FreeLibrary(driver->module); return FALSE; } } while(0)
LDFC(GetPriority);
LDFC(GetEndpointIDs);
LDFC(GetAudioEndpoint);
LDFC(GetAudioSessionManager);
#undef LDFC
lstrcpyW(drvs.module_name, driver_module);
TRACE("Successfully loaded %s\n", wine_dbgstr_w(driver_module));
driver->priority = driver->pGetPriority();
lstrcpyW(driver->module_name, driver_module);
TRACE("Successfully loaded %s with priority %s\n",
wine_dbgstr_w(driver_module), get_priority_string(driver->priority));
return TRUE;
}
static BOOL init_driver(void)
{
static const WCHAR alsaW[] = {'a','l','s','a',0};
static const WCHAR ossW[] = {'o','s','s',0};
static const WCHAR coreaudioW[] = {'c','o','r','e','a','u','d','i','o',0};
static const WCHAR *default_drivers[] = { alsaW, coreaudioW, ossW };
static const WCHAR drv_key[] = {'S','o','f','t','w','a','r','e','\\',
'W','i','n','e','\\','D','r','i','v','e','r','s',0};
static const WCHAR drv_value[] = {'A','u','d','i','o',0};
static WCHAR default_list[] = {'a','l','s','a',',','o','s','s',',',
'c','o','r','e','a','u','d','i','o',0};
DriverFuncs driver;
HKEY key;
UINT i;
WCHAR reg_list[256], *p, *next, *driver_list = default_list;
if(drvs.module)
return TRUE;
if(RegOpenKeyW(HKEY_CURRENT_USER, drv_key, &key) == ERROR_SUCCESS){
WCHAR driver_name[256], *p, *next;
DWORD size = sizeof(driver_name);
DWORD size = sizeof(reg_list);
if(RegQueryValueExW(key, drv_value, 0, NULL, (BYTE*)driver_name,
if(RegQueryValueExW(key, drv_value, 0, NULL, (BYTE*)reg_list,
&size) == ERROR_SUCCESS){
RegCloseKey(key);
if(driver_name[0] == '\0')
if(reg_list[0] == '\0'){
TRACE("User explicitly chose no driver\n");
RegCloseKey(key);
return TRUE;
for(next = p = driver_name; next; p = next + 1){
next = strchrW(p, ',');
if(next)
*next = '\0';
if(load_driver(p))
return TRUE;
TRACE("Failed to load driver: %s\n", wine_dbgstr_w(driver_name));
}
ERR("No drivers in the registry loaded successfully!\n");
return FALSE;
driver_list = reg_list;
}
RegCloseKey(key);
}
for(i = 0; i < sizeof(default_drivers)/sizeof(*default_drivers); ++i)
if(load_driver(default_drivers[i]))
return TRUE;
TRACE("Loading driver list %s\n", wine_dbgstr_w(driver_list));
for(next = p = driver_list; next; p = next + 1){
next = strchrW(p, ',');
if(next)
*next = '\0';
driver.priority = Priority_Unavailable;
if(load_driver(p, &driver)){
if(driver.priority == Priority_Unavailable)
FreeLibrary(driver.module);
else if(!drvs.module || driver.priority > drvs.priority){
TRACE("Selecting driver %s with priority %s\n",
wine_dbgstr_w(p), get_priority_string(driver.priority));
if(drvs.module)
FreeLibrary(drvs.module);
drvs = driver;
}else
FreeLibrary(driver.module);
}else
TRACE("Failed to load driver %s\n", wine_dbgstr_w(p));
if(next)
*next = ',';
}
return FALSE;
return drvs.module ? TRUE : FALSE;
}
BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
......
......@@ -25,9 +25,24 @@ extern void MMDevEnum_Free(void) DECLSPEC_HIDDEN;
extern HRESULT MMDevice_GetPropValue(const GUID *devguid, DWORD flow, REFPROPERTYKEY key, PROPVARIANT *pv) DECLSPEC_HIDDEN;
/* Changes to this enum must be synced in drivers. */
enum _DriverPriority {
Priority_Unavailable = 0, /* driver won't work */
Priority_Low, /* driver may work, but unlikely */
Priority_Neutral, /* driver makes no judgment */
Priority_Preferred /* driver thinks it's correct */
};
typedef struct _DriverFuncs {
HMODULE module;
WCHAR module_name[64];
int priority;
/* Returns a "priority" value for the driver. Highest priority wins.
* If multiple drivers think they are valid, they will return a
* priority value reflecting the likelihood that they are actually
* valid. See enum _DriverPriority. */
int WINAPI (*pGetPriority)(void);
/* ids gets an array of human-friendly endpoint names
* keys gets an array of driver-specific stuff that is used
......
......@@ -223,6 +223,19 @@ BOOL WINAPI DllMain(HINSTANCE dll, DWORD reason, void *reserved)
return TRUE;
}
/* From <dlls/mmdevapi/mmdevapi.h> */
enum DriverPriority {
Priority_Unavailable = 0,
Priority_Low,
Priority_Neutral,
Priority_Preferred
};
int WINAPI AUDDRV_GetPriority(void)
{
return Priority_Neutral;
}
static HRESULT alsa_get_card_devices(EDataFlow flow, WCHAR **ids, char **keys,
UINT *num, snd_ctl_t *ctl, int card, const WCHAR *cardnameW)
{
......
......@@ -7,6 +7,7 @@
@ stdcall -private wodMessage(long long long long long) ALSA_wodMessage
# MMDevAPI driver functions
@ stdcall -private GetPriority() AUDDRV_GetPriority
@ stdcall -private GetEndpointIDs(long ptr ptr ptr ptr) AUDDRV_GetEndpointIDs
@ stdcall -private GetAudioEndpoint(ptr ptr long ptr) AUDDRV_GetAudioEndpoint
@ stdcall -private GetAudioSessionManager(ptr ptr) AUDDRV_GetAudioSessionManager
......@@ -242,6 +242,19 @@ BOOL WINAPI DllMain(HINSTANCE dll, DWORD reason, void *reserved)
return TRUE;
}
/* From <dlls/mmdevapi/mmdevapi.h> */
enum DriverPriority {
Priority_Unavailable = 0,
Priority_Low,
Priority_Neutral,
Priority_Preferred
};
int WINAPI AUDDRV_GetPriority(void)
{
return Priority_Neutral;
}
HRESULT WINAPI AUDDRV_GetEndpointIDs(EDataFlow flow, WCHAR ***ids,
AudioDeviceID ***keys, UINT *num, UINT *def_index)
{
......
......@@ -7,6 +7,7 @@
@ stdcall -private mxdMessage(long long long long long) CoreAudio_mxdMessage
# MMDevAPI driver functions
@ stdcall -private GetPriority() AUDDRV_GetPriority
@ stdcall -private GetEndpointIDs(long ptr ptr ptr) AUDDRV_GetEndpointIDs
@ stdcall -private GetAudioEndpoint(str long ptr) AUDDRV_GetAudioEndpoint
@ stdcall -private GetAudioSessionManager(ptr ptr) AUDDRV_GetAudioSessionManager
......@@ -233,6 +233,54 @@ BOOL WINAPI DllMain(HINSTANCE dll, DWORD reason, void *reserved)
return TRUE;
}
/* From <dlls/mmdevapi/mmdevapi.h> */
enum DriverPriority {
Priority_Unavailable = 0,
Priority_Low,
Priority_Neutral,
Priority_Preferred
};
int WINAPI AUDDRV_GetPriority(void)
{
int mixer_fd;
oss_sysinfo sysinfo;
/* Attempt to determine if we are running on OSS or ALSA's OSS
* compatibility layer. There is no official way to do that, so just check
* for validity as best as possible, without rejecting valid OSS
* implementations. */
mixer_fd = open("/dev/mixer", O_RDONLY, 0);
if(mixer_fd < 0){
TRACE("Priority_Unavailable: open failed\n");
return Priority_Unavailable;
}
sysinfo.version[0] = 0xFF;
sysinfo.versionnum = ~0;
if(ioctl(mixer_fd, SNDCTL_SYSINFO, &sysinfo) < 0){
TRACE("Priority_Unavailable: ioctl failed\n");
close(mixer_fd);
return Priority_Unavailable;
}
close(mixer_fd);
if(sysinfo.version[0] < '4' || sysinfo.version[0] > '9'){
TRACE("Priority_Low: sysinfo.version[0]: %x\n", sysinfo.version[0]);
return Priority_Low;
}
if(sysinfo.versionnum & 0x80000000){
TRACE("Priority_Low: sysinfo.versionnum: %x\n", sysinfo.versionnum);
return Priority_Low;
}
TRACE("Priority_Preferred: Seems like valid OSS!\n");
return Priority_Preferred;
}
static UINT get_default_index(EDataFlow flow, char **keys, UINT num)
{
int fd = -1, err, i;
......
......@@ -8,6 +8,7 @@
@ stdcall -private wodMessage(long long long long long) OSS_wodMessage
# MMDevAPI driver functions
@ stdcall -private GetPriority() AUDDRV_GetPriority
@ stdcall -private GetEndpointIDs(long ptr ptr ptr ptr) AUDDRV_GetEndpointIDs
@ stdcall -private GetAudioEndpoint(ptr ptr long ptr) AUDDRV_GetAudioEndpoint
@ stdcall -private GetAudioSessionManager(ptr ptr) AUDDRV_GetAudioSessionManager
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment