wireplumber/lib/wp/private/pipewire-object-mixin.c

259 lines
7.6 KiB
C
Raw Normal View History

/* 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);
}