=?UTF-8?Q?J=C3=B6rg=20H=C3=B6hle=20?=: winealsa: Separate read and write pointers.
Alexandre Julliard
julliard at winehq.org
Tue Dec 18 13:49:06 CST 2012
Module: wine
Branch: master
Commit: 17f098869fec3f051e6c85d8716fb22cb7bc18e6
URL: http://source.winehq.org/git/wine.git/?a=commit;h=17f098869fec3f051e6c85d8716fb22cb7bc18e6
Author: Jörg Höhle <hoehle at users.sourceforge.net>
Date: Thu Mar 8 22:47:37 2012 +0100
winealsa: Separate read and write pointers.
---
dlls/winealsa.drv/mmdevdrv.c | 53 ++++++++++++++++++++++++++---------------
1 files changed, 33 insertions(+), 20 deletions(-)
diff --git a/dlls/winealsa.drv/mmdevdrv.c b/dlls/winealsa.drv/mmdevdrv.c
index e903b9e..3e8ad8d 100644
--- a/dlls/winealsa.drv/mmdevdrv.c
+++ b/dlls/winealsa.drv/mmdevdrv.c
@@ -118,6 +118,7 @@ struct ACImpl {
UINT32 bufsize_frames, held_frames, tmp_buffer_frames, mmdev_period_frames;
snd_pcm_uframes_t remapping_buf_frames;
UINT32 lcl_offs_frames; /* offs into local_buffer where valid data starts */
+ UINT32 wri_offs_frames; /* where to write fresh data in local_buffer */
UINT32 hidden_frames; /* ALSA reserve to ensure continuous rendering */
HANDLE timer;
@@ -1960,13 +1961,28 @@ static snd_pcm_sframes_t alsa_write_best_effort(snd_pcm_t *handle, BYTE *buf,
return written;
}
+/* The callback and mmdevapi API functions execute concurrently.
+ * Shared state & life time after Start:
+ * This constant until _Release
+ *->pcm_handle likewise
+ *->fmt likewise
+ *->alsa_format, hidden_frames likewise
+ *->local_buffer, bufsize_frames, alsa_bufsize_frames likewise
+ *->event Read Only, even constant until _Release(!)
+ *->started Read Only from cb POV, constant if _Stop kills the cb
+ *
+ *->held_frames is the only R/W object.
+ *->lcl_offs_frames/wri_offs_frames are written by one side exclusively:
+ * lcl_offs_frames by CaptureClient & write callback
+ * wri_offs_frames by read callback & RenderClient
+ */
static void alsa_write_data(ACImpl *This)
{
snd_pcm_sframes_t written, in_alsa;
snd_pcm_uframes_t to_write, avail, write_limit, max_period;
int err;
BYTE *buf =
- This->local_buffer + (This->lcl_offs_frames * This->fmt->nBlockAlign);
+ This->local_buffer + This->lcl_offs_frames * This->fmt->nBlockAlign;
/* this call seems to be required to get an accurate snd_pcm_state() */
avail = snd_pcm_avail_update(This->pcm_handle);
@@ -2064,14 +2080,16 @@ static void alsa_write_data(ACImpl *This)
static void alsa_read_data(ACImpl *This)
{
- snd_pcm_sframes_t pos, readable, nread;
+ snd_pcm_sframes_t nread;
+ UINT32 pos = This->wri_offs_frames, limit = This->held_frames;
- pos = (This->held_frames + This->lcl_offs_frames) % This->bufsize_frames;
- readable = This->bufsize_frames - pos;
+ /* FIXME: Detect overrun and signal DATA_DISCONTINUITY
+ * How to count overrun frames and report them as position increase? */
+ limit = This->bufsize_frames - max(limit, pos);
nread = snd_pcm_readi(This->pcm_handle,
- This->local_buffer + pos * This->fmt->nBlockAlign, readable);
- TRACE("read %ld from %u limit %lu\n", nread, This->held_frames + This->lcl_offs_frames, readable);
+ This->local_buffer + pos * This->fmt->nBlockAlign, limit);
+ TRACE("read %ld from %u limit %u\n", nread, pos, limit);
if(nread < 0){
int ret;
@@ -2087,7 +2105,7 @@ static void alsa_read_data(ACImpl *This)
}
nread = snd_pcm_readi(This->pcm_handle,
- This->local_buffer + pos * This->fmt->nBlockAlign, readable);
+ This->local_buffer + pos * This->fmt->nBlockAlign, limit);
if(nread < 0){
WARN("read failed: %ld (%s)\n", nread, snd_strerror(nread));
return;
@@ -2103,14 +2121,9 @@ static void alsa_read_data(ACImpl *This)
snd_strerror(err));
}
+ This->wri_offs_frames += nread;
+ This->wri_offs_frames %= This->bufsize_frames;
This->held_frames += nread;
-
- if(This->held_frames > This->bufsize_frames){
- WARN("Overflow of unread data\n");
- This->lcl_offs_frames += This->held_frames;
- This->lcl_offs_frames %= This->bufsize_frames;
- This->held_frames = This->bufsize_frames;
- }
}
static void CALLBACK alsa_push_buffer_data(void *user, BOOLEAN timer)
@@ -2256,6 +2269,7 @@ static HRESULT WINAPI AudioClient_Reset(IAudioClient *iface)
}
This->held_frames = 0;
This->lcl_offs_frames = 0;
+ This->wri_offs_frames = 0;
LeaveCriticalSection(&This->lock);
@@ -2463,8 +2477,7 @@ static HRESULT WINAPI AudioRenderClient_GetBuffer(IAudioRenderClient *iface,
return AUDCLNT_E_BUFFER_TOO_LARGE;
}
- write_pos =
- (This->lcl_offs_frames + This->held_frames) % This->bufsize_frames;
+ write_pos = This->wri_offs_frames;
if(write_pos + frames > This->bufsize_frames){
if(This->tmp_buffer_frames < frames){
HeapFree(GetProcessHeap(), 0, This->tmp_buffer);
@@ -2490,8 +2503,7 @@ static HRESULT WINAPI AudioRenderClient_GetBuffer(IAudioRenderClient *iface,
static void alsa_wrap_buffer(ACImpl *This, BYTE *buffer, UINT32 written_frames)
{
- snd_pcm_uframes_t write_offs_frames =
- (This->lcl_offs_frames + This->held_frames) % This->bufsize_frames;
+ snd_pcm_uframes_t write_offs_frames = This->wri_offs_frames;
UINT32 write_offs_bytes = write_offs_frames * This->fmt->nBlockAlign;
snd_pcm_uframes_t chunk_frames = This->bufsize_frames - write_offs_frames;
UINT32 chunk_bytes = chunk_frames * This->fmt->nBlockAlign;
@@ -2533,8 +2545,7 @@ static HRESULT WINAPI AudioRenderClient_ReleaseBuffer(
}
if(This->getbuf_last >= 0)
- buffer = This->local_buffer + This->fmt->nBlockAlign *
- ((This->lcl_offs_frames + This->held_frames) % This->bufsize_frames);
+ buffer = This->local_buffer + This->wri_offs_frames * This->fmt->nBlockAlign;
else
buffer = This->tmp_buffer;
@@ -2548,6 +2559,8 @@ static HRESULT WINAPI AudioRenderClient_ReleaseBuffer(
if(This->getbuf_last < 0)
alsa_wrap_buffer(This, buffer, written_frames);
+ This->wri_offs_frames += written_frames;
+ This->wri_offs_frames %= This->bufsize_frames;
This->held_frames += written_frames;
This->written_frames += written_frames;
This->getbuf_last = 0;
More information about the wine-cvs
mailing list