Signed-off-by: Andrew Eikum aeikum@codeweavers.com
On Tue, Feb 15, 2022 at 01:09:53PM +0000, Huw Davies wrote:
Signed-off-by: Huw Davies huw@codeweavers.com
dlls/winealsa.drv/Makefile.in | 2 + dlls/winealsa.drv/alsa.c | 458 ++++++++++++++++++++++++++++++++++ dlls/winealsa.drv/mmdevdrv.c | 458 +++++----------------------------- dlls/winealsa.drv/unixlib.h | 42 ++++ 4 files changed, 560 insertions(+), 400 deletions(-) create mode 100644 dlls/winealsa.drv/alsa.c create mode 100644 dlls/winealsa.drv/unixlib.h
diff --git a/dlls/winealsa.drv/Makefile.in b/dlls/winealsa.drv/Makefile.in index 7ce382e64c2..2158e087251 100644 --- a/dlls/winealsa.drv/Makefile.in +++ b/dlls/winealsa.drv/Makefile.in @@ -1,5 +1,6 @@ EXTRADEFS = -DWINE_NO_LONG_TYPES MODULE = winealsa.drv +UNIXLIB = winealsa.so IMPORTS = uuid ole32 advapi32 DELAYIMPORTS = winmm EXTRALIBS = $(ALSA_LIBS) @@ -7,5 +8,6 @@ EXTRALIBS = $(ALSA_LIBS) EXTRADLLFLAGS = -mcygwin
C_SRCS = \
- alsa.c \ midi.c \ mmdevdrv.c
diff --git a/dlls/winealsa.drv/alsa.c b/dlls/winealsa.drv/alsa.c new file mode 100644 index 00000000000..ae05c7a8b9b --- /dev/null +++ b/dlls/winealsa.drv/alsa.c @@ -0,0 +1,458 @@ +/*
- Copyright 2010 Maarten Lankhorst for CodeWeavers
- Copyright 2011 Andrew Eikum for CodeWeavers
- Copyright 2022 Huw Davies
- This library is free software; you can redistribute it and/or
- modify it under the terms of the GNU Lesser General Public
- License as published by the Free Software Foundation; either
- version 2.1 of the License, or (at your option) any later version.
- This library is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Lesser General Public License for more details.
- You should have received a copy of the GNU Lesser General Public
- License along with this library; if not, write to the Free Software
- Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
- */
+#if 0 +#pragma makedep unix +#endif
+#include "config.h"
+#include <stdarg.h> +#include <stdio.h>
+#include <alsa/asoundlib.h>
+#include "ntstatus.h" +#define WIN32_NO_STATUS +#include "windef.h" +#include "winbase.h" +#include "winternl.h" +#include "mmdeviceapi.h"
+#include "wine/debug.h" +#include "wine/list.h" +#include "wine/unixlib.h"
+#include "unixlib.h"
+WINE_DEFAULT_DEBUG_CHANNEL(alsa);
+static const WCHAR drv_keyW[] = {'S','o','f','t','w','a','r','e','\',
- 'W','i','n','e','\','D','r','i','v','e','r','s','\',
- 'w','i','n','e','a','l','s','a','.','d','r','v'};
+static inline void ascii_to_unicode( WCHAR *dst, const char *src, size_t len ) +{
- while (len--) *dst++ = (unsigned char)*src++;
+}
+static HKEY reg_open_key( HKEY root, const WCHAR *name, ULONG name_len ) +{
- UNICODE_STRING nameW = { name_len, name_len, (WCHAR *)name };
- OBJECT_ATTRIBUTES attr;
- HANDLE ret;
- attr.Length = sizeof(attr);
- attr.RootDirectory = root;
- attr.ObjectName = &nameW;
- attr.Attributes = 0;
- attr.SecurityDescriptor = NULL;
- attr.SecurityQualityOfService = NULL;
- if (NtOpenKeyEx( &ret, MAXIMUM_ALLOWED, &attr, 0 )) return 0;
- return ret;
+}
+static HKEY open_hkcu(void) +{
- char buffer[256];
- WCHAR bufferW[256];
- DWORD_PTR sid_data[(sizeof(TOKEN_USER) + SECURITY_MAX_SID_SIZE) / sizeof(DWORD_PTR)];
- DWORD i, len = sizeof(sid_data);
- SID *sid;
- if (NtQueryInformationToken( GetCurrentThreadEffectiveToken(), TokenUser, sid_data, len, &len ))
return 0;
- sid = ((TOKEN_USER *)sid_data)->User.Sid;
- len = sprintf( buffer, "\Registry\User\S-%u-%u", sid->Revision,
MAKELONG( MAKEWORD( sid->IdentifierAuthority.Value[5], sid->IdentifierAuthority.Value[4] ),
MAKEWORD( sid->IdentifierAuthority.Value[3], sid->IdentifierAuthority.Value[2] )));
- for (i = 0; i < sid->SubAuthorityCount; i++)
len += sprintf( buffer + len, "-%u", sid->SubAuthority[i] );
- ascii_to_unicode( bufferW, buffer, len + 1 );
- return reg_open_key( NULL, bufferW, len * sizeof(WCHAR) );
+}
+static HKEY reg_open_hkcu_key( const WCHAR *name, ULONG name_len ) +{
- HKEY hkcu = open_hkcu(), key;
- key = reg_open_key( hkcu, name, name_len );
- NtClose( hkcu );
- return key;
+}
+ULONG reg_query_value( HKEY hkey, const WCHAR *name,
KEY_VALUE_PARTIAL_INFORMATION *info, ULONG size )
+{
- unsigned int name_size = name ? wcslen( name ) * sizeof(WCHAR) : 0;
- UNICODE_STRING nameW = { name_size, name_size, (WCHAR *)name };
- if (NtQueryValueKey( hkey, &nameW, KeyValuePartialInformation,
info, size, &size ))
return 0;
- return size - FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION, Data);
+}
+static snd_pcm_stream_t alsa_get_direction(EDataFlow flow) +{
- return (flow == eRender) ? SND_PCM_STREAM_PLAYBACK : SND_PCM_STREAM_CAPTURE;
+}
+static WCHAR *strdupAtoW(const char *str) +{
- unsigned int len;
- WCHAR *ret;
- if(!str) return NULL;
- len = strlen(str) + 1;
- ret = malloc(len * sizeof(WCHAR));
- if(ret) ntdll_umbstowcs(str, len, ret, len);
- return ret;
+}
+static BOOL alsa_try_open(const char *devnode, EDataFlow flow) +{
- snd_pcm_t *handle;
- int err;
- TRACE("devnode: %s, flow: %d\n", devnode, flow);
- if((err = snd_pcm_open(&handle, devnode, alsa_get_direction(flow), SND_PCM_NONBLOCK)) < 0){
WARN("The device \"%s\" failed to open: %d (%s).\n", devnode, err, snd_strerror(err));
return FALSE;
- }
- snd_pcm_close(handle);
- return TRUE;
+}
+static WCHAR *construct_device_id(EDataFlow flow, const WCHAR *chunk1, const WCHAR *chunk2) +{
- WCHAR *ret;
- const WCHAR *prefix;
- size_t len_wchars = 0, chunk1_len = 0, chunk2_len = 0, copied = 0, prefix_len;
- static const WCHAR dashW[] = {' ','-',' ',0};
- static const size_t dashW_len = ARRAY_SIZE(dashW) - 1;
- static const WCHAR outW[] = {'O','u','t',':',' ',0};
- static const WCHAR inW[] = {'I','n',':',' ',0};
- if(flow == eRender){
prefix = outW;
prefix_len = ARRAY_SIZE(outW) - 1;
len_wchars += prefix_len;
- }else{
prefix = inW;
prefix_len = ARRAY_SIZE(inW) - 1;
len_wchars += prefix_len;
- }
- if(chunk1){
chunk1_len = wcslen(chunk1);
len_wchars += chunk1_len;
- }
- if(chunk1 && chunk2)
len_wchars += dashW_len;
- if(chunk2){
chunk2_len = wcslen(chunk2);
len_wchars += chunk2_len;
- }
- len_wchars += 1; /* NULL byte */
- ret = malloc(len_wchars * sizeof(WCHAR));
- memcpy(ret, prefix, prefix_len * sizeof(WCHAR));
- copied += prefix_len;
- if(chunk1){
memcpy(ret + copied, chunk1, chunk1_len * sizeof(WCHAR));
copied += chunk1_len;
- }
- if(chunk1 && chunk2){
memcpy(ret + copied, dashW, dashW_len * sizeof(WCHAR));
copied += dashW_len;
- }
- if(chunk2){
memcpy(ret + copied, chunk2, chunk2_len * sizeof(WCHAR));
copied += chunk2_len;
- }
- ret[copied] = 0;
- TRACE("Enumerated device: %s\n", wine_dbgstr_w(ret));
- return ret;
+}
+struct endpoints_info +{
- unsigned int num, size;
- struct endpoint *endpoints;
+};
+static void endpoints_add(struct endpoints_info *endpoints, WCHAR *name, char *device) +{
- if(endpoints->num >= endpoints->size){
if (!endpoints->size) endpoints->size = 16;
else endpoints->size *= 2;
endpoints->endpoints = realloc(endpoints->endpoints, endpoints->size * sizeof(*endpoints->endpoints));
- }
- endpoints->endpoints[endpoints->num].name = name;
- endpoints->endpoints[endpoints->num++].device = device;
+}
+static HRESULT alsa_get_card_devices(EDataFlow flow, struct endpoints_info *endpoints_info,
snd_ctl_t *ctl, int card, const WCHAR *cardname)
+{
- int err, device;
- snd_pcm_info_t *info;
- info = calloc(1, snd_pcm_info_sizeof());
- if(!info)
return E_OUTOFMEMORY;
- snd_pcm_info_set_subdevice(info, 0);
- snd_pcm_info_set_stream(info, alsa_get_direction(flow));
- device = -1;
- for(err = snd_ctl_pcm_next_device(ctl, &device); device != -1 && err >= 0;
err = snd_ctl_pcm_next_device(ctl, &device)){
char devnode[32];
WCHAR *devname;
snd_pcm_info_set_device(info, device);
if((err = snd_ctl_pcm_info(ctl, info)) < 0){
if(err == -ENOENT)
/* This device doesn't have the right stream direction */
continue;
WARN("Failed to get info for card %d, device %d: %d (%s)\n",
card, device, err, snd_strerror(err));
continue;
}
sprintf(devnode, "plughw:%d,%d", card, device);
if(!alsa_try_open(devnode, flow))
continue;
devname = strdupAtoW(snd_pcm_info_get_name(info));
if(!devname){
WARN("Unable to get device name for card %d, device %d\n", card, device);
continue;
}
endpoints_add(endpoints_info, construct_device_id(flow, cardname, devname), strdup(devnode));
free(devname);
- }
- free(info);
- if(err != 0)
WARN("Got a failure during device enumeration on card %d: %d (%s)\n",
card, err, snd_strerror(err));
- return S_OK;
+}
+static void get_reg_devices(EDataFlow flow, struct endpoints_info *endpoints_info) +{
- static const WCHAR ALSAOutputDevices[] = {'A','L','S','A','O','u','t','p','u','t','D','e','v','i','c','e','s',0};
- static const WCHAR ALSAInputDevices[] = {'A','L','S','A','I','n','p','u','t','D','e','v','i','c','e','s',0};
- char buffer[4096];
- KEY_VALUE_PARTIAL_INFORMATION *key_info = (void *)buffer;
- HKEY key;
- DWORD size;
- const WCHAR *value_name = (flow == eRender) ? ALSAOutputDevices : ALSAInputDevices;
- /* @@ Wine registry key: HKCU\Software\Wine\Drivers\winealsa.drv */
- if((key = reg_open_hkcu_key(drv_keyW, sizeof(drv_keyW)))){
if((size = reg_query_value(key, value_name, key_info, sizeof(buffer)))){
WCHAR *p = (WCHAR *)key_info->Data;
if(key_info->Type != REG_MULTI_SZ){
ERR("Registry ALSA device list value type must be REG_MULTI_SZ\n");
NtClose(key);
return;
}
while(*p){
int len = wcslen(p);
char *devname = malloc(len * 3 + 1);
ntdll_wcstoumbs(p, len + 1, devname, len * 3 + 1, FALSE);
if(alsa_try_open(devname, flow))
endpoints_add(endpoints_info, construct_device_id(flow, p, NULL), strdup(devname));
free(devname);
p += len + 1;
}
}
NtClose(key);
- }
+}
+struct card_type {
- struct list entry;
- int first_card_number;
- char string[1];
+};
+static struct list card_types = LIST_INIT(card_types);
+static BOOL need_card_number(int card, const char *string) +{
- struct card_type *cptr;
- LIST_FOR_EACH_ENTRY(cptr, &card_types, struct card_type, entry)
- {
if(!strcmp(string, cptr->string))
return card != cptr->first_card_number;
- }
- /* this is the first instance of string */
- cptr = malloc(sizeof(struct card_type) + strlen(string));
- if(!cptr)
/* Default to displaying card number if we can't track cards */
return TRUE;
- cptr->first_card_number = card;
- strcpy(cptr->string, string);
- list_add_head(&card_types, &cptr->entry);
- return FALSE;
+}
+static WCHAR *alsa_get_card_name(int card) +{
- char *cardname;
- WCHAR *ret;
- int err;
- if((err = snd_card_get_name(card, &cardname)) < 0){
/* FIXME: Should be localized */
WARN("Unable to get card name for ALSA device %d: %d (%s)\n", card, err, snd_strerror(err));
cardname = strdup("Unknown soundcard");
- }
- if(need_card_number(card, cardname)){
char *cardnameN;
/*
* For identical card names, second and subsequent instances get
* card number prefix to distinguish them (like Windows).
*/
if(asprintf(&cardnameN, "%u-%s", card, cardname) > 0){
free(cardname);
cardname = cardnameN;
}
- }
- ret = strdupAtoW(cardname);
- free(cardname);
- return ret;
+}
+static NTSTATUS get_endpoint_ids(void *args) +{
- static const WCHAR defaultW[] = {'d','e','f','a','u','l','t',0};
- struct get_endpoint_ids_params *params = args;
- struct endpoints_info endpoints_info;
- unsigned int i, needed, name_len, device_len;
- struct endpoint *endpoint;
- int err, card;
- char *ptr;
- card = -1;
- endpoints_info.num = endpoints_info.size = 0;
- endpoints_info.endpoints = NULL;
- if(alsa_try_open("default", params->flow))
endpoints_add(&endpoints_info, construct_device_id(params->flow, defaultW, NULL), strdup("default"));
- get_reg_devices(params->flow, &endpoints_info);
- for(err = snd_card_next(&card); card != -1 && err >= 0; err = snd_card_next(&card)){
char cardpath[64];
WCHAR *cardname;
snd_ctl_t *ctl;
sprintf(cardpath, "hw:%u", card);
if((err = snd_ctl_open(&ctl, cardpath, 0)) < 0){
WARN("Unable to open ctl for ALSA device %s: %d (%s)\n", cardpath,
err, snd_strerror(err));
continue;
}
cardname = alsa_get_card_name(card);
alsa_get_card_devices(params->flow, &endpoints_info, ctl, card, cardname);
free(cardname);
snd_ctl_close(ctl);
- }
- if(err != 0)
WARN("Got a failure during card enumeration: %d (%s)\n", err, snd_strerror(err));
- needed = endpoints_info.num * sizeof(*params->endpoints);
- endpoint = params->endpoints;
- ptr = (char *)(endpoint + endpoints_info.num);
- for(i = 0; i < endpoints_info.num; i++){
name_len = wcslen(endpoints_info.endpoints[i].name) + 1;
device_len = strlen(endpoints_info.endpoints[i].device) + 1;
needed += name_len * sizeof(WCHAR) + ((device_len + 1) & ~1);
if(needed <= params->size){
endpoint->name = (WCHAR *)ptr;
memcpy(endpoint->name, endpoints_info.endpoints[i].name, name_len * sizeof(WCHAR));
ptr += name_len * sizeof(WCHAR);
endpoint->device = ptr;
memcpy(endpoint->device, endpoints_info.endpoints[i].device, device_len);
ptr += (device_len + 1) & ~1;
endpoint++;
}
free(endpoints_info.endpoints[i].name);
free(endpoints_info.endpoints[i].device);
- }
- free(endpoints_info.endpoints);
- params->num = endpoints_info.num;
- params->default_idx = 0;
- if(needed > params->size){
params->size = needed;
params->result = HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER);
- } else
params->result = S_OK;
- return STATUS_SUCCESS;
+}
+unixlib_entry_t __wine_unix_call_funcs[] = +{
- get_endpoint_ids,
+}; diff --git a/dlls/winealsa.drv/mmdevdrv.c b/dlls/winealsa.drv/mmdevdrv.c index 9a8f80a7beb..516bba1e5fc 100644 --- a/dlls/winealsa.drv/mmdevdrv.c +++ b/dlls/winealsa.drv/mmdevdrv.c @@ -1,6 +1,7 @@ /*
- Copyright 2010 Maarten Lankhorst for CodeWeavers
- Copyright 2011 Andrew Eikum for CodeWeavers
- Copyright 2022 Huw Davies
- This library is free software; you can redistribute it and/or
- modify it under the terms of the GNU Lesser General Public
@@ -32,6 +33,7 @@ #include "wine/debug.h" #include "wine/unicode.h" #include "wine/list.h" +#include "wine/unixlib.h"
#include "propsys.h" #include "initguid.h" @@ -49,8 +51,12 @@
#include <alsa/asoundlib.h>
+#include "unixlib.h"
WINE_DEFAULT_DEBUG_CHANNEL(alsa);
+unixlib_handle_t alsa_handle = 0;
#define NULL_PTR_ERR MAKE_HRESULT(SEVERITY_ERROR, FACILITY_WIN32, RPC_X_NULL_REF_POINTER)
static const REFERENCE_TIME DefaultPeriod = 100000; @@ -161,12 +167,6 @@ static CRITICAL_SECTION_DEBUG g_sessions_lock_debug = static CRITICAL_SECTION g_sessions_lock = { &g_sessions_lock_debug, -1, 0, 0, 0, 0 }; static struct list g_sessions = LIST_INIT(g_sessions);
-static const WCHAR defaultW[] = {'d','e','f','a','u','l','t',0}; -static const char defname[] = "default";
-static const WCHAR drv_keyW[] = {'S','o','f','t','w','a','r','e','\',
- 'W','i','n','e','\','D','r','i','v','e','r','s','\',
- 'w','i','n','e','a','l','s','a','.','d','r','v'};
static const WCHAR drv_key_devicesW[] = {'S','o','f','t','w','a','r','e','\', 'W','i','n','e','\','D','r','i','v','e','r','s','\', 'w','i','n','e','a','l','s','a','.','d','r','v','\','d','e','v','i','c','e','s',0}; @@ -240,6 +240,9 @@ BOOL WINAPI DllMain(HINSTANCE dll, DWORD reason, void *reserved) switch (reason) { case DLL_PROCESS_ATTACH:
if(NtQueryVirtualMemory(GetCurrentProcess(), dll, MemoryWineUnixFuncs,
&alsa_handle, sizeof(alsa_handle), NULL))
return FALSE; g_timer_q = CreateTimerQueue(); if(!g_timer_q) return FALSE;
@@ -266,19 +269,6 @@ int WINAPI AUDDRV_GetPriority(void) return Priority_Neutral; }
-static WCHAR *strdupAtoW(const char *str) -{
- unsigned int len;
- WCHAR *ret;
- if(!str) return NULL;
- len = MultiByteToWideChar(CP_UNIXCP, 0, str, -1, NULL, 0);
- ret = malloc(len * sizeof(WCHAR));
- if(ret) MultiByteToWideChar(CP_UNIXCP, 0, str, -1, ret, len);
- return ret;
-}
static void set_device_guid(EDataFlow flow, HKEY drv_key, const WCHAR *key_name, GUID *guid) { @@ -351,399 +341,67 @@ static void get_device_guid(EDataFlow flow, const char *device, GUID *guid) RegCloseKey(key); }
-static inline void ascii_to_unicode( WCHAR *dst, const char *src, size_t len ) -{
- while (len--) *dst++ = (unsigned char)*src++;
-}
-static HKEY reg_open_key( HKEY root, const WCHAR *name, ULONG name_len ) -{
- UNICODE_STRING nameW = { name_len, name_len, (WCHAR *)name };
- OBJECT_ATTRIBUTES attr;
- HANDLE ret;
- attr.Length = sizeof(attr);
- attr.RootDirectory = root;
- attr.ObjectName = &nameW;
- attr.Attributes = 0;
- attr.SecurityDescriptor = NULL;
- attr.SecurityQualityOfService = NULL;
- if (NtOpenKeyEx( &ret, MAXIMUM_ALLOWED, &attr, 0 )) return 0;
- return ret;
-}
-static HKEY open_hkcu(void) -{
- char buffer[256];
- WCHAR bufferW[256];
- DWORD_PTR sid_data[(sizeof(TOKEN_USER) + SECURITY_MAX_SID_SIZE) / sizeof(DWORD_PTR)];
- DWORD i, len = sizeof(sid_data);
- SID *sid;
- if (NtQueryInformationToken( GetCurrentThreadEffectiveToken(), TokenUser, sid_data, len, &len ))
return 0;
- sid = ((TOKEN_USER *)sid_data)->User.Sid;
- len = sprintf( buffer, "\Registry\User\S-%u-%u", sid->Revision,
MAKELONG( MAKEWORD( sid->IdentifierAuthority.Value[5], sid->IdentifierAuthority.Value[4] ),
MAKEWORD( sid->IdentifierAuthority.Value[3], sid->IdentifierAuthority.Value[2] )));
- for (i = 0; i < sid->SubAuthorityCount; i++)
len += sprintf( buffer + len, "-%u", sid->SubAuthority[i] );
- ascii_to_unicode( bufferW, buffer, len + 1 );
- return reg_open_key( NULL, bufferW, len * sizeof(WCHAR) );
-}
-static HKEY reg_open_hkcu_key( const WCHAR *name, ULONG name_len ) -{
- HKEY hkcu = open_hkcu(), key;
- key = reg_open_key( hkcu, name, name_len );
- NtClose( hkcu );
- return key;
-}
-ULONG reg_query_value( HKEY hkey, const WCHAR *name,
KEY_VALUE_PARTIAL_INFORMATION *info, ULONG size )
-{
- unsigned int name_size = name ? lstrlenW( name ) * sizeof(WCHAR) : 0;
- UNICODE_STRING nameW = { name_size, name_size, (WCHAR *)name };
- if (NtQueryValueKey( hkey, &nameW, KeyValuePartialInformation,
info, size, &size ))
return 0;
- return size - FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION, Data);
-}
static snd_pcm_stream_t alsa_get_direction(EDataFlow flow) { return (flow == eRender) ? SND_PCM_STREAM_PLAYBACK : SND_PCM_STREAM_CAPTURE; }
-static BOOL alsa_try_open(const char *devnode, EDataFlow flow) -{
- snd_pcm_t *handle;
- int err;
- TRACE("devnode: %s, flow: %d\n", devnode, flow);
- if((err = snd_pcm_open(&handle, devnode, alsa_get_direction(flow), SND_PCM_NONBLOCK)) < 0){
WARN("The device \"%s\" failed to open: %d (%s).\n", devnode, err, snd_strerror(err));
return FALSE;
- }
- snd_pcm_close(handle);
- return TRUE;
-}
-static WCHAR *construct_device_id(EDataFlow flow, const WCHAR *chunk1, const WCHAR *chunk2) -{
- WCHAR *ret;
- const WCHAR *prefix;
- size_t len_wchars = 0, chunk1_len = 0, chunk2_len = 0, copied = 0, prefix_len;
- static const WCHAR dashW[] = {' ','-',' ',0};
- static const size_t dashW_len = ARRAY_SIZE(dashW) - 1;
- static const WCHAR outW[] = {'O','u','t',':',' ',0};
- static const WCHAR inW[] = {'I','n',':',' ',0};
- if(flow == eRender){
prefix = outW;
prefix_len = ARRAY_SIZE(outW) - 1;
len_wchars += prefix_len;
- }else{
prefix = inW;
prefix_len = ARRAY_SIZE(inW) - 1;
len_wchars += prefix_len;
- }
- if(chunk1){
chunk1_len = strlenW(chunk1);
len_wchars += chunk1_len;
- }
- if(chunk1 && chunk2)
len_wchars += dashW_len;
- if(chunk2){
chunk2_len = strlenW(chunk2);
len_wchars += chunk2_len;
- }
- len_wchars += 1; /* NULL byte */
- ret = HeapAlloc(GetProcessHeap(), 0, len_wchars * sizeof(WCHAR));
- memcpy(ret, prefix, prefix_len * sizeof(WCHAR));
- copied += prefix_len;
- if(chunk1){
memcpy(ret + copied, chunk1, chunk1_len * sizeof(WCHAR));
copied += chunk1_len;
- }
- if(chunk1 && chunk2){
memcpy(ret + copied, dashW, dashW_len * sizeof(WCHAR));
copied += dashW_len;
- }
- if(chunk2){
memcpy(ret + copied, chunk2, chunk2_len * sizeof(WCHAR));
copied += chunk2_len;
- }
- ret[copied] = 0;
- TRACE("Enumerated device: %s\n", wine_dbgstr_w(ret));
- return ret;
-}
-static HRESULT alsa_get_card_devices(EDataFlow flow, WCHAR ***ids, GUID **guids, UINT *num,
snd_ctl_t *ctl, int card, const WCHAR *cardname)
-{
- int err, device;
- snd_pcm_info_t *info;
- info = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, snd_pcm_info_sizeof());
- if(!info)
return E_OUTOFMEMORY;
- snd_pcm_info_set_subdevice(info, 0);
- snd_pcm_info_set_stream(info, alsa_get_direction(flow));
- device = -1;
- for(err = snd_ctl_pcm_next_device(ctl, &device); device != -1 && err >= 0;
err = snd_ctl_pcm_next_device(ctl, &device)){
char devnode[32];
WCHAR *devname;
snd_pcm_info_set_device(info, device);
if((err = snd_ctl_pcm_info(ctl, info)) < 0){
if(err == -ENOENT)
/* This device doesn't have the right stream direction */
continue;
WARN("Failed to get info for card %d, device %d: %d (%s)\n",
card, device, err, snd_strerror(err));
continue;
}
sprintf(devnode, "plughw:%d,%d", card, device);
if(!alsa_try_open(devnode, flow))
continue;
if(*num){
*ids = HeapReAlloc(GetProcessHeap(), 0, *ids, sizeof(WCHAR *) * (*num + 1));
*guids = HeapReAlloc(GetProcessHeap(), 0, *guids, sizeof(GUID) * (*num + 1));
}else{
*ids = HeapAlloc(GetProcessHeap(), 0, sizeof(WCHAR *));
*guids = HeapAlloc(GetProcessHeap(), 0, sizeof(GUID));
}
devname = strdupAtoW(snd_pcm_info_get_name(info));
if(!devname){
WARN("Unable to get device name for card %d, device %d\n", card, device);
continue;
}
(*ids)[*num] = construct_device_id(flow, cardname, devname);
get_device_guid(flow, devnode, &(*guids)[*num]);
free(devname);
++(*num);
- }
- HeapFree(GetProcessHeap(), 0, info);
- if(err != 0)
WARN("Got a failure during device enumeration on card %d: %d (%s)\n",
card, err, snd_strerror(err));
- return S_OK;
-}
-static void get_reg_devices(EDataFlow flow, WCHAR ***ids, GUID **guids, UINT *num) -{
- static const WCHAR ALSAOutputDevices[] = {'A','L','S','A','O','u','t','p','u','t','D','e','v','i','c','e','s',0};
- static const WCHAR ALSAInputDevices[] = {'A','L','S','A','I','n','p','u','t','D','e','v','i','c','e','s',0};
- char buffer[4096];
- KEY_VALUE_PARTIAL_INFORMATION *key_info = (void *)buffer;
- HKEY key;
- DWORD size;
- const WCHAR *value_name = (flow == eRender) ? ALSAOutputDevices : ALSAInputDevices;
- /* @@ Wine registry key: HKCU\Software\Wine\Drivers\winealsa.drv */
- if((key = reg_open_hkcu_key(drv_keyW, sizeof(drv_keyW)))){
if((size = reg_query_value(key, value_name, key_info, sizeof(buffer)))){
WCHAR *p = (WCHAR *)key_info->Data;
if(key_info->Type != REG_MULTI_SZ){
ERR("Registry ALSA device list value type must be REG_MULTI_SZ\n");
NtClose(key);
return;
}
while(*p){
int len = lstrlenW(p);
char *devname = malloc(len * 3 + 1);
WideCharToMultiByte(CP_UNIXCP, 0, p, -1, devname, len * 3 + 1, NULL, NULL);
if(alsa_try_open(devname, flow)){
if(*num){
*ids = HeapReAlloc(GetProcessHeap(), 0, *ids, sizeof(WCHAR *) * (*num + 1));
*guids = HeapReAlloc(GetProcessHeap(), 0, *guids, sizeof(GUID) * (*num + 1));
}else{
*ids = HeapAlloc(GetProcessHeap(), 0, sizeof(WCHAR *));
*guids = HeapAlloc(GetProcessHeap(), 0, sizeof(GUID));
}
(*ids)[*num] = construct_device_id(flow, p, NULL);
get_device_guid(flow, devname, &(*guids)[*num]);
++*num;
}
free(devname);
p += len + 1;
}
}
NtClose(key);
- }
-}
-struct card_type {
- struct list entry;
- int first_card_number;
- char string[1];
-};
-static struct list card_types = LIST_INIT(card_types);
-static BOOL need_card_number(int card, const char *string) -{
- struct card_type *cptr;
- LIST_FOR_EACH_ENTRY(cptr, &card_types, struct card_type, entry)
- {
if(!strcmp(string, cptr->string))
return card != cptr->first_card_number;
- }
- /* this is the first instance of string */
- cptr = HeapAlloc(GetProcessHeap(), 0, sizeof(struct card_type) + strlen(string));
- if(!cptr)
/* Default to displaying card number if we can't track cards */
return TRUE;
- cptr->first_card_number = card;
- strcpy(cptr->string, string);
- list_add_head(&card_types, &cptr->entry);
- return FALSE;
-}
-static WCHAR *alsa_get_card_name(int card) -{
- char *cardname;
- WCHAR *ret;
- int err;
- if((err = snd_card_get_name(card, &cardname)) < 0){
/* FIXME: Should be localized */
WARN("Unable to get card name for ALSA device %d: %d (%s)\n", card, err, snd_strerror(err));
cardname = strdup("Unknown soundcard");
- }
- if(need_card_number(card, cardname)){
char *cardnameN;
/*
* For identical card names, second and subsequent instances get
* card number prefix to distinguish them (like Windows).
*/
if(asprintf(&cardnameN, "%u-%s", card, cardname) > 0){
free(cardname);
cardname = cardnameN;
}
- }
- ret = strdupAtoW(cardname);
- free(cardname);
- return ret;
-}
-static HRESULT alsa_enum_devices(EDataFlow flow, WCHAR ***ids, GUID **guids,
UINT *num)
-{
- int err, card;
- card = -1;
- *num = 0;
- if(alsa_try_open(defname, flow)){
*ids = HeapAlloc(GetProcessHeap(), 0, sizeof(WCHAR *));
(*ids)[0] = construct_device_id(flow, defaultW, NULL);
*guids = HeapAlloc(GetProcessHeap(), 0, sizeof(GUID));
get_device_guid(flow, defname, &(*guids)[0]);
++*num;
- }
- get_reg_devices(flow, ids, guids, num);
- for(err = snd_card_next(&card); card != -1 && err >= 0; err = snd_card_next(&card)){
char cardpath[64];
WCHAR *cardname;
snd_ctl_t *ctl;
sprintf(cardpath, "hw:%u", card);
if((err = snd_ctl_open(&ctl, cardpath, 0)) < 0){
WARN("Unable to open ctl for ALSA device %s: %d (%s)\n", cardpath,
err, snd_strerror(err));
continue;
}
cardname = alsa_get_card_name(card);
alsa_get_card_devices(flow, ids, guids, num, ctl, card, cardname);
free(cardname);
snd_ctl_close(ctl);
- }
- if(err != 0)
WARN("Got a failure during card enumeration: %d (%s)\n",
err, snd_strerror(err));
- return S_OK;
-}
-HRESULT WINAPI AUDDRV_GetEndpointIDs(EDataFlow flow, WCHAR ***ids, GUID **guids, +HRESULT WINAPI AUDDRV_GetEndpointIDs(EDataFlow flow, WCHAR ***ids_out, GUID **guids_out, UINT *num, UINT *def_index) {
- HRESULT hr;
struct get_endpoint_ids_params params;
unsigned int i;
GUID *guids = NULL;
WCHAR **ids = NULL;
TRACE("%d %p %p %p %p\n", flow, ids, guids, num, def_index);
- *ids = NULL;
- *guids = NULL;
- hr = alsa_enum_devices(flow, ids, guids, num);
- if(FAILED(hr)){
UINT i;
for(i = 0; i < *num; ++i)
HeapFree(GetProcessHeap(), 0, (*ids)[i]);
HeapFree(GetProcessHeap(), 0, *ids);
HeapFree(GetProcessHeap(), 0, *guids);
return E_OUTOFMEMORY;
- }
- TRACE("Enumerated %u devices\n", *num);
- if(*num == 0){
HeapFree(GetProcessHeap(), 0, *ids);
*ids = NULL;
HeapFree(GetProcessHeap(), 0, *guids);
*guids = NULL;
- params.flow = flow;
- params.size = 1000;
- params.endpoints = NULL;
- do{
HeapFree(GetProcessHeap(), 0, params.endpoints);
params.endpoints = HeapAlloc(GetProcessHeap(), 0, params.size);
ALSA_CALL(get_endpoint_ids, ¶ms);
- }while(params.result == HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER));
- if(FAILED(params.result)) goto end;
- ids = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, params.num * sizeof(*ids));
- guids = HeapAlloc(GetProcessHeap(), 0, params.num * sizeof(*guids));
- if(!ids || !guids){
params.result = E_OUTOFMEMORY;
goto end;
- }
- for(i = 0; i < params.num; i++){
unsigned int size = (strlenW(params.endpoints[i].name) + 1) * sizeof(WCHAR);
ids[i] = HeapAlloc(GetProcessHeap(), 0, size);
if(!ids[i]){
params.result = E_OUTOFMEMORY;
goto end;
}
memcpy(ids[i], params.endpoints[i].name, size);
get_device_guid(flow, params.endpoints[i].device, guids + i);
- }
- *def_index = params.default_idx;
+end:
- HeapFree(GetProcessHeap(), 0, params.endpoints);
- if(FAILED(params.result)){
HeapFree(GetProcessHeap(), 0, guids);
if(ids){
for(i = 0; i < params.num; i++)
HeapFree(GetProcessHeap(), 0, ids[i]);
HeapFree(GetProcessHeap(), 0, ids);
}
- }else{
*ids_out = ids;
*guids_out = guids;
}*num = params.num;
- *def_index = 0;
- return S_OK;
- return params.result;
}
static BOOL get_alsa_name_by_guid(GUID *guid, char *name, DWORD name_size, EDataFlow *flow) diff --git a/dlls/winealsa.drv/unixlib.h b/dlls/winealsa.drv/unixlib.h new file mode 100644 index 00000000000..f3014d0b448 --- /dev/null +++ b/dlls/winealsa.drv/unixlib.h @@ -0,0 +1,42 @@ +/*
- Copyright 2022 Huw Davies
- This library is free software; you can redistribute it and/or
- modify it under the terms of the GNU Lesser General Public
- License as published by the Free Software Foundation; either
- version 2.1 of the License, or (at your option) any later version.
- This library is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Lesser General Public License for more details.
- You should have received a copy of the GNU Lesser General Public
- License along with this library; if not, write to the Free Software
- Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
- */
+struct endpoint +{
- WCHAR *name;
- char *device;
+};
+struct get_endpoint_ids_params +{
- EDataFlow flow;
- struct endpoint *endpoints;
- unsigned int size;
- HRESULT result;
- unsigned int num;
- unsigned int default_idx;
+};
+enum alsa_funcs +{
- alsa_get_endpoint_ids,
+};
+extern unixlib_handle_t alsa_handle;
+#define ALSA_CALL(func, params) __wine_unix_call(alsa_handle, alsa_ ## func, params)
2.25.1