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