mirror of
https://gitlab.freedesktop.org/pipewire/wireplumber.git
synced 2026-05-20 21:08:18 +02:00
lib: implement WpSessionItem base class
This commit is contained in:
parent
5f169d190f
commit
32dd485649
4 changed files with 489 additions and 0 deletions
|
|
@ -16,6 +16,7 @@ wp_lib_sources = files(
|
|||
'properties.c',
|
||||
'proxy.c',
|
||||
'session.c',
|
||||
'session-item.c',
|
||||
'spa-props.c',
|
||||
'transition.c',
|
||||
)
|
||||
|
|
@ -39,6 +40,7 @@ wp_lib_headers = files(
|
|||
'properties.h',
|
||||
'proxy.h',
|
||||
'session.h',
|
||||
'session-item.h',
|
||||
'transition.h',
|
||||
'wp.h',
|
||||
)
|
||||
|
|
|
|||
354
lib/wp/session-item.c
Normal file
354
lib/wp/session-item.c
Normal file
|
|
@ -0,0 +1,354 @@
|
|||
/* WirePlumber
|
||||
*
|
||||
* Copyright © 2020 Collabora Ltd.
|
||||
* @author George Kiagiadakis <george.kiagiadakis@collabora.com>
|
||||
*
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
/**
|
||||
* SECTION: WpSessionItem
|
||||
*/
|
||||
|
||||
#include "session-item.h"
|
||||
#include "wpenums.h"
|
||||
|
||||
typedef struct _WpSessionItemPrivate WpSessionItemPrivate;
|
||||
struct _WpSessionItemPrivate
|
||||
{
|
||||
GWeakRef session;
|
||||
guint32 flags;
|
||||
};
|
||||
|
||||
enum {
|
||||
SIGNAL_FLAGS_CHANGED,
|
||||
N_SIGNALS
|
||||
};
|
||||
|
||||
guint32 signals[N_SIGNALS] = {0};
|
||||
|
||||
G_DEFINE_ABSTRACT_TYPE_WITH_PRIVATE (WpSessionItem, wp_session_item, G_TYPE_OBJECT)
|
||||
|
||||
static void
|
||||
wp_session_item_init (WpSessionItem * self)
|
||||
{
|
||||
WpSessionItemPrivate *priv =
|
||||
wp_session_item_get_instance_private (self);
|
||||
|
||||
g_weak_ref_init (&priv->session, NULL);
|
||||
}
|
||||
|
||||
static void
|
||||
wp_session_item_dispose (GObject * object)
|
||||
{
|
||||
WpSessionItem * self = WP_SESSION_ITEM (object);
|
||||
|
||||
wp_session_item_reset (self);
|
||||
|
||||
G_OBJECT_CLASS (wp_session_item_parent_class)->dispose (object);
|
||||
}
|
||||
|
||||
static void
|
||||
wp_session_item_finalize (GObject * object)
|
||||
{
|
||||
WpSessionItem * self = WP_SESSION_ITEM (object);
|
||||
WpSessionItemPrivate *priv =
|
||||
wp_session_item_get_instance_private (self);
|
||||
|
||||
g_weak_ref_clear (&priv->session);
|
||||
|
||||
G_OBJECT_CLASS (wp_session_item_parent_class)->finalize (object);
|
||||
}
|
||||
|
||||
static void
|
||||
wp_session_item_default_reset (WpSessionItem * self)
|
||||
{
|
||||
WpSessionItemPrivate *priv =
|
||||
wp_session_item_get_instance_private (self);
|
||||
|
||||
priv->flags &= ~(WP_SI_FLAG_ACTIVE | WP_SI_FLAG_IN_ERROR);
|
||||
g_signal_emit (self, signals[SIGNAL_FLAGS_CHANGED], 0, priv->flags);
|
||||
}
|
||||
|
||||
static void
|
||||
wp_session_item_class_init (WpSessionItemClass * klass)
|
||||
{
|
||||
GObjectClass *object_class = (GObjectClass *) klass;
|
||||
|
||||
object_class->dispose = wp_session_item_dispose;
|
||||
object_class->finalize = wp_session_item_finalize;
|
||||
|
||||
klass->reset = wp_session_item_default_reset;
|
||||
|
||||
/**
|
||||
* WpSessionItem::flags-changed:
|
||||
* @self: the session item
|
||||
* @flags: the current flags
|
||||
*/
|
||||
signals[SIGNAL_FLAGS_CHANGED] = g_signal_new (
|
||||
"flags-changed", G_TYPE_FROM_CLASS (klass),
|
||||
G_SIGNAL_RUN_LAST, 0, NULL, NULL, NULL,
|
||||
G_TYPE_NONE, 1, WP_TYPE_SI_FLAGS);
|
||||
}
|
||||
|
||||
/**
|
||||
* wp_session_item_get_session:
|
||||
* @self: the session item
|
||||
*
|
||||
* Returns: (nullable) (transfer full): the session that owns this item, or
|
||||
* %NULL if this item is not part of a session
|
||||
*/
|
||||
WpSession *
|
||||
wp_session_item_get_session (WpSessionItem * self)
|
||||
{
|
||||
g_return_val_if_fail (WP_IS_SESSION_ITEM (self), NULL);
|
||||
|
||||
WpSessionItemPrivate *priv =
|
||||
wp_session_item_get_instance_private (self);
|
||||
return g_weak_ref_get (&priv->session);
|
||||
}
|
||||
|
||||
/**
|
||||
* wp_session_item_get_flags:
|
||||
* @self: the session item
|
||||
*
|
||||
* Returns: the item's flags
|
||||
*/
|
||||
WpSiFlags
|
||||
wp_session_item_get_flags (WpSessionItem * self)
|
||||
{
|
||||
g_return_val_if_fail (WP_IS_SESSION_ITEM (self), 0);
|
||||
|
||||
WpSessionItemPrivate *priv =
|
||||
wp_session_item_get_instance_private (self);
|
||||
return priv->flags;
|
||||
}
|
||||
|
||||
/**
|
||||
* wp_session_item_set_flag:
|
||||
* @self: the session item
|
||||
* @flag: the flag to set
|
||||
*
|
||||
* Sets the specified @flag on this item.
|
||||
*
|
||||
* Note that bits 1-8 cannot be set using this function, they can only
|
||||
* be changed internally.
|
||||
*/
|
||||
void
|
||||
wp_session_item_set_flag (WpSessionItem * self, WpSiFlags flag)
|
||||
{
|
||||
g_return_if_fail (WP_IS_SESSION_ITEM (self));
|
||||
|
||||
WpSessionItemPrivate *priv =
|
||||
wp_session_item_get_instance_private (self);
|
||||
|
||||
/* mask to make sure we are not changing an immutable flag */
|
||||
flag &= ~((1<<8) - 1);
|
||||
if (flag != 0) {
|
||||
priv->flags |= flag;
|
||||
g_signal_emit (self, signals[SIGNAL_FLAGS_CHANGED], 0, priv->flags);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* wp_session_item_clear_flag:
|
||||
* @self: the session item
|
||||
* @flag: the flag to clear
|
||||
*
|
||||
* Clears the specified @flag from this item.
|
||||
*
|
||||
* Note that bits 1-8 cannot be cleared using this function, they can only
|
||||
* be changed internally.
|
||||
*/
|
||||
void
|
||||
wp_session_item_clear_flag (WpSessionItem * self, WpSiFlags flag)
|
||||
{
|
||||
g_return_if_fail (WP_IS_SESSION_ITEM (self));
|
||||
|
||||
WpSessionItemPrivate *priv =
|
||||
wp_session_item_get_instance_private (self);
|
||||
|
||||
/* mask to make sure we are not changing an immutable flag */
|
||||
flag &= ~((1<<8) - 1);
|
||||
if (flag != 0) {
|
||||
priv->flags &= ~flag;
|
||||
g_signal_emit (self, signals[SIGNAL_FLAGS_CHANGED], 0, priv->flags);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* wp_session_item_get_config_spec: (virtual get_config_spec)
|
||||
* @self: the session item
|
||||
*
|
||||
* Constructs and returns a description of all the configuration options
|
||||
* that this item has. Configuration options are a way for items to accept
|
||||
* input from external sources that affects their behavior, or to provide
|
||||
* output for other items to consume as their configuration.
|
||||
*
|
||||
* The returned GVariant has the a(ssymv) type. This is an array of tuples,
|
||||
* where each tuple has the following values, in order:
|
||||
* * s (string): the name of the option
|
||||
* * s (string): a GVariant type string, describing the type of the data
|
||||
* * y (byte): a combination of #WpSiConfigOptionFlags
|
||||
* * mv (optional variant): optionally, an additional variant
|
||||
* This is provided to allow extensions.
|
||||
*
|
||||
* Returns: (transfer full): the configuration description
|
||||
*/
|
||||
GVariant *
|
||||
wp_session_item_get_config_spec (WpSessionItem * self)
|
||||
{
|
||||
g_return_val_if_fail (WP_IS_SESSION_ITEM (self), NULL);
|
||||
g_return_val_if_fail (WP_SESSION_ITEM_GET_CLASS (self)->get_config_spec,
|
||||
NULL);
|
||||
|
||||
return WP_SESSION_ITEM_GET_CLASS (self)->get_config_spec (self);
|
||||
}
|
||||
|
||||
/**
|
||||
* wp_session_item_configure: (virtual configure)
|
||||
* @self: the session item
|
||||
* @args: (transfer floating): the configuration options to set
|
||||
* (`a{sv}` dictionary, mapping option names to values)
|
||||
*
|
||||
* Returns: %TRUE on success, %FALSE if the options could not be set
|
||||
*/
|
||||
gboolean
|
||||
wp_session_item_configure (WpSessionItem * self, GVariant * args)
|
||||
{
|
||||
g_return_val_if_fail (WP_IS_SESSION_ITEM (self), FALSE);
|
||||
g_return_val_if_fail (WP_SESSION_ITEM_GET_CLASS (self)->configure,
|
||||
FALSE);
|
||||
g_return_val_if_fail (g_variant_is_of_type (args, G_VARIANT_TYPE ("a{sv}")),
|
||||
FALSE);
|
||||
|
||||
return WP_SESSION_ITEM_GET_CLASS (self)->configure (self, args);
|
||||
}
|
||||
|
||||
/**
|
||||
* wp_session_item_get_configuration: (virtual get_configuration)
|
||||
* @self: the session item
|
||||
*
|
||||
* Returns: (transfer full): the active configuration, as a `a{sv}` dictionary
|
||||
*/
|
||||
GVariant *
|
||||
wp_session_item_get_configuration (WpSessionItem * self)
|
||||
{
|
||||
g_return_val_if_fail (WP_IS_SESSION_ITEM (self), NULL);
|
||||
g_return_val_if_fail (WP_SESSION_ITEM_GET_CLASS (self)->get_configuration,
|
||||
NULL);
|
||||
|
||||
return WP_SESSION_ITEM_GET_CLASS (self)->get_configuration (self);
|
||||
}
|
||||
|
||||
typedef WpTransition WpSiTransition;
|
||||
typedef WpTransitionClass WpSiTransitionClass;
|
||||
|
||||
G_DEFINE_TYPE (WpSiTransition, wp_si_transition, WP_TYPE_TRANSITION)
|
||||
|
||||
static void
|
||||
wp_si_transition_init (WpSiTransition * transition) {}
|
||||
|
||||
static guint
|
||||
wp_si_transition_get_next_step (WpTransition * transition, guint step)
|
||||
{
|
||||
WpSessionItem *item = wp_transition_get_source_object (transition);
|
||||
g_return_val_if_fail (
|
||||
WP_SESSION_ITEM_GET_CLASS (item)->get_next_step,
|
||||
WP_TRANSITION_STEP_ERROR);
|
||||
g_return_val_if_fail (
|
||||
WP_SESSION_ITEM_GET_CLASS (item)->execute_step,
|
||||
WP_TRANSITION_STEP_ERROR);
|
||||
|
||||
return WP_SESSION_ITEM_GET_CLASS (item)->get_next_step (item,
|
||||
transition, step);
|
||||
}
|
||||
|
||||
static void
|
||||
wp_si_transition_execute_step (WpTransition * transition, guint step)
|
||||
{
|
||||
WpSessionItem *item = wp_transition_get_source_object (transition);
|
||||
WP_SESSION_ITEM_GET_CLASS (item)->execute_step (item, transition, step);
|
||||
}
|
||||
|
||||
static void
|
||||
wp_si_transition_class_init (WpSiTransitionClass * klass)
|
||||
{
|
||||
WpTransitionClass *transition_class = (WpTransitionClass *) klass;
|
||||
|
||||
transition_class->get_next_step = wp_si_transition_get_next_step;
|
||||
transition_class->execute_step = wp_si_transition_execute_step;
|
||||
}
|
||||
|
||||
static void
|
||||
on_transition_completed (WpTransition * transition, GParamSpec * pspec,
|
||||
WpSessionItem * self)
|
||||
{
|
||||
WpSessionItemPrivate *priv =
|
||||
wp_session_item_get_instance_private (self);
|
||||
|
||||
if (wp_transition_had_error (transition))
|
||||
priv->flags |= WP_SI_FLAG_IN_ERROR;
|
||||
else
|
||||
priv->flags |= WP_SI_FLAG_ACTIVE;
|
||||
|
||||
priv->flags &= ~WP_SI_FLAG_ACTIVATING;
|
||||
g_signal_emit (self, signals[SIGNAL_FLAGS_CHANGED], 0, priv->flags);
|
||||
}
|
||||
|
||||
/**
|
||||
* wp_session_item_activate:
|
||||
* @self: the session item
|
||||
* @callback: (scope async): a callback to call when activation is finished
|
||||
* @callback_data: (closure): data passed to @callback
|
||||
*
|
||||
* Activates the item asynchronously. This internally starts a #WpTransition
|
||||
* that calls into #WpSessionItemClass.get_next_step() and
|
||||
* #WpSessionItemClass.execute_step() to advance.
|
||||
*
|
||||
* You can use wp_transition_finish() in the @callback to figure out the
|
||||
* result of this operation.
|
||||
*
|
||||
* Normally this function is called internally by the session; there is no need
|
||||
* to activate an item externally, except for unit testing purposes.
|
||||
*/
|
||||
void
|
||||
wp_session_item_activate (WpSessionItem * self,
|
||||
GAsyncReadyCallback callback,
|
||||
gpointer callback_data)
|
||||
{
|
||||
g_return_if_fail (WP_IS_SESSION_ITEM (self));
|
||||
|
||||
WpSessionItemPrivate *priv =
|
||||
wp_session_item_get_instance_private (self);
|
||||
|
||||
g_return_if_fail (!(priv->flags & (WP_SI_FLAG_ACTIVATING | WP_SI_FLAG_ACTIVE)));
|
||||
|
||||
/* TODO: add a way to cancel the transition if reset() is called in the meantime */
|
||||
WpTransition *transition = wp_transition_new (wp_si_transition_get_type (),
|
||||
self, NULL, callback, callback_data);
|
||||
wp_transition_set_source_tag (transition, wp_session_item_activate);
|
||||
g_signal_connect (transition, "notify::completed",
|
||||
(GCallback) on_transition_completed, self);
|
||||
|
||||
priv->flags |= WP_SI_FLAG_ACTIVATING;
|
||||
g_signal_emit (self, signals[SIGNAL_FLAGS_CHANGED], 0, priv->flags);
|
||||
|
||||
wp_transition_advance (transition);
|
||||
}
|
||||
|
||||
/**
|
||||
* wp_session_item_reset: (virtual reset)
|
||||
* @self: the session item
|
||||
*
|
||||
* Resets the state of the item, deactivating it, and possibly
|
||||
* resetting configuration options as well.
|
||||
*/
|
||||
void
|
||||
wp_session_item_reset (WpSessionItem * self)
|
||||
{
|
||||
g_return_if_fail (WP_IS_SESSION_ITEM (self));
|
||||
g_return_if_fail (WP_SESSION_ITEM_GET_CLASS (self)->reset);
|
||||
|
||||
WP_SESSION_ITEM_GET_CLASS (self)->reset (self);
|
||||
}
|
||||
132
lib/wp/session-item.h
Normal file
132
lib/wp/session-item.h
Normal file
|
|
@ -0,0 +1,132 @@
|
|||
/* WirePlumber
|
||||
*
|
||||
* Copyright © 2020 Collabora Ltd.
|
||||
* @author George Kiagiadakis <george.kiagiadakis@collabora.com>
|
||||
*
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
#ifndef __WIREPLUMBER_SESSION_ITEM_H__
|
||||
#define __WIREPLUMBER_SESSION_ITEM_H__
|
||||
|
||||
#include "transition.h"
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
typedef struct _WpSession WpSession;
|
||||
|
||||
/**
|
||||
* WP_TYPE_SESSION_ITEM:
|
||||
*
|
||||
* The #WpSessionItem #GType
|
||||
*/
|
||||
#define WP_TYPE_SESSION_ITEM (wp_session_item_get_type ())
|
||||
WP_API
|
||||
G_DECLARE_DERIVABLE_TYPE (WpSessionItem, wp_session_item,
|
||||
WP, SESSION_ITEM, GObject)
|
||||
|
||||
/**
|
||||
* WpSiFlags:
|
||||
* @WP_SI_FLAG_ACTIVATING: set when an activation transition is in progress
|
||||
* @WP_SI_FLAG_ACTIVE: set when an activation transition completes successfully
|
||||
* @WP_SI_FLAG_EXPORTED: set when the item has exported all necessary objects
|
||||
* to PipeWire
|
||||
* @WP_SI_FLAG_IN_ERROR: set when there was an error in the activation process;
|
||||
* to recover, the handler must call wp_session_item_reset() before anything
|
||||
* else
|
||||
* @WP_SI_FLAG_CONFIGURED: must be set by subclasses when all the required
|
||||
* (%WP_SI_CONFIG_OPTION_REQUIRED) configuration options have been set
|
||||
*/
|
||||
typedef enum {
|
||||
/* immutable flags, set internally */
|
||||
WP_SI_FLAG_ACTIVATING = (1<<0),
|
||||
WP_SI_FLAG_ACTIVE = (1<<1),
|
||||
WP_SI_FLAG_EXPORTED = (1<<2),
|
||||
WP_SI_FLAG_IN_ERROR = (1<<3),
|
||||
|
||||
/* flags that can be changed by subclasses */
|
||||
WP_SI_FLAG_CONFIGURED = (1<<8),
|
||||
|
||||
/* implementation-specific flags */
|
||||
WP_SI_FLAG_CUSTOM_START = (1<<16),
|
||||
} WpSiFlags;
|
||||
|
||||
/**
|
||||
* WpSiConfigOptionFlags:
|
||||
* @WP_SI_CONFIG_OPTION_WRITEABLE: the option can be set externally
|
||||
* @WP_SI_CONFIG_OPTION_REQUIRED: the option is required to complete activation
|
||||
* @WP_SI_CONFIG_OPTION_PROVIDED: the value of this option can be provided
|
||||
* by the implementation if it is not set externally; this can be used to
|
||||
* have a "default fallback" value or to report immutable configuration
|
||||
* that is discovered from an underlying layer (ex. hardware properties)
|
||||
*/
|
||||
typedef enum {
|
||||
WP_SI_CONFIG_OPTION_WRITEABLE = (1<<0),
|
||||
WP_SI_CONFIG_OPTION_REQUIRED = (1<<1),
|
||||
WP_SI_CONFIG_OPTION_PROVIDED = (1<<2),
|
||||
} WpSiConfigOptionFlags;
|
||||
|
||||
/**
|
||||
* WpSessionItemClass:
|
||||
* @get_config_spec: See wp_session_item_get_config_spec()
|
||||
* @configure: See wp_session_item_configure()
|
||||
* @get_configuration: See wp_session_item_get_configuration()
|
||||
* @get_next_step: Implements #WpTransitionClass.get_next_step() for the
|
||||
* transition of wp_session_item_activate()
|
||||
* @execute_step: Implements #WpTransitionClass.execute_step() for the
|
||||
* transition of wp_session_item_activate()
|
||||
* @reset: See wp_session_item_reset()
|
||||
*/
|
||||
struct _WpSessionItemClass
|
||||
{
|
||||
GObjectClass parent_class;
|
||||
|
||||
GVariant * (*get_config_spec) (WpSessionItem * self);
|
||||
gboolean (*configure) (WpSessionItem * self, GVariant * args);
|
||||
GVariant * (*get_configuration) (WpSessionItem * self);
|
||||
|
||||
guint (*get_next_step) (WpSessionItem * self, WpTransition * transition,
|
||||
guint step);
|
||||
void (*execute_step) (WpSessionItem * self, WpTransition * transition,
|
||||
guint step);
|
||||
|
||||
void (*reset) (WpSessionItem * self);
|
||||
};
|
||||
|
||||
/* properties */
|
||||
|
||||
WP_API
|
||||
WpSession * wp_session_item_get_session (WpSessionItem * self);
|
||||
|
||||
WP_API
|
||||
WpSiFlags wp_session_item_get_flags (WpSessionItem * self);
|
||||
|
||||
WP_API
|
||||
void wp_session_item_set_flag (WpSessionItem * self, WpSiFlags flag);
|
||||
|
||||
WP_API
|
||||
void wp_session_item_clear_flag (WpSessionItem * self, WpSiFlags flag);
|
||||
|
||||
/* configuration */
|
||||
|
||||
WP_API
|
||||
GVariant * wp_session_item_get_config_spec (WpSessionItem * self);
|
||||
|
||||
WP_API
|
||||
gboolean wp_session_item_configure (WpSessionItem * self, GVariant * args);
|
||||
|
||||
WP_API
|
||||
GVariant * wp_session_item_get_configuration (WpSessionItem * self);
|
||||
|
||||
/* state management */
|
||||
|
||||
WP_API
|
||||
void wp_session_item_activate (WpSessionItem * self,
|
||||
GAsyncReadyCallback callback, gpointer callback_data);
|
||||
|
||||
WP_API
|
||||
void wp_session_item_reset (WpSessionItem * self);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif
|
||||
|
|
@ -23,5 +23,6 @@
|
|||
#include "properties.h"
|
||||
#include "proxy.h"
|
||||
#include "session.h"
|
||||
#include "session-item.h"
|
||||
#include "transition.h"
|
||||
#include "wpenums.h"
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue