diff --git a/dlls/winealsa.drv/alsa.c b/dlls/winealsa.drv/alsa.c index 9eb50cd..af9547c 100644 --- a/dlls/winealsa.drv/alsa.c +++ b/dlls/winealsa.drv/alsa.c @@ -2,6 +2,7 @@ * Wine Driver for ALSA * * Copyright 2002 Eric Pouech + * Copyright 2006 Jaroslav Kysela * Copyright 2007 Maarten Lankhorst * * This file has a few shared generic subroutines shared among the alsa @@ -558,22 +559,40 @@ out: /************************************************************************** * ALSA_XRUNRecovery [internal] * - * used to recovery from XRUN errors (buffer underflow/overflow) + * Code copied from alsa-lib v1.0.23 snd_pcm_recover implementation. + * used to recover from XRUN errors (buffer underflow/overflow) */ -int ALSA_XRUNRecovery(WINE_WAVEDEV * wwo, int err) +int ALSA_XRUNRecovery(snd_pcm_t *pcm, int err, int silent) { - if (err == -EPIPE) { /* under-run */ - err = snd_pcm_prepare(wwo->pcm); - if (err < 0) - ERR( "underrun recovery failed. prepare failed: %s\n", snd_strerror(err)); + if (err > 0) + err = -err; + if (err == -EINTR) /* nothing to do, continue */ return 0; - } else if (err == -ESTRPIPE) { - while ((err = snd_pcm_resume(wwo->pcm)) == -EAGAIN) - sleep(1); /* wait until the suspend flag is released */ + if (err == -EPIPE) { + const char *s; + if (snd_pcm_stream(pcm) == SND_PCM_STREAM_PLAYBACK) + s = "underrun"; + else + s = "overrun"; + if (!silent) + SNDERR("%s occured", s); + err = snd_pcm_prepare(pcm); + if (err < 0) { + SNDERR("cannot recovery from %s, prepare failed: %s", s, snd_strerror(err)); + return err; + } + return 0; + } + if (err == -ESTRPIPE) { + while ((err = snd_pcm_resume(pcm)) == -EAGAIN) + /* wait until suspend flag is released */ + poll(NULL, 0, 1000); if (err < 0) { - err = snd_pcm_prepare(wwo->pcm); - if (err < 0) - ERR("recovery from suspend failed, prepare failed: %s\n", snd_strerror(err)); + err = snd_pcm_prepare(pcm); + if (err < 0) { + SNDERR("cannot recovery from suspend, prepare failed: %s", snd_strerror(err)); + return err; + } } return 0; } diff --git a/dlls/winealsa.drv/alsa.h b/dlls/winealsa.drv/alsa.h index 7c2f0f4..5315b67 100644 --- a/dlls/winealsa.drv/alsa.h +++ b/dlls/winealsa.drv/alsa.h @@ -187,7 +187,7 @@ const char * ALSA_getFormat(WORD wFormatTag); BOOL ALSA_NearMatch(int rate1, int rate2); DWORD ALSA_bytes_to_mmtime(LPMMTIME lpTime, DWORD position, WAVEFORMATPCMEX* format); void ALSA_TraceParameters(snd_pcm_hw_params_t * hw_params, snd_pcm_sw_params_t * sw, int full); -int ALSA_XRUNRecovery(WINE_WAVEDEV * wwo, int err); +int ALSA_XRUNRecovery(snd_pcm_t *pcm, int err, int silent); void ALSA_copyFormat(LPWAVEFORMATEX wf1, LPWAVEFORMATPCMEX wf2); BOOL ALSA_supportedFormat(LPWAVEFORMATEX wf); diff --git a/dlls/winealsa.drv/dsoutput.c b/dlls/winealsa.drv/dsoutput.c index bb81621..c4f32b0 100644 --- a/dlls/winealsa.drv/dsoutput.c +++ b/dlls/winealsa.drv/dsoutput.c @@ -406,7 +406,7 @@ static HRESULT WINAPI IDsDriverBufferImpl_Unlock(PIDSDRIVERBUFFER iface, if (ret == -EPIPE) { WARN("Underrun occurred\n"); - snd_pcm_recover(This->pcm, -EPIPE, 1); + ALSA_XRUNRecovery(This->pcm, -EPIPE, 1); ret = snd_pcm_writei(This->pcm, pvAudio1, writelen); /* Advance mmap pointer a little to make dsound notice the underrun and respond to it */ diff --git a/dlls/winealsa.drv/waveout.c b/dlls/winealsa.drv/waveout.c index 4001f26..da5ba58 100644 --- a/dlls/winealsa.drv/waveout.c +++ b/dlls/winealsa.drv/waveout.c @@ -110,7 +110,7 @@ static BOOL wodUpdatePlayedTotal(WINE_WAVEDEV* wwo, snd_pcm_status_t* ps) if (state != SND_PCM_STATE_RUNNING && state != SND_PCM_STATE_PREPARED) { WARN("Unexpected state (%d) while updating Total Played, resetting\n", state); - snd_pcm_recover(wwo->pcm, -EPIPE, 0); + ALSA_XRUNRecovery(wwo->pcm, -EPIPE, 0); delay=0; } @@ -244,7 +244,7 @@ static int wodPlayer_WriteMaxFrags(WINE_WAVEDEV* wwo, DWORD* frames) written = (wwo->write)(wwo->pcm, lpWaveHdr->lpData + wwo->dwPartialOffset, toWrite); if ( written < 0) { /* XRUN occurred. let's try to recover */ - ALSA_XRUNRecovery(wwo, written); + ALSA_XRUNRecovery(wwo->pcm, written, 0); written = (wwo->write)(wwo->pcm, lpWaveHdr->lpData + wwo->dwPartialOffset, toWrite); } if (written <= 0) {