lib: refactor WpProxy
This is an attempt to unclutter the API of WpProxy and split functionality into smaller pieces, making it easier to work with. In this new class layout, we have the following classes: - WpObject: base class for everything; handles activating | and deactivating "features" |- WpProxy: base class for anything that wraps a pw_proxy; | handles events from pw_proxy and nothing more |- WpGlobalProxy: handles integration with the registry All the other classes derive from WpGlobalProxy. The reason for separating WpGlobalProxy from WpProxy, though, is that classes such as WpImplNode / WpSpaDevice can also derive from WpProxy now, without interfacing with the registry. All objects that come with an "info" structure and have properties and/or params also implement the WpPipewireObject interface. This provides the API to query properties and get/set params. Essentially, this is implemented by all classes except WpMetadata (pw_metadata does not have info) This interface is implemented on each object separately, using a private "mixin", which is a set of vfunc implementations and helper functions (and macros) to facilitate the implementation of this interface. A notable difference to the old WpProxy is that now features can be deactivated, so it is possible to enable something and later disable it again. This commit disables modules, tests, tools, etc, to avoid growing the patch more, while ensuring that the project compiles.
This commit is contained in:
258
lib/wp/private/pipewire-object-mixin.c
Normal file
258
lib/wp/private/pipewire-object-mixin.c
Normal file
@@ -0,0 +1,258 @@
|
||||
/* WirePlumber
|
||||
*
|
||||
* Copyright © 2020 Collabora Ltd.
|
||||
* @author George Kiagiadakis <george.kiagiadakis@collabora.com>
|
||||
*
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
#define G_LOG_DOMAIN "wp-pw-obj-mixin"
|
||||
|
||||
#include "private/pipewire-object-mixin.h"
|
||||
#include "core.h"
|
||||
#include "error.h"
|
||||
|
||||
G_DEFINE_QUARK (WpPipewireObjectMixinEnumParamsTasks, enum_params_tasks)
|
||||
|
||||
void
|
||||
wp_pipewire_object_mixin_get_property (GObject * object, guint property_id,
|
||||
GValue * value, GParamSpec * pspec)
|
||||
{
|
||||
switch (property_id) {
|
||||
case WP_PIPEWIRE_OBJECT_MIXIN_PROP_NATIVE_INFO:
|
||||
g_value_set_pointer (value, (gpointer)
|
||||
wp_pipewire_object_get_native_info (WP_PIPEWIRE_OBJECT (object)));
|
||||
break;
|
||||
case WP_PIPEWIRE_OBJECT_MIXIN_PROP_PROPERTIES:
|
||||
g_value_set_boxed (value,
|
||||
wp_pipewire_object_get_properties (WP_PIPEWIRE_OBJECT (object)));
|
||||
break;
|
||||
case WP_PIPEWIRE_OBJECT_MIXIN_PROP_PARAM_INFO:
|
||||
g_value_set_variant (value,
|
||||
wp_pipewire_object_get_param_info (WP_PIPEWIRE_OBJECT (object)));
|
||||
break;
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
wp_pipewire_object_mixin_class_override_properties (GObjectClass * klass)
|
||||
{
|
||||
g_object_class_override_property (klass,
|
||||
WP_PIPEWIRE_OBJECT_MIXIN_PROP_NATIVE_INFO, "native-info");
|
||||
g_object_class_override_property (klass,
|
||||
WP_PIPEWIRE_OBJECT_MIXIN_PROP_PROPERTIES, "properties");
|
||||
g_object_class_override_property (klass,
|
||||
WP_PIPEWIRE_OBJECT_MIXIN_PROP_PARAM_INFO, "param-info");
|
||||
}
|
||||
|
||||
static const struct {
|
||||
gint param_id;
|
||||
WpObjectFeatures feature;
|
||||
} feature_mappings[] = {
|
||||
{ SPA_PARAM_Props, WP_PIPEWIRE_OBJECT_FEATURE_PARAM_PROPS },
|
||||
{ SPA_PARAM_Format, WP_PIPEWIRE_OBJECT_FEATURE_PARAM_FORMAT },
|
||||
{ SPA_PARAM_Profile, WP_PIPEWIRE_OBJECT_FEATURE_PARAM_PROFILE },
|
||||
{ SPA_PARAM_PortConfig, WP_PIPEWIRE_OBJECT_FEATURE_PARAM_PORT_CONFIG },
|
||||
{ SPA_PARAM_Route, WP_PIPEWIRE_OBJECT_FEATURE_PARAM_ROUTE },
|
||||
};
|
||||
|
||||
WpObjectFeatures
|
||||
wp_pipewire_object_mixin_param_info_to_features (struct spa_param_info * info,
|
||||
guint n_params)
|
||||
{
|
||||
WpObjectFeatures ft = 0;
|
||||
|
||||
for (gint i = 0; i < n_params; i++) {
|
||||
for (gint j = 0; j < G_N_ELEMENTS (feature_mappings); j++) {
|
||||
if (info[i].id == feature_mappings[j].param_id &&
|
||||
info[i].flags & SPA_PARAM_INFO_READ)
|
||||
ft |= feature_mappings[j].feature;
|
||||
}
|
||||
}
|
||||
return ft;
|
||||
}
|
||||
|
||||
guint
|
||||
wp_pipewire_object_mixin_activate_get_next_step (WpObject * object,
|
||||
WpFeatureActivationTransition * transition, guint step,
|
||||
WpObjectFeatures missing)
|
||||
{
|
||||
/* bind if not already bound */
|
||||
if (missing & WP_PROXY_FEATURE_BOUND)
|
||||
return WP_PIPEWIRE_OBJECT_MIXIN_STEP_BIND;
|
||||
/* then cache info */
|
||||
else
|
||||
return WP_PIPEWIRE_OBJECT_MIXIN_STEP_CACHE_INFO;
|
||||
|
||||
/* returning to STEP_NONE is handled by WpFeatureActivationTransition */
|
||||
}
|
||||
|
||||
void
|
||||
wp_pipewire_object_mixin_cache_info (WpObject * object,
|
||||
WpFeatureActivationTransition * transition)
|
||||
{
|
||||
/* TODO */
|
||||
}
|
||||
|
||||
void
|
||||
wp_pipewire_object_mixin_deactivate (WpObject * object,
|
||||
WpObjectFeatures features)
|
||||
{
|
||||
/* TODO */
|
||||
}
|
||||
|
||||
static gint
|
||||
task_has_seq (gconstpointer task, gconstpointer seq)
|
||||
{
|
||||
gpointer t_seq = g_task_get_source_tag (G_TASK (task));
|
||||
return (GPOINTER_TO_INT (t_seq) == GPOINTER_TO_INT (seq)) ? 0 : 1;
|
||||
}
|
||||
|
||||
void
|
||||
wp_pipewire_object_mixin_handle_event_param (gpointer instance, int seq,
|
||||
uint32_t id, uint32_t index, uint32_t next, const struct spa_pod *param)
|
||||
{
|
||||
g_autoptr (WpSpaPod) w_param = wp_spa_pod_new_wrap_const (param);
|
||||
GList *list;
|
||||
GTask *task;
|
||||
|
||||
list = g_object_get_qdata (G_OBJECT (instance), enum_params_tasks_quark ());
|
||||
list = g_list_find_custom (list, GINT_TO_POINTER (seq), task_has_seq);
|
||||
task = list ? G_TASK (list->data) : NULL;
|
||||
|
||||
if (task) {
|
||||
GPtrArray *array = g_task_get_task_data (task);
|
||||
g_ptr_array_add (array, wp_spa_pod_copy (w_param));
|
||||
}
|
||||
}
|
||||
|
||||
GVariant *
|
||||
wp_pipewire_object_mixin_param_info_to_gvariant (struct spa_param_info * info,
|
||||
guint n_params)
|
||||
{
|
||||
g_auto (GVariantBuilder) b =
|
||||
G_VARIANT_BUILDER_INIT (G_VARIANT_TYPE_DICTIONARY);
|
||||
|
||||
if (!info || n_params == 0)
|
||||
return NULL;
|
||||
|
||||
for (guint i = 0; i < n_params; i++) {
|
||||
const gchar *nick = NULL;
|
||||
gchar flags[3];
|
||||
guint flags_idx = 0;
|
||||
|
||||
wp_spa_type_get_by_id (WP_SPA_TYPE_TABLE_PARAM, info[i].id, NULL, &nick,
|
||||
NULL);
|
||||
g_return_val_if_fail (nick != NULL, NULL);
|
||||
|
||||
if (info[i].flags & SPA_PARAM_INFO_READ)
|
||||
flags[flags_idx++] = 'r';
|
||||
if (info[i].flags & SPA_PARAM_INFO_WRITE)
|
||||
flags[flags_idx++] = 'w';
|
||||
flags[flags_idx] = '\0';
|
||||
|
||||
g_variant_builder_add (&b, "{ss}", nick, flags);
|
||||
}
|
||||
|
||||
return g_variant_builder_end (&b);
|
||||
}
|
||||
|
||||
WpIterator *
|
||||
wp_pipewire_object_mixin_enum_params_finish (WpPipewireObject * obj,
|
||||
GAsyncResult * res, GError ** error)
|
||||
{
|
||||
g_return_val_if_fail (g_task_is_valid (res, obj), NULL);
|
||||
|
||||
GPtrArray *array = g_task_propagate_pointer (G_TASK (res), error);
|
||||
if (!array)
|
||||
return NULL;
|
||||
|
||||
return wp_iterator_new_ptr_array (array, WP_TYPE_SPA_POD);
|
||||
}
|
||||
|
||||
WpIterator *
|
||||
wp_pipewire_object_mixin_enum_cached_params (WpPipewireObject * obj,
|
||||
const gchar * id)
|
||||
{
|
||||
return NULL; //TODO
|
||||
}
|
||||
|
||||
void
|
||||
wp_pipewire_object_mixin_enum_params_unimplemented (WpPipewireObject * obj,
|
||||
const gchar * id, WpSpaPod *filter, GCancellable * cancellable,
|
||||
GAsyncReadyCallback callback, gpointer user_data)
|
||||
{
|
||||
wp_pipewire_object_mixin_create_enum_params_task (obj, 0, cancellable,
|
||||
callback, user_data);
|
||||
}
|
||||
|
||||
void
|
||||
wp_pipewire_object_mixin_set_param_unimplemented (WpPipewireObject * obj,
|
||||
const gchar * id, WpSpaPod * param)
|
||||
{
|
||||
wp_warning_object (obj,
|
||||
"setting params is not implemented on this object type");
|
||||
}
|
||||
|
||||
static void
|
||||
enum_params_done (WpCore * core, GAsyncResult * res, gpointer data)
|
||||
{
|
||||
g_autoptr (GTask) task = G_TASK (data);
|
||||
g_autoptr (GError) error = NULL;
|
||||
gpointer instance = g_task_get_source_object (G_TASK (data));
|
||||
GList *list;
|
||||
|
||||
/* finish the sync task */
|
||||
wp_core_sync_finish (core, res, &error);
|
||||
|
||||
/* remove the task from the stored list; ref is held by the g_autoptr */
|
||||
list = g_object_get_qdata (G_OBJECT (instance), enum_params_tasks_quark ());
|
||||
list = g_list_remove (list, instance);
|
||||
g_object_set_qdata (G_OBJECT (instance), enum_params_tasks_quark (), list);
|
||||
|
||||
if (error)
|
||||
g_task_return_error (task, g_steal_pointer (&error));
|
||||
else {
|
||||
GPtrArray *params = g_task_get_task_data (task);
|
||||
g_task_return_pointer (task, g_ptr_array_ref (params),
|
||||
(GDestroyNotify) g_ptr_array_unref);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
wp_pipewire_object_mixin_create_enum_params_task (gpointer instance,
|
||||
gint seq, GCancellable * cancellable, GAsyncReadyCallback callback,
|
||||
gpointer user_data)
|
||||
{
|
||||
g_autoptr (GTask) task = NULL;
|
||||
GPtrArray *params;
|
||||
GList *list;
|
||||
|
||||
/* create task */
|
||||
task = g_task_new (instance, cancellable, callback, user_data);
|
||||
params = g_ptr_array_new_with_free_func ((GDestroyNotify) wp_spa_pod_unref);
|
||||
g_task_set_task_data (task, params, (GDestroyNotify) g_ptr_array_unref);
|
||||
g_task_set_source_tag (task, GINT_TO_POINTER (seq));
|
||||
|
||||
/* return early if seq contains an error */
|
||||
if (G_UNLIKELY (SPA_RESULT_IS_ERROR (seq))) {
|
||||
wp_message_object (instance, "enum_params failed: %s", spa_strerror (seq));
|
||||
g_task_return_new_error (task, WP_DOMAIN_LIBRARY,
|
||||
WP_LIBRARY_ERROR_OPERATION_FAILED, "enum_params failed: %s",
|
||||
spa_strerror (seq));
|
||||
return;
|
||||
}
|
||||
|
||||
/* store */
|
||||
list = g_object_get_qdata (G_OBJECT (instance), enum_params_tasks_quark ());
|
||||
list = g_list_append (list, g_object_ref (task));
|
||||
g_object_set_qdata (G_OBJECT (instance), enum_params_tasks_quark (), list);
|
||||
|
||||
/* call sync */
|
||||
g_autoptr (WpCore) core = wp_object_get_core (WP_OBJECT (instance));
|
||||
wp_core_sync (core, cancellable, (GAsyncReadyCallback) enum_params_done,
|
||||
task);
|
||||
}
|
Reference in New Issue
Block a user