The sad state of audio GetPosition

Maarten Lankhorst m.b.lankhorst at gmail.com
Fri Aug 19 07:53:17 CDT 2011


On 08/19/2011 01:30 PM, Joerg-Cyril.Hoehle at t-systems.com wrote:
> 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.
afaict pause, with reset mapped to drop, but for historic reasons
that didn't work (surprise! love from dmix). Even worse,
snd_pcm_drain would deadlock if called twice.

I can't remember why pause didn't work, but if it works go for it.
>
> 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);
HeapAlloc(GetProcessHeap(), HEAP_ZERO_FLAG, snd_pcm_status_sizeof()) or something like that if available please..
>      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;
>      }
Unneeded part. Follow that flow..

>  
> -    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;
> +    }
> +    }

if 0 is bad...
> +    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;
Isn't delay_frames < 0 the definition of underrun? no point in adding MAX_LATE_SECONDS

> +    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);
>  
Getting an avail update again? Why?



More information about the wine-devel mailing list