[PATCH 4/6] winealsa: Move MIDM_OPEN and MIDM_CLOSE to the unixlib.
Huw Davies
huw at codeweavers.com
Fri Mar 25 03:42:17 CDT 2022
Signed-off-by: Huw Davies <huw at codeweavers.com>
---
dlls/winealsa.drv/Makefile.in | 2 +-
dlls/winealsa.drv/alsa.c | 4 -
dlls/winealsa.drv/alsamidi.c | 231 ++++++++++++++++++++++++---
dlls/winealsa.drv/midi.c | 287 ----------------------------------
dlls/winealsa.drv/unixlib.h | 33 ----
5 files changed, 206 insertions(+), 351 deletions(-)
diff --git a/dlls/winealsa.drv/Makefile.in b/dlls/winealsa.drv/Makefile.in
index 41be57d8b83..2113594fbe3 100644
--- a/dlls/winealsa.drv/Makefile.in
+++ b/dlls/winealsa.drv/Makefile.in
@@ -3,7 +3,7 @@ MODULE = winealsa.drv
UNIXLIB = winealsa.so
IMPORTS = uuid ole32 advapi32
DELAYIMPORTS = winmm
-EXTRALIBS = $(ALSA_LIBS)
+EXTRALIBS = $(ALSA_LIBS) $(PTHREAD_LIBS)
EXTRADLLFLAGS = -mcygwin
diff --git a/dlls/winealsa.drv/alsa.c b/dlls/winealsa.drv/alsa.c
index b18588ab1c0..e068f6608f3 100644
--- a/dlls/winealsa.drv/alsa.c
+++ b/dlls/winealsa.drv/alsa.c
@@ -2449,8 +2449,4 @@ unixlib_entry_t __wine_unix_call_funcs[] =
midi_out_message,
midi_in_message,
midi_notify_wait,
-
- midi_seq_lock, /* temporary */
- midi_seq_open,
- midi_handle_event,
};
diff --git a/dlls/winealsa.drv/alsamidi.c b/dlls/winealsa.drv/alsamidi.c
index 1633268b533..8ec646281d2 100644
--- a/dlls/winealsa.drv/alsamidi.c
+++ b/dlls/winealsa.drv/alsamidi.c
@@ -60,6 +60,19 @@ struct midi_dest
int port_out;
};
+struct midi_src
+{
+ int state; /* -1 disabled, 0 is no recording started, 1 in recording, bit 2 set if in sys exclusive recording */
+ MIDIOPENDESC midiDesc;
+ WORD wFlags;
+ MIDIHDR *lpQueueHdr;
+ UINT startTime;
+ MIDIINCAPSW caps;
+ snd_seq_t *seq;
+ snd_seq_addr_t addr;
+ int port_in;
+};
+
static pthread_mutex_t seq_mutex = PTHREAD_MUTEX_INITIALIZER;
static pthread_mutex_t in_buffer_mutex = PTHREAD_MUTEX_INITIALIZER;
@@ -70,6 +83,10 @@ static snd_seq_t *midi_seq;
static unsigned int seq_refs;
static int port_in = -1;
+static unsigned int num_midi_in_started;
+static int rec_cancel_pipe[2];
+static pthread_t rec_thread_id;
+
static pthread_mutex_t notify_mutex = PTHREAD_MUTEX_INITIALIZER;
static pthread_cond_t notify_cond = PTHREAD_COND_INITIALIZER;
static BOOL notify_quit;
@@ -87,14 +104,6 @@ static void seq_unlock(void)
pthread_mutex_unlock(&seq_mutex);
}
-NTSTATUS midi_seq_lock(void *args)
-{
- if (args) seq_lock();
- else seq_unlock();
-
- return STATUS_SUCCESS;
-}
-
static void in_buffer_lock(void)
{
pthread_mutex_lock(&in_buffer_mutex);
@@ -233,18 +242,6 @@ static void seq_close(void)
seq_unlock();
}
-NTSTATUS midi_seq_open(void *args)
-{
- struct midi_seq_open_params *params = args;
-
- if (!params->close)
- params->seq = seq_open(params->port_in);
- else
- seq_close();
-
- return STATUS_SUCCESS;
-}
-
static int alsa_to_win_device_type(unsigned int type)
{
/* MOD_MIDIPORT output port
@@ -458,8 +455,6 @@ NTSTATUS midi_init(void *args)
free( pinfo );
*params->err = NOERROR;
- params->num_srcs = num_srcs;
- params->srcs = srcs;
TRACE("End\n");
@@ -1033,9 +1028,8 @@ static void handle_regular_event(struct midi_src *src, snd_seq_event_t *ev)
}
}
-NTSTATUS midi_handle_event(void *args)
+static void midi_handle_event(snd_seq_event_t *ev)
{
- snd_seq_event_t *ev = args;
struct midi_src *src;
/* Find the target device */
@@ -1043,14 +1037,193 @@ NTSTATUS midi_handle_event(void *args)
if ((ev->source.client == src->addr.client) && (ev->source.port == src->addr.port))
break;
if ((src == srcs + num_srcs) || (src->state != 1))
- return STATUS_SUCCESS;
+ return;
if (ev->type == SND_SEQ_EVENT_SYSEX)
handle_sysex_event(src, ev->data.ext.ptr, ev->data.ext.len);
else
handle_regular_event(src, ev);
+}
- return STATUS_SUCCESS;
+static void *rec_thread_proc(void *arg)
+{
+ snd_seq_t *midi_seq = (snd_seq_t *)arg;
+ int num_fds;
+ struct pollfd *pollfd;
+ int ret;
+
+ /* Add on one for the read end of the cancel pipe */
+ num_fds = snd_seq_poll_descriptors_count(midi_seq, POLLIN) + 1;
+ pollfd = malloc(num_fds * sizeof(struct pollfd));
+
+ while(1)
+ {
+ pollfd[0].fd = rec_cancel_pipe[0];
+ pollfd[0].events = POLLIN;
+
+ seq_lock();
+ snd_seq_poll_descriptors(midi_seq, pollfd + 1, num_fds - 1, POLLIN);
+ seq_unlock();
+
+ /* Check if an event is present */
+ if (poll(pollfd, num_fds, -1) <= 0)
+ continue;
+
+ if (pollfd[0].revents & POLLIN) /* cancelled */
+ break;
+
+ do
+ {
+ snd_seq_event_t *ev;
+
+ seq_lock();
+ snd_seq_event_input(midi_seq, &ev);
+ seq_unlock();
+
+ if (ev)
+ {
+ midi_handle_event(ev);
+ snd_seq_free_event(ev);
+ }
+
+ seq_lock();
+ ret = snd_seq_event_input_pending(midi_seq, 0);
+ seq_unlock();
+ } while(ret > 0);
+ }
+
+ free(pollfd);
+ return 0;
+}
+
+static UINT midi_in_open(WORD dev_id, MIDIOPENDESC *desc, UINT flags, struct notify_context *notify)
+{
+ struct midi_src *src;
+ int ret = 0, port_in;
+ snd_seq_t *midi_seq;
+
+ TRACE("(%04X, %p, %08X);\n", dev_id, desc, flags);
+
+ if (!desc)
+ {
+ WARN("Invalid Parameter !\n");
+ return MMSYSERR_INVALPARAM;
+ }
+
+ /* FIXME: check that contents of desc are correct */
+
+ if (dev_id >= num_srcs)
+ {
+ WARN("dev_id too large (%u) !\n", dev_id);
+ return MMSYSERR_BADDEVICEID;
+ }
+ src = srcs + dev_id;
+
+ if (src->state == -1)
+ {
+ WARN("device disabled\n");
+ return MIDIERR_NODEVICE;
+ }
+ if (src->midiDesc.hMidi)
+ {
+ WARN("device already open !\n");
+ return MMSYSERR_ALLOCATED;
+ }
+ if (flags & MIDI_IO_STATUS)
+ {
+ WARN("No support for MIDI_IO_STATUS in flags yet, ignoring it\n");
+ flags &= ~MIDI_IO_STATUS;
+ }
+ if (flags & ~CALLBACK_TYPEMASK)
+ {
+ FIXME("Bad flags %08X\n", flags);
+ return MMSYSERR_INVALFLAG;
+ }
+
+ if (!(midi_seq = seq_open(&port_in)))
+ return MMSYSERR_ERROR;
+
+ src->wFlags = HIWORD(flags & CALLBACK_TYPEMASK);
+
+ src->lpQueueHdr = NULL;
+ src->midiDesc = *desc;
+ src->state = 0;
+ src->startTime = 0;
+ src->seq = midi_seq;
+ src->port_in = port_in;
+
+ /* Connect our app port to the device port */
+ seq_lock();
+ ret = snd_seq_connect_from(midi_seq, port_in, src->addr.client, src->addr.port);
+ seq_unlock();
+ if (ret < 0)
+ return MMSYSERR_NOTENABLED;
+
+ TRACE("Input port :%d connected %d:%d\n", port_in, src->addr.client, src->addr.port);
+
+ if (num_midi_in_started++ == 0)
+ {
+ pipe(rec_cancel_pipe);
+ if (pthread_create(&rec_thread_id, NULL, rec_thread_proc, midi_seq))
+ {
+ close(rec_cancel_pipe[0]);
+ close(rec_cancel_pipe[1]);
+ num_midi_in_started = 0;
+ WARN("Couldn't create thread for midi-in\n");
+ seq_close();
+ return MMSYSERR_ERROR;
+ }
+ }
+
+ set_in_notify(notify, src, dev_id, MIM_OPEN, 0, 0);
+ return MMSYSERR_NOERROR;
+}
+
+static UINT midi_in_close(WORD dev_id, struct notify_context *notify)
+{
+ struct midi_src *src;
+
+ TRACE("(%04X);\n", dev_id);
+
+ if (dev_id >= num_srcs)
+ {
+ WARN("dev_id too big (%u) !\n", dev_id);
+ return MMSYSERR_BADDEVICEID;
+ }
+ src = srcs + dev_id;
+ if (!src->midiDesc.hMidi)
+ {
+ WARN("device not opened !\n");
+ return MMSYSERR_ERROR;
+ }
+ if (src->lpQueueHdr)
+ return MIDIERR_STILLPLAYING;
+
+ if (src->seq == NULL)
+ {
+ WARN("ooops !\n");
+ return MMSYSERR_ERROR;
+ }
+ if (--num_midi_in_started == 0)
+ {
+ TRACE("Stopping thread for midi-in\n");
+ write(rec_cancel_pipe[1], "x", 1);
+ pthread_join(rec_thread_id, NULL);
+ close(rec_cancel_pipe[0]);
+ close(rec_cancel_pipe[1]);
+ TRACE("Stopped thread for midi-in\n");
+ }
+
+ seq_lock();
+ snd_seq_disconnect_from(src->seq, src->port_in, src->addr.client, src->addr.port);
+ seq_unlock();
+ seq_close();
+
+ set_in_notify(notify, src, dev_id, MIM_CLOSE, 0, 0);
+ src->midiDesc.hMidi = 0;
+ src->seq = NULL;
+
+ return MMSYSERR_NOERROR;
}
static UINT midi_in_add_buffer(WORD dev_id, MIDIHDR *hdr, UINT hdr_size)
@@ -1257,6 +1430,12 @@ NTSTATUS midi_in_message(void *args)
/* FIXME: Pretend this is supported */
*params->err = MMSYSERR_NOERROR;
break;
+ case MIDM_OPEN:
+ *params->err = midi_in_open(params->dev_id, (MIDIOPENDESC *)params->param_1, params->param_2, params->notify);
+ break;
+ case MIDM_CLOSE:
+ *params->err = midi_in_close(params->dev_id, params->notify);
+ break;
case MIDM_ADDBUFFER:
*params->err = midi_in_add_buffer(params->dev_id, (MIDIHDR *)params->param_1, params->param_2);
break;
diff --git a/dlls/winealsa.drv/midi.c b/dlls/winealsa.drv/midi.c
index 327d4b7b200..b768517e655 100644
--- a/dlls/winealsa.drv/midi.c
+++ b/dlls/winealsa.drv/midi.c
@@ -47,26 +47,6 @@
WINE_DEFAULT_DEBUG_CHANNEL(midi);
-static WINE_MIDIIN *MidiInDev;
-
-/* this is the total number of MIDI out devices found */
-static int MIDM_NumDevs = 0;
-
-static int numStartedMidiIn = 0;
-
-static int rec_cancel_pipe[2];
-static HANDLE hThread;
-
-static void seq_lock(void)
-{
- ALSA_CALL(midi_seq_lock, (void *)(UINT_PTR)1);
-}
-
-static void seq_unlock(void)
-{
- ALSA_CALL(midi_seq_lock, (void *)(UINT_PTR)0);
-}
-
static void notify_client(struct notify_context *notify)
{
TRACE("dev_id = %d msg = %d param1 = %04lX param2 = %04lX\n", notify->dev_id, notify->msg, notify->param_1, notify->param_2);
@@ -75,264 +55,6 @@ static void notify_client(struct notify_context *notify)
notify->instance, notify->param_1, notify->param_2);
}
-/*======================================================================*
- * Low level MIDI implementation *
- *======================================================================*/
-
-#if 0 /* Debug Purpose */
-static void error_handler(const char* file, int line, const char* function, int err, const char* fmt, ...)
-{
- va_list arg;
- if (err == ENOENT)
- return;
- va_start(arg, fmt);
- fprintf(stderr, "ALSA lib %s:%i:(%s) ", file, line, function);
- vfprintf(stderr, fmt, arg);
- if (err)
- fprintf(stderr, ": %s", snd_strerror(err));
- putc('\n', stderr);
- va_end(arg);
-}
-#endif
-
-/**************************************************************************
- * MIDI_NotifyClient [internal]
- */
-static void MIDI_NotifyClient(UINT wDevID, WORD wMsg,
- DWORD_PTR dwParam1, DWORD_PTR dwParam2)
-{
- DWORD_PTR dwCallBack;
- UINT uFlags;
- HANDLE hDev;
- DWORD_PTR dwInstance;
-
- TRACE("wDevID = %04X wMsg = %d dwParm1 = %04lX dwParam2 = %04lX\n",
- wDevID, wMsg, dwParam1, dwParam2);
-
- switch (wMsg) {
- case MIM_OPEN:
- case MIM_CLOSE:
- if (wDevID > MIDM_NumDevs) return;
-
- dwCallBack = MidiInDev[wDevID].midiDesc.dwCallback;
- uFlags = MidiInDev[wDevID].wFlags;
- hDev = MidiInDev[wDevID].midiDesc.hMidi;
- dwInstance = MidiInDev[wDevID].midiDesc.dwInstance;
- break;
- default:
- ERR("Unsupported MSW-MIDI message %u\n", wMsg);
- return;
- }
-
- DriverCallback(dwCallBack, uFlags, hDev, wMsg, dwInstance, dwParam1, dwParam2);
-}
-
-/**************************************************************************
- * midiOpenSeq [internal]
- */
-static snd_seq_t *midiOpenSeq(int *port_in_ret)
-{
- struct midi_seq_open_params params;
-
- params.port_in = port_in_ret;
- params.close = 0;
- ALSA_CALL(midi_seq_open, ¶ms);
-
- return params.seq;
-}
-
-/**************************************************************************
- * midiCloseSeq [internal]
- */
-static int midiCloseSeq(void)
-{
- struct midi_seq_open_params params;
-
- params.port_in = NULL;
- params.close = 1;
- ALSA_CALL(midi_seq_open, ¶ms);
-
- return 0;
-}
-
-static DWORD WINAPI midRecThread(void *arg)
-{
- snd_seq_t *midi_seq = arg;
- int num_fds;
- struct pollfd *pollfd;
- int ret;
-
- /* Add on one for the read end of the cancel pipe */
- num_fds = snd_seq_poll_descriptors_count(midi_seq, POLLIN) + 1;
- pollfd = malloc(num_fds * sizeof(struct pollfd));
-
- while(1) {
- pollfd[0].fd = rec_cancel_pipe[0];
- pollfd[0].events = POLLIN;
-
- seq_lock();
- snd_seq_poll_descriptors(midi_seq, pollfd + 1, num_fds - 1, POLLIN);
- seq_unlock();
-
- /* Check if an event is present */
- if (poll(pollfd, num_fds, -1) <= 0)
- continue;
-
- if (pollfd[0].revents & POLLIN) /* cancelled */
- break;
-
- do {
- snd_seq_event_t *ev;
-
- seq_lock();
- snd_seq_event_input(midi_seq, &ev);
- seq_unlock();
-
- if (ev) {
- ALSA_CALL(midi_handle_event, ev);
- snd_seq_free_event(ev);
- }
-
- seq_lock();
- ret = snd_seq_event_input_pending(midi_seq, 0);
- seq_unlock();
- } while(ret > 0);
- }
-
- free(pollfd);
- return 0;
-}
-
-/**************************************************************************
- * midOpen [internal]
- */
-static DWORD midOpen(WORD wDevID, LPMIDIOPENDESC lpDesc, DWORD dwFlags)
-{
- int ret = 0, port_in;
- snd_seq_t *midi_seq;
-
- TRACE("(%04X, %p, %08X);\n", wDevID, lpDesc, dwFlags);
-
- if (lpDesc == NULL) {
- WARN("Invalid Parameter !\n");
- return MMSYSERR_INVALPARAM;
- }
-
- /* FIXME :
- * how to check that content of lpDesc is correct ?
- */
- if (wDevID >= MIDM_NumDevs) {
- WARN("wDevID too large (%u) !\n", wDevID);
- return MMSYSERR_BADDEVICEID;
- }
- if (MidiInDev[wDevID].state == -1) {
- WARN("device disabled\n");
- return MIDIERR_NODEVICE;
- }
- if (MidiInDev[wDevID].midiDesc.hMidi != 0) {
- WARN("device already open !\n");
- return MMSYSERR_ALLOCATED;
- }
- if ((dwFlags & MIDI_IO_STATUS) != 0) {
- WARN("No support for MIDI_IO_STATUS in dwFlags yet, ignoring it\n");
- dwFlags &= ~MIDI_IO_STATUS;
- }
- if ((dwFlags & ~CALLBACK_TYPEMASK) != 0) {
- FIXME("Bad dwFlags\n");
- return MMSYSERR_INVALFLAG;
- }
-
- if (!(midi_seq = midiOpenSeq(&port_in))) {
- return MMSYSERR_ERROR;
- }
-
- MidiInDev[wDevID].wFlags = HIWORD(dwFlags & CALLBACK_TYPEMASK);
-
- MidiInDev[wDevID].lpQueueHdr = NULL;
- MidiInDev[wDevID].midiDesc = *lpDesc;
- MidiInDev[wDevID].state = 0;
- MidiInDev[wDevID].startTime = 0;
- MidiInDev[wDevID].seq = midi_seq;
- MidiInDev[wDevID].port_in = port_in;
-
- /* Connect our app port to the device port */
- seq_lock();
- ret = snd_seq_connect_from(midi_seq, port_in, MidiInDev[wDevID].addr.client,
- MidiInDev[wDevID].addr.port);
- seq_unlock();
- if (ret < 0)
- return MMSYSERR_NOTENABLED;
-
- TRACE("Input port :%d connected %d:%d\n",port_in,MidiInDev[wDevID].addr.client,MidiInDev[wDevID].addr.port);
-
- if (numStartedMidiIn++ == 0) {
- pipe(rec_cancel_pipe);
- hThread = CreateThread(NULL, 0, midRecThread, midi_seq, 0, NULL);
- if (!hThread) {
- close(rec_cancel_pipe[0]);
- close(rec_cancel_pipe[1]);
- numStartedMidiIn = 0;
- WARN("Couldn't create thread for midi-in\n");
- midiCloseSeq();
- return MMSYSERR_ERROR;
- }
- SetThreadPriority(hThread, THREAD_PRIORITY_TIME_CRITICAL);
- TRACE("Created thread for midi-in\n");
- }
-
- MIDI_NotifyClient(wDevID, MIM_OPEN, 0L, 0L);
- return MMSYSERR_NOERROR;
-}
-
-/**************************************************************************
- * midClose [internal]
- */
-static DWORD midClose(WORD wDevID)
-{
- int ret = MMSYSERR_NOERROR;
-
- TRACE("(%04X);\n", wDevID);
-
- if (wDevID >= MIDM_NumDevs) {
- WARN("wDevID too big (%u) !\n", wDevID);
- return MMSYSERR_BADDEVICEID;
- }
- if (MidiInDev[wDevID].midiDesc.hMidi == 0) {
- WARN("device not opened !\n");
- return MMSYSERR_ERROR;
- }
- if (MidiInDev[wDevID].lpQueueHdr != 0) {
- return MIDIERR_STILLPLAYING;
- }
-
- if (MidiInDev[wDevID].seq == NULL) {
- WARN("ooops !\n");
- return MMSYSERR_ERROR;
- }
- if (--numStartedMidiIn == 0) {
- TRACE("Stopping thread for midi-in\n");
- write(rec_cancel_pipe[1], "x", 1);
- if (WaitForSingleObject(hThread, 5000) != WAIT_OBJECT_0) {
- WARN("Thread end not signaled, force termination\n");
- TerminateThread(hThread, 0);
- }
- close(rec_cancel_pipe[0]);
- close(rec_cancel_pipe[1]);
- TRACE("Stopped thread for midi-in\n");
- }
-
- seq_lock();
- snd_seq_disconnect_from(MidiInDev[wDevID].seq, MidiInDev[wDevID].port_in, MidiInDev[wDevID].addr.client, MidiInDev[wDevID].addr.port);
- seq_unlock();
- midiCloseSeq();
-
- MIDI_NotifyClient(wDevID, MIM_CLOSE, 0L, 0L);
- MidiInDev[wDevID].midiDesc.hMidi = 0;
- MidiInDev[wDevID].seq = NULL;
-
- return ret;
-}
-
/*======================================================================*
* MIDI entry points *
*======================================================================*/
@@ -350,11 +72,6 @@ static BOOL ALSA_MidiInit(void)
params.err = &err;
ALSA_CALL(midi_init, ¶ms);
- if (!err)
- {
- MIDM_NumDevs = params.num_srcs;
- MidiInDev = params.srcs;
- }
return TRUE;
}
@@ -374,10 +91,6 @@ DWORD WINAPI ALSA_midMessage(UINT wDevID, UINT wMsg, DWORD_PTR dwUser,
case DRVM_INIT:
ALSA_MidiInit();
return 0;
- case MIDM_OPEN:
- return midOpen(wDevID, (LPMIDIOPENDESC)dwParam1, dwParam2);
- case MIDM_CLOSE:
- return midClose(wDevID);
}
params.dev_id = wDevID;
diff --git a/dlls/winealsa.drv/unixlib.h b/dlls/winealsa.drv/unixlib.h
index 46f256a1c6a..ad8865a0988 100644
--- a/dlls/winealsa.drv/unixlib.h
+++ b/dlls/winealsa.drv/unixlib.h
@@ -207,27 +207,9 @@ struct get_prop_value_params
unsigned int *buffer_size;
};
-#include <alsa/asoundlib.h>
-#include "mmddk.h"
-
-typedef struct midi_src
-{
- int state; /* -1 disabled, 0 is no recording started, 1 in recording, bit 2 set if in sys exclusive recording */
- MIDIOPENDESC midiDesc;
- WORD wFlags;
- MIDIHDR *lpQueueHdr;
- UINT startTime;
- MIDIINCAPSW caps;
- snd_seq_t *seq;
- snd_seq_addr_t addr;
- int port_in;
-} WINE_MIDIIN;
-
struct midi_init_params
{
UINT *err;
- unsigned int num_srcs;
- void *srcs;
};
struct notify_context
@@ -271,13 +253,6 @@ struct midi_notify_wait_params
struct notify_context *notify;
};
-struct midi_seq_open_params
-{
- int close;
- snd_seq_t *seq;
- int *port_in;
-};
-
enum alsa_funcs
{
alsa_get_endpoint_ids,
@@ -308,10 +283,6 @@ enum alsa_funcs
alsa_midi_out_message,
alsa_midi_in_message,
alsa_midi_notify_wait,
-
- alsa_midi_seq_lock, /* temporary */
- alsa_midi_seq_open,
- alsa_midi_handle_event,
};
NTSTATUS midi_init(void *args) DECLSPEC_HIDDEN;
@@ -320,10 +291,6 @@ NTSTATUS midi_out_message(void *args) DECLSPEC_HIDDEN;
NTSTATUS midi_in_message(void *args) DECLSPEC_HIDDEN;
NTSTATUS midi_notify_wait(void *args) DECLSPEC_HIDDEN;
-NTSTATUS midi_seq_lock(void *args) DECLSPEC_HIDDEN;
-NTSTATUS midi_seq_open(void *args) DECLSPEC_HIDDEN;
-NTSTATUS midi_handle_event(void *args) DECLSPEC_HIDDEN;
-
extern unixlib_handle_t alsa_handle;
#define ALSA_CALL(func, params) __wine_unix_call(alsa_handle, alsa_ ## func, params)
--
2.25.1
More information about the wine-devel
mailing list