audio.c

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

C
2,103
字号
    spec[PLAYBACK].precision=(wwo->format.wBitsPerSample );    if (spec[PLAYBACK].precision==16) spec[PLAYBACK].type=TYPE_SIGNED; else spec[PLAYBACK].type=TYPE_UNSIGNED;    spec[PLAYBACK].channels=(wwo->format.wf.nChannels);    spec[PLAYBACK].encoding=ENCODE_PCM;    spec[PLAYBACK].endian=ENDIAN_INTEL;    spec[PLAYBACK].max_blocks=16;  /*FIXME This is the libaudioio equivalent to fragments, it controls latency*/	audio = AudioIOOpenX( O_WRONLY|O_NDELAY,&spec[PLAYBACK],&spec[PLAYBACK]);    if (audio == -1) {	WARN("can't open sound device %s (%s)!\n", SOUND_DEV, strerror(errno));	return MMSYSERR_ALLOCATED;    } /*   fcntl(audio, F_SETFD, 1); *//* set close on exec flag */    wwo->unixdev = audio;    /* even if we set fragment size above, read it again, just in case */    wwo->dwFragmentSize = DEFAULT_FRAGMENT_SIZE;    wwo->msg_toget = 0;    wwo->msg_tosave = 0;    wwo->msg_event = CreateEventA(NULL, FALSE, FALSE, NULL);    memset(wwo->messages, 0, sizeof(WWO_MSG)*WWO_RING_BUFFER_SIZE);    InitializeCriticalSection(&wwo->msg_crst);    if (!(dwFlags & WAVE_DIRECTSOUND)) {	wwo->hEvent = CreateEventA(NULL, FALSE, FALSE, NULL);	wwo->hThread = CreateThread(NULL, 0, wodPlayer, (LPVOID)(DWORD)wDevID, 0, &(wwo->dwThreadID));	WaitForSingleObject(wwo->hEvent, INFINITE);    } else {	wwo->hEvent = INVALID_HANDLE_VALUE;	wwo->hThread = INVALID_HANDLE_VALUE;	wwo->dwThreadID = 0;    }    TRACE("fd=%d fragmentSize=%ld\n",	  wwo->unixdev, wwo->dwFragmentSize);    if (wwo->dwFragmentSize % wwo->format.wf.nBlockAlign)	ERR("Fragment doesn't contain an integral number of data blocks\n");    TRACE("wBitsPerSample=%u, nAvgBytesPerSec=%lu, nSamplesPerSec=%lu, nChannels=%u nBlockAlign=%u!\n",	  wwo->format.wBitsPerSample, wwo->format.wf.nAvgBytesPerSec,	  wwo->format.wf.nSamplesPerSec, wwo->format.wf.nChannels,	  wwo->format.wf.nBlockAlign);    if (LIBAUDIOIO_NotifyClient(wDevID, WOM_OPEN, 0L, 0L) != MMSYSERR_NOERROR) {	WARN("can't notify client !\n");	return MMSYSERR_INVALPARAM;    }    return MMSYSERR_NOERROR;}/************************************************************************** * 				wodClose			[internal] */static DWORD wodClose(WORD wDevID){    DWORD		ret = MMSYSERR_NOERROR;    WINE_WAVEOUT*	wwo;    TRACE("(%u);\n", wDevID);    if (wDevID >= MAX_WAVEOUTDRV || WOutDev[wDevID].unixdev == -1) {	WARN("bad device ID !\n");	return MMSYSERR_BADDEVICEID;    }    wwo = &WOutDev[wDevID];    if (wwo->lpQueuePtr) {	WARN("buffers still playing !\n");	ret = WAVERR_STILLPLAYING;    } else {	TRACE("imhere[3-close]\n");	if (wwo->hEvent != INVALID_HANDLE_VALUE) {	    wodPlayer_Message(wwo, WINE_WM_CLOSING, 0);	    WaitForSingleObject(wwo->hEvent, INFINITE);	    CloseHandle(wwo->hEvent);	}	if (wwo->mapping) {	    munmap(wwo->mapping, wwo->maplen);	    wwo->mapping = NULL;	}	AudioIOClose();	wwo->unixdev = -1;	wwo->dwFragmentSize = 0;	if (LIBAUDIOIO_NotifyClient(wDevID, WOM_CLOSE, 0L, 0L) != MMSYSERR_NOERROR) {	    WARN("can't notify client !\n");	    ret = MMSYSERR_INVALPARAM;	}    }    return ret;}/************************************************************************** * 				wodWrite			[internal] * */static DWORD wodWrite(WORD wDevID, LPWAVEHDR lpWaveHdr, DWORD dwSize){    TRACE("(%u, %p, %08lX);\n", wDevID, lpWaveHdr, dwSize);    /* first, do the sanity checks... */    if (wDevID >= MAX_WAVEOUTDRV || WOutDev[wDevID].unixdev == -1) {        WARN("bad dev ID !\n");	return MMSYSERR_BADDEVICEID;    }    if (lpWaveHdr->lpData == NULL || !(lpWaveHdr->dwFlags & WHDR_PREPARED))	return WAVERR_UNPREPARED;    if (lpWaveHdr->dwFlags & WHDR_INQUEUE)	return WAVERR_STILLPLAYING;    lpWaveHdr->dwFlags &= ~WHDR_DONE;    lpWaveHdr->dwFlags |= WHDR_INQUEUE;    lpWaveHdr->lpNext = 0;    TRACE("imhere[3-HEADER]\n");    wodPlayer_Message(&WOutDev[wDevID], WINE_WM_HEADER, (DWORD)lpWaveHdr);    return MMSYSERR_NOERROR;}/************************************************************************** * 				wodPrepare			[internal] */static DWORD wodPrepare(WORD wDevID, LPWAVEHDR lpWaveHdr, DWORD dwSize){    TRACE("(%u, %p, %08lX);\n", wDevID, lpWaveHdr, dwSize);    if (wDevID >= MAX_WAVEOUTDRV) {	WARN("bad device ID !\n");	return MMSYSERR_BADDEVICEID;    }    if (lpWaveHdr->dwFlags & WHDR_INQUEUE)	return WAVERR_STILLPLAYING;    lpWaveHdr->dwFlags |= WHDR_PREPARED;    lpWaveHdr->dwFlags &= ~WHDR_DONE;    return MMSYSERR_NOERROR;}/************************************************************************** * 				wodUnprepare			[internal] */static DWORD wodUnprepare(WORD wDevID, LPWAVEHDR lpWaveHdr, DWORD dwSize){    TRACE("(%u, %p, %08lX);\n", wDevID, lpWaveHdr, dwSize);    if (wDevID >= MAX_WAVEOUTDRV) {	WARN("bad device ID !\n");	return MMSYSERR_BADDEVICEID;    }    if (lpWaveHdr->dwFlags & WHDR_INQUEUE)	return WAVERR_STILLPLAYING;    lpWaveHdr->dwFlags &= ~WHDR_PREPARED;    lpWaveHdr->dwFlags |= WHDR_DONE;    return MMSYSERR_NOERROR;}/************************************************************************** * 			wodPause				[internal] */static DWORD wodPause(WORD wDevID){    TRACE("(%u);!\n", wDevID);    if (wDevID >= MAX_WAVEOUTDRV || WOutDev[wDevID].unixdev == -1) {	WARN("bad device ID !\n");	return MMSYSERR_BADDEVICEID;    }    TRACE("imhere[3-PAUSING]\n");    wodPlayer_Message(&WOutDev[wDevID], WINE_WM_PAUSING, 0);    WaitForSingleObject(WOutDev[wDevID].hEvent, INFINITE);    return MMSYSERR_NOERROR;}/************************************************************************** * 			wodRestart				[internal] */static DWORD wodRestart(WORD wDevID){    TRACE("(%u);\n", wDevID);    if (wDevID >= MAX_WAVEOUTDRV || WOutDev[wDevID].unixdev == -1) {	WARN("bad device ID !\n");	return MMSYSERR_BADDEVICEID;    }    if (WOutDev[wDevID].state == WINE_WS_PAUSED) {	TRACE("imhere[3-RESTARTING]\n");	wodPlayer_Message(&WOutDev[wDevID], WINE_WM_RESTARTING, 0);	WaitForSingleObject(WOutDev[wDevID].hEvent, INFINITE);    }    /* FIXME: is NotifyClient with WOM_DONE right ? (Comet Busters 1.3.3 needs this notification) */    /* FIXME: Myst crashes with this ... hmm -MM       if (LIBAUDIOIO_NotifyClient(wDevID, WOM_DONE, 0L, 0L) != MMSYSERR_NOERROR) {       WARN("can't notify client !\n");       return MMSYSERR_INVALPARAM;       }    */    return MMSYSERR_NOERROR;}/************************************************************************** * 			wodReset				[internal] */static DWORD wodReset(WORD wDevID){    TRACE("(%u);\n", wDevID);    if (wDevID >= MAX_WAVEOUTDRV || WOutDev[wDevID].unixdev == -1) {	WARN("bad device ID !\n");	return MMSYSERR_BADDEVICEID;    }    TRACE("imhere[3-RESET]\n");    wodPlayer_Message(&WOutDev[wDevID], WINE_WM_RESETTING, 0);    WaitForSingleObject(WOutDev[wDevID].hEvent, INFINITE);    return MMSYSERR_NOERROR;}/************************************************************************** * 				wodGetPosition			[internal] */static DWORD wodGetPosition(WORD wDevID, LPMMTIME lpTime, DWORD uSize){    int			time;    DWORD		val;    WINE_WAVEOUT*	wwo;    TRACE("(%u, %p, %lu);\n", wDevID, lpTime, uSize);    if (wDevID >= MAX_WAVEOUTDRV || WOutDev[wDevID].unixdev == -1) {	WARN("bad device ID !\n");	return MMSYSERR_BADDEVICEID;    }    if (lpTime == NULL)	return MMSYSERR_INVALPARAM;    wwo = &WOutDev[wDevID];    val = wwo->dwPlayedTotal;    TRACE("wType=%04X wBitsPerSample=%u nSamplesPerSec=%lu nChannels=%u nAvgBytesPerSec=%lu\n",	  lpTime->wType, wwo->format.wBitsPerSample,	  wwo->format.wf.nSamplesPerSec, wwo->format.wf.nChannels,	  wwo->format.wf.nAvgBytesPerSec);    TRACE("dwTotalPlayed=%lu\n", val);    switch (lpTime->wType) {    case TIME_BYTES:	lpTime->u.cb = val;	TRACE("TIME_BYTES=%lu\n", lpTime->u.cb);	break;    case TIME_SAMPLES:	lpTime->u.sample = val * 8 / wwo->format.wBitsPerSample;	TRACE("TIME_SAMPLES=%lu\n", lpTime->u.sample);	break;    case TIME_SMPTE:	time = val / (wwo->format.wf.nAvgBytesPerSec / 1000);	lpTime->u.smpte.hour = time / 108000;	time -= lpTime->u.smpte.hour * 108000;	lpTime->u.smpte.min = time / 1800;	time -= lpTime->u.smpte.min * 1800;	lpTime->u.smpte.sec = time / 30;	time -= lpTime->u.smpte.sec * 30;	lpTime->u.smpte.frame = time;	lpTime->u.smpte.fps = 30;	TRACE("TIME_SMPTE=%02u:%02u:%02u:%02u\n",	      lpTime->u.smpte.hour, lpTime->u.smpte.min,	      lpTime->u.smpte.sec, lpTime->u.smpte.frame);	break;    default:	FIXME("Format %d not supported ! use TIME_MS !\n", lpTime->wType);	lpTime->wType = TIME_MS;    case TIME_MS:	lpTime->u.ms = val / (wwo->format.wf.nAvgBytesPerSec / 1000);	TRACE("TIME_MS=%lu\n", lpTime->u.ms);	break;    }    return MMSYSERR_NOERROR;}/************************************************************************** * 				wodGetVolume			[internal] */static DWORD wodGetVolume(WORD wDevID, LPDWORD lpdwVol){    int 	mixer;    int		vol,bal;    DWORD	left, right;    TRACE("(%u, %p);\n", wDevID, lpdwVol);    if (lpdwVol == NULL)	return MMSYSERR_NOTENABLED;     vol=AudioIOGetPlaybackVolume();     bal=AudioIOGetPlaybackBalance();     if(bal<0) {     	left = vol;     	right=-(vol*(-100+bal)/100);     }      else     {     	right = vol;     	left=(vol*(100-bal)/100);     }    *lpdwVol = ((left * 0xFFFFl) / 100) + (((right * 0xFFFFl) / 100) << 16);    return MMSYSERR_NOERROR;}/************************************************************************** * 				wodSetVolume			[internal] */static DWORD wodSetVolume(WORD wDevID, DWORD dwParam){    int 	mixer;    int		volume,bal;    DWORD	left, right;    TRACE("(%u, %08lX);\n", wDevID, dwParam);    left  = (LOWORD(dwParam) * 100) / 0xFFFFl;    right = (HIWORD(dwParam) * 100) / 0xFFFFl;    volume = max(left , right );    bal=min(left,right);    bal=bal*100/volume;    if(right>left) bal=-100+bal; else bal=100-bal;    AudioIOSetPlaybackVolume(volume);    AudioIOSetPlaybackBalance(bal);    return MMSYSERR_NOERROR;}/************************************************************************** * 				wodGetNumDevs			[internal] */static	DWORD	wodGetNumDevs(void){    DWORD	ret = 1;    /* FIXME: For now, only one sound device (SOUND_DEV) is allowed */    int audio = open(SOUND_DEV, O_WRONLY|O_NDELAY, 0);    if (audio == -1) {	if (errno != EBUSY)	    ret = 0;    } else {	close(audio);    }    TRACE("NumDrivers = %d\n",ret);    return ret;}/************************************************************************** * 				wodMessage (WINEAUDIOIO.@) */DWORD WINAPI LIBAUDIOIO_wodMessage(UINT wDevID, UINT wMsg, DWORD dwUser,			    DWORD dwParam1, DWORD dwParam2){    TRACE("(%u, %04X, %08lX, %08lX, %08lX);\n",	  wDevID, wMsg, dwUser, dwParam1, dwParam2);    switch (wMsg) {    case DRVM_INIT:    case DRVM_EXIT:    case DRVM_ENABLE:    case DRVM_DISABLE:	/* FIXME: Pretend this is supported */	return 0;    case WODM_OPEN:	 	return wodOpen		(wDevID, (LPWAVEOPENDESC)dwParam1,	dwParam2);    case WODM_CLOSE:	 	return wodClose		(wDevID);    case WODM_WRITE:	 	return wodWrite		(wDevID, (LPWAVEHDR)dwParam1,		dwParam2);    case WODM_PAUSE:	 	return wodPause		(wDevID);    case WODM_GETPOS:	 	return wodGetPosition	(wDevID, (LPMMTIME)dwParam1, 		dwParam2);    case WODM_BREAKLOOP: 	return MMSYSERR_NOTSUPPORTED;    case WODM_PREPARE:	 	return wodPrepare	(wDevID, (LPWAVEHDR)dwParam1, 		dwParam2);    case WODM_UNPREPARE: 	return wodUnprepare	(wDevID, (LPWAVEHDR)dwParam1, 		dwParam2);    case WODM_GETDEVCAPS:	return wodGetDevCaps	(wDevID, (LPWAVEOUTCAPSA)dwParam1,	dwParam2);    case WODM_GETNUMDEVS:	return wodGetNumDevs	();    case WODM_GETPITCH:	 	return MMSYSERR_NOTSUPPORTED;    case WODM_SETPITCH:	 	return MMSYSERR_NOTSUPPORTED;    case WODM_GETPLAYBACKRATE:	return MMSYSERR_NOTSUPPORTED;    case WODM_SETPLAYBACKRATE:	return MMSYSERR_NOTSUPPORTED;    case WODM_GETVOLUME:	return wodGetVolume	(wDevID, (LPDWORD)dwParam1);    case WODM_SETVOLUME:	return wodSetVolume	(wDevID, dwParam1);    case WODM_RESTART:		return wodRestart	(wDevID);    case WODM_RESET:		return wodReset		(wDevID);    case DRV_QUERYDSOUNDIFACE:	return wodDsCreate	(wDevID, (PIDSDRIVER*)dwParam1);    case DRV_QUERYDSOUNDDESC:	return wodDsDesc	(wDevID, (PDSDRIVERDESC)dwParam1);    case DRV_QUERYDSOUNDGUID:	return wodDsGuid	(wDevID, (LPGUID)dwParam1);    default:	FIXME("unknown message %d!\n", wMsg);    }    return MMSYSERR_NOTSUPPORTED;}/*======================================================================* *                  Low level DSOUND implementation			* *		While I have tampered somewhat with this code it is wholely unlikely that it works

⌨️ 快捷键说明

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