From 27d352afbd2c0ca72c458799fd18a52b08d4652f Mon Sep 17 00:00:00 2001 From: Jonathan Yong <10walls@gmail.com> Date: Sat, 13 Jul 2013 00:32:55 +0800 Subject: ao_wasapi0: use new mp_ring buffer --- audio/out/ao_wasapi0.c | 107 ++++++++++++------------------------------------- 1 file changed, 25 insertions(+), 82 deletions(-) (limited to 'audio') diff --git a/audio/out/ao_wasapi0.c b/audio/out/ao_wasapi0.c index 8d0fe27801..a45ca829e5 100644 --- a/audio/out/ao_wasapi0.c +++ b/audio/out/ao_wasapi0.c @@ -30,6 +30,7 @@ #include "core/subopt-helper.h" #include "audio/format.h" #include "core/mp_msg.h" +#include "core/mp_ring.h" #include "ao.h" #define RING_BUFFER_COUNT 64 @@ -75,17 +76,13 @@ typedef struct wasapi0_state { CRITICAL_SECTION print_lock; /* Buffers */ - CRITICAL_SECTION buffer_lock; + struct mp_ring *ringbuff; size_t buffer_block_size; /* Size of each block in bytes */ - LONG read_block_ptr, write_block_ptr; /*Which block are we in?*/ - LONG write_ahead_count; /* how many blocks writer is ahead of reader? should be less than RING_BUFFER_COUNT*/ - uintptr_t write_offset; /*offset while writing partial blocks, used only in main thread */ REFERENCE_TIME minRequestedDuration; /* minimum wasapi buffer block size, in 100-nanosecond units */ REFERENCE_TIME defaultRequestedDuration; /* default wasapi default block size, in 100-nanosecond units */ UINT32 bufferFrameCount; /* wasapi buffer block size, number of frames, frame size at format.nBlockAlign */ - void *ring_buffer[RING_BUFFER_COUNT]; /* each bufferFrameCount sized, owned by main thread */ /* WASAPI handles, owned by other thread */ IMMDeviceEnumerator *pEnumerator; @@ -317,7 +314,6 @@ static int fix_format(struct wasapi0_state *state) /* cargo cult code to negotiate buffer block size, affected by hardware/drivers combinations, gradually grow it to 10s, by 0.5s, consider failure if it still doesn't work */ - EnterCriticalSection(&state->buffer_lock); hr = IAudioClient_GetDevicePeriod(state->pAudioClient, &state->defaultRequestedDuration, &state->minRequestedDuration); @@ -365,7 +361,6 @@ reinit: EXIT_ON_ERROR(hr) state->buffer_block_size = state->format.Format.nBlockAlign * state->bufferFrameCount; - LeaveCriticalSection(&state->buffer_lock); state->hTask = state->VistaBlob.pAvSetMmThreadCharacteristicsW(L"Pro Audio", &state->taskIndex); EnterCriticalSection(&state->print_lock); @@ -380,7 +375,6 @@ exit_label: "ao-wasapi: fix_format fails with %s, failed to determine buffer block size!\n", explain_err(hr)); LeaveCriticalSection(&state->print_lock); - LeaveCriticalSection(&state->buffer_lock); SetEvent(state->fatal_error); return 1; } @@ -440,22 +434,23 @@ static void thread_reset(wasapi0_state *state) IAudioClient_Reset(state->pAudioClient); } -static void thread_feed(wasapi0_state *state) +/* force_feed - feed in even if available data is smaller than required buffer, to clear the buffer */ +static void thread_feed(wasapi0_state *state,int force_feed) { BYTE *pData; + int buffer_size; HRESULT hr = IAudioRenderClient_GetBuffer(state->pRenderClient, state->bufferFrameCount, &pData); EXIT_ON_ERROR(hr) - EnterCriticalSection(&state->buffer_lock); - if (state->write_ahead_count > 0) { /* OK to copy! */ - memcpy(pData, state->ring_buffer[state->read_block_ptr], - state->buffer_block_size); - state->read_block_ptr++; - state->read_block_ptr = state->read_block_ptr % RING_BUFFER_COUNT; - state->write_ahead_count--; - LeaveCriticalSection(&state->buffer_lock); + buffer_size = mp_ring_buffered(state->ringbuff); + if( buffer_size > state->buffer_block_size) { /* OK to copy! */ + mp_ring_read(state->ringbuff, (unsigned char *)pData, + state->buffer_block_size); + } else if(force_feed) { + /* should be smaller than buffer block size by now */ + memset(pData,0,state->buffer_block_size); + mp_ring_read(state->ringbuff, (unsigned char *)pData, buffer_size); } else { - LeaveCriticalSection(&state->buffer_lock); /* buffer underrun?! abort */ hr = IAudioRenderClient_ReleaseBuffer(state->pRenderClient, state->bufferFrameCount, @@ -475,7 +470,7 @@ exit_label: static void thread_play(wasapi0_state *state) { - thread_feed(state); + thread_feed(state, 0); IAudioClient_Start(state->pAudioClient); return; } @@ -499,11 +494,10 @@ static void thread_uninit(wasapi0_state *state) if (!state->immed) { /* feed until empty */ while (1) { - EnterCriticalSection(&state->buffer_lock); - LONG ahead = state->write_ahead_count; - LeaveCriticalSection(&state->buffer_lock); - if (WaitForSingleObject(state->hFeed, 2000) == WAIT_OBJECT_0 && ahead) { - thread_feed(state); + if (WaitForSingleObject(state->hFeed,2000) == WAIT_OBJECT_0 && + mp_ring_buffered(state->ringbuff)) + { + thread_feed(state, 1); } else break; } @@ -568,7 +562,7 @@ static unsigned int __stdcall ThreadLoop(void *lpParameter) break; case (WAIT_OBJECT_0 + 6): /* feed */ feedwatch = 1; - thread_feed(state); + thread_feed(state, 0); break; case WAIT_TIMEOUT: /* Did our feed die? */ if (feedwatch) @@ -608,48 +602,22 @@ static void closehandles(struct ao *ao) static int get_space(struct ao *ao) { - int ret = 0; if (!ao || !ao->priv) return -1; struct wasapi0_state *state = (struct wasapi0_state *)ao->priv; - EnterCriticalSection(&state->buffer_lock); - LONG ahead = state->write_ahead_count; - size_t block_size = state->buffer_block_size; - LeaveCriticalSection(&state->buffer_lock); - ret = (RING_BUFFER_COUNT - ahead) * block_size; /* rough */ - return ret - (block_size - state->write_offset); /* take offset into account */ + return mp_ring_available(state->ringbuff); } static void reset_buffers(struct wasapi0_state *state) { - EnterCriticalSection(&state->buffer_lock); - state->read_block_ptr = state->write_block_ptr = 0; - state->write_ahead_count = 0; - state->write_offset = 0; - LeaveCriticalSection(&state->buffer_lock); -} - -static void free_buffers(struct wasapi0_state *state) -{ - int iter; - for (iter = 0; iter < RING_BUFFER_COUNT; iter++) { - free(state->ring_buffer[iter]); - state->ring_buffer[iter] = NULL; - } + mp_ring_reset(state->ringbuff); } static int setup_buffers(struct wasapi0_state *state) { - int iter; - reset_buffers(state); - for (iter = 0; iter < RING_BUFFER_COUNT; iter++) { - state->ring_buffer[iter] = malloc(state->buffer_block_size); - if (!state->ring_buffer[iter]) { - free_buffers(state); - return 1; /* failed */ - } - } - return 0; + state->ringbuff = + mp_ring_new(state, RING_BUFFER_COUNT * state->buffer_block_size); + return !state->ringbuff; } static void uninit(struct ao *ao, bool immed) @@ -663,9 +631,7 @@ static void uninit(struct ao *ao, bool immed) SetEvent(state->fatal_error); if (state->VistaBlob.hAvrt) FreeLibrary(state->VistaBlob.hAvrt); - free_buffers(state); closehandles(ao); - DeleteCriticalSection(&state->buffer_lock); DeleteCriticalSection(&state->print_lock); talloc_free(state); ao->priv = NULL; @@ -694,7 +660,6 @@ static int init(struct ao *ao, char *params) state->hUninit = CreateEventW(NULL, FALSE, FALSE, NULL); state->fatal_error = CreateEventW(NULL, TRUE, FALSE, NULL); state->hFeed = CreateEvent(NULL, FALSE, FALSE, NULL); /* for wasapi event mode */ - InitializeCriticalSection(&state->buffer_lock); InitializeCriticalSection(&state->print_lock); if (!state->init_done || !state->fatal_error || !state->hPlay || !state->hPause || !state->hFeed || !state->hReset || !state->hGetvol || @@ -772,7 +737,6 @@ static void reset(struct ao *ao) static int play(struct ao *ao, void *data, int len, int flags) { int ret = 0; - unsigned char *dat = data; if (!ao || !ao->priv) return ret; struct wasapi0_state *state = (struct wasapi0_state *)ao->priv; @@ -781,28 +745,7 @@ static int play(struct ao *ao, void *data, int len, int flags) return ret; } - /* round to nearest block size? */ - EnterCriticalSection(&state->buffer_lock); - /* make sure write ahead does not bust buffer count */ - while ((RING_BUFFER_COUNT - 1) > state->write_ahead_count) { - /* data left is larger than block size, do block by block copy */ - if ((len - ret) > state->buffer_block_size) { - memcpy(state->ring_buffer[state->write_block_ptr], &dat[ret], - state->buffer_block_size); - } else if (flags & AOPLAY_FINAL_CHUNK) { - /* zero out and fill with whatever that is left, but only if it is final block */ - memset(state->ring_buffer[state->write_block_ptr], 0, - state->buffer_block_size); - memcpy(state->ring_buffer[state->write_block_ptr], &dat[ret], - (len - ret)); - } else - break; /* otherwise leave buffers outside of block alignment and let player figure it out */ - state->write_block_ptr++; - state->write_block_ptr %= RING_BUFFER_COUNT; - state->write_ahead_count++; - ret += state->buffer_block_size; - } - LeaveCriticalSection(&state->buffer_lock); + ret = mp_ring_write(state->ringbuff, data, len); if (!state->is_playing) { /* start playing */ -- cgit v1.2.3