/* * Sample Wine Driver for Open Sound System (featured in Linux and FreeBSD) * * Copyright 1994 Martin Ayotte * 1999 Eric Pouech (async playing in waveOut/waveIn) * 2000 Eric Pouech (loops in waveOut) * 2002 Eric Pouech (full duplex) * * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #ifdef HAVE_OSS /* unless someone makes a wineserver kernel module, Unix pipes are faster than win32 events */ #define USE_PIPE_SYNC #define MAX_WAVEDRV (6) #define MAX_CHANNELS 6 /* states of the playing device */ #define WINE_WS_PLAYING 0 #define WINE_WS_PAUSED 1 #define WINE_WS_STOPPED 2 #define WINE_WS_CLOSED 3 /* events to be send to device */ enum win_wm_message { WINE_WM_PAUSING = WM_USER + 1, WINE_WM_RESTARTING, WINE_WM_RESETTING, WINE_WM_HEADER, WINE_WM_UPDATE, WINE_WM_BREAKLOOP, WINE_WM_CLOSING, WINE_WM_STARTING, WINE_WM_STOPPING }; #ifdef USE_PIPE_SYNC #define SIGNAL_OMR(omr) do { int x = 0; write((omr)->msg_pipe[1], &x, sizeof(x)); } while (0) #define CLEAR_OMR(omr) do { int x = 0; read((omr)->msg_pipe[0], &x, sizeof(x)); } while (0) #define RESET_OMR(omr) do { } while (0) #define WAIT_OMR(omr, sleep) \ do { struct pollfd pfd; pfd.fd = (omr)->msg_pipe[0]; \ pfd.events = POLLIN; poll(&pfd, 1, sleep); } while (0) #else #define SIGNAL_OMR(omr) do { SetEvent((omr)->msg_event); } while (0) #define CLEAR_OMR(omr) do { } while (0) #define RESET_OMR(omr) do { ResetEvent((omr)->msg_event); } while (0) #define WAIT_OMR(omr, sleep) \ do { WaitForSingleObject((omr)->msg_event, sleep); } while (0) #endif typedef struct { enum win_wm_message msg; /* message identifier */ DWORD param; /* parameter for this message */ HANDLE hEvent; /* if message is synchronous, handle of event for synchro */ } OSS_MSG; /* implement an in-process message ring for better performance * (compared to passing thru the server) * this ring will be used by the input (resp output) record (resp playback) routine */ #define OSS_RING_BUFFER_INCREMENT 64 typedef struct { int ring_buffer_size; OSS_MSG * messages; int msg_tosave; int msg_toget; #ifdef USE_PIPE_SYNC int msg_pipe[2]; #else HANDLE msg_event; #endif CRITICAL_SECTION msg_crst; } OSS_MSG_RING; typedef struct tagOSS_DEVICE { char* dev_name; char* mixer_name; char* interface_name; unsigned open_count; WAVEOUTCAPSW out_caps; WAVEOUTCAPSW duplex_out_caps; WAVEINCAPSW in_caps; DWORD in_caps_support; unsigned open_access; int fd; DWORD owner_tid; int sample_rate; int channels; int format; unsigned audio_fragment; BOOL full_duplex; BOOL bTriggerSupport; BOOL bOutputEnabled; BOOL bInputEnabled; DSDRIVERDESC ds_desc; DSDRIVERCAPS ds_caps; DSCDRIVERCAPS dsc_caps; } OSS_DEVICE; typedef struct { OSS_DEVICE* ossdev; volatile int state; /* one of the WINE_WS_ manifest constants */ WAVEOPENDESC waveDesc; WORD wFlags; WAVEFORMATPCMEX waveFormat; DWORD volume; /* OSS information */ DWORD dwFragmentSize; /* size of OSS buffer fragment */ DWORD dwBufferSize; /* size of whole OSS buffer in bytes */ LPWAVEHDR lpQueuePtr; /* start of queued WAVEHDRs (waiting to be notified) */ LPWAVEHDR lpPlayPtr; /* start of not yet fully played buffers */ DWORD dwPartialOffset; /* Offset of not yet written bytes in lpPlayPtr */ LPWAVEHDR lpLoopPtr; /* pointer of first buffer in loop, if any */ DWORD dwLoops; /* private copy of loop counter */ DWORD dwPlayedTotal; /* number of bytes actually played since opening */ DWORD dwWrittenTotal; /* number of bytes written to OSS buffer since opening */ BOOL bNeedPost; /* whether audio still needs to be physically started */ /* synchronization stuff */ HANDLE hStartUpEvent; HANDLE hThread; DWORD dwThreadID; OSS_MSG_RING msgRing; /* make accomodation for the inacuraccy of OSS when reporting buffer size remaining by using the clock instead of GETOSPACE */ DWORD dwProjectedFinishTime; } WINE_WAVEOUT; typedef struct { OSS_DEVICE* ossdev; volatile int state; DWORD dwFragmentSize; /* OpenSound '/dev/dsp' give us that size */ WAVEOPENDESC waveDesc; WORD wFlags; WAVEFORMATPCMEX waveFormat; LPWAVEHDR lpQueuePtr; DWORD dwTotalRecorded; DWORD dwTotalRead; /* synchronization stuff */ HANDLE hThread; DWORD dwThreadID; HANDLE hStartUpEvent; OSS_MSG_RING msgRing; } WINE_WAVEIN; extern OSS_DEVICE OSS_Devices[MAX_WAVEDRV]; extern WINE_WAVEOUT WOutDev[MAX_WAVEDRV]; extern WINE_WAVEIN WInDev[MAX_WAVEDRV]; extern unsigned numOutDev; extern unsigned numInDev; extern int getEnables(OSS_DEVICE *ossdev); extern void copy_format(LPWAVEFORMATEX wf1, LPWAVEFORMATPCMEX wf2); extern DWORD OSS_OpenDevice(OSS_DEVICE* ossdev, unsigned req_access, int* frag, int strict_format, int sample_rate, int stereo, int fmt); extern void OSS_CloseDevice(OSS_DEVICE* ossdev); extern DWORD wodOpen(WORD wDevID, LPWAVEOPENDESC lpDesc, DWORD dwFlags); extern DWORD wodSetVolume(WORD wDevID, DWORD dwParam); extern DWORD widOpen(WORD wDevID, LPWAVEOPENDESC lpDesc, DWORD dwFlags); /* dscapture.c */ extern DWORD widDsCreate(UINT wDevID, PIDSCDRIVER* drv); extern DWORD widDsDesc(UINT wDevID, PDSDRIVERDESC desc); /* dsrender.c */ extern DWORD wodDsCreate(UINT wDevID, PIDSDRIVER* drv); extern DWORD wodDsDesc(UINT wDevID, PDSDRIVERDESC desc); #endif /* HAVE_OSS */