Commit 207b38a8 authored by Huw Davies's avatar Huw Davies Committed by Alexandre Julliard

wineoss: Move MIDM_OPEN and MIDM_CLOSE to the unixlib.

parent 4a943cbd
......@@ -3,7 +3,7 @@ MODULE = wineoss.drv
UNIXLIB = wineoss.so
IMPORTS = uuid ole32 user32 advapi32
DELAYIMPORTS = winmm
EXTRALIBS = $(OSS4_LIBS)
EXTRALIBS = $(OSS4_LIBS) $(PTHREAD_LIBS)
EXTRAINCL = $(OSS4_CFLAGS)
EXTRADLLFLAGS = -mcygwin
......
......@@ -63,23 +63,10 @@
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;
/*======================================================================*
* Low level MIDI implementation *
*======================================================================*/
static int midiOpenSeq(void);
static int midiCloseSeq(int);
static int MIDI_loadcount;
/**************************************************************************
* OSS_MidiInit [internal]
......@@ -100,11 +87,6 @@ static LRESULT OSS_MidiInit(void)
params.err = &err;
OSS_CALL(midi_init, &params);
if (!err)
{
MidiInDev = params.srcs;
MIDM_NumDevs = params.num_srcs;
}
return err;
}
......@@ -120,9 +102,6 @@ static LRESULT OSS_MidiExit(void)
if (--MIDI_loadcount)
return 1;
MidiInDev = NULL;
MIDM_NumDevs = 0;
return 0;
}
......@@ -135,224 +114,6 @@ static void notify_client(struct notify_context *notify)
notify->instance, notify->param_1, notify->param_2);
}
/**************************************************************************
* 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:
case MIM_DATA:
case MIM_LONGDATA:
case MIM_ERROR:
case MIM_LONGERROR:
case MIM_MOREDATA:
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 int midiOpenSeq(void)
{
struct midi_seq_open_params params;
params.close = 0;
params.fd = -1;
OSS_CALL(midi_seq_open, &params);
return params.fd;
}
/**************************************************************************
* midiCloseSeq [internal]
*/
static int midiCloseSeq(int fd)
{
struct midi_seq_open_params params;
params.close = 1;
params.fd = fd;
OSS_CALL(midi_seq_open, &params);
return 0;
}
static void handle_midi_data(unsigned char *buffer, unsigned int len)
{
struct midi_handle_data_params params;
params.buffer = buffer;
params.len = len;
OSS_CALL(midi_handle_data, &params);
}
static DWORD WINAPI midRecThread(void *arg)
{
int fd = (int)(INT_PTR)arg;
unsigned char buffer[256];
int len;
struct pollfd pollfd[2];
pollfd[0].fd = rec_cancel_pipe[0];
pollfd[0].events = POLLIN;
pollfd[1].fd = fd;
pollfd[1].events = POLLIN;
while (1)
{
/* Check if an event is present */
if (poll(pollfd, ARRAY_SIZE(pollfd), -1) <= 0)
continue;
if (pollfd[0].revents & POLLIN) /* cancelled */
break;
len = read(fd, buffer, sizeof(buffer));
if (len > 0 && len % 4 == 0)
handle_midi_data(buffer, len);
}
return 0;
}
/**************************************************************************
* midOpen [internal]
*/
static DWORD midOpen(WORD wDevID, LPMIDIOPENDESC lpDesc, DWORD dwFlags)
{
int fd;
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;
}
fd = midiOpenSeq();
if (fd < 0) {
return MMSYSERR_ERROR;
}
if (numStartedMidiIn++ == 0) {
pipe(rec_cancel_pipe);
hThread = CreateThread(NULL, 0, midRecThread, (void *)(INT_PTR)fd, 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(fd);
return MMSYSERR_ERROR;
}
SetThreadPriority(hThread, THREAD_PRIORITY_TIME_CRITICAL);
TRACE("Created thread for midi-in\n");
}
MidiInDev[wDevID].wFlags = HIWORD(dwFlags & CALLBACK_TYPEMASK);
MidiInDev[wDevID].lpQueueHdr = NULL;
MidiInDev[wDevID].midiDesc = *lpDesc;
MidiInDev[wDevID].state = 0;
MidiInDev[wDevID].incLen = 0;
MidiInDev[wDevID].startTime = 0;
MidiInDev[wDevID].fd = fd;
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].fd == -1) {
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");
}
midiCloseSeq(MidiInDev[wDevID].fd);
MidiInDev[wDevID].fd = -1;
MIDI_NotifyClient(wDevID, MIM_CLOSE, 0L, 0L);
MidiInDev[wDevID].midiDesc.hMidi = 0;
return ret;
}
/*======================================================================*
* MIDI entry points *
*======================================================================*/
......@@ -374,10 +135,6 @@ DWORD WINAPI OSS_midMessage(UINT wDevID, UINT wMsg, DWORD_PTR dwUser,
return OSS_MidiInit();
case DRVM_EXIT:
return OSS_MidiExit();
case MIDM_OPEN:
return midOpen(wDevID, (LPMIDIOPENDESC)dwParam1, dwParam2);
case MIDM_CLOSE:
return midClose(wDevID);
}
params.dev_id = wDevID;
......
......@@ -1410,7 +1410,4 @@ unixlib_entry_t __wine_unix_call_funcs[] =
midi_out_message,
midi_in_message,
midi_notify_wait,
midi_seq_open,
midi_handle_data,
};
......@@ -33,6 +33,7 @@
#include <stdint.h>
#include <time.h>
#include <unistd.h>
#include <poll.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/stat.h>
......@@ -45,6 +46,7 @@
#define WIN32_NO_STATUS
#include "winternl.h"
#include "audioclient.h"
#include "mmddk.h"
#include "wine/debug.h"
#include "wine/unixlib.h"
......@@ -62,12 +64,30 @@ struct midi_dest
int fd;
};
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;
unsigned char incoming[3];
unsigned char incPrev;
char incLen;
UINT startTime;
MIDIINCAPSW caps;
int fd;
};
static pthread_mutex_t in_buffer_mutex = PTHREAD_MUTEX_INITIALIZER;
static unsigned int num_dests, num_srcs, num_synths, seq_refs;
static struct midi_dest dests[MAX_MIDIOUTDRV];
static struct midi_src srcs[MAX_MIDIINDRV];
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_read_cond = PTHREAD_COND_INITIALIZER;
static pthread_cond_t notify_write_cond = PTHREAD_COND_INITIALIZER;
......@@ -281,18 +301,6 @@ static int seq_close(int fd)
return 0;
}
NTSTATUS midi_seq_open(void *args)
{
struct midi_seq_open_params *params = args;
if (!params->close)
params->fd = seq_open();
else
seq_close(params->fd);
return STATUS_SUCCESS;
}
NTSTATUS midi_init(void *args)
{
struct midi_init_params *params = args;
......@@ -499,8 +507,6 @@ wrapup:
seq_close(fd);
*params->err = 0;
params->num_srcs = num_srcs;
params->srcs = srcs;
return STATUS_SUCCESS;
}
......@@ -1313,11 +1319,8 @@ static void handle_regular_data(struct midi_src *src, unsigned char value, UINT
}
}
NTSTATUS midi_handle_data(void *args)
static void handle_midi_data(unsigned char *buffer, unsigned int len)
{
struct midi_handle_data_params *params = args;
unsigned char *buffer = params->buffer;
unsigned int len = params->len;
unsigned int time = get_time_msec(), i;
struct midi_src *src;
unsigned char value;
......@@ -1339,7 +1342,153 @@ NTSTATUS midi_handle_data(void *args)
else
handle_regular_data(src, value, time - src->startTime);
}
return STATUS_SUCCESS;
}
static void *rec_thread_proc(void *arg)
{
int fd = PtrToLong(arg);
unsigned char buffer[256];
int len;
struct pollfd pollfd[2];
pollfd[0].fd = rec_cancel_pipe[0];
pollfd[0].events = POLLIN;
pollfd[1].fd = fd;
pollfd[1].events = POLLIN;
while (1)
{
/* Check if an event is present */
if (poll(pollfd, ARRAY_SIZE(pollfd), -1) <= 0)
continue;
if (pollfd[0].revents & POLLIN) /* cancelled */
break;
len = read(fd, buffer, sizeof(buffer));
if (len > 0 && len % 4 == 0)
handle_midi_data(buffer, len);
}
return NULL;
}
static UINT midi_in_open(WORD dev_id, MIDIOPENDESC *desc, UINT flags, struct notify_context *notify)
{
struct midi_src *src;
int fd;
TRACE("(%04X, %p, %08X);\n", dev_id, desc, flags);
if (desc == NULL)
{
WARN("Invalid Parameter !\n");
return MMSYSERR_INVALPARAM;
}
/* FIXME :
* how to check that content of lpDesc is correct ?
*/
if (dev_id >= num_srcs)
{
WARN("wDevID 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 != 0)
{
WARN("device already open !\n");
return MMSYSERR_ALLOCATED;
}
if ((flags & MIDI_IO_STATUS) != 0)
{
WARN("No support for MIDI_IO_STATUS in dwFlags yet, ignoring it\n");
flags &= ~MIDI_IO_STATUS;
}
if ((flags & ~CALLBACK_TYPEMASK) != 0)
{
FIXME("Bad flags\n");
return MMSYSERR_INVALFLAG;
}
fd = seq_open();
if (fd < 0)
return MMSYSERR_ERROR;
if (num_midi_in_started++ == 0)
{
pipe(rec_cancel_pipe);
if (pthread_create(&rec_thread_id, NULL, rec_thread_proc, LongToPtr(fd)))
{
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(fd);
return MMSYSERR_ERROR;
}
TRACE("Created thread for midi-in\n");
}
src->wFlags = HIWORD(flags & CALLBACK_TYPEMASK);
src->lpQueueHdr = NULL;
src->midiDesc = *desc;
src->state = 0;
src->incLen = 0;
src->startTime = 0;
src->fd = fd;
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 == 0)
{
WARN("device not opened !\n");
return MMSYSERR_ERROR;
}
if (src->lpQueueHdr != 0)
return MIDIERR_STILLPLAYING;
if (src->fd == -1)
{
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_close(src->fd);
src->fd = -1;
set_in_notify(notify, src, dev_id, MIM_CLOSE, 0, 0);
src->midiDesc.hMidi = 0;
return MMSYSERR_NOERROR;
}
static UINT midi_in_add_buffer(WORD dev_id, MIDIHDR *hdr, UINT hdr_size)
......@@ -1544,6 +1693,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;
......
......@@ -209,27 +209,9 @@ struct is_started_params
HRESULT result;
};
#include <mmddk.h> /* temporary */
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;
unsigned char incoming[3];
unsigned char incPrev;
char incLen;
UINT startTime;
MIDIINCAPSW caps;
int fd;
} WINE_MIDIIN;
struct midi_init_params
{
UINT *err;
unsigned int num_srcs;
struct midi_src *srcs;
};
struct notify_context
......@@ -273,18 +255,6 @@ struct midi_notify_wait_params
struct notify_context *notify;
};
struct midi_seq_open_params
{
int close;
int fd;
};
struct midi_handle_data_params
{
unsigned char *buffer;
unsigned int len;
};
enum oss_funcs
{
oss_test_connect,
......@@ -315,9 +285,6 @@ enum oss_funcs
oss_midi_out_message,
oss_midi_in_message,
oss_midi_notify_wait,
oss_midi_seq_open, /* temporary */
oss_midi_handle_data,
};
NTSTATUS midi_init(void *args) DECLSPEC_HIDDEN;
......@@ -325,8 +292,6 @@ NTSTATUS midi_release(void *args) DECLSPEC_HIDDEN;
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_open(void *args) DECLSPEC_HIDDEN;
NTSTATUS midi_handle_data(void *args) DECLSPEC_HIDDEN;
extern unixlib_handle_t oss_handle;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment