Merge branch 'error-handling' into 'master'

Error handling and fixes

See merge request gkiagia/wireplumber!21
This commit is contained in:
George Kiagiadakis 2019-07-25 12:33:08 +03:00
commit ecfcbd7b6d
13 changed files with 289 additions and 83 deletions

View file

@ -6,6 +6,7 @@
* SPDX-License-Identifier: MIT
*/
#include "error.h"
#include "proxy-link.h"
#include <pipewire/pipewire.h>
@ -15,7 +16,7 @@ struct _WpProxyLink
/* The task to signal the proxy is initialized */
GTask *init_task;
/* The link proxy listener */
struct spa_hook listener;
@ -69,6 +70,22 @@ wp_proxy_link_finalize (GObject * object)
G_OBJECT_CLASS (wp_proxy_link_parent_class)->finalize (object);
}
static void
wp_proxy_link_destroy (WpProxy * proxy)
{
WpProxyLink *self = WP_PROXY_LINK(proxy);
GError *error = NULL;
/* Return error if the pipewire destruction happened while the async creation
* of this proxy link object has not finished */
if (self->init_task) {
g_set_error (&error, WP_DOMAIN_LIBRARY, WP_LIBRARY_ERROR_OPERATION_FAILED,
"pipewire link proxy destroyed before finishing");
g_task_return_error (self->init_task, error);
g_clear_object (&self->init_task);
}
}
static void
wp_proxy_link_init_async (GAsyncInitable *initable, int io_priority,
GCancellable *cancellable, GAsyncReadyCallback callback, gpointer data)
@ -105,8 +122,11 @@ static void
wp_proxy_link_class_init (WpProxyLinkClass * klass)
{
GObjectClass *object_class = (GObjectClass *) klass;
WpProxyClass *proxy_class = (WpProxyClass *) klass;
object_class->finalize = wp_proxy_link_finalize;
proxy_class->destroy = wp_proxy_link_destroy;
}
void

View file

@ -6,6 +6,7 @@
* SPDX-License-Identifier: MIT
*/
#include "error.h"
#include "proxy-node.h"
#include <pipewire/pipewire.h>
@ -15,7 +16,7 @@ struct _WpProxyNode
/* The task to signal the proxy is initialized */
GTask *init_task;
/* The node proxy listener */
struct spa_hook listener;
@ -69,6 +70,22 @@ wp_proxy_node_finalize (GObject * object)
G_OBJECT_CLASS (wp_proxy_node_parent_class)->finalize (object);
}
static void
wp_proxy_node_destroy (WpProxy * proxy)
{
WpProxyNode *self = WP_PROXY_NODE(proxy);
GError *error = NULL;
/* Return error if the pipewire destruction happened while the async creation
* of this proxy node object has not finished */
if (self->init_task) {
g_set_error (&error, WP_DOMAIN_LIBRARY, WP_LIBRARY_ERROR_OPERATION_FAILED,
"pipewire node proxy destroyed before finishing");
g_task_return_error (self->init_task, error);
g_clear_object (&self->init_task);
}
}
static void
wp_proxy_node_init_async (GAsyncInitable *initable, int io_priority,
GCancellable *cancellable, GAsyncReadyCallback callback, gpointer data)
@ -105,8 +122,11 @@ static void
wp_proxy_node_class_init (WpProxyNodeClass * klass)
{
GObjectClass *object_class = (GObjectClass *) klass;
WpProxyClass *proxy_class = (WpProxyClass *) klass;
object_class->finalize = wp_proxy_node_finalize;
proxy_class->destroy = wp_proxy_node_destroy;
}
void

View file

