mirror of
				https://gitlab.freedesktop.org/pipewire/pipewire.git
				synced 2025-11-03 09:01:54 -05:00 
			
		
		
		
	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:
		
							parent
							
								
									e2f0ab5710
								
							
						
					
					
						commit
						3c2ab98a2a
					
				
					 4 changed files with 38 additions and 31 deletions
				
			
		| 
						 | 
					@ -287,7 +287,9 @@ handle_node(struct impl *impl, struct sm_object *object)
 | 
				
			||||||
		else
 | 
							else
 | 
				
			||||||
			return 0;
 | 
								return 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		if (strcmp(media_class, "Sink") == 0 || strcmp(media_class, "Duplex") == 0)
 | 
							if (strcmp(media_class, "Sink") == 0 ||
 | 
				
			||||||
 | 
							    strcmp(media_class, "Duplex") == 0 ||
 | 
				
			||||||
 | 
							    strcmp(media_class, "Source/Virtual") == 0)
 | 
				
			||||||
			direction = PW_DIRECTION_INPUT;
 | 
								direction = PW_DIRECTION_INPUT;
 | 
				
			||||||
		else if (strcmp(media_class, "Source") == 0)
 | 
							else if (strcmp(media_class, "Source") == 0)
 | 
				
			||||||
			direction = PW_DIRECTION_OUTPUT;
 | 
								direction = PW_DIRECTION_OUTPUT;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -89,7 +89,7 @@ static void node_port_init(void *data, struct pw_impl_port *port)
 | 
				
			||||||
	struct pw_properties *new;
 | 
						struct pw_properties *new;
 | 
				
			||||||
	const char *str, *path, *node_name, *media_class;
 | 
						const char *str, *path, *node_name, *media_class;
 | 
				
			||||||
	char position[8], *prefix;
 | 
						char position[8], *prefix;
 | 
				
			||||||
	bool is_monitor, is_device, is_duplex;
 | 
						bool is_monitor, is_device, is_duplex, is_virtual;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	direction = pw_impl_port_get_direction(port);
 | 
						direction = pw_impl_port_get_direction(port);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -112,14 +112,19 @@ static void node_port_init(void *data, struct pw_impl_port *port)
 | 
				
			||||||
		is_device = false;
 | 
							is_device = false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	is_duplex = media_class != NULL && strstr(media_class, "Duplex") != NULL;
 | 
						is_duplex = media_class != NULL && strstr(media_class, "Duplex") != NULL;
 | 
				
			||||||
 | 
						is_virtual = media_class != NULL && strstr(media_class, "Virtual") != NULL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	new = pw_properties_new(NULL, NULL);
 | 
						new = pw_properties_new(NULL, NULL);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (is_monitor && !is_duplex)
 | 
						if (is_duplex)
 | 
				
			||||||
		prefix = "monitor";
 | 
					 | 
				
			||||||
	else if (is_device || is_duplex)
 | 
					 | 
				
			||||||
		prefix = direction == PW_DIRECTION_INPUT ?
 | 
							prefix = direction == PW_DIRECTION_INPUT ?
 | 
				
			||||||
			"playback" : "capture";
 | 
								"playback" : "capture";
 | 
				
			||||||
 | 
						else if (is_virtual)
 | 
				
			||||||
 | 
							prefix = direction == PW_DIRECTION_INPUT ?
 | 
				
			||||||
 | 
								"input" : "capture";
 | 
				
			||||||
 | 
						else if (is_device)
 | 
				
			||||||
 | 
							prefix = direction == PW_DIRECTION_INPUT ?
 | 
				
			||||||
 | 
								"playback" : is_monitor ? "monitor" : "capture";
 | 
				
			||||||
	else
 | 
						else
 | 
				
			||||||
		prefix = direction == PW_DIRECTION_INPUT ?
 | 
							prefix = direction == PW_DIRECTION_INPUT ?
 | 
				
			||||||
			"input" : "output";
 | 
								"input" : "output";
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -35,31 +35,30 @@ static bool object_is_module(struct pw_manager_object *o)
 | 
				
			||||||
