File: tutorial7.c

package info (click to toggle)
pipewire 1.6.2-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 17,856 kB
  • sloc: ansic: 309,496; cpp: 2,812; xml: 408; python: 243; sh: 214; makefile: 176; pascal: 85
file content (152 lines) | stat: -rw-r--r-- 3,813 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
/*
  [title]
  \ref page_tutorial7
  [title]
 */
/* [code] */
#include <stdio.h>
#include <errno.h>
#include <math.h>
#include <signal.h>

#include <spa/pod/builder.h>
#include <spa/param/latency-utils.h>

#include <pipewire/pipewire.h>
#include <pipewire/filter.h>

struct data;

struct port {
	struct data *data;
};

struct data {
	struct pw_main_loop *loop;
	struct pw_filter *filter;
	struct port *in_port;
	struct port *out_port;
};

/* [on_process] */
static void on_process(void *userdata, struct spa_io_position *position)
{
	struct data *data = userdata;
	float *in, *out;
	uint32_t n_samples = position->clock.duration;

	pw_log_trace("do process %d", n_samples);

	in = pw_filter_get_dsp_buffer(data->in_port, n_samples);
	out = pw_filter_get_dsp_buffer(data->out_port, n_samples);

	if (in == NULL || out == NULL)
		return;

	/* Simple passthrough - copy input to output.
	 * Here you could implement any audio processing:
	 * - Filters (lowpass, highpass, bandpass)
	 * - Effects (reverb, delay, distortion)
	 * - Dynamic processing (compressor, limiter)
	 * - Equalization
	 * - etc.
	 */
	memcpy(out, in, n_samples * sizeof(float));
}
/* [on_process] */

static const struct pw_filter_events filter_events = {
	PW_VERSION_FILTER_EVENTS,
	.process = on_process,
};

static void do_quit(void *userdata, int signal_number)
{
	struct data *data = userdata;
	pw_main_loop_quit(data->loop);
}

int main(int argc, char *argv[])
{
	struct data data = { 0, };
	const struct spa_pod *params[1];
	uint32_t n_params = 0;
	uint8_t buffer[1024];
	struct spa_pod_builder b = SPA_POD_BUILDER_INIT(buffer, sizeof(buffer));

	pw_init(&argc, &argv);

	/* make a main loop. If you already have another main loop, you can add
	 * the fd of this pipewire mainloop to it. */
	data.loop = pw_main_loop_new(NULL);

	pw_loop_add_signal(pw_main_loop_get_loop(data.loop), SIGINT, do_quit, &data);
	pw_loop_add_signal(pw_main_loop_get_loop(data.loop), SIGTERM, do_quit, &data);

	/* Create a simple filter, the simple filter manages the core and remote
	 * objects for you if you don't need to deal with them.
	 *
	 * Pass your events and a user_data pointer as the last arguments. This
	 * will inform you about the filter state. The most important event
	 * you need to listen to is the process event where you need to process
	 * the data.
	 */
	data.filter = pw_filter_new_simple(
			pw_main_loop_get_loop(data.loop),
			"audio-filter",
			pw_properties_new(
				PW_KEY_MEDIA_TYPE, "Audio",
				PW_KEY_MEDIA_CATEGORY, "Filter",
				PW_KEY_MEDIA_ROLE, "DSP",
				NULL),
			&filter_events,
			&data);

	/* make an audio DSP input port */
	data.in_port = pw_filter_add_port(data.filter,
			PW_DIRECTION_INPUT,
			PW_FILTER_PORT_FLAG_MAP_BUFFERS,
			sizeof(struct port),
			pw_properties_new(
				PW_KEY_FORMAT_DSP, "32 bit float mono audio",
				PW_KEY_PORT_NAME, "input",
				NULL),
			NULL, 0);

	/* make an audio DSP output port */
	data.out_port = pw_filter_add_port(data.filter,
			PW_DIRECTION_OUTPUT,
			PW_FILTER_PORT_FLAG_MAP_BUFFERS,
			sizeof(struct port),
			pw_properties_new(
				PW_KEY_FORMAT_DSP, "32 bit float mono audio",
				PW_KEY_PORT_NAME, "output",
				NULL),
			NULL, 0);

	/* Set processing latency information */
	params[n_params++] = spa_process_latency_build(&b,
			SPA_PARAM_ProcessLatency,
			&SPA_PROCESS_LATENCY_INFO_INIT(
				.ns = 10 * SPA_NSEC_PER_MSEC
			));

	/* Now connect this filter. We ask that our process function is
	 * called in a realtime thread. */
	if (pw_filter_connect(data.filter,
				PW_FILTER_FLAG_RT_PROCESS,
				params, n_params) < 0) {
		fprintf(stderr, "can't connect\n");
		return -1;
	}

	/* and wait while we let things run */
	pw_main_loop_run(data.loop);

	pw_filter_destroy(data.filter);
	pw_main_loop_destroy(data.loop);
	pw_deinit();

	return 0;
}
/* [code] */