mirror of
				https://gitlab.freedesktop.org/pipewire/pipewire.git
				synced 2025-11-03 09:01:54 -05:00 
			
		
		
		
	pulse: add a small pulseaudio daemon
Add a small application that loads the pulse server and makes it listen on the pulseaudio socket. Add some systemd activation files to start the service.
This commit is contained in:
		
							parent
							
								
									10207456f0
								
							
						
					
					
						commit
						798bcc10b1
					
				
					 5 changed files with 181 additions and 1 deletions
				
			
		| 
						 | 
					@ -41,6 +41,14 @@ executable('pipewire',
 | 
				
			||||||
  dependencies : [pipewire_dep, ],
 | 
					  dependencies : [pipewire_dep, ],
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					executable('pipewire-pulse',
 | 
				
			||||||
 | 
					  'pipewire-pulse.c',
 | 
				
			||||||
 | 
					  install: true,
 | 
				
			||||||
 | 
					  c_args : pipewire_c_args,
 | 
				
			||||||
 | 
					  include_directories : [configinc, spa_inc],
 | 
				
			||||||
 | 
					  dependencies : [pipewire_dep, ],
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
if get_option('systemd') and systemd.found()
 | 
					if get_option('systemd') and systemd.found()
 | 
				
			||||||
  subdir('systemd')
 | 
					  subdir('systemd')
 | 
				
			||||||
endif
 | 
					endif
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										129
									
								
								src/daemon/pipewire-pulse.c
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										129
									
								
								src/daemon/pipewire-pulse.c
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,129 @@
 | 
				
			||||||
 | 
					/* PipeWire
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * Copyright © 2020 Wim Taymans
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * 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.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <signal.h>
 | 
				
			||||||
 | 
					#include <getopt.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <spa/utils/result.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <pipewire/impl.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "config.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static const char *address;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void do_quit(void *data, int signal_number)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct pw_main_loop *loop = data;
 | 
				
			||||||
 | 
						pw_main_loop_quit(loop);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void show_help(const char *name)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						fprintf(stdout, "%s [options]\n"
 | 
				
			||||||
 | 
							"  -h, --help                            Show this help\n"
 | 
				
			||||||
 | 
							"      --version                         Show version\n"
 | 
				
			||||||
 | 
							"  -a  --address                         comma separated list of addresses (Default %s)\n",
 | 
				
			||||||
 | 
							name,
 | 
				
			||||||
 | 
							address);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int main(int argc, char *argv[])
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct pw_context *context;
 | 
				
			||||||
 | 
						struct pw_main_loop *loop;
 | 
				
			||||||
 | 
						struct pw_properties *properties;
 | 
				
			||||||
 | 
						char *args;
 | 
				
			||||||
 | 
						static const struct option long_options[] = {
 | 
				
			||||||
 | 
							{ "help",	no_argument,		NULL, 'h' },
 | 
				
			||||||
 | 
							{ "version",	no_argument,		NULL, 'V' },
 | 
				
			||||||
 | 
							{ "address",	required_argument,	NULL, 'a' },
 | 
				
			||||||
 | 
							{ NULL, 0, NULL, 0}
 | 
				
			||||||
 | 
						};
 | 
				
			||||||
 | 
						int c;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						pw_init(&argc, &argv);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						address = "unix:native";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						while ((c = getopt_long(argc, argv, "hVa:", long_options, NULL)) != -1) {
 | 
				
			||||||
 | 
							switch (c) {
 | 
				
			||||||
 | 
							case 'h':
 | 
				
			||||||
 | 
								show_help(argv[0]);
 | 
				
			||||||
 | 
								return 0;
 | 
				
			||||||
 | 
							case 'V':
 | 
				
			||||||
 | 
								fprintf(stdout, "%s\n"
 | 
				
			||||||
 | 
									"Compiled with libpipewire %s\n"
 | 
				
			||||||
 | 
									"Linked with libpipewire %s\n",
 | 
				
			||||||
 | 
									argv[0],
 | 
				
			||||||
 | 
									pw_get_headers_version(),
 | 
				
			||||||
 | 
									pw_get_library_version());
 | 
				
			||||||
 | 
								return 0;
 | 
				
			||||||
 | 
							case 'a':
 | 
				
			||||||
 | 
								address = optarg;
 | 
				
			||||||
 | 
								fprintf(stdout, "set address %s\n", address);
 | 
				
			||||||
 | 
								break;
 | 
				
			||||||
 | 
							default:
 | 
				
			||||||
 | 
								return -1;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						properties = pw_properties_new(
 | 
				
			||||||
 | 
									PW_KEY_CONTEXT_PROFILE_MODULES, "default,rtkit",
 | 
				
			||||||
 | 
									NULL);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						loop = pw_main_loop_new(&properties->dict);
 | 
				
			||||||
 | 
						if (loop == NULL) {
 | 
				
			||||||
 | 
							pw_log_error("failed to create main-loop: %m");
 | 
				
			||||||
 | 
							return -1;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						pw_loop_add_signal(pw_main_loop_get_loop(loop), SIGINT, do_quit, loop);
 | 
				
			||||||
 | 
						pw_loop_add_signal(pw_main_loop_get_loop(loop), SIGTERM, do_quit, loop);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						context = pw_context_new(pw_main_loop_get_loop(loop), properties, 0);
 | 
				
			||||||
 | 
						if (context == NULL) {
 | 
				
			||||||
 | 
							pw_log_error("failed to create context: %m");
 | 
				
			||||||
 | 
							return -1;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						args = spa_aprintf("server.address=%s", address);
 | 
				
			||||||
 | 
						if (pw_context_load_module(context,
 | 
				
			||||||
 | 
									"libpipewire-module-protocol-pulse",
 | 
				
			||||||
 | 
									args, NULL) == NULL) {
 | 
				
			||||||
 | 
							pw_log_error("failed to create pulse module: %m");
 | 
				
			||||||
 | 
							return -1;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						pw_log_info("start main loop");
 | 
				
			||||||
 | 
						pw_main_loop_run(loop);
 | 
				
			||||||
 | 
						pw_log_info("leave main loop");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						free(args);
 | 
				
			||||||
 | 
						pw_context_destroy(context);
 | 
				
			||||||
 | 
						pw_main_loop_destroy(loop);
 | 
				
			||||||
 | 
						pw_deinit();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -1,11 +1,19 @@
 | 
				
			||||||
systemd_user_services_dir = systemd.get_pkgconfig_variable('systemduserunitdir', define_variable : [ 'prefix', prefix])
 | 
					systemd_user_services_dir = systemd.get_pkgconfig_variable('systemduserunitdir', define_variable : [ 'prefix', prefix])
 | 
				
			||||||
 | 
					
 | 
				
			||||||
install_data(sources : 'pipewire.socket', install_dir : systemd_user_services_dir)
 | 
					install_data(
 | 
				
			||||||
 | 
					  sources : ['pipewire.socket', 'pipewire-pulse.socket'],
 | 
				
			||||||
 | 
					  install_dir : systemd_user_services_dir)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
systemd_config = configuration_data()
 | 
					systemd_config = configuration_data()
 | 
				
			||||||
systemd_config.set('PW_BINARY', join_paths(pipewire_bindir, 'pipewire'))
 | 
					systemd_config.set('PW_BINARY', join_paths(pipewire_bindir, 'pipewire'))
 | 
				
			||||||
 | 
					systemd_config.set('PW_PULSE_BINARY', join_paths(pipewire_bindir, 'pipewire-pulse'))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
configure_file(input : 'pipewire.service.in',
 | 
					configure_file(input : 'pipewire.service.in',
 | 
				
			||||||
               output : 'pipewire.service',
 | 
					               output : 'pipewire.service',
 | 
				
			||||||
               configuration : systemd_config,
 | 
					               configuration : systemd_config,
 | 
				
			||||||
               install_dir : systemd_user_services_dir)
 | 
					               install_dir : systemd_user_services_dir)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					configure_file(input : 'pipewire-pulse.service.in',
 | 
				
			||||||
 | 
					               output : 'pipewire-pulse.service',
 | 
				
			||||||
 | 
					               configuration : systemd_config,
 | 
				
			||||||
 | 
					               install_dir : systemd_user_services_dir)
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										25
									
								
								src/daemon/systemd/user/pipewire-pulse.service.in
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										25
									
								
								src/daemon/systemd/user/pipewire-pulse.service.in
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,25 @@
 | 
				
			||||||
 | 
					[Unit]
 | 
				
			||||||
 | 
					Description=PipeWire PulseAudio
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# We require pipewire-pulse.socket to be active before starting the daemon, because
 | 
				
			||||||
 | 
					# while it is possible to use the service without the socket, it is not clear
 | 
				
			||||||
 | 
					# why it would be desirable.
 | 
				
			||||||
 | 
					#
 | 
				
			||||||
 | 
					# A user installing pipewire and doing `systemctl --user start pipewire-pulse`
 | 
				
			||||||
 | 
					# will not get the socket started, which might be confusing and problematic if
 | 
				
			||||||
 | 
					# the server is to be restarted later on, as the client autospawn feature
 | 
				
			||||||
 | 
					# might kick in. Also, a start of the socket unit will fail, adding to the
 | 
				
			||||||
 | 
					# confusion.
 | 
				
			||||||
 | 
					#
 | 
				
			||||||
 | 
					# After=pipewire-pulse.socket is not needed, as it is already implicit in the
 | 
				
			||||||
 | 
					# socket-service relationship, see systemd.socket(5).
 | 
				
			||||||
 | 
					Requires=pipewire-pulse.socket
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[Service]
 | 
				
			||||||
 | 
					Type=simple
 | 
				
			||||||
 | 
					ExecStart=@PW_PULSE_BINARY@
 | 
				
			||||||
 | 
					Restart=on-failure
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[Install]
 | 
				
			||||||
 | 
					Also=pipewire-pulse.socket
 | 
				
			||||||
 | 
					WantedBy=default.target
 | 
				
			||||||
							
								
								
									
										10
									
								
								src/daemon/systemd/user/pipewire-pulse.socket
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										10
									
								
								src/daemon/systemd/user/pipewire-pulse.socket
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,10 @@
 | 
				
			||||||
 | 
					[Unit]
 | 
				
			||||||
 | 
					Description=PipeWire PulseAudio
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[Socket]
 | 
				
			||||||
 | 
					Priority=6
 | 
				
			||||||
 | 
					Backlog=5
 | 
				
			||||||
 | 
					ListenStream=%t/pulse/native
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[Install]
 | 
				
			||||||
 | 
					WantedBy=sockets.target
 | 
				
			||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue