From 05be564fe6056856c92368ff8f225100b9ae8ad6 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Apr 26 2021 11:21:04 +0000 Subject: Add some important upstream patches. --- diff --git a/0002-acp-sync-with-pulseaudio.patch b/0002-acp-sync-with-pulseaudio.patch new file mode 100644 index 0000000..7628b00 --- /dev/null +++ b/0002-acp-sync-with-pulseaudio.patch @@ -0,0 +1,91 @@ +From cd4a47666d537fce00e736dde5a0170f93260f10 Mon Sep 17 00:00:00 2001 +From: Wim Taymans +Date: Thu, 22 Apr 2021 12:25:48 +0200 +Subject: [PATCH 2/6] acp: sync with pulseaudio + +Remove our custom hack to work around missing duplex and use +upstream fix. +--- + spa/plugins/alsa/acp/alsa-mixer.c | 24 +++++++++++++++++------- + spa/plugins/alsa/acp/idxset.h | 8 ++++++++ + 2 files changed, 25 insertions(+), 7 deletions(-) + +diff --git a/spa/plugins/alsa/acp/alsa-mixer.c b/spa/plugins/alsa/acp/alsa-mixer.c +index 606d00b8..9d41b193 100644 +--- a/spa/plugins/alsa/acp/alsa-mixer.c ++++ b/spa/plugins/alsa/acp/alsa-mixer.c +@@ -5142,6 +5142,7 @@ void pa_alsa_profile_set_probe( + pa_alsa_profile **pp, **probe_order; + pa_alsa_mapping *m; + pa_hashmap *broken_inputs, *broken_outputs, *used_paths; ++ pa_alsa_mapping *selected_fallback_input = NULL, *selected_fallback_output = NULL; + + pa_assert(ps); + pa_assert(dev_id); +@@ -5164,13 +5165,16 @@ void pa_alsa_profile_set_probe( + uint32_t idx; + p = *pp; + +- pa_log_debug("Check Profile %s.", p->name); +- +- /* Skip if fallback and already found something */ ++ /* Skip if fallback and already found something, but still probe already selected fallbacks. ++ * If UCM is used then both fallback_input and fallback_output flags are false. ++ * If UCM is not used then there will be only a single entry in mappings. ++ */ + if (found_input && p->fallback_input) +- continue; ++ if (selected_fallback_input == NULL || pa_idxset_get_by_index(p->input_mappings, 0) != selected_fallback_input) ++ continue; + if (found_output && p->fallback_output) +- continue; ++ if (selected_fallback_output == NULL || pa_idxset_get_by_index(p->output_mappings, 0) != selected_fallback_output) ++ continue; + + /* Skip if this is already marked that it is supported (i.e. from the config file) */ + if (!p->supported) { +@@ -5261,14 +5265,20 @@ void pa_alsa_profile_set_probe( + if (p->output_mappings) + PA_IDXSET_FOREACH(m, p->output_mappings, idx) + if (m->output_pcm) { +- found_output |= !p->fallback_output; ++ found_output = true; ++ if (p->fallback_output && selected_fallback_output == NULL) { ++ selected_fallback_output = m; ++ } + mapping_paths_probe(m, p, PA_ALSA_DIRECTION_OUTPUT, used_paths, mixers); + } + + if (p->input_mappings) + PA_IDXSET_FOREACH(m, p->input_mappings, idx) + if (m->input_pcm) { +- found_input |= !p->fallback_input; ++ found_input = true; ++ if (p->fallback_input && selected_fallback_input == NULL) { ++ selected_fallback_input = m; ++ } + mapping_paths_probe(m, p, PA_ALSA_DIRECTION_INPUT, used_paths, mixers); + } + } +diff --git a/spa/plugins/alsa/acp/idxset.h b/spa/plugins/alsa/acp/idxset.h +index 4840f0fc..6e88a847 100644 +--- a/spa/plugins/alsa/acp/idxset.h ++++ b/spa/plugins/alsa/acp/idxset.h +@@ -181,6 +181,14 @@ static inline void* pa_idxset_get_by_data(pa_idxset*s, const void *p, uint32_t * + return item->ptr; + } + ++static inline void* pa_idxset_get_by_index(pa_idxset*s, uint32_t idx) ++{ ++ pa_idxset_item *item; ++ if (!pa_array_check_index(&s->array, idx, pa_idxset_item)) ++ return NULL; ++ item = pa_array_get_unchecked(&s->array, idx, pa_idxset_item); ++ return item->ptr; ++} + + #define PA_IDXSET_FOREACH(e, s, idx) \ + for ((e) = pa_idxset_first((s), &(idx)); (e); (e) = pa_idxset_next((s), &(idx))) +-- +2.30.2 + diff --git a/0003-media-session-fix-match-rule.patch b/0003-media-session-fix-match-rule.patch new file mode 100644 index 0000000..425d6dd --- /dev/null +++ b/0003-media-session-fix-match-rule.patch @@ -0,0 +1,30 @@ +From 87b30e280e1e36cecd57422d9c619293feef2307 Mon Sep 17 00:00:00 2001 +From: Wim Taymans +Date: Sun, 25 Apr 2021 13:47:23 +0200 +Subject: [PATCH 3/6] media-session: fix match rule + +When matching without regex, don't just to a startswith check but also +check that the sizes of the strings match. + +Fixes #1098 +--- + src/examples/media-session/match-rules.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/src/examples/media-session/match-rules.c b/src/examples/media-session/match-rules.c +index 84dca414..7e2ab701 100644 +--- a/src/examples/media-session/match-rules.c ++++ b/src/examples/media-session/match-rules.c +@@ -72,7 +72,8 @@ static bool find_match(struct spa_json *arr, struct pw_properties *props) + success = true; + regfree(&preg); + } +- } else if (strncmp(str, value, len) == 0) { ++ } else if (strncmp(str, value, len) == 0 && ++ strlen(str) == (size_t)len) { + success = true; + } + } +-- +2.30.2 + diff --git a/0004-media-session-keep-track-of-seq-in-pw_-_enum_params.patch b/0004-media-session-keep-track-of-seq-in-pw_-_enum_params.patch new file mode 100644 index 0000000..28e270e --- /dev/null +++ b/0004-media-session-keep-track-of-seq-in-pw_-_enum_params.patch @@ -0,0 +1,151 @@ +From a193bf7e1faa03d1907ebecac097f9ccc3420310 Mon Sep 17 00:00:00 2001 +From: Pauli Virtanen +Date: Sun, 25 Apr 2021 19:11:43 +0300 +Subject: [PATCH 4/6] media-session: keep track of seq in pw_*_enum_params + +If multiple async enum param are running at the same time, take results +only from the latest one. +--- + src/examples/media-session/media-session.c | 55 +++++++++++++++++----- + src/examples/media-session/media-session.h | 4 ++ + 2 files changed, 46 insertions(+), 13 deletions(-) + +diff --git a/src/examples/media-session/media-session.c b/src/examples/media-session/media-session.c +index 640c4caa..21fc8030 100644 +--- a/src/examples/media-session/media-session.c ++++ b/src/examples/media-session/media-session.c +@@ -361,7 +361,7 @@ int sm_object_destroy(struct sm_object *obj) + } + + static struct param *add_param(struct spa_list *param_list, +- uint32_t id, const struct spa_pod *param) ++ int seq, int *param_seq, uint32_t id, const struct spa_pod *param) + { + struct param *p; + +@@ -372,6 +372,19 @@ static struct param *add_param(struct spa_list *param_list, + if (id == SPA_ID_INVALID) + id = SPA_POD_OBJECT_ID(param); + ++ if (id >= SM_MAX_PARAMS) { ++ pw_log_error(NAME": too big param id %d", id); ++ errno = EINVAL; ++ return NULL; ++ } ++ ++ if (seq != param_seq[id]) { ++ pw_log_debug(NAME": ignoring param %d, seq:%d != current_seq:%d", ++ id, seq, param_seq[id]); ++ errno = EBUSY; ++ return NULL; ++ } ++ + p = malloc(sizeof(struct param) + SPA_POD_SIZE(param)); + if (p == NULL) + return NULL; +@@ -490,13 +503,21 @@ static void device_event_info(void *object, const struct pw_device_info *info) + if (info->params[i].user == 0) + continue; + ++ if (id >= SM_MAX_PARAMS) { ++ pw_log_error(NAME" %p: too big param id %d", impl, id); ++ continue; ++ } ++ + device->n_params -= clear_params(&device->param_list, id); + + if (info->params[i].flags & SPA_PARAM_INFO_READ) { +- pw_log_debug(NAME" %p: device %d enum params %d", impl, +- device->obj.id, id); +- pw_device_enum_params((struct pw_device*)device->obj.proxy, +- 1, id, 0, UINT32_MAX, NULL); ++ int res; ++ res = pw_device_enum_params((struct pw_device*)device->obj.proxy, ++ ++device->param_seq[id], id, 0, UINT32_MAX, NULL); ++ if (SPA_RESULT_IS_ASYNC(res)) ++ device->param_seq[id] = res; ++ pw_log_debug(NAME" %p: device %d enum params %d seq:%d", impl, ++ device->obj.id, id, device->param_seq[id]); + } + info->params[i].user = 0; + } +@@ -512,8 +533,8 @@ static void device_event_param(void *object, int seq, + struct sm_device *device = object; + struct impl *impl = SPA_CONTAINER_OF(device->obj.session, struct impl, this); + +- pw_log_debug(NAME" %p: device %p param %d index:%d", impl, device, id, index); +- if (add_param(&device->param_list, id, param) != NULL) ++ pw_log_debug(NAME" %p: device %p param %d index:%d seq:%d", impl, device, id, index, seq); ++ if (add_param(&device->param_list, seq, device->param_seq, id, param) != NULL) + device->n_params++; + + device->obj.avail |= SM_DEVICE_CHANGE_MASK_PARAMS; +@@ -591,13 +612,21 @@ static void node_event_info(void *object, const struct pw_node_info *info) + if (info->params[i].user == 0) + continue; + ++ if (id >= SM_MAX_PARAMS) { ++ pw_log_error(NAME" %p: too big param id %d", impl, id); ++ continue; ++ } ++ + node->n_params -= clear_params(&node->param_list, id); + + if (info->params[i].flags & SPA_PARAM_INFO_READ) { +- pw_log_debug(NAME" %p: node %d enum params %d", impl, +- node->obj.id, id); +- pw_node_enum_params((struct pw_node*)node->obj.proxy, +- 1, id, 0, UINT32_MAX, NULL); ++ int res; ++ res = pw_node_enum_params((struct pw_node*)node->obj.proxy, ++ ++node->param_seq[id], id, 0, UINT32_MAX, NULL); ++ if (SPA_RESULT_IS_ASYNC(res)) ++ node->param_seq[id] = res; ++ pw_log_debug(NAME" %p: node %d enum params %d seq:%d", impl, ++ node->obj.id, id, node->param_seq[id]); + } + info->params[i].user = 0; + } +@@ -613,8 +642,8 @@ static void node_event_param(void *object, int seq, + struct sm_node *node = object; + struct impl *impl = SPA_CONTAINER_OF(node->obj.session, struct impl, this); + +- pw_log_debug(NAME" %p: node %p param %d index:%d", impl, node, id, index); +- if (add_param(&node->param_list, id, param) != NULL) ++ pw_log_debug(NAME" %p: node %p param %d index:%d seq:%d", impl, node, id, index, seq); ++ if (add_param(&node->param_list, seq, node->param_seq, id, param) != NULL) + node->n_params++; + + node->obj.avail |= SM_NODE_CHANGE_MASK_PARAMS; +diff --git a/src/examples/media-session/media-session.h b/src/examples/media-session/media-session.h +index edfb1331..7d036288 100644 +--- a/src/examples/media-session/media-session.h ++++ b/src/examples/media-session/media-session.h +@@ -35,6 +35,8 @@ extern "C" { + + #define SM_TYPE_MEDIA_SESSION PW_TYPE_INFO_OBJECT_BASE "SessionManager" + ++#define SM_MAX_PARAMS 32 ++ + struct sm_media_session; + + struct sm_object_events { +@@ -133,6 +135,7 @@ struct sm_device { + #define SM_DEVICE_CHANGE_MASK_NODES (SM_OBJECT_CHANGE_MASK_LAST<<2) + uint32_t n_params; + struct spa_list param_list; /**< list of sm_param */ ++ int param_seq[SM_MAX_PARAMS]; + struct pw_device_info *info; + struct spa_list node_list; + }; +@@ -148,6 +151,7 @@ struct sm_node { + #define SM_NODE_CHANGE_MASK_PORTS (SM_OBJECT_CHANGE_MASK_LAST<<2) + uint32_t n_params; + struct spa_list param_list; /**< list of sm_param */ ++ int param_seq[SM_MAX_PARAMS]; + struct pw_node_info *info; + struct spa_list port_list; + +-- +2.30.2 + diff --git a/0005-pulse-server-keep-track-of-seq-in-pw_-_enum_params.patch b/0005-pulse-server-keep-track-of-seq-in-pw_-_enum_params.patch new file mode 100644 index 0000000..a6602c4 --- /dev/null +++ b/0005-pulse-server-keep-track-of-seq-in-pw_-_enum_params.patch @@ -0,0 +1,155 @@ +From f6cbb05aa95f0580bded97c194d928296cc0e874 Mon Sep 17 00:00:00 2001 +From: Pauli Virtanen +Date: Sun, 25 Apr 2021 20:42:03 +0300 +Subject: [PATCH 5/6] pulse-server: keep track of seq in pw_*_enum_params + +If multiple async enum param are running at the same time, take results +only from the latest one. +--- + src/modules/module-protocol-pulse/manager.c | 55 +++++++++++++++++---- + 1 file changed, 46 insertions(+), 9 deletions(-) + +diff --git a/src/modules/module-protocol-pulse/manager.c b/src/modules/module-protocol-pulse/manager.c +index 8aff48a4..6d0e65f6 100644 +--- a/src/modules/module-protocol-pulse/manager.c ++++ b/src/modules/module-protocol-pulse/manager.c +@@ -26,8 +26,11 @@ + + #include + #include ++#include + #include + ++#define MAX_PARAMS 32 ++ + #define manager_emit_sync(m) spa_hook_list_call(&m->hooks, struct pw_manager_events, sync, 0) + #define manager_emit_added(m,o) spa_hook_list_call(&m->hooks, struct pw_manager_events, added, 0, o) + #define manager_emit_updated(m,o) spa_hook_list_call(&m->hooks, struct pw_manager_events, updated, 0, o) +@@ -72,6 +75,8 @@ struct object { + struct spa_hook proxy_listener; + struct spa_hook object_listener; + ++ int param_seq[MAX_PARAMS]; ++ + struct spa_list data_list; + }; + +@@ -97,7 +102,8 @@ static uint32_t clear_params(struct spa_list *param_list, uint32_t id) + return count; + } + +-static struct pw_manager_param *add_param(struct spa_list *params, uint32_t id, const struct spa_pod *param) ++static struct pw_manager_param *add_param(struct spa_list *params, ++ int seq, int *param_seq, uint32_t id, const struct spa_pod *param) + { + struct pw_manager_param *p; + +@@ -109,6 +115,19 @@ static struct pw_manager_param *add_param(struct spa_list *params, uint32_t id, + id = SPA_POD_OBJECT_ID(param); + } + ++ if (id >= MAX_PARAMS) { ++ pw_log_error("too big param id %d", id); ++ errno = EINVAL; ++ return NULL; ++ } ++ ++ if (seq != param_seq[id]) { ++ pw_log_debug("ignoring param %d, seq:%d != current_seq:%d", ++ id, seq, param_seq[id]); ++ errno = EBUSY; ++ return NULL; ++ } ++ + p = malloc(sizeof(*p) + (param != NULL ? SPA_POD_SIZE(param) : 0)); + if (p == NULL) + return NULL; +@@ -287,11 +306,17 @@ static void device_event_info(void *object, const struct pw_device_info *info) + if (info->change_mask & PW_DEVICE_CHANGE_MASK_PARAMS) { + for (i = 0; i < info->n_params; i++) { + uint32_t id = info->params[i].id; ++ int res; + + if (info->params[i].user == 0) + continue; + info->params[i].user = 0; + ++ if (id >= MAX_PARAMS) { ++ pw_log_error("too big param id %d", id); ++ continue; ++ } ++ + switch (id) { + case SPA_PARAM_EnumProfile: + case SPA_PARAM_Profile: +@@ -301,12 +326,14 @@ static void device_event_info(void *object, const struct pw_device_info *info) + case SPA_PARAM_Route: + break; + } +- add_param(&o->pending_list, id, NULL); ++ add_param(&o->pending_list, o->param_seq[id], o->param_seq, id, NULL); + if (!(info->params[i].flags & SPA_PARAM_INFO_READ)) + continue; + +- pw_device_enum_params((struct pw_device*)o->this.proxy, +- 0, id, 0, -1, NULL); ++ res = pw_device_enum_params((struct pw_device*)o->this.proxy, ++ ++o->param_seq[id], id, 0, -1, NULL); ++ if (SPA_RESULT_IS_ASYNC(res)) ++ o->param_seq[id] = res; + } + } + if (changed) { +@@ -343,7 +370,9 @@ static void device_event_param(void *object, int seq, + struct manager *m = o->manager; + struct pw_manager_param *p; + +- p = add_param(&o->pending_list, id, param); ++ p = add_param(&o->pending_list, seq, o->param_seq, id, param); ++ if (p == NULL) ++ return; + + if (id == SPA_PARAM_Route && !has_param(&o->this.param_list, p)) { + uint32_t id, device; +@@ -400,18 +429,26 @@ static void node_event_info(void *object, const struct pw_node_info *info) + if (info->change_mask & PW_NODE_CHANGE_MASK_PARAMS) { + for (i = 0; i < info->n_params; i++) { + uint32_t id = info->params[i].id; ++ int res; + + if (info->params[i].user == 0) + continue; + info->params[i].user = 0; + ++ if (id >= MAX_PARAMS) { ++ pw_log_error("too big param id %d", id); ++ continue; ++ } ++ + changed++; +- add_param(&o->pending_list, id, NULL); ++ add_param(&o->pending_list, o->param_seq[id], o->param_seq, id, NULL); + if (!(info->params[i].flags & SPA_PARAM_INFO_READ)) + continue; + +- pw_node_enum_params((struct pw_node*)o->this.proxy, +- 0, id, 0, -1, NULL); ++ res = pw_node_enum_params((struct pw_node*)o->this.proxy, ++ ++o->param_seq[id], id, 0, -1, NULL); ++ if (SPA_RESULT_IS_ASYNC(res)) ++ o->param_seq[id] = res; + } + } + if (changed) { +@@ -425,7 +462,7 @@ static void node_event_param(void *object, int seq, + const struct spa_pod *param) + { + struct object *o = object; +- add_param(&o->pending_list, id, param); ++ add_param(&o->pending_list, seq, o->param_seq, id, param); + } + + static const struct pw_node_events node_events = { +-- +2.30.2 + diff --git a/0006-bluez5-don-t-unregister-HFP-HSP-profiles-when-shutti.patch b/0006-bluez5-don-t-unregister-HFP-HSP-profiles-when-shutti.patch new file mode 100644 index 0000000..5a3c714 --- /dev/null +++ b/0006-bluez5-don-t-unregister-HFP-HSP-profiles-when-shutti.patch @@ -0,0 +1,29 @@ +From b6d6800fc39538db50753df35d117b7b6a8c3311 Mon Sep 17 00:00:00 2001 +From: Pauli Virtanen +Date: Sun, 25 Apr 2021 21:18:45 +0300 +Subject: [PATCH 6/6] bluez5: don't unregister HFP/HSP profiles when shutting + down + +This apparently causes delays in shutdown under some conditions, and +closing the DBus connection should be enought to tell BlueZ that we are +shutting down. +--- + spa/plugins/bluez5/backend-native.c | 2 -- + 1 file changed, 2 deletions(-) + +diff --git a/spa/plugins/bluez5/backend-native.c b/spa/plugins/bluez5/backend-native.c +index ceb00c52..c546c2af 100644 +--- a/spa/plugins/bluez5/backend-native.c ++++ b/spa/plugins/bluez5/backend-native.c +@@ -1870,8 +1870,6 @@ static int backend_native_free(void *data) + + sco_close(backend); + +- backend_native_unregister_profiles(backend); +- + #ifdef HAVE_BLUEZ_5_BACKEND_HSP_NATIVE + dbus_connection_unregister_object_path(backend->conn, PROFILE_HSP_AG); + dbus_connection_unregister_object_path(backend->conn, PROFILE_HSP_HS); +-- +2.30.2 + diff --git a/pipewire.spec b/pipewire.spec index 82fde61..34c8c98 100644 --- a/pipewire.spec +++ b/pipewire.spec @@ -8,7 +8,7 @@ %global libversion %{soversion}.%(bash -c '((intversion = (%{minorversion} * 100) + %{microversion})); echo ${intversion}').0 # For rpmdev-bumpspec and releng automation -%global baserelease 2 +%global baserelease 3 #global snapdate 20210107 #global gitcommit b17db2cebc1a5ab2c01851d29c05f79cd2f262bb @@ -53,13 +53,17 @@ Source0: https://gitlab.freedesktop.org/pipewire/pipewire/-/archive/%{ver %endif ## upstream patches +Patch0001: 0002-acp-sync-with-pulseaudio.patch +Patch0002: 0003-media-session-fix-match-rule.patch +Patch0003: 0004-media-session-keep-track-of-seq-in-pw_-_enum_params.patch +Patch0004: 0005-pulse-server-keep-track-of-seq-in-pw_-_enum_params.patch +Patch0005: 0006-bluez5-don-t-unregister-HFP-HSP-profiles-when-shutti.patch ## upstreamable patches ## fedora patches Patch1001: 0001-conf-start-media-session-through-pipewire.patch - BuildRequires: gettext BuildRequires: meson >= 0.49.0 BuildRequires: gcc @@ -473,6 +477,9 @@ systemctl --no-reload preset --global pipewire.socket >/dev/null 2>&1 || : %endif %changelog +* Tue Apr 26 2021 Wim Taymans - 0.3.26-3 +- Add some important upstream patches. + * Sat Apr 24 2021 Neal Gompa - 0.3.26-2 - Disable JACK server integration on RHEL