Andrew Eikum : winealsa.drv: Inject handle_underrun= 1 setting for pulse-backed devices.
Alexandre Julliard
julliard at winehq.org
Fri Aug 5 10:20:51 CDT 2011
Module: wine
Branch: master
Commit: 9ad60d1d143809c6ae477eb53e75c3dc93736e0e
URL: http://source.winehq.org/git/wine.git/?a=commit;h=9ad60d1d143809c6ae477eb53e75c3dc93736e0e
Author: Andrew Eikum <aeikum at 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,
More information about the wine-cvs
mailing list