Skip to content
GitLab
Explore
Sign in
Register
Primary navigation
Search or go to…
Project
W
wireplumber
Manage
Activity
Members
Labels
Code
Merge requests
Repository
Branches
Commits
Tags
Repository graph
Compare revisions
Snippets
Build
Pipelines
Jobs
Pipeline schedules
Artifacts
Deploy
Releases
Package registry
Model registry
Operate
Environments
Terraform modules
Analyze
Value stream analytics
Contributor analytics
CI/CD analytics
Repository analytics
Model experiments
Help
Help
Support
GitLab documentation
Compare GitLab plans
Community forum
Contribute to GitLab
Provide feedback
Terms and privacy
Keyboard shortcuts
?
Snippets
Groups
Projects
Show more breadcrumbs
pkg
wireplumber
Commits
18229e82
Commit
18229e82
authored
4 years ago
by
George Kiagiadakis
Browse files
Options
Downloads
Patches
Plain Diff
spa-device: derive from WpProxy and manage child objects internally
port module-monitor to follow the changes
parent
9d6e220e
No related branches found
Branches containing commit
No related tags found
Tags containing commit
No related merge requests found
Changes
4
Hide whitespace changes
Inline
Side-by-side
Showing
4 changed files
lib/wp/device.c
+166
-107
166 additions, 107 deletions
lib/wp/device.c
lib/wp/device.h
+15
-9
15 additions, 9 deletions
lib/wp/device.h
lib/wp/object.c
+6
-0
6 additions, 0 deletions
lib/wp/object.c
modules/module-monitor.c
+42
-135
42 additions, 135 deletions
modules/module-monitor.c
with
229 additions
and
251 deletions
lib/wp/device.c
+
166
−
107
View file @
18229e82
...
...
@@ -17,9 +17,11 @@
#include
"node.h"
#include
"core.h"
#include
"debug.h"
#include
"error.h"
#include
"private/pipewire-object-mixin.h"
#include
<pipewire/impl.h>
#include
<spa/debug/types.h>
#include
<spa/monitor/device.h>
#include
<spa/utils/result.h>
...
...
@@ -192,26 +194,23 @@ wp_device_new_from_factory (WpCore * core,
enum
{
PROP_0
,
PROP_CORE
,
PROP_SPA_DEVICE_HANDLE
,
PROP_PROPERTIES
,
};
struct
_WpSpaDevice
{
GObject
parent
;
GWeakRef
core
;
WpProxy
parent
;
struct
spa_handle
*
handle
;
struct
spa_device
*
device
;
struct
spa_hook
listener
;
WpProperties
*
properties
;
struct
pw_proxy
*
proxy
;
struct
spa_hook
proxy_listener
;
GPtrArray
*
managed_objs
;
};
enum
{
SIGNAL_OBJECT
_INFO
,
SIGNAL_
CREATE_
OBJECT
,
SPA_DEVICE_LAST_SIGNAL
,
};
...
...
@@ -224,14 +223,30 @@ static guint spa_device_signals[SPA_DEVICE_LAST_SIGNAL] = { 0 };
* loading the implementation from a SPA factory. This is useful to run device
* monitors inside the session manager and have control over creating the
* actual nodes that the `spa_device` requests to create.
*
* To enable the spa device, call wp_object_activate() requesting
* %WP_SPA_DEVICE_FEATURE_ENABLED.
*
* For actual devices (not device monitors) it also possible and desirable
* to export the device to PipeWire, which can be done by requesting
* %WP_PROXY_FEATURE_BOUND from wp_object_activate(). When exporting, the
* export should be done before enabling the device, by requesting both
* features at the same time.
*/
G_DEFINE_TYPE
(
WpSpaDevice
,
wp_spa_device
,
G_TYPE_OBJECT
)
G_DEFINE_TYPE
(
WpSpaDevice
,
wp_spa_device
,
WP_TYPE_PROXY
)
static
void
object_unref_safe
(
gpointer
object
)
{
if
(
object
)
g_object_unref
(
object
);
}
static
void
wp_spa_device_init
(
WpSpaDevice
*
self
)
{
g_weak_ref_init
(
&
self
->
core
,
NULL
);
self
->
properties
=
wp_properties_new_empty
();
self
->
managed_objs
=
g_ptr_array_new_with_free_func
(
object_unref_safe
);
}
static
void
...
...
@@ -260,11 +275,10 @@ wp_spa_device_finalize (GObject * object)
{
WpSpaDevice
*
self
=
WP_SPA_DEVICE
(
object
);
g_clear_pointer
(
&
self
->
proxy
,
pw_proxy_destroy
);
self
->
device
=
NULL
;
g_clear_pointer
(
&
self
->
handle
,
pw_unload_spa_handle
);
g_clear_pointer
(
&
self
->
properties
,
wp_properties_unref
);
g_
weak_ref_clear
(
&
self
->
co
re
);
g_
clear_pointer
(
&
self
->
managed_objs
,
g_ptr_array_un
re
f
);
G_OBJECT_CLASS
(
wp_spa_device_parent_class
)
->
finalize
(
object
);
}
...
...
@@ -276,9 +290,6 @@ wp_spa_device_set_property (GObject * object, guint property_id,
WpSpaDevice
*
self
=
WP_SPA_DEVICE
(
object
);
switch
(
property_id
)
{
case
PROP_CORE
:
g_weak_ref_set
(
&
self
->
core
,
g_value_get_object
(
value
));
break
;
case
PROP_SPA_DEVICE_HANDLE
:
self
->
handle
=
g_value_get_pointer
(
value
);
break
;
...
...
@@ -301,9 +312,6 @@ wp_spa_device_get_property (GObject * object, guint property_id, GValue * value,
WpSpaDevice
*
self
=
WP_SPA_DEVICE
(
object
);
switch
(
property_id
)
{
case
PROP_CORE
:
g_value_take_object
(
value
,
g_weak_ref_get
(
&
self
->
core
));
break
;
case
PROP_SPA_DEVICE_HANDLE
:
g_value_set_pointer
(
value
,
self
->
handle
);
break
;
...
...
@@ -336,20 +344,20 @@ spa_device_event_object_info (void *data, uint32_t id,
const
struct
spa_device_object_info
*
info
)
{
WpSpaDevice
*
self
=
WP_SPA_DEVICE
(
data
);
GType
type
=
G_TYPE_NONE
;
g_autoptr
(
WpProperties
)
props
=
NULL
;
if
(
info
)
{
if
(
!
g_strcmp0
(
info
->
type
,
SPA_TYPE_INTERFACE_Device
))
type
=
WP_TYPE_DEVICE
;
else
if
(
!
g_strcmp0
(
info
->
type
,
SPA_TYPE_INTERFACE_Node
))
type
=
WP_TYPE_NODE
;
const
gchar
*
type
;
g_autoptr
(
WpProperties
)
props
=
NULL
;
type
=
spa_debug_type_short_name
(
info
->
type
);
props
=
wp_properties_new_wrap_dict
(
info
->
props
);
}
g_signal_emit
(
self
,
spa_device_signals
[
SIGNAL_OBJECT_INFO
],
0
,
id
,
type
,
info
?
info
->
factory_name
:
NULL
,
props
,
self
->
properties
);
g_signal_emit
(
self
,
spa_device_signals
[
SIGNAL_CREATE_OBJECT
],
0
,
id
,
type
,
info
->
factory_name
,
props
);
}
else
{
wp_spa_device_store_managed_object
(
self
,
id
,
NULL
);
}
}
static
const
struct
spa_device_events
spa_device_events
=
{
...
...
@@ -358,19 +366,93 @@ static const struct spa_device_events spa_device_events = {
.
object_info
=
spa_device_event_object_info
};
static
WpObjectFeatures
wp_spa_device_get_supported_features
(
WpObject
*
object
)
{
return
WP_PROXY_FEATURE_BOUND
|
WP_SPA_DEVICE_FEATURE_ENABLED
;
}
enum
{
STEP_EXPORT
=
WP_TRANSITION_STEP_CUSTOM_START
,
STEP_ADD_DEVICE_LISTENER
,
};
static
guint
wp_spa_device_activate_get_next_step
(
WpObject
*
object
,
WpFeatureActivationTransition
*
transition
,
guint
step
,
WpObjectFeatures
missing
)
{
if
(
missing
&
WP_PROXY_FEATURE_BOUND
)
return
STEP_EXPORT
;
else
if
(
missing
&
WP_SPA_DEVICE_FEATURE_ENABLED
)
return
STEP_ADD_DEVICE_LISTENER
;
else
return
WP_TRANSITION_STEP_NONE
;
}
static
void
wp_spa_device_activate_execute_step
(
WpObject
*
object
,
WpFeatureActivationTransition
*
transition
,
guint
step
,
WpObjectFeatures
missing
)
{
WpSpaDevice
*
self
=
WP_SPA_DEVICE
(
object
);
switch
(
step
)
{
case
STEP_EXPORT
:
{
g_autoptr
(
WpCore
)
core
=
wp_object_get_core
(
object
);
struct
pw_core
*
pw_core
=
wp_core_get_pw_core
(
core
);
g_return_if_fail
(
pw_core
);
wp_proxy_set_pw_proxy
(
WP_PROXY
(
self
),
pw_core_export
(
pw_core
,
SPA_TYPE_INTERFACE_Device
,
wp_properties_peek_dict
(
self
->
properties
),
self
->
device
,
0
));
break
;
}
case
STEP_ADD_DEVICE_LISTENER
:
{
gint
res
=
spa_device_add_listener
(
self
->
device
,
&
self
->
listener
,
&
spa_device_events
,
self
);
if
(
res
<
0
)
wp_transition_return_error
(
WP_TRANSITION
(
transition
),
g_error_new
(
WP_DOMAIN_LIBRARY
,
WP_LIBRARY_ERROR_OPERATION_FAILED
,
"failed to activate device: %s"
,
spa_strerror
(
res
)));
else
wp_object_update_features
(
object
,
WP_SPA_DEVICE_FEATURE_ENABLED
,
0
);
break
;
}
default:
g_assert_not_reached
();
}
}
static
void
wp_spa_device_deactivate
(
WpObject
*
object
,
WpObjectFeatures
features
)
{
WP_OBJECT_CLASS
(
wp_spa_device_parent_class
)
->
deactivate
(
object
,
features
);
if
(
features
&
WP_SPA_DEVICE_FEATURE_ENABLED
)
{
WpSpaDevice
*
self
=
WP_SPA_DEVICE
(
object
);
spa_hook_remove
(
&
self
->
listener
);
g_ptr_array_set_size
(
self
->
managed_objs
,
0
);
wp_object_update_features
(
object
,
0
,
WP_SPA_DEVICE_FEATURE_ENABLED
);
}
}
static
void
wp_spa_device_class_init
(
WpSpaDeviceClass
*
klass
)
{
GObjectClass
*
object_class
=
(
GObjectClass
*
)
klass
;
WpObjectClass
*
wpobject_class
=
(
WpObjectClass
*
)
klass
;
object_class
->
constructed
=
wp_spa_device_constructed
;
object_class
->
finalize
=
wp_spa_device_finalize
;
object_class
->
set_property
=
wp_spa_device_set_property
;
object_class
->
get_property
=
wp_spa_device_get_property
;
g_object_class_install_property
(
object_class
,
PROP_CORE
,
g_param_spec_object
(
"core"
,
"core"
,
"The WpCore"
,
WP_TYPE_CORE
,
G_PARAM_READWRITE
|
G_PARAM_CONSTRUCT_ONLY
|
G_PARAM_STATIC_STRINGS
));
wpobject_class
->
get_supported_features
=
wp_spa_device_get_supported_features
;
wpobject_class
->
activate_get_next_step
=
wp_spa_device_activate_get_next_step
;
wpobject_class
->
activate_execute_step
=
wp_spa_device_activate_execute_step
;
wpobject_class
->
deactivate
=
wp_spa_device_deactivate
;
g_object_class_install_property
(
object_class
,
PROP_SPA_DEVICE_HANDLE
,
g_param_spec_pointer
(
"spa-device-handle"
,
"spa-device-handle"
,
...
...
@@ -383,34 +465,25 @@ wp_spa_device_class_init (WpSpaDeviceClass * klass)
G_PARAM_READWRITE
|
G_PARAM_CONSTRUCT_ONLY
|
G_PARAM_STATIC_STRINGS
));
/**
* WpSpaDevice::object
-info
:
* WpSpaDevice::
create-
object:
* @self: the #WpSpaDevice
* @id: the id of the managed object
* @type: the #WpProxy subclass type that the managed object should have,
* or %G_TYPE_NONE if the object is being destroyed
* @factory: (nullable): the name of the SPA factory to use to construct
* the managed object, or %NULL if the object is being destroyed
* @properties: (nullable): additional properties that the managed object
* should have, or %NULL if the object is being destroyed
* @parent_props: the properties of the device itself
*
* This signal is emitted when the device is creating or destroying a managed
* object. The handler is expected to actually construct or destroy the
* object using the requested SPA @factory and with the given @properties.
* @type: the SPA type that the managed object should have
* @factory: the name of the SPA factory to use to construct the managed object
* @properties: additional properties that the managed object should have
*
* The handler may also use @parent_props to enrich the properties set
* that will be assigned on the object. @parent_props contains all the
* properties that this device object has.
*
* When the object is being created, @type can either be %WP_TYPE_DEVICE
* or %WP_TYPE_NODE. The handler is free to create a substitute of those,
* like %WP_TYPE_SPA_DEVICE instead of %WP_TYPE_DEVICE, depending on the
* use case.
* This signal is emitted when the device is creating a managed object
* The handler is expected to actually construct the object using the
* requested SPA @factory and with the given @properties.
* The handler should then store the object with
* wp_spa_device_store_managed_object(). The #WpSpaDevice will later unref
* the reference stored by this function when the managed object is to be
* destroyed.
*/
spa_device_signals
[
SIGNAL_OBJECT
_INFO
]
=
g_signal_new
(
"object
-info
"
,
G_TYPE_FROM_CLASS
(
klass
),
G_SIGNAL_RUN_FIRST
,
0
,
NULL
,
NULL
,
NULL
,
G_TYPE_NONE
,
5
,
G_TYPE_UINT
,
G_TYPE_
GTYPE
,
G_TYPE_STRING
,
WP_TYPE_PROPERTIES
,
WP_TYPE_PROPERTIES
);
spa_device_signals
[
SIGNAL_
CREATE_
OBJECT
]
=
g_signal_new
(
"
create-
object"
,
G_TYPE_FROM_CLASS
(
klass
),
G_SIGNAL_RUN_FIRST
,
0
,
NULL
,
NULL
,
NULL
,
G_TYPE_NONE
,
4
,
G_TYPE_UINT
,
G_TYPE_
STRING
,
G_TYPE_STRING
,
WP_TYPE_PROPERTIES
);
}
/**
...
...
@@ -444,7 +517,7 @@ wp_spa_device_new_wrap (WpCore * core, gpointer spa_device_handle,
* @factory_name.
*
* To export this device to the PipeWire server, you need to call
* wp_
proxy_augment
() requesting %WP_PROXY_FEATURE_BOUND and
* wp_
object_activate
() requesting %WP_PROXY_FEATURE_BOUND and
* wait for the operation to complete.
*
* Returns: (nullable) (transfer full): A new #WpSpaDevice wrapping the
...
...
@@ -473,70 +546,56 @@ wp_spa_device_new_from_spa_factory (WpCore * core,
return
wp_spa_device_new_wrap
(
core
,
handle
,
g_steal_pointer
(
&
props
));
}
guint32
wp_spa_device_get_bound_id
(
WpSpaDevice
*
self
)
/**
* wp_spa_device_get_properties:
* @self: the spa device
*
* Returns: (transfer full): the device properties
*/
WpProperties
*
wp_spa_device_get_properties
(
WpSpaDevice
*
self
)
{
g_return_val_if_fail
(
WP_IS_SPA_DEVICE
(
self
),
SPA_ID_INVALID
);
return
self
->
proxy
?
pw_proxy_get_bound_id
(
self
->
proxy
)
:
SPA_ID_INVALID
;
g_return_val_if_fail
(
WP_IS_SPA_DEVICE
(
self
),
NULL
);
return
wp_properties_ref
(
self
->
properties
)
;
}
static
void
proxy_event_bound
(
void
*
data
,
uint32_t
global_id
)
/**
* wp_spa_device_get_managed_object:
* @self: the spa device
* @id: the (device-internal) id of the object to get
*
* Returns: (transfer full): the managed object associated with @id
*/
GObject
*
wp_spa_device_get_managed_object
(
WpSpaDevice
*
self
,
guint
id
)
{
GTask
*
task
=
G_TASK
(
data
);
WpSpaDevice
*
self
=
g_task_get_source_object
(
task
);
g_return_val_if_fail
(
WP_IS_SPA_DEVICE
(
self
),
NULL
);
spa_hook_remove
(
&
self
->
proxy_listener
);
g_task_return_boolean
(
task
,
TRUE
)
;
g_object_
un
ref
(
task
)
;
GObject
*
ret
=
(
id
<
self
->
managed_objs
->
len
)
?
g_ptr_array_index
(
self
->
managed_objs
,
id
)
:
NULL
;
return
ret
?
g_object_ref
(
ret
)
:
ret
;
}
static
const
struct
pw_proxy_events
proxy_events
=
{
PW_VERSION_PROXY_EVENTS
,
.
bound
=
proxy_event_bound
,
};
/**
* wp_spa_device_store_managed_object:
* @self: the spa device
* @id: the (device-internal) id of the object
* @object: (transfer full) (nullable): the object to store or %NULL to remove
* the managed object associated with @id
*/
void
wp_spa_device_
expor
t
(
WpSpaDevice
*
self
,
GCancellable
*
cancellable
,
G
AsyncReadyCallback
callback
,
gpointer
user_data
)
wp_spa_device_
store_managed_objec
t
(
WpSpaDevice
*
self
,
guint
id
,
G
Object
*
object
)
{
g_autoptr
(
GTask
)
task
=
NULL
;
g_return_if_fail
(
WP_IS_SPA_DEVICE
(
self
));
g_return_if_fail
(
!
self
->
proxy
);
g_autoptr
(
WpCore
)
core
=
g_weak_ref_get
(
&
self
->
core
);
struct
pw_core
*
pw_core
=
wp_core_get_pw_core
(
core
);
g_return_if_fail
(
pw_core
);
task
=
g_task_new
(
self
,
cancellable
,
callback
,
user_data
);
self
->
proxy
=
pw_core_export
(
pw_core
,
SPA_TYPE_INTERFACE_Device
,
wp_properties_peek_dict
(
self
->
properties
),
self
->
device
,
0
);
pw_proxy_add_listener
(
self
->
proxy
,
&
self
->
proxy_listener
,
&
proxy_events
,
g_steal_pointer
(
&
task
));
}
gboolean
wp_spa_device_export_finish
(
WpSpaDevice
*
self
,
GAsyncResult
*
res
,
GError
**
error
)
{
g_return_val_if_fail
(
WP_IS_SPA_DEVICE
(
self
),
FALSE
);
g_return_val_if_fail
(
g_task_is_valid
(
res
,
self
),
FALSE
);
return
g_task_propagate_boolean
(
G_TASK
(
res
),
error
);
}
if
(
id
>=
self
->
managed_objs
->
len
)
g_ptr_array_set_size
(
self
->
managed_objs
,
id
+
1
);
void
wp_spa_device_activate
(
WpSpaDevice
*
self
)
{
g_return_if_fail
(
WP_IS_SPA_DEVICE
(
self
));
gint
res
=
spa_device_add_listener
(
self
->
device
,
&
self
->
listener
,
&
spa_device_events
,
self
);
if
(
res
<
0
)
wp_warning_object
(
self
,
"failed to activate device: %s"
,
spa_strerror
(
res
));
/* replace the item at @id; g_ptr_array_insert is tempting to use here
instead, but it's wrong because it will not remove the previous item */
gpointer
*
ptr
=
&
g_ptr_array_index
(
self
->
managed_objs
,
id
);
if
(
*
ptr
)
g_object_unref
(
*
ptr
);
*
ptr
=
object
;
}
This diff is collapsed.
Click to expand it.
lib/wp/device.h
+
15
−
9
View file @
18229e82
...
...
@@ -30,6 +30,16 @@ WpDevice * wp_device_new_from_factory (WpCore * core,
/* WpSpaDevice */
/**
* WpSpaDeviceFeatures:
* @WP_SPA_DEVICE_FEATURE_ENABLED: enables a device
*
* Flags to be used as #WpObjectFeatures for #WpSpaDevice
*/
typedef
enum
{
/*< flags >*/
WP_SPA_DEVICE_FEATURE_ENABLED
=
(
WP_PROXY_FEATURE_CUSTOM_START
<<
0
),
}
WpSpaDeviceFeatures
;
/**
* WP_TYPE_SPA_DEVICE:
*
...
...
@@ -37,7 +47,7 @@ WpDevice * wp_device_new_from_factory (WpCore * core,
*/
#define WP_TYPE_SPA_DEVICE (wp_spa_device_get_type ())
WP_API
G_DECLARE_FINAL_TYPE
(
WpSpaDevice
,
wp_spa_device
,
WP
,
SPA_DEVICE
,
GObject
)
G_DECLARE_FINAL_TYPE
(
WpSpaDevice
,
wp_spa_device
,
WP
,
SPA_DEVICE
,
WpProxy
)
WP_API
WpSpaDevice
*
wp_spa_device_new_wrap
(
WpCore
*
core
,
...
...
@@ -48,18 +58,14 @@ WpSpaDevice * wp_spa_device_new_from_spa_factory (WpCore * core,
const
gchar
*
factory_name
,
WpProperties
*
properties
);
WP_API
guint32
wp_spa_device_get_bound_id
(
WpSpaDevice
*
self
);
WP_API
void
wp_spa_device_export
(
WpSpaDevice
*
self
,
GCancellable
*
cancellable
,
GAsyncReadyCallback
callback
,
gpointer
user_data
);
WpProperties
*
wp_spa_device_get_properties
(
WpSpaDevice
*
self
);
WP_API
gboolean
wp_spa_device_export_finish
(
WpSpaDevice
*
self
,
GAsyncResult
*
res
,
GError
**
error
);
GObject
*
wp_spa_device_get_managed_object
(
WpSpaDevice
*
self
,
guint
id
);
WP_API
void
wp_spa_device_activate
(
WpSpaDevice
*
self
);
void
wp_spa_device_store_managed_object
(
WpSpaDevice
*
self
,
guint
id
,
GObject
*
object
);
G_END_DECLS
...
...
This diff is collapsed.
Click to expand it.
lib/wp/object.c
+
6
−
0
View file @
18229e82
...
...
@@ -164,6 +164,8 @@ wp_object_dispose (GObject * object)
WpObject
*
self
=
WP_OBJECT
(
object
);
WpObjectPrivate
*
priv
=
wp_object_get_instance_private
(
self
);
wp_trace_object
(
self
,
"dispose"
);
wp_object_deactivate
(
self
,
WP_OBJECT_FEATURES_ALL
);
if
(
priv
->
idle_advnc_source
)
...
...
@@ -304,6 +306,10 @@ wp_object_get_supported_features (WpObject * self)
static
gboolean
wp_object_advance_transitions
(
WpObject
*
self
)
{
/* keep @self alive; in rare cases, the last transition may be
holding the last ref on @self and g_queue_peek_head will crash
right after droping that last ref */
g_autoptr
(
WpObject
)
self_ref
=
g_object_ref
(
self
);
WpObjectPrivate
*
priv
=
wp_object_get_instance_private
(
self
);
WpTransition
*
t
;
...
...
This diff is collapsed.
Click to expand it.
modules/module-monitor.c
+
42
−
135
View file @
18229e82
...
...
@@ -15,9 +15,6 @@
#include
<spa/monitor/device.h>
#include
<spa/pod/builder.h>
G_DEFINE_QUARK
(
wp
-
module
-
monitor
-
id
,
id
);
G_DEFINE_QUARK
(
wp
-
module
-
monitor
-
children
,
children
);
typedef
enum
{
FLAG_LOCAL_NODES
=
(
1
<<
0
),
FLAG_USE_ADAPTER
=
(
1
<<
1
),
...
...
@@ -57,10 +54,9 @@ struct _WpMonitor
G_DECLARE_FINAL_TYPE
(
WpMonitor
,
wp_monitor
,
WP
,
MONITOR
,
WpPlugin
)
G_DEFINE_TYPE
(
WpMonitor
,
wp_monitor
,
WP_TYPE_PLUGIN
)
static
void
on_object_info
(
WpSpaDevice
*
device
,
guint
id
,
GType
type
,
const
gchar
*
spa_factory
,
WpProperties
*
props
,
WpProperties
*
parent_props
,
WpMonitor
*
self
);
static
void
on_create_object
(
WpSpaDevice
*
device
,
guint
id
,
const
gchar
*
type
,
const
gchar
*
spa_factory
,
WpProperties
*
props
,
WpMonitor
*
self
);
struct
DeviceData
{
WpMonitor
*
self
;
...
...
@@ -68,7 +64,6 @@ struct DeviceData {
guint
id
;
gchar
*
spa_factory
;
WpProperties
*
props
;
WpSpaDevice
*
device
;
};
static
void
...
...
@@ -259,35 +254,14 @@ activate_done (WpObject * proxy, GAsyncResult * res, gpointer user_data)
}
static
void
free_children
(
GList
*
children
)
{
g_list_free_full
(
children
,
g_object_unref
);
}
static
void
find_child
(
GObject
*
parent
,
guint32
id
,
GList
**
children
,
GList
**
link
,
GObject
**
child
)
{
*
children
=
g_object_steal_qdata
(
parent
,
children_quark
());
/* Find the child */
for
(
*
link
=
*
children
;
*
link
!=
NULL
;
*
link
=
g_list_next
(
*
link
))
{
*
child
=
G_OBJECT
((
*
link
)
->
data
);
guint32
child_id
=
GPOINTER_TO_UINT
(
g_object_get_qdata
(
*
child
,
id_quark
()));
if
(
id
==
child_id
)
break
;
}
}
static
void
create_node
(
WpMonitor
*
self
,
WpSpaDevice
*
parent
,
GList
**
children
,
guint
id
,
const
gchar
*
spa_factory
,
WpProperties
*
props
,
WpProperties
*
parent_props
)
create_node
(
WpMonitor
*
self
,
WpSpaDevice
*
parent
,
guint
id
,
const
gchar
*
spa_factory
,
WpProperties
*
props
,
WpProperties
*
dev_props
)
{
GObject
*
node
=
NULL
;
const
gchar
*
pw_factory_name
;
wp_debug_object
(
self
,
"%s new node %u (%s)"
,
self
->
factory
,
id
,
spa_factory
);
wp_debug_object
(
self
,
WP_OBJECT_FORMAT
" new node %u (%s)"
,
WP_OBJECT_ARGS
(
parent
),
id
,
spa_factory
);
/* use the adapter instead of spa-node-factory if requested */
pw_factory_name
=
...
...
@@ -298,11 +272,11 @@ create_node (WpMonitor * self, WpSpaDevice * parent, GList ** children,
/* add device id property */
{
guint32
device_id
=
wp_
spa_device
_get_bound_id
(
parent
);
guint32
device_id
=
wp_
proxy
_get_bound_id
(
WP_PROXY
(
parent
)
)
;
wp_properties_setf
(
props
,
PW_KEY_DEVICE_ID
,
"%u"
,
device_id
);
}
setup_node_props
(
parent
_props
,
props
);
setup_node_props
(
dev
_props
,
props
);
/* create the node using the local core */
node
=
(
self
->
flags
&
FLAG_LOCAL_NODES
)
?
...
...
@@ -313,45 +287,25 @@ create_node (WpMonitor * self, WpSpaDevice * parent, GList ** children,
if
(
!
node
)
return
;
/* export to pipewire
by requesting FEATURE_BOUND
*/
/* export to pipewire */
if
(
WP_IS_IMPL_NODE
(
node
))
wp_impl_node_export
(
WP_IMPL_NODE
(
node
));
else
wp_object_activate
(
WP_OBJECT
(
node
),
WP_PIPEWIRE_OBJECT_FEATURES_MINIMAL
,
NULL
,
(
GAsyncReadyCallback
)
activate_done
,
self
);
g_object_set_qdata
(
G_OBJECT
(
node
),
id_quark
(),
GUINT_TO_POINTER
(
id
));
*
children
=
g_list_prepend
(
*
children
,
node
);
wp_spa_device_store_managed_object
(
parent
,
id
,
node
);
}
static
void
device_created
(
GObject
*
device
,
GAsyncResult
*
res
,
gpointer
user_data
)
{
WpMonitor
*
self
=
user_data
;
g_autoptr
(
GError
)
error
=
NULL
;
if
(
!
wp_spa_device_export_finish
(
WP_SPA_DEVICE
(
device
),
res
,
&
error
))
{
wp_warning_object
(
self
,
"%s"
,
error
->
message
);
return
;
}
wp_spa_device_activate
(
WP_SPA_DEVICE
(
device
));
}
static
WpSpaDevice
*
create_device
(
WpMonitor
*
self
,
WpSpaDevice
*
parent
,
guint
id
,
const
gchar
*
spa_factory
,
WpProperties
*
props
)
{
WpSpaDevice
*
device
=
NULL
;
GList
*
children
=
NULL
;
GList
*
link
=
NULL
;
GObject
*
child
=
NULL
;
const
char
*
factory_name
=
NULL
;
g_return_val_if_fail
(
parent
,
NULL
);
g_return_val_if_fail
(
spa_factory
,
NULL
);
find_child
(
G_OBJECT
(
parent
),
id
,
&
children
,
&
link
,
&
child
);
g_return_if_fail
(
parent
);
g_return_if_fail
(
spa_factory
);
factory_name
=
self
->
flags
&
FLAG_USE_ACP
?
SPA_NAME_API_ALSA_ACP_DEVICE
:
spa_factory
;
...
...
@@ -360,58 +314,31 @@ create_device (WpMonitor * self, WpSpaDevice * parent, guint id,
device
=
wp_spa_device_new_from_spa_factory
(
self
->
local_core
,
factory_name
,
props
);
if
(
!
device
)
return
NULL
;
return
;
/* Handle object
-info
singal */
g_signal_connect
(
device
,
"object
-info
"
,
(
GCallback
)
on_object
_info
,
self
);
/* Handle
create-
object singal */
g_signal_connect
(
device
,
"
create-
object"
,
(
GCallback
)
on_
create_
object
,
self
);
/* Export the device */
wp_spa_device_export
(
device
,
NULL
,
device_created
,
self
);
wp_object_activate
(
WP_OBJECT
(
device
),
WP_OBJECT_FEATURES_ALL
,
NULL
,
(
GAsyncReadyCallback
)
activate_done
,
self
);
/* Set device data */
g_object_set_qdata
(
G_OBJECT
(
device
),
id_quark
(),
GUINT_TO_POINTER
(
id
));
children
=
g_list_prepend
(
children
,
device
);
wp_spa_device_store_managed_object
(
parent
,
id
,
G_OBJECT
(
device
));
/* Set parent data */
g_object_set_qdata_full
(
G_OBJECT
(
parent
),
children_quark
(),
children
,
(
GDestroyNotify
)
free_children
);
wp_info_object
(
self
,
"device %p created"
,
device
);
return
device
;
wp_debug_object
(
self
,
"device %p created"
,
device
);
}
static
void
on_reservation_manage_device
(
GObject
*
obj
,
gboolean
create
,
gpointer
data
)
{
struct
DeviceData
*
dd
=
data
;
WpMonitor
*
self
=
dd
->
self
;
g_autoptr
(
WpPlugin
)
dr
=
g_weak_ref_get
(
&
self
->
dbus_reservation
);
g_return_if_fail
(
dd
);
/* Create */
if
(
create
&&
!
dd
->
device
)
{
dd
->
device
=
create_device
(
dd
->
self
,
dd
->
parent
,
dd
->
id
,
dd
->
spa_factory
,
if
(
create
)
create_device
(
dd
->
self
,
dd
->
parent
,
dd
->
id
,
dd
->
spa_factory
,
dd
->
props
?
wp_properties_ref
(
dd
->
props
)
:
NULL
);
}
/* Destroy */
else
if
(
!
create
&&
dd
->
device
)
{
GList
*
children
=
NULL
;
GList
*
link
=
NULL
;
GObject
*
child
=
NULL
;
/* Remove the device from its parent children list */
find_child
(
G_OBJECT
(
dd
->
parent
),
dd
->
id
,
&
children
,
&
link
,
&
child
);
children
=
g_list_remove_link
(
children
,
link
);
g_object_set_qdata_full
(
G_OBJECT
(
dd
->
parent
),
children_quark
(),
children
,
(
GDestroyNotify
)
free_children
);
/* Release the device and its children */
g_list_free_full
(
link
,
g_object_unref
);
wp_info_object
(
self
,
"device %p destroyed"
,
dd
->
device
);
dd
->
device
=
NULL
;
}
else
wp_spa_device_store_managed_object
(
dd
->
parent
,
dd
->
id
,
NULL
);
}
static
void
...
...
@@ -441,7 +368,6 @@ maybe_create_device (WpMonitor * self, WpSpaDevice * parent, guint id,
dd
->
parent
=
g_object_ref
(
parent
);
dd
->
spa_factory
=
g_strdup
(
spa_factory
);
dd
->
props
=
props
;
dd
->
device
=
NULL
;
/* Create the closure */
closure
=
g_cclosure_new
(
G_CALLBACK
(
on_reservation_manage_device
),
dd
,
...
...
@@ -456,40 +382,20 @@ maybe_create_device (WpMonitor * self, WpSpaDevice * parent, guint id,
}
static
void
on_object_info
(
WpSpaDevice
*
device
,
guint
id
,
GType
type
,
const
gchar
*
spa_factory
,
WpProperties
*
props
,
WpProperties
*
parent_props
,
WpMonitor
*
self
)
on_create_object
(
WpSpaDevice
*
device
,
guint
id
,
const
gchar
*
type
,
const
gchar
*
spa_factory
,
WpProperties
*
props
,
WpMonitor
*
self
)
{
GList
*
children
=
NULL
;
GList
*
link
=
NULL
;
GObject
*
child
=
NULL
;
/* Find the child */
find_child
(
G_OBJECT
(
device
),
id
,
&
children
,
&
link
,
&
child
);
/* new object, construct... */
if
(
type
!=
G_TYPE_NONE
&&
!
link
)
{
if
(
type
==
WP_TYPE_DEVICE
)
{
maybe_create_device
(
self
,
device
,
id
,
spa_factory
,
props
);
return
;
}
else
if
(
type
==
WP_TYPE_NODE
)
{
create_node
(
self
,
device
,
&
children
,
id
,
spa_factory
,
props
,
parent_props
);
}
else
{
wp_debug_object
(
self
,
"%s got device object-info for unknown object "
"type %s"
,
self
->
factory
,
g_type_name
(
type
));
}
}
/* object removed, delete... */
else
if
(
type
==
G_TYPE_NONE
&&
link
)
{
g_object_unref
(
child
);
children
=
g_list_delete_link
(
children
,
link
);
if
(
!
g_strcmp0
(
type
,
"Device"
))
{
maybe_create_device
(
self
,
device
,
id
,
spa_factory
,
props
);
}
else
if
(
!
g_strcmp0
(
type
,
"Node"
))
{
g_autoptr
(
WpProperties
)
parent_props
=
wp_spa_device_get_properties
(
device
);
create_node
(
self
,
device
,
id
,
spa_factory
,
props
,
parent_props
);
}
else
{
wp_debug_object
(
self
,
"%s got device create-object for unknown object "
"type: %s"
,
self
->
factory
,
type
);
}
/* put back the children */
g_object_set_qdata_full
(
G_OBJECT
(
device
),
children_quark
(),
children
,
(
GDestroyNotify
)
free_children
);
}
static
void
...
...
@@ -524,14 +430,15 @@ wp_monitor_activate (WpPlugin * plugin)
G_CALLBACK
(
on_plugin_added
),
self
,
0
);
wp_core_install_object_manager
(
core
,
self
->
plugins_om
);
/* create the monitor and handle
onject-info
callback */
/* create the monitor and handle
create-object
callback */
self
->
monitor
=
wp_spa_device_new_from_spa_factory
(
self
->
local_core
,
self
->
factory
,
NULL
);
g_signal_connect
(
self
->
monitor
,
"
object-info"
,
(
GCallback
)
on_
object
_info
,
self
);
g_signal_connect
(
self
->
monitor
,
"
create-
object
"
,
(
GCallback
)
on_create_object
,
self
);
/* activate directly; exporting the monitor device is buggy */
wp_spa_device_activate
(
self
->
monitor
);
/* activate monitor */
wp_object_activate
(
WP_OBJECT
(
self
->
monitor
),
WP_SPA_DEVICE_FEATURE_ENABLED
,
NULL
,
(
GAsyncReadyCallback
)
activate_done
,
self
);
}
static
void
...
...
This diff is collapsed.
Click to expand it.
Preview
0%
Loading
Try again
or
attach a new file
.
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Save comment
Cancel
Please
register
or
sign in
to comment