summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJonathan Yong <10walls@gmail.com>2013-07-13 00:32:55 +0800
committerwm4 <wm4@nowhere>2013-07-12 20:01:23 +0200
commit27d352afbd2c0ca72c458799fd18a52b08d4652f (patch)
tree052bc4dd7108b93d964b8a3115f2b3dbbb792b1b
parent9dfc7daf79a855cb638baf99d3cb7e3833bf99a5 (diff)
downloadmpv-27d352afbd2c0ca72c458799fd18a52b08d4652f.tar.bz2
mpv-27d352afbd2c0ca72c458799fd18a52b08d4652f.tar.xz
ao_wasapi0: use new mp_ring buffer
-rw-r--r--audio/out/ao_wasapi0.c107
1 files changed, 25 insertions, 82 deletions
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 */