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

Andrew Eikum aeikum at codeweavers.com
Tue Apr 5 13:28:51 CDT 2022


Signed-off-by: Andrew Eikum <aeikum at codeweavers.com>

On Thu, Mar 31, 2022 at 08:21:50AM +0100, Huw Davies wrote:
> Signed-off-by: Huw Davies <huw at codeweavers.com>
> ---
> v2: Don't use OSS_DEVNAME_SIZE
> 
>  dlls/wineoss.drv/mmdevdrv.c | 251 ++++++++++--------------------------
>  dlls/wineoss.drv/oss.c      | 207 +++++++++++++++++++++++++++++
>  dlls/wineoss.drv/unixlib.h  |  19 +++
>  3 files changed, 294 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..ab7751ac174 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,212 @@ 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;
> +    oss_audioinfo ai;
> +    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[ARRAY_SIZE(ai.name) + 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){
> +        char devnode[OSS_DEVNODE_SIZE];
> +        int fd, prefix_len;
> +        const WCHAR *prefix;
> +
> +        memset(&ai, 0, sizeof(ai));
> +        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