pcm_pipewire: optimize by updating existing stream

pw_stream_connect can take a very long time to finish connecting. This
process continues after snd_pcm_pipewire_prepare has released lock on
pw->main_loop and during this time the device returns EBUSY on write
attempts. This adds a significant latency to playback compared to pre-
pipewire configurations. This is a problem when using for example
Gstreamer alsasink with tight time synchronization options since
GstAudioBaseSink keeps track of internal time by counting processed
samples. Also worth noting is that alsasink calls prepare often,
for example on receiving a caps event.

With this change an existing pipewire stream will be updated rather than
destroyed and re-created when prepare is called.
This commit is contained in:
Erik Fröbrant 2022-10-06 08:25:05 +00:00 committed by Wim Taymans
parent 4a41a03f5c
commit 552bca8595

View file

@ -563,11 +563,6 @@ static int snd_pcm_pipewire_prepare(snd_pcm_ioplug_t *io)
goto done;
pw->hw_params_changed = false;
if (pw->stream != NULL) {
pw_stream_destroy(pw->stream);
pw->stream = NULL;
}
props = pw_properties_new(NULL, NULL);
if (props == NULL)
goto error;
@ -593,13 +588,20 @@ static int snd_pcm_pipewire_prepare(snd_pcm_ioplug_t *io)
pw_properties_get(props, PW_KEY_MEDIA_ROLE) == NULL)
pw_properties_setf(props, PW_KEY_MEDIA_ROLE, "%s", pw->role);
params[0] = spa_format_audio_raw_build(&b, SPA_PARAM_EnumFormat, &pw->format);
if (pw->stream != NULL) {
pw_stream_update_properties(pw->stream, &props->dict);
pw_stream_update_params(pw->stream, params, 1);
goto done;
}
pw->stream = pw_stream_new(pw->core, pw->node_name, props);
if (pw->stream == NULL)
goto error;
pw_stream_add_listener(pw->stream, &pw->stream_listener, &stream_events, pw);
params[0] = spa_format_audio_raw_build(&b, SPA_PARAM_EnumFormat, &pw->format);
pw->error = 0;
pw_stream_connect(pw->stream,