static bool object_is_card(struct pw_manager_object *o)
 | 
					static bool object_is_card(struct pw_manager_object *o)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	const char *str;
 | 
						const char *str;
 | 
				
			||||||
	return
 | 
						return strcmp(o->type, PW_TYPE_INTERFACE_Device) == 0 &&
 | 
				
			||||||
	    strcmp(o->type, PW_TYPE_INTERFACE_Device) == 0 &&
 | 
							o->props != NULL &&
 | 
				
			||||||
	    o->props != NULL &&
 | 
							(str = pw_properties_get(o->props, PW_KEY_MEDIA_CLASS)) != NULL &&
 | 
				
			||||||
	    (str = pw_properties_get(o->props, PW_KEY_MEDIA_CLASS)) != NULL &&
 | 
							strcmp(str, "Audio/Device") == 0;
 | 
				
			||||||
	    strcmp(str, "Audio/Device") == 0;
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static bool object_is_sink(struct pw_manager_object *o)
 | 
					static bool object_is_sink(struct pw_manager_object *o)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	const char *str;
 | 
						const char *str;
 | 
				
			||||||
	return
 | 
						return strcmp(o->type, PW_TYPE_INTERFACE_Node) == 0 &&
 | 
				
			||||||
	    strcmp(o->type, PW_TYPE_INTERFACE_Node) == 0 &&
 | 
							o->props != NULL &&
 | 
				
			||||||
	    o->props != NULL &&
 | 
							(str = pw_properties_get(o->props, PW_KEY_MEDIA_CLASS)) != NULL &&
 | 
				
			||||||
	    (str = pw_properties_get(o->props, PW_KEY_MEDIA_CLASS)) != NULL &&
 | 
							(strcmp(str, "Audio/Sink") == 0 || strcmp(str, "Audio/Duplex") == 0);
 | 
				
			||||||
	    (strcmp(str, "Audio/Sink") == 0 || strcmp(str, "Audio/Duplex") == 0);
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static bool object_is_source(struct pw_manager_object *o)
 | 
					static bool object_is_source(struct pw_manager_object *o)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	const char *str;
 | 
						const char *str;
 | 
				
			||||||
	return
 | 
						return strcmp(o->type, PW_TYPE_INTERFACE_Node) == 0 &&
 | 
				
			||||||
	    strcmp(o->type, PW_TYPE_INTERFACE_Node) == 0 &&
 | 
							o->props != NULL &&
 | 
				
			||||||
	    o->props != NULL &&
 | 
							(str = pw_properties_get(o->props, PW_KEY_MEDIA_CLASS)) != NULL &&
 | 
				
			||||||
	    (str = pw_properties_get(o->props, PW_KEY_MEDIA_CLASS)) != NULL &&
 | 
							(strcmp(str, "Audio/Source") == 0 ||
 | 
				
			||||||
	    (strcmp(str, "Audio/Source") == 0 || strcmp(str, "Audio/Duplex") == 0);
 | 
							 strcmp(str, "Audio/Duplex") == 0 ||
 | 
				
			||||||
 | 
							 strcmp(str, "Audio/Source/Virtual") == 0);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static bool object_is_monitor(struct pw_manager_object *o)
 | 
					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)
 | 
					static bool object_is_sink_input(struct pw_manager_object *o)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	const char *str;
 | 
						const char *str;
 | 
				
			||||||
	return
 | 
						return strcmp(o->type, PW_TYPE_INTERFACE_Node) == 0 &&
 | 
				
			||||||
	    strcmp(o->type, PW_TYPE_INTERFACE_Node) == 0 &&
 | 
							o->props != NULL &&
 | 
				
			||||||
	    o->props != NULL &&
 | 
							(str = pw_properties_get(o->props, PW_KEY_MEDIA_CLASS)) != NULL &&
 | 
				
			||||||
	    (str = pw_properties_get(o->props, PW_KEY_MEDIA_CLASS)) != NULL &&
 | 
							strcmp(str, "Stream/Output/Audio") == 0;
 | 
				
			||||||
	    strcmp(str, "Stream/Output/Audio") == 0;
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static bool object_is_source_output(struct pw_manager_object *o)
 | 
					static bool object_is_source_output(struct pw_manager_object *o)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	const char *str;
 | 
						const char *str;
 | 
				
			||||||
	return
 | 
						return strcmp(o->type, PW_TYPE_INTERFACE_Node) == 0 &&
 | 
				
			||||||
	    strcmp(o->type, PW_TYPE_INTERFACE_Node) == 0 &&
 | 
							o->props != NULL &&
 | 
				
			||||||
	    o->props != NULL &&
 | 
							(str = pw_properties_get(o->props, PW_KEY_MEDIA_CLASS)) != NULL &&
 | 
				
			||||||
	    (str = pw_properties_get(o->props, PW_KEY_MEDIA_CLASS)) != NULL &&
 | 
							strcmp(str, "Stream/Input/Audio") == 0;
 | 
				
			||||||
	    strcmp(str, "Stream/Input/Audio") == 0;
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static bool object_is_recordable(struct pw_manager_object *o)
 | 
					static bool object_is_recordable(struct pw_manager_object *o)
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -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) {
 | 
						if ((name = spa_dict_lookup(info->props, PW_KEY_NODE_NAME)) != NULL) {
 | 
				
			||||||
		size_t size = strlen(name) + 10;
 | 
							size_t size = strlen(name) + 10;
 | 
				
			||||||
		monitor_name = alloca(size);
 | 
							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)
 | 
						if ((desc = spa_dict_lookup(info->props, PW_KEY_NODE_DESCRIPTION)) == NULL)
 | 
				
			||||||
		desc = name;
 | 
							desc = name;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue