Commit fbf8de84 authored by Julian Bouzas's avatar Julian Bouzas

modules: replace dsp class with stream, adapter and convert classes

parent 8d58243f
......@@ -65,7 +65,9 @@ shared_library(
'wireplumber-module-pw-audio-softdsp-endpoint',
[
'module-pw-audio-softdsp-endpoint.c',
'module-pw-audio-softdsp-endpoint/dsp.c',
'module-pw-audio-softdsp-endpoint/stream.c',
'module-pw-audio-softdsp-endpoint/adapter.c',
'module-pw-audio-softdsp-endpoint/convert.c',
],
c_args : [common_c_args, '-DG_LOG_DOMAIN="m-pw-audio-softdsp-endpoint"'],
install : true,
......
......@@ -246,12 +246,13 @@ emit_endpoint_ports(WpPipewireSimpleEndpoint *self)
/* Build the param profile */
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,
SPA_PARAM_PROFILE_direction, SPA_POD_Id(self->direction),
SPA_PARAM_PROFILE_format, SPA_POD_Pod(param));
SPA_TYPE_OBJECT_ParamPortConfig, SPA_PARAM_PortConfig,
SPA_PARAM_PORT_CONFIG_direction, SPA_POD_Id(self->direction),
SPA_PARAM_PORT_CONFIG_mode, SPA_POD_Id(SPA_PARAM_PORT_CONFIG_MODE_dsp),
SPA_PARAM_PORT_CONFIG_format, SPA_POD_Pod(param));
/* Set the param profile to emit the ports */
pw_node_proxy_set_param(node_proxy, SPA_PARAM_Profile, 0, param);
pw_node_proxy_set_param(node_proxy, SPA_PARAM_PortConfig, 0, param);
}
static void
......
......@@ -103,13 +103,13 @@ on_node_added(WpRemotePipewire *rp, guint id, guint parent_id, gconstpointer p,
/* Make sure the node has properties */
g_return_if_fail(props);
/* Get the name and media_class */
/* Get the media_class */
media_class = spa_dict_lookup(props, "media.class");
/* Make sure the media class is non-dsp audio */
/* Make sure the media class is non-convert audio */
if (!g_str_has_prefix (media_class, "Audio/"))
return;
if (g_str_has_prefix (media_class, "Audio/DSP"))
if (g_str_has_prefix (media_class, "Audio/Convert"))
return;
/* Get the name */
......
This diff is collapsed.
/* WirePlumber
*
* Copyright © 2019 Collabora Ltd.
* @author Julian Bouzas <julian.bouzas@collabora.com>
*
* SPDX-License-Identifier: MIT
*/
#include <pipewire/pipewire.h>
#include <spa/param/audio/format-utils.h>
#include <spa/pod/builder.h>
#include <spa/param/props.h>
#include "adapter.h"
enum {
PROP_0,
PROP_ADAPTER_ID,
PROP_CONVERT,
};
struct _WpAudioAdapter
{
WpAudioStream parent;
/* The task to signal the proxy is initialized */
GTask *init_task;
gboolean init_abort;
/* Props */
guint adapter_id;
gboolean convert;
/* Proxies */
WpProxyNode *proxy;
};
static GAsyncInitableIface *wp_audio_adapter_parent_interface = NULL;
static void wp_audio_adapter_async_initable_init (gpointer iface,
gpointer iface_data);
G_DEFINE_TYPE_WITH_CODE (WpAudioAdapter, wp_audio_adapter, WP_TYPE_AUDIO_STREAM,
G_IMPLEMENT_INTERFACE (G_TYPE_ASYNC_INITABLE,
wp_audio_adapter_async_initable_init))
typedef GObject* (*WpObjectNewFinishFunc)(GObject *initable, GAsyncResult *res,
GError **error);
static GObject *
object_safe_new_finish(WpAudioAdapter * 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 ("WpAudioAdapter:%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
on_audio_adapter_done(WpProxy *proxy, gpointer data)
{
WpAudioAdapter *self = data;
/* Don't do anything if the audio adapter has already been initialized */
if (!self->init_task)
return;
/* Finish the creation of the audio adapter */
g_task_return_boolean (self->init_task, TRUE);
g_clear_object(&self->init_task);
}
static void
on_audio_adapter_proxy_created(GObject *initable, GAsyncResult *res,
gpointer data)
{
WpAudioAdapter *self = data;
enum pw_direction direction =
wp_audio_stream_get_direction ( WP_AUDIO_STREAM (self));
struct pw_node_proxy *pw_proxy = NULL;
uint8_t buf[1024];
struct spa_pod_builder pod_builder = SPA_POD_BUILDER_INIT(buf, sizeof(buf));
struct spa_pod *param;
/* Get the adapter proxy */
self->proxy = WP_PROXY_NODE (object_safe_new_finish (self, initable,
res, (WpObjectNewFinishFunc)wp_proxy_node_new_finish));
if (!self->proxy)
return;
/* Get the pipewire proxy */
pw_proxy = wp_proxy_get_pw_proxy(WP_PROXY(self->proxy));
g_return_if_fail (pw_proxy);
/* Emit the props param */
pw_node_proxy_enum_params (pw_proxy, 0, SPA_PARAM_Props, 0, -1, NULL);
/* Emit the ports */
if (self->convert) {
param = spa_pod_builder_add_object(&pod_builder,
SPA_TYPE_OBJECT_ParamPortConfig, SPA_PARAM_PortConfig,
SPA_PARAM_PORT_CONFIG_direction, SPA_POD_Id(direction),
SPA_PARAM_PORT_CONFIG_mode, SPA_POD_Id(SPA_PARAM_PORT_CONFIG_MODE_convert));
pw_node_proxy_set_param(pw_proxy, SPA_PARAM_PortConfig, 0, param);
} else {
struct spa_audio_info_raw format;
spa_zero(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;
param = spa_format_audio_raw_build(&pod_builder, SPA_PARAM_Format, &format);
param = spa_pod_builder_add_object(&pod_builder,
SPA_TYPE_OBJECT_ParamPortConfig, SPA_PARAM_PortConfig,
SPA_PARAM_PORT_CONFIG_direction, SPA_POD_Id(direction),
SPA_PARAM_PORT_CONFIG_mode, SPA_POD_Id(SPA_PARAM_PORT_CONFIG_MODE_dsp),
SPA_PARAM_PORT_CONFIG_format, SPA_POD_Pod(param));
pw_node_proxy_set_param(pw_proxy, SPA_PARAM_PortConfig, 0, param);
}
/* Register a callback to know when all the adapter ports have been emitted */
g_signal_connect_object(self->proxy, "done", (GCallback)on_audio_adapter_done,
self, 0);
wp_proxy_sync (WP_PROXY(self->proxy));
}
static gpointer
wp_audio_adapter_create_proxy (WpAudioStream * as, WpRemotePipewire *rp)
{
WpAudioAdapter * self = WP_AUDIO_ADAPTER (as);
struct pw_node_proxy *proxy = NULL;
/* Create the adapter proxy by binding it */
proxy = wp_remote_pipewire_proxy_bind (rp, self->adapter_id,
PW_TYPE_INTERFACE_Node);
g_return_val_if_fail (proxy, NULL);
wp_proxy_node_new(self->adapter_id, proxy, on_audio_adapter_proxy_created,
self);
return proxy;
}
static gconstpointer
wp_audio_adapter_get_info (WpAudioStream * as)
{
WpAudioAdapter * self = WP_AUDIO_ADAPTER (as);
g_return_val_if_fail (self->proxy, NULL);
/* Return the info */
return wp_proxy_node_get_info (self->proxy);
}
static void
wp_audio_adapter_init_async (GAsyncInitable *initable, int io_priority,
GCancellable *cancellable, GAsyncReadyCallback callback, gpointer data)
{
WpAudioAdapter *self = WP_AUDIO_ADAPTER(initable);
/* Create the async task */
self->init_task = g_task_new (initable, cancellable, callback, data);
/* Call the parent interface */
wp_audio_adapter_parent_interface->init_async (initable, io_priority,
cancellable, callback, data);
}
static void
wp_audio_adapter_async_initable_init (gpointer iface, gpointer iface_data)
{
GAsyncInitableIface *ai_iface = iface;
/* Set the parent interface */
wp_audio_adapter_parent_interface = g_type_interface_peek_parent (iface);
ai_iface->init_async = wp_audio_adapter_init_async;
}
static void
wp_audio_adapter_set_property (GObject * object, guint property_id,
const GValue * value, GParamSpec * pspec)
{
WpAudioAdapter *self = WP_AUDIO_ADAPTER (object);
switch (property_id) {
case PROP_ADAPTER_ID:
self->adapter_id = g_value_get_uint(value);
break;
case PROP_CONVERT:
self->convert = g_value_get_boolean(value);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
break;
}
}
static void
wp_audio_adapter_get_property (GObject * object, guint property_id,
GValue * value, GParamSpec * pspec)
{
WpAudioAdapter *self = WP_AUDIO_ADAPTER (object);
switch (property_id) {
case PROP_ADAPTER_ID:
g_value_set_uint (value, self->adapter_id);
break;
case PROP_CONVERT:
g_value_set_boolean (value, self->convert);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
break;
}
}
static void
wp_audio_adapter_finalize (GObject * object)
{
WpAudioAdapter *self = WP_AUDIO_ADAPTER(object);
/* Destroy the proxy */
g_clear_object(&self->proxy);
G_OBJECT_CLASS (wp_audio_adapter_parent_class)->finalize (object);
}
static void
wp_audio_adapter_init (WpAudioAdapter * self)
{
self->init_abort = FALSE;
}
static void
wp_audio_adapter_class_init (WpAudioAdapterClass * klass)
{
GObjectClass *object_class = (GObjectClass *) klass;
WpAudioStreamClass *audio_stream_class = (WpAudioStreamClass *) klass;
object_class->finalize = wp_audio_adapter_finalize;
object_class->set_property = wp_audio_adapter_set_property;
object_class->get_property = wp_audio_adapter_get_property;
audio_stream_class->create_proxy = wp_audio_adapter_create_proxy;
audio_stream_class->get_info = wp_audio_adapter_get_info;
/* Install the properties */
g_object_class_install_property (object_class, PROP_ADAPTER_ID,
g_param_spec_uint ("adapter-id", "adapter-id", "The Id of the adapter", 0,
G_MAXUINT, 0,
G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS));
g_object_class_install_property (object_class, PROP_CONVERT,
g_param_spec_boolean ("convert", "convert", "Do convert only or not",
FALSE,
G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS));
}
void
wp_audio_adapter_new (WpEndpoint *endpoint, guint stream_id,
const char *stream_name, enum pw_direction direction, guint adapter_id,
gboolean convert, GAsyncReadyCallback callback, gpointer user_data)
{
g_async_initable_new_async (
WP_TYPE_AUDIO_ADAPTER, G_PRIORITY_DEFAULT, NULL, callback, user_data,
"endpoint", endpoint,
"id", stream_id,
"name", stream_name,
"direction", direction,
"adapter-id", adapter_id,
"convert", convert,
NULL);
}
guint
wp_audio_adapter_get_adapter_id (WpAudioAdapter *self)
{
return self->adapter_id;
}
gboolean
wp_audio_adapter_is_convert (WpAudioAdapter *self)
{
return self->convert;
}
/* WirePlumber
*
* Copyright © 2019 Collabora Ltd.
* @author Julian Bouzas <julian.bouzas@collabora.com>
*
* SPDX-License-Identifier: MIT
*/
#ifndef __WIREPLUMBER_AUDIO_ADAPTER_H__
#define __WIREPLUMBER_AUDIO_ADAPTER_H__
#include <gio/gio.h>
#include <wp/wp.h>
#include "stream.h"
G_BEGIN_DECLS
#define WP_TYPE_AUDIO_ADAPTER (wp_audio_adapter_get_type ())
G_DECLARE_FINAL_TYPE (WpAudioAdapter, wp_audio_adapter, WP, AUDIO_ADAPTER,
WpAudioStream)
void wp_audio_adapter_new (WpEndpoint *endpoint, guint stream_id,
const char *stream_name, enum pw_direction direction, guint adapter_id,
gboolean convert, GAsyncReadyCallback callback, gpointer user_data);
guint wp_audio_adapter_get_adapter_id (WpAudioAdapter *self);
gboolean wp_audio_adapter_is_convert (WpAudioAdapter *self);
G_END_DECLS
#endif
This diff is collapsed.
/* WirePlumber
*
* Copyright © 2019 Collabora Ltd.
* @author Julian Bouzas <julian.bouzas@collabora.com>
*
* SPDX-License-Identifier: MIT
*/
#ifndef __WIREPLUMBER_AUDIO_CONVERT_H__
#define __WIREPLUMBER_AUDIO_CONVERT_H__
#include <gio/gio.h>
#include <wp/wp.h>
#include "stream.h"
G_BEGIN_DECLS
#define WP_TYPE_AUDIO_CONVERT (wp_audio_convert_get_type ())
G_DECLARE_FINAL_TYPE (WpAudioConvert, wp_audio_convert, WP, AUDIO_CONVERT,
WpAudioStream)
void wp_audio_convert_new (WpEndpoint *endpoint, guint stream_id,
const char *stream_name, enum pw_direction direction,
const struct pw_node_info *target, GAsyncReadyCallback callback,
gpointer user_data);
const struct pw_node_info *wp_audio_convert_get_target (WpAudioConvert *self);
G_END_DECLS
#endif
/* WirePlumber
*
* Copyright © 2019 Collabora Ltd.
* @author Julian Bouzas <julian.bouzas@collabora.com>
*
* SPDX-License-Identifier: MIT
*/
#include <gio/gio.h>
#include <wp/wp.h>
#ifndef __WP_PW_AUDIO_DSP_H__
#define __WP_PW_AUDIO_DSP_H__
G_DECLARE_FINAL_TYPE (WpPwAudioDsp, wp_pw_audio_dsp,
WP_PW, AUDIO_DSP, GObject)
guint wp_pw_audio_dsp_id_encode (guint stream_id, guint control_id);
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, GAsyncReadyCallback callback,
gpointer user_data);
WpPwAudioDsp * wp_pw_audio_dsp_new_finish (GObject *initable, GAsyncResult *res,
GError **error);
const struct pw_node_info *wp_pw_audio_dsp_get_info (WpPwAudioDsp * self);
gboolean wp_pw_audio_dsp_prepare_link (WpPwAudioDsp * self,
GVariant ** properties, GError ** error);
GVariant * wp_pw_audio_dsp_get_control_value (WpPwAudioDsp * self,
guint32 control_id);
gboolean wp_pw_audio_dsp_set_control_value (WpPwAudioDsp * self,
guint32 control_id, GVariant * value);
#endif
/* WirePlumber
*
* Copyright © 2019 Collabora Ltd.
* @author Julian Bouzas <julian.bouzas@collabora.com>
*
* SPDX-License-Identifier: MIT
*/
#ifndef __WIREPLUMBER_AUDIO_STREAM_H__
#define __WIREPLUMBER_AUDIO_STREAM_H__
#include <gio/gio.h>
#include <wp/wp.h>
G_BEGIN_DECLS
guint wp_audio_stream_id_encode (guint stream_id, guint control_id);
void wp_audio_stream_id_decode (guint id, guint *stream_id, guint *control_id);
#define WP_TYPE_AUDIO_STREAM (wp_audio_stream_get_type ())
G_DECLARE_DERIVABLE_TYPE (WpAudioStream, wp_audio_stream, WP, AUDIO_STREAM, GObject)
/* The audio stream base class */
struct _WpAudioStreamClass
{
GObjectClass parent_class;
/* Methods */
gpointer (*create_proxy) (WpAudioStream * self, WpRemotePipewire *rp);
gconstpointer (*get_info) (WpAudioStream * self);
void (*event_info) (WpAudioStream * self, gconstpointer info, WpRemotePipewire *rp);
};
WpAudioStream * wp_audio_stream_new_finish (GObject *initable,
GAsyncResult *res, GError **error);
const char *wp_audio_stream_get_name (WpAudioStream * self);
enum pw_direction wp_audio_stream_get_direction (WpAudioStream * self);
gconstpointer wp_audio_stream_get_info (WpAudioStream * self);
gboolean wp_audio_stream_prepare_link (WpAudioStream * self,
GVariant ** properties, GError ** error);
GVariant * wp_audio_stream_get_control_value (WpAudioStream * self,
guint32 control_id);
gboolean wp_audio_stream_set_control_value (WpAudioStream * self,
guint32 control_id, GVariant * value);
G_END_DECLS
#endif
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment