From 5290f53193d0d43ad2867098228a2599422ebf61 Mon Sep 17 00:00:00 2001 From: Maarten Lankhorst Date: Fri, 7 Dec 2007 10:50:03 +0100 Subject: [PATCH] winealsa: Simplify the feeding of capture buffers. --- dlls/winealsa.drv/wavein.c | 188 +++++++++++-------------------------- 1 file changed, 57 insertions(+), 131 deletions(-) diff --git a/dlls/winealsa.drv/wavein.c b/dlls/winealsa.drv/wavein.c index 6d1cf246c27..652e0cd8d97 100644 --- a/dlls/winealsa.drv/wavein.c +++ b/dlls/winealsa.drv/wavein.c @@ -146,8 +146,6 @@ static DWORD CALLBACK widRecorder(LPVOID pmt) WAVEHDR* lpWaveHdr; DWORD dwSleepTime; DWORD bytesRead; - LPVOID buffer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, wwi->dwPeriodSize); - char *pOffset = buffer; enum win_wm_message msg; DWORD param; HANDLE ev; @@ -171,140 +169,69 @@ static DWORD CALLBACK widRecorder(LPVOID pmt) */ if (wwi->lpQueuePtr != NULL && wwi->state == WINE_WS_PLAYING) { - int periods; - DWORD frames; - DWORD bytes; - DWORD read; + DWORD frames; + DWORD bytes; + DWORD read; lpWaveHdr = wwi->lpQueuePtr; /* read all the fragments accumulated so far */ - frames = snd_pcm_avail_update(wwi->pcm); - bytes = snd_pcm_frames_to_bytes(wwi->pcm, frames); + frames = snd_pcm_avail_update(wwi->pcm); + bytes = snd_pcm_frames_to_bytes(wwi->pcm, frames); - TRACE("frames = %d bytes = %d\n", frames, bytes); - periods = bytes / wwi->dwPeriodSize; - while ((periods > 0) && (wwi->lpQueuePtr)) + TRACE("frames = %d bytes = %d state=%d\n", frames, bytes, snd_pcm_state(wwi->pcm)); + if (snd_pcm_state(wwi->pcm) == SND_PCM_STATE_XRUN) { - periods--; - bytes = wwi->dwPeriodSize; - TRACE("bytes = %d\n",bytes); - if (lpWaveHdr->dwBufferLength - lpWaveHdr->dwBytesRecorded >= wwi->dwPeriodSize) - { - /* directly read fragment in wavehdr */ - read = wwi->read(wwi->pcm, lpWaveHdr->lpData + lpWaveHdr->dwBytesRecorded, frames_per_period); - bytesRead = snd_pcm_frames_to_bytes(wwi->pcm, read); - - TRACE("bytesRead=%d (direct)\n", bytesRead); - if (read != (DWORD) -1) - { - /* update number of bytes recorded in current buffer and by this device */ - lpWaveHdr->dwBytesRecorded += bytesRead; - InterlockedExchangeAdd((LONG*)&wwi->dwTotalRecorded, bytesRead); - - /* buffer is full. notify client */ - if (lpWaveHdr->dwBytesRecorded == lpWaveHdr->dwBufferLength) - { - /* must copy the value of next waveHdr, because we have no idea of what - * will be done with the content of lpWaveHdr in callback - */ - LPWAVEHDR lpNext = lpWaveHdr->lpNext; - - lpWaveHdr->dwFlags &= ~WHDR_INQUEUE; - lpWaveHdr->dwFlags |= WHDR_DONE; - - wwi->lpQueuePtr = lpNext; - widNotifyClient(wwi, WIM_DATA, (DWORD)lpWaveHdr, 0); - lpWaveHdr = lpNext; - } - } else { - FIXME("read(%s, %p, %d) failed (%s)\n", wwi->pcmname, - lpWaveHdr->lpData + lpWaveHdr->dwBytesRecorded, - frames_per_period, snd_strerror(read)); - } - } - else - { - /* read the fragment in a local buffer */ - read = wwi->read(wwi->pcm, buffer, frames_per_period); - bytesRead = snd_pcm_frames_to_bytes(wwi->pcm, read); - pOffset = buffer; - - TRACE("bytesRead=%d (local)\n", bytesRead); - - if (read == (DWORD) -1) { - TRACE("read(%s, %p, %d) failed (%s)\n", wwi->pcmname, - buffer, frames_per_period, strerror(errno)); - continue; - } - - /* copy data in client buffers */ - while (read != (DWORD) -1 && bytesRead > 0) - { - DWORD dwToCopy = min (bytesRead, lpWaveHdr->dwBufferLength - lpWaveHdr->dwBytesRecorded); - - memcpy(lpWaveHdr->lpData + lpWaveHdr->dwBytesRecorded, - pOffset, - dwToCopy); - - /* update number of bytes recorded in current buffer and by this device */ - lpWaveHdr->dwBytesRecorded += dwToCopy; - InterlockedExchangeAdd((LONG*)&wwi->dwTotalRecorded, dwToCopy); - bytesRead -= dwToCopy; - pOffset += dwToCopy; - - /* client buffer is full. notify client */ - if (lpWaveHdr->dwBytesRecorded == lpWaveHdr->dwBufferLength) - { - /* must copy the value of next waveHdr, because we have no idea of what - * will be done with the content of lpWaveHdr in callback - */ - LPWAVEHDR lpNext = lpWaveHdr->lpNext; - TRACE("lpNext=%p\n", lpNext); - - lpWaveHdr->dwFlags &= ~WHDR_INQUEUE; - lpWaveHdr->dwFlags |= WHDR_DONE; - - wwi->lpQueuePtr = lpNext; - widNotifyClient(wwi, WIM_DATA, (DWORD)lpWaveHdr, 0); - - lpWaveHdr = lpNext; - if (!lpNext && bytesRead) { - /* before we give up, check for more header messages */ - while (ALSA_PeekRingMessage(&wwi->msgRing, &msg, ¶m, &ev)) - { - if (msg == WINE_WM_HEADER) { - LPWAVEHDR hdr; - ALSA_RetrieveRingMessage(&wwi->msgRing, &msg, ¶m, &ev); - hdr = ((LPWAVEHDR)param); - TRACE("msg = %s, hdr = %p, ev = %p\n", ALSA_getCmdString(msg), hdr, ev); - hdr->lpNext = 0; - if (lpWaveHdr == 0) { - /* new head of queue */ - wwi->lpQueuePtr = lpWaveHdr = hdr; - } else { - /* insert buffer at the end of queue */ - LPWAVEHDR* wh; - for (wh = &(wwi->lpQueuePtr); *wh; wh = &((*wh)->lpNext)); - *wh = hdr; - } - } else - break; - } - - if (lpWaveHdr == 0) { - /* no more buffer to copy data to, but we did read more. - * what hasn't been copied will be dropped - */ - WARN("buffer under run! %u bytes dropped.\n", bytesRead); - wwi->lpQueuePtr = NULL; - break; - } - } - } - } - } + FIXME("Recovering from XRUN!\n"); + snd_pcm_prepare(wwi->pcm); + frames = snd_pcm_avail_update(wwi->pcm); + bytes = snd_pcm_frames_to_bytes(wwi->pcm, frames); + snd_pcm_start(wwi->pcm); + snd_pcm_forward(wwi->pcm, frames - snd_pcm_bytes_to_frames(wwi->pcm, wwi->dwPeriodSize)); + continue; } - } + while (frames > 0 && wwi->lpQueuePtr) + { + TRACE("bytes = %d\n", bytes); + if (lpWaveHdr->dwBufferLength - lpWaveHdr->dwBytesRecorded < bytes) + { + bytes = lpWaveHdr->dwBufferLength - lpWaveHdr->dwBytesRecorded; + frames = snd_pcm_bytes_to_frames(wwi->pcm, bytes); + } + /* directly read fragment in wavehdr */ + read = wwi->read(wwi->pcm, lpWaveHdr->lpData + lpWaveHdr->dwBytesRecorded, frames); + bytesRead = snd_pcm_frames_to_bytes(wwi->pcm, read); + + TRACE("bytesRead=(%d(%d)/(%d)) -> (%d/%d) \n", bytesRead, read, frames, lpWaveHdr->dwBufferLength, lpWaveHdr->dwBufferLength - lpWaveHdr->dwBytesRecorded); + if (read != (DWORD) -1) + { + /* update number of bytes recorded in current buffer and by this device */ + lpWaveHdr->dwBytesRecorded += bytesRead; + InterlockedExchangeAdd((LONG*)&wwi->dwTotalRecorded, bytesRead); + frames -= read; + bytes -= bytesRead; + + /* buffer is full. notify client */ + if (!snd_pcm_bytes_to_frames(wwi->pcm, lpWaveHdr->dwBytesRecorded - lpWaveHdr->dwBufferLength)) + { + /* must copy the value of next waveHdr, because we have no idea of what + * will be done with the content of lpWaveHdr in callback + */ + LPWAVEHDR lpNext = lpWaveHdr->lpNext; + + lpWaveHdr->dwFlags &= ~WHDR_INQUEUE; + lpWaveHdr->dwFlags |= WHDR_DONE; + + wwi->lpQueuePtr = lpNext; + widNotifyClient(wwi, WIM_DATA, (DWORD)lpWaveHdr, 0); + lpWaveHdr = lpNext; + } + } else { + WARN("read(%s, %p, %d) failed (%d/%s)\n", wwi->pcmname, + lpWaveHdr->lpData + lpWaveHdr->dwBytesRecorded, + frames, frames, snd_strerror(read)); + } + } + } ALSA_WaitRingMessage(&wwi->msgRing, dwSleepTime); @@ -383,7 +310,6 @@ static DWORD CALLBACK widRecorder(LPVOID pmt) wwi->hThread = 0; wwi->state = WINE_WS_CLOSED; SetEvent(ev); - HeapFree(GetProcessHeap(), 0, buffer); ExitThread(0); /* shouldn't go here */ default: