camera: improve PipeWire version checks
Remove the custom server version check. We can easily do this as part of starting the hotplug loop. Check that we are at least running against a 1.0.0 server. Log the compiled, linked, server and required versions. Check that we are compiled and linked with the right version before using the time symbol of a struct.
This commit is contained in:
committed by
Sam Lantinga
parent
da06e67b1b
commit
2b9ac185cd
@@ -41,6 +41,10 @@
|
|||||||
#define PW_THREAD_NAME_BUFFER_LENGTH 128
|
#define PW_THREAD_NAME_BUFFER_LENGTH 128
|
||||||
#define PW_MAX_IDENTIFIER_LENGTH 256
|
#define PW_MAX_IDENTIFIER_LENGTH 256
|
||||||
|
|
||||||
|
#define PW_REQUIRED_MAJOR 1
|
||||||
|
#define PW_REQUIRED_MINOR 0
|
||||||
|
#define PW_REQUIRED_PATCH 0
|
||||||
|
|
||||||
enum PW_READY_FLAGS
|
enum PW_READY_FLAGS
|
||||||
{
|
{
|
||||||
PW_READY_FLAG_BUFFER_ADDED = 0x1,
|
PW_READY_FLAG_BUFFER_ADDED = 0x1,
|
||||||
@@ -55,6 +59,7 @@ static SDL_bool pipewire_initialized = SDL_FALSE;
|
|||||||
|
|
||||||
// Pipewire entry points
|
// Pipewire entry points
|
||||||
static const char *(*PIPEWIRE_pw_get_library_version)(void);
|
static const char *(*PIPEWIRE_pw_get_library_version)(void);
|
||||||
|
static bool (*PIPEWIRE_pw_check_library_version)(int major, int minor, int micro);
|
||||||
static void (*PIPEWIRE_pw_init)(int *, char ***);
|
static void (*PIPEWIRE_pw_init)(int *, char ***);
|
||||||
static void (*PIPEWIRE_pw_deinit)(void);
|
static void (*PIPEWIRE_pw_deinit)(void);
|
||||||
static struct pw_main_loop *(*PIPEWIRE_pw_main_loop_new)(struct pw_main_loop *loop);
|
static struct pw_main_loop *(*PIPEWIRE_pw_main_loop_new)(struct pw_main_loop *loop);
|
||||||
@@ -149,6 +154,7 @@ static void unload_pipewire_library(void)
|
|||||||
static int load_pipewire_syms(void)
|
static int load_pipewire_syms(void)
|
||||||
{
|
{
|
||||||
SDL_PIPEWIRE_SYM(pw_get_library_version);
|
SDL_PIPEWIRE_SYM(pw_get_library_version);
|
||||||
|
SDL_PIPEWIRE_SYM(pw_check_library_version);
|
||||||
SDL_PIPEWIRE_SYM(pw_init);
|
SDL_PIPEWIRE_SYM(pw_init);
|
||||||
SDL_PIPEWIRE_SYM(pw_deinit);
|
SDL_PIPEWIRE_SYM(pw_deinit);
|
||||||
SDL_PIPEWIRE_SYM(pw_main_loop_new);
|
SDL_PIPEWIRE_SYM(pw_main_loop_new);
|
||||||
@@ -190,107 +196,14 @@ static int load_pipewire_syms(void)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* When in a container, the library version can differ from the underlying core version,
|
static int init_pipewire_library(void)
|
||||||
* so make sure the underlying Pipewire implementation meets the version requirement.
|
|
||||||
*/
|
|
||||||
struct version_data
|
|
||||||
{
|
|
||||||
struct pw_main_loop *loop;
|
|
||||||
int major, minor, patch;
|
|
||||||
int seq;
|
|
||||||
};
|
|
||||||
|
|
||||||
static void version_check_core_info_callback(void *data, const struct pw_core_info *info)
|
|
||||||
{
|
|
||||||
struct version_data *v = data;
|
|
||||||
|
|
||||||
if (SDL_sscanf(info->version, "%d.%d.%d", &v->major, &v->minor, &v->patch) < 3) {
|
|
||||||
v->major = 0;
|
|
||||||
v->minor = 0;
|
|
||||||
v->patch = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void version_check_core_done_callback(void *data, uint32_t id, int seq)
|
|
||||||
{
|
|
||||||
struct version_data *v = data;
|
|
||||||
|
|
||||||
if (id == PW_ID_CORE && v->seq == seq) {
|
|
||||||
PIPEWIRE_pw_main_loop_quit(v->loop);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static const struct pw_core_events version_check_core_events =
|
|
||||||
{
|
|
||||||
.version = PW_VERSION_CORE_EVENTS,
|
|
||||||
.info = version_check_core_info_callback,
|
|
||||||
.done = version_check_core_done_callback
|
|
||||||
};
|
|
||||||
|
|
||||||
static SDL_bool pipewire_core_version_at_least(int major, int minor, int patch)
|
|
||||||
{
|
|
||||||
struct pw_main_loop *loop = NULL;
|
|
||||||
struct pw_context *context = NULL;
|
|
||||||
struct pw_core *core = NULL;
|
|
||||||
struct version_data version_data;
|
|
||||||
struct spa_hook core_listener;
|
|
||||||
SDL_bool ret = SDL_FALSE;
|
|
||||||
|
|
||||||
loop = PIPEWIRE_pw_main_loop_new(NULL);
|
|
||||||
if (!loop) {
|
|
||||||
goto done;
|
|
||||||
}
|
|
||||||
|
|
||||||
context = PIPEWIRE_pw_context_new(PIPEWIRE_pw_main_loop_get_loop(loop), NULL, 0);
|
|
||||||
if (!context) {
|
|
||||||
goto done;
|
|
||||||
}
|
|
||||||
|
|
||||||
core = PIPEWIRE_pw_context_connect(context, NULL, 0);
|
|
||||||
if (!core) {
|
|
||||||
goto done;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Attach a core listener and get the version. */
|
|
||||||
spa_zero(version_data);
|
|
||||||
version_data.loop = loop;
|
|
||||||
pw_core_add_listener(core, &core_listener, &version_check_core_events, &version_data);
|
|
||||||
version_data.seq = pw_core_sync(core, PW_ID_CORE, 0);
|
|
||||||
|
|
||||||
PIPEWIRE_pw_main_loop_run(loop);
|
|
||||||
|
|
||||||
spa_hook_remove(&core_listener);
|
|
||||||
|
|
||||||
ret = (version_data.major >= major) &&
|
|
||||||
(version_data.major > major || version_data.minor >= minor) &&
|
|
||||||
(version_data.major > major || version_data.minor > minor || version_data.patch >= patch);
|
|
||||||
|
|
||||||
done:
|
|
||||||
if (core) {
|
|
||||||
PIPEWIRE_pw_core_disconnect(core);
|
|
||||||
}
|
|
||||||
if (context) {
|
|
||||||
PIPEWIRE_pw_context_destroy(context);
|
|
||||||
}
|
|
||||||
if (loop) {
|
|
||||||
PIPEWIRE_pw_main_loop_destroy(loop);
|
|
||||||
}
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int init_pipewire_library(SDL_bool check_preferred_version)
|
|
||||||
{
|
{
|
||||||
if (!load_pipewire_library()) {
|
if (!load_pipewire_library()) {
|
||||||
if (!load_pipewire_syms()) {
|
if (!load_pipewire_syms()) {
|
||||||
PIPEWIRE_pw_init(NULL, NULL);
|
PIPEWIRE_pw_init(NULL, NULL);
|
||||||
|
return 0;
|
||||||
if (!check_preferred_version || pipewire_core_version_at_least(1, 0, 0)) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -309,6 +222,9 @@ static struct
|
|||||||
|
|
||||||
struct pw_core *core;
|
struct pw_core *core;
|
||||||
struct spa_hook core_listener;
|
struct spa_hook core_listener;
|
||||||
|
int server_major;
|
||||||
|
int server_minor;
|
||||||
|
int server_patch;
|
||||||
int last_seq;
|
int last_seq;
|
||||||
int pending_seq;
|
int pending_seq;
|
||||||
|
|
||||||
@@ -317,6 +233,7 @@ static struct
|
|||||||
|
|
||||||
struct spa_list global_list;
|
struct spa_list global_list;
|
||||||
|
|
||||||
|
SDL_bool have_1_0_5;
|
||||||
SDL_bool init_complete;
|
SDL_bool init_complete;
|
||||||
SDL_bool events_enabled;
|
SDL_bool events_enabled;
|
||||||
} hotplug;
|
} hotplug;
|
||||||
@@ -648,7 +565,11 @@ static int PIPEWIRECAMERA_AcquireFrame(SDL_CameraDevice *device, SDL_Surface *fr
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
*timestampNS = b->time;
|
#if PW_CHECK_VERSION(1,0,5)
|
||||||
|
*timestampNS = hotplug.have_1_0_5 ? b->time : SDL_GetTicksNS();
|
||||||
|
#else
|
||||||
|
*timestampNS = SDL_GetTicksNS();
|
||||||
|
#endif
|
||||||
frame->pixels = b->buffer->datas[0].data;
|
frame->pixels = b->buffer->datas[0].data;
|
||||||
frame->pitch = b->buffer->datas[0].chunk->stride;
|
frame->pitch = b->buffer->datas[0].chunk->stride;
|
||||||
|
|
||||||
@@ -777,8 +698,6 @@ static void add_device(struct global *g)
|
|||||||
|
|
||||||
SDL_zero(data);
|
SDL_zero(data);
|
||||||
|
|
||||||
SDL_Log("CAMERA: found %d", g->id);
|
|
||||||
|
|
||||||
spa_list_for_each(p, &g->param_list, link) {
|
spa_list_for_each(p, &g->param_list, link) {
|
||||||
if (p->id != SPA_PARAM_EnumFormat)
|
if (p->id != SPA_PARAM_EnumFormat)
|
||||||
continue;
|
continue;
|
||||||
@@ -989,6 +908,21 @@ static const struct pw_registry_events hotplug_registry_events =
|
|||||||
.global_remove = hotplug_registry_global_remove_callback
|
.global_remove = hotplug_registry_global_remove_callback
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static void parse_version(const char *str, int *major, int *minor, int *patch)
|
||||||
|
{
|
||||||
|
if (SDL_sscanf(str, "%d.%d.%d", major, minor, patch) < 3) {
|
||||||
|
*major = 0;
|
||||||
|
*minor = 0;
|
||||||
|
*patch = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Core info, called with thread_loop lock
|
||||||
|
static void hotplug_core_info_callback(void *data, const struct pw_core_info *info)
|
||||||
|
{
|
||||||
|
parse_version(info->version, &hotplug.server_major, &hotplug.server_minor, &hotplug.server_patch);
|
||||||
|
}
|
||||||
|
|
||||||
// Core sync points, called with thread_loop lock
|
// Core sync points, called with thread_loop lock
|
||||||
static void hotplug_core_done_callback(void *object, uint32_t id, int seq)
|
static void hotplug_core_done_callback(void *object, uint32_t id, int seq)
|
||||||
{
|
{
|
||||||
@@ -1015,9 +949,20 @@ static void hotplug_core_done_callback(void *object, uint32_t id, int seq)
|
|||||||
static const struct pw_core_events hotplug_core_events =
|
static const struct pw_core_events hotplug_core_events =
|
||||||
{
|
{
|
||||||
.version = PW_VERSION_CORE_EVENTS,
|
.version = PW_VERSION_CORE_EVENTS,
|
||||||
|
.info = hotplug_core_info_callback,
|
||||||
.done = hotplug_core_done_callback
|
.done = hotplug_core_done_callback
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/* When in a container, the library version can differ from the underlying core version,
|
||||||
|
* so make sure the underlying Pipewire implementation meets the version requirement.
|
||||||
|
*/
|
||||||
|
static SDL_bool pipewire_server_version_at_least(int major, int minor, int patch)
|
||||||
|
{
|
||||||
|
return (hotplug.server_major >= major) &&
|
||||||
|
(hotplug.server_major > major || hotplug.server_minor >= minor) &&
|
||||||
|
(hotplug.server_major > major || hotplug.server_minor > minor || hotplug.server_patch >= patch);
|
||||||
|
}
|
||||||
|
|
||||||
// The hotplug thread
|
// The hotplug thread
|
||||||
static int hotplug_loop_init(void)
|
static int hotplug_loop_init(void)
|
||||||
{
|
{
|
||||||
@@ -1025,6 +970,8 @@ static int hotplug_loop_init(void)
|
|||||||
|
|
||||||
spa_list_init(&hotplug.global_list);
|
spa_list_init(&hotplug.global_list);
|
||||||
|
|
||||||
|
hotplug.have_1_0_5 = PIPEWIRE_pw_check_library_version(1,0,5);
|
||||||
|
|
||||||
hotplug.loop = PIPEWIRE_pw_thread_loop_new("SDLAudioHotplug", NULL);
|
hotplug.loop = PIPEWIRE_pw_thread_loop_new("SDLAudioHotplug", NULL);
|
||||||
if (!hotplug.loop) {
|
if (!hotplug.loop) {
|
||||||
return SDL_SetError("Pipewire: Failed to create hotplug detection loop (%i)", errno);
|
return SDL_SetError("Pipewire: Failed to create hotplug detection loop (%i)", errno);
|
||||||
@@ -1050,13 +997,31 @@ static int hotplug_loop_init(void)
|
|||||||
spa_zero(hotplug.registry_listener);
|
spa_zero(hotplug.registry_listener);
|
||||||
pw_registry_add_listener(hotplug.registry, &hotplug.registry_listener, &hotplug_registry_events, NULL);
|
pw_registry_add_listener(hotplug.registry, &hotplug.registry_listener, &hotplug_registry_events, NULL);
|
||||||
|
|
||||||
hotplug.pending_seq = pw_core_sync(hotplug.core, PW_ID_CORE, 0);
|
do_resync();
|
||||||
|
|
||||||
res = PIPEWIRE_pw_thread_loop_start(hotplug.loop);
|
res = PIPEWIRE_pw_thread_loop_start(hotplug.loop);
|
||||||
if (res != 0) {
|
if (res != 0) {
|
||||||
return SDL_SetError("Pipewire: Failed to start hotplug detection loop");
|
return SDL_SetError("Pipewire: Failed to start hotplug detection loop");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
PIPEWIRE_pw_thread_loop_lock(hotplug.loop);
|
||||||
|
while (!hotplug.init_complete) {
|
||||||
|
PIPEWIRE_pw_thread_loop_wait(hotplug.loop);
|
||||||
|
}
|
||||||
|
PIPEWIRE_pw_thread_loop_unlock(hotplug.loop);
|
||||||
|
|
||||||
|
SDL_Log("CAMERA: PipeWire compiled:%s library:%s server:%d.%d.%d required:%d.%d.%d",
|
||||||
|
pw_get_headers_version(),
|
||||||
|
PIPEWIRE_pw_get_library_version(),
|
||||||
|
hotplug.server_major, hotplug.server_minor, hotplug.server_patch,
|
||||||
|
PW_REQUIRED_MAJOR, PW_REQUIRED_MINOR, PW_REQUIRED_PATCH);
|
||||||
|
|
||||||
|
if (!pipewire_server_version_at_least(PW_REQUIRED_MAJOR, PW_REQUIRED_MINOR, PW_REQUIRED_PATCH)) {
|
||||||
|
return SDL_SetError("Pipewire: server version is too old %d.%d.%d < %d.%d.%d",
|
||||||
|
hotplug.server_major, hotplug.server_minor, hotplug.server_patch,
|
||||||
|
PW_REQUIRED_MAJOR, PW_REQUIRED_MINOR, PW_REQUIRED_PATCH);
|
||||||
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1092,7 +1057,7 @@ static SDL_bool PIPEWIRECAMERA_Init(SDL_CameraDriverImpl *impl)
|
|||||||
{
|
{
|
||||||
if (!pipewire_initialized) {
|
if (!pipewire_initialized) {
|
||||||
|
|
||||||
if (init_pipewire_library(true) < 0) {
|
if (init_pipewire_library() < 0) {
|
||||||
return SDL_FALSE;
|
return SDL_FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user