diff --git a/src/daemon/media-session.d/media-session.conf b/src/daemon/media-session.d/media-session.conf index b724d1e94..a32a23d73 100644 --- a/src/daemon/media-session.d/media-session.conf +++ b/src/daemon/media-session.d/media-session.conf @@ -84,6 +84,7 @@ session.modules = { #default-profile # restore default profiles #default-routes # restore default route #streams-follow-default # move streams when default changes + #alsa-no-dsp # do not configure audio nodes in DSP mode #alsa-seq # alsa seq midi support #alsa-monitor # alsa udev detection #bluez5 # bluetooth support diff --git a/src/examples/media-session/alsa-no-dsp.c b/src/examples/media-session/alsa-no-dsp.c new file mode 100644 index 000000000..ac78d101b --- /dev/null +++ b/src/examples/media-session/alsa-no-dsp.c @@ -0,0 +1,51 @@ +/* PipeWire + * + * Copyright © 2021 Collabora Ltd. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +/* + * Instruct policy-node to not configure audio adapter nodes in DSP mode. + * Device nodes will always be configured in passthrough mode. If a client node + * wants to be linked with a device node that has a different format, then the + * policy will configure the client node in convert mode so that both nodes + * have the same format. + * + * This is done by just setting a session property flag, and policy-node does the rest. + */ + +#include "config.h" + +#include "pipewire/pipewire.h" +#include "pipewire/extensions/metadata.h" + +#include "media-session.h" + +/** \page page_media_session_module_no_dsp Media Session Module: No DSP + */ + +#define KEY_NAME "policy-node.alsa-no-dsp" + +int sm_alsa_no_dsp_start(struct sm_media_session *session) +{ + pw_properties_set(session->props, KEY_NAME, "true"); + return 0; +} diff --git a/src/examples/media-session/media-session.c b/src/examples/media-session/media-session.c index 2f01f756e..7b94e5ba5 100644 --- a/src/examples/media-session/media-session.c +++ b/src/examples/media-session/media-session.c @@ -90,6 +90,7 @@ int sm_default_profile_start(struct sm_media_session *sess); int sm_default_routes_start(struct sm_media_session *sess); int sm_restore_stream_start(struct sm_media_session *sess); int sm_streams_follow_default_start(struct sm_media_session *sess); +int sm_alsa_no_dsp_start(struct sm_media_session *sess); int sm_alsa_midi_start(struct sm_media_session *sess); int sm_v4l2_monitor_start(struct sm_media_session *sess); int sm_libcamera_monitor_start(struct sm_media_session *sess); @@ -2390,6 +2391,7 @@ static const struct { { "default-routes", "restore default route", sm_default_routes_start, NULL }, { "restore-stream", "restore stream settings", sm_restore_stream_start, NULL }, { "streams-follow-default", "move streams when default changes", sm_streams_follow_default_start, NULL }, + { "alsa-no-dsp", "do not configure audio nodes in DSP mode", sm_alsa_no_dsp_start, NULL }, { "alsa-seq", "alsa seq midi support", sm_alsa_midi_start, NULL }, { "alsa-monitor", "alsa card udev detection", sm_alsa_monitor_start, NULL }, { "v4l2", "video for linux udev detection", sm_v4l2_monitor_start, NULL }, diff --git a/src/examples/media-session/policy-node.c b/src/examples/media-session/policy-node.c index 67e86e0f9..842001a10 100644 --- a/src/examples/media-session/policy-node.c +++ b/src/examples/media-session/policy-node.c @@ -92,6 +92,7 @@ struct impl { struct default_node defaults[4]; bool streams_follow_default; + bool alsa_no_dsp; }; struct node { @@ -279,6 +280,7 @@ static int configure_node(struct node *node, struct spa_audio_info *info, bool f struct spa_pod *param; struct spa_audio_info format; enum pw_direction direction; + uint32_t mode; if (node->configured && !force) { pw_log_debug("node %d is configured passthrough:%d", node->id, node->passthrough); @@ -292,7 +294,18 @@ static int configure_node(struct node *node, struct spa_audio_info *info, bool f format = node->format; - if (info != NULL && info->info.raw.channels > 0) { + if (impl->alsa_no_dsp) { + if ((info != NULL && memcmp(&node->format, info, sizeof(node->format)) == 0) || + node->type == NODE_TYPE_DEVICE) + mode = SPA_PARAM_PORT_CONFIG_MODE_passthrough; + else + mode = SPA_PARAM_PORT_CONFIG_MODE_convert; + } else { + mode = SPA_PARAM_PORT_CONFIG_MODE_dsp; + } + + if (mode != SPA_PARAM_PORT_CONFIG_MODE_passthrough && + info != NULL && info->info.raw.channels > 0) { pw_log_info("node %d monitor:%d channelmix %d->%d", node->id, node->monitor, format.info.raw.channels, info->info.raw.channels); @@ -313,7 +326,7 @@ static int configure_node(struct node *node, struct spa_audio_info *info, bool f param = spa_pod_builder_add_object(&b, SPA_TYPE_OBJECT_ParamPortConfig, SPA_PARAM_PortConfig, SPA_PARAM_PORT_CONFIG_direction, SPA_POD_Id(direction), - SPA_PARAM_PORT_CONFIG_mode, SPA_POD_Id(SPA_PARAM_PORT_CONFIG_MODE_dsp), + SPA_PARAM_PORT_CONFIG_mode, SPA_POD_Id(mode), SPA_PARAM_PORT_CONFIG_monitor, SPA_POD_Bool(true), SPA_PARAM_PORT_CONFIG_format, SPA_POD_Pod(param)); @@ -1314,6 +1327,8 @@ int sm_policy_node_start(struct sm_media_session *session) flag = pw_properties_get(session->props, NAME ".streams-follow-default"); impl->streams_follow_default = (flag != NULL && pw_properties_parse_bool(flag)); + flag = pw_properties_get(session->props, NAME ".alsa-no-dsp"); + impl->alsa_no_dsp = (flag != NULL && pw_properties_parse_bool(flag)); spa_list_init(&impl->node_list); diff --git a/src/examples/meson.build b/src/examples/meson.build index 5d4fe27d7..e3e446297 100644 --- a/src/examples/meson.build +++ b/src/examples/meson.build @@ -66,6 +66,7 @@ if get_option('session-managers').contains('media-session') and alsa_dep.found() media_session_sources = [ 'media-session/access-flatpak.c', 'media-session/access-portal.c', + 'media-session/alsa-no-dsp.c', 'media-session/alsa-midi.c', 'media-session/alsa-monitor.c', 'media-session/alsa-endpoint.c',