@ -6,6 +6,7 @@
* SPDX-License-Identifier: MIT
*/
#include "error.h"
#include "proxy-port.h"
#include <pipewire/pipewire.h>
#include <spa/param/audio/format-utils.h>
@ -99,6 +100,22 @@ wp_proxy_port_finalize (GObject * object)
G_OBJECT_CLASS (wp_proxy_port_parent_class)->finalize (object);
}
static void
wp_proxy_port_destroy (WpProxy * proxy)
{
WpProxyPort *self = WP_PROXY_PORT(proxy);
GError *error = NULL;
/* Return error if the pipewire destruction happened while the async creation
* of this proxy port object has not finished */
if (self->init_task) {
g_set_error (&error, WP_DOMAIN_LIBRARY, WP_LIBRARY_ERROR_OPERATION_FAILED,
"pipewire port proxy destroyed before finishing");
g_task_return_error (self->init_task, error);
g_clear_object (&self->init_task);
}
}
static void
wp_proxy_port_init_async (GAsyncInitable *initable, int io_priority,
GCancellable *cancellable, GAsyncReadyCallback callback, gpointer data)
@ -139,8 +156,11 @@ static void
wp_proxy_port_class_init (WpProxyPortClass * klass)
{
GObjectClass *object_class = (GObjectClass *) klass;
WpProxyClass *proxy_class = (WpProxyClass *) klass;
object_class->finalize = wp_proxy_port_finalize;
proxy_class->destroy = wp_proxy_port_destroy;
}
void

View file

