📄 audio.c
字号:
EXIT_ON_ERROR( snd_pcm_sw_params_set_avail_min(pcm, sw_params, period_size), MMSYSERR_ERROR, "unable to set avail min"); EXIT_ON_ERROR( snd_pcm_sw_params_set_xfer_align(pcm, sw_params, 1), MMSYSERR_ERROR, "unable to set xfer align"); EXIT_ON_ERROR( snd_pcm_sw_params_set_silence_threshold(pcm, sw_params, 0), MMSYSERR_ERROR, "unable to set silence threshold"); EXIT_ON_ERROR( snd_pcm_sw_params(pcm, sw_params), MMSYSERR_ERROR, "unable to set sw params for playback");#undef EXIT_ON_ERROR snd_pcm_prepare(pcm); if (TRACE_ON(wave)) ALSA_TraceParameters(hw_params, sw_params, FALSE); /* now, we can save all required data for later use... */ if ( wwo->hw_params ) snd_pcm_hw_params_free(wwo->hw_params); snd_pcm_hw_params_malloc(&(wwo->hw_params)); snd_pcm_hw_params_copy(wwo->hw_params, hw_params); wwo->dwBufferSize = buffer_size; wwo->lpQueuePtr = wwo->lpPlayPtr = wwo->lpLoopPtr = NULL; wwo->p_handle = pcm; ALSA_InitRingMessage(&wwo->msgRing); wwo->count = snd_pcm_poll_descriptors_count (wwo->p_handle); if (wwo->count <= 0) { ERR("Invalid poll descriptors count\n"); return MMSYSERR_ERROR; } wwo->ufds = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY, sizeof(struct pollfd) * wwo->count); if (wwo->ufds == NULL) { ERR("No enough memory\n"); return MMSYSERR_NOMEM; } if ((err = snd_pcm_poll_descriptors(wwo->p_handle, wwo->ufds, wwo->count)) < 0) { ERR("Unable to obtain poll descriptors for playback: %s\n", snd_strerror(err)); return MMSYSERR_ERROR; } 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("handle=%08lx \n", (DWORD)wwo->p_handle);/* 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 >= MAX_WAVEOUTDRV || WOutDev[wDevID].p_handle == NULL) { 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) { ALSA_AddRingMessage(&wwo->msgRing, WINE_WM_CLOSING, 0, TRUE); } ALSA_DestroyRingMessage(&wwo->msgRing); snd_pcm_hw_params_free(wwo->hw_params); wwo->hw_params = NULL; snd_pcm_close(wwo->p_handle); wwo->p_handle = NULL; ret = wodNotifyClient(wwo, WOM_CLOSE, 0L, 0L); } HeapFree(GetProcessHeap(), 0, wwo->ufds); 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].p_handle == NULL) { 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; ALSA_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].p_handle == NULL) { WARN("bad device ID !\n"); return MMSYSERR_BADDEVICEID; } ALSA_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].p_handle == NULL) { WARN("bad device ID !\n"); return MMSYSERR_BADDEVICEID; } if (WOutDev[wDevID].state == WINE_WS_PAUSED) { ALSA_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].p_handle == NULL) { WARN("bad device ID !\n"); return MMSYSERR_BADDEVICEID; } ALSA_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].p_handle == NULL) { WARN("bad device ID !\n"); return MMSYSERR_BADDEVICEID; } if (lpTime == NULL) return MMSYSERR_INVALPARAM; wwo = &WOutDev[wDevID]; ALSA_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].p_handle == NULL) { WARN("bad device ID !\n"); return MMSYSERR_BADDEVICEID; } ALSA_AddRingMessage(&WOutDev[wDevID].msgRing, WINE_WM_BREAKLOOP, 0, TRUE); return MMSYSERR_NOERROR;}/************************************************************************** * wodGetVolume [internal] */static DWORD wodGetVolume(WORD wDevID, LPDWORD lpdwVol){ WORD left, right; WINE_WAVEOUT* wwo; int count; long min, max; TRACE("(%u, %p);\n", wDevID, lpdwVol); if (wDevID >= MAX_WAVEOUTDRV || WOutDev[wDevID].p_handle == NULL) { WARN("bad device ID !\n"); return MMSYSERR_BADDEVICEID; } wwo = &WOutDev[wDevID]; count = snd_ctl_elem_info_get_count(wwo->playback_einfo); min = snd_ctl_elem_info_get_min(wwo->playback_einfo); max = snd_ctl_elem_info_get_max(wwo->playback_einfo);#define VOLUME_ALSA_TO_WIN(x) (((x)-min) * 65536 /(max-min)) if (lpdwVol == NULL) return MMSYSERR_NOTENABLED; switch (count) { case 2: left = VOLUME_ALSA_TO_WIN(snd_ctl_elem_value_get_integer(wwo->playback_evalue, 0)); right = VOLUME_ALSA_TO_WIN(snd_ctl_elem_value_get_integer(wwo->playback_evalue, 1)); break; case 1: left = right = VOLUME_ALSA_TO_WIN(snd_ctl_elem_value_get_integer(wwo->playback_evalue, 0)); break; default: WARN("%d channels mixer not supported\n", count); return MMSYSERR_NOERROR; }#undef VOLUME_ALSA_TO_WIN TRACE("left=%d right=%d !\n", left, right); *lpdwVol = MAKELONG( left, right ); return MMSYSERR_NOERROR;}/************************************************************************** * wodSetVolume [internal] */static DWORD wodSetVolume(WORD wDevID, DWORD dwParam){ WORD left, right; WINE_WAVEOUT* wwo; int count, err; long min, max; TRACE("(%u, %08lX);\n", wDevID, dwParam); if (wDevID >= MAX_WAVEOUTDRV || WOutDev[wDevID].p_handle == NULL) { WARN("bad device ID !\n"); return MMSYSERR_BADDEVICEID; } wwo = &WOutDev[wDevID]; count=snd_ctl_elem_info_get_count(wwo->playback_einfo); min = snd_ctl_elem_info_get_min(wwo->playback_einfo); max = snd_ctl_elem_info_get_max(wwo->playback_einfo); left = LOWORD(dwParam); right = HIWORD(dwParam);#define VOLUME_WIN_TO_ALSA(x) ( (((x) * (max-min)) / 65536) + min ) switch (count) { case 2: snd_ctl_elem_value_set_integer(wwo->playback_evalue, 0, VOLUME_WIN_TO_ALSA(left)); snd_ctl_elem_value_set_integer(wwo->playback_evalue, 1, VOLUME_WIN_TO_ALSA(right)); break; case 1: snd_ctl_elem_value_set_integer(wwo->playback_evalue, 0, VOLUME_WIN_TO_ALSA(left)); break; default: WARN("%d channels mixer not supported\n", count); }#undef VOLUME_WIN_TO_ALSA if ( (err = snd_ctl_elem_write(wwo->ctl, wwo->playback_evalue)) < 0) { ERR("error writing snd_ctl_elem_value: %s\n", snd_strerror(err)); } return MMSYSERR_NOERROR;}/************************************************************************** * wodGetNumDevs [internal] */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -