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
|
#ifndef PKE_AUDIO_IMPL_PW_HPP
#define PKE_AUDIO_IMPL_PW_HPP
#include <atomic>
#include "pk.h"
// 2025-06-24 spa does not have c++ headers so we have to use c headers.
// They throw a ton of pedantic warnings that spam the build output.
// Might be too large of a swath, but none of this is my code anyway.
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wpedantic"
#include <pipewire/pipewire.h>
#include <pipewire/extensions/metadata.h>
#include <spa/param/audio/format-utils.h>
#include <spa/param/audio/raw.h>
#include <spa/param/param.h>
#include <spa/utils/string.h>
#pragma GCC diagnostic pop
#define PKE_AUDIO_POD_BUFFER_LEN 1024
enum pke_audio_pw_object_type : uint8_t {
PKE_AUDIO_PW_OBJECT_TYPE_ANY,
PKE_AUDIO_PW_OBJECT_TYPE_NODE,
PKE_AUDIO_PW_OBJECT_TYPE_PORT,
PKE_AUDIO_PW_OBJECT_TYPE_LINK,
PKE_AUDIO_PW_OBJECT_TYPE_METADATA,
};
struct pke_audio_pw_object {
union {
struct {
enum pw_direction direction;
uint32_t node;
uint32_t id;
} port;
struct {
uint32_t output_port;
uint32_t input_port;
uint32_t dummy;
} link;
} data;
uint32_t id;
enum pke_audio_pw_object_type type;
struct pw_properties *props;
};
struct pke_audio_implementation_pipewire {
pk_membucket *bkt;
pw_thread_loop *loop;
uint8_t *pod_buffer;
pw_stream *stream;
pw_core *core;
pw_registry *registry;
spa_hook registry_listener;
pw_metadata *metadata;
spa_hook metadata_listener;
pk_arr_t<pke_audio_pw_object> pw_objects;
pk_arr_t<void*> created_objects;
char *default_sink_name;
spa_audio_info format;
uint32_t default_sink_id;
std::atomic_bool is_needing_output_remapped;
};
extern struct pke_audio_implementation_pipewire pke_audio_pw;
void pke_audio_pw_init();
void pke_audio_pw_teardown();
void pke_audio_pw_remap_outputs();
void on_pipewire_process(void *user_data);
void on_pipewire_stream_param_changed(void *, uint32_t id, const struct spa_pod *param);
void on_registry_event_global(void *data, uint32_t id, uint32_t permissions, const char *type, uint32_t version, const struct spa_dict *props);
void on_registry_event_global_removal(void *data, uint32_t id);
#endif /* PKE_AUDIO_IMPL_PW_HPP */
|