aboutsummaryrefslogtreecommitdiffhomepage
path: root/src
diff options
context:
space:
mode:
authorMatthew Gregan <[email protected]>2012-03-16 17:08:11 +1300
committerMatthew Gregan <[email protected]>2012-03-16 17:08:11 +1300
commitbe256d2a159d2286e78f08f55929646f097629d1 (patch)
treec55748643e85c2faf1694fa4b82dbc00959fafd1 /src
parent39e511c1f19e8c6dfbdbfd5d9fb4ed9706f578d4 (diff)
downloadcubeb-be256d2a159d2286e78f08f55929646f097629d1.tar.gz
cubeb-be256d2a159d2286e78f08f55929646f097629d1.zip
winmm: refactor buffer management code.
Diffstat (limited to 'src')
-rw-r--r--src/cubeb_winmm.c92
1 files changed, 50 insertions, 42 deletions
diff --git a/src/cubeb_winmm.c b/src/cubeb_winmm.c
index 0251a2d..d119f6f 100644
--- a/src/cubeb_winmm.c
+++ b/src/cubeb_winmm.c
@@ -69,7 +69,7 @@ cubeb_get_next_buffer(cubeb_stream * stm)
assert(stm->free_buffers > 0 && stm->free_buffers <= NBUFS);
hdr = &stm->buffers[stm->next_buffer];
- assert(hdr->dwFlags == 0 ||
+ assert(hdr->dwFlags & WHDR_PREPARED ||
(hdr->dwFlags & WHDR_DONE && !(hdr->dwFlags & WHDR_INQUEUE)));
stm->next_buffer = (stm->next_buffer + 1) % NBUFS;
stm->free_buffers -= 1;
@@ -78,22 +78,47 @@ cubeb_get_next_buffer(cubeb_stream * stm)
}
static void
-cubeb_submit_buffer(cubeb_stream * stm, WAVEHDR * hdr)
+cubeb_refill_stream(cubeb_stream * stm)
{
+ WAVEHDR * hdr;
long got;
+ long wanted;
MMRESULT r;
+ EnterCriticalSection(&stm->lock);
+ stm->free_buffers += 1;
+ assert(stm->free_buffers > 0 && stm->free_buffers <= NBUFS);
+
+ if (stm->draining) {
+ LeaveCriticalSection(&stm->lock);
+ if (stm->free_buffers == NBUFS) {
+ stm->state_callback(stm, stm->user_ptr, CUBEB_STATE_DRAINED);
+ }
+ SetEvent(stm->event);
+ return;
+ }
+
+ if (stm->shutdown) {
+ LeaveCriticalSection(&stm->lock);
+ SetEvent(stm->event);
+ return;
+ }
+
+ hdr = cubeb_get_next_buffer(stm);
+
+ wanted = (DWORD) hdr->dwBufferLength / bytes_per_frame(stm->params);
+
/* It is assumed that the caller is holding this lock. It must be dropped
during the callback to avoid deadlocks. */
LeaveCriticalSection(&stm->lock);
- got = stm->data_callback(stm, stm->user_ptr, hdr->lpData,
- hdr->dwBufferLength / bytes_per_frame(stm->params));
+ got = stm->data_callback(stm, stm->user_ptr, hdr->lpData, wanted);
EnterCriticalSection(&stm->lock);
if (got < 0) {
/* XXX handle this case */
assert(0);
return;
- } else if ((DWORD) got < hdr->dwBufferLength / bytes_per_frame(stm->params)) {
+ } else if (got < wanted) {
+ /* Buffer smaller than expected, reprepare it before submission. */
r = waveOutUnprepareHeader(stm->waveout, hdr, sizeof(*hdr));
assert(r == MMSYSERR_NOERROR);
@@ -109,6 +134,8 @@ cubeb_submit_buffer(cubeb_stream * stm, WAVEHDR * hdr)
r = waveOutWrite(stm->waveout, hdr, sizeof(*hdr));
assert(r == MMSYSERR_NOERROR);
+
+ LeaveCriticalSection(&stm->lock);
}
static unsigned __stdcall
@@ -126,28 +153,8 @@ cubeb_buffer_thread(void * user_ptr)
item = (struct cubeb_stream_item *) InterlockedPopEntrySList(ctx->work);
while (item) {
- cubeb_stream * stm = item->stream;
-
- EnterCriticalSection(&stm->lock);
- stm->free_buffers += 1;
- assert(stm->free_buffers > 0 && stm->free_buffers <= NBUFS);
-
- if (stm->draining || stm->shutdown) {
- if (stm->free_buffers == NBUFS) {
- if (stm->draining) {
- LeaveCriticalSection(&stm->lock);
- stm->state_callback(stm, stm->user_ptr, CUBEB_STATE_DRAINED);
- EnterCriticalSection(&stm->lock);
- }
- SetEvent(stm->event);
- }
- } else {
- cubeb_submit_buffer(stm, cubeb_get_next_buffer(stm));
- }
- LeaveCriticalSection(&stm->lock);
-
+ cubeb_refill_stream(item->stream);
_aligned_free(item);
-
item = (struct cubeb_stream_item *) InterlockedPopEntrySList(ctx->work);
}
@@ -310,13 +317,6 @@ cubeb_stream_init(cubeb * context, cubeb_stream ** stream, char const * stream_n
}
assert(bufsz % bytes_per_frame(stm->params) == 0);
- for (i = 0; i < NBUFS; ++i) {
- stm->buffers[i].lpData = calloc(1, bufsz);
- assert(stm->buffers[i].lpData);
- stm->buffers[i].dwBufferLength = bufsz;
- stm->buffers[i].dwFlags = 0;
- }
-
InitializeCriticalSection(&stm->lock);
stm->event = CreateEvent(NULL, FALSE, FALSE, NULL);
@@ -325,8 +325,6 @@ cubeb_stream_init(cubeb * context, cubeb_stream ** stream, char const * stream_n
return CUBEB_ERROR;
}
- stm->free_buffers = NBUFS;
-
/* cubeb_buffer_callback will be called during waveOutOpen, so all
other initialization must be complete before calling it. */
r = waveOutOpen(&stm->waveout, WAVE_MAPPER, &wfx.Format,
@@ -341,17 +339,19 @@ cubeb_stream_init(cubeb * context, cubeb_stream ** stream, char const * stream_n
r = waveOutPause(stm->waveout);
assert(r == MMSYSERR_NOERROR);
- /* cubeb_submit_buffer assumes the stream lock is held. */
- EnterCriticalSection(&stm->lock);
for (i = 0; i < NBUFS; ++i) {
- WAVEHDR * hdr = cubeb_get_next_buffer(stm);
+ WAVEHDR * hdr = &stm->buffers[i];
+
+ hdr->lpData = calloc(1, bufsz);
+ assert(hdr->lpData);
+ hdr->dwBufferLength = bufsz;
+ hdr->dwFlags = 0;
r = waveOutPrepareHeader(stm->waveout, hdr, sizeof(*hdr));
assert(r == MMSYSERR_NOERROR);
- cubeb_submit_buffer(stm, hdr);
+ cubeb_refill_stream(stm);
}
- LeaveCriticalSection(&stm->lock);
*stream = stm;
@@ -376,12 +376,18 @@ cubeb_stream_destroy(cubeb_stream * stm)
enqueued = NBUFS - stm->free_buffers;
LeaveCriticalSection(&stm->lock);
- /* wait for all blocks to complete */
- if (enqueued > 0) {
+ /* Wait for all blocks to complete. */
+ while (enqueued > 0) {
rv = WaitForSingleObject(stm->event, INFINITE);
assert(rv == WAIT_OBJECT_0);
+
+ EnterCriticalSection(&stm->lock);
+ enqueued = NBUFS - stm->free_buffers;
+ LeaveCriticalSection(&stm->lock);
}
+ EnterCriticalSection(&stm->lock);
+
for (i = 0; i < NBUFS; ++i) {
r = waveOutUnprepareHeader(stm->waveout, &stm->buffers[i], sizeof(stm->buffers[i]));
assert(r == MMSYSERR_NOERROR);
@@ -389,6 +395,8 @@ cubeb_stream_destroy(cubeb_stream * stm)
r = waveOutClose(stm->waveout);
assert(r == MMSYSERR_NOERROR);
+
+ LeaveCriticalSection(&stm->lock);
}
if (stm->event) {