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 + -
显示快捷键?