⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 audio.c

📁 Wine-20031016
💻 C
📖 第 1 页 / 共 5 页
字号:
/* -*- tab-width: 8; c-basic-offset: 4 -*- *//* * 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 *//* * FIXME: *	pause in waveOut does not work correctly in loop mode *	Direct Sound Capture driver does not work (not complete yet) *//*#define EMULATE_SB16*//* unless someone makes a wineserver kernel module, Unix pipes are faster than win32 events */#define USE_PIPE_SYNC/* an exact wodGetPosition is usually not worth the extra context switches, * as we're going to have near fragment accuracy anyway *//* #define EXACT_WODPOSITION */#include "config.h"#include "wine/port.h"#include <stdlib.h>#include <stdarg.h>#include <stdio.h>#include <string.h>#ifdef HAVE_UNISTD_H# include <unistd.h>#endif#include <errno.h>#include <fcntl.h>#ifdef HAVE_SYS_IOCTL_H# include <sys/ioctl.h>#endif#ifdef HAVE_SYS_MMAN_H# include <sys/mman.h>#endif#ifdef HAVE_SYS_POLL_H# include <sys/poll.h>#endif#include "windef.h"#include "winbase.h"#include "wingdi.h"#include "winerror.h"#include "wine/winuser16.h"#include "mmddk.h"#include "dsound.h"#include "dsdriver.h"#include "oss.h"#include "wine/debug.h"WINE_DEFAULT_DEBUG_CHANNEL(wave);/* Allow 1% deviation for sample rates (some ES137x cards) */#define NEAR_MATCH(rate1,rate2) (((100*((int)(rate1)-(int)(rate2)))/(rate1))==0)#ifdef HAVE_OSS#define MAX_WAVEDRV 	(6)/* state diagram for waveOut writing: * * +---------+-------------+---------------+---------------------------------+ * |  state  |  function   |     event     |            new state	     | * +---------+-------------+---------------+---------------------------------+ * |	     | open()	   |		   | STOPPED		       	     | * | PAUSED  | write()	   | 		   | PAUSED		       	     | * | STOPPED | write()	   | <thrd create> | PLAYING		  	     | * | PLAYING | write()	   | HEADER        | PLAYING		  	     | * | (other) | write()	   | <error>       |		       		     | * | (any)   | pause()	   | PAUSING	   | PAUSED		       	     | * | PAUSED  | restart()   | RESTARTING    | PLAYING (if no thrd => STOPPED) | * | (any)   | reset()	   | RESETTING     | STOPPED		      	     | * | (any)   | close()	   | CLOSING	   | CLOSED		      	     | * +---------+-------------+---------------+---------------------------------+ *//* 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)#endiftypedef 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	64typedef 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[32];    char                        mixer_name[32];    unsigned                    open_count;    WAVEOUTCAPSA                out_caps;    WAVEINCAPSA                 in_caps;    DWORD                       in_caps_support;    unsigned                    open_access;    int                         fd;    DWORD                       owner_tid;    int                         sample_rate;    int                         stereo;    int                         format;    unsigned                    audio_fragment;    BOOL                        full_duplex;    BOOL                        bTriggerSupport;    BOOL                        bOutputEnabled;    BOOL                        bInputEnabled;    DSDRIVERDESC                ds_desc;    DSDRIVERCAPS                ds_caps;    DSCDRIVERCAPS               dsc_caps;    GUID                        ds_guid;    GUID                        dsc_guid;} OSS_DEVICE;static OSS_DEVICE   OSS_Devices[MAX_WAVEDRV];typedef struct {    OSS_DEVICE*                 ossdev;    volatile int		state;			/* one of the WINE_WS_ manifest constants */    WAVEOPENDESC		waveDesc;    WORD			wFlags;    PCMWAVEFORMAT		format;    /* 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;    /* DirectSound stuff */    LPBYTE			mapping;    DWORD			maplen;} WINE_WAVEOUT;typedef struct {    OSS_DEVICE*                 ossdev;    volatile int		state;    DWORD			dwFragmentSize;		/* OpenSound '/dev/dsp' give us that size */    WAVEOPENDESC		waveDesc;    WORD			wFlags;    PCMWAVEFORMAT		format;    LPWAVEHDR			lpQueuePtr;    DWORD			dwTotalRecorded;    /* synchronization stuff */    HANDLE			hThread;    DWORD			dwThreadID;    HANDLE			hStartUpEvent;    OSS_MSG_RING		msgRing;    /* DirectSound stuff */    LPBYTE                      mapping;    DWORD                       maplen;} WINE_WAVEIN;static WINE_WAVEOUT	WOutDev   [MAX_WAVEDRV];static WINE_WAVEIN	WInDev    [MAX_WAVEDRV];static unsigned         numOutDev;static unsigned         numInDev;static DWORD wodDsCreate(UINT wDevID, PIDSDRIVER* drv);static DWORD widDsCreate(UINT wDevID, PIDSCDRIVER* drv);static DWORD wodDsDesc(UINT wDevID, PDSDRIVERDESC desc);static DWORD widDsDesc(UINT wDevID, PDSDRIVERDESC desc);static DWORD wodDsGuid(UINT wDevID, LPGUID pGuid);static DWORD widDsGuid(UINT wDevID, LPGUID pGuid);/* These strings used only for tracing */static const char *wodPlayerCmdString[] = {    "WINE_WM_PAUSING",    "WINE_WM_RESTARTING",    "WINE_WM_RESETTING",    "WINE_WM_HEADER",    "WINE_WM_UPDATE",    "WINE_WM_BREAKLOOP",    "WINE_WM_CLOSING",    "WINE_WM_STARTING",    "WINE_WM_STOPPING",};static int getEnables(OSS_DEVICE *ossdev){    return ( (ossdev->bOutputEnabled ? PCM_ENABLE_OUTPUT : 0) |              (ossdev->bInputEnabled  ? PCM_ENABLE_INPUT  : 0) );}/*======================================================================* *                  Low level WAVE implementation			* *======================================================================*//****************************************************************** *		OSS_RawOpenDevice * * Low level device opening (from values stored in ossdev) */static DWORD      OSS_RawOpenDevice(OSS_DEVICE* ossdev, int strict_format){    int fd, val, rc;    TRACE("(%p,%d)\n",ossdev,strict_format);    if ((fd = open(ossdev->dev_name, ossdev->open_access|O_NDELAY, 0)) == -1)    {        WARN("Couldn't open %s (%s)\n", ossdev->dev_name, strerror(errno));        return (errno == EBUSY) ? MMSYSERR_ALLOCATED : MMSYSERR_ERROR;    }    fcntl(fd, F_SETFD, 1); /* set close on exec flag */    /* turn full duplex on if it has been requested */    if (ossdev->open_access == O_RDWR && ossdev->full_duplex) {        rc = ioctl(fd, SNDCTL_DSP_SETDUPLEX, 0);        /* on *BSD, as full duplex is always enabled by default, this ioctl         * will fail with EINVAL         * so, we don't consider EINVAL an error here         */        if (rc != 0 && errno != EINVAL) {	    ERR("ioctl(%s, SNDCTL_DSP_SETDUPLEX) failed (%s)\n", ossdev->dev_name, strerror(errno));            goto error2;	}    }    if (ossdev->audio_fragment) {        rc = ioctl(fd, SNDCTL_DSP_SETFRAGMENT, &ossdev->audio_fragment);        if (rc != 0) {	    ERR("ioctl(%s, SNDCTL_DSP_SETFRAGMENT) failed (%s)\n", ossdev->dev_name, strerror(errno));            goto error2;	}    }    /* First size and stereo then samplerate */    if (ossdev->format>=0)    {        val = ossdev->format;        rc = ioctl(fd, SNDCTL_DSP_SETFMT, &ossdev->format);        if (rc != 0 || val != ossdev->format) {            TRACE("Can't set format to %d (returned %d)\n", val, ossdev->format);            if (strict_format)                goto error;        }    }    if (ossdev->stereo>=0)    {        val = ossdev->stereo;        rc = ioctl(fd, SNDCTL_DSP_STEREO, &ossdev->stereo);        if (rc != 0 || val != ossdev->stereo) {            TRACE("Can't set stereo to %u (returned %d)\n", val, ossdev->stereo);            if (strict_format)                goto error;        }    }    if (ossdev->sample_rate>=0)    {        val = ossdev->sample_rate;        rc = ioctl(fd, SNDCTL_DSP_SPEED, &ossdev->sample_rate);        if (rc != 0 || !NEAR_MATCH(val, ossdev->sample_rate)) {            TRACE("Can't set sample_rate to %u (returned %d)\n", val, ossdev->sample_rate);            if (strict_format)                goto error;        }    }    ossdev->fd = fd;    if (ossdev->bTriggerSupport) {	int trigger;	rc = ioctl(fd, SNDCTL_DSP_GETTRIGGER, &trigger);	if (rc != 0) {	    ERR("ioctl(%s, SNDCTL_DSP_GETTRIGGER) failed (%s)\n", 		ossdev->dev_name, strerror(errno));	    goto error;	}	    	ossdev->bOutputEnabled = ((trigger & PCM_ENABLE_OUTPUT) == PCM_ENABLE_OUTPUT);    	ossdev->bInputEnabled  = ((trigger & PCM_ENABLE_INPUT) == PCM_ENABLE_INPUT);    } else {    	ossdev->bOutputEnabled = TRUE;	/* OSS enables by default */    	ossdev->bInputEnabled  = TRUE;	/* OSS enables by default */    }    return MMSYSERR_NOERROR;error:    close(fd);    return WAVERR_BADFORMAT; error2:    close(fd);    return MMSYSERR_ERROR;}/****************************************************************** *		OSS_OpenDevice * * since OSS has poor capabilities in full duplex, we try here to let a program * open the device for both waveout and wavein streams... * this is hackish, but it's the way OSS interface is done... */static DWORD OSS_OpenDevice(OSS_DEVICE* ossdev, unsigned req_access,                            int* frag, int strict_format,                            int sample_rate, int stereo, int fmt){    DWORD       ret;    TRACE("(%p,%u,%p,%d,%d,%d,%x)\n",ossdev,req_access,frag,strict_format,sample_rate,stereo,fmt);    if (ossdev->full_duplex && (req_access == O_RDONLY || req_access == O_WRONLY))        req_access = O_RDWR;    /* FIXME: this should be protected, and it also contains a race with OSS_CloseDevice */    if (ossdev->open_count == 0)    {	if (access(ossdev->dev_name, 0) != 0) return MMSYSERR_NODRIVER;        ossdev->audio_fragment = (frag) ? *frag : 0;        ossdev->sample_rate = sample_rate;        ossdev->stereo = stereo;        ossdev->format = fmt;        ossdev->open_access = req_access;        ossdev->owner_tid = GetCurrentThreadId();

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -