Signed-off-by: Huw Davies huw@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, ¶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 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;
Signed-off-by: Andrew Eikum aeikum@codeweavers.com
On Thu, Mar 31, 2022 at 08:21:50AM +0100, Huw Davies wrote:
Signed-off-by: Huw Davies huw@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, ¶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 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