aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/cubeb_winmm.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/cubeb_winmm.c')
-rw-r--r--src/cubeb_winmm.c116
1 files changed, 67 insertions, 49 deletions
diff --git a/src/cubeb_winmm.c b/src/cubeb_winmm.c
index abc272c..ef7f2bb 100644
--- a/src/cubeb_winmm.c
+++ b/src/cubeb_winmm.c
@@ -17,14 +17,20 @@
#define NBUFS 4
+struct cubeb_stream_item {
+ SLIST_ENTRY head;
+ cubeb_stream * stream;
+};
+
struct cubeb {
HANDLE event;
HANDLE thread;
- unsigned int thread_id;
int shutdown;
+ PSLIST_HEADER work;
};
struct cubeb_stream {
+ cubeb * context;
cubeb_stream_params params;
cubeb_data_callback data_callback;
cubeb_state_callback state_callback;
@@ -109,55 +115,40 @@ cubeb_buffer_thread(void * user_ptr)
cubeb * ctx = (cubeb *) user_ptr;
assert(ctx);
- /* force creation of thread's message queue. */
- PeekMessage(NULL, NULL, 0, 0, PM_NOREMOVE);
- SetEvent(ctx->event);
-
for (;;) {
DWORD rv;
+ struct cubeb_stream_item * item;
+
+ rv = WaitForSingleObject(ctx->event, INFINITE);
+ assert(rv == WAIT_OBJECT_0);
+
+ 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);
- rv = MsgWaitForMultipleObjects(1, &ctx->event, FALSE, INFINITE, QS_ALLEVENTS);
- assert(rv == WAIT_OBJECT_0 || rv == WAIT_OBJECT_0 + 1);
-
- if (rv == WAIT_OBJECT_0 + 1) {
- MSG msg;
- BOOL ok = PeekMessage(&msg, NULL, 0, 0, PM_REMOVE);
- assert(ok);
- switch (msg.message) {
- case MM_WOM_OPEN:
- fprintf(stderr, "stream open\n");
- break;
- case MM_WOM_CLOSE:
- fprintf(stderr, "stream close\n");
- break;
- case MM_WOM_DONE: {
- cubeb_stream * stm = (cubeb_stream *)((WAVEHDR *) msg.lParam)->dwUser;
- fprintf(stderr, "stream buffer done\n");
-
- 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) {
- stm->state_callback(stm, stm->user_ptr, CUBEB_STATE_DRAINED);
- }
- SetEvent(stm->event);
+ if (stm->draining || stm->shutdown) {
+ if (stm->free_buffers == NBUFS) {
+ if (stm->draining) {
+ stm->state_callback(stm, stm->user_ptr, CUBEB_STATE_DRAINED);
}
- } else {
- cubeb_submit_buffer(stm, cubeb_get_next_buffer(stm));
+ SetEvent(stm->event);
}
- LeaveCriticalSection(&stm->lock);
-
- break;
- }
- default:
- fprintf(stderr, "weird message: %u\n", msg.message);
- assert(0);
+ } else {
+ cubeb_submit_buffer(stm, cubeb_get_next_buffer(stm));
}
+ LeaveCriticalSection(&stm->lock);
+
+ _aligned_free(item);
+
+ item = (struct cubeb_stream_item *) InterlockedPopEntrySList(ctx->work);
}
+ assert(!InterlockedPopEntrySList(ctx->work));
+
if (ctx->shutdown) {
break;
}
@@ -166,6 +157,24 @@ cubeb_buffer_thread(void * user_ptr)
return 0;
}
+static void CALLBACK
+cubeb_buffer_callback(HWAVEOUT waveout, UINT msg, DWORD_PTR user_ptr, DWORD_PTR p1, DWORD_PTR p2)
+{
+ cubeb_stream * stm = (cubeb_stream *) user_ptr;
+ struct cubeb_stream_item * item;
+
+ if (msg != WOM_DONE) {
+ return;
+ }
+
+ item = _aligned_malloc(sizeof(struct cubeb_stream_item), MEMORY_ALLOCATION_ALIGNMENT);
+ assert(item);
+ item->stream = stm;
+ InterlockedPushEntrySList(stm->context->work, &item->head);
+
+ SetEvent(stm->context->event);
+}
+
int
cubeb_init(cubeb ** context, char const * context_name)
{
@@ -174,13 +183,17 @@ cubeb_init(cubeb ** context, char const * context_name)
ctx = calloc(1, sizeof(*ctx));
assert(ctx);
+ ctx->work = _aligned_malloc(sizeof(*ctx->work), MEMORY_ALLOCATION_ALIGNMENT);
+ assert(ctx->work);
+ InitializeSListHead(ctx->work);
+
ctx->event = CreateEvent(NULL, FALSE, FALSE, NULL);
if (!ctx->event) {
cubeb_destroy(ctx);
return CUBEB_ERROR;
}
- ctx->thread = (HANDLE) _beginthreadex(NULL, 64 * 1024, cubeb_buffer_thread, ctx, 0, &ctx->thread_id);
+ ctx->thread = (HANDLE) _beginthreadex(NULL, 64 * 1024, cubeb_buffer_thread, ctx, 0, NULL);
if (!ctx->thread) {
cubeb_destroy(ctx);
return CUBEB_ERROR;
@@ -188,9 +201,6 @@ cubeb_init(cubeb ** context, char const * context_name)
SetThreadPriority(ctx->thread, THREAD_PRIORITY_TIME_CRITICAL);
- /* wait for thread to start; need thread message queue created before creating a stream. */
- WaitForSingleObject(ctx->event, INFINITE);
-
*context = ctx;
return CUBEB_OK;
@@ -201,6 +211,8 @@ cubeb_destroy(cubeb * ctx)
{
DWORD rv;
+ assert(!InterlockedPopEntrySList(ctx->work));
+
if (ctx->thread) {
ctx->shutdown = 1;
SetEvent(ctx->event);
@@ -213,11 +225,13 @@ cubeb_destroy(cubeb * ctx)
CloseHandle(ctx->event);
}
+ _aligned_free(ctx->work);
+
free(ctx);
}
int
-cubeb_stream_init(cubeb * ctx, cubeb_stream ** stream, char const * stream_name,
+cubeb_stream_init(cubeb * context, cubeb_stream ** stream, char const * stream_name,
cubeb_stream_params stream_params, unsigned int latency,
cubeb_data_callback data_callback,
cubeb_state_callback state_callback,
@@ -268,6 +282,8 @@ cubeb_stream_init(cubeb * ctx, cubeb_stream ** stream, char const * stream_name,
stm = calloc(1, sizeof(*stm));
assert(stm);
+ stm->context = context;
+
stm->params = stream_params;
stm->data_callback = data_callback;
@@ -285,7 +301,6 @@ cubeb_stream_init(cubeb * ctx, cubeb_stream ** stream, char const * stream_name,
assert(stm->buffers[i].lpData);
stm->buffers[i].dwBufferLength = bufsz;
stm->buffers[i].dwFlags = 0;
- stm->buffers[i].dwUser = (DWORD_PTR) stm;
}
InitializeCriticalSection(&stm->lock);
@@ -298,8 +313,11 @@ cubeb_stream_init(cubeb * ctx, cubeb_stream ** stream, char const * stream_name,
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,
- (DWORD_PTR) NULL, (DWORD_PTR) ctx->thread_id, CALLBACK_THREAD);
+ (DWORD_PTR) cubeb_buffer_callback, (DWORD_PTR) stm,
+ CALLBACK_FUNCTION);
if (r != MMSYSERR_NOERROR) {
cubeb_stream_destroy(stm);
return CUBEB_ERROR;