[PATCH 5/5] wineoss: Move get_endpoint_ids to the unixlib.

Huw Davies huw at codeweavers.com
Mon Mar 28 04:37:45 CDT 2022


Signed-off-by: Huw Davies <huw at codeweavers.com>
---
 dlls/wineoss.drv/mmdevdrv.c | 251 ++++++++++--------------------------
 dlls/wineoss.drv/oss.c      | 206 +++++++++++++++++++++++++++++
 dlls/wineoss.drv/unixlib.h  |  19 +++
 3 files changed, 293 insertions(+), 183 deletions(-)

diff --git a/dlls/wineoss.drv/mmdevdrv.c b/dlls/wineoss.drv/mmdevdrv.c
index e5206627528..fd35a439c5a 100644
--- a/dlls/wineoss.drv/mmdevdrv.c
+++ b/dlls/wineoss.drv/mmdevdrv.c
@@ -53,6 +53,7 @@
 
 #include "wine/debug.h"
 #include "wine/list.h"
+#include "wine/unicode.h"
 #include "wine/unixlib.h"
 
 #include "unixlib.h"
@@ -147,11 +148,10 @@ typedef struct _SessionMgr {
 } SessionMgr;
 
 typedef struct _OSSDevice {
+    struct list entry;
     EDataFlow flow;
-    char devnode[OSS_DEVNODE_SIZE];
     GUID guid;
-
-    struct list entry;
+    char devnode[0];
 } OSSDevice;
 
 static struct list g_devices = LIST_INIT(g_devices);
@@ -346,25 +346,6 @@ static void get_device_guid(EDataFlow flow, const char *device, GUID *guid)
         RegCloseKey(key);
 }
 
-/* dst must be large enough to hold devnode */
-static void oss_clean_devnode(char *dest, const char *devnode)
-{
-    const char *dot, *slash;
-    size_t len;
-
-    strcpy(dest, devnode);
-    dot = strrchr(dest, '.');
-    if(!dot)
-        return;
-
-    slash = strrchr(dest, '/');
-    if(slash && dot < slash)
-        return;
-
-    len = dot - dest;
-    dest[len] = '\0';
-}
-
 static int open_device(const char *device, EDataFlow flow)
 {
     int flags = ((flow == eRender) ? O_WRONLY : O_RDONLY) | O_NONBLOCK;
@@ -372,44 +353,6 @@ static int open_device(const char *device, EDataFlow flow)
     return open(device, flags, 0);
 }
 
-static UINT get_default_index(EDataFlow flow)
-{
-    int fd = -1, err;
-    UINT i;
-    oss_audioinfo ai;
-    char devnode[OSS_DEVNODE_SIZE];
-    OSSDevice *dev_item;
-
-    fd = open_device("/dev/dsp", flow);
-    if(fd < 0){
-        WARN("Couldn't open default device!\n");
-        return 0;
-    }
-
-    ai.dev = -1;
-    if((err = ioctl(fd, SNDCTL_ENGINEINFO, &ai)) < 0){
-        WARN("SNDCTL_ENGINEINFO failed: %d (%s)\n", err, strerror(errno));
-        close(fd);
-        return 0;
-    }
-
-    close(fd);
-
-    TRACE("Default devnode: %s\n", ai.devnode);
-    oss_clean_devnode(devnode, ai.devnode);
-    i = 0;
-    LIST_FOR_EACH_ENTRY(dev_item, &g_devices, OSSDevice, entry){
-        if(dev_item->flow == flow){
-            if(!strcmp(devnode, dev_item->devnode))
-                return i;
-            ++i;
-        }
-    }
-
-    WARN("Couldn't find default device! Choosing first.\n");
-    return 0;
-}
-
 static const OSSDevice *get_ossdevice_from_guid(const GUID *guid)
 {
     OSSDevice *dev_item;
@@ -419,138 +362,80 @@ static const OSSDevice *get_ossdevice_from_guid(const GUID *guid)
     return NULL;
 }
 
