=?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