[PATCH v2 2/6] winecoreaudio: Move get_endpoint_ids to a unixlib.

Andrew Eikum aeikum at codeweavers.com
Wed Nov 17 09:08:49 CST 2021


From: Huw Davies <huw at codeweavers.com>

Signed-off-by: Huw Davies <huw at codeweavers.com>
Signed-off-by: Andrew Eikum <aeikum at codeweavers.com>
---
 dlls/winecoreaudio.drv/Makefile.in |   1 +
 dlls/winecoreaudio.drv/coreaudio.c | 229 ++++++++++++++++++++++++++++-
 dlls/winecoreaudio.drv/mmdevdrv.c  | 211 ++++++++------------------
 dlls/winecoreaudio.drv/unixlib.h   |  44 ++++++
 4 files changed, 326 insertions(+), 159 deletions(-)
 create mode 100644 dlls/winecoreaudio.drv/unixlib.h

diff --git a/dlls/winecoreaudio.drv/Makefile.in b/dlls/winecoreaudio.drv/Makefile.in
index afbc50c7148..b6bf5bd4587 100644
--- a/dlls/winecoreaudio.drv/Makefile.in
+++ b/dlls/winecoreaudio.drv/Makefile.in
@@ -1,4 +1,5 @@
 MODULE    = winecoreaudio.drv
+UNIXLIB   = winecoreaudio.so
 IMPORTS   = uuid ole32 user32 advapi32
 DELAYIMPORTS = winmm
 EXTRALIBS = $(COREAUDIO_LIBS)