-HRESULT WINAPI AUDDRV_GetEndpointIDs(EDataFlow flow, WCHAR ***ids, GUID **guids,
-        UINT *num, UINT *def_index)
+static void device_add(OSSDevice *oss_dev)
 {
-    int i, mixer_fd;
-    oss_sysinfo sysinfo;
-    static int print_once = 0;
+    if(get_ossdevice_from_guid(&oss_dev->guid)) /* already in list */
+        HeapFree(GetProcessHeap(), 0, oss_dev);
+    else
+        list_add_tail(&g_devices, &oss_dev->entry);
+}
 
-    static const WCHAR outW[] = {'O','u','t',':',' ',0};
-    static const WCHAR inW[] = {'I','n',':',' ',0};
+HRESULT WINAPI AUDDRV_GetEndpointIDs(EDataFlow flow, WCHAR ***ids_out, GUID **guids_out,
+        UINT *num, UINT *def_index)
+{
+    struct get_endpoint_ids_params params;
+    GUID *guids = NULL;
+    WCHAR **ids = NULL;
+    unsigned int i;
 
     TRACE("%d %p %p %p %p\n", flow, ids, guids, num, def_index);
 
-    mixer_fd = open("/dev/mixer", O_RDONLY, 0);
-    if(mixer_fd < 0){
-        ERR("OSS /dev/mixer doesn't seem to exist\n");
-        return AUDCLNT_E_SERVICE_NOT_RUNNING;
-    }
-
-    if(ioctl(mixer_fd, SNDCTL_SYSINFO, &sysinfo) < 0){
-        close(mixer_fd);
-
-        if(errno == EINVAL){
-            ERR("OSS version too old, need at least OSSv4\n");
-            return AUDCLNT_E_SERVICE_NOT_RUNNING;
-        }
-
-        ERR("Error getting SNDCTL_SYSINFO: %d (%s)\n", errno, strerror(errno));
-        return E_FAIL;
-    }
-
-    if(!print_once){
-        TRACE("OSS sysinfo:\n");
-        TRACE("product: %s\n", sysinfo.product);
-        TRACE("version: %s\n", sysinfo.version);
-        TRACE("versionnum: %x\n", sysinfo.versionnum);
-        TRACE("numaudios: %d\n", sysinfo.numaudios);
-        TRACE("nummixers: %d\n", sysinfo.nummixers);
-        TRACE("numcards: %d\n", sysinfo.numcards);
-        TRACE("numaudioengines: %d\n", sysinfo.numaudioengines);
-        print_once = 1;
-    }
-
-    if(sysinfo.numaudios <= 0){
-        WARN("No audio devices!\n");
-        close(mixer_fd);
-        return AUDCLNT_E_SERVICE_NOT_RUNNING;
-    }
-
-    *ids = HeapAlloc(GetProcessHeap(), 0, sysinfo.numaudios * sizeof(WCHAR *));
-    *guids = HeapAlloc(GetProcessHeap(), 0, sysinfo.numaudios * sizeof(GUID));
-
-    *num = 0;
-    for(i = 0; i < sysinfo.numaudios; ++i){
-        oss_audioinfo ai = {0};
-        char devnode[OSS_DEVNODE_SIZE];
-        OSSDevice *dev_item;
-        int fd;
-
-        ai.dev = i;
-        if(ioctl(mixer_fd, SNDCTL_AUDIOINFO, &ai) < 0){
-            WARN("Error getting AUDIOINFO for dev %d: %d (%s)\n", i, errno,
-                    strerror(errno));
-            continue;
-        }
-
-        oss_clean_devnode(devnode, ai.devnode);
-
-        /* check for duplicates */
-        LIST_FOR_EACH_ENTRY(dev_item, &g_devices, OSSDevice, entry){
-            if(dev_item->flow == flow && !strcmp(devnode, dev_item->devnode))
-                break;
+    params.flow = flow;
+    params.size = 1000;
+    params.endpoints = NULL;
+    do{
+        HeapFree(GetProcessHeap(), 0, params.endpoints);
+        params.endpoints = HeapAlloc(GetProcessHeap(), 0, params.size);
+        OSS_CALL(get_endpoint_ids, &params);
+    }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 name_size = (strlenW(params.endpoints[i].name) + 1) * sizeof(WCHAR);
+        unsigned int dev_size = strlen(params.endpoints[i].device) + 1;
+        OSSDevice *oss_dev;
+
+        ids[i] = HeapAlloc(GetProcessHeap(), 0, name_size);
+        oss_dev = HeapAlloc(GetProcessHeap(), 0, offsetof(OSSDevice, devnode[dev_size]));
+        if(!ids[i] || !oss_dev){
+            HeapFree(GetProcessHeap, 0, oss_dev);
+            params.result = E_OUTOFMEMORY;
+            goto end;
         }
-        if(&dev_item->entry != &g_devices)
-            continue;
-
-        fd = open_device(devnode, flow);
-        if(fd < 0){
-            WARN("Opening device \"%s\" failed, pretending it doesn't exist: %d (%s)\n",
-                    devnode, errno, strerror(errno));
-            continue;
-        }
-        close(fd);
-
-        if((flow == eCapture && (ai.caps & PCM_CAP_INPUT)) ||
-                (flow == eRender && (ai.caps & PCM_CAP_OUTPUT))){
-            size_t len, prefix_len;
-            const WCHAR *prefix;
-
-            dev_item = HeapAlloc(GetProcessHeap(), 0, sizeof(*dev_item));
-
-            dev_item->flow = flow;
-            get_device_guid(flow, devnode, &dev_item->guid);
-            strcpy(dev_item->devnode, devnode);
-
-            (*guids)[*num] = dev_item->guid;
-
-            len = MultiByteToWideChar(CP_UNIXCP, 0, ai.name, -1, NULL, 0);
-            if(flow == eRender){
-                prefix = outW;
-                prefix_len = ARRAY_SIZE(outW) - 1;
-                len += prefix_len;
-            }else{
-                prefix = inW;
-                prefix_len = ARRAY_SIZE(inW) - 1;
-                len += prefix_len;
-            }
-            (*ids)[*num] = HeapAlloc(GetProcessHeap(), 0,
-                    len * sizeof(WCHAR));
-            if(!(*ids)[*num]){
-                for(i = 0; i < *num; ++i)
-                    HeapFree(GetProcessHeap(), 0, (*ids)[i]);
-                HeapFree(GetProcessHeap(), 0, *ids);
-                HeapFree(GetProcessHeap(), 0, *guids);
-                HeapFree(GetProcessHeap(), 0, dev_item);
-                close(mixer_fd);
-                return E_OUTOFMEMORY;
-            }
-            memcpy((*ids)[*num], prefix, prefix_len * sizeof(WCHAR));
-            MultiByteToWideChar(CP_UNIXCP, 0, ai.name, -1,
-                    (*ids)[*num] + prefix_len, len - prefix_len);
-
-            list_add_tail(&g_devices, &dev_item->entry);
-
-            (*num)++;
+        memcpy(ids[i], params.endpoints[i].name, name_size);
+        get_device_guid(flow, params.endpoints[i].device, guids + i);
+
+        oss_dev->flow = flow;
+        oss_dev->guid = guids[i];
+        memcpy(oss_dev->devnode, params.endpoints[i].device, dev_size);
+        device_add(oss_dev);
+    }
+    *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;
     }
 
-    close(mixer_fd);
-
-    *def_index = get_default_index(flow);
-
-    return S_OK;
+    return params.result;
 }
 
 HRESULT WINAPI AUDDRV_GetAudioEndpoint(GUID *guid, IMMDevice *dev,
diff --git a/dlls/wineoss.drv/oss.c b/dlls/wineoss.drv/oss.c
index 9c1de25acb5..ae4e4981d2d 100644
--- a/dlls/wineoss.drv/oss.c
+++ b/dlls/wineoss.drv/oss.c
@@ -29,11 +29,13 @@
 #include <sys/ioctl.h>
 #include <fcntl.h>
 #include <unistd.h>
+#include <errno.h>
 #include <sys/soundcard.h>
 
 #include "ntstatus.h"
 #define WIN32_NO_STATUS
 #include "winternl.h"
+#include "audioclient.h"
 
 #include "wine/debug.h"
 #include "wine/unixlib.h"
@@ -88,7 +90,211 @@ static NTSTATUS test_connect(void *args)
     return STATUS_SUCCESS;
 }
 
+/* dst must be large enough to hold devnode */
+static void oss_clean_devnode(char *dest, const char *devnode)
+{
+    const char *dot, *slash;
+    size_t len;
+
+    strcpy(dest, devnode);
+    dot = strrchr(dest, '.');
+    if(!dot)
+        return;
+
+    slash = strrchr(dest, '/');
+    if(slash && dot < slash)
+        return;
+
+    len = dot - dest;
+    dest[len] = '\0';
+}
+
+static int open_device(const char *device, EDataFlow flow)
+{
+    int flags = ((flow == eRender) ? O_WRONLY : O_RDONLY) | O_NONBLOCK;
+
+    return open(device, flags, 0);
+}
+
+static void get_default_device(EDataFlow flow, char device[OSS_DEVNODE_SIZE])
+{
+    int fd, err;
+    oss_audioinfo ai;
+
+    device[0] = '\0';
+    fd = open_device("/dev/dsp", flow);
+    if(fd < 0){
+        WARN("Couldn't open default device!\n");
+        return;
+    }
+
+    ai.dev = -1;
+    if((err = ioctl(fd, SNDCTL_ENGINEINFO, &ai)) < 0){
+        WARN("SNDCTL_ENGINEINFO failed: %d (%s)\n", err, strerror(errno));
+        close(fd);
+        return;
+    }
+    close(fd);
+
+    TRACE("Default devnode: %s\n", ai.devnode);
+    oss_clean_devnode(device, ai.devnode);
+    return;
+}
+
+static NTSTATUS get_endpoint_ids(void *args)
+{
+    struct get_endpoint_ids_params *params = args;
+    oss_sysinfo sysinfo;
+    static int print_once = 0;
+    static const WCHAR outW[] = {'O','u','t',':',' ',0};
+    static const WCHAR inW[] = {'I','n',':',' ',0};
+    struct endpoint_info
+    {
+        WCHAR name[OSS_DEVNAME_SIZE + ARRAY_SIZE(outW)];
+        char device[OSS_DEVNODE_SIZE];
+    } *info;
+    unsigned int i, j, num, needed, name_len, device_len, default_idx = 0;
+    char default_device[OSS_DEVNODE_SIZE];
+    struct endpoint *endpoint;
+    int mixer_fd;
+    char *ptr;
+
+    mixer_fd = open("/dev/mixer", O_RDONLY, 0);
+    if(mixer_fd < 0){
+        ERR("OSS /dev/mixer doesn't seem to exist\n");
+        params->result = AUDCLNT_E_SERVICE_NOT_RUNNING;
+        return STATUS_SUCCESS;
+    }
+
+    if(ioctl(mixer_fd, SNDCTL_SYSINFO, &sysinfo) < 0){
+        close(mixer_fd);
+        if(errno == EINVAL){
+            ERR("OSS version too old, need at least OSSv4\n");
+            params->result = AUDCLNT_E_SERVICE_NOT_RUNNING;
+            return STATUS_SUCCESS;
+        }
+
+        ERR("Error getting SNDCTL_SYSINFO: %d (%s)\n", errno, strerror(errno));
+        params->result = E_FAIL;
+        return STATUS_SUCCESS;
+    }
+
+    if(!print_once){
+        TRACE("OSS sysinfo:\n");
+        TRACE("product: %s\n", sysinfo.product);
+        TRACE("version: %s\n", sysinfo.version);
+        TRACE("versionnum: %x\n", sysinfo.versionnum);
+        TRACE("numaudios: %d\n", sysinfo.numaudios);
+        TRACE("nummixers: %d\n", sysinfo.nummixers);
+        TRACE("numcards: %d\n", sysinfo.numcards);
+        TRACE("numaudioengines: %d\n", sysinfo.numaudioengines);
+        print_once = 1;
+    }
+
+    if(sysinfo.numaudios <= 0){
+        WARN("No audio devices!\n");
+        close(mixer_fd);
+        params->result = AUDCLNT_E_SERVICE_NOT_RUNNING;
+        return STATUS_SUCCESS;
+    }
+
+    info = malloc(sysinfo.numaudios * sizeof(*info));
+    if(!info){
+        close(mixer_fd);
+        params->result = E_OUTOFMEMORY;
+        return STATUS_SUCCESS;
+    }
+
+    get_default_device(params->flow, default_device);
+
+    num = 0;
+    for(i = 0; i < sysinfo.numaudios; ++i){
+        oss_audioinfo ai = {0};
+        char devnode[OSS_DEVNODE_SIZE];
+        int fd, prefix_len;
+        const WCHAR *prefix;
+
+        ai.dev = i;
+        if(ioctl(mixer_fd, SNDCTL_AUDIOINFO, &ai) < 0){
+            WARN("Error getting AUDIOINFO for dev %d: %d (%s)\n", i, errno,
+                    strerror(errno));
+            continue;
+        }
+
+        oss_clean_devnode(devnode, ai.devnode);
+
+        /* check for duplicates */
+        for(j = 0; j < num; j++)
+            if(!strcmp(devnode, info[j].device))
+                break;
+        if(j < num)
+            continue;
+
+        fd = open_device(devnode, params->flow);
+        if(fd < 0){
+            WARN("Opening device \"%s\" failed, pretending it doesn't exist: %d (%s)\n",
+                    devnode, errno, strerror(errno));
+            continue;
+        }
+        close(fd);
+
+        if((params->flow == eCapture && !(ai.caps & PCM_CAP_INPUT)) ||
+           (params->flow == eRender && !(ai.caps & PCM_CAP_OUTPUT)))
+            continue;
+
+        strcpy(info[num].device, devnode);
+
+        if(params->flow == eRender){
+            prefix = outW;
+            prefix_len = ARRAY_SIZE(outW) - 1;
+        }else{
+            prefix = inW;
+            prefix_len = ARRAY_SIZE(inW) - 1;
+        }
+        memcpy(info[num].name, prefix, prefix_len * sizeof(WCHAR));
+        ntdll_umbstowcs(ai.name, strlen(ai.name) + 1, info[num].name + prefix_len,
+                        ARRAY_SIZE(info[num].name) - prefix_len);
+        if(!strcmp(default_device, info[num].device))
+            default_idx = num;
+        num++;
+    }
+    close(mixer_fd);
+
+    needed = num * sizeof(*params->endpoints);
+    endpoint = params->endpoints;
+    ptr = (char *)(endpoint + num);
+
+    for(i = 0; i < num; i++){
+        name_len = wcslen(info[i].name) + 1;
+        device_len = strlen(info[i].device) + 1;
+        needed += name_len * sizeof(WCHAR) + ((device_len + 1) & ~1);
+
+        if(needed <= params->size){
+            endpoint->name = (WCHAR *)ptr;
+            memcpy(endpoint->name, info[i].name, name_len * sizeof(WCHAR));
+            ptr += name_len * sizeof(WCHAR);
+            endpoint->device = ptr;
+            memcpy(endpoint->device, info[i].device, device_len);
+            ptr += (device_len + 1) & ~1;
+            endpoint++;
+        }
+    }
+    free(info);
+
+    params->num = num;
+    params->default_idx = default_idx;
+
+    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[] =
 {
     test_connect,
+    get_endpoint_ids,
 };
diff --git a/dlls/wineoss.drv/unixlib.h b/dlls/wineoss.drv/unixlib.h
index d4fb5db3102..1a80794f150 100644
--- a/dlls/wineoss.drv/unixlib.h
+++ b/dlls/wineoss.drv/unixlib.h
@@ -16,6 +16,8 @@
  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
  */
 
+#include "mmdeviceapi.h"
+
 /* From <dlls/mmdevapi/mmdevapi.h> */
 enum DriverPriority
 {
@@ -30,9 +32,26 @@ struct test_connect_params
     enum DriverPriority priority;
 };
 
+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 oss_funcs
 {
     oss_test_connect,
+    oss_get_endpoint_ids,
 };
 
 extern unixlib_handle_t oss_handle;
-- 
2.25.1




More information about the wine-devel mailing list