mirror of
https://gitlab.freedesktop.org/pipewire/pipewire.git
synced 2025-12-20 08:56:56 -05:00
adapter: add adapter.auto-port-config property
This automatically configures the node in a supported format with the highest amount of channels. Options are available to enable monitor and to override the port channels as AUX or UNKNOWN.
This commit is contained in:
parent
aa128ed489
commit
5a72e2769a
2 changed files with 143 additions and 20 deletions
|
|
@ -207,18 +207,23 @@ context.objects = [
|
||||||
# audio.channels 6
|
# audio.channels 6
|
||||||
# ]
|
# ]
|
||||||
#}
|
#}
|
||||||
node.param.PortConfig = {
|
adapter.auto-port-config = {
|
||||||
direction = Output
|
|
||||||
mode = dsp
|
mode = dsp
|
||||||
format = {
|
monitor = false
|
||||||
mediaType = audio
|
position = unknown # aux, preserve
|
||||||
mediaSubtype = raw
|
|
||||||
format = F32
|
|
||||||
rate = 48000
|
|
||||||
channels = 4
|
|
||||||
#position = [ FL FR RL RR ]
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
#node.param.PortConfig = {
|
||||||
|
# direction = Output
|
||||||
|
# mode = dsp
|
||||||
|
# format = {
|
||||||
|
# mediaType = audio
|
||||||
|
# mediaSubtype = raw
|
||||||
|
# format = F32
|
||||||
|
# rate = 48000
|
||||||
|
# channels = 4
|
||||||
|
# position = [ FL FR RL RR ]
|
||||||
|
# }
|
||||||
|
#}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
{ factory = adapter
|
{ factory = adapter
|
||||||
|
|
@ -257,18 +262,23 @@ context.objects = [
|
||||||
# audio.format S16
|
# audio.format S16
|
||||||
# ]
|
# ]
|
||||||
#}
|
#}
|
||||||
node.param.PortConfig = {
|
adapter.auto-port-config = {
|
||||||
direction = Input
|
|
||||||
mode = dsp
|
mode = dsp
|
||||||
monitor = true
|
monitor = false
|
||||||
format = {
|
position = unknown # aux, preserve
|
||||||
mediaType = audio
|
|
||||||
mediaSubtype = raw
|
|
||||||
format = F32
|
|
||||||
rate = 48000
|
|
||||||
channels = 4
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
#node.param.PortConfig = {
|
||||||
|
# direction = Input
|
||||||
|
# mode = dsp
|
||||||
|
# monitor = true
|
||||||
|
# format = {
|
||||||
|
# mediaType = audio
|
||||||
|
# mediaSubtype = raw
|
||||||
|
# format = F32
|
||||||
|
# rate = 48000
|
||||||
|
# channels = 4
|
||||||
|
# }
|
||||||
|
#}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|
|
||||||
|
|
@ -38,6 +38,8 @@
|
||||||
#include <spa/utils/string.h>
|
#include <spa/utils/string.h>
|
||||||
#include <spa/utils/type-info.h>
|
#include <spa/utils/type-info.h>
|
||||||
#include <spa/param/format.h>
|
#include <spa/param/format.h>
|
||||||
|
#include <spa/param/audio/format.h>
|
||||||
|
#include <spa/param/audio/format-utils.h>
|
||||||
#include <spa/param/format-utils.h>
|
#include <spa/param/format-utils.h>
|
||||||
#include <spa/debug/types.h>
|
#include <spa/debug/types.h>
|
||||||
#include <spa/debug/pod.h>
|
#include <spa/debug/pod.h>
|
||||||
|
|
@ -227,6 +229,114 @@ static int find_format(struct pw_impl_node *node, enum pw_direction direction,
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int do_auto_port_config(struct node *n, const char *str)
|
||||||
|
{
|
||||||
|
uint32_t state = 0, i;
|
||||||
|
uint8_t buffer[4096];
|
||||||
|
struct spa_pod_builder b;
|
||||||
|
#define POSITION_PRESERVE 0
|
||||||
|
#define POSITION_AUX 1
|
||||||
|
#define POSITION_UNKNOWN 2
|
||||||
|
int res, position = POSITION_PRESERVE;
|
||||||
|
struct spa_pod *param;
|
||||||
|
uint32_t media_type, media_subtype;
|
||||||
|
bool have_format = false, monitor = false;
|
||||||
|
struct spa_audio_info format = { 0, };
|
||||||
|
enum spa_param_port_config_mode mode = SPA_PARAM_PORT_CONFIG_MODE_none;
|
||||||
|
struct spa_json it[2];
|
||||||
|
char key[1024], val[256];
|
||||||
|
|
||||||
|
spa_json_init(&it[0], str, strlen(str));
|
||||||
|
if (spa_json_enter_object(&it[0], &it[1]) <= 0)
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
while (spa_json_get_string(&it[1], key, sizeof(key)) > 0) {
|
||||||
|
if (spa_json_get_string(&it[1], val, sizeof(val)) <= 0)
|
||||||
|
break;
|
||||||
|
|
||||||
|
if (spa_streq(key, "mode")) {
|
||||||
|
mode = spa_debug_type_find_type_short(spa_type_param_port_config_mode, val);
|
||||||
|
if (mode == SPA_ID_INVALID)
|
||||||
|
mode = SPA_PARAM_PORT_CONFIG_MODE_none;
|
||||||
|
} else if (spa_streq(key, "monitor")) {
|
||||||
|
monitor = spa_atob(val);
|
||||||
|
} else if (spa_streq(key, "position")) {
|
||||||
|
if (spa_streq(val, "unknown"))
|
||||||
|
position = POSITION_UNKNOWN;
|
||||||
|
else if (spa_streq(val, "aux"))
|
||||||
|
position = POSITION_AUX;
|
||||||
|
else
|
||||||
|
position = POSITION_PRESERVE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
while (true) {
|
||||||
|
struct spa_audio_info info = { 0, };
|
||||||
|
struct spa_pod *position = NULL;
|
||||||
|
uint32_t n_position = 0;
|
||||||
|
|
||||||
|
spa_pod_builder_init(&b, buffer, sizeof(buffer));
|
||||||
|
if ((res = spa_node_port_enum_params_sync(pw_impl_node_get_implementation(n->follower),
|
||||||
|
n->direction == PW_DIRECTION_INPUT ?
|
||||||
|
SPA_DIRECTION_INPUT :
|
||||||
|
SPA_DIRECTION_OUTPUT, 0,
|
||||||
|
SPA_PARAM_EnumFormat, &state,
|
||||||
|
NULL, ¶m, &b)) != 1)
|
||||||
|
break;
|
||||||
|
|
||||||
|
if ((res = spa_format_parse(param, &media_type, &media_subtype)) < 0)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (media_type != SPA_MEDIA_TYPE_audio ||
|
||||||
|
media_subtype != SPA_MEDIA_SUBTYPE_raw)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
spa_pod_object_fixate((struct spa_pod_object*)param);
|
||||||
|
|
||||||
|
if (spa_pod_parse_object(param,
|
||||||
|
SPA_TYPE_OBJECT_Format, NULL,
|
||||||
|
SPA_FORMAT_AUDIO_format, SPA_POD_Id(&info.info.raw.format),
|
||||||
|
SPA_FORMAT_AUDIO_rate, SPA_POD_Int(&info.info.raw.rate),
|
||||||
|
SPA_FORMAT_AUDIO_channels, SPA_POD_Int(&info.info.raw.channels),
|
||||||
|
SPA_FORMAT_AUDIO_position, SPA_POD_OPT_Pod(&position)) < 0)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (position != NULL)
|
||||||
|
n_position = spa_pod_copy_array(position, SPA_TYPE_Id,
|
||||||
|
info.info.raw.position, SPA_AUDIO_MAX_CHANNELS);
|
||||||
|
if (n_position == 0 || n_position != info.info.raw.channels)
|
||||||
|
SPA_FLAG_SET(info.info.raw.flags, SPA_AUDIO_FLAG_UNPOSITIONED);
|
||||||
|
|
||||||
|
if (format.info.raw.channels >= info.info.raw.channels)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
format = info;
|
||||||
|
have_format = true;
|
||||||
|
}
|
||||||
|
if (!have_format)
|
||||||
|
return -ENOENT;
|
||||||
|
|
||||||
|
if (position == POSITION_AUX) {
|
||||||
|
for (i = 0; i < format.info.raw.channels; i++)
|
||||||
|
format.info.raw.position[i] = SPA_AUDIO_CHANNEL_START_Aux + i;
|
||||||
|
} else if (position == POSITION_UNKNOWN) {
|
||||||
|
for (i = 0; i < format.info.raw.channels; i++)
|
||||||
|
format.info.raw.position[i] = SPA_AUDIO_CHANNEL_UNKNOWN;
|
||||||
|
}
|
||||||
|
|
||||||
|
spa_pod_builder_init(&b, buffer, sizeof(buffer));
|
||||||
|
param = spa_format_audio_raw_build(&b, SPA_PARAM_Format, &format.info.raw);
|
||||||
|
param = spa_pod_builder_add_object(&b,
|
||||||
|
SPA_TYPE_OBJECT_ParamPortConfig, SPA_PARAM_PortConfig,
|
||||||
|
SPA_PARAM_PORT_CONFIG_direction, SPA_POD_Id(n->direction),
|
||||||
|
SPA_PARAM_PORT_CONFIG_mode, SPA_POD_Id(mode),
|
||||||
|
SPA_PARAM_PORT_CONFIG_monitor, SPA_POD_Bool(monitor),
|
||||||
|
SPA_PARAM_PORT_CONFIG_format, SPA_POD_Pod(param));
|
||||||
|
pw_impl_node_set_param(n->node, SPA_PARAM_PortConfig, 0, param);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
struct pw_impl_node *pw_adapter_new(struct pw_context *context,
|
struct pw_impl_node *pw_adapter_new(struct pw_context *context,
|
||||||
struct pw_impl_node *follower,
|
struct pw_impl_node *follower,
|
||||||
struct pw_properties *props,
|
struct pw_properties *props,
|
||||||
|
|
@ -330,6 +440,9 @@ struct pw_impl_node *pw_adapter_new(struct pw_context *context,
|
||||||
|
|
||||||
pw_impl_node_add_listener(node, &n->node_listener, &node_events, n);
|
pw_impl_node_add_listener(node, &n->node_listener, &node_events, n);
|
||||||
|
|
||||||
|
if ((str = pw_properties_get(props, "adapter.auto-port-config")) != NULL)
|
||||||
|
do_auto_port_config(n, str);
|
||||||
|
|
||||||
spa_dict_for_each(it, &props->dict) {
|
spa_dict_for_each(it, &props->dict) {
|
||||||
if (spa_strstartswith(it->key, "node.param.")) {
|
if (spa_strstartswith(it->key, "node.param.")) {
|
||||||
if ((res = handle_node_param(node, &it->key[11], it->value)) < 0)
|
if ((res = handle_node_param(node, &it->key[11], it->value)) < 0)
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue