[PATCH 2/6] winecoreaudio: Move get_endpoint_ids to a unixlib.
Huw Davies
huw at codeweavers.com
Mon Nov 15 06:27:10 CST 2021
Signed-off-by: Huw Davies <huw at codeweavers.com>
---
dlls/winecoreaudio.drv/Makefile.in | 1 +
dlls/winecoreaudio.drv/coreaudio.c | 229 ++++++++++++++++++++++++++++-
dlls/winecoreaudio.drv/mmdevdrv.c | 203 +++++++------------------
dlls/winecoreaudio.drv/unixlib.h | 44 ++++++
4 files changed, 322 insertions(+), 155 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);
- }
+ struct get_endpoint_ids_params params;
+ unsigned int i;
+ GUID *guids;
+ WCHAR **ids;
- 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);
- }
+ TRACE("%d %p %p %p\n", flow, ids_out, num, def_index);
- ndevices = devsize / sizeof(AudioDeviceID);
+ 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, ¶ms);
+ }while(params.result == HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER));
- *ids = HeapAlloc(GetProcessHeap(), 0, ndevices * sizeof(WCHAR *));
- if(!*ids){
- HeapFree(GetProcessHeap(), 0, devices);
- return E_OUTOFMEMORY;
- }
+ if(FAILED(params.result)) goto end;
- *guids = HeapAlloc(GetProcessHeap(), 0, ndevices * sizeof(GUID));
- if(!*guids){
- HeapFree(GetProcessHeap(), 0, *ids);
- HeapFree(GetProcessHeap(), 0, devices);
- return E_OUTOFMEMORY;
+ ids = heap_alloc_zero(params.num * sizeof(*ids));
+ guids = heap_alloc(params.num * sizeof(*guids));
+ if(!ids || !guids){
+ params.result = E_OUTOFMEMORY;
+ goto end;
}
- *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;
- }
-
- 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;
+ 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;
}
-
- 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.23.0
More information about the wine-devel
mailing list