=?UTF-8?Q?J=C3=B6rg=20H=C3=B6hle=20?=: winealsa: Implement IAudioClock:: GetPosition() using snd_pcm_delay.

Alexandre Julliard julliard at winehq.org
Mon Dec 12 12:25:55 CST 2011


Module: wine
Branch: master
Commit: 62017964bead565a1da427faaf083e5103c27440
URL:    http://source.winehq.org/git/wine.git/?a=commit;h=62017964bead565a1da427faaf083e5103c27440

Author: Jörg Höhle <Joerg-Cyril.Hoehle at t-systems.com>
Date:   Fri Dec  9 17:12:54 2011 +0100

winealsa: Implement IAudioClock::GetPosition() using snd_pcm_delay.

---

 dlls/winealsa.drv/mmdevdrv.c |   50 ++++++++++++++++++++++++++++++++---------
 1 files changed, 39 insertions(+), 11 deletions(-)

diff --git a/dlls/winealsa.drv/mmdevdrv.c b/dlls/winealsa.drv/mmdevdrv.c
index bfff159..359997e 100644
--- a/dlls/winealsa.drv/mmdevdrv.c
+++ b/dlls/winealsa.drv/mmdevdrv.c
@@ -109,7 +109,7 @@ struct ACImpl {
 
     BOOL initted, started;
     REFERENCE_TIME mmdev_period_rt;
-    UINT64 written_frames;
+    UINT64 written_frames, last_pos_frames;
     UINT32 bufsize_frames, held_frames, tmp_buffer_frames;
     UINT32 lcl_offs_frames; /* offs into local_buffer where valid data starts */
 
@@ -1790,6 +1790,7 @@ static HRESULT WINAPI AudioClient_Reset(IAudioClient *iface)
     if(snd_pcm_prepare(This->pcm_handle) < 0)
         WARN("snd_pcm_prepare failed\n");
 
+    This->last_pos_frames = 0;
     This->held_frames = 0;
     This->written_frames = 0;
     This->lcl_offs_frames = 0;
@@ -2291,8 +2292,12 @@ static HRESULT WINAPI AudioClock_GetPosition(IAudioClock *iface, UINT64 *pos,
         UINT64 *qpctime)
 {
     ACImpl *This = impl_from_IAudioClock(iface);
-    UINT32 pad;
-    HRESULT hr;
+    UINT64 written_frames, position;
+    UINT32 held_frames;
+    int err;
+    snd_pcm_state_t alsa_state;
+    snd_pcm_uframes_t avail_frames;
+    snd_pcm_sframes_t delay_frames;
 
     TRACE("(%p)->(%p, %p)\n", This, pos, qpctime);
 
@@ -2301,19 +2306,42 @@ static HRESULT WINAPI AudioClock_GetPosition(IAudioClock *iface, UINT64 *pos,
 
     EnterCriticalSection(&This->lock);
 
-    hr = IAudioClient_GetCurrentPadding(&This->IAudioClient_iface, &pad);
-    if(FAILED(hr)){
-        LeaveCriticalSection(&This->lock);
-        return hr;
+    /* call required to get accurate snd_pcm_state() */
+    avail_frames = snd_pcm_avail_update(This->pcm_handle);
+    alsa_state = snd_pcm_state(This->pcm_handle);
+    written_frames = This->written_frames;
+    held_frames = This->held_frames;
+
+    err = snd_pcm_delay(This->pcm_handle, &delay_frames);
+    if(err < 0){
+        /* old Pulse, shortly after start */
+        WARN("snd_pcm_delay failed in state %u: %d (%s)\n", alsa_state, err, snd_strerror(err));
     }
 
-    if(This->dataflow == eRender)
-        *pos = This->written_frames - pad;
-    else if(This->dataflow == eCapture)
-        *pos = This->written_frames + pad;
+    if(This->dataflow == eRender){
+        position = written_frames - held_frames; /* maximum */
+        if(!This->started || alsa_state > SND_PCM_STATE_RUNNING)
+            ; /* mmdevapi stopped or ALSA underrun: pretend everything was played */
+        else if(err<0 || delay_frames > position - This->last_pos_frames)
+            /* Pulse bug: past underrun, despite recovery, avail_frames & delay
+             * may be larger than alsa_bufsize_frames, as if cumulating frames. */
+            /* Pulse bug: EIO(-5) shortly after starting: nothing played */
+            position = This->last_pos_frames;
+        else if(delay_frames > 0)
+            position -= delay_frames;
+    }else
+        position = written_frames + held_frames;
+
+    /* ensure monotic growth */
+    This->last_pos_frames = position;
 
     LeaveCriticalSection(&This->lock);
 
+    TRACE("frames written: %u, held: %u, avail: %ld, delay: %ld state %d, pos: %u\n",
+          (UINT32)(written_frames%1000000000), held_frames,
+          avail_frames, delay_frames, alsa_state, (UINT32)(position%1000000000));
+    *pos = position;
+
     if(qpctime){
         LARGE_INTEGER stamp, freq;
         QueryPerformanceCounter(&stamp);




More information about the wine-cvs mailing list