📄 audio.c
字号:
if (wwo->format.wBitsPerSample == 0) { WARN("Resetting zeroed wBitsPerSample\n"); wwo->format.wBitsPerSample = 8 * (wwo->format.wf.nAvgBytesPerSec / wwo->format.wf.nSamplesPerSec) / wwo->format.wf.nChannels; } /* Read output space info for future reference */ 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)); OSS_CloseDevice(wwo->ossdev); wwo->state = WINE_WS_CLOSED; return MMSYSERR_NOTENABLED; } /* Check that fragsize is correct per our settings above */ if ((info.fragsize > 1024) && (LOWORD(audio_fragment) <= 10)) { /* we've tried to set 1K fragments or less, but it didn't work */ ERR("fragment size set failed, size is now %d\n", info.fragsize); MESSAGE("Your Open Sound System driver did not let us configure small enough sound fragments.\n"); MESSAGE("This may cause delays and other problems in audio playback with certain applications.\n"); } /* Remember fragsize and total buffer size for future use */ wwo->dwFragmentSize = info.fragsize; wwo->dwBufferSize = info.fragstotal * info.fragsize; wwo->dwPlayedTotal = 0; wwo->dwWrittenTotal = 0; wwo->bNeedPost = TRUE; OSS_InitRingMessage(&wwo->msgRing); wwo->hStartUpEvent = CreateEventA(NULL, FALSE, FALSE, NULL); wwo->hThread = CreateThread(NULL, 0, wodPlayer, (LPVOID)(DWORD)wDevID, 0, &(wwo->dwThreadID)); WaitForSingleObject(wwo->hStartUpEvent, INFINITE); CloseHandle(wwo->hStartUpEvent); wwo->hStartUpEvent = INVALID_HANDLE_VALUE; TRACE("fd=%d fragmentSize=%ld\n", wwo->ossdev->fd, 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); return wodNotifyClient(wwo, WOM_OPEN, 0L, 0L);}/************************************************************************** * wodClose [internal] */static DWORD wodClose(WORD wDevID){ DWORD ret = MMSYSERR_NOERROR; WINE_WAVEOUT* wwo; TRACE("(%u);\n", wDevID); if (wDevID >= numOutDev || WOutDev[wDevID].state == WINE_WS_CLOSED) { WARN("bad device ID !\n"); return MMSYSERR_BADDEVICEID; } wwo = &WOutDev[wDevID]; if (wwo->lpQueuePtr) { WARN("buffers still playing !\n"); ret = WAVERR_STILLPLAYING; } else { if (wwo->hThread != INVALID_HANDLE_VALUE) { OSS_AddRingMessage(&wwo->msgRing, WINE_WM_CLOSING, 0, TRUE); } if (wwo->mapping) { munmap(wwo->mapping, wwo->maplen); wwo->mapping = NULL; } OSS_DestroyRingMessage(&wwo->msgRing); OSS_CloseDevice(wwo->ossdev); wwo->state = WINE_WS_CLOSED; wwo->dwFragmentSize = 0; ret = wodNotifyClient(wwo, WOM_CLOSE, 0L, 0L); } 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 >= numOutDev || WOutDev[wDevID].state == WINE_WS_CLOSED) { 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; if ((lpWaveHdr->dwBufferLength & (WOutDev[wDevID].format.wf.nBlockAlign - 1)) != 0) { WARN("WaveHdr length isn't a multiple of the PCM block size: %ld %% %d\n",lpWaveHdr->dwBufferLength,WOutDev[wDevID].format.wf.nBlockAlign); lpWaveHdr->dwBufferLength &= ~(WOutDev[wDevID].format.wf.nBlockAlign - 1); } OSS_AddRingMessage(&WOutDev[wDevID].msgRing, WINE_WM_HEADER, (DWORD)lpWaveHdr, FALSE); return MMSYSERR_NOERROR;}/************************************************************************** * wodPrepare [internal] */static DWORD wodPrepare(WORD wDevID, LPWAVEHDR lpWaveHdr, DWORD dwSize){ TRACE("(%u, %p, %08lX);\n", wDevID, lpWaveHdr, dwSize); if (wDevID >= numOutDev) { 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 >= numOutDev) { 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 >= numOutDev || WOutDev[wDevID].state == WINE_WS_CLOSED) { WARN("bad device ID !\n"); return MMSYSERR_BADDEVICEID; } OSS_AddRingMessage(&WOutDev[wDevID].msgRing, WINE_WM_PAUSING, 0, TRUE); return MMSYSERR_NOERROR;}/************************************************************************** * wodRestart [internal] */static DWORD wodRestart(WORD wDevID){ TRACE("(%u);\n", wDevID); if (wDevID >= numOutDev || WOutDev[wDevID].state == WINE_WS_CLOSED) { WARN("bad device ID !\n"); return MMSYSERR_BADDEVICEID; } OSS_AddRingMessage(&WOutDev[wDevID].msgRing, WINE_WM_RESTARTING, 0, TRUE); /* FIXME: is NotifyClient with WOM_DONE right ? (Comet Busters 1.3.3 needs this notification) */ /* FIXME: Myst crashes with this ... hmm -MM return wodNotifyClient(wwo, WOM_DONE, 0L, 0L); */ return MMSYSERR_NOERROR;}/************************************************************************** * wodReset [internal] */static DWORD wodReset(WORD wDevID){ TRACE("(%u);\n", wDevID); if (wDevID >= numOutDev || WOutDev[wDevID].state == WINE_WS_CLOSED) { WARN("bad device ID !\n"); return MMSYSERR_BADDEVICEID; } OSS_AddRingMessage(&WOutDev[wDevID].msgRing, WINE_WM_RESETTING, 0, TRUE); 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 >= numOutDev || WOutDev[wDevID].state == WINE_WS_CLOSED) { WARN("bad device ID !\n"); return MMSYSERR_BADDEVICEID; } if (lpTime == NULL) return MMSYSERR_INVALPARAM; wwo = &WOutDev[wDevID];#ifdef EXACT_WODPOSITION OSS_AddRingMessage(&wwo->msgRing, WINE_WM_UPDATE, 0, TRUE);#endif 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("dwPlayedTotal=%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 /wwo->format.wf.nChannels; TRACE("TIME_SAMPLES=%lu\n", lpTime->u.sample); break; case TIME_SMPTE: time = val / (wwo->format.wf.nAvgBytesPerSec / 1000); lpTime->u.smpte.hour = time / (60 * 60 * 1000); time -= lpTime->u.smpte.hour * (60 * 60 * 1000); lpTime->u.smpte.min = time / (60 * 1000); time -= lpTime->u.smpte.min * (60 * 1000); lpTime->u.smpte.sec = time / 1000; time -= lpTime->u.smpte.sec * 1000; lpTime->u.smpte.frame = time * 30 / 1000; 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;}/************************************************************************** * wodBreakLoop [internal] */static DWORD wodBreakLoop(WORD wDevID){ TRACE("(%u);\n", wDevID); if (wDevID >= numOutDev || WOutDev[wDevID].state == WINE_WS_CLOSED) { WARN("bad device ID !\n"); return MMSYSERR_BADDEVICEID; } OSS_AddRingMessage(&WOutDev[wDevID].msgRing, WINE_WM_BREAKLOOP, 0, TRUE); return MMSYSERR_NOERROR;}/************************************************************************** * wodGetVolume [internal] */static DWORD wodGetVolume(WORD wDevID, LPDWORD lpdwVol){ int mixer; int volume; DWORD left, right; TRACE("(%u, %p);\n", wDevID, lpdwVol); if (lpdwVol == NULL) return MMSYSERR_NOTENABLED; if (wDevID >= numOutDev) return MMSYSERR_INVALPARAM; if ((mixer = open(WOutDev[wDevID].ossdev->mixer_name, O_RDONLY|O_NDELAY)) < 0) { WARN("mixer device not available !\n"); return MMSYSERR_NOTENABLED; } if (ioctl(mixer, SOUND_MIXER_READ_PCM, &volume) == -1) { WARN("ioctl(%s, SOUND_MIXER_READ_PCM) failed (%s)n", WOutDev[wDevID].ossdev->mixer_name, strerror(errno)); return MMSYSERR_NOTENABLED; } close(mixer); left = LOBYTE(volume); right = HIBYTE(volume); TRACE("left=%ld right=%ld !\n", left, right); *lpdwVol = ((left * 0xFFFFl) / 100) + (((right * 0xFFFFl) / 100) << 16); return MMSYSERR_NOERROR;}/************************************************************************** * wodSetVolume [internal] */static DWORD wodSetVolume(WORD wDevID, DWORD dwParam){ int mixer; int volume; DWORD left, right; TRACE("(%u, %08lX);\n", wDevID, dwParam); left = (LOWORD(dwParam) * 100) / 0xFFFFl; right = (HIWORD(dwParam) * 100) / 0xFFFFl; volume = left + (right << 8); if (wDevID >= numOutDev) { WARN("invalid parameter: wDevID > %d\n", numOutDev); return MMSYSERR_INVALPARAM; } if ((mixer = open(WOutDev[wDevID].ossdev->mixer_name, O_WRONLY|O_NDELAY)) < 0) { WARN("mixer device not available !\n"); return MMSYSERR_NOTENABLED; } if (ioctl(mixer, SOUND_MIXER_WRITE_PCM, &volume) == -1) { WARN("ioctl(%s, SOUND_MIXER_WRITE_PCM) failed (%s)\n", WOutDev[wDevID].ossdev->mixer_name, strerror(errno)); return MMSYSERR_NOTENABLED; } else { TRACE("volume=%04x\n", (unsigned)volume); } close(mixer); return MMSYSERR_NOERROR;}/************************************************************************** * wodMessage (WINEOSS.7) */DWORD WINAPI OSS_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)dwPara
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -