📄 audio.c
字号:
if(WOutDev[wDevID].play_stream != (arts_stream_t*)-1) { TRACE("device already allocated\n"); return MMSYSERR_ALLOCATED; } /* only PCM format is supported so far... */ if (lpDesc->lpFormat->wFormatTag != WAVE_FORMAT_PCM || lpDesc->lpFormat->nChannels == 0 || lpDesc->lpFormat->nSamplesPerSec == 0) { WARN("Bad format: tag=%04X nChannels=%d nSamplesPerSec=%ld !\n", lpDesc->lpFormat->wFormatTag, lpDesc->lpFormat->nChannels, lpDesc->lpFormat->nSamplesPerSec); return WAVERR_BADFORMAT; } if (dwFlags & WAVE_FORMAT_QUERY) { TRACE("Query format: tag=%04X nChannels=%d nSamplesPerSec=%ld !\n", lpDesc->lpFormat->wFormatTag, lpDesc->lpFormat->nChannels, lpDesc->lpFormat->nSamplesPerSec); return MMSYSERR_NOERROR; } wwo = &WOutDev[wDevID]; /* direct sound not supported, ignore the flag */ dwFlags &= ~WAVE_DIRECTSOUND; wwo->wFlags = HIWORD(dwFlags & CALLBACK_TYPEMASK); memcpy(&wwo->waveDesc, lpDesc, sizeof(WAVEOPENDESC)); memcpy(&wwo->format, lpDesc->lpFormat, sizeof(PCMWAVEFORMAT)); 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; } wwo->play_stream = arts_play_stream(wwo->format.wf.nSamplesPerSec, wwo->format.wBitsPerSample, wwo->format.wf.nChannels, "winearts"); /* clear these so we don't have any confusion ;-) */ wwo->sound_buffer = 0; wwo->buffer_size = 0; arts_stream_set(wwo->play_stream, ARTS_P_BLOCKING, 0); /* disable blocking on this stream */ if(!wwo->play_stream) return MMSYSERR_ALLOCATED; /* Try to set buffer size from constant and store the value that it was set to for future use */ wwo->dwBufferSize = arts_stream_set(wwo->play_stream, ARTS_P_BUFFER_SIZE, BUFFER_SIZE); TRACE("Tried to set BUFFER_SIZE of %d, wwo->dwBufferSize is actually %ld\n", BUFFER_SIZE, wwo->dwBufferSize); wwo->dwPlayedTotal = 0; wwo->dwWrittenTotal = 0; /* Initialize volume to full level */ wwo->volume_left = 100; wwo->volume_right = 100; ARTS_InitRingMessage(&wwo->msgRing); /* create player thread */ if (!(dwFlags & WAVE_DIRECTSOUND)) { 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); } else { wwo->hThread = INVALID_HANDLE_VALUE; wwo->dwThreadID = 0; } wwo->hStartUpEvent = INVALID_HANDLE_VALUE; TRACE("stream=0x%lx, dwBufferSize=%ld\n", (long)wwo->play_stream, wwo->dwBufferSize); 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 >= MAX_WAVEOUTDRV || WOutDev[wDevID].play_stream == (arts_stream_t*)-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->hThread != INVALID_HANDLE_VALUE) { ARTS_AddRingMessage(&wwo->msgRing, WINE_WM_CLOSING, 0, TRUE); } ARTS_DestroyRingMessage(&wwo->msgRing); ARTS_CloseDevice(wwo); /* close the stream and clean things up */ 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 >= MAX_WAVEOUTDRV || WOutDev[wDevID].play_stream == (arts_stream_t*)-1) { WARN("bad dev ID !\n"); return MMSYSERR_BADDEVICEID; } if (lpWaveHdr->lpData == NULL || !(lpWaveHdr->dwFlags & WHDR_PREPARED)) { TRACE("unprepared\n"); return WAVERR_UNPREPARED; } if (lpWaveHdr->dwFlags & WHDR_INQUEUE) { TRACE("still playing\n"); return WAVERR_STILLPLAYING; } lpWaveHdr->dwFlags &= ~WHDR_DONE; lpWaveHdr->dwFlags |= WHDR_INQUEUE; lpWaveHdr->lpNext = 0; TRACE("adding ring message\n"); ARTS_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 >= 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].play_stream == (arts_stream_t*)-1) { WARN("bad device ID !\n"); return MMSYSERR_BADDEVICEID; } TRACE("imhere[3-PAUSING]\n"); ARTS_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 >= MAX_WAVEOUTDRV || WOutDev[wDevID].play_stream == (arts_stream_t*)-1) { WARN("bad device ID !\n"); return MMSYSERR_BADDEVICEID; } if (WOutDev[wDevID].state == WINE_WS_PAUSED) { TRACE("imhere[3-RESTARTING]\n"); ARTS_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 >= MAX_WAVEOUTDRV || WOutDev[wDevID].play_stream == (arts_stream_t*)-1) { WARN("bad device ID !\n"); return MMSYSERR_BADDEVICEID; } TRACE("imhere[3-RESET]\n"); ARTS_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 >= MAX_WAVEOUTDRV || WOutDev[wDevID].play_stream == (arts_stream_t*)-1) { WARN("bad device ID !\n"); return MMSYSERR_BADDEVICEID; } if (lpTime == NULL) return MMSYSERR_INVALPARAM; wwo = &WOutDev[wDevID]; ARTS_AddRingMessage(&wwo->msgRing, WINE_WM_UPDATE, 0, TRUE); 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 / 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;}/************************************************************************** * wodBreakLoop [internal] */static DWORD wodBreakLoop(WORD wDevID){ TRACE("(%u);\n", wDevID); if (wDevID >= MAX_WAVEOUTDRV || WOutDev[wDevID].play_stream == (arts_stream_t*)-1) { WARN("bad device ID !\n"); return MMSYSERR_BADDEVICEID; } ARTS_AddRingMessage(&WOutDev[wDevID].msgRing, WINE_WM_BREAKLOOP, 0, TRUE); return MMSYSERR_NOERROR;}/************************************************************************** * wodGetVolume [internal] */static DWORD wodGetVolume(WORD wDevID, LPDWORD lpdwVol){ DWORD left, right; left = WOutDev[wDevID].volume_left; right = WOutDev[wDevID].volume_right; TRACE("(%u, %p);\n", wDevID, lpdwVol); *lpdwVol = ((left * 0xFFFFl) / 100) + (((right * 0xFFFFl) / 100) << 16); return MMSYSERR_NOERROR;}/************************************************************************** * wodSetVolume [internal] */static DWORD wodSetVolume(WORD wDevID, DWORD dwParam){ DWORD left, right; left = (LOWORD(dwParam) * 100) / 0xFFFFl; right = (HIWORD(dwParam) * 100) / 0xFFFFl; TRACE("(%u, %08lX);\n", wDevID, dwParam); WOutDev[wDevID].volume_left = left; WOutDev[wDevID].volume_right = right; return MMSYSERR_NOERROR;}/************************************************************************** * wodGetNumDevs [internal] */static DWORD wodGetNumDevs(void){ return MAX_WAVEOUTDRV;}/************************************************************************** * wodMessage (WINEARTS.@) */DWORD WINAPI ARTS_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 wodBreakLoop (wDevID); 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 * *======================================================================*/static DWORD wodDsCreate(UINT wDevID, PIDSDRIVER* drv){ /* we can't perform memory mapping as we don't have a file stream interface with arts like we do with oss */ MESSAGE("This sound card's driver does not support direct access\n"); MESSAGE("The (slower) DirectSound HEL mode will be used instead.\n"); return MMSYSERR_NOTSUPPORTED;}static DWORD wodDsDesc(UINT wDevID, PDSDRIVERDESC desc){ memset(desc, 0, sizeof(*desc)); strcpy(desc->szDesc, "Wine aRts DirectSound Driver"); strcpy(desc->szDrvName, "winearts.drv"); return MMSYSERR_NOERROR;}static DWORD wodDsGuid(UINT wDevID, LPGUID pGuid){ memcpy(pGuid, &DSDEVID_DefaultPlayback, sizeof(GUID)); return MMSYSERR_NOERROR;}#else /* !HAVE_ARTS *//************************************************************************** * wodMessage (WINEARTS.@) */DWORD WINAPI ARTS_wodMessage(WORD wDevID, WORD wMsg, DWORD dwUser, DWORD dwParam1, DWORD dwParam2){ FIXME("(%u, %04X, %08lX, %08lX, %08lX):stub\n", wDevID, wMsg, dwUser, dwParam1, dwParam2); return MMSYSERR_NOTENABLED;}#endif /* HAVE_ARTS */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -