Module: wine Branch: master Commit: 9ad60d1d143809c6ae477eb53e75c3dc93736e0e URL: http://source.winehq.org/git/wine.git/?a=commit;h=9ad60d1d143809c6ae477eb53e...
Author: Andrew Eikum aeikum@codeweavers.com Date: Fri Aug 5 09:33:10 2011 -0500
winealsa.drv: Inject handle_underrun=1 setting for pulse-backed devices.
---
dlls/winealsa.drv/mmdevdrv.c | 110 +++++++++++++++++++++++++++++++++++++++-- 1 files changed, 104 insertions(+), 6 deletions(-)
diff --git a/dlls/winealsa.drv/mmdevdrv.c b/dlls/winealsa.drv/mmdevdrv.c index ded6b2a..6c902f5 100644 --- a/dlls/winealsa.drv/mmdevdrv.c +++ b/dlls/winealsa.drv/mmdevdrv.c @@ -407,12 +407,96 @@ HRESULT WINAPI AUDDRV_GetEndpointIDs(EDataFlow flow, WCHAR ***ids, char ***keys, return S_OK; }
+/* Using the pulse PCM device from alsa-plugins 1.0.24 triggers a bug + * which causes audio to cease playing after a few minutes of playback. + * Setting handle_underrun=1 on pulse-backed ALSA devices seems to work + * around this issue. */ +static snd_config_t *make_handle_underrun_config(const char *name) +{ + snd_config_t *lconf, *dev_node, *hu_node, *type_node; + char dev_node_name[64]; + const char *type_str; + int err; + + snd_config_update(); + + if((err = snd_config_copy(&lconf, snd_config)) < 0){ + WARN("snd_config_copy failed: %d (%s)\n", err, snd_strerror(err)); + return NULL; + } + + sprintf(dev_node_name, "pcm.%s", name); + err = snd_config_search(lconf, dev_node_name, &dev_node); + if(err == -ENOENT){ + snd_config_delete(lconf); + return NULL; + } + if(err < 0){ + snd_config_delete(lconf); + WARN("snd_config_search failed: %d (%s)\n", err, snd_strerror(err)); + return NULL; + } + + /* ALSA is extremely fragile. If it runs into a config setting it doesn't + * recognize, it tends to fail or assert. So we only want to inject + * handle_underrun=1 on devices that we know will recognize it. */ + err = snd_config_search(dev_node, "type", &type_node); + if(err == -ENOENT){ + snd_config_delete(lconf); + return NULL; + } + if(err < 0){ + snd_config_delete(lconf); + WARN("snd_config_search failed: %d (%s)\n", err, snd_strerror(err)); + return NULL; + } + + if((err = snd_config_get_string(type_node, &type_str)) < 0){ + snd_config_delete(lconf); + return NULL; + } + + if(strcmp(type_str, "pulse") != 0){ + snd_config_delete(lconf); + return NULL; + } + + err = snd_config_search(dev_node, "handle_underrun", &hu_node); + if(err >= 0){ + /* user already has an explicit handle_underrun setting, so don't + * use a local config */ + snd_config_delete(lconf); + return NULL; + } + if(err != -ENOENT){ + snd_config_delete(lconf); + WARN("snd_config_search failed: %d (%s)\n", err, snd_strerror(err)); + return NULL; + } + + if((err = snd_config_imake_integer(&hu_node, "handle_underrun", 1)) < 0){ + snd_config_delete(lconf); + WARN("snd_config_imake_integer failed: %d (%s)\n", err, + snd_strerror(err)); + return NULL; + } + + if((err = snd_config_add(dev_node, hu_node)) < 0){ + snd_config_delete(lconf); + WARN("snd_config_add failed: %d (%s)\n", err, snd_strerror(err)); + return NULL; + } + + return lconf; +} + HRESULT WINAPI AUDDRV_GetAudioEndpoint(const char *key, IMMDevice *dev, EDataFlow dataflow, IAudioClient **out) { ACImpl *This; int err; snd_pcm_stream_t stream; + snd_config_t *lconf;
TRACE(""%s" %p %d %p\n", key, dev, dataflow, out);
@@ -436,13 +520,27 @@ HRESULT WINAPI AUDDRV_GetAudioEndpoint(const char *key, IMMDevice *dev, return E_UNEXPECTED; }
+ lconf = make_handle_underrun_config(key); + This->dataflow = dataflow; - if((err = snd_pcm_open(&This->pcm_handle, key, stream, - SND_PCM_NONBLOCK)) < 0){ - HeapFree(GetProcessHeap(), 0, This); - WARN("Unable to open PCM "%s": %d (%s)\n", key, err, - snd_strerror(err)); - return E_FAIL; + if(lconf){ + if((err = snd_pcm_open_lconf(&This->pcm_handle, key, stream, + SND_PCM_NONBLOCK, lconf)) < 0){ + snd_config_delete(lconf); + HeapFree(GetProcessHeap(), 0, This); + WARN("Unable to open PCM "%s": %d (%s)\n", key, err, + snd_strerror(err)); + return E_FAIL; + } + snd_config_delete(lconf); + }else{ + if((err = snd_pcm_open(&This->pcm_handle, key, stream, + SND_PCM_NONBLOCK)) < 0){ + HeapFree(GetProcessHeap(), 0, This); + WARN("Unable to open PCM "%s": %d (%s)\n", key, err, + snd_strerror(err)); + return E_FAIL; + } }
This->hw_params = HeapAlloc(GetProcessHeap(), 0,