-
Notifications
You must be signed in to change notification settings - Fork 242
/
Copy pathpipewire.c
148 lines (116 loc) · 4.46 KB
/
pipewire.c
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
#include "input/pipewire.h"
#include "input/common.h"
#include <math.h>
#include <spa/param/audio/format-utils.h>
#include <spa/param/latency-utils.h>
#include <pipewire/pipewire.h>
struct pw_data {
struct pw_main_loop *loop;
struct pw_stream *stream;
struct spa_audio_info format;
unsigned move : 1;
struct audio_data *cava_audio;
};
static void on_process(void *userdata) {
struct pw_data *data = userdata;
struct pw_buffer *b;
struct spa_buffer *buf;
uint32_t n_samples;
int16_t *samples;
if (data->cava_audio->terminate == 1)
pw_main_loop_quit(data->loop);
if ((b = pw_stream_dequeue_buffer(data->stream)) == NULL) {
pw_log_warn("out of buffers: %m");
return;
}
buf = b->buffer;
if ((samples = buf->datas[0].data) == NULL)
return;
n_samples = buf->datas[0].chunk->size / (data->cava_audio->format / 8);
write_to_cava_input_buffers(n_samples, buf->datas[0].data, data->cava_audio);
pw_stream_queue_buffer(data->stream, b);
}
static void on_stream_param_changed(void *_data, uint32_t id, const struct spa_pod *param) {
struct pw_data *data = _data;
if (param == NULL || id != SPA_PARAM_Format)
return;
if (spa_format_parse(param, &data->format.media_type, &data->format.media_subtype) < 0)
return;
if (data->format.media_type != SPA_MEDIA_TYPE_audio ||
data->format.media_subtype != SPA_MEDIA_SUBTYPE_raw)
return;
spa_format_audio_raw_parse(param, &data->format.info.raw);
}
static const struct pw_stream_events stream_events = {
PW_VERSION_STREAM_EVENTS,
.param_changed = on_stream_param_changed,
.process = on_process,
};
static void do_quit(void *userdata, int signal_number) {
struct pw_data *data = userdata;
data->cava_audio->terminate = 1;
pw_log_warn("pw quit signal %d received, terminating...", signal_number);
pw_main_loop_quit(data->loop);
}
void *input_pipewire(void *audiodata) {
struct pw_data data = {
0,
};
data.cava_audio = (struct audio_data *)audiodata;
const struct spa_pod *params[1];
uint8_t buffer[data.cava_audio->input_buffer_size];
struct pw_properties *props;
struct spa_pod_builder b = SPA_POD_BUILDER_INIT(buffer, sizeof(buffer));
uint32_t nom;
nom = nearbyint((10000 * data.cava_audio->rate) / 1000000.0);
pw_init(0, 0);
data.loop = pw_main_loop_new(NULL);
if (data.loop == NULL) {
data.cava_audio->terminate = 1;
sprintf(data.cava_audio->error_message,
__FILE__ ": Could not create main loop. Is your system running pipewire? Maybe try "
"pulse input method instead.");
return 0;
}
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);
props = pw_properties_new(PW_KEY_MEDIA_TYPE, "Audio", PW_KEY_MEDIA_CATEGORY, "Capture",
PW_KEY_MEDIA_ROLE, "Music", NULL);
const char *source = data.cava_audio->source;
if (strcmp(source, "auto") == 0) {
pw_properties_set(props, PW_KEY_STREAM_CAPTURE_SINK, "true");
} else {
pw_properties_set(props, PW_KEY_TARGET_OBJECT, source);
}
pw_properties_setf(props, PW_KEY_NODE_LATENCY, "%u/%u", nom, data.cava_audio->rate);
pw_properties_set(props, PW_KEY_NODE_ALWAYS_PROCESS, "true");
data.stream = pw_stream_new_simple(pw_main_loop_get_loop(data.loop), "cava", props,
&stream_events, &data);
enum spa_audio_format audio_format = SPA_AUDIO_FORMAT_S16;
switch (data.cava_audio->format) {
case 8:
audio_format = SPA_AUDIO_FORMAT_S8;
break;
case 16:
audio_format = SPA_AUDIO_FORMAT_S16;
break;
case 24:
audio_format = SPA_AUDIO_FORMAT_S24;
break;
case 32:
audio_format = SPA_AUDIO_FORMAT_S32;
break;
};
params[0] = spa_format_audio_raw_build(
&b, SPA_PARAM_EnumFormat,
&SPA_AUDIO_INFO_RAW_INIT(.format = audio_format, .rate = data.cava_audio->rate));
pw_stream_connect(data.stream, PW_DIRECTION_INPUT, PW_ID_ANY,
PW_STREAM_FLAG_AUTOCONNECT | PW_STREAM_FLAG_MAP_BUFFERS |
PW_STREAM_FLAG_RT_PROCESS,
params, 1);
pw_main_loop_run(data.loop);
pw_stream_destroy(data.stream);
pw_main_loop_destroy(data.loop);
pw_deinit();
return 0;
}