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

📄 audio.c

📁 Wine-20031016
💻 C
📖 第 1 页 / 共 3 页
字号:
/* -*- tab-width: 8; c-basic-offset: 4 -*- *//* * Wine Driver for NAS Network Audio System *   http://radscan.com/nas.html * * Copyright 1994 Martin Ayotte *           1999 Eric Pouech (async playing in waveOut/waveIn) *	     2000 Eric Pouech (loops in waveOut) *	     2002 Chris Morgan (aRts version of this file) *           2002 Nicolas Escuder (NAS version of this file) * * Copyright 2002 Nicolas Escuder <n.escuder@alineanet.com> * * 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 *//* NOTE: *    with nas we cannot stop the audio that is already in *    the servers buffer. * * FIXME: *	pause in waveOut does not work correctly in loop mode * */#include "config.h"#include <stdlib.h>#include <stdarg.h>#include <stdio.h>#include <string.h>#ifdef HAVE_UNISTD_H# include <unistd.h>#endif#ifdef HAVE_SYS_TIME_H# include <sys/time.h>#endif#include <fcntl.h>#if 0#define EMULATE_SB16#endif#define FRAG_SIZE  1024#define FRAG_COUNT 10/* avoid type conflicts */#define INT8 X_INT8#define INT16 X_INT16#define INT32 X_INT32#define BOOL X_BOOL#define BYTE X_BYTE#ifdef HAVE_AUDIO_AUDIOLIB_H#include <audio/audiolib.h>#endif#ifdef HAVE_AUDIO_SOUNDLIB_H#include <audio/soundlib.h>#endif#undef INT8#undef INT16#undef INT32#undef BOOL#undef BYTE#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 "nas.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_NASstatic AuServer         *AuServ;#define MAX_WAVEOUTDRV 	(1)/* 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};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 */} RING_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 NAS_RING_BUFFER_INCREMENT      64typedef struct {    RING_MSG			* messages;    int                         ring_buffer_size;    int				msg_tosave;    int				msg_toget;    HANDLE			msg_event;    CRITICAL_SECTION		msg_crst;} MSG_RING;typedef struct {    volatile int		state;			/* one of the WINE_WS_ manifest constants */    WAVEOPENDESC		waveDesc;    WORD			wFlags;    PCMWAVEFORMAT		format;    WAVEOUTCAPSA		caps;    int				Id;    int                         open;    AuServer                    *AuServ;    AuDeviceID                  AuDev;    AuFlowID                    AuFlow;    BOOL                        FlowStarted;    DWORD                       writeBytes;    DWORD                       freeBytes;    DWORD                       sendBytes;    DWORD                       BufferSize;           /* size of whole buffer in bytes */    char*                       SoundBuffer;    long                        BufferUsed;    DWORD			volume_left;		/* volume control information */    DWORD			volume_right;    LPWAVEHDR			lpQueuePtr;		/* start of queued WAVEHDRs (waiting to be notified) */    LPWAVEHDR			lpPlayPtr;		/* start of not yet fully played buffers */    LPWAVEHDR			lpLoopPtr;              /* pointer of first buffer in loop, if any */    DWORD			dwLoops;		/* private copy of loop counter */    DWORD			PlayedTotal;		/* number of bytes actually played since opening */    DWORD                       WrittenTotal;         /* number of bytes written to the audio device since opening */    /* synchronization stuff */    HANDLE			hStartUpEvent;    HANDLE			hThread;    DWORD			dwThreadID;    MSG_RING			msgRing;} WINE_WAVEOUT;static WINE_WAVEOUT	WOutDev   [MAX_WAVEOUTDRV];static DWORD wodDsCreate(UINT wDevID, PIDSDRIVER* drv);static DWORD wodDsDesc(UINT wDevID, PDSDRIVERDESC desc);static DWORD wodDsGuid(UINT wDevID, LPGUID pGuid);/* NASFUNC */static AuBool event_handler(AuServer* aud, AuEvent* ev, AuEventHandlerRec* hnd);static int nas_init(void);static int nas_end(void);static int nas_finddev(WINE_WAVEOUT* wwo);static int nas_open(WINE_WAVEOUT* wwo);static int nas_free(WINE_WAVEOUT* wwo);static int nas_close(WINE_WAVEOUT* wwo);static void buffer_resize(WINE_WAVEOUT* wwo, int len);static int nas_add_buffer(WINE_WAVEOUT* wwo);static int nas_send_buffer(WINE_WAVEOUT* wwo);/* 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",};static char *nas_elementnotify_kinds[] = {        "LowWater",        "HighWater",        "State",        "Unknown"};static char *nas_states[] = {        "Stop",        "Start",        "Pause",        "Any"};static char *nas_reasons[] = {        "User",        "Underrun",        "Overrun",        "EOF",        "Watermark",        "Hardware",        "Any"};static char* nas_reason(unsigned int reason){        if (reason > 6) reason = 6;        return nas_reasons[reason];}static char* nas_elementnotify_kind(unsigned int kind){        if (kind > 2) kind = 3;        return nas_elementnotify_kinds[kind];}#if 0static const char* nas_event_type(unsigned int type){        static const char * const nas_event_types[] =        {            "Undefined",            "Undefined",            "ElementNotify",            "GrabNotify",            "MonitorNotify",            "BucketNotify",            "DeviceNotify"        };        if (type > 6) type = 0;        return nas_event_types[type];}#endifstatic char* nas_state(unsigned int state){        if (state > 3) state = 3;        return nas_states[state];}/*======================================================================* *                  Low level WAVE implementation			* *======================================================================*//* Volume functions derived from Alsaplayer source *//* length is the number of 16 bit samples */void volume_effect16(void *bufin, void* bufout, int length, int left,		int right, int 	nChannels){  short *d_out = (short *)bufout;  short *d_in = (short *)bufin;  int i, v;/*  TRACE("length == %d, nChannels == %d\n", length, nChannels);*/  if (right == -1) right = left;  for(i = 0; i < length; i+=(nChannels))  {    v = (int) ((*(d_in++) * left) / 100);    *(d_out++) = (v>32767) ? 32767 : ((v<-32768) ? -32768 : v);    if(nChannels == 2)    {      v = (int) ((*(d_in++) * right) / 100);      *(d_out++) = (v>32767) ? 32767 : ((v<-32768) ? -32768 : v);    }  }}/* length is the number of 8 bit samples */void volume_effect8(void *bufin, void* bufout, int length, int left,		int right, int 	nChannels){  char *d_out = (char *)bufout;  char *d_in = (char *)bufin;  int i, v;/*  TRACE("length == %d, nChannels == %d\n", length, nChannels);*/  if (right == -1) right = left;  for(i = 0; i < length; i+=(nChannels))  {    v = (char) ((*(d_in++) * left) / 100);    *(d_out++) = (v>255) ? 255 : ((v<0) ? 0 : v);    if(nChannels == 2)    {      v = (char) ((*(d_in++) * right) / 100);      *(d_out++) = (v>255) ? 255 : ((v<0) ? 0 : v);    }  }}/****************************************************************** *		NAS_CloseDevice * */void		NAS_CloseDevice(WINE_WAVEOUT* wwo){  TRACE("NAS_CloseDevice\n");  nas_close(wwo);}/****************************************************************** *		NAS_WaveClose */LONG		NAS_WaveClose(void){    nas_end();    /* free up nas server */    return 1;}/****************************************************************** *		NAS_WaveInit * * Initialize internal structures from NAS server info */LONG NAS_WaveInit(void){    int 	i;    nas_init();    /* initialize all device handles to -1 */    for (i = 0; i < MAX_WAVEOUTDRV; ++i)    {	memset(&WOutDev[i].caps, 0, sizeof(WOutDev[i].caps)); /* zero out caps values */        WOutDev[i].AuServ = AuServ;        WOutDev[i].AuDev = AuNone;	WOutDev[i].Id = i;    /* FIXME: some programs compare this string against the content of the registry     * for MM drivers. The names have to match in order for the program to work     * (e.g. MS win9x mplayer.exe)     */#ifdef EMULATE_SB16    	WOutDev[i].caps.wMid = 0x0002;    	WOutDev[i].caps.wPid = 0x0104;    	strcpy(WOutDev[i].caps.szPname, "SB16 Wave Out");#else    	WOutDev[i].caps.wMid = 0x00FF; 	/* Manufac ID */    	WOutDev[i].caps.wPid = 0x0001; 	/* Product ID */    /*    strcpy(WOutDev[i].caps.szPname, "OpenSoundSystem WAVOUT Driver");*/    	strcpy(WOutDev[i].caps.szPname, "CS4236/37/38");#endif        WOutDev[i].AuFlow = 0;    	WOutDev[i].caps.vDriverVersion = 0x0100;    	WOutDev[i].caps.dwFormats = 0x00000000;    	WOutDev[i].caps.dwSupport = WAVECAPS_VOLUME;    	WOutDev[i].caps.wChannels = 2;    	WOutDev[i].caps.dwSupport |= WAVECAPS_LRVOLUME;    	WOutDev[i].caps.dwFormats |= WAVE_FORMAT_4M08;    	WOutDev[i].caps.dwFormats |= WAVE_FORMAT_4S08;    	WOutDev[i].caps.dwFormats |= WAVE_FORMAT_4S16;    	WOutDev[i].caps.dwFormats |= WAVE_FORMAT_4M16;    	WOutDev[i].caps.dwFormats |= WAVE_FORMAT_2M08;    	WOutDev[i].caps.dwFormats |= WAVE_FORMAT_2S08;    	WOutDev[i].caps.dwFormats |= WAVE_FORMAT_2M16;    	WOutDev[i].caps.dwFormats |= WAVE_FORMAT_2S16;    	WOutDev[i].caps.dwFormats |= WAVE_FORMAT_1M08;    	WOutDev[i].caps.dwFormats |= WAVE_FORMAT_1S08;	WOutDev[i].caps.dwFormats |= WAVE_FORMAT_1M16;	WOutDev[i].caps.dwFormats |= WAVE_FORMAT_1S16;    }    return 0;}/****************************************************************** *		NAS_InitRingMessage * * Initialize the ring of messages for passing between driver's caller and playback/record * thread */static int NAS_InitRingMessage(MSG_RING* mr){    mr->msg_toget = 0;    mr->msg_tosave = 0;    mr->msg_event = CreateEventA(NULL, FALSE, FALSE, NULL);    mr->ring_buffer_size = NAS_RING_BUFFER_INCREMENT;    mr->messages = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,mr->ring_buffer_size * sizeof(RING_MSG));    InitializeCriticalSection(&mr->msg_crst);    return 0;}/****************************************************************** *		NAS_DestroyRingMessage * */static int NAS_DestroyRingMessage(MSG_RING* mr){    CloseHandle(mr->msg_event);    HeapFree(GetProcessHeap(),0,mr->messages);    DeleteCriticalSection(&mr->msg_crst);    return 0;}/****************************************************************** *		NAS_AddRingMessage * * Inserts a new message into the ring (should be called from DriverProc derivated routines) */static int NAS_AddRingMessage(MSG_RING* mr, enum win_wm_message msg, DWORD param, BOOL wait){    HANDLE      hEvent = INVALID_HANDLE_VALUE;    EnterCriticalSection(&mr->msg_crst);    if ((mr->msg_toget == ((mr->msg_tosave + 1) % mr->ring_buffer_size)))    {	mr->ring_buffer_size += NAS_RING_BUFFER_INCREMENT;	TRACE("omr->ring_buffer_size=%d\n",mr->ring_buffer_size);	mr->messages = HeapReAlloc(GetProcessHeap(),0,mr->messages, mr->ring_buffer_size * sizeof(RING_MSG));    }    if (wait)    {        hEvent = CreateEventA(NULL, FALSE, FALSE, NULL);        if (hEvent == INVALID_HANDLE_VALUE)        {            ERR("can't create event !?\n");            LeaveCriticalSection(&mr->msg_crst);            return 0;        }        if (mr->msg_toget != mr->msg_tosave && mr->messages[mr->msg_toget].msg != WINE_WM_HEADER)            FIXME("two fast messages in the queue!!!!\n");        /* fast messages have to be added at the start of the queue */        mr->msg_toget = (mr->msg_toget + mr->ring_buffer_size - 1) % mr->ring_buffer_size;        mr->messages[mr->msg_toget].msg = msg;        mr->messages[mr->msg_toget].param = param;        mr->messages[mr->msg_toget].hEvent = hEvent;    }    else    {        mr->messages[mr->msg_tosave].msg = msg;        mr->messages[mr->msg_tosave].param = param;        mr->messages[mr->msg_tosave].hEvent = INVALID_HANDLE_VALUE;        mr->msg_tosave = (mr->msg_tosave + 1) % mr->ring_buffer_size;    }    LeaveCriticalSection(&mr->msg_crst);    SetEvent(mr->msg_event);    /* signal a new message */    if (wait)    {        /* wait for playback/record thread to have processed the message */        WaitForSingleObject(hEvent, INFINITE);        CloseHandle(hEvent);    }    return 1;}/****************************************************************** *		NAS_RetrieveRingMessage * * Get a message from the ring. Should be called by the playback/record thread. */static int NAS_RetrieveRingMessage(MSG_RING* mr,                                   enum win_wm_message *msg, DWORD *param, HANDLE *hEvent){    EnterCriticalSection(&mr->msg_crst);

⌨️ 快捷键说明

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