diff --git a/dlls/winecoreaudio.drv/coreaudio.c b/dlls/winecoreaudio.drv/coreaudio.c
index 1f222367bed..f3af24f80fb 100644
--- a/dlls/winecoreaudio.drv/coreaudio.c
+++ b/dlls/winecoreaudio.drv/coreaudio.c
@@ -1,5 +1,8 @@
 /*
- * Wine Driver for CoreAudio
+ * Unixlib for winecoreaudio driver.
+ *
+ * Copyright 2011 Andrew Eikum for CodeWeavers
+ * Copyright 2021 Huw Davies
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
@@ -15,16 +18,230 @@
  * 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"
 
+#define LoadResource __carbon_LoadResource
+#define CompareString __carbon_CompareString
+#define GetCurrentThread __carbon_GetCurrentThread
+#define GetCurrentProcess __carbon_GetCurrentProcess
+
 #include <stdarg.h>
 
+#include <errno.h>
+#include <limits.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/ioctl.h>
+#include <fcntl.h>
+#include <fenv.h>
+#include <unistd.h>
+
+#include <libkern/OSAtomic.h>
+#include <CoreAudio/CoreAudio.h>
+#include <AudioToolbox/AudioFormat.h>
+#include <AudioToolbox/AudioConverter.h>
+#include <AudioUnit/AudioUnit.h>
+
+#undef LoadResource
+#undef CompareString
+#undef GetCurrentThread
+#undef GetCurrentProcess
+#undef _CDECL
+
+#include "ntstatus.h"
+#define WIN32_NO_STATUS
 #include "windef.h"
 #include "winbase.h"
-#include "wingdi.h"
-#include "winuser.h"
-#include "mmddk.h"
-#include "coreaudio.h"
+#include "winnls.h"
+#include "winreg.h"
+#include "mmdeviceapi.h"
+#include "initguid.h"
+#include "audioclient.h"
 #include "wine/debug.h"
+#include "wine/unicode.h"
+#include "wine/unixlib.h"
+
+#include "unixlib.h"
+
+WINE_DEFAULT_DEBUG_CHANNEL(coreaudio);
+
+static HRESULT osstatus_to_hresult(OSStatus sc)
+{
+    switch(sc){
+    case kAudioFormatUnsupportedDataFormatError:
+    case kAudioFormatUnknownFormatError:
+    case kAudioDeviceUnsupportedFormatError:
+        return AUDCLNT_E_UNSUPPORTED_FORMAT;
+    case kAudioHardwareBadDeviceError:
+        return AUDCLNT_E_DEVICE_INVALIDATED;
+    }
+    return E_FAIL;
+}
+
+static AudioObjectPropertyScope get_scope(EDataFlow flow)
+{
+    return (flow == eRender) ? kAudioDevicePropertyScopeOutput : kAudioDevicePropertyScopeInput;
+}
+
+static BOOL device_has_channels(AudioDeviceID device, EDataFlow flow)
+{
+    AudioObjectPropertyAddress addr;
+    AudioBufferList *buffers;
+    BOOL ret = FALSE;
+    OSStatus sc;
+    UInt32 size;
+    int i;
+
+    addr.mSelector = kAudioDevicePropertyStreamConfiguration;
+    addr.mScope = get_scope(flow);
+    addr.mElement = 0;
+
+    sc = AudioObjectGetPropertyDataSize(device, &addr, 0, NULL, &size);
+    if(sc != noErr){
+        WARN("Unable to get _StreamConfiguration property size for device %u: %x\n",
+             (unsigned int)device, (int)sc);
+        return FALSE;
+    }
+
+    buffers = malloc(size);
+    if(!buffers) return FALSE;
+
+    sc = AudioObjectGetPropertyData(device, &addr, 0, NULL, &size, buffers);
+    if(sc != noErr){
+        WARN("Unable to get _StreamConfiguration property for device %u: %x\n",
+             (unsigned int)device, (int)sc);
+        free(buffers);
+        return FALSE;
+    }
+
+    for(i = 0; i < buffers->mNumberBuffers; i++){
+        if(buffers->mBuffers[i].mNumberChannels > 0){
+            ret = TRUE;
+            break;
+        }
+    }
+    free(buffers);
+    return ret;
+}
+
+static NTSTATUS get_endpoint_ids(void *args)
+{
+    struct get_endpoint_ids_params *params = args;
+    unsigned int num_devices, i, needed;
+    AudioDeviceID *devices, default_id;
+    AudioObjectPropertyAddress addr;
+    struct endpoint *endpoint;
+    UInt32 devsize, size;
+    struct endpoint_info
+    {
+        CFStringRef name;
+        AudioDeviceID id;
+    } *info;
+    OSStatus sc;
+    WCHAR *ptr;
+
+    params->num = 0;
+    params->default_idx = 0;
+
+    addr.mScope = kAudioObjectPropertyScopeGlobal;
+    addr.mElement = kAudioObjectPropertyElementMaster;
+    if(params->flow == eRender) addr.mSelector = kAudioHardwarePropertyDefaultOutputDevice;
+    else if(params->flow == eCapture) addr.mSelector = kAudioHardwarePropertyDefaultInputDevice;
+    else{
+        params->result = E_INVALIDARG;
+        return STATUS_SUCCESS;
+    }
+
+    size = sizeof(default_id);
+    sc = AudioObjectGetPropertyData(kAudioObjectSystemObject, &addr, 0, NULL, &size, &default_id);
+    if(sc != noErr){
+        WARN("Getting _DefaultInputDevice property failed: %x\n", (int)sc);
+        default_id = -1;
+    }
+
+    addr.mSelector = kAudioHardwarePropertyDevices;
+    sc = AudioObjectGetPropertyDataSize(kAudioObjectSystemObject, &addr, 0, NULL, &devsize);
+    if(sc != noErr){
+        WARN("Getting _Devices property size failed: %x\n", (int)sc);
+        params->result = osstatus_to_hresult(sc);
+        return STATUS_SUCCESS;
+    }
+
+    num_devices = devsize / sizeof(AudioDeviceID);
+    devices = malloc(devsize);
+    info = malloc(num_devices * sizeof(*info));
+    if(!devices || !info){
+        free(info);
+        free(devices);
+        params->result = E_OUTOFMEMORY;
+        return STATUS_SUCCESS;
+    }
+
+    sc = AudioObjectGetPropertyData(kAudioObjectSystemObject, &addr, 0, NULL, &devsize, devices);
+    if(sc != noErr){
+        WARN("Getting _Devices property failed: %x\n", (int)sc);
+        free(info);
+        free(devices);
+        params->result = osstatus_to_hresult(sc);
+        return STATUS_SUCCESS;
+    }
+
+    addr.mSelector = kAudioObjectPropertyName;
+    addr.mScope = get_scope(params->flow);
+    addr.mElement = 0;
+
+    for(i = 0; i < num_devices; i++){
+        if(!device_has_channels(devices[i], params->flow)) continue;
+
+        size = sizeof(CFStringRef);
+        sc = AudioObjectGetPropertyData(devices[i], &addr, 0, NULL, &size, &info[params->num].name);
+        if(sc != noErr){
+            WARN("Unable to get _Name property for device %u: %x\n",
+                 (unsigned int)devices[i], (int)sc);
+            continue;
+        }
+        info[params->num++].id = devices[i];
+    }
+    free(devices);
+
+    needed = sizeof(*endpoint) * params->num;
+    endpoint = params->endpoints;
+    ptr = (WCHAR *)(endpoint + params->num);
+
+    for(i = 0; i < params->num; i++){
+        SIZE_T len = CFStringGetLength(info[i].name);
+        needed += (len + 1) * sizeof(WCHAR);
+
+        if(needed <= params->size){
+            endpoint->name = ptr;
+            CFStringGetCharacters(info[i].name, CFRangeMake(0, len), (UniChar*)endpoint->name);
+            ptr[len] = 0;
+            endpoint->id = info[i].id;
+            endpoint++;
+            ptr += len + 1;
+        }
+        CFRelease(info[i].name);
+        if(info[i].id == default_id) params->default_idx = i;
+    }
+    free(info);
+
+    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/winecoreaudio.drv/mmdevdrv.c b/dlls/winecoreaudio.drv/mmdevdrv.c
index f07f4bae5fb..f8b538971f2 100644
--- a/dlls/winecoreaudio.drv/mmdevdrv.c
+++ b/dlls/winecoreaudio.drv/mmdevdrv.c
@@ -56,8 +56,10 @@
 #include "winnls.h"
 #include "winreg.h"
 #include "wine/debug.h"
+#include "wine/heap.h"
 #include "wine/unicode.h"
 #include "wine/list.h"
+#include "wine/unixlib.h"
 
 #include "ole2.h"
 #include "mmdeviceapi.h"
@@ -69,9 +71,12 @@
 #include "endpointvolume.h"
 #include "audioclient.h"
 #include "audiopolicy.h"
+#include "unixlib.h"
 
 WINE_DEFAULT_DEBUG_CHANNEL(coreaudio);
 
+unixlib_handle_t coreaudio_handle = 0;
+
 #define NULL_PTR_ERR MAKE_HRESULT(SEVERITY_ERROR, FACILITY_WIN32, RPC_X_NULL_REF_POINTER)
 
 static const REFERENCE_TIME DefaultPeriod = 100000;
@@ -245,6 +250,9 @@ BOOL WINAPI DllMain(HINSTANCE dll, DWORD reason, void *reserved)
     switch (reason)
     {
     case DLL_PROCESS_ATTACH:
+        if(NtQueryVirtualMemory(GetCurrentProcess(), dll, MemoryWineUnixFuncs,
+                                &coreaudio_handle, sizeof(coreaudio_handle), NULL))
+            return FALSE;
         g_timer_q = CreateTimerQueue();
         if(!g_timer_q)
             return FALSE;
@@ -319,7 +327,7 @@ exit:
         RegCloseKey(drv_key);
 }
 
-static void get_device_guid(EDataFlow flow, AudioDeviceID device, GUID *guid)
+static void get_device_guid(EDataFlow flow, DWORD device_id, GUID *guid)
 {
     HKEY key = NULL, dev_key;
     DWORD type, size = sizeof(*guid);
@@ -333,7 +341,7 @@ static void get_device_guid(EDataFlow flow, AudioDeviceID device, GUID *guid)
         key_name[0] = '0';
     key_name[1] = ',';
 
-    sprintfW(key_name + 2, key_fmt, device);
+    sprintfW(key_name + 2, key_fmt, device_id);
 
     if(RegOpenKeyExW(HKEY_CURRENT_USER, drv_key_devicesW, 0, KEY_WRITE|KEY_READ, &key) == ERROR_SUCCESS){
         if(RegOpenKeyExW(key, key_name, 0, KEY_READ, &dev_key) == ERROR_SUCCESS){
@@ -359,164 +367,61 @@ static void get_device_guid(EDataFlow flow, AudioDeviceID device, GUID *guid)
         RegCloseKey(key);
 }
 
-HRESULT WINAPI AUDDRV_GetEndpointIDs(EDataFlow flow, WCHAR ***ids,
-        GUID **guids, UINT *num, UINT *def_index)
+HRESULT WINAPI AUDDRV_GetEndpointIDs(EDataFlow flow, WCHAR ***ids_out,
+        GUID **guids_out, UINT *num, UINT *def_index)
 {
-    UInt32 devsize, size;
-    AudioDeviceID *devices;
-    AudioDeviceID default_id;
-    AudioObjectPropertyAddress addr;
-    OSStatus sc;
-    int i, ndevices;
-
-    TRACE("%d %p %p %p\n", flow, ids, num, def_index);
-
-    addr.mScope = kAudioObjectPropertyScopeGlobal;
-    addr.mElement = kAudioObjectPropertyElementMaster;
-    if(flow == eRender)
-        addr.mSelector = kAudioHardwarePropertyDefaultOutputDevice;
-    else if(flow == eCapture)
-        addr.mSelector = kAudioHardwarePropertyDefaultInputDevice;
-    else
-        return E_INVALIDARG;
-
-    size = sizeof(default_id);
-    sc = AudioObjectGetPropertyData(kAudioObjectSystemObject, &addr, 0,
-            NULL, &size, &default_id);
-    if(sc != noErr){
-        WARN("Getting _DefaultInputDevice property failed: %x\n", (int)sc);
-        default_id = -1;
-    }
-
-    addr.mSelector = kAudioHardwarePropertyDevices;
-    sc = AudioObjectGetPropertyDataSize(kAudioObjectSystemObject, &addr, 0,
-            NULL, &devsize);
-    if(sc != noErr){
-        WARN("Getting _Devices property size failed: %x\n", (int)sc);
-        return osstatus_to_hresult(sc);
-    }
-
-    devices = HeapAlloc(GetProcessHeap(), 0, devsize);
-    if(!devices)
-        return E_OUTOFMEMORY;
-
-    sc = AudioObjectGetPropertyData(kAudioObjectSystemObject, &addr, 0, NULL,
-            &devsize, devices);
-    if(sc != noErr){
-        WARN("Getting _Devices property failed: %x\n", (int)sc);
-        HeapFree(GetProcessHeap(), 0, devices);
-        return osstatus_to_hresult(sc);
+    struct get_endpoint_ids_params params;
+    unsigned int i;
+    GUID *guids;
+    WCHAR **ids;
+
+    TRACE("%d %p %p %p\n", flow, ids_out, num, def_index);
+
+    params.flow = flow;
+    params.size = 1000;
+    params.endpoints = NULL;
+    do{
+        heap_free(params.endpoints);
+        params.endpoints = heap_alloc(params.size);
+        UNIX_CALL(get_endpoint_ids, &params);
+    }while(params.result == HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER));
+
+    if(FAILED(params.result)) goto end;
+
+    ids = heap_alloc_zero(params.num * sizeof(*ids));
+    guids = heap_alloc(params.num * sizeof(*guids));
+    if(!ids || !guids){
+        params.result = E_OUTOFMEMORY;
+        goto end;
     }
 
-    ndevices = devsize / sizeof(AudioDeviceID);
-
-    *ids = HeapAlloc(GetProcessHeap(), 0, ndevices * sizeof(WCHAR *));
-    if(!*ids){
-        HeapFree(GetProcessHeap(), 0, devices);
-        return E_OUTOFMEMORY;
-    }
-
-    *guids = HeapAlloc(GetProcessHeap(), 0, ndevices * sizeof(GUID));
-    if(!*guids){
-        HeapFree(GetProcessHeap(), 0, *ids);
-        HeapFree(GetProcessHeap(), 0, devices);
-        return E_OUTOFMEMORY;
-    }
-
-    *num = 0;
-    *def_index = (UINT)-1;
-    for(i = 0; i < ndevices; ++i){
-        AudioBufferList *buffers;
-        CFStringRef name;
-        SIZE_T len;
-        int j;
-
-        addr.mSelector = kAudioDevicePropertyStreamConfiguration;
-        if(flow == eRender)
-            addr.mScope = kAudioDevicePropertyScopeOutput;
-        else
-            addr.mScope = kAudioDevicePropertyScopeInput;
-        addr.mElement = 0;
-        sc = AudioObjectGetPropertyDataSize(devices[i], &addr, 0, NULL, &size);
-        if(sc != noErr){
-            WARN("Unable to get _StreamConfiguration property size for "
-                    "device %u: %x\n", (unsigned int)devices[i], (int)sc);
-            continue;
-        }
-
-        buffers = HeapAlloc(GetProcessHeap(), 0, size);
-        if(!buffers){
-            HeapFree(GetProcessHeap(), 0, devices);
-            for(j = 0; j < *num; ++j)
-                HeapFree(GetProcessHeap(), 0, (*ids)[j]);
-            HeapFree(GetProcessHeap(), 0, *guids);
-            HeapFree(GetProcessHeap(), 0, *ids);
-            return E_OUTOFMEMORY;
+    for(i = 0; i < params.num; i++){
+        int size = (strlenW(params.endpoints[i].name) + 1) * sizeof(WCHAR);
+        ids[i] = heap_alloc(size);
+        if(!ids[i]){
+            params.result = E_OUTOFMEMORY;
+            goto end;
         }
-
-        sc = AudioObjectGetPropertyData(devices[i], &addr, 0, NULL,
-                &size, buffers);
-        if(sc != noErr){
-            WARN("Unable to get _StreamConfiguration property for "
-                    "device %u: %x\n", (unsigned int)devices[i], (int)sc);
-            HeapFree(GetProcessHeap(), 0, buffers);
-            continue;
-        }
-
-        /* check that there's at least one channel in this device before
-         * we claim it as usable */
-        for(j = 0; j < buffers->mNumberBuffers; ++j)
-            if(buffers->mBuffers[j].mNumberChannels > 0)
-                break;
-        if(j >= buffers->mNumberBuffers){
-            HeapFree(GetProcessHeap(), 0, buffers);
-            continue;
-        }
-
-        HeapFree(GetProcessHeap(), 0, buffers);
-
-        size = sizeof(name);
-        addr.mSelector = kAudioObjectPropertyName;
-        sc = AudioObjectGetPropertyData(devices[i], &addr, 0, NULL,
-                &size, &name);
-        if(sc != noErr){
-            WARN("Unable to get _Name property for device %u: %x\n",
-                    (unsigned int)devices[i], (int)sc);
-            continue;
-        }
-
-        len = CFStringGetLength(name) + 1;
-        (*ids)[*num] = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
-        if(!(*ids)[*num]){
-            CFRelease(name);
-            HeapFree(GetProcessHeap(), 0, devices);
-            for(j = 0; j < *num; ++j)
-                HeapFree(GetProcessHeap(), 0, (*ids)[j]);
-            HeapFree(GetProcessHeap(), 0, *ids);
-            HeapFree(GetProcessHeap(), 0, *guids);
-            return E_OUTOFMEMORY;
+        memcpy(ids[i], params.endpoints[i].name, size);
+        get_device_guid(flow, params.endpoints[i].id, guids + i);
+    }
+    *def_index = params.default_idx;
+
+end:
+    heap_free(params.endpoints);
+    if(FAILED(params.result)){
+        heap_free(guids);
+        if(ids){
+            for(i = 0; i < params.num; i++) heap_free(ids[i]);
+            heap_free(ids);
         }
-        CFStringGetCharacters(name, CFRangeMake(0, len - 1), (UniChar*)(*ids)[*num]);
-        ((*ids)[*num])[len - 1] = 0;
-        CFRelease(name);
-
-        get_device_guid(flow, devices[i], &(*guids)[*num]);
-
-        if(*def_index == (UINT)-1 && devices[i] == default_id)
-            *def_index = *num;
-
-        TRACE("device %u: id %s key %u%s\n", *num, debugstr_w((*ids)[*num]),
-              (unsigned int)devices[i], (*def_index == *num) ? " (default)" : "");
-
-        (*num)++;
+    }else{
+        *ids_out = ids;
+        *guids_out = guids;
+        *num = params.num;
     }
 
-    if(*def_index == (UINT)-1)
-        *def_index = 0;
-
-    HeapFree(GetProcessHeap(), 0, devices);
-
-    return S_OK;
+    return params.result;
 }
 
 static BOOL get_deviceid_by_guid(GUID *guid, AudioDeviceID *id, EDataFlow *flow)
diff --git a/dlls/winecoreaudio.drv/unixlib.h b/dlls/winecoreaudio.drv/unixlib.h
new file mode 100644
index 00000000000..7c1200464b9
--- /dev/null
+++ b/dlls/winecoreaudio.drv/unixlib.h
@@ -0,0 +1,44 @@
+/*
+ * Unixlib header file for winecoreaudio driver.
+ *
+ * Copyright 2021 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;
+    DWORD id;
+};
+
+struct get_endpoint_ids_params
+{
+    EDataFlow flow;
+    struct endpoint *endpoints;
+    unsigned int size;
+    HRESULT result;
+    unsigned int num;
+    unsigned int default_idx;
+};
+
+enum unix_funcs
+{
+    unix_get_endpoint_ids,
+};
+
+extern unixlib_handle_t coreaudio_handle;
+
+#define UNIX_CALL( func, params ) __wine_unix_call( coreaudio_handle, unix_ ## func, params )
-- 
2.33.1





More information about the wine-devel mailing list