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
GitLab community forum
Contribute to GitLab
Provide feedback
Terms and privacy
Keyboard shortcuts
?
Snippets
Groups
Projects
Show more breadcrumbs
pkg
wireplumber
Commits
e1ef9b11
Commit
e1ef9b11
authored
6 years ago
by
George Kiagiadakis
Browse files
Options
Downloads
Patches
Plain Diff
module-pipewire: implement client node detection and simple-endpoint creation
parent
df48fd89
Branches
Branches containing commit
Tags
Tags containing commit
No related merge requests found
Changes
2
Show whitespace changes
Inline
Side-by-side
Showing
2 changed files
modules/module-pipewire.c
+117
-14
117 additions, 14 deletions
modules/module-pipewire.c
modules/module-pipewire/simple-endpoint.c
+104
-9
104 additions, 9 deletions
modules/module-pipewire/simple-endpoint.c
with
221 additions
and
23 deletions
modules/module-pipewire.c
+
117
−
14
View file @
e1ef9b11
...
...
@@ -22,6 +22,106 @@ gpointer simple_endpoint_factory (WpFactory * factory, GType type,
gpointer
simple_endpoint_link_factory
(
WpFactory
*
factory
,
GType
type
,
GVariant
*
properties
);
struct
module_data
{
WpModule
*
module
;
struct
pw_core
*
core
;
struct
pw_remote
*
remote
;
struct
spa_hook
remote_listener
;
struct
pw_registry_proxy
*
registry_proxy
;
struct
spa_hook
registry_listener
;
};
static
void
registry_global
(
void
*
d
,
uint32_t
id
,
uint32_t
parent_id
,
uint32_t
permissions
,
uint32_t
type
,
uint32_t
version
,
const
struct
spa_dict
*
props
)
{
struct
module_data
*
data
=
d
;
const
gchar
*
name
;
const
gchar
*
media_class
;
struct
pw_proxy
*
proxy
;
GVariantBuilder
b
;
g_autoptr
(
GVariant
)
endpoint_props
=
NULL
;
g_autoptr
(
WpCore
)
core
=
NULL
;
/* listen for client "Stream" nodes and create endpoints for them */
if
(
type
==
PW_TYPE_INTERFACE_Node
&&
props
&&
(
media_class
=
spa_dict_lookup
(
props
,
"media.class"
))
&&
g_str_has_prefix
(
media_class
,
"Stream/"
))
{
name
=
spa_dict_lookup
(
props
,
"media.name"
);
if
(
!
name
)
name
=
spa_dict_lookup
(
props
,
"node.name"
);
g_debug
(
"found stream node: id:%u ; name:%s ; media_class:%s"
,
id
,
name
,
media_class
);
proxy
=
pw_registry_proxy_bind
(
data
->
registry_proxy
,
id
,
type
,
PW_VERSION_NODE
,
0
);
g_variant_builder_init
(
&
b
,
G_VARIANT_TYPE_VARDICT
);
g_variant_builder_add
(
&
b
,
"{sv}"
,
"name"
,
name
?
g_variant_new_string
(
name
)
:
g_variant_new_take_string
(
g_strdup_printf
(
"Stream %u"
,
id
)));
g_variant_builder_add
(
&
b
,
"{sv}"
,
"media-class"
,
g_variant_new_string
(
media_class
));
g_variant_builder_add
(
&
b
,
"{sv}"
,
"node-proxy"
,
g_variant_new_uint64
((
guint64
)
proxy
));
endpoint_props
=
g_variant_builder_end
(
&
b
);
core
=
wp_module_get_core
(
data
->
module
);
wp_factory_make
(
core
,
"pipewire-simple-endpoint"
,
WP_TYPE_ENDPOINT
,
endpoint_props
);
}
}
static
const
struct
pw_registry_proxy_events
registry_events
=
{
PW_VERSION_REGISTRY_PROXY_EVENTS
,
.
global
=
registry_global
,
};
static
void
on_remote_state_changed
(
void
*
d
,
enum
pw_remote_state
old_state
,
enum
pw_remote_state
new_state
,
const
char
*
error
)
{
struct
module_data
*
data
=
d
;
struct
pw_core_proxy
*
core_proxy
;
g_debug
(
"remote state changed, old:%s new:%s"
,
pw_remote_state_as_string
(
old_state
),
pw_remote_state_as_string
(
new_state
));
switch
(
new_state
)
{
case
PW_REMOTE_STATE_CONNECTED
:
core_proxy
=
pw_remote_get_core_proxy
(
data
->
remote
);
data
->
registry_proxy
=
pw_core_proxy_get_registry
(
core_proxy
,
PW_TYPE_INTERFACE_Registry
,
PW_VERSION_REGISTRY
,
0
);
pw_registry_proxy_add_listener
(
data
->
registry_proxy
,
&
data
->
registry_listener
,
&
registry_events
,
data
);
break
;
case
PW_REMOTE_STATE_UNCONNECTED
:
// TODO quit wireplumber
break
;
case
PW_REMOTE_STATE_ERROR
:
// TODO quit wireplumber
break
;
default:
break
;
}
}
static
const
struct
pw_remote_events
remote_events
=
{
PW_VERSION_REMOTE_EVENTS
,
.
state_changed
=
on_remote_state_changed
,
};
static
gboolean
connect_in_idle
(
struct
pw_remote
*
remote
)
{
...
...
@@ -30,38 +130,41 @@ connect_in_idle (struct pw_remote *remote)
}
static
void
module_destroy
(
gpointer
r
)
module_destroy
(
gpointer
d
)
{
struct
pw_remote
*
remote
=
r
;
struct
pw_core
*
core
=
pw_remote_get_core
(
remote
);
struct
module_data
*
data
=
d
;
pw_remote_destroy
(
remote
);
pw_core_destroy
(
core
);
pw_remote_destroy
(
data
->
remote
);
pw_core_destroy
(
data
->
core
);
g_slice_free
(
struct
module_data
,
data
);
}
void
wireplumber__module_init
(
WpModule
*
module
,
WpCore
*
core
,
GVariant
*
args
)
{
GSource
*
source
;
struct
pw_core
*
pw_core
;
struct
pw_remote
*
pw_remote
;
struct
module_data
*
data
;
pw_init
(
NULL
,
NULL
);
data
=
g_slice_new0
(
struct
module_data
);
data
->
module
=
module
;
wp_module_set_destroy_callback
(
module
,
module_destroy
,
data
);
source
=
wp_loop_source_new
();
g_source_attach
(
source
,
NULL
);
pw_core
=
pw_core_new
(
WP_LOOP_SOURCE
(
source
)
->
loop
,
NULL
,
0
);
wp_core_register_global
(
core
,
WP_GLOBAL_PW_CORE
,
pw_core
,
NULL
);
pw_remote
=
pw_remote_new
(
pw_core
,
NULL
,
0
);
wp_core_register_global
(
core
,
WP_GLOBAL_PW_REMOTE
,
pw_remote
,
NULL
);
data
->
core
=
pw_core_new
(
WP_LOOP_SOURCE
(
source
)
->
loop
,
NULL
,
0
);
wp_core_register_global
(
core
,
WP_GLOBAL_PW_CORE
,
data
->
core
,
NULL
);
wp_module_set_destroy_callback
(
module
,
module_destroy
,
pw_remote
);
data
->
remote
=
pw_remote_new
(
data
->
core
,
NULL
,
0
);
pw_remote_add_listener
(
data
->
remote
,
&
data
->
remote_listener
,
&
remote_events
,
data
->
remote
);
wp_core_register_global
(
core
,
WP_GLOBAL_PW_REMOTE
,
data
->
remote
,
NULL
);
wp_factory_new
(
core
,
"pipewire-simple-endpoint"
,
simple_endpoint_factory
);
wp_factory_new
(
core
,
"pipewire-simple-endpoint-link"
,
simple_endpoint_link_factory
);
g_idle_add
((
GSourceFunc
)
connect_in_idle
,
pw_
remote
);
g_idle_add
((
GSourceFunc
)
connect_in_idle
,
data
->
remote
);
}
This diff is collapsed.
Click to expand it.
modules/module-pipewire/simple-endpoint.c
+
104
−
9
View file @
e1ef9b11
...
...
@@ -19,6 +19,13 @@
struct
_WpPipewireSimpleEndpoint
{
WpEndpoint
parent
;
struct
pw_node_proxy
*
node
;
struct
spa_hook
proxy_listener
;
};
enum
{
PROP_0
,
PROP_NODE_PROXY
,
};
G_DECLARE_FINAL_TYPE
(
WpPipewireSimpleEndpoint
,
...
...
@@ -37,6 +44,51 @@ simple_endpoint_init (WpPipewireSimpleEndpoint * self)
wp_endpoint_register_stream
(
WP_ENDPOINT
(
self
),
g_variant_builder_end
(
&
b
));
}
static
void
simple_endpoint_finalize
(
GObject
*
object
)
{
WpPipewireSimpleEndpoint
*
self
=
WP_PIPEWIRE_SIMPLE_ENDPOINT
(
object
);
if
(
self
->
node
)
{
spa_hook_remove
(
&
self
->
proxy_listener
);
pw_proxy_destroy
((
struct
pw_proxy
*
)
self
->
node
);
}
G_OBJECT_CLASS
(
simple_endpoint_parent_class
)
->
finalize
(
object
);
}
static
void
simple_endpoint_set_property
(
GObject
*
object
,
guint
property_id
,
const
GValue
*
value
,
GParamSpec
*
pspec
)
{
WpPipewireSimpleEndpoint
*
self
=
WP_PIPEWIRE_SIMPLE_ENDPOINT
(
object
);
switch
(
property_id
)
{
case
PROP_NODE_PROXY
:
self
->
node
=
g_value_get_pointer
(
value
);
break
;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID
(
object
,
property_id
,
pspec
);
break
;
}
}
static
void
simple_endpoint_get_property
(
GObject
*
object
,
guint
property_id
,
GValue
*
value
,
GParamSpec
*
pspec
)
{
WpPipewireSimpleEndpoint
*
self
=
WP_PIPEWIRE_SIMPLE_ENDPOINT
(
object
);
switch
(
property_id
)
{
case
PROP_NODE_PROXY
:
g_value_set_pointer
(
value
,
self
->
node
);
break
;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID
(
object
,
property_id
,
pspec
);
break
;
}
}
static
gboolean
simple_endpoint_prepare_link
(
WpEndpoint
*
self
,
guint32
stream_id
,
WpEndpointLink
*
link
,
GVariant
**
properties
,
GError
**
error
)
...
...
@@ -48,22 +100,65 @@ simple_endpoint_prepare_link (WpEndpoint * self, guint32 stream_id,
static
void
simple_endpoint_class_init
(
WpPipewireSimpleEndpointClass
*
klass
)
{
GObjectClass
*
object_class
=
(
GObjectClass
*
)
klass
;
WpEndpointClass
*
endpoint_class
=
(
WpEndpointClass
*
)
klass
;
object_class
->
finalize
=
simple_endpoint_finalize
;
object_class
->
set_property
=
simple_endpoint_set_property
;
object_class
->
get_property
=
simple_endpoint_get_property
;
endpoint_class
->
prepare_link
=
simple_endpoint_prepare_link
;
g_object_class_install_property
(
object_class
,
PROP_NODE_PROXY
,
g_param_spec_pointer
(
"node-proxy"
,
"node-proxy"
,
"Pointer to the pw_node_proxy* to wrap"
,
G_PARAM_READWRITE
|
G_PARAM_CONSTRUCT_ONLY
|
G_PARAM_STATIC_STRINGS
));
}
static
void
node_proxy_destroy
(
void
*
data
)
{
WpPipewireSimpleEndpoint
*
self
=
WP_PIPEWIRE_SIMPLE_ENDPOINT
(
data
);
self
->
node
=
NULL
;
//TODO unregister the endpoint from the session manager
}
static
const
struct
pw_proxy_events
node_proxy_events
=
{
PW_VERSION_PROXY_EVENTS
,
.
destroy
=
node_proxy_destroy
,
};
gpointer
simple_endpoint_factory
(
WpFactory
*
factory
,
GType
type
,
GVariant
*
properties
)
{
if
(
type
!=
WP_TYPE_ENDPOINT
)
WpPipewireSimpleEndpoint
*
ep
;
guint64
proxy
;
const
gchar
*
name
;
const
gchar
*
media_class
;
g_return_val_if_fail
(
type
==
WP_TYPE_ENDPOINT
,
NULL
);
g_return_val_if_fail
(
properties
!=
NULL
,
NULL
);
g_return_val_if_fail
(
g_variant_is_of_type
(
properties
,
G_VARIANT_TYPE_VARDICT
),
NULL
);
if
(
!
g_variant_lookup
(
properties
,
"name"
,
"&s"
,
&
name
))
return
NULL
;
if
(
!
g_variant_lookup
(
properties
,
"media-class"
,
"&s"
,
&
media_class
))
return
NULL
;
if
(
!
g_variant_lookup
(
properties
,
"node-proxy"
,
"t"
,
&
proxy
))
return
NULL
;
/* TODO: retrieve pw_node* from @properties and keep it
* TODO: populate media_class and name on the endpoint
* TODO: potentially choose between subclasses of SimpleEndpoint
* in order to add interfaces (volume, color balance, etc)
*/
return
g_object_new
(
simple_endpoint_get_type
(),
NULL
);
ep
=
g_object_new
(
simple_endpoint_get_type
(),
"name"
,
name
,
"media-class"
,
media_class
,
"node-proxy"
,
(
gpointer
)
proxy
,
NULL
);
pw_proxy_add_listener
((
gpointer
)
proxy
,
&
ep
->
proxy_listener
,
&
node_proxy_events
,
ep
);
//TODO register the endpoint with the session manager
return
ep
;
}
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