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

📄 audio.c

📁 Wine-20031016
💻 C
📖 第 1 页 / 共 5 页
字号:
/****************************************************************** *		ALSA_WaveInit * * Initialize internal structures from ALSA information */LONG ALSA_WaveInit(void){    snd_pcm_t*                  h = NULL;    snd_pcm_info_t *            info;    snd_pcm_hw_params_t *       hw_params;    WINE_WAVEOUT*	        wwo;    wwo = &WOutDev[0];    /* FIXME: use better values */    wwo->device = FAKE_CHARPTR("hw");    wwo->caps.wMid = 0x0002;    wwo->caps.wPid = 0x0104;    strcpy(wwo->caps.szPname, "SB16 Wave Out");    wwo->caps.vDriverVersion = 0x0100;    wwo->caps.dwFormats = 0x00000000;    wwo->caps.dwSupport = WAVECAPS_VOLUME;    strcpy(wwo->ds_desc.szDesc, "WineALSA DirectSound Driver");    strcpy(wwo->ds_desc.szDrvName, "winealsa.drv");    wwo->ds_guid = DSDEVID_DefaultPlayback;    if (!wine_dlopen("libasound.so.2", RTLD_LAZY|RTLD_GLOBAL, NULL, 0))    {        ERR("Error: ALSA lib needs to be loaded with flags RTLD_LAZY and RTLD_GLOBAL.\n");        return -1;    }    snd_pcm_info_alloca(&info);    snd_pcm_hw_params_alloca(&hw_params);#define EXIT_ON_ERROR(f,txt) do { int err; if ( (err = (f) ) < 0) { ERR(txt ": %s\n", snd_strerror(err)); if (h) snd_pcm_close(h); return -1; } } while(0)    ALSA_WodNumDevs = 0;    EXIT_ON_ERROR( snd_pcm_open(&h, wwo->device, SND_PCM_STREAM_PLAYBACK, SND_PCM_NONBLOCK) , "open pcm" );    if (!h) return -1;    ALSA_WodNumDevs++;    EXIT_ON_ERROR( snd_pcm_info(h, info) , "pcm info" );    TRACE("dev=%d id=%s name=%s subdev=%d subdev_name=%s subdev_avail=%d subdev_num=%d stream=%s subclass=%s \n",       snd_pcm_info_get_device(info),       snd_pcm_info_get_id(info),       snd_pcm_info_get_name(info),       snd_pcm_info_get_subdevice(info),       snd_pcm_info_get_subdevice_name(info),       snd_pcm_info_get_subdevices_avail(info),       snd_pcm_info_get_subdevices_count(info),       snd_pcm_stream_name(snd_pcm_info_get_stream(info)),       (snd_pcm_info_get_subclass(info) == SND_PCM_SUBCLASS_GENERIC_MIX ? "GENERIC MIX": "MULTI MIX"));    EXIT_ON_ERROR( snd_pcm_hw_params_any(h, hw_params) , "pcm hw params" );#undef EXIT_ON_ERROR    if (TRACE_ON(wave))	ALSA_TraceParameters(hw_params, NULL, TRUE);    {	snd_pcm_format_mask_t *     fmask;	int ratemin = snd_pcm_hw_params_get_rate_min(hw_params, 0);	int ratemax = snd_pcm_hw_params_get_rate_max(hw_params, 0);	int chmin = snd_pcm_hw_params_get_channels_min(hw_params); \	int chmax = snd_pcm_hw_params_get_channels_max(hw_params); \	snd_pcm_format_mask_alloca(&fmask);	snd_pcm_hw_params_get_format_mask(hw_params, fmask);#define X(r,v) \       if ( (r) >= ratemin && ( (r) <= ratemax || ratemax == -1) ) \       { \          if (snd_pcm_format_mask_test( fmask, SND_PCM_FORMAT_U8)) \          { \              if (chmin <= 1 && 1 <= chmax) \                  wwo->caps.dwFormats |= WAVE_FORMAT_##v##S08; \              if (chmin <= 2 && 2 <= chmax) \                  wwo->caps.dwFormats |= WAVE_FORMAT_##v##S08; \          } \          if (snd_pcm_format_mask_test( fmask, SND_PCM_FORMAT_S16_LE)) \          { \              if (chmin <= 1 && 1 <= chmax) \                  wwo->caps.dwFormats |= WAVE_FORMAT_##v##S16; \              if (chmin <= 2 && 2 <= chmax) \                  wwo->caps.dwFormats |= WAVE_FORMAT_##v##S16; \          } \       }       X(11025,1);       X(22050,2);       X(44100,4);#undef X    }    if ( snd_pcm_hw_params_get_channels_min(hw_params) > 1) FIXME("-\n");    wwo->caps.wChannels = (snd_pcm_hw_params_get_channels_max(hw_params) >= 2) ? 2 : 1;    if (snd_pcm_hw_params_get_channels_min(hw_params) <= 2 && 2 <= snd_pcm_hw_params_get_channels_max(hw_params))        wwo->caps.dwSupport |= WAVECAPS_LRVOLUME;    /* FIXME: always true ? */    wwo->caps.dwSupport |= WAVECAPS_SAMPLEACCURATE;    {	snd_pcm_access_mask_t *     acmask;	snd_pcm_access_mask_alloca(&acmask);	snd_pcm_hw_params_get_access_mask(hw_params, acmask);	/* FIXME: NONITERLEAVED and COMPLEX are not supported right now */	if ( snd_pcm_access_mask_test( acmask, SND_PCM_ACCESS_MMAP_INTERLEAVED ) )            wwo->caps.dwSupport |= WAVECAPS_DIRECTSOUND;    }    TRACE("Configured with dwFmts=%08lx dwSupport=%08lx\n",          wwo->caps.dwFormats, wwo->caps.dwSupport);    snd_pcm_close(h);    ALSA_InitializeVolumeCtl(wwo);    return 0;}/****************************************************************** *		ALSA_InitRingMessage * * Initialize the ring of messages for passing between driver's caller and playback/record * thread */static int ALSA_InitRingMessage(ALSA_MSG_RING* omr){    omr->msg_toget = 0;    omr->msg_tosave = 0;    omr->msg_event = CreateEventA(NULL, FALSE, FALSE, NULL);    omr->ring_buffer_size = ALSA_RING_BUFFER_INCREMENT;    omr->messages = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,omr->ring_buffer_size * sizeof(ALSA_MSG));    InitializeCriticalSection(&omr->msg_crst);    return 0;}/****************************************************************** *		ALSA_DestroyRingMessage * */static int ALSA_DestroyRingMessage(ALSA_MSG_RING* omr){    CloseHandle(omr->msg_event);    HeapFree(GetProcessHeap(),0,omr->messages);    DeleteCriticalSection(&omr->msg_crst);    return 0;}/****************************************************************** *		ALSA_AddRingMessage * * Inserts a new message into the ring (should be called from DriverProc derivated routines) */static int ALSA_AddRingMessage(ALSA_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 += ALSA_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(ALSA_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 */    SetEvent(omr->msg_event);    if (wait)    {        /* wait for playback/record thread to have processed the message */        WaitForSingleObject(hEvent, INFINITE);        CloseHandle(hEvent);    }    return 1;}/****************************************************************** *		ALSA_RetrieveRingMessage * * Get a message from the ring. Should be called by the playback/record thread. */static int ALSA_RetrieveRingMessage(ALSA_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;    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, snd_pcm_status_t* ps){   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;    wwo->lpPlayPtr->reserved = 0;    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;	}    }}/************************************************************************** * 				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;    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;	    wwo->lpPlayPtr->reserved = 0;	} 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 play a * period */static DWORD wodPlayer_DSPWait(const WINE_WAVEOUT *wwo){    /* time for one period to be played */    return snd_pcm_hw_params_get_period_time(wwo->hw_params, 0) / 1000;}/************************************************************************** * 			     wodPllayer_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;    dwMillis = (lpWaveHdr->dwBufferLength - lpWaveHdr->reserved) * 1000 / wwo->format.wf.nAvgBytesPerSec;    if (!dwMillis) dwMillis = 1;    return dwMillis;}/************************************************************************** * 			     wodPlayer_WriteMaxFrags            [internal] * Writes the maximum number of frames possible to the DSP and returns * the number of frames written. */static int wodPlayer_WriteMaxFrags(WINE_WAVEOUT* wwo, DWORD* frames){    /* Only attempt to write to free frames */    LPWAVEHDR lpWaveHdr = wwo->lpPlayPtr;    DWORD dwLength = snd_pcm_bytes_to_frames(wwo->p_handle, lpWaveHdr->dwBufferLength - lpWaveHdr->reserved);    int toWrite = min(dwLength, *frames);    int written;    TRACE("Writing wavehdr %p.%lu[%lu]\n", lpWaveHdr, lpWaveHdr->reserved, lpWaveHdr->dwBufferLength);    written = (wwo->write)(wwo->p_handle, lpWaveHdr->lpData + lpWaveHdr->reserved, toWrite);    if ( written < 0)    {    	/* XRUN occurred. let's try to recover */        ALSA_XRUNRecovery(wwo, written);	written = (wwo->write)(wwo->p_handle, lpWaveHdr->lpData + lpWaveHdr->reserved, toWrite);    }    if (written <= 0)    {        /* still in error */        ERR("Error in writing wavehdr. Reason: %s\n", snd_strerror(written));        return written;    }    lpWaveHdr->reserved += snd_pcm_frames_to_bytes(wwo->p_handle, written);    if ( lpWaveHdr->reserved >= lpWaveHdr->dwBufferLength) {

⌨️ 快捷键说明

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