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
ab5a5871
Commit
ab5a5871
authored
4 years ago
by
Julian Bouzas
Browse files
Options
Downloads
Patches
Plain Diff
m-default-metadata: add support for default audio nodes
parent
f86a5efc
No related branches found
Branches containing commit
No related tags found
Tags containing commit
No related merge requests found
Changes
1
Hide whitespace changes
Inline
Side-by-side
Showing
1 changed file
modules/module-default-metadata.c
+136
-78
136 additions, 78 deletions
modules/module-default-metadata.c
with
136 additions
and
78 deletions
modules/module-default-metadata.c
+
136
−
78
View file @
ab5a5871
...
...
@@ -20,25 +20,26 @@
"default.session.endpoint.sink" : "default.session.endpoint.source")
#define default_audio_node_key(dir) ((dir == WP_DIRECTION_INPUT) ? \
"default.audio.sink" : "default.audio.source")
"default.
configured.
audio.sink" : "default.
configured.
audio.source")
G_DECLARE_FINAL_TYPE
(
WpDefaultMetadata
,
wp_default_metadata
,
WP
,
DEFAULT_METADATA
,
WpPlugin
)
struct
_WpDefault
Endpoints
struct
_WpDefault
Data
{
WpDefaultMetadata
*
self
;
gchar
*
group
;
WpProperties
*
props
;
};
typedef
struct
_WpDefault
Endpoints
WpDefault
Endpoints
;
typedef
struct
_WpDefault
Data
WpDefault
Data
;
struct
_WpDefaultMetadata
{
WpPlugin
parent
;
WpState
*
state
;
WpDefault
Endpoints
default_endpoints
[
2
];
WpDefault
Data
default_datas
[
2
][
2
];
/* AudioNode/Endpoint Input/Output*/
WpObjectManager
*
metadatas_om
;
WpObjectManager
*
nodes_om
;
WpObjectManager
*
sessions_om
;
guint
metadata_id
;
GSource
*
timeout_source
;
...
...
@@ -49,7 +50,7 @@ G_DEFINE_TYPE (WpDefaultMetadata, wp_default_metadata, WP_TYPE_PLUGIN)
static
gboolean
timeout_save_callback
(
gpointer
p
)
{
WpDefault
Endpoints
*
d
=
p
;
WpDefault
Data
*
d
=
p
;
WpDefaultMetadata
*
self
=
d
->
self
;
if
(
!
wp_state_save
(
self
->
state
,
d
->
group
,
d
->
props
))
...
...
@@ -60,7 +61,8 @@ timeout_save_callback (gpointer p)
}
static
void
timeout_save_default_endpoints
(
WpDefaultMetadata
*
self
,
guint
dir
,
guint
ms
)
timeout_save_default_data
(
WpDefaultMetadata
*
self
,
gboolean
is_ep
,
guint
dir
,
guint
ms
)
{
g_autoptr
(
WpCore
)
core
=
wp_object_get_core
(
WP_OBJECT
(
self
));
g_return_if_fail
(
core
);
...
...
@@ -72,7 +74,7 @@ timeout_save_default_endpoints (WpDefaultMetadata *self, guint dir, guint ms)
/* Add the timeout callback */
wp_core_timeout_add
(
core
,
&
self
->
timeout_source
,
ms
,
timeout_save_callback
,
self
->
default_
endpoints
+
dir
,
NULL
);
&
self
->
default_
datas
[
is_ep
][
dir
]
,
NULL
);
}
static
WpEndpoint
*
...
...
@@ -98,37 +100,11 @@ find_endpoint_with_endpoint_id (WpDefaultMetadata * self, guint session_id,
return
g_object_ref
(
ep
);
}
static
WpEndpoint
*
find_endpoint_with_node_id
(
WpDefaultMetadata
*
self
,
guint
node_id
,
WpSession
**
session
)
{
g_autoptr
(
WpIterator
)
it
=
NULL
;
g_auto
(
GValue
)
value
=
G_VALUE_INIT
;
it
=
wp_object_manager_new_iterator
(
self
->
sessions_om
);
for
(;
wp_iterator_next
(
it
,
&
value
);
g_value_unset
(
&
value
))
{
WpSession
*
s
=
g_value_get_object
(
&
value
);
g_autoptr
(
WpEndpoint
)
ep
=
NULL
;
ep
=
wp_session_lookup_endpoint
(
s
,
WP_CONSTRAINT_TYPE_PW_PROPERTY
,
PW_KEY_NODE_ID
,
"=u"
,
node_id
,
NULL
);
if
(
ep
)
{
if
(
session
)
*
session
=
g_object_ref
(
s
);
return
g_object_ref
(
ep
);
}
}
return
NULL
;
}
static
void
on_default_metadata_changed
(
WpMetadata
*
m
,
guint32
subject
,
const
gchar
*
key
,
const
gchar
*
type
,
const
gchar
*
value
,
gpointer
*
d
)
{
WpDefaultMetadata
*
self
=
WP_DEFAULT_METADATA
(
d
);
g_autoptr
(
WpSession
)
session
=
NULL
;
g_autoptr
(
WpEndpoint
)
ep
=
NULL
;
const
gchar
*
session_name
=
NULL
,
*
ep_name
=
NULL
;
guint
dir
=
WP_DIRECTION_INPUT
;
gboolean
is_default_ep
=
FALSE
;
...
...
@@ -149,39 +125,52 @@ on_default_metadata_changed (WpMetadata *m, guint32 subject,
return
;
}
/* Get the edpoint and session */
ep
=
is_default_ep
?
find_endpoint_with_endpoint_id
(
self
,
subject
,
atoi
(
value
),
&
session
)
:
find_endpoint_with_node_id
(
self
,
atoi
(
value
),
&
session
);
if
(
!
ep
||
!
session
)
return
;
/* Update the default node when default endpoint changes, and vice versa */
g_signal_handlers_block_by_func
(
m
,
on_default_metadata_changed
,
self
);
/* Endpoint */
if
(
is_default_ep
)
{
const
gchar
*
n_id
=
NULL
,
*
mc
=
NULL
;
n_id
=
wp_pipewire_object_get_property
(
WP_PIPEWIRE_OBJECT
(
ep
),
PW_KEY_NODE_ID
);
mc
=
wp_endpoint_get_media_class
(
ep
);
if
(
n_id
&&
g_str_has_prefix
(
mc
,
"Audio/"
))
wp_metadata_set
(
m
,
0
,
default_audio_node_key
(
dir
),
"Spa:Int"
,
n_id
);
}
else
{
g_autofree
gchar
*
v
=
g_strdup_printf
(
"%d"
,
wp_proxy_get_bound_id
(
WP_PROXY
(
ep
)));
wp_metadata_set
(
m
,
wp_proxy_get_bound_id
(
WP_PROXY
(
session
)),
default_endpoint_key
(
dir
),
"Spa:Int"
,
v
);
const
gchar
*
session_name
=
NULL
,
*
ep_name
=
NULL
;
g_autoptr
(
WpSession
)
session
=
NULL
;
g_autoptr
(
WpEndpoint
)
ep
=
NULL
;
/* Find endpoint and session */
ep
=
find_endpoint_with_endpoint_id
(
self
,
subject
,
atoi
(
value
),
&
session
);
if
(
!
ep
||
!
session
)
return
;
/* Get endpoint name and session name */
session_name
=
wp_session_get_name
(
session
);
ep_name
=
wp_endpoint_get_name
(
ep
);
g_return_if_fail
(
session_name
);
g_return_if_fail
(
ep_name
);
/* Set state properties */
wp_properties_set
(
self
->
default_datas
[
1
][
dir
].
props
,
session_name
,
ep_name
);
}
g_signal_handlers_unblock_by_func
(
m
,
on_default_metadata_changed
,
self
);
/* Get the session name and endpoint name */
session_name
=
wp_session_get_name
(
session
);
g_return_if_fail
(
session_name
);
ep_name
=
wp_endpoint_get_name
(
ep
);
g_return_if_fail
(
ep_name
);
/* Audio Node */
else
{
g_autoptr
(
WpNode
)
node
=
NULL
;
const
gchar
*
node_name
=
NULL
;
/* Find node */
node
=
wp_object_manager_lookup
(
self
->
nodes_om
,
WP_TYPE_NODE
,
WP_CONSTRAINT_TYPE_G_PROPERTY
,
"bound-id"
,
"=u"
,
atoi
(
value
),
NULL
);
if
(
!
node
)
return
;
/* Get node name */
node_name
=
wp_pipewire_object_get_property
(
WP_PIPEWIRE_OBJECT
(
node
),
PW_KEY_NODE_NAME
);
g_return_if_fail
(
node_name
);
/* Set state properties */
wp_properties_set
(
self
->
default_datas
[
0
][
dir
].
props
,
"audio"
,
node_name
);
}
/* Set the property and save state */
wp_properties_set
(
self
->
default_endpoints
[
dir
].
props
,
session_name
,
ep_name
);
timeout_save_default_endpoints
(
self
,
dir
,
SAVE_INTERVAL_MS
);
/* Save state after specific interval */
timeout_save_default_data
(
self
,
is_default_ep
,
dir
,
SAVE_INTERVAL_MS
);
}
static
WpEndpoint
*
...
...
@@ -216,15 +205,15 @@ reevaluate_default_endpoints (WpDefaultMetadata * self, WpMetadata *m,
WpSession
*
session
,
guint
dir
)
{
g_autoptr
(
WpEndpoint
)
ep
=
NULL
;
const
gchar
*
session_name
=
NULL
,
*
ep_name
=
NULL
,
*
n_id
=
NULL
,
*
mc
=
NULL
;
const
gchar
*
session_name
=
NULL
,
*
ep_name
=
NULL
;
guint
ep_id
=
0
;
g_return_if_fail
(
m
);
g_return_if_fail
(
self
->
default_
endpoints
[
dir
].
props
);
g_return_if_fail
(
self
->
default_
datas
[
1
]
[
dir
].
props
);
/* Find the default endpoint */
session_name
=
wp_session_get_name
(
session
);
ep_name
=
wp_properties_get
(
self
->
default_
endpoints
[
dir
].
props
,
session_name
);
ep_name
=
wp_properties_get
(
self
->
default_
datas
[
1
]
[
dir
].
props
,
session_name
);
if
(
ep_name
)
{
ep
=
wp_session_lookup_endpoint
(
session
,
WP_CONSTRAINT_TYPE_PW_PROPERTY
,
"endpoint.name"
,
"=s"
,
ep_name
,
...
...
@@ -238,9 +227,6 @@ reevaluate_default_endpoints (WpDefaultMetadata * self, WpMetadata *m,
if
(
ep
)
{
ep_id
=
wp_proxy_get_bound_id
(
WP_PROXY
(
ep
));
n_id
=
wp_pipewire_object_get_property
(
WP_PIPEWIRE_OBJECT
(
ep
),
PW_KEY_NODE_ID
);
mc
=
wp_endpoint_get_media_class
(
ep
);
/* block the signal to avoid storing this; only selections done by the user
* should be stored */
...
...
@@ -251,10 +237,6 @@ reevaluate_default_endpoints (WpDefaultMetadata * self, WpMetadata *m,
wp_metadata_set
(
m
,
wp_proxy_get_bound_id
(
WP_PROXY
(
session
)),
default_endpoint_key
(
dir
),
"Spa:Int"
,
value
);
/* Also set the default node if audio endpoint and node Id is present */
if
(
n_id
&&
g_str_has_prefix
(
mc
,
"Audio/"
))
wp_metadata_set
(
m
,
0
,
default_audio_node_key
(
dir
),
"Spa:Int"
,
n_id
);
g_signal_handlers_unblock_by_func
(
m
,
on_default_metadata_changed
,
self
);
wp_info_object
(
self
,
"set default %s endpoint with id %d on session '%s'"
,
...
...
@@ -262,6 +244,50 @@ reevaluate_default_endpoints (WpDefaultMetadata * self, WpMetadata *m,
}
}
static
void
reevaluate_default_audio_nodes
(
WpDefaultMetadata
*
self
,
WpMetadata
*
m
,
guint
dir
)
{
g_autoptr
(
WpNode
)
node
=
NULL
;
const
gchar
*
node_name
=
NULL
;
guint
node_id
=
0
;
g_return_if_fail
(
m
);
g_return_if_fail
(
self
->
default_datas
[
0
][
dir
].
props
);
/* Find the default node */
node_name
=
wp_properties_get
(
self
->
default_datas
[
0
][
dir
].
props
,
"audio"
);
if
(
node_name
)
{
node
=
wp_object_manager_lookup
(
self
->
nodes_om
,
WP_TYPE_NODE
,
WP_CONSTRAINT_TYPE_PW_PROPERTY
,
"node.name"
,
"=s"
,
node_name
,
WP_CONSTRAINT_TYPE_PW_PROPERTY
,
"media.class"
,
"=s"
,
(
dir
==
WP_DIRECTION_INPUT
)
?
"Audio/Sink"
:
"Audio/Source"
,
NULL
);
}
/* If not found, get the first one available */
if
(
!
node
)
node
=
wp_object_manager_lookup
(
self
->
sessions_om
,
WP_TYPE_NODE
,
WP_CONSTRAINT_TYPE_PW_PROPERTY
,
"media.class"
,
"=s"
,
(
dir
==
WP_DIRECTION_INPUT
)
?
"Audio/Sink"
:
"Audio/Source"
,
NULL
);
if
(
node
)
{
node_id
=
wp_proxy_get_bound_id
(
WP_PROXY
(
node
));
/* block the signal to avoid storing this; only selections done by the user
* should be stored */
g_signal_handlers_block_by_func
(
m
,
on_default_metadata_changed
,
self
);
/* Set default node */
g_autofree
gchar
*
value
=
g_strdup_printf
(
"%d"
,
node_id
);
wp_metadata_set
(
m
,
0
,
default_audio_node_key
(
dir
),
"Spa:Int"
,
value
);
g_signal_handlers_unblock_by_func
(
m
,
on_default_metadata_changed
,
self
);
wp_info_object
(
self
,
"set default %s audio node with id %d"
,
direction_to_dbg_string
(
dir
),
node_id
);
}
}
static
void
on_endpoints_changed
(
WpSession
*
session
,
WpDefaultMetadata
*
self
)
{
...
...
@@ -286,6 +312,22 @@ on_session_added (WpObjectManager * om, WpSession * session,
G_CALLBACK
(
on_endpoints_changed
),
self
,
0
);
}
static
void
on_nodes_changed
(
WpObjectManager
*
om
,
WpDefaultMetadata
*
self
)
{
g_autoptr
(
WpMetadata
)
metadata
=
NULL
;
/* Get the metadata */
metadata
=
wp_object_manager_lookup
(
self
->
metadatas_om
,
WP_TYPE_METADATA
,
WP_CONSTRAINT_TYPE_G_PROPERTY
,
"bound-id"
,
"=u"
,
self
->
metadata_id
,
NULL
);
if
(
!
metadata
)
return
;
wp_trace_object
(
om
,
"nodes changed, re-evaluating defaults"
);
reevaluate_default_audio_nodes
(
self
,
metadata
,
WP_DIRECTION_INPUT
);
reevaluate_default_audio_nodes
(
self
,
metadata
,
WP_DIRECTION_OUTPUT
);
}
static
void
on_metadata_added
(
WpObjectManager
*
om
,
WpMetadata
*
metadata
,
gpointer
d
)
{
...
...
@@ -303,6 +345,15 @@ on_metadata_added (WpObjectManager *om, WpMetadata *metadata, gpointer d)
g_signal_connect_object
(
metadata
,
"changed"
,
G_CALLBACK
(
on_default_metadata_changed
),
self
,
0
);
/* Create the nodes object manager */
self
->
nodes_om
=
wp_object_manager_new
();
wp_object_manager_add_interest
(
self
->
nodes_om
,
WP_TYPE_NODE
,
NULL
);
wp_object_manager_request_object_features
(
self
->
nodes_om
,
WP_TYPE_NODE
,
WP_OBJECT_FEATURES_ALL
);
g_signal_connect_object
(
self
->
nodes_om
,
"objects-changed"
,
G_CALLBACK
(
on_nodes_changed
),
self
,
0
);
wp_core_install_object_manager
(
core
,
self
->
nodes_om
);
/* Create the sessions object manager */
self
->
sessions_om
=
wp_object_manager_new
();
wp_object_manager_add_interest
(
self
->
sessions_om
,
WP_TYPE_SESSION
,
NULL
);
...
...
@@ -340,11 +391,12 @@ wp_default_metadata_disable (WpPlugin * plugin)
WpDefaultMetadata
*
self
=
WP_DEFAULT_METADATA
(
plugin
);
g_clear_object
(
&
self
->
metadatas_om
);
g_clear_object
(
&
self
->
nodes_om
);
g_clear_object
(
&
self
->
sessions_om
);
}
static
void
unload_default_
endpoints
(
WpDefaultMetadata
*
self
,
WpDefault
Endpoints
*
d
)
unload_default_
data
(
WpDefaultMetadata
*
self
,
WpDefault
Data
*
d
)
{
g_clear_pointer
(
&
d
->
props
,
wp_properties_unref
);
g_clear_pointer
(
&
d
->
group
,
g_free
);
...
...
@@ -352,7 +404,7 @@ unload_default_endpoints (WpDefaultMetadata * self, WpDefaultEndpoints * d)
}
static
void
load_default_
endpoints
(
WpDefaultMetadata
*
self
,
WpDefault
Endpoints
*
d
,
load_default_
data
(
WpDefaultMetadata
*
self
,
WpDefault
Data
*
d
,
const
gchar
*
group
)
{
d
->
self
=
self
;
...
...
@@ -373,8 +425,10 @@ wp_default_metadata_finalize (GObject * object)
g_source_destroy
(
self
->
timeout_source
);
g_clear_pointer
(
&
self
->
timeout_source
,
g_source_unref
);
unload_default_endpoints
(
self
,
self
->
default_endpoints
+
WP_DIRECTION_INPUT
);
unload_default_endpoints
(
self
,
self
->
default_endpoints
+
WP_DIRECTION_OUTPUT
);
unload_default_data
(
self
,
&
self
->
default_datas
[
0
][
WP_DIRECTION_INPUT
]);
unload_default_data
(
self
,
&
self
->
default_datas
[
0
][
WP_DIRECTION_OUTPUT
]);
unload_default_data
(
self
,
&
self
->
default_datas
[
1
][
WP_DIRECTION_INPUT
]);
unload_default_data
(
self
,
&
self
->
default_datas
[
1
][
WP_DIRECTION_OUTPUT
]);
g_clear_object
(
&
self
->
state
);
G_OBJECT_CLASS
(
wp_default_metadata_parent_class
)
->
finalize
(
object
);
...
...
@@ -384,9 +438,13 @@ static void
wp_default_metadata_init
(
WpDefaultMetadata
*
self
)
{
self
->
state
=
wp_state_new
(
STATE_NAME
);
load_default_endpoints
(
self
,
self
->
default_endpoints
+
WP_DIRECTION_INPUT
,
load_default_data
(
self
,
&
self
->
default_datas
[
0
][
WP_DIRECTION_INPUT
],
default_audio_node_key
(
WP_DIRECTION_INPUT
));
load_default_data
(
self
,
&
self
->
default_datas
[
0
][
WP_DIRECTION_OUTPUT
],
default_audio_node_key
(
WP_DIRECTION_OUTPUT
));
load_default_data
(
self
,
&
self
->
default_datas
[
1
][
WP_DIRECTION_INPUT
],
default_endpoint_key
(
WP_DIRECTION_INPUT
));
load_default_
endpoints
(
self
,
self
->
default_
endpoints
+
WP_DIRECTION_OUTPUT
,
load_default_
data
(
self
,
&
self
->
default_
datas
[
1
][
WP_DIRECTION_OUTPUT
]
,
default_endpoint_key
(
WP_DIRECTION_OUTPUT
));
}
...
...
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