Rename endpoint concept to virtual session item
This commit is contained in:
@@ -389,49 +389,51 @@ files and are placed under ``wireplumber.conf.d/``. More on this below.
|
|||||||
* wp_settings_apply_rule () is WpSettings API for rules.
|
* wp_settings_apply_rule () is WpSettings API for rules.
|
||||||
|
|
||||||
|
|
||||||
* *wireplumber.endpoints*
|
* *wireplumber.virtuals*
|
||||||
|
|
||||||
Endpoints are a way of grouping different kinds of clients or
|
Virtual session items are a way of grouping different kinds of clients or
|
||||||
applications(for example Music, Voice, Navigation, Gaming etc).
|
applications(for example Music, Voice, Navigation, Gaming etc).
|
||||||
The actual grouping is done based on the `media.role` of the client
|
The actual grouping is done based on the `media.role` of the client
|
||||||
stream node.
|
stream node.
|
||||||
|
|
||||||
Endpoints allows for that actions to be taken up at group level rather than
|
Virtual session items allows for that actions to be taken up at group level
|
||||||
at individual stream level, which can be cumbersome.
|
rather than at individual stream level, which can be cumbersome.
|
||||||
|
|
||||||
For example imagine the following scenarios.
|
For example imagine the following scenarios.
|
||||||
* Incoming Navigation message needs to duck the volume of
|
* Incoming Navigation message needs to duck the volume of
|
||||||
Audio playback(all the apps playing audio).
|
Audio playback(all the apps playing audio).
|
||||||
* Incoming voice/voip call needs to stop(cork) the Audio playback.
|
* Incoming voice/voip call needs to stop(cork) the Audio playback.
|
||||||
|
|
||||||
Endpoints realize this functionality with ease.
|
Virtual session items realize this functionality with ease.
|
||||||
|
|
||||||
* *Defining Endpoints*
|
* *Defining Virtual session items*
|
||||||
|
|
||||||
Example::
|
Example::
|
||||||
|
|
||||||
endpoints = {
|
virtual-items = {
|
||||||
endpoint.capture = {
|
virtual-item.capture = {
|
||||||
media.class = "Audio/Source"
|
media.class = "Audio/Source"
|
||||||
role = "Capture"
|
role = "Capture"
|
||||||
}
|
}
|
||||||
endpoint.multimedia = {
|
virtual-item.multimedia = {
|
||||||
media.class = "Audio/Sink"
|
media.class = "Audio/Sink"
|
||||||
role = "Multimedia"
|
role = "Multimedia"
|
||||||
}
|
}
|
||||||
endpoint.navigation = {
|
virtual-item.navigation = {
|
||||||
media.class = "Audio/Sink"
|
media.class = "Audio/Sink"
|
||||||
role = "Navigation"
|
role = "Navigation"
|
||||||
}
|
}
|
||||||
|
|
||||||
This example creates 3 endpoints, with names ``endpoint.capture``,
|
This example creates 3 virtual session items, with names
|
||||||
``endpoint.multimedia`` and ``endpoint.navigation`` and assigned roles
|
``virtual-item.capture``, ``virtual-item.multimedia`` and
|
||||||
``Capture``, ``Multimedia`` and ``Navigation`` respectively.
|
``virtual-item.navigation`` and assigned roles ``Capture``, ``Multimedia``
|
||||||
|
and ``Navigation`` respectively.
|
||||||
|
|
||||||
First end point has a media class of ``Audio/Source`` used for capture and rest of the endpoints have ``Audio/Sink`` media class, and so are only
|
First virtual item has a media class of ``Audio/Source`` used for capture
|
||||||
used for playback.
|
and rest of the virtual items have ``Audio/Sink`` media class, and so are
|
||||||
|
only used for playback.
|
||||||
|
|
||||||
* *Endpoints config*
|
* *Virtual session items config*
|
||||||
|
|
||||||
Example::
|
Example::
|
||||||
|
|
||||||
@@ -456,15 +458,15 @@ files and are placed under ``wireplumber.conf.d/``. More on this below.
|
|||||||
|
|
||||||
The above example defines actions for both ``Multimedia`` and ``Navigation``
|
The above example defines actions for both ``Multimedia`` and ``Navigation``
|
||||||
roles. Since the Navigation role has more priority than the Multimedia
|
roles. Since the Navigation role has more priority than the Multimedia
|
||||||
role, when a client connects to the Navigation endpoint, it will ``duck``
|
role, when a client connects to the Navigation virtual session item, it
|
||||||
the volume of all Multimedia clients. If Multiple Navigation clients want
|
will ``duck`` the volume of all Multimedia clients. If Multiple Navigation
|
||||||
to play audio, their audio will be mixed.
|
clients want to play audio, their audio will be mixed.
|
||||||
|
|
||||||
Possible values of actions are: ``mix`` (Mixes audio),
|
Possible values of actions are: ``mix`` (Mixes audio),
|
||||||
``duck`` (Mixes and lowers the audio volume) or ``cork`` (Pauses audio).
|
``duck`` (Mixes and lowers the audio volume) or ``cork`` (Pauses audio).
|
||||||
|
|
||||||
Endpoints are not used for desktop use cases, it is more suitable for
|
Virtual session items are not used for desktop use cases, it is more suitable
|
||||||
embedded use cases.
|
for embedded use cases.
|
||||||
|
|
||||||
* *Split Configuration files*
|
* *Split Configuration files*
|
||||||
|
|
||||||
|
@@ -62,16 +62,16 @@ Native API clients
|
|||||||
pw-cat
|
pw-cat
|
||||||
^^^^^^
|
^^^^^^
|
||||||
|
|
||||||
Using the default endpoint:
|
Using the default device:
|
||||||
|
|
||||||
.. code:: console
|
.. code:: console
|
||||||
|
|
||||||
$ wpctl status # verify the default endpoints
|
$ wpctl status # verify the default device
|
||||||
$ pw-record test.wav
|
$ pw-record test.wav
|
||||||
$ pw-play test.wav
|
$ pw-play test.wav
|
||||||
|
|
||||||
|
|
||||||
Using a non-default endpoint:
|
Using a non-default device:
|
||||||
|
|
||||||
.. code:: console
|
.. code:: console
|
||||||
|
|
||||||
@@ -84,19 +84,18 @@ or
|
|||||||
|
|
||||||
.. code:: console
|
.. code:: console
|
||||||
|
|
||||||
$ wpctl status # find the capture & playback endpoint ids
|
$ wpctl status # find the capture & playback node ids
|
||||||
$ pw-record --target <endpoint_id> test.wav
|
$ pw-record --target <node_id> test.wav
|
||||||
$ pw-play --target <endpoint_id> test.wav
|
$ pw-play --target <node_id> test.wav
|
||||||
|
|
||||||
.. note::
|
.. note::
|
||||||
|
|
||||||
node ids and endpoint ids can be used interchangeably when specifying
|
node ids can be used interchangeably when specifying targets in all use cases
|
||||||
targets in all use cases
|
|
||||||
|
|
||||||
video-play
|
video-play
|
||||||
^^^^^^^^^^
|
^^^^^^^^^^
|
||||||
|
|
||||||
Using the default endpoint:
|
Using the default device:
|
||||||
|
|
||||||
.. code:: console
|
.. code:: console
|
||||||
|
|
||||||
@@ -104,13 +103,13 @@ Using the default endpoint:
|
|||||||
$ ./build/src/examples/video-play
|
$ ./build/src/examples/video-play
|
||||||
|
|
||||||
|
|
||||||
Using a non-default endpoint:
|
Using a non-default device:
|
||||||
|
|
||||||
.. code:: console
|
.. code:: console
|
||||||
|
|
||||||
$ wpctl status # find the endpoint id from the list
|
$ wpctl status # find the device node id from the list
|
||||||
$ cd path/to/pipewire-source-dir
|
$ cd path/to/pipewire-source-dir
|
||||||
$ ./build/src/examples/video-play <endpoint_id>
|
$ ./build/src/examples/video-play <node_id>
|
||||||
|
|
||||||
.. tip::
|
.. tip::
|
||||||
|
|
||||||
@@ -123,11 +122,11 @@ PulseAudio compat API clients
|
|||||||
pacat
|
pacat
|
||||||
^^^^^
|
^^^^^
|
||||||
|
|
||||||
Using the default endpoint:
|
Using the default device:
|
||||||
|
|
||||||
.. code:: console
|
.. code:: console
|
||||||
|
|
||||||
$ wpctl status # verify the default endpoints
|
$ wpctl status # verify the default device
|
||||||
$ parecord test.wav
|
$ parecord test.wav
|
||||||
$ paplay test.wav
|
$ paplay test.wav
|
||||||
|
|
||||||
@@ -158,29 +157,29 @@ aplay / arecord
|
|||||||
``pipewire-alsa/conf/50-pipewire.conf`` in your ``~/.asoundrc``
|
``pipewire-alsa/conf/50-pipewire.conf`` in your ``~/.asoundrc``
|
||||||
(or anywhere else, system-wide, where libasound can read it)
|
(or anywhere else, system-wide, where libasound can read it)
|
||||||
|
|
||||||
Using the default endpoint:
|
Using the default device:
|
||||||
|
|
||||||
.. code:: console
|
.. code:: console
|
||||||
|
|
||||||
$ wpctl status # verify the default endpoints
|
$ wpctl status # verify the default devices
|
||||||
$ arecord -D pipewire -f S16_LE -r 48000 test.wav
|
$ arecord -D pipewire -f S16_LE -r 48000 test.wav
|
||||||
$ aplay -D pipewire test.wav
|
$ aplay -D pipewire test.wav
|
||||||
|
|
||||||
Using a non-default endpoint:
|
Using a non-default device:
|
||||||
|
|
||||||
.. code:: console
|
.. code:: console
|
||||||
|
|
||||||
$ wpctl status # find the capture & playback endpoint ids
|
$ wpctl status # find the capture & playback node ids
|
||||||
$ PIPEWIRE_NODE=<endpoint_id> arecord -D pipewire -f S16_LE -r 48000 test.wav
|
$ PIPEWIRE_NODE=<node_id> arecord -D pipewire -f S16_LE -r 48000 test.wav
|
||||||
$ PIPEWIRE_NODE=<endpoint_id> aplay -D pipewire test.wav
|
$ PIPEWIRE_NODE=<node_id> aplay -D pipewire test.wav
|
||||||
|
|
||||||
or
|
or
|
||||||
|
|
||||||
.. code:: console
|
.. code:: console
|
||||||
|
|
||||||
$ wpctl status # find the capture & playback endpoint ids
|
$ wpctl status # find the capture & playback device node ids
|
||||||
$ arecord -D pipewire:NODE=<endpoint_id> -f S16_LE -r 48000 test.wav
|
$ arecord -D pipewire:NODE=<node_id> -f S16_LE -r 48000 test.wav
|
||||||
$ aplay -D pipewire:NODE=<endpoint_id> test.wav
|
$ aplay -D pipewire:NODE=<node_id> test.wav
|
||||||
|
|
||||||
|
|
||||||
JACK compat API clients
|
JACK compat API clients
|
||||||
@@ -201,15 +200,14 @@ jack_simple_client
|
|||||||
|
|
||||||
.. code:: console
|
.. code:: console
|
||||||
|
|
||||||
$ wpctl status # find the target endpoint id
|
$ wpctl status # find the target device node id
|
||||||
$ wpctl inspect <endpoint_id> # find the node.id
|
$ wpctl inspect <node_id> # find the node.id
|
||||||
$ PIPEWIRE_NODE=<node_id> pw-jack jack_simple_client
|
$ PIPEWIRE_NODE=<node_id> pw-jack jack_simple_client
|
||||||
|
|
||||||
.. note::
|
.. note::
|
||||||
|
|
||||||
The JACK layer is not controlled by the session manager, it creates its own
|
The JACK layer is not controlled by the session manager, it creates its own
|
||||||
links; which is why it is required to specify a node id (endpoint id will not
|
links; which is why it is required to specify a node id.
|
||||||
work)
|
|
||||||
|
|
||||||
Device Reservation
|
Device Reservation
|
||||||
------------------
|
------------------
|
||||||
@@ -263,7 +261,7 @@ with JACK
|
|||||||
3. Wait a few seconds and run ``wpctl status`` to inspect
|
3. Wait a few seconds and run ``wpctl status`` to inspect
|
||||||
|
|
||||||
- The devices taken by JACK should no longer be available
|
- The devices taken by JACK should no longer be available
|
||||||
- There should be two *JACK System* endpoints (sink & source)
|
- There should be two *JACK System* nodes (sink & source)
|
||||||
|
|
||||||
4. Run an audio client on PipeWire (ex ``pw-play test.wav``)
|
4. Run an audio client on PipeWire (ex ``pw-play test.wav``)
|
||||||
|
|
||||||
@@ -277,7 +275,7 @@ with JACK
|
|||||||
6. Wait a few seconds and run ``wpctl status`` to inspect
|
6. Wait a few seconds and run ``wpctl status`` to inspect
|
||||||
|
|
||||||
- The devices that were release by JACK should again be available
|
- The devices that were release by JACK should again be available
|
||||||
- There should be no *JACK System* endpoint
|
- There should be no *JACK System* nodes
|
||||||
|
|
||||||
.. note::
|
.. note::
|
||||||
|
|
||||||
|
@@ -76,11 +76,11 @@ shared_library(
|
|||||||
)
|
)
|
||||||
|
|
||||||
shared_library(
|
shared_library(
|
||||||
'wireplumber-module-si-audio-endpoint',
|
'wireplumber-module-si-audio-virtual',
|
||||||
[
|
[
|
||||||
'module-si-audio-endpoint.c',
|
'module-si-audio-virtual.c',
|
||||||
],
|
],
|
||||||
c_args : [common_c_args, '-DG_LOG_DOMAIN="m-si-audio-endpoint"'],
|
c_args : [common_c_args, '-DG_LOG_DOMAIN="m-si-audio-virtual"'],
|
||||||
install : true,
|
install : true,
|
||||||
install_dir : wireplumber_module_dir,
|
install_dir : wireplumber_module_dir,
|
||||||
dependencies : [wp_dep, pipewire_dep],
|
dependencies : [wp_dep, pipewire_dep],
|
||||||
|
@@ -175,13 +175,6 @@ local Feature = {
|
|||||||
Node = {
|
Node = {
|
||||||
PORTS = (1 << 16),
|
PORTS = (1 << 16),
|
||||||
},
|
},
|
||||||
Session = {
|
|
||||||
ENDPOINTS = (1 << 16),
|
|
||||||
LINKS = (1 << 17),
|
|
||||||
},
|
|
||||||
Endpoint = {
|
|
||||||
STREAMS = (1 << 16),
|
|
||||||
},
|
|
||||||
Metadata = {
|
Metadata = {
|
||||||
DATA = (1 << 16),
|
DATA = (1 << 16),
|
||||||
},
|
},
|
||||||
|
@@ -12,9 +12,9 @@
|
|||||||
#include <spa/param/audio/raw.h>
|
#include <spa/param/audio/raw.h>
|
||||||
#include <spa/param/param.h>
|
#include <spa/param/param.h>
|
||||||
|
|
||||||
#define SI_FACTORY_NAME "si-audio-endpoint"
|
#define SI_FACTORY_NAME "si-audio-virtual"
|
||||||
|
|
||||||
struct _WpSiAudioEndpoint
|
struct _WpSiAudioVirtual
|
||||||
{
|
{
|
||||||
WpSessionItem parent;
|
WpSessionItem parent;
|
||||||
|
|
||||||
@@ -31,26 +31,26 @@ struct _WpSiAudioEndpoint
|
|||||||
WpSiAdapter *adapter;
|
WpSiAdapter *adapter;
|
||||||
};
|
};
|
||||||
|
|
||||||
static void si_audio_endpoint_linkable_init (WpSiLinkableInterface * iface);
|
static void si_audio_virtual_linkable_init (WpSiLinkableInterface * iface);
|
||||||
static void si_audio_endpoint_adapter_init (WpSiAdapterInterface * iface);
|
static void si_audio_virtual_adapter_init (WpSiAdapterInterface * iface);
|
||||||
|
|
||||||
G_DECLARE_FINAL_TYPE(WpSiAudioEndpoint, si_audio_endpoint, WP,
|
G_DECLARE_FINAL_TYPE(WpSiAudioVirtual, si_audio_virtual, WP,
|
||||||
SI_AUDIO_ENDPOINT, WpSessionItem)
|
SI_AUDIO_VIRTUAL, WpSessionItem)
|
||||||
G_DEFINE_TYPE_WITH_CODE (WpSiAudioEndpoint, si_audio_endpoint,
|
G_DEFINE_TYPE_WITH_CODE (WpSiAudioVirtual, si_audio_virtual,
|
||||||
WP_TYPE_SESSION_ITEM,
|
WP_TYPE_SESSION_ITEM,
|
||||||
G_IMPLEMENT_INTERFACE (WP_TYPE_SI_LINKABLE,
|
G_IMPLEMENT_INTERFACE (WP_TYPE_SI_LINKABLE,
|
||||||
si_audio_endpoint_linkable_init)
|
si_audio_virtual_linkable_init)
|
||||||
G_IMPLEMENT_INTERFACE (WP_TYPE_SI_ADAPTER, si_audio_endpoint_adapter_init))
|
G_IMPLEMENT_INTERFACE (WP_TYPE_SI_ADAPTER, si_audio_virtual_adapter_init))
|
||||||
|
|
||||||
static void
|
static void
|
||||||
si_audio_endpoint_init (WpSiAudioEndpoint * self)
|
si_audio_virtual_init (WpSiAudioVirtual * self)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
si_audio_endpoint_reset (WpSessionItem * item)
|
si_audio_virtual_reset (WpSessionItem * item)
|
||||||
{
|
{
|
||||||
WpSiAudioEndpoint *self = WP_SI_AUDIO_ENDPOINT (item);
|
WpSiAudioVirtual *self = WP_SI_AUDIO_VIRTUAL (item);
|
||||||
|
|
||||||
/* deactivate first */
|
/* deactivate first */
|
||||||
wp_object_deactivate (WP_OBJECT (self),
|
wp_object_deactivate (WP_OBJECT (self),
|
||||||
@@ -64,18 +64,18 @@ si_audio_endpoint_reset (WpSessionItem * item)
|
|||||||
self->priority = 0;
|
self->priority = 0;
|
||||||
self->disable_dsp = FALSE;
|
self->disable_dsp = FALSE;
|
||||||
|
|
||||||
WP_SESSION_ITEM_CLASS (si_audio_endpoint_parent_class)->reset (item);
|
WP_SESSION_ITEM_CLASS (si_audio_virtual_parent_class)->reset (item);
|
||||||
}
|
}
|
||||||
|
|
||||||
static gboolean
|
static gboolean
|
||||||
si_audio_endpoint_configure (WpSessionItem * item, WpProperties *p)
|
si_audio_virtual_configure (WpSessionItem * item, WpProperties *p)
|
||||||
{
|
{
|
||||||
WpSiAudioEndpoint *self = WP_SI_AUDIO_ENDPOINT (item);
|
WpSiAudioVirtual *self = WP_SI_AUDIO_VIRTUAL (item);
|
||||||
g_autoptr (WpProperties) si_props = wp_properties_ensure_unique_owner (p);
|
g_autoptr (WpProperties) si_props = wp_properties_ensure_unique_owner (p);
|
||||||
const gchar *str;
|
const gchar *str;
|
||||||
|
|
||||||
/* reset previous config */
|
/* reset previous config */
|
||||||
si_audio_endpoint_reset (item);
|
si_audio_virtual_reset (item);
|
||||||
|
|
||||||
str = wp_properties_get (si_props, "name");
|
str = wp_properties_get (si_props, "name");
|
||||||
if (!str)
|
if (!str)
|
||||||
@@ -116,18 +116,18 @@ si_audio_endpoint_configure (WpSessionItem * item, WpProperties *p)
|
|||||||
}
|
}
|
||||||
|
|
||||||
static gpointer
|
static gpointer
|
||||||
si_audio_endpoint_get_associated_proxy (WpSessionItem * item, GType proxy_type)
|
si_audio_virtual_get_associated_proxy (WpSessionItem * item, GType proxy_type)
|
||||||
{
|
{
|
||||||
WpSiAudioEndpoint *self = WP_SI_AUDIO_ENDPOINT (item);
|
WpSiAudioVirtual *self = WP_SI_AUDIO_VIRTUAL (item);
|
||||||
|
|
||||||
return wp_session_item_get_associated_proxy (
|
return wp_session_item_get_associated_proxy (
|
||||||
WP_SESSION_ITEM (self->adapter), proxy_type);
|
WP_SESSION_ITEM (self->adapter), proxy_type);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
si_audio_endpoint_disable_active (WpSessionItem *si)
|
si_audio_virtual_disable_active (WpSessionItem *si)
|
||||||
{
|
{
|
||||||
WpSiAudioEndpoint *self = WP_SI_AUDIO_ENDPOINT (si);
|
WpSiAudioVirtual *self = WP_SI_AUDIO_VIRTUAL (si);
|
||||||
|
|
||||||
g_clear_object (&self->adapter);
|
g_clear_object (&self->adapter);
|
||||||
g_clear_object (&self->node);
|
g_clear_object (&self->node);
|
||||||
@@ -136,9 +136,9 @@ si_audio_endpoint_disable_active (WpSessionItem *si)
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
si_audio_endpoint_disable_exported (WpSessionItem *si)
|
si_audio_virtual_disable_exported (WpSessionItem *si)
|
||||||
{
|
{
|
||||||
WpSiAudioEndpoint *self = WP_SI_AUDIO_ENDPOINT (si);
|
WpSiAudioVirtual *self = WP_SI_AUDIO_VIRTUAL (si);
|
||||||
|
|
||||||
wp_object_update_features (WP_OBJECT (self), 0,
|
wp_object_update_features (WP_OBJECT (self), 0,
|
||||||
WP_SESSION_ITEM_FEATURE_EXPORTED);
|
WP_SESSION_ITEM_FEATURE_EXPORTED);
|
||||||
@@ -148,7 +148,7 @@ static void
|
|||||||
on_adapter_activate_done (WpObject * adapter, GAsyncResult * res,
|
on_adapter_activate_done (WpObject * adapter, GAsyncResult * res,
|
||||||
WpTransition * transition)
|
WpTransition * transition)
|
||||||
{
|
{
|
||||||
WpSiAudioEndpoint *self = wp_transition_get_source_object (transition);
|
WpSiAudioVirtual *self = wp_transition_get_source_object (transition);
|
||||||
g_autoptr (GError) error = NULL;
|
g_autoptr (GError) error = NULL;
|
||||||
|
|
||||||
if (!wp_object_activate_finish (adapter, res, &error)) {
|
if (!wp_object_activate_finish (adapter, res, &error)) {
|
||||||
@@ -163,7 +163,7 @@ on_adapter_activate_done (WpObject * adapter, GAsyncResult * res,
|
|||||||
static void
|
static void
|
||||||
on_adapter_port_state_changed (WpSiAdapter *item,
|
on_adapter_port_state_changed (WpSiAdapter *item,
|
||||||
WpSiAdapterPortsState old_state, WpSiAdapterPortsState new_state,
|
WpSiAdapterPortsState old_state, WpSiAdapterPortsState new_state,
|
||||||
WpSiAudioEndpoint *self)
|
WpSiAudioVirtual *self)
|
||||||
{
|
{
|
||||||
g_signal_emit_by_name (self, "adapter-ports-state-changed", old_state,
|
g_signal_emit_by_name (self, "adapter-ports-state-changed", old_state,
|
||||||
new_state);
|
new_state);
|
||||||
@@ -173,7 +173,7 @@ static void
|
|||||||
on_node_activate_done (WpObject * node, GAsyncResult * res,
|
on_node_activate_done (WpObject * node, GAsyncResult * res,
|
||||||
WpTransition * transition)
|
WpTransition * transition)
|
||||||
{
|
{
|
||||||
WpSiAudioEndpoint *self = wp_transition_get_source_object (transition);
|
WpSiAudioVirtual *self = wp_transition_get_source_object (transition);
|
||||||
g_autoptr (GError) error = NULL;
|
g_autoptr (GError) error = NULL;
|
||||||
g_autoptr (WpCore) core = NULL;
|
g_autoptr (WpCore) core = NULL;
|
||||||
g_autoptr (WpProperties) props = NULL;
|
g_autoptr (WpProperties) props = NULL;
|
||||||
@@ -190,7 +190,7 @@ on_node_activate_done (WpObject * node, GAsyncResult * res,
|
|||||||
if (!self->adapter) {
|
if (!self->adapter) {
|
||||||
wp_transition_return_error (transition,
|
wp_transition_return_error (transition,
|
||||||
g_error_new (WP_DOMAIN_LIBRARY, WP_LIBRARY_ERROR_INVARIANT,
|
g_error_new (WP_DOMAIN_LIBRARY, WP_LIBRARY_ERROR_INVARIANT,
|
||||||
"si-audio-endpoint: could not create si-audio-adapter"));
|
"si-audio-virtual: could not create si-audio-adapter"));
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Forward adapter-ports-state-changed signal */
|
/* Forward adapter-ports-state-changed signal */
|
||||||
@@ -210,7 +210,7 @@ on_node_activate_done (WpObject * node, GAsyncResult * res,
|
|||||||
g_steal_pointer (&props))) {
|
g_steal_pointer (&props))) {
|
||||||
wp_transition_return_error (transition,
|
wp_transition_return_error (transition,
|
||||||
g_error_new (WP_DOMAIN_LIBRARY, WP_LIBRARY_ERROR_INVARIANT,
|
g_error_new (WP_DOMAIN_LIBRARY, WP_LIBRARY_ERROR_INVARIANT,
|
||||||
"si-audio-endpoint: could not configure si-audio-adapter"));
|
"si-audio-virtual: could not configure si-audio-adapter"));
|
||||||
}
|
}
|
||||||
|
|
||||||
/* activate adapter */
|
/* activate adapter */
|
||||||
@@ -219,12 +219,12 @@ on_node_activate_done (WpObject * node, GAsyncResult * res,
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
si_audio_endpoint_enable_active (WpSessionItem *si, WpTransition *transition)
|
si_audio_virtual_enable_active (WpSessionItem *si, WpTransition *transition)
|
||||||
{
|
{
|
||||||
WpSiAudioEndpoint *self = WP_SI_AUDIO_ENDPOINT (si);
|
WpSiAudioVirtual *self = WP_SI_AUDIO_VIRTUAL (si);
|
||||||
g_autoptr (WpCore) core = wp_object_get_core (WP_OBJECT (self));
|
g_autoptr (WpCore) core = wp_object_get_core (WP_OBJECT (self));
|
||||||
g_autofree gchar *name = g_strdup_printf ("control.%s", self->name);
|
g_autofree gchar *name = g_strdup_printf ("control.%s", self->name);
|
||||||
g_autofree gchar *desc = g_strdup_printf ("%s %s Endpoint", self->role,
|
g_autofree gchar *desc = g_strdup_printf ("%s %s Virtual", self->role,
|
||||||
(self->direction == WP_DIRECTION_OUTPUT) ? "Capture" : "Playback");
|
(self->direction == WP_DIRECTION_OUTPUT) ? "Capture" : "Playback");
|
||||||
g_autofree gchar *media = g_strdup_printf ("Audio/%s",
|
g_autofree gchar *media = g_strdup_printf ("Audio/%s",
|
||||||
(self->direction == WP_DIRECTION_OUTPUT) ? "Source" : "Sink");
|
(self->direction == WP_DIRECTION_OUTPUT) ? "Source" : "Sink");
|
||||||
@@ -232,7 +232,7 @@ si_audio_endpoint_enable_active (WpSessionItem *si, WpTransition *transition)
|
|||||||
if (!wp_session_item_is_configured (si)) {
|
if (!wp_session_item_is_configured (si)) {
|
||||||
wp_transition_return_error (transition,
|
wp_transition_return_error (transition,
|
||||||
g_error_new (WP_DOMAIN_LIBRARY, WP_LIBRARY_ERROR_INVARIANT,
|
g_error_new (WP_DOMAIN_LIBRARY, WP_LIBRARY_ERROR_INVARIANT,
|
||||||
"si-audio-endpoint: item is not configured"));
|
"si-audio-virtual: item is not configured"));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -244,12 +244,12 @@ si_audio_endpoint_enable_active (WpSessionItem *si, WpTransition *transition)
|
|||||||
PW_KEY_FACTORY_NAME, "support.null-audio-sink",
|
PW_KEY_FACTORY_NAME, "support.null-audio-sink",
|
||||||
PW_KEY_NODE_DESCRIPTION, desc,
|
PW_KEY_NODE_DESCRIPTION, desc,
|
||||||
"monitor.channel-volumes", "true",
|
"monitor.channel-volumes", "true",
|
||||||
"wireplumber.is-endpoint", "true",
|
"wireplumber.is-virtual", "true",
|
||||||
NULL));
|
NULL));
|
||||||
if (!self->node) {
|
if (!self->node) {
|
||||||
wp_transition_return_error (transition,
|
wp_transition_return_error (transition,
|
||||||
g_error_new (WP_DOMAIN_LIBRARY, WP_LIBRARY_ERROR_INVARIANT,
|
g_error_new (WP_DOMAIN_LIBRARY, WP_LIBRARY_ERROR_INVARIANT,
|
||||||
"si-audio-endpoint: could not create null-audio-sink node"));
|
"si-audio-virtual: could not create null-audio-sink node"));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -260,84 +260,84 @@ si_audio_endpoint_enable_active (WpSessionItem *si, WpTransition *transition)
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
si_audio_endpoint_enable_exported (WpSessionItem *si, WpTransition *transition)
|
si_audio_virtual_enable_exported (WpSessionItem *si, WpTransition *transition)
|
||||||
{
|
{
|
||||||
WpSiAudioEndpoint *self = WP_SI_AUDIO_ENDPOINT (si);
|
WpSiAudioVirtual *self = WP_SI_AUDIO_VIRTUAL (si);
|
||||||
|
|
||||||
wp_object_update_features (WP_OBJECT (self),
|
wp_object_update_features (WP_OBJECT (self),
|
||||||
WP_SESSION_ITEM_FEATURE_EXPORTED, 0);
|
WP_SESSION_ITEM_FEATURE_EXPORTED, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
si_audio_endpoint_class_init (WpSiAudioEndpointClass * klass)
|
si_audio_virtual_class_init (WpSiAudioVirtualClass * klass)
|
||||||
{
|
{
|
||||||
WpSessionItemClass *si_class = (WpSessionItemClass *) klass;
|
WpSessionItemClass *si_class = (WpSessionItemClass *) klass;
|
||||||
|
|
||||||
si_class->reset = si_audio_endpoint_reset;
|
si_class->reset = si_audio_virtual_reset;
|
||||||
si_class->configure = si_audio_endpoint_configure;
|
si_class->configure = si_audio_virtual_configure;
|
||||||
si_class->get_associated_proxy = si_audio_endpoint_get_associated_proxy;
|
si_class->get_associated_proxy = si_audio_virtual_get_associated_proxy;
|
||||||
si_class->disable_active = si_audio_endpoint_disable_active;
|
si_class->disable_active = si_audio_virtual_disable_active;
|
||||||
si_class->disable_exported = si_audio_endpoint_disable_exported;
|
si_class->disable_exported = si_audio_virtual_disable_exported;
|
||||||
si_class->enable_active = si_audio_endpoint_enable_active;
|
si_class->enable_active = si_audio_virtual_enable_active;
|
||||||
si_class->enable_exported = si_audio_endpoint_enable_exported;
|
si_class->enable_exported = si_audio_virtual_enable_exported;
|
||||||
}
|
}
|
||||||
|
|
||||||
static GVariant *
|
static GVariant *
|
||||||
si_audio_endpoint_get_ports (WpSiLinkable * item, const gchar * context)
|
si_audio_virtual_get_ports (WpSiLinkable * item, const gchar * context)
|
||||||
{
|
{
|
||||||
WpSiAudioEndpoint *self = WP_SI_AUDIO_ENDPOINT (item);
|
WpSiAudioVirtual *self = WP_SI_AUDIO_VIRTUAL (item);
|
||||||
return wp_si_linkable_get_ports (WP_SI_LINKABLE (self->adapter), context);
|
return wp_si_linkable_get_ports (WP_SI_LINKABLE (self->adapter), context);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
si_audio_endpoint_linkable_init (WpSiLinkableInterface * iface)
|
si_audio_virtual_linkable_init (WpSiLinkableInterface * iface)
|
||||||
{
|
{
|
||||||
iface->get_ports = si_audio_endpoint_get_ports;
|
iface->get_ports = si_audio_virtual_get_ports;
|
||||||
}
|
}
|
||||||
|
|
||||||
static WpSiAdapterPortsState
|
static WpSiAdapterPortsState
|
||||||
si_audio_endpoint_get_ports_state (WpSiAdapter * item)
|
si_audio_virtual_get_ports_state (WpSiAdapter * item)
|
||||||
{
|
{
|
||||||
WpSiAudioEndpoint *self = WP_SI_AUDIO_ENDPOINT (item);
|
WpSiAudioVirtual *self = WP_SI_AUDIO_VIRTUAL (item);
|
||||||
return wp_si_adapter_get_ports_state (self->adapter);
|
return wp_si_adapter_get_ports_state (self->adapter);
|
||||||
}
|
}
|
||||||
|
|
||||||
static WpSpaPod *
|
static WpSpaPod *
|
||||||
si_audio_endpoint_get_ports_format (WpSiAdapter * item, const gchar **mode)
|
si_audio_virtual_get_ports_format (WpSiAdapter * item, const gchar **mode)
|
||||||
{
|
{
|
||||||
WpSiAudioEndpoint *self = WP_SI_AUDIO_ENDPOINT (item);
|
WpSiAudioVirtual *self = WP_SI_AUDIO_VIRTUAL (item);
|
||||||
return wp_si_adapter_get_ports_format (self->adapter, mode);
|
return wp_si_adapter_get_ports_format (self->adapter, mode);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
si_audio_endpoint_set_ports_format (WpSiAdapter * item, WpSpaPod *f,
|
si_audio_virtual_set_ports_format (WpSiAdapter * item, WpSpaPod *f,
|
||||||
const gchar *mode, GAsyncReadyCallback callback, gpointer data)
|
const gchar *mode, GAsyncReadyCallback callback, gpointer data)
|
||||||
{
|
{
|
||||||
WpSiAudioEndpoint *self = WP_SI_AUDIO_ENDPOINT (item);
|
WpSiAudioVirtual *self = WP_SI_AUDIO_VIRTUAL (item);
|
||||||
wp_si_adapter_set_ports_format (self->adapter, f, mode, callback, data);
|
wp_si_adapter_set_ports_format (self->adapter, f, mode, callback, data);
|
||||||
}
|
}
|
||||||
|
|
||||||
static gboolean
|
static gboolean
|
||||||
si_audio_endpoint_set_ports_format_finish (WpSiAdapter * item,
|
si_audio_virtual_set_ports_format_finish (WpSiAdapter * item,
|
||||||
GAsyncResult * res, GError ** error)
|
GAsyncResult * res, GError ** error)
|
||||||
{
|
{
|
||||||
WpSiAudioEndpoint *self = WP_SI_AUDIO_ENDPOINT (item);
|
WpSiAudioVirtual *self = WP_SI_AUDIO_VIRTUAL (item);
|
||||||
return wp_si_adapter_set_ports_format_finish (self->adapter, res, error);
|
return wp_si_adapter_set_ports_format_finish (self->adapter, res, error);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
si_audio_endpoint_adapter_init (WpSiAdapterInterface * iface)
|
si_audio_virtual_adapter_init (WpSiAdapterInterface * iface)
|
||||||
{
|
{
|
||||||
iface->get_ports_state = si_audio_endpoint_get_ports_state;
|
iface->get_ports_state = si_audio_virtual_get_ports_state;
|
||||||
iface->get_ports_format = si_audio_endpoint_get_ports_format;
|
iface->get_ports_format = si_audio_virtual_get_ports_format;
|
||||||
iface->set_ports_format = si_audio_endpoint_set_ports_format;
|
iface->set_ports_format = si_audio_virtual_set_ports_format;
|
||||||
iface->set_ports_format_finish = si_audio_endpoint_set_ports_format_finish;
|
iface->set_ports_format_finish = si_audio_virtual_set_ports_format_finish;
|
||||||
}
|
}
|
||||||
|
|
||||||
WP_PLUGIN_EXPORT gboolean
|
WP_PLUGIN_EXPORT gboolean
|
||||||
wireplumber__module_init (WpCore * core, GVariant * args, GError ** error)
|
wireplumber__module_init (WpCore * core, GVariant * args, GError ** error)
|
||||||
{
|
{
|
||||||
wp_si_factory_register (core, wp_si_factory_new_simple (SI_FACTORY_NAME,
|
wp_si_factory_register (core, wp_si_factory_new_simple (SI_FACTORY_NAME,
|
||||||
si_audio_endpoint_get_type ()));
|
si_audio_virtual_get_type ()));
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
@@ -550,10 +550,10 @@ configure_and_link_adapters (WpSiStandardLink *self, WpTransition *transition)
|
|||||||
in->is_device = !g_strcmp0 (str, "device");
|
in->is_device = !g_strcmp0 (str, "device");
|
||||||
|
|
||||||
str = wp_session_item_get_property (WP_SESSION_ITEM (out->si), "item.factory.name");
|
str = wp_session_item_get_property (WP_SESSION_ITEM (out->si), "item.factory.name");
|
||||||
out->is_device = (str && !g_strcmp0 (str, "si-audio-endpoint") && !in->is_device)
|
out->is_device = (str && !g_strcmp0 (str, "si-audio-virtual") && !in->is_device)
|
||||||
|| out->is_device;
|
|| out->is_device;
|
||||||
str = wp_session_item_get_property (WP_SESSION_ITEM (in->si), "item.factory.name");
|
str = wp_session_item_get_property (WP_SESSION_ITEM (in->si), "item.factory.name");
|
||||||
in->is_device = (str && !g_strcmp0 (str, "si-audio-endpoint") && !out->is_device)
|
in->is_device = (str && !g_strcmp0 (str, "si-audio-virtual") && !out->is_device)
|
||||||
|| in->is_device;
|
|| in->is_device;
|
||||||
|
|
||||||
str = wp_session_item_get_property (WP_SESSION_ITEM (out->si), "stream.dont-remix");
|
str = wp_session_item_get_property (WP_SESSION_ITEM (out->si), "stream.dont-remix");
|
||||||
|
@@ -131,7 +131,7 @@ wireplumber.components = [
|
|||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
name = libwireplumber-module-si-audio-endpoint,
|
name = libwireplumber-module-si-audio-virtual,
|
||||||
type = module
|
type = module
|
||||||
## default priority for session item modules
|
## default priority for session item modules
|
||||||
priority = 130
|
priority = 130
|
||||||
|
@@ -1,48 +1,48 @@
|
|||||||
## The WirePlumber endpoint configuration
|
## The WirePlumber virtual item configuration
|
||||||
|
|
||||||
endpoints = {
|
virtual-items = {
|
||||||
## The list of endpoints to create
|
## The list of virtual items to create
|
||||||
|
|
||||||
# endpoint.capture = {
|
# virtual-item.capture = {
|
||||||
# media.class = "Audio/Source"
|
# media.class = "Audio/Source"
|
||||||
# role = "Capture"
|
# role = "Capture"
|
||||||
# }
|
# }
|
||||||
# endpoint.multimedia = {
|
# virtual-item.multimedia = {
|
||||||
# media.class = "Audio/Sink"
|
# media.class = "Audio/Sink"
|
||||||
# role = "Multimedia"
|
# role = "Multimedia"
|
||||||
# }
|
# }
|
||||||
# endpoint.speech_low = {
|
# virtual-item.speech_low = {
|
||||||
# media.class = "Audio/Sink"
|
# media.class = "Audio/Sink"
|
||||||
# role = "Speech-Low"
|
# role = "Speech-Low"
|
||||||
# }
|
# }
|
||||||
# endpoint.custom_low = {
|
# virtual-item.custom_low = {
|
||||||
# media.class = "Audio/Sink"
|
# media.class = "Audio/Sink"
|
||||||
# role = "Custom-Low"
|
# role = "Custom-Low"
|
||||||
# }
|
# }
|
||||||
# endpoint.navigation = {
|
# virtual-item.navigation = {
|
||||||
# media.class = "Audio/Sink"
|
# media.class = "Audio/Sink"
|
||||||
# role = "Navigation"
|
# role = "Navigation"
|
||||||
# }
|
# }
|
||||||
# endpoint.speech_high = {
|
# virtual-item.speech_high = {
|
||||||
# media.class = "Audio/Sink"
|
# media.class = "Audio/Sink"
|
||||||
# role = "Speech-High"
|
# role = "Speech-High"
|
||||||
# }
|
# }
|
||||||
# endpoint.custom_high = {
|
# virtual-item.custom_high = {
|
||||||
# media.class = "Audio/Sink"
|
# media.class = "Audio/Sink"
|
||||||
# role = "Custom-High"
|
# role = "Custom-High"
|
||||||
# }
|
# }
|
||||||
# endpoint.communication = {
|
# virtual-item.communication = {
|
||||||
# media.class = "Audio/Sink"
|
# media.class = "Audio/Sink"
|
||||||
# role = "Communication"
|
# role = "Communication"
|
||||||
# }
|
# }
|
||||||
# endpoint.emergency = {
|
# virtual-item.emergency = {
|
||||||
# media.class = "Audio/Sink"
|
# media.class = "Audio/Sink"
|
||||||
# role = "Emergency"
|
# role = "Emergency"
|
||||||
# }
|
# }
|
||||||
}
|
}
|
||||||
|
|
||||||
endpoint-roles = {
|
virtual-item-roles = {
|
||||||
## The list of endpoint roles to use
|
## The list of virtual item roles to use
|
||||||
|
|
||||||
# Capture = {
|
# Capture = {
|
||||||
# alias = [ "Multimedia", "Music", "Voice", "Capture" ]
|
# alias = [ "Multimedia", "Music", "Voice", "Capture" ]
|
42
src/scripts/create-virtual-item.lua
Normal file
42
src/scripts/create-virtual-item.lua
Normal file
@@ -0,0 +1,42 @@
|
|||||||
|
-- WirePlumber
|
||||||
|
--
|
||||||
|
-- Copyright © 2021 Collabora Ltd.
|
||||||
|
-- @author Julian Bouzas <julian.bouzas@collabora.com>
|
||||||
|
--
|
||||||
|
-- SPDX-License-Identifier: MIT
|
||||||
|
|
||||||
|
-- Receive script arguments from config.lua
|
||||||
|
|
||||||
|
local defaults = {}
|
||||||
|
defaults.virtual_items = Json.Object {}
|
||||||
|
|
||||||
|
local config = {}
|
||||||
|
config.virtual_items = Conf.get_section (
|
||||||
|
"virtual-items", defaults.virtual_items):parse ()
|
||||||
|
|
||||||
|
function createVirtualItem (factory_name, properties)
|
||||||
|
-- create virtual item
|
||||||
|
local si_v = SessionItem ( factory_name )
|
||||||
|
if not si_v then
|
||||||
|
Log.warning (si_v, "could not create virtual item of type " .. factory_name)
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
-- configure virtual item
|
||||||
|
if not si_v:configure(properties) then
|
||||||
|
Log.warning(si_v, "failed to configure virtual item " .. properties.name)
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
-- activate and register virtual item
|
||||||
|
si_v:activate (Features.ALL, function (item)
|
||||||
|
item:register ()
|
||||||
|
Log.info(item, "registered virtual item " .. properties.name)
|
||||||
|
end)
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
for name, properties in pairs(config.virtual_items) do
|
||||||
|
properties["name"] = name
|
||||||
|
createVirtualItem ("si-audio-virtual", properties)
|
||||||
|
end
|
@@ -12,8 +12,8 @@ node_om = ObjectManager {
|
|||||||
Interest {
|
Interest {
|
||||||
type = "node",
|
type = "node",
|
||||||
Constraint { "media.class", "matches", "Audio/Sink", type = "pw-global" },
|
Constraint { "media.class", "matches", "Audio/Sink", type = "pw-global" },
|
||||||
-- Do not consider endpoints created by WirePlumber
|
-- Do not consider virtual items created by WirePlumber
|
||||||
Constraint { "wireplumber.is-endpoint", "!", true, type = "pw" },
|
Constraint { "wireplumber.is-virtual", "!", true, type = "pw" },
|
||||||
-- or the fallback sink itself
|
-- or the fallback sink itself
|
||||||
Constraint { "wireplumber.is-fallback", "!", true, type = "pw" },
|
Constraint { "wireplumber.is-fallback", "!", true, type = "pw" },
|
||||||
}
|
}
|
||||||
|
@@ -22,8 +22,7 @@ function checkLinkable (si, om, handle_nonstreams)
|
|||||||
end
|
end
|
||||||
|
|
||||||
-- Determine if we can handle item by this policy
|
-- Determine if we can handle item by this policy
|
||||||
if om:lookup { type = "SiEndpoint" } and
|
if si_props ["item.factory.name"] == "si-audio-virtual" then
|
||||||
si_props ["item.factory.name"] == "si-audio-adapter" then
|
|
||||||
return false
|
return false
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@@ -74,7 +74,7 @@ AsyncEventHook {
|
|||||||
EventInterest {
|
EventInterest {
|
||||||
Constraint { "event.type", "=", "node-added" },
|
Constraint { "event.type", "=", "node-added" },
|
||||||
Constraint { "media.class", "#", "Audio/*", type = "pw-global" },
|
Constraint { "media.class", "#", "Audio/*", type = "pw-global" },
|
||||||
Constraint { "wireplumber.is-endpoint", "-", type = "pw" },
|
Constraint { "wireplumber.is-virtual", "-", type = "pw" },
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
steps = {
|
steps = {
|
||||||
@@ -144,7 +144,7 @@ SimpleEventHook {
|
|||||||
EventInterest {
|
EventInterest {
|
||||||
Constraint { "event.type", "=", "node-removed" },
|
Constraint { "event.type", "=", "node-removed" },
|
||||||
Constraint { "media.class", "#", "Audio/*", type = "pw-global" },
|
Constraint { "media.class", "#", "Audio/*", type = "pw-global" },
|
||||||
Constraint { "wireplumber.is-endpoint", "-", type = "pw" },
|
Constraint { "wireplumber.is-virtual", "-", type = "pw" },
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
execute = function (event)
|
execute = function (event)
|
||||||
|
@@ -13,7 +13,7 @@ local config = {}
|
|||||||
config.duck_level = Conf.get_value_float ("wireplumber.settings",
|
config.duck_level = Conf.get_value_float ("wireplumber.settings",
|
||||||
"policy.default.duck-level", defaults.duck_level)
|
"policy.default.duck-level", defaults.duck_level)
|
||||||
config.roles = Conf.get_section (
|
config.roles = Conf.get_section (
|
||||||
"endpoint-roles", defaults.roles):parse ()
|
"virtual-item-roles", defaults.roles):parse ()
|
||||||
|
|
||||||
function findRole(role)
|
function findRole(role)
|
||||||
if role and not config.roles[role] then
|
if role and not config.roles[role] then
|
||||||
@@ -50,32 +50,38 @@ end
|
|||||||
function restoreVolume(role, media_class)
|
function restoreVolume(role, media_class)
|
||||||
if not mixer_api then return end
|
if not mixer_api then return end
|
||||||
|
|
||||||
local ep = endpoints_om:lookup {
|
local si_v = virtuals_om:lookup {
|
||||||
Constraint { "media.role", "=", role, type = "pw" },
|
Constraint { "media.role", "=", role, type = "pw" },
|
||||||
Constraint { "media.class", "=", media_class, type = "pw" },
|
Constraint { "media.class", "=", media_class, type = "pw" },
|
||||||
}
|
}
|
||||||
|
|
||||||
if ep and ep.properties["node.id"] then
|
if si_v then
|
||||||
Log.debug(ep, "restore role " .. role)
|
local n = si_v:get_associated_proxy ("node")
|
||||||
mixer_api:call("set-volume", ep.properties["node.id"], {
|
if n then
|
||||||
monitorVolume = 1.0,
|
Log.debug(si_v, "restore role " .. role)
|
||||||
})
|
mixer_api:call("set-volume", n["bound-id"], {
|
||||||
|
monitorVolume = 1.0,
|
||||||
|
})
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
function duck(role, media_class)
|
function duck(role, media_class)
|
||||||
if not mixer_api then return end
|
if not mixer_api then return end
|
||||||
|
|
||||||
local ep = endpoints_om:lookup {
|
local si_v = virtuals_om:lookup {
|
||||||
Constraint { "media.role", "=", role, type = "pw" },
|
Constraint { "media.role", "=", role, type = "pw" },
|
||||||
Constraint { "media.class", "=", media_class, type = "pw" },
|
Constraint { "media.class", "=", media_class, type = "pw" },
|
||||||
}
|
}
|
||||||
|
|
||||||
if ep and ep.properties["node.id"] then
|
if si_v then
|
||||||
Log.debug(ep, "duck role " .. role)
|
local n = si_v:get_associated_proxy ("node")
|
||||||
mixer_api:call("set-volume", ep.properties["node.id"], {
|
if n then
|
||||||
monitorVolume = config.duck_level,
|
Log.debug(si_v, "duck role " .. role)
|
||||||
})
|
mixer_api:call("set-volume", n["bound-id"], {
|
||||||
|
monitorVolume = config.duck_level,
|
||||||
|
})
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -98,7 +104,7 @@ function rescan()
|
|||||||
["Video/Source"] = {},
|
["Video/Source"] = {},
|
||||||
}
|
}
|
||||||
|
|
||||||
Log.info("Rescan endpoint links")
|
Log.info("Rescan virtual links")
|
||||||
|
|
||||||
-- deactivate all links if suspend playback metadata is present
|
-- deactivate all links if suspend playback metadata is present
|
||||||
local suspend = getSuspendPlaybackMetadata()
|
local suspend = getSuspendPlaybackMetadata()
|
||||||
@@ -193,7 +199,7 @@ end
|
|||||||
silinks_om = ObjectManager {
|
silinks_om = ObjectManager {
|
||||||
Interest {
|
Interest {
|
||||||
type = "SiLink",
|
type = "SiLink",
|
||||||
Constraint { "is.policy.endpoint.client.link", "=", true },
|
Constraint { "is.policy.virtual.client.link", "=", true },
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
silinks_om:connect("objects-changed", maybeRescan)
|
silinks_om:connect("objects-changed", maybeRescan)
|
||||||
@@ -202,10 +208,12 @@ silinks_om:activate()
|
|||||||
-- enable ducking if mixer-api is loaded
|
-- enable ducking if mixer-api is loaded
|
||||||
mixer_api = Plugin.find("mixer-api")
|
mixer_api = Plugin.find("mixer-api")
|
||||||
if mixer_api then
|
if mixer_api then
|
||||||
endpoints_om = ObjectManager {
|
virtuals_om = ObjectManager { Interest { type = "SiLinkable",
|
||||||
Interest { type = "endpoint" },
|
Constraint {
|
||||||
|
"item.factory.name", "=", "si-audio-virtual", type = "pw-global" },
|
||||||
|
}
|
||||||
}
|
}
|
||||||
endpoints_om:activate()
|
virtuals_om:activate()
|
||||||
end
|
end
|
||||||
|
|
||||||
metadata_om = ObjectManager {
|
metadata_om = ObjectManager {
|
@@ -12,7 +12,7 @@ defaults.roles = Json.Object {}
|
|||||||
|
|
||||||
local config = {}
|
local config = {}
|
||||||
config.roles = Conf.get_section (
|
config.roles = Conf.get_section (
|
||||||
"endpoint-roles", defaults.roles):parse ()
|
"virtual-item-roles", defaults.roles):parse ()
|
||||||
|
|
||||||
local self = {}
|
local self = {}
|
||||||
self.scanning = false
|
self.scanning = false
|
||||||
@@ -73,7 +73,7 @@ function findRole(role, tmc)
|
|||||||
return role
|
return role
|
||||||
end
|
end
|
||||||
|
|
||||||
function findTargetEndpoint (node, media_class, role)
|
function findTargetVirtual (node, media_class, role)
|
||||||
local target_class_assoc = {
|
local target_class_assoc = {
|
||||||
["Stream/Input/Audio"] = "Audio/Source",
|
["Stream/Input/Audio"] = "Audio/Source",
|
||||||
["Stream/Output/Audio"] = "Audio/Sink",
|
["Stream/Output/Audio"] = "Audio/Sink",
|
||||||
@@ -89,9 +89,9 @@ function findTargetEndpoint (node, media_class, role)
|
|||||||
return nil
|
return nil
|
||||||
end
|
end
|
||||||
|
|
||||||
-- find highest priority endpoint by role
|
-- find highest priority virtual by role
|
||||||
media_role = findRole(role, target_media_class)
|
media_role = findRole(role, target_media_class)
|
||||||
for si_target_ep in endpoints_om:iterate {
|
for si_target_ep in virtuals_om:iterate {
|
||||||
Constraint { "role", "=", media_role, type = "pw-global" },
|
Constraint { "role", "=", media_role, type = "pw-global" },
|
||||||
Constraint { "media.class", "=", target_media_class, type = "pw-global" },
|
Constraint { "media.class", "=", target_media_class, type = "pw-global" },
|
||||||
} do
|
} do
|
||||||
@@ -132,7 +132,7 @@ function createLink (si, si_target_ep)
|
|||||||
["in.item"] = in_item,
|
["in.item"] = in_item,
|
||||||
["out.item.port.context"] = "output",
|
["out.item.port.context"] = "output",
|
||||||
["in.item.port.context"] = "input",
|
["in.item.port.context"] = "input",
|
||||||
["is.policy.endpoint.client.link"] = true,
|
["is.policy.virtual.client.link"] = true,
|
||||||
["media.role"] = target_ep_props["role"],
|
["media.role"] = target_ep_props["role"],
|
||||||
["target.media.class"] = target_ep_props["media.class"],
|
["target.media.class"] = target_ep_props["media.class"],
|
||||||
["item.plugged.usec"] = si_props["item.plugged.usec"],
|
["item.plugged.usec"] = si_props["item.plugged.usec"],
|
||||||
@@ -159,7 +159,7 @@ function checkLinkable (si)
|
|||||||
end
|
end
|
||||||
|
|
||||||
-- Determine if we can handle item by this policy
|
-- Determine if we can handle item by this policy
|
||||||
if endpoints_om:get_n_objects () == 0 then
|
if virtuals_om:get_n_objects () == 0 then
|
||||||
Log.debug (si, "item won't be handled by this policy")
|
Log.debug (si, "item won't be handled by this policy")
|
||||||
return false
|
return false
|
||||||
end
|
end
|
||||||
@@ -178,10 +178,10 @@ function handleLinkable (si)
|
|||||||
Log.info (si, "handling item " .. tostring(node.properties["node.name"]) ..
|
Log.info (si, "handling item " .. tostring(node.properties["node.name"]) ..
|
||||||
" with role " .. media_role)
|
" with role " .. media_role)
|
||||||
|
|
||||||
-- find proper target endpoint
|
-- find proper target virtual
|
||||||
local si_target_ep = findTargetEndpoint (node, media_class, media_role)
|
local si_target_ep = findTargetVirtual (node, media_class, media_role)
|
||||||
if not si_target_ep then
|
if not si_target_ep then
|
||||||
Log.info (si, "... target endpoint not found")
|
Log.info (si, "... target virtual not found")
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -191,11 +191,11 @@ function handleLinkable (si)
|
|||||||
local in_id = tonumber(link.properties["in.item.id"])
|
local in_id = tonumber(link.properties["in.item.id"])
|
||||||
if out_id == si.id or in_id == si.id then
|
if out_id == si.id or in_id == si.id then
|
||||||
local is_out = out_id == si.id and true or false
|
local is_out = out_id == si.id and true or false
|
||||||
for peer_ep in endpoints_om:iterate() do
|
for peer_ep in virtuals_om:iterate() do
|
||||||
if peer_ep.id == (is_out and in_id or out_id) then
|
if peer_ep.id == (is_out and in_id or out_id) then
|
||||||
|
|
||||||
if peer_ep.id == si_target_ep.id then
|
if peer_ep.id == si_target_ep.id then
|
||||||
Log.info (si, "... already linked to proper target endpoint")
|
Log.info (si, "... already linked to proper target virtual")
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -237,7 +237,11 @@ function unhandleLinkable (si)
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
endpoints_om = ObjectManager { Interest { type = "SiEndpoint" }}
|
virtuals_om = ObjectManager { Interest { type = "SiLinkable",
|
||||||
|
Constraint {
|
||||||
|
"item.factory.name", "=", "si-audio-virtual", type = "pw-global" },
|
||||||
|
}
|
||||||
|
}
|
||||||
linkables_om = ObjectManager { Interest { type = "SiLinkable",
|
linkables_om = ObjectManager { Interest { type = "SiLinkable",
|
||||||
-- only handle si-audio-adapter and si-node
|
-- only handle si-audio-adapter and si-node
|
||||||
Constraint {
|
Constraint {
|
||||||
@@ -248,7 +252,7 @@ linkables_om = ObjectManager { Interest { type = "SiLinkable",
|
|||||||
}
|
}
|
||||||
links_om = ObjectManager { Interest { type = "SiLink",
|
links_om = ObjectManager { Interest { type = "SiLink",
|
||||||
-- only handle links created by this policy
|
-- only handle links created by this policy
|
||||||
Constraint { "is.policy.endpoint.client.link", "=", true, type = "pw-global" },
|
Constraint { "is.policy.virtual.client.link", "=", true, type = "pw-global" },
|
||||||
} }
|
} }
|
||||||
|
|
||||||
linkables_om:connect("objects-changed", function (om)
|
linkables_om:connect("objects-changed", function (om)
|
||||||
@@ -259,6 +263,6 @@ linkables_om:connect("object-removed", function (om, si)
|
|||||||
unhandleLinkable (si)
|
unhandleLinkable (si)
|
||||||
end)
|
end)
|
||||||
|
|
||||||
endpoints_om:activate()
|
virtuals_om:activate()
|
||||||
linkables_om:activate()
|
linkables_om:activate()
|
||||||
links_om:activate()
|
links_om:activate()
|
@@ -17,9 +17,9 @@ self.scanning = false
|
|||||||
self.pending_rescan = false
|
self.pending_rescan = false
|
||||||
|
|
||||||
function rescan ()
|
function rescan ()
|
||||||
-- check endpoints and register new links
|
-- check virtuals and register new links
|
||||||
for si_ep in endpoints_om:iterate() do
|
for si_v in virtuals_om:iterate() do
|
||||||
handleEndpoint (si_ep)
|
handleVirtual (si_v)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -111,7 +111,7 @@ function createLink (si_ep, si_target)
|
|||||||
["out.item.port.context"] = "output",
|
["out.item.port.context"] = "output",
|
||||||
["in.item.port.context"] = "input",
|
["in.item.port.context"] = "input",
|
||||||
["passive"] = true,
|
["passive"] = true,
|
||||||
["is.policy.endpoint.device.link"] = true,
|
["is.policy.virtual.device.link"] = true,
|
||||||
} then
|
} then
|
||||||
Log.warning (si_link, "failed to configure si-standard-link")
|
Log.warning (si_link, "failed to configure si-standard-link")
|
||||||
return
|
return
|
||||||
@@ -131,8 +131,8 @@ function createLink (si_ep, si_target)
|
|||||||
end)
|
end)
|
||||||
end
|
end
|
||||||
|
|
||||||
function handleEndpoint (si_ep)
|
function handleVirtual (si_ep)
|
||||||
Log.info (si_ep, "handling endpoint " .. si_ep.properties["name"])
|
Log.info (si_ep, "handling virtual " .. si_ep.properties["name"])
|
||||||
|
|
||||||
-- find proper target item
|
-- find proper target item
|
||||||
local si_target = findUndefinedTarget (si_ep)
|
local si_target = findUndefinedTarget (si_ep)
|
||||||
@@ -192,7 +192,11 @@ function unhandleLinkable (si)
|
|||||||
end
|
end
|
||||||
|
|
||||||
default_nodes = Plugin.find("default-nodes-api")
|
default_nodes = Plugin.find("default-nodes-api")
|
||||||
endpoints_om = ObjectManager { Interest { type = "SiEndpoint" }}
|
virtuals_om = ObjectManager { Interest { type = "SiLinkable",
|
||||||
|
Constraint {
|
||||||
|
"item.factory.name", "=", "si-audio-virtual", type = "pw-global" },
|
||||||
|
}
|
||||||
|
}
|
||||||
linkables_om = ObjectManager {
|
linkables_om = ObjectManager {
|
||||||
Interest {
|
Interest {
|
||||||
type = "SiLinkable",
|
type = "SiLinkable",
|
||||||
@@ -206,7 +210,7 @@ links_om = ObjectManager {
|
|||||||
Interest {
|
Interest {
|
||||||
type = "SiLink",
|
type = "SiLink",
|
||||||
-- only handle links created by this policy
|
-- only handle links created by this policy
|
||||||
Constraint { "is.policy.endpoint.device.link", "=", true, type = "pw-global" },
|
Constraint { "is.policy.virtual.device.link", "=", true, type = "pw-global" },
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -221,7 +225,7 @@ linkables_om:connect("objects-changed", function (om)
|
|||||||
scheduleRescan ()
|
scheduleRescan ()
|
||||||
end)
|
end)
|
||||||
|
|
||||||
endpoints_om:connect("object-added", function (om)
|
virtuals_om:connect("object-added", function (om)
|
||||||
scheduleRescan ()
|
scheduleRescan ()
|
||||||
end)
|
end)
|
||||||
|
|
||||||
@@ -229,6 +233,6 @@ linkables_om:connect("object-removed", function (om, si)
|
|||||||
unhandleLinkable (si)
|
unhandleLinkable (si)
|
||||||
end)
|
end)
|
||||||
|
|
||||||
endpoints_om:activate()
|
virtuals_om:activate()
|
||||||
linkables_om:activate()
|
linkables_om:activate()
|
||||||
links_om:activate()
|
links_om:activate()
|
@@ -1,42 +0,0 @@
|
|||||||
-- WirePlumber
|
|
||||||
--
|
|
||||||
-- Copyright © 2021 Collabora Ltd.
|
|
||||||
-- @author Julian Bouzas <julian.bouzas@collabora.com>
|
|
||||||
--
|
|
||||||
-- SPDX-License-Identifier: MIT
|
|
||||||
|
|
||||||
-- Receive script arguments from config.lua
|
|
||||||
|
|
||||||
local defaults = {}
|
|
||||||
defaults.endpoints = Json.Object {}
|
|
||||||
|
|
||||||
local config = {}
|
|
||||||
config.endpoints = Conf.get_section (
|
|
||||||
"endpoints", defaults.endpoints):parse ()
|
|
||||||
|
|
||||||
function createEndpoint (factory_name, properties)
|
|
||||||
-- create endpoint
|
|
||||||
local ep = SessionItem ( factory_name )
|
|
||||||
if not ep then
|
|
||||||
Log.warning (ep, "could not create endpoint of type " .. factory_name)
|
|
||||||
return
|
|
||||||
end
|
|
||||||
|
|
||||||
-- configure endpoint
|
|
||||||
if not ep:configure(properties) then
|
|
||||||
Log.warning(ep, "failed to configure endpoint " .. properties.name)
|
|
||||||
return
|
|
||||||
end
|
|
||||||
|
|
||||||
-- activate and register endpoint
|
|
||||||
ep:activate (Features.ALL, function (item)
|
|
||||||
item:register ()
|
|
||||||
Log.info(item, "registered endpoint " .. properties.name)
|
|
||||||
end)
|
|
||||||
end
|
|
||||||
|
|
||||||
|
|
||||||
for name, properties in pairs(config.endpoints) do
|
|
||||||
properties["name"] = name
|
|
||||||
createEndpoint ("si-audio-endpoint", properties)
|
|
||||||
end
|
|
@@ -38,8 +38,8 @@ test(
|
|||||||
)
|
)
|
||||||
|
|
||||||
test(
|
test(
|
||||||
'test-si-audio-endpoint',
|
'test-si-audio-virtual',
|
||||||
executable('test-si-audio-endpoint', 'si-audio-endpoint.c',
|
executable('test-si-audio-virtual', 'si-audio-virtual.c',
|
||||||
dependencies: common_deps, c_args: common_args),
|
dependencies: common_deps, c_args: common_args),
|
||||||
env: common_env,
|
env: common_env,
|
||||||
)
|
)
|
||||||
|
@@ -13,7 +13,7 @@ typedef struct {
|
|||||||
} TestFixture;
|
} TestFixture;
|
||||||
|
|
||||||
static void
|
static void
|
||||||
test_si_audio_endpoint_setup (TestFixture * f, gconstpointer user_data)
|
test_si_audio_virtual_setup (TestFixture * f, gconstpointer user_data)
|
||||||
{
|
{
|
||||||
wp_base_test_fixture_setup (&f->base, 0);
|
wp_base_test_fixture_setup (&f->base, 0);
|
||||||
|
|
||||||
@@ -36,22 +36,22 @@ test_si_audio_endpoint_setup (TestFixture * f, gconstpointer user_data)
|
|||||||
{
|
{
|
||||||
g_autoptr (GError) error = NULL;
|
g_autoptr (GError) error = NULL;
|
||||||
wp_core_load_component (f->base.core,
|
wp_core_load_component (f->base.core,
|
||||||
"libwireplumber-module-si-audio-endpoint", "module", NULL, &error);
|
"libwireplumber-module-si-audio-virtual", "module", NULL, &error);
|
||||||
g_assert_no_error (error);
|
g_assert_no_error (error);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
test_si_audio_endpoint_teardown (TestFixture * f, gconstpointer user_data)
|
test_si_audio_virtual_teardown (TestFixture * f, gconstpointer user_data)
|
||||||
{
|
{
|
||||||
wp_base_test_fixture_teardown (&f->base);
|
wp_base_test_fixture_teardown (&f->base);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
test_si_audio_endpoint_configure_activate (TestFixture * f,
|
test_si_audio_virtual_configure_activate (TestFixture * f,
|
||||||
gconstpointer user_data)
|
gconstpointer user_data)
|
||||||
{
|
{
|
||||||
g_autoptr (WpSessionItem) endpoint = NULL;
|
g_autoptr (WpSessionItem) item = NULL;
|
||||||
|
|
||||||
/* skip the test if null-audio-sink factory is not installed */
|
/* skip the test if null-audio-sink factory is not installed */
|
||||||
if (!test_is_spa_lib_installed (&f->base, "support.null-audio-sink")) {
|
if (!test_is_spa_lib_installed (&f->base, "support.null-audio-sink")) {
|
||||||
@@ -59,53 +59,53 @@ test_si_audio_endpoint_configure_activate (TestFixture * f,
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* create endpoint */
|
/* create item */
|
||||||
|
|
||||||
endpoint = wp_session_item_make (f->base.core, "si-audio-endpoint");
|
item = wp_session_item_make (f->base.core, "si-audio-virtual");
|
||||||
g_assert_nonnull (endpoint);
|
g_assert_nonnull (item);
|
||||||
|
|
||||||
/* configure endpoint */
|
/* configure item */
|
||||||
|
|
||||||
{
|
{
|
||||||
WpProperties *props = wp_properties_new_empty ();
|
WpProperties *props = wp_properties_new_empty ();
|
||||||
wp_properties_set (props, "name", "endpoint");
|
wp_properties_set (props, "name", "virtual");
|
||||||
wp_properties_set (props, "media.class", "Audio/Source");
|
wp_properties_set (props, "media.class", "Audio/Source");
|
||||||
g_assert_true (wp_session_item_configure (endpoint, props));
|
g_assert_true (wp_session_item_configure (item, props));
|
||||||
g_assert_true (wp_session_item_is_configured (endpoint));
|
g_assert_true (wp_session_item_is_configured (item));
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
const gchar *str = NULL;
|
const gchar *str = NULL;
|
||||||
g_autoptr (WpProperties) props = wp_session_item_get_properties (endpoint);
|
g_autoptr (WpProperties) props = wp_session_item_get_properties (item);
|
||||||
g_assert_nonnull (props);
|
g_assert_nonnull (props);
|
||||||
str = wp_properties_get (props, "name");
|
str = wp_properties_get (props, "name");
|
||||||
g_assert_nonnull (str);
|
g_assert_nonnull (str);
|
||||||
g_assert_cmpstr ("endpoint", ==, str);
|
g_assert_cmpstr ("virtual", ==, str);
|
||||||
str = wp_properties_get (props, "direction");
|
str = wp_properties_get (props, "direction");
|
||||||
g_assert_nonnull (str);
|
g_assert_nonnull (str);
|
||||||
g_assert_cmpstr ("1", ==, str);
|
g_assert_cmpstr ("1", ==, str);
|
||||||
str = wp_properties_get (props, "item.factory.name");
|
str = wp_properties_get (props, "item.factory.name");
|
||||||
g_assert_nonnull (str);
|
g_assert_nonnull (str);
|
||||||
g_assert_cmpstr ("si-audio-endpoint", ==, str);
|
g_assert_cmpstr ("si-audio-virtual", ==, str);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* activate endpoint */
|
/* activate item */
|
||||||
|
|
||||||
wp_object_activate (WP_OBJECT (endpoint), WP_SESSION_ITEM_FEATURE_ACTIVE,
|
wp_object_activate (WP_OBJECT (item), WP_SESSION_ITEM_FEATURE_ACTIVE,
|
||||||
NULL, (GAsyncReadyCallback) test_object_activate_finish_cb, f);
|
NULL, (GAsyncReadyCallback) test_object_activate_finish_cb, f);
|
||||||
g_main_loop_run (f->base.loop);
|
g_main_loop_run (f->base.loop);
|
||||||
g_assert_cmphex (wp_object_get_active_features (WP_OBJECT (endpoint)), ==,
|
g_assert_cmphex (wp_object_get_active_features (WP_OBJECT (item)), ==,
|
||||||
WP_SESSION_ITEM_FEATURE_ACTIVE);
|
WP_SESSION_ITEM_FEATURE_ACTIVE);
|
||||||
|
|
||||||
/* reset */
|
/* reset */
|
||||||
wp_session_item_reset (endpoint);
|
wp_session_item_reset (item);
|
||||||
g_assert_false (wp_session_item_is_configured (endpoint));
|
g_assert_false (wp_session_item_is_configured (item));
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
test_si_audio_endpoint_export (TestFixture * f, gconstpointer user_data)
|
test_si_audio_virtual_export (TestFixture * f, gconstpointer user_data)
|
||||||
{
|
{
|
||||||
g_autoptr (WpSessionItem) endpoint = NULL;
|
g_autoptr (WpSessionItem) item = NULL;
|
||||||
g_autoptr (WpObjectManager) clients_om = NULL;
|
g_autoptr (WpObjectManager) clients_om = NULL;
|
||||||
g_autoptr (WpClient) self_client = NULL;
|
g_autoptr (WpClient) self_client = NULL;
|
||||||
|
|
||||||
@@ -115,8 +115,6 @@ test_si_audio_endpoint_export (TestFixture * f, gconstpointer user_data)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* find self_client, to be used for verifying endpoint.client.id */
|
|
||||||
|
|
||||||
clients_om = wp_object_manager_new ();
|
clients_om = wp_object_manager_new ();
|
||||||
wp_object_manager_add_interest (clients_om, WP_TYPE_CLIENT, NULL);
|
wp_object_manager_add_interest (clients_om, WP_TYPE_CLIENT, NULL);
|
||||||
wp_object_manager_request_object_features (clients_om,
|
wp_object_manager_request_object_features (clients_om,
|
||||||
@@ -128,28 +126,28 @@ test_si_audio_endpoint_export (TestFixture * f, gconstpointer user_data)
|
|||||||
self_client = wp_object_manager_lookup (clients_om, WP_TYPE_CLIENT, NULL);
|
self_client = wp_object_manager_lookup (clients_om, WP_TYPE_CLIENT, NULL);
|
||||||
g_assert_nonnull (self_client);
|
g_assert_nonnull (self_client);
|
||||||
|
|
||||||
/* create endpoint */
|
/* create item */
|
||||||
|
|
||||||
endpoint = wp_session_item_make (f->base.core, "si-audio-endpoint");
|
item = wp_session_item_make (f->base.core, "si-audio-virtual");
|
||||||
g_assert_nonnull (endpoint);
|
g_assert_nonnull (item);
|
||||||
|
|
||||||
/* configure endpoint */
|
/* configure item */
|
||||||
{
|
{
|
||||||
WpProperties *props = wp_properties_new_empty ();
|
WpProperties *props = wp_properties_new_empty ();
|
||||||
wp_properties_set (props, "name", "endpoint");
|
wp_properties_set (props, "name", "virtual");
|
||||||
wp_properties_set (props, "media.class", "Audio/Source");
|
wp_properties_set (props, "media.class", "Audio/Source");
|
||||||
g_assert_true (wp_session_item_configure (endpoint, props));
|
g_assert_true (wp_session_item_configure (item, props));
|
||||||
g_assert_true (wp_session_item_is_configured (endpoint));
|
g_assert_true (wp_session_item_is_configured (item));
|
||||||
}
|
}
|
||||||
|
|
||||||
/* activate endpoint */
|
/* activate item */
|
||||||
|
|
||||||
{
|
{
|
||||||
wp_object_activate (WP_OBJECT (endpoint),
|
wp_object_activate (WP_OBJECT (item),
|
||||||
WP_SESSION_ITEM_FEATURE_ACTIVE | WP_SESSION_ITEM_FEATURE_EXPORTED,
|
WP_SESSION_ITEM_FEATURE_ACTIVE | WP_SESSION_ITEM_FEATURE_EXPORTED,
|
||||||
NULL, (GAsyncReadyCallback) test_object_activate_finish_cb, f);
|
NULL, (GAsyncReadyCallback) test_object_activate_finish_cb, f);
|
||||||
g_main_loop_run (f->base.loop);
|
g_main_loop_run (f->base.loop);
|
||||||
g_assert_cmphex (wp_object_get_active_features (WP_OBJECT (endpoint)), ==,
|
g_assert_cmphex (wp_object_get_active_features (WP_OBJECT (item)), ==,
|
||||||
WP_SESSION_ITEM_FEATURE_ACTIVE | WP_SESSION_ITEM_FEATURE_EXPORTED);
|
WP_SESSION_ITEM_FEATURE_ACTIVE | WP_SESSION_ITEM_FEATURE_EXPORTED);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -157,7 +155,7 @@ test_si_audio_endpoint_export (TestFixture * f, gconstpointer user_data)
|
|||||||
g_autoptr (WpNode) n = NULL;
|
g_autoptr (WpNode) n = NULL;
|
||||||
g_autoptr (WpProperties) props = NULL;
|
g_autoptr (WpProperties) props = NULL;
|
||||||
|
|
||||||
n = wp_session_item_get_associated_proxy (endpoint, WP_TYPE_NODE);
|
n = wp_session_item_get_associated_proxy (item, WP_TYPE_NODE);
|
||||||
g_assert_nonnull (n);
|
g_assert_nonnull (n);
|
||||||
props = wp_pipewire_object_get_properties (WP_PIPEWIRE_OBJECT (n));
|
props = wp_pipewire_object_get_properties (WP_PIPEWIRE_OBJECT (n));
|
||||||
g_assert_nonnull (props);
|
g_assert_nonnull (props);
|
||||||
@@ -167,8 +165,8 @@ test_si_audio_endpoint_export (TestFixture * f, gconstpointer user_data)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* reset */
|
/* reset */
|
||||||
wp_session_item_reset (endpoint);
|
wp_session_item_reset (item);
|
||||||
g_assert_false (wp_session_item_is_configured (endpoint));
|
g_assert_false (wp_session_item_is_configured (item));
|
||||||
}
|
}
|
||||||
|
|
||||||
gint
|
gint
|
||||||
@@ -178,18 +176,18 @@ main (gint argc, gchar *argv[])
|
|||||||
wp_init (WP_INIT_ALL);
|
wp_init (WP_INIT_ALL);
|
||||||
|
|
||||||
/* configure-activate */
|
/* configure-activate */
|
||||||
g_test_add ("/modules/si-audio-endpoint/configure-activate",
|
g_test_add ("/modules/si-audio-virtual/configure-activate",
|
||||||
TestFixture, NULL,
|
TestFixture, NULL,
|
||||||
test_si_audio_endpoint_setup,
|
test_si_audio_virtual_setup,
|
||||||
test_si_audio_endpoint_configure_activate,
|
test_si_audio_virtual_configure_activate,
|
||||||
test_si_audio_endpoint_teardown);
|
test_si_audio_virtual_teardown);
|
||||||
|
|
||||||
/* export */
|
/* export */
|
||||||
g_test_add ("/modules/si-audio-endpoint/export",
|
g_test_add ("/modules/si-audio-virtual/export",
|
||||||
TestFixture, NULL,
|
TestFixture, NULL,
|
||||||
test_si_audio_endpoint_setup,
|
test_si_audio_virtual_setup,
|
||||||
test_si_audio_endpoint_export,
|
test_si_audio_virtual_export,
|
||||||
test_si_audio_endpoint_teardown);
|
test_si_audio_virtual_teardown);
|
||||||
|
|
||||||
return g_test_run ();
|
return g_test_run ();
|
||||||
}
|
}
|
@@ -112,13 +112,13 @@ test_si_standard_link_main (TestFixture * f, gconstpointer user_data)
|
|||||||
{
|
{
|
||||||
g_autoptr (WpSessionItem) link = NULL;
|
g_autoptr (WpSessionItem) link = NULL;
|
||||||
|
|
||||||
/* skip the test if audiotestsrc endpoint could not be loaded */
|
/* skip the test if audiotestsrc could not be loaded */
|
||||||
if (!f->src_item) {
|
if (!f->src_item) {
|
||||||
g_test_skip ("The pipewire audiotestsrc factory was not found");
|
g_test_skip ("The pipewire audiotestsrc factory was not found");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* skip the test if null-audio-sink endpoint could not be loaded */
|
/* skip the test if null-audio-sink could not be loaded */
|
||||||
if (!f->sink_item) {
|
if (!f->sink_item) {
|
||||||
g_test_skip ("The pipewire null-audio-sink factory was not found");
|
g_test_skip ("The pipewire null-audio-sink factory was not found");
|
||||||
return;
|
return;
|
||||||
|
@@ -209,7 +209,7 @@ load_components (ScriptRunnerFixture *f, gconstpointer argv)
|
|||||||
|
|
||||||
load_component (f, "si-audio-adapter", "module");
|
load_component (f, "si-audio-adapter", "module");
|
||||||
load_component (f, "si-standard-link", "module");
|
load_component (f, "si-standard-link", "module");
|
||||||
load_component (f, "si-audio-endpoint", "module");
|
load_component (f, "si-audio-virtual", "module");
|
||||||
|
|
||||||
load_component (f, "metadata", "module");
|
load_component (f, "metadata", "module");
|
||||||
load_component (f, "default-nodes-api", "module");
|
load_component (f, "default-nodes-api", "module");
|
||||||
|
Reference in New Issue
Block a user