mmdevapi: Automatically select the correct driver.
This commit is contained in:
parent
f6890ef0e2
commit
c4b94b1ba4
|
@ -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';
|
||||
|
||||
return FALSE;
|
||||
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 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
|
||||
|
|
Loading…
Reference in New Issue