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