winealsa.drv: Inject handle_underrun=1 setting for pulse-backed devices.
This commit is contained in:
parent
8c109aee13
commit
9ad60d1d14
|
@ -407,12 +407,96 @@ HRESULT WINAPI AUDDRV_GetEndpointIDs(EDataFlow flow, WCHAR ***ids, char ***keys,
|
||||||
return S_OK;
|
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,
|
HRESULT WINAPI AUDDRV_GetAudioEndpoint(const char *key, IMMDevice *dev,
|
||||||
EDataFlow dataflow, IAudioClient **out)
|
EDataFlow dataflow, IAudioClient **out)
|
||||||
{
|
{
|
||||||
ACImpl *This;
|
ACImpl *This;
|
||||||
int err;
|
int err;
|
||||||
snd_pcm_stream_t stream;
|
snd_pcm_stream_t stream;
|
||||||
|
snd_config_t *lconf;
|
||||||
|
|
||||||
TRACE("\"%s\" %p %d %p\n", key, dev, dataflow, out);
|
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;
|
return E_UNEXPECTED;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
lconf = make_handle_underrun_config(key);
|
||||||
|
|
||||||
This->dataflow = dataflow;
|
This->dataflow = dataflow;
|
||||||
if((err = snd_pcm_open(&This->pcm_handle, key, stream,
|
if(lconf){
|
||||||
SND_PCM_NONBLOCK)) < 0){
|
if((err = snd_pcm_open_lconf(&This->pcm_handle, key, stream,
|
||||||
HeapFree(GetProcessHeap(), 0, This);
|
SND_PCM_NONBLOCK, lconf)) < 0){
|
||||||
WARN("Unable to open PCM \"%s\": %d (%s)\n", key, err,
|
snd_config_delete(lconf);
|
||||||
snd_strerror(err));
|
HeapFree(GetProcessHeap(), 0, This);
|
||||||
return E_FAIL;
|
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,
|
This->hw_params = HeapAlloc(GetProcessHeap(), 0,
|
||||||
|
|
Loading…
Reference in New Issue