1 /* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim:expandtab:shiftwidth=4:tabstop=4:
3  */
4 /* This Source Code Form is subject to the terms of the Mozilla Public
5  * License, v. 2.0. If a copy of the MPL was not distributed with this
6  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
7 
8 #include <glib.h>
9 #include "mozilla/Types.h"
10 #include "prlink.h"
11 
12 #include <pipewire/pipewire.h>
13 
14 #define GET_FUNC(func, lib)                                  \
15     func##_fn =                                              \
16       (decltype(func##_fn))PR_FindFunctionSymbol(lib, #func) \
17 
18 #define IS_FUNC_LOADED(func)                                          \
19     (func != nullptr)                                                 \
20 
21 struct GUnixFDList;
22 
23 extern "C" gint
g_unix_fd_list_get(struct GUnixFDList * list,gint index_,GError ** error)24 g_unix_fd_list_get(struct GUnixFDList *list,
25                    gint index_,
26                    GError **error)
27 {
28   static PRLibrary* gioLib = nullptr;
29   static bool gioInitialized = false;
30   static gint (*g_unix_fd_list_get_fn)(struct GUnixFDList *list,
31                gint index_, GError **error) = nullptr;
32 
33   if (!gioInitialized) {
34     gioInitialized = true;
35     gioLib = PR_LoadLibrary("libgio-2.0.so.0");
36     if (!gioLib) {
37       return -1;
38     }
39     GET_FUNC(g_unix_fd_list_get, gioLib);
40   }
41 
42   if (!g_unix_fd_list_get_fn) {
43     return -1;
44   }
45 
46   return g_unix_fd_list_get_fn(list, index_, error);
47 }
48 
49 static struct pw_core * (*pw_context_connect_fn)(struct pw_context *context,
50                                               struct pw_properties *properties,
51                                               size_t user_data_size);
52 static struct pw_core * (*pw_context_connect_fd_fn)(struct pw_context *context,
53                                                     int fd,
54                                                     struct pw_properties *properties,
55                                                     size_t user_data_size);
56 static void (*pw_context_destroy_fn)(struct pw_context *context);
57 struct pw_context * (*pw_context_new_fn)(struct pw_loop *main_loop,
58                                       struct pw_properties *props,
59                                       size_t user_data_size);
60 static int (*pw_core_disconnect_fn)(struct pw_core *core);
61 static void (*pipewire_init_fn)(int *argc, char **argv[]);
62 static void (*pw_stream_add_listener_fn)(struct pw_stream *stream,
63                                       struct spa_hook *listener,
64                                       const struct pw_stream_events *events,
65                                       void *data);
66 static int (*pw_stream_connect_fn)(struct pw_stream *stream,
67                                 enum pw_direction direction,
68                                 uint32_t target_id,
69                                 enum pw_stream_flags flags,
70                                 const struct spa_pod **params,
71                                 uint32_t n_params);
72 static struct pw_buffer* (*pw_stream_dequeue_buffer_fn)(struct pw_stream *stream);
73 static void (*pw_stream_destroy_fn)(struct pw_stream *stream);
74 static struct pw_stream* (*pw_stream_new_fn)(struct pw_core *core,
75                                           const char *name,
76                                           struct pw_properties *props);
77 static int (*pw_stream_queue_buffer_fn)(struct pw_stream *stream,
78                                      struct pw_buffer *buffer);
79 static int (*pw_stream_update_params_fn)(struct pw_stream *stream,
80                                       const struct spa_pod **params,
81                                       uint32_t n_params);
82 static void (*pw_thread_loop_destroy_fn)(struct pw_thread_loop *loop);
83 static struct pw_loop* (*pw_thread_loop_get_loop_fn)(struct pw_thread_loop *loop);
84 static struct pw_thread_loop* (*pw_thread_loop_new_fn)(const char *name,
85                                                 const struct spa_dict *props);
86 static int (*pw_thread_loop_start_fn)(struct pw_thread_loop *loop);
87 static void (*pw_thread_loop_stop_fn)(struct pw_thread_loop *loop);
88 
IsPwLibraryLoaded()89 bool IsPwLibraryLoaded() {
90   static bool isLoaded =
91          (IS_FUNC_LOADED(pw_context_connect_fn) &&
92           IS_FUNC_LOADED(pw_context_connect_fd_fn) &&
93           IS_FUNC_LOADED(pw_context_destroy_fn) &&
94           IS_FUNC_LOADED(pw_context_new_fn) &&
95           IS_FUNC_LOADED(pw_core_disconnect_fn) &&
96           IS_FUNC_LOADED(pipewire_init_fn) &&
97           IS_FUNC_LOADED(pw_stream_add_listener_fn) &&
98           IS_FUNC_LOADED(pw_stream_connect_fn) &&
99           IS_FUNC_LOADED(pw_stream_dequeue_buffer_fn) &&
100           IS_FUNC_LOADED(pw_stream_destroy_fn) &&
101           IS_FUNC_LOADED(pw_stream_new_fn) &&
102           IS_FUNC_LOADED(pw_stream_queue_buffer_fn) &&
103           IS_FUNC_LOADED(pw_stream_update_params_fn) &&
104           IS_FUNC_LOADED(pw_thread_loop_destroy_fn) &&
105           IS_FUNC_LOADED(pw_thread_loop_get_loop_fn) &&
106           IS_FUNC_LOADED(pw_thread_loop_new_fn) &&
107           IS_FUNC_LOADED(pw_thread_loop_start_fn) &&
108           IS_FUNC_LOADED(pw_thread_loop_stop_fn));
109 
110   return isLoaded;
111 }
112 
LoadPWLibrary()113 bool LoadPWLibrary() {
114   static PRLibrary* pwLib = nullptr;
115   static bool pwInitialized = false;
116 
117   //TODO Thread safe
118   if (!pwInitialized) {
119     pwInitialized = true;
120     pwLib = PR_LoadLibrary("libpipewire-0.3.so.0");
121     if (!pwLib) {
122       return false;
123     }
124 
125     GET_FUNC(pw_context_connect, pwLib);
126     GET_FUNC(pw_context_connect_fd, pwLib);
127     GET_FUNC(pw_context_destroy, pwLib);
128     GET_FUNC(pw_context_new, pwLib);
129     GET_FUNC(pw_core_disconnect, pwLib);
130     GET_FUNC(pipewire_init, pwLib);
131     GET_FUNC(pw_stream_add_listener, pwLib);
132     GET_FUNC(pw_stream_connect, pwLib);
133     GET_FUNC(pw_stream_dequeue_buffer, pwLib);
134     GET_FUNC(pw_stream_destroy, pwLib);
135     GET_FUNC(pw_stream_new, pwLib);
136     GET_FUNC(pw_stream_queue_buffer, pwLib);
137     GET_FUNC(pw_stream_update_params, pwLib);
138     GET_FUNC(pw_thread_loop_destroy, pwLib);
139     GET_FUNC(pw_thread_loop_get_loop, pwLib);
140     GET_FUNC(pw_thread_loop_new, pwLib);
141     GET_FUNC(pw_thread_loop_start, pwLib);
142     GET_FUNC(pw_thread_loop_stop, pwLib);
143   }
144 
145   return IsPwLibraryLoaded();
146 }
147 
148 struct pw_core *
pw_context_connect(struct pw_context * context,struct pw_properties * properties,size_t user_data_size)149 pw_context_connect(struct pw_context *context,
150                    struct pw_properties *properties,
151                    size_t user_data_size)
152 {
153   if (!LoadPWLibrary()) {
154     return nullptr;
155   }
156   return pw_context_connect_fn(context, properties, user_data_size);
157 }
158 
159 struct pw_core *
pw_context_connect_fd(struct pw_context * context,int fd,struct pw_properties * properties,size_t user_data_size)160 pw_context_connect_fd(struct pw_context *context,
161                       int fd,
162                       struct pw_properties *properties,
163                       size_t user_data_size)
164 {
165   if (!LoadPWLibrary()) {
166     return nullptr;
167   }
168   return pw_context_connect_fd_fn(context, fd, properties, user_data_size);
169 }
170 
171 void
pw_context_destroy(struct pw_context * context)172 pw_context_destroy(struct pw_context *context)
173 {
174   if (!LoadPWLibrary()) {
175     return;
176   }
177   pw_context_destroy_fn(context);
178 }
179 
180 struct pw_context *
pw_context_new(struct pw_loop * main_loop,struct pw_properties * props,size_t user_data_size)181 pw_context_new(struct pw_loop *main_loop,
182                struct pw_properties *props,
183                size_t user_data_size)
184 {
185   if (!LoadPWLibrary()) {
186     return nullptr;
187   }
188   return pw_context_new_fn(main_loop, props, user_data_size);
189 }
190 
191 int
pw_core_disconnect(struct pw_core * core)192 pw_core_disconnect(struct pw_core *core)
193 {
194   if (!LoadPWLibrary()) {
195     return 0;
196   }
197   return pw_core_disconnect_fn(core);
198 }
199 
200 void
pipewire_init(int * argc,char ** argv[])201 pipewire_init(int *argc, char **argv[])
202 {
203   if (!LoadPWLibrary()) {
204     return;
205   }
206   return pipewire_init_fn(argc, argv);
207 }
208 
209 void
pw_stream_add_listener(struct pw_stream * stream,struct spa_hook * listener,const struct pw_stream_events * events,void * data)210 pw_stream_add_listener(struct pw_stream *stream,
211                        struct spa_hook *listener,
212                        const struct pw_stream_events *events,
213                        void *data)
214 {
215   if (!LoadPWLibrary()) {
216     return;
217   }
218   return pw_stream_add_listener_fn(stream, listener, events, data);
219 }
220 
221 int
pw_stream_connect(struct pw_stream * stream,enum pw_direction direction,uint32_t target_id,enum pw_stream_flags flags,const struct spa_pod ** params,uint32_t n_params)222 pw_stream_connect(struct pw_stream *stream,
223                   enum pw_direction direction,
224                   uint32_t target_id,
225                   enum pw_stream_flags flags,
226                   const struct spa_pod **params,
227                   uint32_t n_params)
228 {
229   if (!LoadPWLibrary()) {
230     return 0;
231   }
232   return pw_stream_connect_fn(stream, direction, target_id, flags,
233                               params, n_params);
234 }
235 
236 struct pw_buffer *
pw_stream_dequeue_buffer(struct pw_stream * stream)237 pw_stream_dequeue_buffer(struct pw_stream *stream)
238 {
239   if (!LoadPWLibrary()) {
240     return nullptr;
241   }
242   return pw_stream_dequeue_buffer_fn(stream);
243 }
244 
245 void
pw_stream_destroy(struct pw_stream * stream)246 pw_stream_destroy(struct pw_stream *stream)
247 {
248   if (!LoadPWLibrary()) {
249     return;
250   }
251   return pw_stream_destroy_fn(stream);
252 }
253 
254 struct pw_stream *
pw_stream_new(struct pw_core * core,const char * name,struct pw_properties * props)255 pw_stream_new(struct pw_core *core,
256               const char *name,
257               struct pw_properties *props)
258 {
259   if (!LoadPWLibrary()) {
260     return nullptr;
261   }
262   return pw_stream_new_fn(core, name, props);
263 }
264 
265 int
pw_stream_queue_buffer(struct pw_stream * stream,struct pw_buffer * buffer)266 pw_stream_queue_buffer(struct pw_stream *stream,
267                        struct pw_buffer *buffer)
268 {
269   if (!LoadPWLibrary()) {
270     return 0;
271   }
272   return pw_stream_queue_buffer_fn(stream, buffer);
273 }
274 
275 int
pw_stream_update_params(struct pw_stream * stream,const struct spa_pod ** params,uint32_t n_params)276 pw_stream_update_params(struct pw_stream *stream,
277                         const struct spa_pod **params,
278                         uint32_t n_params)
279 {
280   if (!LoadPWLibrary()) {
281     return 0;
282   }
283   return pw_stream_update_params_fn(stream, params, n_params);
284 }
285 
286 void
pw_thread_loop_destroy(struct pw_thread_loop * loop)287 pw_thread_loop_destroy(struct pw_thread_loop *loop)
288 {
289   if (!LoadPWLibrary()) {
290     return;
291   }
292   return pw_thread_loop_destroy_fn(loop);
293 }
294 
295 struct pw_loop *
pw_thread_loop_get_loop(struct pw_thread_loop * loop)296 pw_thread_loop_get_loop(struct pw_thread_loop *loop)
297 {
298   if (!LoadPWLibrary()) {
299     return nullptr;
300   }
301   return pw_thread_loop_get_loop_fn(loop);
302 }
303 
304 struct pw_thread_loop *
pw_thread_loop_new(const char * name,const struct spa_dict * props)305 pw_thread_loop_new(const char *name,
306                    const struct spa_dict *props)
307 {
308   if (!LoadPWLibrary()) {
309     return nullptr;
310   }
311   return pw_thread_loop_new_fn(name, props);
312 }
313 
314 int
pw_thread_loop_start(struct pw_thread_loop * loop)315 pw_thread_loop_start(struct pw_thread_loop *loop)
316 {
317   if (!LoadPWLibrary()) {
318     return 0;
319   }
320   return pw_thread_loop_start_fn(loop);
321 }
322 
323 void
pw_thread_loop_stop(struct pw_thread_loop * loop)324 pw_thread_loop_stop(struct pw_thread_loop *loop)
325 {
326   if (!LoadPWLibrary()) {
327     return;
328   }
329   return pw_thread_loop_stop_fn(loop);
330 }
331