The sad state of audio GetPosition

Joerg-Cyril.Hoehle at t-systems.com Joerg-Cyril.Hoehle at t-systems.com
Fri Aug 19 06:30:09 CDT 2011


Reece,

I wrote the text in a hurry and forgot that Wine results
are most interesting to me with my patch applied.

Please use my patch with something like:
WINETEST_DEBUG=3 WINEDEBUG=warn+alsa wine mmdevapi_test.exe render

>render.c:897: Test failed: Position 24000 too far after 200ms
That's not PA's fault.  IMHO AudioClient_Stop must not map
to snd_pcm_drop.  It is more like snd_pcm_pause. Or perhaps
simply lead ALSA into an underrun.  I've not made up my mind
yet as the models (mmdevapi vs. ALSA) are different w.r.t. buffering.


As you can see, the patch is nowhere final.

#From 60689763bd21513bd9b8dbd2df3abc5f2586f1f2 Mon Sep 17 00:00:00 2001
#From: =?UTF-8?q?J=C3=B6rg=20H=C3=B6hle?= <hoehle at users.sourceforge.net>
Date: Wed, 17 Aug 2011 21:04:34 +0200
Subject: winealsa: Play with GetPosition.

---
 dlls/winealsa.drv/mmdevdrv.c |   52 ++++++++++++++++++++++++++++++++++-------
 1 files changed, 43 insertions(+), 9 deletions(-)

diff --git a/dlls/winealsa.drv/mmdevdrv.c b/dlls/winealsa.drv/mmdevdrv.c
index 3e3edc3..51e9b81 100644
--- a/dlls/winealsa.drv/mmdevdrv.c
+++ b/dlls/winealsa.drv/mmdevdrv.c
@@ -2289,26 +2289,60 @@ static HRESULT WINAPI AudioClock_GetPosition(IAudioClock *iface, UINT64 *pos,
         UINT64 *qpctime)
 {
     ACImpl *This = impl_from_IAudioClock(iface);
-    UINT32 pad;
-    HRESULT hr;
+    int err;
+    snd_pcm_uframes_t avail_frames;
+    snd_pcm_sframes_t delay_frames, pad_frames;
+    snd_pcm_status_t *status;
 
     TRACE("(%p)->(%p, %p)\n", This, pos, qpctime);
 
     if(!pos)
         return E_POINTER;
+    snd_pcm_status_alloca(&status);
 
     EnterCriticalSection(&This->lock);
 
-    hr = IAudioClient_GetCurrentPadding(&This->IAudioClient_iface, &pad);
-    if(FAILED(hr)){
+    if(!This->initted){
         LeaveCriticalSection(&This->lock);
-        return hr;
+        return AUDCLNT_E_NOT_INITIALIZED;
     }
 
-    if(This->dataflow == eRender)
-        *pos = This->written_frames - pad;
-    else if(This->dataflow == eCapture)
-        *pos = This->written_frames + pad;
+    if((err = snd_pcm_status(This->pcm_handle, status)) < 0){
+        LeaveCriticalSection(&This->lock);
+        ERR("ALSA status error: %d (%s)\n",
+            err, snd_strerror(err));
+        return E_FAIL;
+    }
+    if(0){
+    avail_frames = snd_pcm_status_get_avail(status);
+    delay_frames = snd_pcm_status_get_delay(status);
+    }else{
+    avail_frames = snd_pcm_avail_update(This->pcm_handle);
+    err = snd_pcm_delay(This->pcm_handle, &delay_frames);
+    if(err < 0){ /* e.g. in STATE_PREPARED */
+        ERR("ALSA delay error: %d (%s)\n",
+            err, snd_strerror(err));
+        delay_frames = 0;
+    }
+    }
+    pad_frames = This->bufsize_alsa - avail_frames;
+#define MAX_LATE_SECONDS 5  /* huge USB or network latency */
+    if(avail_frames <= This->bufsize_alsa + MAX_LATE_SECONDS * This->fmt->nSamplesPerSec
+       && delay_frames > 0)
+        *pos = This->written_frames - This->held_frames - delay_frames;
+    else if(pad_frames > 0)
+        /* delay may be slightly < 0 past reset */
+        *pos = This->written_frames - This->held_frames - pad_frames;
+    else
+        *pos = This->written_frames - This->held_frames;
+    /* FIXME: if(This->dataflow == eCapture) */
+
+    ERR("avail %lu, delay %ld, sum %ld, alsa %lu, written %lu, held %u: %lu\n",
+        avail_frames, delay_frames, avail_frames+delay_frames, This->bufsize_alsa, (ulong)This->written_frames, This->held_frames, (ulong)*pos);
+    avail_frames = snd_pcm_avail_update(This->pcm_handle);
+    err = snd_pcm_delay(This->pcm_handle, &delay_frames);
+    ERR("avail %lu, delay %ld, sum %ld, alsa %lu, written %lu, held %u: %lu\n",
+        avail_frames, delay_frames, avail_frames+delay_frames, This->bufsize_alsa, (ulong)This->written_frames, This->held_frames, (ulong)*pos);
 
     LeaveCriticalSection(&This->lock);
 
-- 
1.7.0.4




More information about the wine-devel mailing list