@ -46,10 +46,15 @@ G_DEFINE_ABSTRACT_TYPE_WITH_CODE (WpProxy, wp_proxy, G_TYPE_OBJECT,
static void
proxy_event_destroy (void *data)
{
WpProxyPrivate *self = wp_proxy_get_instance_private (WP_PROXY(data));
WpProxy *self = WP_PROXY (data);
WpProxyPrivate *priv = wp_proxy_get_instance_private (self);
/* Set the proxy to NULL */
self->proxy = NULL;
priv->proxy = NULL;
/* Call the destroy method */
if (WP_PROXY_GET_CLASS (self)->destroy)
WP_PROXY_GET_CLASS (self)->destroy (self);
}
static void
@ -68,24 +73,24 @@ static const struct pw_proxy_events proxy_events = {
static void
wp_proxy_constructed (GObject * object)
{
WpProxyPrivate *self = wp_proxy_get_instance_private (WP_PROXY(object));
WpProxyPrivate *priv = wp_proxy_get_instance_private (WP_PROXY(object));
/* Add the event listener */
pw_proxy_add_listener (self->proxy, &self->listener, &proxy_events, object);
pw_proxy_add_listener (priv->proxy, &priv->listener, &proxy_events, object);
}
static void
wp_proxy_finalize (GObject * object)
{
WpProxyPrivate *self = wp_proxy_get_instance_private (WP_PROXY(object));
WpProxyPrivate *priv = wp_proxy_get_instance_private (WP_PROXY(object));
g_debug ("%s:%p destroyed (pw proxy %p)", G_OBJECT_TYPE_NAME (object),
object, self->proxy);
object, priv->proxy);
/* Destroy the proxy */
if (self->proxy) {
pw_proxy_destroy (self->proxy);
self->proxy = NULL;
if (priv->proxy) {
pw_proxy_destroy (priv->proxy);
priv->proxy = NULL;
}
G_OBJECT_CLASS (wp_proxy_parent_class)->finalize (object);
@ -95,14 +100,14 @@ static void
wp_proxy_set_property (GObject * object, guint property_id,
const GValue * value, GParamSpec * pspec)
{
WpProxyPrivate *self = wp_proxy_get_instance_private (WP_PROXY(object));
WpProxyPrivate *priv = wp_proxy_get_instance_private (WP_PROXY(object));
switch (property_id) {
case PROP_GLOBAL_ID:
self->global_id = g_value_get_uint (value);
priv->global_id = g_value_get_uint (value);
break;
case PROP_PROXY:
self->proxy = g_value_get_pointer (value);
priv->proxy = g_value_get_pointer (value);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
@ -114,14 +119,14 @@ static void
wp_proxy_get_property (GObject * object, guint property_id, GValue * value,
GParamSpec * pspec)
{
WpProxyPrivate *self = wp_proxy_get_instance_private (WP_PROXY(object));
WpProxyPrivate *priv = wp_proxy_get_instance_private (WP_PROXY(object));
switch (property_id) {
case PROP_GLOBAL_ID:
g_value_set_uint (value, self->global_id);
g_value_set_uint (value, priv->global_id);
break;
case PROP_PROXY:
g_value_set_pointer (value, self->proxy);
g_value_set_pointer (value, priv->proxy);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);

View file

@ -23,6 +23,9 @@ struct _WpProxyClass
{
GObjectClass parent_class;
/* Methods */
void (*destroy) (WpProxy * self);
/* Signals */
void (*done)(WpProxy *wp_proxy, gpointer data);
};

View file

@ -229,9 +229,11 @@ simple_endpoint_link_create (WpEndpointLink * epl, GVariant * src_data,
if (in_direction == PW_DIRECTION_OUTPUT)
continue;
/* Skip the port if it is already linked */
/* Skip the ports if they are already linked */
if (g_hash_table_contains (linked_ports, GUINT_TO_POINTER(in_id)))
continue;
if (g_hash_table_contains (linked_ports, GUINT_TO_POINTER(out_id)))
continue;
/* Create the properties */
props = pw_properties_new(NULL, NULL);
@ -248,8 +250,9 @@ simple_endpoint_link_create (WpEndpointLink * epl, GVariant * src_data,
self);
self->link_count++;
/* Insert the port id in the hash table to know it is linked */
/* Insert the port ids in the hash tables to know they are linked */
g_hash_table_insert (linked_ports, GUINT_TO_POINTER(in_id), NULL);
g_hash_table_insert (linked_ports, GUINT_TO_POINTER(out_id), NULL);
/* Clean up */
pw_properties_free(props);

View file

@ -31,6 +31,7 @@ struct _WpPipewireSimpleEndpoint
/* The task to signal the endpoint is initialized */
GTask *init_task;
gboolean init_abort;
/* The remote pipewire */
WpRemotePipewire *remote_pipewire;
@ -74,6 +75,37 @@ G_DEFINE_TYPE_WITH_CODE (WpPipewireSimpleEndpoint, simple_endpoint,
G_IMPLEMENT_INTERFACE (G_TYPE_ASYNC_INITABLE,
wp_simple_endpoint_async_initable_init))
typedef GObject* (*WpObjectNewFinishFunc)(GObject *initable, GAsyncResult *res,
GError **error);
static GObject *
object_safe_new_finish(WpPipewireSimpleEndpoint * self, GObject *initable,
GAsyncResult *res, WpObjectNewFinishFunc new_finish_func)
{
GObject *object = NULL;
GError *error = NULL;
/* Return NULL if we are already aborting */
if (self->init_abort)
return NULL;
/* Get the object */
object = G_OBJECT (new_finish_func (initable, res, &error));
g_return_val_if_fail (object, NULL);
/* Check for error */
if (error) {
g_clear_object (&object);
g_warning ("WpPipewireSimpleEndpoint:%p Aborting construction", self);
self->init_abort = TRUE;
g_task_return_error (self->init_task, error);
g_clear_object (&self->init_task);
return NULL;
}
return object;
}
static void
node_proxy_param (void *object, int seq, uint32_t id,
uint32_t index, uint32_t next, const struct spa_pod *param)
@ -146,8 +178,10 @@ on_proxy_port_created(GObject *initable, GAsyncResult *res, gpointer data)
WpProxyPort *proxy_port = NULL;
/* Get the proxy port */
proxy_port = wp_proxy_port_new_finish(initable, res, NULL);
g_return_if_fail (proxy_port);
proxy_port = WP_PROXY_PORT (object_safe_new_finish (self, initable, res,
(WpObjectNewFinishFunc)wp_proxy_port_new_finish));
if (!proxy_port)
return;
/* Add the proxy port to the array */
g_return_if_fail (self->proxies_port);
@ -168,6 +202,10 @@ on_port_added(WpRemotePipewire *rp, guint id, guint parent_id, gconstpointer p,
WpPipewireSimpleEndpoint *self = d;
struct pw_port_proxy *port_proxy = NULL;
/* Don't do anything if we are aborting */
if (self->init_abort)
return;
/* Only handle ports owned by this endpoint */
if (parent_id != self->global_id)
return;
@ -185,23 +223,22 @@ emit_endpoint_ports(WpPipewireSimpleEndpoint *self)
struct pw_node_proxy* node_proxy = NULL;
struct spa_audio_info_raw format = { 0, };
struct spa_pod *param;
struct spa_pod_builder pod_builder = { 0, };
char buf[1024];
struct spa_pod_builder pod_builder = SPA_POD_BUILDER_INIT(buf, sizeof(buf));
/* Get the pipewire node proxy */
node_proxy = wp_proxy_get_pw_proxy(WP_PROXY(self->proxy_node));
g_return_if_fail (node_proxy);
/* TODO: Assume all clients have this format for now */
/* The default format for audio clients */
format.format = SPA_AUDIO_FORMAT_F32P;
format.flags = 1;
format.rate = 48000;
format.channels = 2;
format.position[0] = 0;
format.position[1] = 0;
format.position[0] = SPA_AUDIO_CHANNEL_FL;
format.position[1] = SPA_AUDIO_CHANNEL_FR;
/* Build the param profile */
spa_pod_builder_init(&pod_builder, buf, sizeof(buf));
param = spa_format_audio_raw_build(&pod_builder, SPA_PARAM_Format, &format);
param = spa_pod_builder_add_object(&pod_builder,
SPA_TYPE_OBJECT_ParamProfile, SPA_PARAM_Profile,
@ -222,8 +259,10 @@ on_proxy_node_created(GObject *initable, GAsyncResult *res, gpointer data)
struct pw_node_proxy *node_proxy = NULL;
/* Get the proxy node */
self->proxy_node = wp_proxy_node_new_finish(initable, res, NULL);
g_return_if_fail (self->proxy_node);
self->proxy_node = WP_PROXY_NODE (object_safe_new_finish (self, initable,
res, (WpObjectNewFinishFunc)wp_proxy_node_new_finish));
if (!self->proxy_node)
return;
self->role = g_strdup (spa_dict_lookup (
wp_proxy_node_get_info (self->proxy_node)->props, "media.role"));
@ -319,6 +358,7 @@ wp_simple_endpoint_async_initable_init (gpointer iface, gpointer iface_data)
static void
simple_endpoint_init (WpPipewireSimpleEndpoint * self)
{
self->init_abort = FALSE;
}
static void

View file

@ -29,11 +29,18 @@ on_endpoint_created(GObject *initable, GAsyncResult *res, gpointer d)
struct impl *impl = d;
WpEndpoint *endpoint = NULL;
guint global_id = 0;
GError *error = NULL;
/* Get the endpoint */
endpoint = wp_endpoint_new_finish(initable, res, NULL);
if (!endpoint)
g_return_if_fail (endpoint);
/* Check for error */
if (error) {
g_clear_object (&endpoint);
g_warning ("Failed to create alsa endpoint: %s", error->message);
return;
}
/* Get the endpoint global id */
g_object_get (endpoint, "global-id", &global_id, NULL);

View file

@ -27,11 +27,18 @@ on_endpoint_created(GObject *initable, GAsyncResult *res, gpointer d)
struct module_data *data = d;
WpEndpoint *endpoint = NULL;
guint global_id = 0;
GError *error = NULL;
/* Get the endpoint */
endpoint = wp_endpoint_new_finish(initable, res, NULL);
if (!endpoint)
g_return_if_fail (endpoint);
/* Check for error */
if (error) {
g_clear_object (&endpoint);
g_warning ("Failed to create client endpoint: %s", error->message);
return;
}
/* Get the endpoint global id */
g_object_get (endpoint, "global-id", &global_id, NULL);

View file

@ -38,6 +38,7 @@ struct _WpPwAudioSoftdspEndpoint
/* The task to signal the endpoint is initialized */
GTask *init_task;
gboolean init_abort;
/* The remote pipewire */
WpRemotePipewire *remote_pipewire;
@ -71,6 +72,37 @@ G_DEFINE_TYPE_WITH_CODE (WpPwAudioSoftdspEndpoint, endpoint, WP_TYPE_ENDPOINT,
G_IMPLEMENT_INTERFACE (G_TYPE_ASYNC_INITABLE,
wp_endpoint_async_initable_init))
typedef GObject* (*WpObjectNewFinishFunc)(GObject *initable, GAsyncResult *res,
GError **error);
static GObject *
object_safe_new_finish(WpPwAudioSoftdspEndpoint * self, GObject *initable,
GAsyncResult *res, WpObjectNewFinishFunc new_finish_func)
{
GObject *object = NULL;
GError *error = NULL;
/* Return NULL if we are already aborting */
if (self->init_abort)
return NULL;
/* Get the object */
object = G_OBJECT (new_finish_func (initable, res, &error));
g_return_val_if_fail (object, NULL);
/* Check for error */
if (error) {
g_clear_object (&object);
g_warning ("WpPwAudioSoftdspEndpoint:%p Aborting construction", self);
self->init_abort = TRUE;
g_task_return_error (self->init_task, error);
g_clear_object (&self->init_task);
return NULL;
}
return object;
}
static gboolean
endpoint_prepare_link (WpEndpoint * ep, guint32 stream_id,
WpEndpointLink * link, GVariant ** properties, GError ** error)
@ -110,8 +142,10 @@ on_audio_dsp_stream_created(GObject *initable, GAsyncResult *res, gpointer data)
g_autofree gchar *name = NULL;
/* Get the stream */
dsp = wp_pw_audio_dsp_new_finish(initable, res, NULL);
g_return_if_fail (dsp);
dsp = WP_PW_AUDIO_DSP (object_safe_new_finish (self, initable, res,
(WpObjectNewFinishFunc)wp_pw_audio_dsp_new_finish));
if (!dsp)
return;
/* Get the stream id */
g_object_get (dsp, "id", &stream_id, "name", &name, NULL);
@ -135,27 +169,26 @@ on_audio_dsp_converter_created(GObject *initable, GAsyncResult *res,
WpPwAudioSoftdspEndpoint *self = data;
g_autoptr (WpCore) core = wp_endpoint_get_core(WP_ENDPOINT(self));
const struct pw_node_info *target = NULL;
const struct spa_audio_info_raw *format = NULL;
GVariantDict d;
GVariantIter iter;
const gchar *stream;
int i;
/* Get the proxy dsp converter */
self->converter = wp_pw_audio_dsp_new_finish(initable, res, NULL);
g_return_if_fail (self->converter);
self->converter = WP_PW_AUDIO_DSP (object_safe_new_finish (self, initable,
res, (WpObjectNewFinishFunc)wp_pw_audio_dsp_new_finish));
if (!self->converter)
return;
/* Get the target and format */
target = wp_pw_audio_dsp_get_info (self->converter);
g_return_if_fail (target);
g_object_get (self->converter, "format", &format, NULL);
g_return_if_fail (format);
/* Create the audio dsp streams */
g_variant_iter_init (&iter, self->streams);
for (i = 0; g_variant_iter_next (&iter, "&s", &stream); i++) {
wp_pw_audio_dsp_new (WP_ENDPOINT(self), i, stream, self->direction,
FALSE, target, format, on_audio_dsp_stream_created, self);
wp_pw_audio_dsp_new (WP_ENDPOINT(self), i, stream, self->direction, FALSE,
target, on_audio_dsp_stream_created, self);
/* Register the stream */
g_variant_dict_init (&d, NULL);
@ -174,11 +207,12 @@ on_proxy_node_created(GObject *initable, GAsyncResult *res, gpointer data)
g_autofree gchar *name = NULL;
const struct spa_dict *props;
const struct pw_node_info *target = NULL;
const struct spa_audio_info_raw *format = NULL;
/* Get the proxy node */
self->proxy_node = wp_proxy_node_new_finish(initable, res, NULL);
g_return_if_fail (self->proxy_node);
self->proxy_node = WP_PROXY_NODE (object_safe_new_finish (self, initable,
res, (WpObjectNewFinishFunc)wp_proxy_node_new_finish));
if (!self->proxy_node)
return;
/* Give a proper name to this endpoint based on ALSA properties */
props = wp_proxy_node_get_info (self->proxy_node)->props;
@ -192,13 +226,8 @@ on_proxy_node_created(GObject *initable, GAsyncResult *res, gpointer data)
/* Create the converter proxy */
target = wp_proxy_node_get_info (self->proxy_node);
g_return_if_fail (target);
format = wp_proxy_port_get_format (self->proxy_port);
g_return_if_fail (format);
/* TODO: For now we create convert as a stream because convert mode does not
* generate any ports, not sure why */
wp_pw_audio_dsp_new (WP_ENDPOINT(self), WP_STREAM_ID_NONE, "master",
self->direction, TRUE, target, format, on_audio_dsp_converter_created,
self);
self->direction, TRUE, target, on_audio_dsp_converter_created, self);
}
static void
@ -208,8 +237,10 @@ on_proxy_port_created(GObject *initable, GAsyncResult *res, gpointer data)
struct pw_node_proxy *node_proxy = NULL;
/* Get the proxy port */
self->proxy_port = wp_proxy_port_new_finish(initable, res, NULL);
g_return_if_fail (self->proxy_port);
self->proxy_port = WP_PROXY_PORT (object_safe_new_finish (self, initable, res,
(WpObjectNewFinishFunc)wp_proxy_port_new_finish));
if (!self->proxy_port)
return;
/* Create the proxy node async */
node_proxy = wp_remote_pipewire_proxy_bind (self->remote_pipewire,
@ -225,6 +256,10 @@ on_port_added(WpRemotePipewire *rp, guint id, guint parent_id, gconstpointer p,
WpPwAudioSoftdspEndpoint *self = d;
struct pw_port_proxy *port_proxy = NULL;
/* Don't do anything if we are aborting */
if (self->init_abort)
return;
/* Check if it is a node port and handle it */
if (self->global_id != parent_id)
return;
@ -407,6 +442,7 @@ wp_endpoint_async_initable_init (gpointer iface, gpointer iface_data)
static void
endpoint_init (WpPwAudioSoftdspEndpoint * self)
{
self->init_abort = FALSE;
self->dsps = g_ptr_array_new_with_free_func (g_object_unref);
}

View file

@ -24,7 +24,6 @@ enum {
PROP_DIRECTION,
PROP_CONVERT,
PROP_TARGET,
PROP_FORMAT,
};
enum {
@ -39,6 +38,7 @@ struct _WpPwAudioDsp
/* The task to signal the audio dsp is initialized */
GTask *init_task;
gboolean init_abort;
/* The remote pipewire */
WpRemotePipewire *remote_pipewire;
@ -50,7 +50,6 @@ struct _WpPwAudioDsp
enum pw_direction direction;
gboolean convert;
const struct pw_node_info *target;
const struct spa_audio_info_raw *format;
/* All ports handled by the port added callback */
GHashTable *handled_ports;
@ -58,7 +57,7 @@ struct _WpPwAudioDsp
/* Proxies */
WpProxyNode *proxy;
GPtrArray *port_proxies;
struct pw_proxy *link_proxy;
WpProxyLink *link_proxy;
/* Listener */
struct spa_hook listener;
@ -75,6 +74,37 @@ G_DEFINE_TYPE_WITH_CODE (WpPwAudioDsp, wp_pw_audio_dsp, G_TYPE_OBJECT,
G_IMPLEMENT_INTERFACE (G_TYPE_ASYNC_INITABLE,
wp_pw_audio_dsp_async_initable_init))
typedef GObject* (*WpObjectNewFinishFunc)(GObject *initable, GAsyncResult *res,
GError **error);
static GObject *
object_safe_new_finish(WpPwAudioDsp * self, GObject *initable,
GAsyncResult *res, WpObjectNewFinishFunc new_finish_func)
{
GObject *object = NULL;
GError *error = NULL;
/* Return NULL if we are already aborting */
if (self->init_abort)
return NULL;
/* Get the object */
object = G_OBJECT (new_finish_func (initable, res, &error));
g_return_val_if_fail (object, NULL);
/* Check for error */
if (error) {
g_clear_object (&object);
g_warning ("WpPwAudioDsp:%p Aborting construction", self);
self->init_abort = TRUE;
g_task_return_error (self->init_task, error);
g_clear_object (&self->init_task);
return NULL;
}
return object;
}
guint
wp_pw_audio_dsp_id_encode (guint stream_id, guint control_id)
{
@ -147,8 +177,10 @@ on_audio_dsp_port_created(GObject *initable, GAsyncResult *res,
WpProxyPort *port_proxy = NULL;
/* Get the proxy port */
port_proxy = wp_proxy_port_new_finish(initable, res, NULL);
g_return_if_fail (port_proxy);
port_proxy = WP_PROXY_PORT (object_safe_new_finish (self, initable, res,
(WpObjectNewFinishFunc)wp_proxy_port_new_finish));
if (!port_proxy)
return;
/* Add the proxy port to the array */
g_return_if_fail (self->port_proxies);
@ -164,6 +196,10 @@ handled_ports_foreach_func (gpointer key, gpointer value, gpointer data)
const guint id = GPOINTER_TO_INT (key);
const guint parent_id = GPOINTER_TO_INT (value);
/* Don't do anything if we are aborting */
if (self->init_abort)
return;
/* Get the dsp info */
g_return_if_fail (self->proxy);
dsp_info = wp_proxy_node_get_info(self->proxy);
@ -218,11 +254,23 @@ on_audio_dsp_port_added(WpRemotePipewire *rp, guint id, guint parent_id,
GUINT_TO_POINTER(parent_id));
}
static void
on_proxy_link_created(GObject *initable, GAsyncResult *res, gpointer data)
{
WpPwAudioDsp *self = data;
/* Get the link */
self->link_proxy = WP_PROXY_LINK (object_safe_new_finish (self, initable,
res, (WpObjectNewFinishFunc)wp_proxy_link_new_finish));
g_return_if_fail (self->link_proxy);
}
static void
on_audio_dsp_running(WpPwAudioDsp *self)
{
struct pw_properties *props;
const struct pw_node_info *dsp_info = NULL;
struct pw_proxy *proxy = NULL;
/* Return if the node has already been linked */
if (self->link_proxy)
@ -252,8 +300,10 @@ on_audio_dsp_running(WpPwAudioDsp *self)
g_debug ("%p linking DSP to node", self);
/* Create the link */
self->link_proxy = wp_remote_pipewire_create_object(self->remote_pipewire,
proxy = wp_remote_pipewire_create_object(self->remote_pipewire,
"link-factory", PW_TYPE_INTERFACE_Link, &props->dict);
wp_proxy_link_new (pw_proxy_get_id(proxy), proxy, on_proxy_link_created,
self);
/* Clean up */
pw_properties_free(props);
@ -262,10 +312,8 @@ on_audio_dsp_running(WpPwAudioDsp *self)
static void
on_audio_dsp_idle (WpPwAudioDsp *self)
{
if (self->link_proxy != NULL) {
pw_proxy_destroy (self->link_proxy);
self->link_proxy = NULL;
}
/* Clear the proxy */
g_clear_object (&self->link_proxy);
}
static void
@ -351,12 +399,14 @@ on_audio_dsp_proxy_created(GObject *initable, GAsyncResult *res,
struct pw_node_proxy *pw_proxy = NULL;
struct spa_audio_info_raw format;
uint8_t buf[1024];
struct spa_pod_builder pod_builder = { 0, };
struct spa_pod_builder pod_builder = SPA_POD_BUILDER_INIT(buf, sizeof(buf));
struct spa_pod *param;
/* Get the audio dsp proxy */
self->proxy = wp_proxy_node_new_finish(initable, res, NULL);
g_return_if_fail (self->proxy);
self->proxy = WP_PROXY_NODE (object_safe_new_finish (self, initable,
res, (WpObjectNewFinishFunc)wp_proxy_node_new_finish));
if (!self->proxy)
return;
/* Add a custom dsp listener */
pw_proxy = wp_proxy_get_pw_proxy(WP_PROXY(self->proxy));
@ -368,12 +418,15 @@ on_audio_dsp_proxy_created(GObject *initable, GAsyncResult *res,
pw_node_proxy_enum_params (pw_proxy, 0, SPA_PARAM_Props, 0, -1, NULL);
if (!self->convert) {
/* Get the port format */
g_return_if_fail (self->format);
format = *self->format;
/* Use the default format */
format.format = SPA_AUDIO_FORMAT_F32P;
format.flags = 1;
format.rate = 48000;
format.channels = 2;
format.position[0] = SPA_AUDIO_CHANNEL_FL;
format.position[1] = SPA_AUDIO_CHANNEL_FR;
/* Emit the ports */
spa_pod_builder_init(&pod_builder, buf, sizeof(buf));
param = spa_format_audio_raw_build(&pod_builder, SPA_PARAM_Format, &format);
param = spa_pod_builder_add_object(&pod_builder,
SPA_TYPE_OBJECT_ParamProfile, SPA_PARAM_Profile,
@ -413,6 +466,9 @@ wp_pw_audio_dsp_finalize (GObject * object)
self->port_proxies = NULL;
}
/* Destroy the link proxy */
g_clear_object (&self->link_proxy);
G_OBJECT_CLASS (wp_pw_audio_dsp_parent_class)->finalize (object);
}
@ -441,9 +497,6 @@ wp_pw_audio_dsp_set_property (GObject * object, guint property_id,
case PROP_TARGET:
self->target = g_value_get_pointer(value);
break;
case PROP_FORMAT:
self->format = g_value_get_pointer(value);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
break;
@ -475,9 +528,6 @@ wp_pw_audio_dsp_get_property (GObject * object, guint property_id,
case PROP_TARGET:
g_value_set_pointer (value, (gpointer)self->target);
break;
case PROP_FORMAT:
g_value_set_pointer (value, (gpointer)self->format);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
break;
@ -561,6 +611,7 @@ wp_pw_audio_dsp_async_initable_init (gpointer iface, gpointer iface_data)
static void
wp_pw_audio_dsp_init (WpPwAudioDsp * self)
{
self->init_abort = FALSE;
}
static void
@ -595,17 +646,12 @@ wp_pw_audio_dsp_class_init (WpPwAudioDspClass * klass)
g_param_spec_pointer ("target", "target",
"The target node info of the audio DSP",
G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS));
g_object_class_install_property (object_class, PROP_FORMAT,
g_param_spec_pointer ("format", "format",
"The format of the audio DSP ports",
G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS));
}
void
wp_pw_audio_dsp_new (WpEndpoint *endpoint, guint id, const char *name,
enum pw_direction direction, gboolean convert,
const struct pw_node_info *target, const struct spa_audio_info_raw *format,
GAsyncReadyCallback callback,
const struct pw_node_info *target, GAsyncReadyCallback callback,
gpointer user_data)
{
g_async_initable_new_async (
@ -617,7 +663,6 @@ wp_pw_audio_dsp_new (WpEndpoint *endpoint, guint id, const char *name,
"direction", direction,
"convert", convert,
"target", target,
"format", format,
NULL);
}

View file

@ -20,8 +20,8 @@ void wp_pw_audio_dsp_id_decode (guint id, guint *stream_id, guint *control_id);
void wp_pw_audio_dsp_new (WpEndpoint *endpoint, guint id, const char *name,
enum pw_direction direction, gboolean convert,
const struct pw_node_info *target, const struct spa_audio_info_raw *format,
GAsyncReadyCallback callback, gpointer user_data);
const struct pw_node_info *target, GAsyncReadyCallback callback,
gpointer user_data);
WpPwAudioDsp * wp_pw_audio_dsp_new_finish (GObject *initable, GAsyncResult *res,
GError **error);

View file

@ -471,7 +471,7 @@ simple_policy_find_endpoint (WpPolicy *policy, GVariant *props,
}
/* If not found, return the first endpoint */
ep = (ptr_array->len > 1) ?
ep = (ptr_array->len > 0) ?
g_object_ref (g_ptr_array_index (ptr_array, 0)) : NULL;
select_stream: