link: add WP_LINK_FEATURE_ESTABLISHED to track when a link is PAUSED/ACTIVE

This allows to transparently wait until a link is PAUSED before
returning from the activation transition. This way we can also
catch negotiation/allocation errors while activating a link.

PAUSED is used instead of ACTIVE because ACTIVE depends on the
nodes being activated as well. There are cases where a link may not
activate the nodes (ex, a passive link) and the link may remain
PAUSED for a long time.

Related to: #294
This commit is contained in:
George Kiagiadakis 2022-07-02 17:10:22 +03:00
parent 37bd392119
commit 9def3f96d2
4 changed files with 34 additions and 4 deletions

View file

@ -99,6 +99,17 @@ wp_link_get_property (GObject * object, guint property_id,
}
}
static WpObjectFeatures
wp_link_get_supported_features (WpObject * object)
{
return wp_pw_object_mixin_get_supported_features (object)
| WP_LINK_FEATURE_ESTABLISHED;
}
enum {
STEP_WAIT_ESTABLISHED = WP_PW_OBJECT_MIXIN_STEP_CUSTOM_START,
};
static void
wp_link_activate_execute_step (WpObject * object,
WpFeatureActivationTransition * transition, guint step,
@ -114,6 +125,9 @@ wp_link_activate_execute_step (WpObject * object,
case WP_PW_OBJECT_MIXIN_STEP_WAIT_INFO:
/* just wait, info will be emitted anyway after binding */
break;
case STEP_WAIT_ESTABLISHED:
/* just wait again, the state will be changed automatically */
break;
default:
g_assert_not_reached ();
}
@ -135,6 +149,7 @@ static void
wp_link_pw_proxy_destroyed (WpProxy * proxy)
{
wp_pw_object_mixin_handle_pw_proxy_destroyed (proxy);
wp_object_update_features (WP_OBJECT (proxy), 0, WP_LINK_FEATURE_ESTABLISHED);
WP_PROXY_CLASS (wp_link_parent_class)->pw_proxy_destroyed (proxy);
}
@ -148,8 +163,7 @@ wp_link_class_init (WpLinkClass * klass)
object_class->get_property = wp_link_get_property;
wpobject_class->get_supported_features =
wp_pw_object_mixin_get_supported_features;
wpobject_class->get_supported_features = wp_link_get_supported_features;
wpobject_class->activate_get_next_step =
wp_pw_object_mixin_activate_get_next_step;
wpobject_class->activate_execute_step = wp_link_activate_execute_step;
@ -175,13 +189,20 @@ wp_link_class_init (WpLinkClass * klass)
static void
wp_link_process_info (gpointer instance, gpointer old_info, gpointer i)
{
WpObject *object = instance;
const struct pw_link_info *info = i;
if (info->change_mask & PW_LINK_CHANGE_MASK_STATE) {
enum pw_link_state old_state = old_info ?
((struct pw_link_info *) old_info)->state : PW_LINK_STATE_INIT;
g_signal_emit (instance, signals[SIGNAL_STATE_CHANGED], 0,
old_state, info->state);
if (info->state >= PW_LINK_STATE_PAUSED && old_state < PW_LINK_STATE_PAUSED)
wp_object_update_features (object, WP_LINK_FEATURE_ESTABLISHED, 0);
else if (info->state < PW_LINK_STATE_PAUSED && old_state >= PW_LINK_STATE_PAUSED)
wp_object_update_features (object, 0, WP_LINK_FEATURE_ESTABLISHED);
}
}

View file

@ -27,6 +27,15 @@ typedef enum {
WP_LINK_STATE_ACTIVE = 4, /*!< the link is active */
} WpLinkState;
/*!
* \brief An extension of WpProxyFeatures
* \ingroup wplink
*/
typedef enum { /*< flags >*/
/*! waits until the state of the link is >= PAUSED */
WP_LINK_FEATURE_ESTABLISHED = (WP_PROXY_FEATURE_CUSTOM_START << 0),
} WpLinkFeatures;
/*!
* \brief The WpLink GType
* \ingroup wplink

View file

@ -327,7 +327,7 @@ create_links (WpSiStandardLink * self, WpTransition * transition,
/* activate to ensure it is created without errors */
wp_object_activate_closure (WP_OBJECT (link),
WP_PIPEWIRE_OBJECT_FEATURES_MINIMAL, NULL,
WP_OBJECT_FEATURES_ALL, NULL,
g_cclosure_new_object (
(GCallback) on_link_activated, G_OBJECT (transition)));
}

View file

@ -233,7 +233,7 @@ test_link_error (TestFixture *f, gconstpointer data)
"link.input.node", "invalid",
NULL)));
g_assert_nonnull (proxy);
wp_object_activate (WP_OBJECT (proxy), WP_PIPEWIRE_OBJECT_FEATURES_MINIMAL,
wp_object_activate (WP_OBJECT (proxy), WP_OBJECT_FEATURES_ALL,
NULL, (GAsyncReadyCallback) activate_error_cb, f);
g_main_loop_run (f->base.loop);
}