Add support for virtual source

A virtual source is usually implemented with a null-sink, it looks
like a source to pulseaudio clients but just forwards what it gets
as input.

Make sure the port names make sense.

You can use the null sink now as:

pactl load-module module-null-sink sink_name=source object.linger=1
     media.class=Audio/Source/Virtual channel_map=FL,FR,RL,RR

     This creates a node with "input" and "capture" ports and looks
     like a virtual source for pulseaudio clients.

pactl load-module module-null-sink sink_name=source object.linger=1
     media.class=Audio/Sink channel_map=FL,FR,RL,RR

     This creates a node with "playback" and "monitor" ports and looks
     like a virtual sink for pulseaudio clients.

pactl load-module module-null-sink sink_name=source object.linger=1
     media.class=Audio/Duplex channel_map=FL,FR,RL,RR

     This creates a node with "playback" and "capture" ports and looks
     like a virtual source and sink for pulseaudio clients.
This commit is contained in:
Wim Taymans 2020-12-02 15:40:23 +01:00
parent e2f0ab5710
commit 3c2ab98a2a
4 changed files with 38 additions and 31 deletions

View file

@ -35,31 +35,30 @@ static bool object_is_module(struct pw_manager_object *o)
static bool object_is_card(struct pw_manager_object *o)
{
const char *str;
return
strcmp(o->type, PW_TYPE_INTERFACE_Device) == 0 &&
o->props != NULL &&
(str = pw_properties_get(o->props, PW_KEY_MEDIA_CLASS)) != NULL &&
strcmp(str, "Audio/Device") == 0;
return strcmp(o->type, PW_TYPE_INTERFACE_Device) == 0 &&
o->props != NULL &&
(str = pw_properties_get(o->props, PW_KEY_MEDIA_CLASS)) != NULL &&
strcmp(str, "Audio/Device") == 0;
}
static bool object_is_sink(struct pw_manager_object *o)
{
const char *str;
return
strcmp(o->type, PW_TYPE_INTERFACE_Node) == 0 &&
o->props != NULL &&
(str = pw_properties_get(o->props, PW_KEY_MEDIA_CLASS)) != NULL &&
(strcmp(str, "Audio/Sink") == 0 || strcmp(str, "Audio/Duplex") == 0);
return strcmp(o->type, PW_TYPE_INTERFACE_Node) == 0 &&
o->props != NULL &&
(str = pw_properties_get(o->props, PW_KEY_MEDIA_CLASS)) != NULL &&
(strcmp(str, "Audio/Sink") == 0 || strcmp(str, "Audio/Duplex") == 0);
}
static bool object_is_source(struct pw_manager_object *o)
{
const char *str;
return
strcmp(o->type, PW_TYPE_INTERFACE_Node) == 0 &&
o->props != NULL &&
(str = pw_properties_get(o->props, PW_KEY_MEDIA_CLASS)) != NULL &&
(strcmp(str, "Audio/Source") == 0 || strcmp(str, "Audio/Duplex") == 0);
return strcmp(o->type, PW_TYPE_INTERFACE_Node) == 0 &&
o->props != NULL &&
(str = pw_properties_get(o->props, PW_KEY_MEDIA_CLASS)) != NULL &&
(strcmp(str, "Audio/Source") == 0 ||
strcmp(str, "Audio/Duplex") == 0 ||
strcmp(str, "Audio/Source/Virtual") == 0);
}
static bool object_is_monitor(struct pw_manager_object *o)
@ -79,21 +78,19 @@ static bool object_is_source_or_monitor(struct pw_manager_object *o)
static bool object_is_sink_input(struct pw_manager_object *o)
{
const char *str;
return
strcmp(o->type, PW_TYPE_INTERFACE_Node) == 0 &&
o->props != NULL &&
(str = pw_properties_get(o->props, PW_KEY_MEDIA_CLASS)) != NULL &&
strcmp(str, "Stream/Output/Audio") == 0;
return strcmp(o->type, PW_TYPE_INTERFACE_Node) == 0 &&
o->props != NULL &&
(str = pw_properties_get(o->props, PW_KEY_MEDIA_CLASS)) != NULL &&
strcmp(str, "Stream/Output/Audio") == 0;
}
static bool object_is_source_output(struct pw_manager_object *o)
{
const char *str;
return
strcmp(o->type, PW_TYPE_INTERFACE_Node) == 0 &&
o->props != NULL &&
(str = pw_properties_get(o->props, PW_KEY_MEDIA_CLASS)) != NULL &&
strcmp(str, "Stream/Input/Audio") == 0;
return strcmp(o->type, PW_TYPE_INTERFACE_Node) == 0 &&
o->props != NULL &&
(str = pw_properties_get(o->props, PW_KEY_MEDIA_CLASS)) != NULL &&
strcmp(str, "Stream/Input/Audio") == 0;
}
static bool object_is_recordable(struct pw_manager_object *o)

View file

@ -3397,7 +3397,10 @@ static int fill_sink_info(struct client *client, struct message *m,
if ((name = spa_dict_lookup(info->props, PW_KEY_NODE_NAME)) != NULL) {
size_t size = strlen(name) + 10;
monitor_name = alloca(size);
snprintf(monitor_name, size, "%s.monitor", name);
if (object_is_source(o))
snprintf(monitor_name, size, "%s", name);
else
snprintf(monitor_name, size, "%s.monitor", name);
}
if ((desc = spa_dict_lookup(info->props, PW_KEY_NODE_DESCRIPTION)) == NULL)
desc = name;