audio.c

来自「Wine-20031016」· C语言 代码 · 共 1,933 行 · 第 1/5 页

C
1,933
字号
#define INIT_GUID(guid, l, w1, w2, b1, b2, b3, b4, b5, b6, b7, b8)	\	guid.Data1 = l; guid.Data2 = w1; guid.Data3 = w2;		\	guid.Data4[0] = b1; guid.Data4[1] = b2; guid.Data4[2] = b3;	\	guid.Data4[3] = b4; guid.Data4[4] = b5; guid.Data4[5] = b6;	\	guid.Data4[6] = b7; guid.Data4[7] = b8;/****************************************************************** *		OSS_WaveInit * * Initialize internal structures from OSS information */LONG OSS_WaveInit(void){    int 	i;    TRACE("()\n");    for (i = 0; i < MAX_WAVEDRV; ++i)    {	if (i == 0) {	    sprintf((char *)OSS_Devices[i].dev_name, "/dev/dsp");	    sprintf((char *)OSS_Devices[i].mixer_name, "/dev/mixer");	} else {	    sprintf((char *)OSS_Devices[i].dev_name, "/dev/dsp%d", i);	    sprintf((char *)OSS_Devices[i].mixer_name, "/dev/mixer%d", i);	}	INIT_GUID(OSS_Devices[i].ds_guid,  0xbd6dd71a, 0x3deb, 0x11d1, 0xb1, 0x71, 0x00, 0xc0, 0x4f, 0xc2, 0x00, 0x00 + i);	INIT_GUID(OSS_Devices[i].dsc_guid, 0xbd6dd71b, 0x3deb, 0x11d1, 0xb1, 0x71, 0x00, 0xc0, 0x4f, 0xc2, 0x00, 0x00 + i);    }    /* start with output devices */    for (i = 0; i < MAX_WAVEDRV; ++i)    {        if (OSS_WaveOutInit(&OSS_Devices[i]))        {            WOutDev[numOutDev].state = WINE_WS_CLOSED;            WOutDev[numOutDev].ossdev = &OSS_Devices[i];            numOutDev++;        }    }    /* then do input devices */    for (i = 0; i < MAX_WAVEDRV; ++i)    {        if (OSS_WaveInInit(&OSS_Devices[i]))        {            WInDev[numInDev].state = WINE_WS_CLOSED;            WInDev[numInDev].ossdev = &OSS_Devices[i];            numInDev++;        }    }    /* finish with the full duplex bits */    for (i = 0; i < MAX_WAVEDRV; i++)        OSS_WaveFullDuplexInit(&OSS_Devices[i]);    return 0;}/****************************************************************** *		OSS_InitRingMessage * * Initialize the ring of messages for passing between driver's caller and playback/record * thread */static int OSS_InitRingMessage(OSS_MSG_RING* omr){    omr->msg_toget = 0;    omr->msg_tosave = 0;#ifdef USE_PIPE_SYNC    if (pipe(omr->msg_pipe) < 0) {	omr->msg_pipe[0] = -1;	omr->msg_pipe[1] = -1;	ERR("could not create pipe, error=%s\n", strerror(errno));    }#else    omr->msg_event = CreateEventA(NULL, FALSE, FALSE, NULL);#endif    omr->ring_buffer_size = OSS_RING_BUFFER_INCREMENT;    omr->messages = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,omr->ring_buffer_size * sizeof(OSS_MSG));    InitializeCriticalSection(&omr->msg_crst);    return 0;}/****************************************************************** *		OSS_DestroyRingMessage * */static int OSS_DestroyRingMessage(OSS_MSG_RING* omr){#ifdef USE_PIPE_SYNC    close(omr->msg_pipe[0]);    close(omr->msg_pipe[1]);#else    CloseHandle(omr->msg_event);#endif    HeapFree(GetProcessHeap(),0,omr->messages);    DeleteCriticalSection(&omr->msg_crst);    return 0;}/****************************************************************** *		OSS_AddRingMessage * * Inserts a new message into the ring (should be called from DriverProc derivated routines) */static int OSS_AddRingMessage(OSS_MSG_RING* omr, enum win_wm_message msg, DWORD param, BOOL wait){    HANDLE	hEvent = INVALID_HANDLE_VALUE;    EnterCriticalSection(&omr->msg_crst);    if ((omr->msg_toget == ((omr->msg_tosave + 1) % omr->ring_buffer_size)))    {	omr->ring_buffer_size += OSS_RING_BUFFER_INCREMENT;	TRACE("omr->ring_buffer_size=%d\n",omr->ring_buffer_size);	omr->messages = HeapReAlloc(GetProcessHeap(),0,omr->messages, omr->ring_buffer_size * sizeof(OSS_MSG));    }    if (wait)    {        hEvent = CreateEventA(NULL, FALSE, FALSE, NULL);        if (hEvent == INVALID_HANDLE_VALUE)        {            ERR("can't create event !?\n");            LeaveCriticalSection(&omr->msg_crst);            return 0;        }        if (omr->msg_toget != omr->msg_tosave && omr->messages[omr->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 */        omr->msg_toget = (omr->msg_toget + omr->ring_buffer_size - 1) % omr->ring_buffer_size;        omr->messages[omr->msg_toget].msg = msg;        omr->messages[omr->msg_toget].param = param;        omr->messages[omr->msg_toget].hEvent = hEvent;    }    else    {        omr->messages[omr->msg_tosave].msg = msg;        omr->messages[omr->msg_tosave].param = param;        omr->messages[omr->msg_tosave].hEvent = INVALID_HANDLE_VALUE;        omr->msg_tosave = (omr->msg_tosave + 1) % omr->ring_buffer_size;    }    LeaveCriticalSection(&omr->msg_crst);    /* signal a new message */    SIGNAL_OMR(omr);    if (wait)    {        /* wait for playback/record thread to have processed the message */        WaitForSingleObject(hEvent, INFINITE);        CloseHandle(hEvent);    }    return 1;}/****************************************************************** *		OSS_RetrieveRingMessage * * Get a message from the ring. Should be called by the playback/record thread. */static int OSS_RetrieveRingMessage(OSS_MSG_RING* omr,                                   enum win_wm_message *msg, DWORD *param, HANDLE *hEvent){    EnterCriticalSection(&omr->msg_crst);    if (omr->msg_toget == omr->msg_tosave) /* buffer empty ? */    {        LeaveCriticalSection(&omr->msg_crst);	return 0;    }    *msg = omr->messages[omr->msg_toget].msg;    omr->messages[omr->msg_toget].msg = 0;    *param = omr->messages[omr->msg_toget].param;    *hEvent = omr->messages[omr->msg_toget].hEvent;    omr->msg_toget = (omr->msg_toget + 1) % omr->ring_buffer_size;    CLEAR_OMR(omr);    LeaveCriticalSection(&omr->msg_crst);    return 1;}/****************************************************************** *              OSS_PeekRingMessage * * Peek at a message from the ring but do not remove it. * Should be called by the playback/record thread. */static int OSS_PeekRingMessage(OSS_MSG_RING* omr,                               enum win_wm_message *msg,                               DWORD *param, HANDLE *hEvent){    EnterCriticalSection(&omr->msg_crst);    if (omr->msg_toget == omr->msg_tosave) /* buffer empty ? */    {	LeaveCriticalSection(&omr->msg_crst);	return 0;    }    *msg = omr->messages[omr->msg_toget].msg;    *param = omr->messages[omr->msg_toget].param;    *hEvent = omr->messages[omr->msg_toget].hEvent;    LeaveCriticalSection(&omr->msg_crst);    return 1;}/*======================================================================* *                  Low level WAVE OUT implementation			* *======================================================================*//************************************************************************** * 			wodNotifyClient			[internal] */static DWORD wodNotifyClient(WINE_WAVEOUT* wwo, WORD wMsg, DWORD dwParam1, DWORD dwParam2){    TRACE("wMsg = 0x%04x dwParm1 = %04lX dwParam2 = %04lX\n", wMsg, dwParam1, dwParam2);    switch (wMsg) {    case WOM_OPEN:    case WOM_CLOSE:    case WOM_DONE:	if (wwo->wFlags != DCB_NULL &&	    !DriverCallback(wwo->waveDesc.dwCallback, wwo->wFlags,			    (HDRVR)wwo->waveDesc.hWave, wMsg,			    wwo->waveDesc.dwInstance, dwParam1, dwParam2)) {	    WARN("can't notify client !\n");	    return MMSYSERR_ERROR;	}	break;    default:	FIXME("Unknown callback message %u\n", wMsg);        return MMSYSERR_INVALPARAM;    }    return MMSYSERR_NOERROR;}/************************************************************************** * 				wodUpdatePlayedTotal	[internal] * */static BOOL wodUpdatePlayedTotal(WINE_WAVEOUT* wwo, audio_buf_info* info){    audio_buf_info dspspace;    if (!info) info = &dspspace;    if (ioctl(wwo->ossdev->fd, SNDCTL_DSP_GETOSPACE, info) < 0) {        ERR("ioctl(%s, SNDCTL_DSP_GETOSPACE) failed (%s)\n", wwo->ossdev->dev_name, strerror(errno));        return FALSE;    }    wwo->dwPlayedTotal = wwo->dwWrittenTotal - (wwo->dwBufferSize - info->bytes);    return TRUE;}/************************************************************************** * 				wodPlayer_BeginWaveHdr          [internal] * * Makes the specified lpWaveHdr the currently playing wave header. * If the specified wave header is a begin loop and we're not already in * a loop, setup the loop. */static void wodPlayer_BeginWaveHdr(WINE_WAVEOUT* wwo, LPWAVEHDR lpWaveHdr){    wwo->lpPlayPtr = lpWaveHdr;    if (!lpWaveHdr) return;    if (lpWaveHdr->dwFlags & WHDR_BEGINLOOP) {	if (wwo->lpLoopPtr) {	    WARN("Already in a loop. Discarding loop on this header (%p)\n", lpWaveHdr);	} else {	    TRACE("Starting loop (%ldx) with %p\n", lpWaveHdr->dwLoops, lpWaveHdr);	    wwo->lpLoopPtr = lpWaveHdr;	    /* Windows does not touch WAVEHDR.dwLoops,	     * so we need to make an internal copy */	    wwo->dwLoops = lpWaveHdr->dwLoops;	}    }    wwo->dwPartialOffset = 0;}/************************************************************************** * 				wodPlayer_PlayPtrNext	        [internal] * * Advance the play pointer to the next waveheader, looping if required. */static LPWAVEHDR wodPlayer_PlayPtrNext(WINE_WAVEOUT* wwo){    LPWAVEHDR lpWaveHdr = wwo->lpPlayPtr;    wwo->dwPartialOffset = 0;    if ((lpWaveHdr->dwFlags & WHDR_ENDLOOP) && wwo->lpLoopPtr) {	/* We're at the end of a loop, loop if required */	if (--wwo->dwLoops > 0) {	    wwo->lpPlayPtr = wwo->lpLoopPtr;	} else {	    /* Handle overlapping loops correctly */	    if (wwo->lpLoopPtr != lpWaveHdr && (lpWaveHdr->dwFlags & WHDR_BEGINLOOP)) {		FIXME("Correctly handled case ? (ending loop buffer also starts a new loop)\n");		/* shall we consider the END flag for the closing loop or for		 * the opening one or for both ???		 * code assumes for closing loop only		 */	    } else {                lpWaveHdr = lpWaveHdr->lpNext;            }            wwo->lpLoopPtr = NULL;            wodPlayer_BeginWaveHdr(wwo, lpWaveHdr);	}    } else {	/* We're not in a loop.  Advance to the next wave header */	wodPlayer_BeginWaveHdr(wwo, lpWaveHdr = lpWaveHdr->lpNext);    }    return lpWaveHdr;}/************************************************************************** * 			     wodPlayer_DSPWait			[internal] * Returns the number of milliseconds to wait for the DSP buffer to write * one fragment. */static DWORD wodPlayer_DSPWait(const WINE_WAVEOUT *wwo){    /* time for one fragment to be played */    return wwo->dwFragmentSize * 1000 / wwo->format.wf.nAvgBytesPerSec;}/************************************************************************** * 			     wodPlayer_NotifyWait               [internal] * Returns the number of milliseconds to wait before attempting to notify * completion of the specified wavehdr. * This is based on the number of bytes remaining to be written in the * wave. */static DWORD wodPlayer_NotifyWait(const WINE_WAVEOUT* wwo, LPWAVEHDR lpWaveHdr){    DWORD dwMillis;    if (lpWaveHdr->reserved < wwo->dwPlayedTotal) {	dwMillis = 1;    } else {	dwMillis = (lpWaveHdr->reserved - wwo->dwPlayedTotal) * 1000 / wwo->format.wf.nAvgBytesPerSec;	if (!dwMillis) dwMillis = 1;    }    return dwMillis;}/************************************************************************** * 			     wodPlayer_WriteMaxFrags            [internal] * Writes the maximum number of bytes possible to the DSP and returns * TRUE iff the current playPtr has been fully played */static BOOL wodPlayer_WriteMaxFrags(WINE_WAVEOUT* wwo, DWORD* bytes){    DWORD       dwLength = wwo->lpPlayPtr->dwBufferLength - wwo->dwPartialOffset;    DWORD       toWrite = min(dwLength, *bytes);    int         written;    BOOL        ret = FALSE;    TRACE("Writing wavehdr %p.%lu[%lu]/%lu\n",          wwo->lpPlayPtr, wwo->dwPartialOffset, wwo->lpPlayPtr->dwBufferLength, toWrite);    if (toWrite > 0)    {        written = write(wwo->ossdev->fd, wwo->lpPlayPtr->lpData + wwo->dwPartialOffset, toWrite);        if (written <= 0) return FALSE;    }    else        written = 0;    if (written >= dwLength) {        /* If we wrote all current wavehdr, skip to the next one */        wodPlayer_PlayPtrNext(wwo);        ret = TRUE;    } else {        /* Remove the amount written */        wwo->dwPartialOffset += written;    }    *bytes -= written;    wwo->dwWrittenTotal += written;    return ret;}

⌨️ 快捷键说明

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