diff options
Diffstat (limited to 'third_party/pipewire/spa/pod')
-rw-r--r-- | third_party/pipewire/spa/pod/builder.h | 696 | ||||
-rw-r--r-- | third_party/pipewire/spa/pod/command.h | 69 | ||||
-rw-r--r-- | third_party/pipewire/spa/pod/compare.h | 190 | ||||
-rw-r--r-- | third_party/pipewire/spa/pod/dynamic.h | 81 | ||||
-rw-r--r-- | third_party/pipewire/spa/pod/event.h | 68 | ||||
-rw-r--r-- | third_party/pipewire/spa/pod/filter.h | 422 | ||||
-rw-r--r-- | third_party/pipewire/spa/pod/iter.h | 475 | ||||
-rw-r--r-- | third_party/pipewire/spa/pod/parser.h | 583 | ||||
-rw-r--r-- | third_party/pipewire/spa/pod/pod.h | 246 | ||||
-rw-r--r-- | third_party/pipewire/spa/pod/vararg.h | 113 |
10 files changed, 2943 insertions, 0 deletions
diff --git a/third_party/pipewire/spa/pod/builder.h b/third_party/pipewire/spa/pod/builder.h new file mode 100644 index 0000000000..624b543c40 --- /dev/null +++ b/third_party/pipewire/spa/pod/builder.h @@ -0,0 +1,696 @@ +/* Simple Plugin API + * + * Copyright © 2018 Wim Taymans + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +#ifndef SPA_POD_BUILDER_H +#define SPA_POD_BUILDER_H + +#ifdef __cplusplus +extern "C" { +#endif + +/** \defgroup spa_pod POD + * Binary data serialization format + */ + +/** + * \addtogroup spa_pod + * \{ + */ + +#include <stdarg.h> + +#include <spa/utils/hook.h> +#include <spa/pod/iter.h> +#include <spa/pod/vararg.h> + +struct spa_pod_builder_state { + uint32_t offset; +#define SPA_POD_BUILDER_FLAG_BODY (1<<0) +#define SPA_POD_BUILDER_FLAG_FIRST (1<<1) + uint32_t flags; + struct spa_pod_frame *frame; +}; + +struct spa_pod_builder; + +struct spa_pod_builder_callbacks { +#define SPA_VERSION_POD_BUILDER_CALLBACKS 0 + uint32_t version; + + int (*overflow) (void *data, uint32_t size); +}; + +struct spa_pod_builder { + void *data; + uint32_t size; + uint32_t _padding; + struct spa_pod_builder_state state; + struct spa_callbacks callbacks; +}; + +#define SPA_POD_BUILDER_INIT(buffer,size) (struct spa_pod_builder){ buffer, size, 0, {}, {} } + +static inline void +spa_pod_builder_get_state(struct spa_pod_builder *builder, struct spa_pod_builder_state *state) +{ + *state = builder->state; +} + +static inline void +spa_pod_builder_set_callbacks(struct spa_pod_builder *builder, + const struct spa_pod_builder_callbacks *callbacks, void *data) +{ + builder->callbacks = SPA_CALLBACKS_INIT(callbacks, data); +} + +static inline void +spa_pod_builder_reset(struct spa_pod_builder *builder, struct spa_pod_builder_state *state) +{ + struct spa_pod_frame *f; + uint32_t size = builder->state.offset - state->offset; + builder->state = *state; + for (f = builder->state.frame; f ; f = f->parent) + f->pod.size -= size; +} + +static inline void spa_pod_builder_init(struct spa_pod_builder *builder, void *data, uint32_t size) +{ + *builder = SPA_POD_BUILDER_INIT(data, size); +} + +static inline struct spa_pod * +spa_pod_builder_deref(struct spa_pod_builder *builder, uint32_t offset) +{ + uint32_t size = builder->size; + if (offset + 8 <= size) { + struct spa_pod *pod = SPA_PTROFF(builder->data, offset, struct spa_pod); + if (offset + SPA_POD_SIZE(pod) <= size) + return pod; + } + return NULL; +} + +static inline struct spa_pod * +spa_pod_builder_frame(struct spa_pod_builder *builder, struct spa_pod_frame *frame) +{ + if (frame->offset + SPA_POD_SIZE(&frame->pod) <= builder->size) + return SPA_PTROFF(builder->data, frame->offset, struct spa_pod); + return NULL; +} + +static inline void +spa_pod_builder_push(struct spa_pod_builder *builder, + struct spa_pod_frame *frame, + const struct spa_pod *pod, + uint32_t offset) +{ + frame->pod = *pod; + frame->offset = offset; + frame->parent = builder->state.frame; + frame->flags = builder->state.flags; + builder->state.frame = frame; + + if (frame->pod.type == SPA_TYPE_Array || frame->pod.type == SPA_TYPE_Choice) + builder->state.flags = SPA_POD_BUILDER_FLAG_FIRST | SPA_POD_BUILDER_FLAG_BODY; +} + +static inline int spa_pod_builder_raw(struct spa_pod_builder *builder, const void *data, uint32_t size) +{ + int res = 0; + struct spa_pod_frame *f; + uint32_t offset = builder->state.offset; + + if (offset + size > builder->size) { + res = -ENOSPC; + spa_callbacks_call_res(&builder->callbacks, struct spa_pod_builder_callbacks, res, + overflow, 0, offset + size); + } + if (res == 0 && data) + memcpy(SPA_PTROFF(builder->data, offset, void), data, size); + + builder->state.offset += size; + + for (f = builder->state.frame; f ; f = f->parent) + f->pod.size += size; + + return res; +} + +static inline int spa_pod_builder_pad(struct spa_pod_builder *builder, uint32_t size) +{ + uint64_t zeroes = 0; + size = SPA_ROUND_UP_N(size, 8) - size; + return size ? spa_pod_builder_raw(builder, &zeroes, size) : 0; +} + +static inline int +spa_pod_builder_raw_padded(struct spa_pod_builder *builder, const void *data, uint32_t size) +{ + int r, res = spa_pod_builder_raw(builder, data, size); + if ((r = spa_pod_builder_pad(builder, size)) < 0) + res = r; + return res; +} + +static inline void *spa_pod_builder_pop(struct spa_pod_builder *builder, struct spa_pod_frame *frame) +{ + struct spa_pod *pod; + + if (SPA_FLAG_IS_SET(builder->state.flags, SPA_POD_BUILDER_FLAG_FIRST)) { + const struct spa_pod p = { 0, SPA_TYPE_None }; + spa_pod_builder_raw(builder, &p, sizeof(p)); + } + if ((pod = (struct spa_pod*)spa_pod_builder_frame(builder, frame)) != NULL) + *pod = frame->pod; + + builder->state.frame = frame->parent; + builder->state.flags = frame->flags; + spa_pod_builder_pad(builder, builder->state.offset); + return pod; +} + +static inline int +spa_pod_builder_primitive(struct spa_pod_builder *builder, const struct spa_pod *p) +{ + const void *data; + uint32_t size; + int r, res; + + if (builder->state.flags == SPA_POD_BUILDER_FLAG_BODY) { + data = SPA_POD_BODY_CONST(p); + size = SPA_POD_BODY_SIZE(p); + } else { + data = p; + size = SPA_POD_SIZE(p); + SPA_FLAG_CLEAR(builder->state.flags, SPA_POD_BUILDER_FLAG_FIRST); + } + res = spa_pod_builder_raw(builder, data, size); + if (builder->state.flags != SPA_POD_BUILDER_FLAG_BODY) + if ((r = spa_pod_builder_pad(builder, size)) < 0) + res = r; + return res; +} + +#define SPA_POD_INIT(size,type) (struct spa_pod) { size, type } + +#define SPA_POD_INIT_None() SPA_POD_INIT(0, SPA_TYPE_None) + +static inline int spa_pod_builder_none(struct spa_pod_builder *builder) +{ + const struct spa_pod p = SPA_POD_INIT_None(); + return spa_pod_builder_primitive(builder, &p); +} + +static inline int spa_pod_builder_child(struct spa_pod_builder *builder, uint32_t size, uint32_t type) +{ + const struct spa_pod p = SPA_POD_INIT(size,type); + SPA_FLAG_CLEAR(builder->state.flags, SPA_POD_BUILDER_FLAG_FIRST); + return spa_pod_builder_raw(builder, &p, sizeof(p)); +} + +#define SPA_POD_INIT_Bool(val) (struct spa_pod_bool){ { sizeof(uint32_t), SPA_TYPE_Bool }, val ? 1 : 0, 0 } + +static inline int spa_pod_builder_bool(struct spa_pod_builder *builder, bool val) +{ + const struct spa_pod_bool p = SPA_POD_INIT_Bool(val); + return spa_pod_builder_primitive(builder, &p.pod); +} + +#define SPA_POD_INIT_Id(val) (struct spa_pod_id){ { sizeof(uint32_t), SPA_TYPE_Id }, (uint32_t)val, 0 } + +static inline int spa_pod_builder_id(struct spa_pod_builder *builder, uint32_t val) +{ + const struct spa_pod_id p = SPA_POD_INIT_Id(val); + return spa_pod_builder_primitive(builder, &p.pod); +} + +#define SPA_POD_INIT_Int(val) (struct spa_pod_int){ { sizeof(int32_t), SPA_TYPE_Int }, (int32_t)val, 0 } + +static inline int spa_pod_builder_int(struct spa_pod_builder *builder, int32_t val) +{ + const struct spa_pod_int p = SPA_POD_INIT_Int(val); + return spa_pod_builder_primitive(builder, &p.pod); +} + +#define SPA_POD_INIT_Long(val) (struct spa_pod_long){ { sizeof(int64_t), SPA_TYPE_Long }, (int64_t)val } + +static inline int spa_pod_builder_long(struct spa_pod_builder *builder, int64_t val) +{ + const struct spa_pod_long p = SPA_POD_INIT_Long(val); + return spa_pod_builder_primitive(builder, &p.pod); +} + +#define SPA_POD_INIT_Float(val) (struct spa_pod_float){ { sizeof(float), SPA_TYPE_Float }, val, 0 } + +static inline int spa_pod_builder_float(struct spa_pod_builder *builder, float val) +{ + const struct spa_pod_float p = SPA_POD_INIT_Float(val); + return spa_pod_builder_primitive(builder, &p.pod); +} + +#define SPA_POD_INIT_Double(val) (struct spa_pod_double){ { sizeof(double), SPA_TYPE_Double }, val } + +static inline int spa_pod_builder_double(struct spa_pod_builder *builder, double val) +{ + const struct spa_pod_double p = SPA_POD_INIT_Double(val); + return spa_pod_builder_primitive(builder, &p.pod); +} + +#define SPA_POD_INIT_String(len) (struct spa_pod_string){ { len, SPA_TYPE_String } } + +static inline int +spa_pod_builder_write_string(struct spa_pod_builder *builder, const char *str, uint32_t len) +{ + int r, res; + res = spa_pod_builder_raw(builder, str, len); + if ((r = spa_pod_builder_raw(builder, "", 1)) < 0) + res = r; + if ((r = spa_pod_builder_pad(builder, builder->state.offset)) < 0) + res = r; + return res; +} + +static inline int +spa_pod_builder_string_len(struct spa_pod_builder *builder, const char *str, uint32_t len) +{ + const struct spa_pod_string p = SPA_POD_INIT_String(len+1); + int r, res = spa_pod_builder_raw(builder, &p, sizeof(p)); + if ((r = spa_pod_builder_write_string(builder, str, len)) < 0) + res = r; + return res; +} + +static inline int spa_pod_builder_string(struct spa_pod_builder *builder, const char *str) +{ + uint32_t len = str ? strlen(str) : 0; + return spa_pod_builder_string_len(builder, str ? str : "", len); +} + +#define SPA_POD_INIT_Bytes(len) (struct spa_pod_bytes){ { len, SPA_TYPE_Bytes } } + +static inline int +spa_pod_builder_bytes(struct spa_pod_builder *builder, const void *bytes, uint32_t len) +{ + const struct spa_pod_bytes p = SPA_POD_INIT_Bytes(len); + int r, res = spa_pod_builder_raw(builder, &p, sizeof(p)); + if ((r = spa_pod_builder_raw_padded(builder, bytes, len)) < 0) + res = r; + return res; +} +static inline void * +spa_pod_builder_reserve_bytes(struct spa_pod_builder *builder, uint32_t len) +{ + uint32_t offset = builder->state.offset; + if (spa_pod_builder_bytes(builder, NULL, len) < 0) + return NULL; + return SPA_POD_BODY(spa_pod_builder_deref(builder, offset)); +} + +#define SPA_POD_INIT_Pointer(type,value) (struct spa_pod_pointer){ { sizeof(struct spa_pod_pointer_body), SPA_TYPE_Pointer }, { type, 0, value } } + +static inline int +spa_pod_builder_pointer(struct spa_pod_builder *builder, uint32_t type, const void *val) +{ + const struct spa_pod_pointer p = SPA_POD_INIT_Pointer(type, val); + return spa_pod_builder_primitive(builder, &p.pod); +} + +#define SPA_POD_INIT_Fd(fd) (struct spa_pod_fd){ { sizeof(int64_t), SPA_TYPE_Fd }, fd } + +static inline int spa_pod_builder_fd(struct spa_pod_builder *builder, int64_t fd) +{ + const struct spa_pod_fd p = SPA_POD_INIT_Fd(fd); + return spa_pod_builder_primitive(builder, &p.pod); +} + +#define SPA_POD_INIT_Rectangle(val) (struct spa_pod_rectangle){ { sizeof(struct spa_rectangle), SPA_TYPE_Rectangle }, val } + +static inline int +spa_pod_builder_rectangle(struct spa_pod_builder *builder, uint32_t width, uint32_t height) +{ + const struct spa_pod_rectangle p = SPA_POD_INIT_Rectangle(SPA_RECTANGLE(width, height)); + return spa_pod_builder_primitive(builder, &p.pod); +} + +#define SPA_POD_INIT_Fraction(val) (struct spa_pod_fraction){ { sizeof(struct spa_fraction), SPA_TYPE_Fraction }, val } + +static inline int +spa_pod_builder_fraction(struct spa_pod_builder *builder, uint32_t num, uint32_t denom) +{ + const struct spa_pod_fraction p = SPA_POD_INIT_Fraction(SPA_FRACTION(num, denom)); + return spa_pod_builder_primitive(builder, &p.pod); +} + +static inline int +spa_pod_builder_push_array(struct spa_pod_builder *builder, struct spa_pod_frame *frame) +{ + const struct spa_pod_array p = + { {sizeof(struct spa_pod_array_body) - sizeof(struct spa_pod), SPA_TYPE_Array}, + {{0, 0}} }; + uint32_t offset = builder->state.offset; + int res = spa_pod_builder_raw(builder, &p, sizeof(p) - sizeof(struct spa_pod)); + spa_pod_builder_push(builder, frame, &p.pod, offset); + return res; +} + +static inline int +spa_pod_builder_array(struct spa_pod_builder *builder, + uint32_t child_size, uint32_t child_type, uint32_t n_elems, const void *elems) +{ + const struct spa_pod_array p = { + {(uint32_t)(sizeof(struct spa_pod_array_body) + n_elems * child_size), SPA_TYPE_Array}, + {{child_size, child_type}} + }; + int r, res = spa_pod_builder_raw(builder, &p, sizeof(p)); + if ((r = spa_pod_builder_raw_padded(builder, elems, child_size * n_elems)) < 0) + res = r; + return res; +} + +#define SPA_POD_INIT_CHOICE_BODY(type, flags, child_size, child_type) \ + (struct spa_pod_choice_body) { type, flags, { child_size, child_type }} + +#define SPA_POD_INIT_Choice(type, ctype, child_type, n_vals, ...) \ + (struct { struct spa_pod_choice choice; ctype vals[n_vals];}) \ + { { { n_vals * sizeof(ctype) + sizeof(struct spa_pod_choice_body), SPA_TYPE_Choice }, \ + { type, 0, { sizeof(ctype), child_type } } }, { __VA_ARGS__ } } + +static inline int +spa_pod_builder_push_choice(struct spa_pod_builder *builder, struct spa_pod_frame *frame, + uint32_t type, uint32_t flags) +{ + const struct spa_pod_choice p = + { {sizeof(struct spa_pod_choice_body) - sizeof(struct spa_pod), SPA_TYPE_Choice}, + { type, flags, {0, 0}} }; + uint32_t offset = builder->state.offset; + int res = spa_pod_builder_raw(builder, &p, sizeof(p) - sizeof(struct spa_pod)); + spa_pod_builder_push(builder, frame, &p.pod, offset); + return res; +} + +#define SPA_POD_INIT_Struct(size) (struct spa_pod_struct){ { size, SPA_TYPE_Struct } } + +static inline int +spa_pod_builder_push_struct(struct spa_pod_builder *builder, struct spa_pod_frame *frame) +{ + const struct spa_pod_struct p = SPA_POD_INIT_Struct(0); + uint32_t offset = builder->state.offset; + int res = spa_pod_builder_raw(builder, &p, sizeof(p)); + spa_pod_builder_push(builder, frame, &p.pod, offset); + return res; +} + +#define SPA_POD_INIT_Object(size,type,id,...) (struct spa_pod_object){ { size, SPA_TYPE_Object }, { type, id }, ##__VA_ARGS__ } + +static inline int +spa_pod_builder_push_object(struct spa_pod_builder *builder, struct spa_pod_frame *frame, + uint32_t type, uint32_t id) +{ + const struct spa_pod_object p = + SPA_POD_INIT_Object(sizeof(struct spa_pod_object_body), type, id); + uint32_t offset = builder->state.offset; + int res = spa_pod_builder_raw(builder, &p, sizeof(p)); + spa_pod_builder_push(builder, frame, &p.pod, offset); + return res; +} + +#define SPA_POD_INIT_Prop(key,flags,size,type) \ + (struct spa_pod_prop){ key, flags, { size, type } } + +static inline int +spa_pod_builder_prop(struct spa_pod_builder *builder, uint32_t key, uint32_t flags) +{ + const struct { uint32_t key; uint32_t flags; } p = { key, flags }; + return spa_pod_builder_raw(builder, &p, sizeof(p)); +} + +#define SPA_POD_INIT_Sequence(size,unit) \ + (struct spa_pod_sequence){ { size, SPA_TYPE_Sequence}, {unit, 0 } } + +static inline int +spa_pod_builder_push_sequence(struct spa_pod_builder *builder, struct spa_pod_frame *frame, uint32_t unit) +{ + const struct spa_pod_sequence p = + SPA_POD_INIT_Sequence(sizeof(struct spa_pod_sequence_body), unit); + uint32_t offset = builder->state.offset; + int res = spa_pod_builder_raw(builder, &p, sizeof(p)); + spa_pod_builder_push(builder, frame, &p.pod, offset); + return res; +} + +static inline uint32_t +spa_pod_builder_control(struct spa_pod_builder *builder, uint32_t offset, uint32_t type) +{ + const struct { uint32_t offset; uint32_t type; } p = { offset, type }; + return spa_pod_builder_raw(builder, &p, sizeof(p)); +} + +static inline uint32_t spa_choice_from_id(char id) +{ + switch (id) { + case 'r': + return SPA_CHOICE_Range; + case 's': + return SPA_CHOICE_Step; + case 'e': + return SPA_CHOICE_Enum; + case 'f': + return SPA_CHOICE_Flags; + case 'n': + default: + return SPA_CHOICE_None; + } +} + +#define SPA_POD_BUILDER_COLLECT(builder,type,args) \ +do { \ + switch (type) { \ + case 'b': \ + spa_pod_builder_bool(builder, !!va_arg(args, int)); \ + break; \ + case 'I': \ + spa_pod_builder_id(builder, va_arg(args, uint32_t)); \ + break; \ + case 'i': \ + spa_pod_builder_int(builder, va_arg(args, int)); \ + break; \ + case 'l': \ + spa_pod_builder_long(builder, va_arg(args, int64_t)); \ + break; \ + case 'f': \ + spa_pod_builder_float(builder, va_arg(args, double)); \ + break; \ + case 'd': \ + spa_pod_builder_double(builder, va_arg(args, double)); \ + break; \ + case 's': \ + { \ + char *strval = va_arg(args, char *); \ + if (strval != NULL) { \ + size_t len = strlen(strval); \ + spa_pod_builder_string_len(builder, strval, len); \ + } \ + else \ + spa_pod_builder_none(builder); \ + break; \ + } \ + case 'S': \ + { \ + char *strval = va_arg(args, char *); \ + size_t len = va_arg(args, int); \ + spa_pod_builder_string_len(builder, strval, len); \ + break; \ + } \ + case 'y': \ + { \ + void *ptr = va_arg(args, void *); \ + int len = va_arg(args, int); \ + spa_pod_builder_bytes(builder, ptr, len); \ + break; \ + } \ + case 'R': \ + { \ + struct spa_rectangle *rectval = \ + va_arg(args, struct spa_rectangle *); \ + spa_pod_builder_rectangle(builder, \ + rectval->width, rectval->height); \ + break; \ + } \ + case 'F': \ + { \ + struct spa_fraction *fracval = \ + va_arg(args, struct spa_fraction *); \ + spa_pod_builder_fraction(builder, fracval->num, fracval->denom);\ + break; \ + } \ + case 'a': \ + { \ + int child_size = va_arg(args, int); \ + int child_type = va_arg(args, int); \ + int n_elems = va_arg(args, int); \ + void *elems = va_arg(args, void *); \ + spa_pod_builder_array(builder, child_size, \ + child_type, n_elems, elems); \ + break; \ + } \ + case 'p': \ + { \ + int t = va_arg(args, uint32_t); \ + spa_pod_builder_pointer(builder, t, va_arg(args, void *)); \ + break; \ + } \ + case 'h': \ + spa_pod_builder_fd(builder, va_arg(args, int)); \ + break; \ + case 'P': \ + case 'O': \ + case 'T': \ + case 'V': \ + { \ + struct spa_pod *pod = va_arg(args, struct spa_pod *); \ + if (pod == NULL) \ + spa_pod_builder_none(builder); \ + else \ + spa_pod_builder_primitive(builder, pod); \ + break; \ + } \ + } \ +} while(false) + +static inline int +spa_pod_builder_addv(struct spa_pod_builder *builder, va_list args) +{ + int res = 0; + struct spa_pod_frame *frame = builder->state.frame; + uint32_t ftype = frame ? frame->pod.type : (uint32_t)SPA_TYPE_None; + + do { + const char *format; + int n_values = 1; + struct spa_pod_frame f; + bool choice; + + switch (ftype) { + case SPA_TYPE_Object: + { + uint32_t key = va_arg(args, uint32_t); + if (key == 0) + goto exit; + spa_pod_builder_prop(builder, key, 0); + break; + } + case SPA_TYPE_Sequence: + { + uint32_t offset = va_arg(args, uint32_t); + uint32_t type = va_arg(args, uint32_t); + if (type == 0) + goto exit; + spa_pod_builder_control(builder, offset, type); + SPA_FALLTHROUGH + } + default: + break; + } + if ((format = va_arg(args, const char *)) == NULL) + break; + + choice = *format == '?'; + if (choice) { + uint32_t type = spa_choice_from_id(*++format); + if (*format != '\0') + format++; + + spa_pod_builder_push_choice(builder, &f, type, 0); + + n_values = va_arg(args, int); + } + while (n_values-- > 0) + SPA_POD_BUILDER_COLLECT(builder, *format, args); + + if (choice) + spa_pod_builder_pop(builder, &f); + } while (true); + + exit: + return res; +} + +static inline int spa_pod_builder_add(struct spa_pod_builder *builder, ...) +{ + int res; + va_list args; + + va_start(args, builder); + res = spa_pod_builder_addv(builder, args); + va_end(args); + + return res; +} + +#define spa_pod_builder_add_object(b,type,id,...) \ +({ \ + struct spa_pod_frame _f; \ + spa_pod_builder_push_object(b, &_f, type, id); \ + spa_pod_builder_add(b, ##__VA_ARGS__, 0); \ + spa_pod_builder_pop(b, &_f); \ +}) + +#define spa_pod_builder_add_struct(b,...) \ +({ \ + struct spa_pod_frame _f; \ + spa_pod_builder_push_struct(b, &_f); \ + spa_pod_builder_add(b, ##__VA_ARGS__, NULL); \ + spa_pod_builder_pop(b, &_f); \ +}) + +#define spa_pod_builder_add_sequence(b,unit,...) \ +({ \ + struct spa_pod_frame _f; \ + spa_pod_builder_push_sequence(b, &_f, unit); \ + spa_pod_builder_add(b, ##__VA_ARGS__, 0, 0); \ + spa_pod_builder_pop(b, &_f); \ +}) + +/** Copy a pod structure */ +static inline struct spa_pod * +spa_pod_copy(const struct spa_pod *pod) +{ + size_t size; + struct spa_pod *c; + + size = SPA_POD_SIZE(pod); + if ((c = (struct spa_pod *) malloc(size)) == NULL) + return NULL; + return (struct spa_pod *) memcpy(c, pod, size); +} + +/** + * \} + */ + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /* SPA_POD_BUILDER_H */ diff --git a/third_party/pipewire/spa/pod/command.h b/third_party/pipewire/spa/pod/command.h new file mode 100644 index 0000000000..0c292eeae5 --- /dev/null +++ b/third_party/pipewire/spa/pod/command.h @@ -0,0 +1,69 @@ +/* Simple Plugin API + * + * Copyright © 2018 Wim Taymans + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +#ifndef SPA_COMMAND_H +#define SPA_COMMAND_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include <spa/utils/defs.h> +#include <spa/pod/pod.h> + +/** + * \addtogroup spa_pod + * \{ + */ + +struct spa_command_body { + struct spa_pod_object_body body; +}; + +struct spa_command { + struct spa_pod pod; + struct spa_command_body body; +}; + +#define SPA_COMMAND_TYPE(cmd) ((cmd)->body.body.type) +#define SPA_COMMAND_ID(cmd,type) (SPA_COMMAND_TYPE(cmd) == type ? \ + (cmd)->body.body.id : SPA_ID_INVALID) + +#define SPA_COMMAND_INIT_FULL(t,size,type,id,...) (t) \ + { { size, SPA_TYPE_Object }, \ + { { type, id }, ##__VA_ARGS__ } } \ + +#define SPA_COMMAND_INIT(type,id) \ + SPA_COMMAND_INIT_FULL(struct spa_command, \ + sizeof(struct spa_command_body), type, id) + +/** + * \} + */ + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /* SPA_COMMAND_H */ diff --git a/third_party/pipewire/spa/pod/compare.h b/third_party/pipewire/spa/pod/compare.h new file mode 100644 index 0000000000..3fd9d00a5b --- /dev/null +++ b/third_party/pipewire/spa/pod/compare.h @@ -0,0 +1,190 @@ +/* Simple Plugin API + * + * Copyright © 2018 Wim Taymans + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +#ifndef SPA_POD_COMPARE_H +#define SPA_POD_COMPARE_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include <stdarg.h> +#include <errno.h> +#include <stdint.h> +#include <stddef.h> +#include <stdio.h> +#include <string.h> + +#include <spa/param/props.h> +#include <spa/pod/iter.h> +#include <spa/pod/builder.h> + +/** + * \addtogroup spa_pod + * \{ + */ + +static inline int spa_pod_compare_value(uint32_t type, const void *r1, const void *r2, uint32_t size) +{ + switch (type) { + case SPA_TYPE_None: + return 0; + case SPA_TYPE_Bool: + case SPA_TYPE_Id: + return *(uint32_t *) r1 == *(uint32_t *) r2 ? 0 : 1; + case SPA_TYPE_Int: + return *(int32_t *) r1 - *(int32_t *) r2; + case SPA_TYPE_Long: + return *(int64_t *) r1 - *(int64_t *) r2; + case SPA_TYPE_Float: + return *(float *) r1 - *(float *) r2; + case SPA_TYPE_Double: + return *(double *) r1 - *(double *) r2; + case SPA_TYPE_String: + return strcmp((char *)r1, (char *)r2); + case SPA_TYPE_Bytes: + return memcmp((char *)r1, (char *)r2, size); + case SPA_TYPE_Rectangle: + { + const struct spa_rectangle *rec1 = (struct spa_rectangle *) r1, + *rec2 = (struct spa_rectangle *) r2; + if (rec1->width == rec2->width && rec1->height == rec2->height) + return 0; + else if (rec1->width < rec2->width || rec1->height < rec2->height) + return -1; + else + return 1; + } + case SPA_TYPE_Fraction: + { + const struct spa_fraction *f1 = (struct spa_fraction *) r1, + *f2 = (struct spa_fraction *) r2; + int64_t n1, n2; + n1 = ((int64_t) f1->num) * f2->denom; + n2 = ((int64_t) f2->num) * f1->denom; + if (n1 < n2) + return -1; + else if (n1 > n2) + return 1; + else + return 0; + } + default: + break; + } + return 0; +} + +static inline int spa_pod_compare(const struct spa_pod *pod1, + const struct spa_pod *pod2) +{ + int res = 0; + uint32_t n_vals1, n_vals2; + uint32_t choice1, choice2; + + spa_return_val_if_fail(pod1 != NULL, -EINVAL); + spa_return_val_if_fail(pod2 != NULL, -EINVAL); + + pod1 = spa_pod_get_values(pod1, &n_vals1, &choice1); + pod2 = spa_pod_get_values(pod2, &n_vals2, &choice2); + + if (n_vals1 != n_vals2) + return -EINVAL; + + if (SPA_POD_TYPE(pod1) != SPA_POD_TYPE(pod2)) + return -EINVAL; + + switch (SPA_POD_TYPE(pod1)) { + case SPA_TYPE_Struct: + { + const struct spa_pod *p1, *p2; + size_t p1s, p2s; + + p1 = (const struct spa_pod*)SPA_POD_BODY_CONST(pod1); + p1s = SPA_POD_BODY_SIZE(pod1); + p2 = (const struct spa_pod*)SPA_POD_BODY_CONST(pod2); + p2s = SPA_POD_BODY_SIZE(pod2); + + while (true) { + if (!spa_pod_is_inside(pod1, p1s, p1) || + !spa_pod_is_inside(pod2, p2s, p2)) + return -EINVAL; + + if ((res = spa_pod_compare(p1, p2)) != 0) + return res; + + p1 = (const struct spa_pod*)spa_pod_next(p1); + p2 = (const struct spa_pod*)spa_pod_next(p2); + } + break; + } + case SPA_TYPE_Object: + { + const struct spa_pod_prop *p1, *p2; + const struct spa_pod_object *o1, *o2; + + o1 = (const struct spa_pod_object*)pod1; + o2 = (const struct spa_pod_object*)pod2; + + p2 = NULL; + SPA_POD_OBJECT_FOREACH(o1, p1) { + if ((p2 = spa_pod_object_find_prop(o2, p2, p1->key)) == NULL) + return 1; + if ((res = spa_pod_compare(&p1->value, &p2->value)) != 0) + return res; + } + p1 = NULL; + SPA_POD_OBJECT_FOREACH(o2, p2) { + if ((p1 = spa_pod_object_find_prop(o1, p1, p2->key)) == NULL) + return -1; + } + break; + } + case SPA_TYPE_Array: + { + if (SPA_POD_BODY_SIZE(pod1) != SPA_POD_BODY_SIZE(pod2)) + return -EINVAL; + res = memcmp(SPA_POD_BODY(pod1), SPA_POD_BODY(pod2), SPA_POD_BODY_SIZE(pod2)); + break; + } + default: + if (SPA_POD_BODY_SIZE(pod1) != SPA_POD_BODY_SIZE(pod2)) + return -EINVAL; + res = spa_pod_compare_value(SPA_POD_TYPE(pod1), + SPA_POD_BODY(pod1), SPA_POD_BODY(pod2), + SPA_POD_BODY_SIZE(pod1)); + break; + } + return res; +} + +/** + * \} + */ + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/third_party/pipewire/spa/pod/dynamic.h b/third_party/pipewire/spa/pod/dynamic.h new file mode 100644 index 0000000000..1fe77beecd --- /dev/null +++ b/third_party/pipewire/spa/pod/dynamic.h @@ -0,0 +1,81 @@ +/* Simple Plugin API + * + * Copyright © 2018 Wim Taymans + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +#ifndef SPA_POD_DYNAMIC_H +#define SPA_POD_DYNAMIC_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include <spa/pod/builder.h> + +struct spa_pod_dynamic_builder { + struct spa_pod_builder b; + void *data; + uint32_t extend; + uint32_t _padding; +}; + +static int spa_pod_dynamic_builder_overflow(void *data, uint32_t size) +{ + struct spa_pod_dynamic_builder *d = (struct spa_pod_dynamic_builder*)data; + int32_t old_size = d->b.size; + int32_t new_size = SPA_ROUND_UP_N(size, d->extend); + void *old_data = d->b.data; + + if (old_data == d->data) + d->b.data = NULL; + if ((d->b.data = realloc(d->b.data, new_size)) == NULL) + return -errno; + if (old_data == d->data && d->b.data != old_data && old_size > 0) + memcpy(d->b.data, old_data, old_size); + d->b.size = new_size; + return 0; +} + +static inline void spa_pod_dynamic_builder_init(struct spa_pod_dynamic_builder *builder, + void *data, uint32_t size, uint32_t extend) +{ + static const struct spa_pod_builder_callbacks spa_pod_dynamic_builder_callbacks = { + SPA_VERSION_POD_BUILDER_CALLBACKS, + .overflow = spa_pod_dynamic_builder_overflow + }; + builder->b = SPA_POD_BUILDER_INIT(data, size); + spa_pod_builder_set_callbacks(&builder->b, &spa_pod_dynamic_builder_callbacks, builder); + builder->extend = extend; + builder->data = data; +} + +static inline void spa_pod_dynamic_builder_clean(struct spa_pod_dynamic_builder *builder) +{ + if (builder->data != builder->b.data) + free(builder->b.data); +} + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /* SPA_POD_DYNAMIC_H */ diff --git a/third_party/pipewire/spa/pod/event.h b/third_party/pipewire/spa/pod/event.h new file mode 100644 index 0000000000..2ecfb0eabb --- /dev/null +++ b/third_party/pipewire/spa/pod/event.h @@ -0,0 +1,68 @@ +/* Simple Plugin API + * + * Copyright © 2018 Wim Taymans + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +#ifndef SPA_EVENT_H +#define SPA_EVENT_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include <spa/pod/pod.h> + +/** + * \addtogroup spa_pod + * \{ + */ + +struct spa_event_body { + struct spa_pod_object_body body; +}; + +struct spa_event { + struct spa_pod pod; + struct spa_event_body body; +}; + +#define SPA_EVENT_TYPE(ev) ((ev)->body.body.type) +#define SPA_EVENT_ID(ev,type) (SPA_EVENT_TYPE(ev) == type ? \ + (ev)->body.body.id : SPA_ID_INVALID) + +#define SPA_EVENT_INIT_FULL(t,size,type,id,...) (t) \ + { { size, SPA_TYPE_OBJECT }, \ + { { type, id }, ##__VA_ARGS__ } } \ + +#define SPA_EVENT_INIT(type,id) \ + SPA_EVENT_INIT_FULL(struct spa_event, \ + sizeof(struct spa_event_body), type, id) + +/** + * \} + */ + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /* SPA_EVENT_H */ diff --git a/third_party/pipewire/spa/pod/filter.h b/third_party/pipewire/spa/pod/filter.h new file mode 100644 index 0000000000..944b4cc64f --- /dev/null +++ b/third_party/pipewire/spa/pod/filter.h @@ -0,0 +1,422 @@ +/* Simple Plugin API + * + * Copyright © 2018 Wim Taymans + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +#ifndef SPA_POD_FILTER_H +#define SPA_POD_FILTER_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include <errno.h> +#include <stdint.h> +#include <stddef.h> +#include <stdio.h> +#include <string.h> + +#include <spa/param/props.h> +#include <spa/pod/iter.h> +#include <spa/pod/builder.h> +#include <spa/pod/compare.h> + +/** + * \addtogroup spa_pod + * \{ + */ + +static inline int spa_pod_choice_fix_default(struct spa_pod_choice *choice) +{ + void *val, *alt; + int i, nvals; + uint32_t type, size; + + nvals = SPA_POD_CHOICE_N_VALUES(choice); + type = SPA_POD_CHOICE_VALUE_TYPE(choice); + size = SPA_POD_CHOICE_VALUE_SIZE(choice); + alt = val = SPA_POD_CHOICE_VALUES(choice); + + switch (choice->body.type) { + case SPA_CHOICE_None: + break; + case SPA_CHOICE_Range: + case SPA_CHOICE_Step: + if (nvals > 1) { + alt = SPA_PTROFF(alt, size, void); + if (spa_pod_compare_value(type, val, alt, size) < 0) + memcpy(val, alt, size); + } + if (nvals > 2) { + alt = SPA_PTROFF(alt, size, void); + if (spa_pod_compare_value(type, val, alt, size) > 0) + memcpy(val, alt, size); + } + break; + case SPA_CHOICE_Flags: + case SPA_CHOICE_Enum: + { + void *best = NULL; + + for (i = 1; i < nvals; i++) { + alt = SPA_PTROFF(alt, size, void); + if (spa_pod_compare_value(type, val, alt, size) == 0) { + best = alt; + break; + } + if (best == NULL) + best = alt; + } + if (best) + memcpy(val, best, size); + + if (nvals <= 1) + choice->body.type = SPA_CHOICE_None; + break; + } + } + return 0; +} + +static inline int spa_pod_filter_flags_value(struct spa_pod_builder *b, + uint32_t type, const void *r1, const void *r2, uint32_t size) +{ + switch (type) { + case SPA_TYPE_Int: + { + int32_t val = (*(int32_t *) r1) & (*(int32_t *) r2); + if (val == 0) + return 0; + spa_pod_builder_int(b, val); + break; + } + case SPA_TYPE_Long: + { + int64_t val = (*(int64_t *) r1) & (*(int64_t *) r2); + if (val == 0) + return 0; + spa_pod_builder_long(b, val); + break; + } + default: + return -ENOTSUP; + } + return 1; +} + + +static inline int +spa_pod_filter_prop(struct spa_pod_builder *b, + const struct spa_pod_prop *p1, + const struct spa_pod_prop *p2) +{ + const struct spa_pod *v1, *v2; + struct spa_pod_choice *nc; + uint32_t j, k, nalt1, nalt2; + void *alt1, *alt2, *a1, *a2; + uint32_t type, size, p1c, p2c; + struct spa_pod_frame f; + + v1 = spa_pod_get_values(&p1->value, &nalt1, &p1c); + alt1 = SPA_POD_BODY(v1); + v2 = spa_pod_get_values(&p2->value, &nalt2, &p2c); + alt2 = SPA_POD_BODY(v2); + + type = v1->type; + size = v1->size; + + /* incompatible property types */ + if (type != v2->type || size != v2->size || p1->key != p2->key) + return -EINVAL; + + if (p1c == SPA_CHOICE_None || p1c == SPA_CHOICE_Flags) { + nalt1 = 1; + } else { + alt1 = SPA_PTROFF(alt1, size, void); + nalt1--; + } + + if (p2c == SPA_CHOICE_None || p2c == SPA_CHOICE_Flags) { + nalt2 = 1; + } else { + alt2 = SPA_PTROFF(alt2, size, void); + nalt2--; + } + + /* start with copying the property */ + spa_pod_builder_prop(b, p1->key, p1->flags & p2->flags); + spa_pod_builder_push_choice(b, &f, 0, 0); + nc = (struct spa_pod_choice*)spa_pod_builder_frame(b, &f); + + /* default value */ + spa_pod_builder_primitive(b, v1); + + if ((p1c == SPA_CHOICE_None && p2c == SPA_CHOICE_None) || + (p1c == SPA_CHOICE_None && p2c == SPA_CHOICE_Enum) || + (p1c == SPA_CHOICE_Enum && p2c == SPA_CHOICE_None) || + (p1c == SPA_CHOICE_Enum && p2c == SPA_CHOICE_Enum)) { + int n_copied = 0; + /* copy all equal values but don't copy the default value again */ + for (j = 0, a1 = alt1; j < nalt1; j++, a1 = SPA_PTROFF(a1, size, void)) { + for (k = 0, a2 = alt2; k < nalt2; k++, a2 = SPA_PTROFF(a2,size,void)) { + if (spa_pod_compare_value(type, a1, a2, size) == 0) { + if (p1c == SPA_CHOICE_Enum || j > 0) + spa_pod_builder_raw(b, a1, size); + n_copied++; + } + } + } + if (n_copied == 0) + return -EINVAL; + nc->body.type = SPA_CHOICE_Enum; + } + + if ((p1c == SPA_CHOICE_None && p2c == SPA_CHOICE_Range) || + (p1c == SPA_CHOICE_Enum && p2c == SPA_CHOICE_Range)) { + int n_copied = 0; + /* copy all values inside the range */ + for (j = 0, a1 = alt1, a2 = alt2; j < nalt1; j++, a1 = SPA_PTROFF(a1,size,void)) { + if (spa_pod_compare_value(type, a1, a2, size) < 0) + continue; + if (spa_pod_compare_value(type, a1, SPA_PTROFF(a2,size,void), size) > 0) + continue; + spa_pod_builder_raw(b, a1, size); + n_copied++; + } + if (n_copied == 0) + return -EINVAL; + nc->body.type = SPA_CHOICE_Enum; + } + + if ((p1c == SPA_CHOICE_None && p2c == SPA_CHOICE_Step) || + (p1c == SPA_CHOICE_Enum && p2c == SPA_CHOICE_Step)) { + return -ENOTSUP; + } + + if ((p1c == SPA_CHOICE_Range && p2c == SPA_CHOICE_None) || + (p1c == SPA_CHOICE_Range && p2c == SPA_CHOICE_Enum)) { + int n_copied = 0; + /* copy all values inside the range */ + for (k = 0, a1 = alt1, a2 = alt2; k < nalt2; k++, a2 = SPA_PTROFF(a2,size,void)) { + if (spa_pod_compare_value(type, a2, a1, size) < 0) + continue; + if (spa_pod_compare_value(type, a2, SPA_PTROFF(a1,size,void), size) > 0) + continue; + spa_pod_builder_raw(b, a2, size); + n_copied++; + } + if (n_copied == 0) + return -EINVAL; + nc->body.type = SPA_CHOICE_Enum; + } + + if ((p1c == SPA_CHOICE_Range && p2c == SPA_CHOICE_Range) || + (p1c == SPA_CHOICE_Range && p2c == SPA_CHOICE_Step) || + (p1c == SPA_CHOICE_Step && p2c == SPA_CHOICE_Range) || + (p1c == SPA_CHOICE_Step && p2c == SPA_CHOICE_Step)) { + if (spa_pod_compare_value(type, alt1, alt2, size) < 0) + spa_pod_builder_raw(b, alt2, size); + else + spa_pod_builder_raw(b, alt1, size); + + alt1 = SPA_PTROFF(alt1,size,void); + alt2 = SPA_PTROFF(alt2,size,void); + + if (spa_pod_compare_value(type, alt1, alt2, size) < 0) + spa_pod_builder_raw(b, alt1, size); + else + spa_pod_builder_raw(b, alt2, size); + + nc->body.type = SPA_CHOICE_Range; + } + + if ((p1c == SPA_CHOICE_None && p2c == SPA_CHOICE_Flags) || + (p1c == SPA_CHOICE_Flags && p2c == SPA_CHOICE_None) || + (p1c == SPA_CHOICE_Flags && p2c == SPA_CHOICE_Flags)) { + if (spa_pod_filter_flags_value(b, type, alt1, alt2, size) != 1) + return -EINVAL; + nc->body.type = SPA_CHOICE_Flags; + } + + if (p1c == SPA_CHOICE_Range && p2c == SPA_CHOICE_Flags) + return -ENOTSUP; + + if (p1c == SPA_CHOICE_Enum && p2c == SPA_CHOICE_Flags) + return -ENOTSUP; + + if (p1c == SPA_CHOICE_Step && p2c == SPA_CHOICE_None) + return -ENOTSUP; + if (p1c == SPA_CHOICE_Step && p2c == SPA_CHOICE_Enum) + return -ENOTSUP; + if (p1c == SPA_CHOICE_Step && p2c == SPA_CHOICE_Flags) + return -ENOTSUP; + + if (p1c == SPA_CHOICE_Flags && p2c == SPA_CHOICE_Range) + return -ENOTSUP; + if (p1c == SPA_CHOICE_Flags && p2c == SPA_CHOICE_Step) + return -ENOTSUP; + if (p1c == SPA_CHOICE_Flags && p2c == SPA_CHOICE_Enum) + return -ENOTSUP; + + spa_pod_builder_pop(b, &f); + spa_pod_choice_fix_default(nc); + + return 0; +} + +static inline int spa_pod_filter_part(struct spa_pod_builder *b, + const struct spa_pod *pod, uint32_t pod_size, + const struct spa_pod *filter, uint32_t filter_size) +{ + const struct spa_pod *pp, *pf; + int res = 0; + + pf = filter; + + SPA_POD_FOREACH(pod, pod_size, pp) { + bool do_copy = false, do_advance = false; + uint32_t filter_offset = 0; + struct spa_pod_frame f; + + switch (SPA_POD_TYPE(pp)) { + case SPA_TYPE_Object: + if (pf != NULL) { + struct spa_pod_object *op = (struct spa_pod_object *) pp; + struct spa_pod_object *of = (struct spa_pod_object *) pf; + const struct spa_pod_prop *p1, *p2; + + if (SPA_POD_TYPE(pf) != SPA_POD_TYPE(pp)) + return -EINVAL; + + spa_pod_builder_push_object(b, &f, op->body.type, op->body.id); + p2 = NULL; + SPA_POD_OBJECT_FOREACH(op, p1) { + p2 = spa_pod_object_find_prop(of, p2, p1->key); + if (p2 != NULL) + res = spa_pod_filter_prop(b, p1, p2); + else if ((p1->flags & SPA_POD_PROP_FLAG_MANDATORY) != 0) + res = -EINVAL; + else + spa_pod_builder_raw_padded(b, p1, SPA_POD_PROP_SIZE(p1)); + if (res < 0) + break; + } + if (res >= 0) { + p1 = NULL; + SPA_POD_OBJECT_FOREACH(of, p2) { + p1 = spa_pod_object_find_prop(op, p1, p2->key); + if (p1 != NULL) + continue; + if ((p2->flags & SPA_POD_PROP_FLAG_MANDATORY) != 0) + res = -EINVAL; + if (res < 0) + break; + spa_pod_builder_raw_padded(b, p2, SPA_POD_PROP_SIZE(p2)); + } + } + spa_pod_builder_pop(b, &f); + do_advance = true; + } + else + do_copy = true; + break; + + case SPA_TYPE_Struct: + if (pf != NULL) { + if (SPA_POD_TYPE(pf) != SPA_POD_TYPE(pp)) + return -EINVAL; + + filter_offset = sizeof(struct spa_pod_struct); + spa_pod_builder_push_struct(b, &f); + res = spa_pod_filter_part(b, + SPA_PTROFF(pp,filter_offset,const struct spa_pod), + SPA_POD_SIZE(pp) - filter_offset, + SPA_PTROFF(pf,filter_offset,const struct spa_pod), + SPA_POD_SIZE(pf) - filter_offset); + spa_pod_builder_pop(b, &f); + do_advance = true; + } + else + do_copy = true; + break; + + default: + if (pf != NULL) { + if (SPA_POD_SIZE(pp) != SPA_POD_SIZE(pf)) + return -EINVAL; + if (memcmp(pp, pf, SPA_POD_SIZE(pp)) != 0) + return -EINVAL; + do_advance = true; + } + do_copy = true; + break; + } + if (do_copy) + spa_pod_builder_raw_padded(b, pp, SPA_POD_SIZE(pp)); + if (do_advance) { + pf = (const struct spa_pod*)spa_pod_next(pf); + if (!spa_pod_is_inside(filter, filter_size, pf)) + pf = NULL; + } + if (res < 0) + break; + } + return res; +} + +static inline int +spa_pod_filter(struct spa_pod_builder *b, + struct spa_pod **result, + const struct spa_pod *pod, + const struct spa_pod *filter) +{ + int res; + struct spa_pod_builder_state state; + + spa_return_val_if_fail(pod != NULL, -EINVAL); + spa_return_val_if_fail(b != NULL, -EINVAL); + + spa_pod_builder_get_state(b, &state); + if (filter == NULL) + res = spa_pod_builder_raw_padded(b, pod, SPA_POD_SIZE(pod)); + else + res = spa_pod_filter_part(b, pod, SPA_POD_SIZE(pod), filter, SPA_POD_SIZE(filter)); + + if (res < 0) { + spa_pod_builder_reset(b, &state); + } else if (result) { + *result = (struct spa_pod*)spa_pod_builder_deref(b, state.offset); + if (*result == NULL) + res = -ENOSPC; + } + return res; +} + +/** + * \} + */ + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /* SPA_POD_FILTER_H */ diff --git a/third_party/pipewire/spa/pod/iter.h b/third_party/pipewire/spa/pod/iter.h new file mode 100644 index 0000000000..d3dcf139de --- /dev/null +++ b/third_party/pipewire/spa/pod/iter.h @@ -0,0 +1,475 @@ +/* Simple Plugin API + * + * Copyright © 2018 Wim Taymans + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +#ifndef SPA_POD_ITER_H +#define SPA_POD_ITER_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include <errno.h> +#include <sys/types.h> + +#include <spa/pod/pod.h> + +/** + * \addtogroup spa_pod + * \{ + */ + +struct spa_pod_frame { + struct spa_pod pod; + struct spa_pod_frame *parent; + uint32_t offset; + uint32_t flags; +}; + +static inline bool spa_pod_is_inside(const void *pod, uint32_t size, const void *iter) +{ + return SPA_POD_BODY(iter) <= SPA_PTROFF(pod, size, void) && + SPA_PTROFF(iter, SPA_POD_SIZE(iter), void) <= SPA_PTROFF(pod, size, void); +} + +static inline void *spa_pod_next(const void *iter) +{ + return SPA_PTROFF(iter, SPA_ROUND_UP_N(SPA_POD_SIZE(iter), 8), void); +} + +static inline struct spa_pod_prop *spa_pod_prop_first(const struct spa_pod_object_body *body) +{ + return SPA_PTROFF(body, sizeof(struct spa_pod_object_body), struct spa_pod_prop); +} + +static inline bool spa_pod_prop_is_inside(const struct spa_pod_object_body *body, + uint32_t size, const struct spa_pod_prop *iter) +{ + return SPA_POD_CONTENTS(struct spa_pod_prop, iter) <= SPA_PTROFF(body, size, void) && + SPA_PTROFF(iter, SPA_POD_PROP_SIZE(iter), void) <= SPA_PTROFF(body, size, void); +} + +static inline struct spa_pod_prop *spa_pod_prop_next(const struct spa_pod_prop *iter) +{ + return SPA_PTROFF(iter, SPA_ROUND_UP_N(SPA_POD_PROP_SIZE(iter), 8), struct spa_pod_prop); +} + +static inline struct spa_pod_control *spa_pod_control_first(const struct spa_pod_sequence_body *body) +{ + return SPA_PTROFF(body, sizeof(struct spa_pod_sequence_body), struct spa_pod_control); +} + +static inline bool spa_pod_control_is_inside(const struct spa_pod_sequence_body *body, + uint32_t size, const struct spa_pod_control *iter) +{ + return SPA_POD_CONTENTS(struct spa_pod_control, iter) <= SPA_PTROFF(body, size, void) && + SPA_PTROFF(iter, SPA_POD_CONTROL_SIZE(iter), void) <= SPA_PTROFF(body, size, void); +} + +static inline struct spa_pod_control *spa_pod_control_next(const struct spa_pod_control *iter) +{ + return SPA_PTROFF(iter, SPA_ROUND_UP_N(SPA_POD_CONTROL_SIZE(iter), 8), struct spa_pod_control); +} + +#define SPA_POD_ARRAY_BODY_FOREACH(body, _size, iter) \ + for ((iter) = (__typeof__(iter))SPA_PTROFF((body), sizeof(struct spa_pod_array_body), void); \ + (iter) < (__typeof__(iter))SPA_PTROFF((body), (_size), void); \ + (iter) = (__typeof__(iter))SPA_PTROFF((iter), (body)->child.size, void)) + +#define SPA_POD_ARRAY_FOREACH(obj, iter) \ + SPA_POD_ARRAY_BODY_FOREACH(&(obj)->body, SPA_POD_BODY_SIZE(obj), iter) + +#define SPA_POD_CHOICE_BODY_FOREACH(body, _size, iter) \ + for ((iter) = (__typeof__(iter))SPA_PTROFF((body), sizeof(struct spa_pod_choice_body), void); \ + (iter) < (__typeof__(iter))SPA_PTROFF((body), (_size), void); \ + (iter) = (__typeof__(iter))SPA_PTROFF((iter), (body)->child.size, void)) + +#define SPA_POD_CHOICE_FOREACH(obj, iter) \ + SPA_POD_CHOICE_BODY_FOREACH(&(obj)->body, SPA_POD_BODY_SIZE(obj), iter) + +#define SPA_POD_FOREACH(pod, size, iter) \ + for ((iter) = (pod); \ + spa_pod_is_inside(pod, size, iter); \ + (iter) = (__typeof__(iter))spa_pod_next(iter)) + +#define SPA_POD_STRUCT_FOREACH(obj, iter) \ + SPA_POD_FOREACH(SPA_POD_BODY(obj), SPA_POD_BODY_SIZE(obj), iter) + +#define SPA_POD_OBJECT_BODY_FOREACH(body, size, iter) \ + for ((iter) = spa_pod_prop_first(body); \ + spa_pod_prop_is_inside(body, size, iter); \ + (iter) = spa_pod_prop_next(iter)) + +#define SPA_POD_OBJECT_FOREACH(obj, iter) \ + SPA_POD_OBJECT_BODY_FOREACH(&(obj)->body, SPA_POD_BODY_SIZE(obj), iter) + +#define SPA_POD_SEQUENCE_BODY_FOREACH(body, size, iter) \ + for ((iter) = spa_pod_control_first(body); \ + spa_pod_control_is_inside(body, size, iter); \ + (iter) = spa_pod_control_next(iter)) + +#define SPA_POD_SEQUENCE_FOREACH(seq, iter) \ + SPA_POD_SEQUENCE_BODY_FOREACH(&(seq)->body, SPA_POD_BODY_SIZE(seq), iter) + + +static inline void *spa_pod_from_data(void *data, size_t maxsize, off_t offset, size_t size) +{ + void *pod; + if (size < sizeof(struct spa_pod) || offset + size > maxsize) + return NULL; + pod = SPA_PTROFF(data, offset, void); + if (SPA_POD_SIZE(pod) > size) + return NULL; + return pod; +} + +static inline int spa_pod_is_none(const struct spa_pod *pod) +{ + return (SPA_POD_TYPE(pod) == SPA_TYPE_None); +} + +static inline int spa_pod_is_bool(const struct spa_pod *pod) +{ + return (SPA_POD_TYPE(pod) == SPA_TYPE_Bool && SPA_POD_BODY_SIZE(pod) >= sizeof(int32_t)); +} + +static inline int spa_pod_get_bool(const struct spa_pod *pod, bool *value) +{ + if (!spa_pod_is_bool(pod)) + return -EINVAL; + *value = !!SPA_POD_VALUE(struct spa_pod_bool, pod); + return 0; +} + +static inline int spa_pod_is_id(const struct spa_pod *pod) +{ + return (SPA_POD_TYPE(pod) == SPA_TYPE_Id && SPA_POD_BODY_SIZE(pod) >= sizeof(uint32_t)); +} + +static inline int spa_pod_get_id(const struct spa_pod *pod, uint32_t *value) +{ + if (!spa_pod_is_id(pod)) + return -EINVAL; + *value = SPA_POD_VALUE(struct spa_pod_id, pod); + return 0; +} + +static inline int spa_pod_is_int(const struct spa_pod *pod) +{ + return (SPA_POD_TYPE(pod) == SPA_TYPE_Int && SPA_POD_BODY_SIZE(pod) >= sizeof(int32_t)); +} + +static inline int spa_pod_get_int(const struct spa_pod *pod, int32_t *value) +{ + if (!spa_pod_is_int(pod)) + return -EINVAL; + *value = SPA_POD_VALUE(struct spa_pod_int, pod); + return 0; +} + +static inline int spa_pod_is_long(const struct spa_pod *pod) +{ + return (SPA_POD_TYPE(pod) == SPA_TYPE_Long && SPA_POD_BODY_SIZE(pod) >= sizeof(int64_t)); +} + +static inline int spa_pod_get_long(const struct spa_pod *pod, int64_t *value) +{ + if (!spa_pod_is_long(pod)) + return -EINVAL; + *value = SPA_POD_VALUE(struct spa_pod_long, pod); + return 0; +} + +static inline int spa_pod_is_float(const struct spa_pod *pod) +{ + return (SPA_POD_TYPE(pod) == SPA_TYPE_Float && SPA_POD_BODY_SIZE(pod) >= sizeof(float)); +} + +static inline int spa_pod_get_float(const struct spa_pod *pod, float *value) +{ + if (!spa_pod_is_float(pod)) + return -EINVAL; + *value = SPA_POD_VALUE(struct spa_pod_float, pod); + return 0; +} + +static inline int spa_pod_is_double(const struct spa_pod *pod) +{ + return (SPA_POD_TYPE(pod) == SPA_TYPE_Double && SPA_POD_BODY_SIZE(pod) >= sizeof(double)); +} + +static inline int spa_pod_get_double(const struct spa_pod *pod, double *value) +{ + if (!spa_pod_is_double(pod)) + return -EINVAL; + *value = SPA_POD_VALUE(struct spa_pod_double, pod); + return 0; +} + +static inline int spa_pod_is_string(const struct spa_pod *pod) +{ + const char *s = (const char *)SPA_POD_CONTENTS(struct spa_pod_string, pod); + return (SPA_POD_TYPE(pod) == SPA_TYPE_String && + SPA_POD_BODY_SIZE(pod) > 0 && + s[SPA_POD_BODY_SIZE(pod)-1] == '\0'); +} + +static inline int spa_pod_get_string(const struct spa_pod *pod, const char **value) +{ + if (!spa_pod_is_string(pod)) + return -EINVAL; + *value = (const char *)SPA_POD_CONTENTS(struct spa_pod_string, pod); + return 0; +} + +static inline int spa_pod_copy_string(const struct spa_pod *pod, size_t maxlen, char *dest) +{ + const char *s = (const char *)SPA_POD_CONTENTS(struct spa_pod_string, pod); + if (!spa_pod_is_string(pod) || maxlen < 1) + return -EINVAL; + strncpy(dest, s, maxlen-1); + dest[maxlen-1]= '\0'; + return 0; +} + +static inline int spa_pod_is_bytes(const struct spa_pod *pod) +{ + return SPA_POD_TYPE(pod) == SPA_TYPE_Bytes; +} + +static inline int spa_pod_get_bytes(const struct spa_pod *pod, const void **value, uint32_t *len) +{ + if (!spa_pod_is_bytes(pod)) + return -EINVAL; + *value = (const void *)SPA_POD_CONTENTS(struct spa_pod_bytes, pod); + *len = SPA_POD_BODY_SIZE(pod); + return 0; +} + +static inline int spa_pod_is_pointer(const struct spa_pod *pod) +{ + return (SPA_POD_TYPE(pod) == SPA_TYPE_Pointer && + SPA_POD_BODY_SIZE(pod) >= sizeof(struct spa_pod_pointer_body)); +} + +static inline int spa_pod_get_pointer(const struct spa_pod *pod, uint32_t *type, const void **value) +{ + if (!spa_pod_is_pointer(pod)) + return -EINVAL; + *type = ((struct spa_pod_pointer*)pod)->body.type; + *value = ((struct spa_pod_pointer*)pod)->body.value; + return 0; +} + +static inline int spa_pod_is_fd(const struct spa_pod *pod) +{ + return (SPA_POD_TYPE(pod) == SPA_TYPE_Fd && + SPA_POD_BODY_SIZE(pod) >= sizeof(int64_t)); +} + +static inline int spa_pod_get_fd(const struct spa_pod *pod, int64_t *value) +{ + if (!spa_pod_is_fd(pod)) + return -EINVAL; + *value = SPA_POD_VALUE(struct spa_pod_fd, pod); + return 0; +} + +static inline int spa_pod_is_rectangle(const struct spa_pod *pod) +{ + return (SPA_POD_TYPE(pod) == SPA_TYPE_Rectangle && + SPA_POD_BODY_SIZE(pod) >= sizeof(struct spa_rectangle)); +} + +static inline int spa_pod_get_rectangle(const struct spa_pod *pod, struct spa_rectangle *value) +{ + if (!spa_pod_is_rectangle(pod)) + return -EINVAL; + *value = SPA_POD_VALUE(struct spa_pod_rectangle, pod); + return 0; +} + +static inline int spa_pod_is_fraction(const struct spa_pod *pod) +{ + return (SPA_POD_TYPE(pod) == SPA_TYPE_Fraction && + SPA_POD_BODY_SIZE(pod) >= sizeof(struct spa_fraction)); +} + +static inline int spa_pod_get_fraction(const struct spa_pod *pod, struct spa_fraction *value) +{ + spa_return_val_if_fail(spa_pod_is_fraction(pod), -EINVAL); + *value = SPA_POD_VALUE(struct spa_pod_fraction, pod); + return 0; +} + +static inline int spa_pod_is_bitmap(const struct spa_pod *pod) +{ + return (SPA_POD_TYPE(pod) == SPA_TYPE_Bitmap && + SPA_POD_BODY_SIZE(pod) >= sizeof(uint8_t)); +} + +static inline int spa_pod_is_array(const struct spa_pod *pod) +{ + return (SPA_POD_TYPE(pod) == SPA_TYPE_Array && + SPA_POD_BODY_SIZE(pod) >= sizeof(struct spa_pod_array_body)); +} + +static inline void *spa_pod_get_array(const struct spa_pod *pod, uint32_t *n_values) +{ + spa_return_val_if_fail(spa_pod_is_array(pod), NULL); + *n_values = SPA_POD_ARRAY_N_VALUES(pod); + return SPA_POD_ARRAY_VALUES(pod); +} + +static inline uint32_t spa_pod_copy_array(const struct spa_pod *pod, uint32_t type, + void *values, uint32_t max_values) +{ + uint32_t n_values; + void *v = spa_pod_get_array(pod, &n_values); + if (v == NULL || max_values == 0 || SPA_POD_ARRAY_VALUE_TYPE(pod) != type) + return 0; + n_values = SPA_MIN(n_values, max_values); + memcpy(values, v, SPA_POD_ARRAY_VALUE_SIZE(pod) * n_values); + return n_values; +} + +static inline int spa_pod_is_choice(const struct spa_pod *pod) +{ + return (SPA_POD_TYPE(pod) == SPA_TYPE_Choice && + SPA_POD_BODY_SIZE(pod) >= sizeof(struct spa_pod_choice_body)); +} + +static inline struct spa_pod *spa_pod_get_values(const struct spa_pod *pod, uint32_t *n_vals, uint32_t *choice) +{ + if (pod->type == SPA_TYPE_Choice) { + *n_vals = SPA_POD_CHOICE_N_VALUES(pod); + if ((*choice = SPA_POD_CHOICE_TYPE(pod)) == SPA_CHOICE_None) + *n_vals = SPA_MIN(1u, SPA_POD_CHOICE_N_VALUES(pod)); + return (struct spa_pod*)SPA_POD_CHOICE_CHILD(pod); + } else { + *n_vals = 1; + *choice = SPA_CHOICE_None; + return (struct spa_pod*)pod; + } +} + +static inline int spa_pod_is_struct(const struct spa_pod *pod) +{ + return (SPA_POD_TYPE(pod) == SPA_TYPE_Struct); +} + +static inline int spa_pod_is_object(const struct spa_pod *pod) +{ + return (SPA_POD_TYPE(pod) == SPA_TYPE_Object && + SPA_POD_BODY_SIZE(pod) >= sizeof(struct spa_pod_object_body)); +} + +static inline bool spa_pod_is_object_type(const struct spa_pod *pod, uint32_t type) +{ + return (pod && spa_pod_is_object(pod) && SPA_POD_OBJECT_TYPE(pod) == type); +} + +static inline bool spa_pod_is_object_id(const struct spa_pod *pod, uint32_t id) +{ + return (pod && spa_pod_is_object(pod) && SPA_POD_OBJECT_ID(pod) == id); +} + +static inline int spa_pod_is_sequence(const struct spa_pod *pod) +{ + return (SPA_POD_TYPE(pod) == SPA_TYPE_Sequence && + SPA_POD_BODY_SIZE(pod) >= sizeof(struct spa_pod_sequence_body)); +} + +static inline const struct spa_pod_prop *spa_pod_object_find_prop(const struct spa_pod_object *pod, + const struct spa_pod_prop *start, uint32_t key) +{ + const struct spa_pod_prop *first, *res; + + first = spa_pod_prop_first(&pod->body); + start = start ? spa_pod_prop_next(start) : first; + + for (res = start; spa_pod_prop_is_inside(&pod->body, pod->pod.size, res); + res = spa_pod_prop_next(res)) { + if (res->key == key) + return res; + } + for (res = first; res != start; res = spa_pod_prop_next(res)) { + if (res->key == key) + return res; + } + return NULL; +} + +static inline const struct spa_pod_prop *spa_pod_find_prop(const struct spa_pod *pod, + const struct spa_pod_prop *start, uint32_t key) +{ + if (!spa_pod_is_object(pod)) + return NULL; + return spa_pod_object_find_prop((const struct spa_pod_object *)pod, start, key); +} + +static inline int spa_pod_object_fixate(struct spa_pod_object *pod) +{ + struct spa_pod_prop *res; + SPA_POD_OBJECT_FOREACH(pod, res) { + if (res->value.type == SPA_TYPE_Choice && + !SPA_FLAG_IS_SET(res->flags, SPA_POD_PROP_FLAG_DONT_FIXATE)) + ((struct spa_pod_choice*)&res->value)->body.type = SPA_CHOICE_None; + } + return 0; +} + +static inline int spa_pod_fixate(struct spa_pod *pod) +{ + if (!spa_pod_is_object(pod)) + return -EINVAL; + return spa_pod_object_fixate((struct spa_pod_object *)pod); +} + +static inline int spa_pod_object_is_fixated(const struct spa_pod_object *pod) +{ + struct spa_pod_prop *res; + SPA_POD_OBJECT_FOREACH(pod, res) { + if (res->value.type == SPA_TYPE_Choice && + ((struct spa_pod_choice*)&res->value)->body.type != SPA_CHOICE_None) + return 0; + } + return 1; +} + +static inline int spa_pod_is_fixated(const struct spa_pod *pod) +{ + if (!spa_pod_is_object(pod)) + return -EINVAL; + return spa_pod_object_is_fixated((const struct spa_pod_object *)pod); +} + +/** + * \} + */ + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /* SPA_POD_H */ diff --git a/third_party/pipewire/spa/pod/parser.h b/third_party/pipewire/spa/pod/parser.h new file mode 100644 index 0000000000..c0a3099da6 --- /dev/null +++ b/third_party/pipewire/spa/pod/parser.h @@ -0,0 +1,583 @@ +/* Spa + * + * Copyright © 2018 Wim Taymans + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +#ifndef SPA_POD_PARSER_H +#define SPA_POD_PARSER_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include <errno.h> +#include <stdarg.h> + +#include <spa/pod/iter.h> +#include <spa/pod/vararg.h> + +/** + * \addtogroup spa_pod + * \{ + */ + +struct spa_pod_parser_state { + uint32_t offset; + uint32_t flags; + struct spa_pod_frame *frame; +}; + +struct spa_pod_parser { + const void *data; + uint32_t size; + uint32_t _padding; + struct spa_pod_parser_state state; +}; + +#define SPA_POD_PARSER_INIT(buffer,size) (struct spa_pod_parser){ buffer, size, 0, {} } + +static inline void spa_pod_parser_init(struct spa_pod_parser *parser, + const void *data, uint32_t size) +{ + *parser = SPA_POD_PARSER_INIT(data, size); +} + +static inline void spa_pod_parser_pod(struct spa_pod_parser *parser, + const struct spa_pod *pod) +{ + spa_pod_parser_init(parser, pod, SPA_POD_SIZE(pod)); +} + +static inline void +spa_pod_parser_get_state(struct spa_pod_parser *parser, struct spa_pod_parser_state *state) +{ + *state = parser->state; +} + +static inline void +spa_pod_parser_reset(struct spa_pod_parser *parser, struct spa_pod_parser_state *state) +{ + parser->state = *state; +} + +static inline struct spa_pod * +spa_pod_parser_deref(struct spa_pod_parser *parser, uint32_t offset, uint32_t size) +{ + if (offset + 8 <= size) { + struct spa_pod *pod = SPA_PTROFF(parser->data, offset, struct spa_pod); + if (offset + SPA_POD_SIZE(pod) <= size) + return pod; + } + return NULL; +} + +static inline struct spa_pod *spa_pod_parser_frame(struct spa_pod_parser *parser, struct spa_pod_frame *frame) +{ + return SPA_PTROFF(parser->data, frame->offset, struct spa_pod); +} + +static inline void spa_pod_parser_push(struct spa_pod_parser *parser, + struct spa_pod_frame *frame, const struct spa_pod *pod, uint32_t offset) +{ + frame->pod = *pod; + frame->offset = offset; + frame->parent = parser->state.frame; + frame->flags = parser->state.flags; + parser->state.frame = frame; +} + +static inline struct spa_pod *spa_pod_parser_current(struct spa_pod_parser *parser) +{ + struct spa_pod_frame *f = parser->state.frame; + uint32_t size = f ? f->offset + SPA_POD_SIZE(&f->pod) : parser->size; + return spa_pod_parser_deref(parser, parser->state.offset, size); +} + +static inline void spa_pod_parser_advance(struct spa_pod_parser *parser, const struct spa_pod *pod) +{ + parser->state.offset += SPA_ROUND_UP_N(SPA_POD_SIZE(pod), 8); +} + +static inline struct spa_pod *spa_pod_parser_next(struct spa_pod_parser *parser) +{ + struct spa_pod *pod = spa_pod_parser_current(parser); + if (pod) + spa_pod_parser_advance(parser, pod); + return pod; +} + +static inline int spa_pod_parser_pop(struct spa_pod_parser *parser, + struct spa_pod_frame *frame) +{ + parser->state.frame = frame->parent; + parser->state.offset = frame->offset + SPA_ROUND_UP_N(SPA_POD_SIZE(&frame->pod), 8); + return 0; +} + +static inline int spa_pod_parser_get_bool(struct spa_pod_parser *parser, bool *value) +{ + int res = -EPIPE; + const struct spa_pod *pod = spa_pod_parser_current(parser); + if (pod != NULL && (res = spa_pod_get_bool(pod, value)) >= 0) + spa_pod_parser_advance(parser, pod); + return res; +} + +static inline int spa_pod_parser_get_id(struct spa_pod_parser *parser, uint32_t *value) +{ + int res = -EPIPE; + const struct spa_pod *pod = spa_pod_parser_current(parser); + if (pod != NULL && (res = spa_pod_get_id(pod, value)) >= 0) + spa_pod_parser_advance(parser, pod); + return res; +} + +static inline int spa_pod_parser_get_int(struct spa_pod_parser *parser, int32_t *value) +{ + int res = -EPIPE; + const struct spa_pod *pod = spa_pod_parser_current(parser); + if (pod != NULL && (res = spa_pod_get_int(pod, value)) >= 0) + spa_pod_parser_advance(parser, pod); + return res; +} + +static inline int spa_pod_parser_get_long(struct spa_pod_parser *parser, int64_t *value) +{ + int res = -EPIPE; + const struct spa_pod *pod = spa_pod_parser_current(parser); + if (pod != NULL && (res = spa_pod_get_long(pod, value)) >= 0) + spa_pod_parser_advance(parser, pod); + return res; +} + +static inline int spa_pod_parser_get_float(struct spa_pod_parser *parser, float *value) +{ + int res = -EPIPE; + const struct spa_pod *pod = spa_pod_parser_current(parser); + if (pod != NULL && (res = spa_pod_get_float(pod, value)) >= 0) + spa_pod_parser_advance(parser, pod); + return res; +} + +static inline int spa_pod_parser_get_double(struct spa_pod_parser *parser, double *value) +{ + int res = -EPIPE; + const struct spa_pod *pod = spa_pod_parser_current(parser); + if (pod != NULL && (res = spa_pod_get_double(pod, value)) >= 0) + spa_pod_parser_advance(parser, pod); + return res; +} + +static inline int spa_pod_parser_get_string(struct spa_pod_parser *parser, const char **value) +{ + int res = -EPIPE; + const struct spa_pod *pod = spa_pod_parser_current(parser); + if (pod != NULL && (res = spa_pod_get_string(pod, value)) >= 0) + spa_pod_parser_advance(parser, pod); + return res; +} + +static inline int spa_pod_parser_get_bytes(struct spa_pod_parser *parser, const void **value, uint32_t *len) +{ + int res = -EPIPE; + const struct spa_pod *pod = spa_pod_parser_current(parser); + if (pod != NULL && (res = spa_pod_get_bytes(pod, value, len)) >= 0) + spa_pod_parser_advance(parser, pod); + return res; +} + +static inline int spa_pod_parser_get_pointer(struct spa_pod_parser *parser, uint32_t *type, const void **value) +{ + int res = -EPIPE; + const struct spa_pod *pod = spa_pod_parser_current(parser); + if (pod != NULL && (res = spa_pod_get_pointer(pod, type, value)) >= 0) + spa_pod_parser_advance(parser, pod); + return res; +} + +static inline int spa_pod_parser_get_fd(struct spa_pod_parser *parser, int64_t *value) +{ + int res = -EPIPE; + const struct spa_pod *pod = spa_pod_parser_current(parser); + if (pod != NULL && (res = spa_pod_get_fd(pod, value)) >= 0) + spa_pod_parser_advance(parser, pod); + return res; +} + +static inline int spa_pod_parser_get_rectangle(struct spa_pod_parser *parser, struct spa_rectangle *value) +{ + int res = -EPIPE; + const struct spa_pod *pod = spa_pod_parser_current(parser); + if (pod != NULL && (res = spa_pod_get_rectangle(pod, value)) >= 0) + spa_pod_parser_advance(parser, pod); + return res; +} + +static inline int spa_pod_parser_get_fraction(struct spa_pod_parser *parser, struct spa_fraction *value) +{ + int res = -EPIPE; + const struct spa_pod *pod = spa_pod_parser_current(parser); + if (pod != NULL && (res = spa_pod_get_fraction(pod, value)) >= 0) + spa_pod_parser_advance(parser, pod); + return res; +} + +static inline int spa_pod_parser_get_pod(struct spa_pod_parser *parser, struct spa_pod **value) +{ + struct spa_pod *pod = spa_pod_parser_current(parser); + if (pod == NULL) + return -EPIPE; + *value = pod; + spa_pod_parser_advance(parser, pod); + return 0; +} +static inline int spa_pod_parser_push_struct(struct spa_pod_parser *parser, + struct spa_pod_frame *frame) +{ + const struct spa_pod *pod = spa_pod_parser_current(parser); + if (pod == NULL) + return -EPIPE; + if (!spa_pod_is_struct(pod)) + return -EINVAL; + spa_pod_parser_push(parser, frame, pod, parser->state.offset); + parser->state.offset += sizeof(struct spa_pod_struct); + return 0; +} + +static inline int spa_pod_parser_push_object(struct spa_pod_parser *parser, + struct spa_pod_frame *frame, uint32_t type, uint32_t *id) +{ + const struct spa_pod *pod = spa_pod_parser_current(parser); + if (pod == NULL) + return -EPIPE; + if (!spa_pod_is_object(pod)) + return -EINVAL; + if (type != SPA_POD_OBJECT_TYPE(pod)) + return -EPROTO; + if (id != NULL) + *id = SPA_POD_OBJECT_ID(pod); + spa_pod_parser_push(parser, frame, pod, parser->state.offset); + parser->state.offset = parser->size; + return 0; +} + +static inline bool spa_pod_parser_can_collect(const struct spa_pod *pod, char type) +{ + if (pod == NULL) + return false; + + if (spa_pod_is_choice(pod) && + SPA_POD_CHOICE_TYPE(pod) == SPA_CHOICE_None && + spa_pod_parser_can_collect(SPA_POD_CHOICE_CHILD(pod), type)) + return true; + + switch (type) { + case 'P': + return true; + case 'b': + return spa_pod_is_bool(pod); + case 'I': + return spa_pod_is_id(pod); + case 'i': + return spa_pod_is_int(pod); + case 'l': + return spa_pod_is_long(pod); + case 'f': + return spa_pod_is_float(pod); + case 'd': + return spa_pod_is_double(pod); + case 's': + return spa_pod_is_string(pod) || spa_pod_is_none(pod); + case 'S': + return spa_pod_is_string(pod); + case 'y': + return spa_pod_is_bytes(pod); + case 'R': + return spa_pod_is_rectangle(pod); + case 'F': + return spa_pod_is_fraction(pod); + case 'B': + return spa_pod_is_bitmap(pod); + case 'a': + return spa_pod_is_array(pod); + case 'p': + return spa_pod_is_pointer(pod); + case 'h': + return spa_pod_is_fd(pod); + case 'T': + return spa_pod_is_struct(pod) || spa_pod_is_none(pod); + case 'O': + return spa_pod_is_object(pod) || spa_pod_is_none(pod); + case 'V': + return spa_pod_is_choice(pod); + default: + return false; + } +} + +#define SPA_POD_PARSER_COLLECT(pod,_type,args) \ +do { \ + switch (_type) { \ + case 'b': \ + *va_arg(args, bool*) = SPA_POD_VALUE(struct spa_pod_bool, pod); \ + break; \ + case 'I': \ + case 'i': \ + *va_arg(args, int32_t*) = SPA_POD_VALUE(struct spa_pod_int, pod); \ + break; \ + case 'l': \ + *va_arg(args, int64_t*) = SPA_POD_VALUE(struct spa_pod_long, pod); \ + break; \ + case 'f': \ + *va_arg(args, float*) = SPA_POD_VALUE(struct spa_pod_float, pod); \ + break; \ + case 'd': \ + *va_arg(args, double*) = SPA_POD_VALUE(struct spa_pod_double, pod); \ + break; \ + case 's': \ + *va_arg(args, char**) = \ + (pod == NULL || (SPA_POD_TYPE(pod) == SPA_TYPE_None) \ + ? NULL \ + : (char *)SPA_POD_CONTENTS(struct spa_pod_string, pod)); \ + break; \ + case 'S': \ + { \ + char *dest = va_arg(args, char*); \ + uint32_t maxlen = va_arg(args, uint32_t); \ + strncpy(dest, (char *)SPA_POD_CONTENTS(struct spa_pod_string, pod), maxlen-1); \ + dest[maxlen-1] = '\0'; \ + break; \ + } \ + case 'y': \ + *(va_arg(args, void **)) = SPA_POD_CONTENTS(struct spa_pod_bytes, pod); \ + *(va_arg(args, uint32_t *)) = SPA_POD_BODY_SIZE(pod); \ + break; \ + case 'R': \ + *va_arg(args, struct spa_rectangle*) = \ + SPA_POD_VALUE(struct spa_pod_rectangle, pod); \ + break; \ + case 'F': \ + *va_arg(args, struct spa_fraction*) = \ + SPA_POD_VALUE(struct spa_pod_fraction, pod); \ + break; \ + case 'B': \ + *va_arg(args, uint32_t **) = \ + (uint32_t *) SPA_POD_CONTENTS(struct spa_pod_bitmap, pod); \ + break; \ + case 'a': \ + *va_arg(args, uint32_t*) = SPA_POD_ARRAY_VALUE_SIZE(pod); \ + *va_arg(args, uint32_t*) = SPA_POD_ARRAY_VALUE_TYPE(pod); \ + *va_arg(args, uint32_t*) = SPA_POD_ARRAY_N_VALUES(pod); \ + *va_arg(args, void**) = SPA_POD_ARRAY_VALUES(pod); \ + break; \ + case 'p': \ + { \ + struct spa_pod_pointer_body *b = \ + (struct spa_pod_pointer_body *) SPA_POD_BODY(pod); \ + *(va_arg(args, uint32_t *)) = b->type; \ + *(va_arg(args, const void **)) = b->value; \ + break; \ + } \ + case 'h': \ + *va_arg(args, int64_t*) = SPA_POD_VALUE(struct spa_pod_fd, pod); \ + break; \ + case 'P': \ + case 'T': \ + case 'O': \ + case 'V': \ + { \ + const struct spa_pod **d = va_arg(args, const struct spa_pod**); \ + if (d) \ + *d = (pod == NULL || (SPA_POD_TYPE(pod) == SPA_TYPE_None) \ + ? NULL : pod); \ + break; \ + } \ + default: \ + break; \ + } \ +} while(false) + +#define SPA_POD_PARSER_SKIP(_type,args) \ +do { \ + switch (_type) { \ + case 'S': \ + va_arg(args, char*); \ + va_arg(args, uint32_t); \ + break; \ + case 'a': \ + va_arg(args, void*); \ + va_arg(args, void*); \ + SPA_FALLTHROUGH \ + case 'p': \ + case 'y': \ + va_arg(args, void*); \ + SPA_FALLTHROUGH \ + case 'b': \ + case 'I': \ + case 'i': \ + case 'l': \ + case 'f': \ + case 'd': \ + case 's': \ + case 'R': \ + case 'F': \ + case 'B': \ + case 'h': \ + case 'V': \ + case 'P': \ + case 'T': \ + case 'O': \ + va_arg(args, void*); \ + break; \ + } \ +} while(false) + +static inline int spa_pod_parser_getv(struct spa_pod_parser *parser, va_list args) +{ + struct spa_pod_frame *f = parser->state.frame; + uint32_t ftype = f ? f->pod.type : (uint32_t)SPA_TYPE_Struct; + const struct spa_pod_prop *prop = NULL; + int count = 0; + + do { + bool optional; + const struct spa_pod *pod = NULL; + const char *format; + + if (ftype == SPA_TYPE_Object) { + uint32_t key = va_arg(args, uint32_t); + const struct spa_pod_object *object; + + if (key == 0) + break; + + object = (const struct spa_pod_object *)spa_pod_parser_frame(parser, f); + prop = spa_pod_object_find_prop(object, prop, key); + pod = prop ? &prop->value : NULL; + } + + if ((format = va_arg(args, char *)) == NULL) + break; + + if (ftype == SPA_TYPE_Struct) + pod = spa_pod_parser_next(parser); + + if ((optional = (*format == '?'))) + format++; + + if (!spa_pod_parser_can_collect(pod, *format)) { + if (!optional) { + if (pod == NULL) + return -ESRCH; + else + return -EPROTO; + } + SPA_POD_PARSER_SKIP(*format, args); + } else { + if (pod->type == SPA_TYPE_Choice && *format != 'V' && + SPA_POD_CHOICE_TYPE(pod) == SPA_CHOICE_None) + pod = SPA_POD_CHOICE_CHILD(pod); + + SPA_POD_PARSER_COLLECT(pod, *format, args); + count++; + } + } while (true); + + return count; +} + +static inline int spa_pod_parser_get(struct spa_pod_parser *parser, ...) +{ + int res; + va_list args; + + va_start(args, parser); + res = spa_pod_parser_getv(parser, args); + va_end(args); + + return res; +} + +#define SPA_POD_OPT_Bool(val) "?" SPA_POD_Bool(val) +#define SPA_POD_OPT_Id(val) "?" SPA_POD_Id(val) +#define SPA_POD_OPT_Int(val) "?" SPA_POD_Int(val) +#define SPA_POD_OPT_Long(val) "?" SPA_POD_Long(val) +#define SPA_POD_OPT_Float(val) "?" SPA_POD_Float(val) +#define SPA_POD_OPT_Double(val) "?" SPA_POD_Double(val) +#define SPA_POD_OPT_String(val) "?" SPA_POD_String(val) +#define SPA_POD_OPT_Stringn(val,len) "?" SPA_POD_Stringn(val,len) +#define SPA_POD_OPT_Bytes(val,len) "?" SPA_POD_Bytes(val,len) +#define SPA_POD_OPT_Rectangle(val) "?" SPA_POD_Rectangle(val) +#define SPA_POD_OPT_Fraction(val) "?" SPA_POD_Fraction(val) +#define SPA_POD_OPT_Array(csize,ctype,n_vals,vals) "?" SPA_POD_Array(csize,ctype,n_vals,vals) +#define SPA_POD_OPT_Pointer(type,val) "?" SPA_POD_Pointer(type,val) +#define SPA_POD_OPT_Fd(val) "?" SPA_POD_Fd(val) +#define SPA_POD_OPT_Pod(val) "?" SPA_POD_Pod(val) +#define SPA_POD_OPT_PodObject(val) "?" SPA_POD_PodObject(val) +#define SPA_POD_OPT_PodStruct(val) "?" SPA_POD_PodStruct(val) +#define SPA_POD_OPT_PodChoice(val) "?" SPA_POD_PodChoice(val) + +#define spa_pod_parser_get_object(p,type,id,...) \ +({ \ + struct spa_pod_frame _f; \ + int _res; \ + if ((_res = spa_pod_parser_push_object(p, &_f, type, id)) == 0) { \ + _res = spa_pod_parser_get(p,##__VA_ARGS__, 0); \ + spa_pod_parser_pop(p, &_f); \ + } \ + _res; \ +}) + +#define spa_pod_parser_get_struct(p,...) \ +({ \ + struct spa_pod_frame _f; \ + int _res; \ + if ((_res = spa_pod_parser_push_struct(p, &_f)) == 0) { \ + _res = spa_pod_parser_get(p,##__VA_ARGS__, NULL); \ + spa_pod_parser_pop(p, &_f); \ + } \ + _res; \ +}) + +#define spa_pod_parse_object(pod,type,id,...) \ +({ \ + struct spa_pod_parser _p; \ + spa_pod_parser_pod(&_p, pod); \ + spa_pod_parser_get_object(&_p,type,id,##__VA_ARGS__); \ +}) + +#define spa_pod_parse_struct(pod,...) \ +({ \ + struct spa_pod_parser _p; \ + spa_pod_parser_pod(&_p, pod); \ + spa_pod_parser_get_struct(&_p,##__VA_ARGS__); \ +}) + +/** + * \} + */ + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /* SPA_POD_PARSER_H */ diff --git a/third_party/pipewire/spa/pod/pod.h b/third_party/pipewire/spa/pod/pod.h new file mode 100644 index 0000000000..2d2eaad6a1 --- /dev/null +++ b/third_party/pipewire/spa/pod/pod.h @@ -0,0 +1,246 @@ +/* Simple Plugin API + * + * Copyright © 2018 Wim Taymans + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +#ifndef SPA_POD_H +#define SPA_POD_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include <spa/utils/defs.h> +#include <spa/utils/type.h> + +/** + * \addtogroup spa_pod + * \{ + */ + +#define SPA_POD_BODY_SIZE(pod) (((struct spa_pod*)(pod))->size) +#define SPA_POD_TYPE(pod) (((struct spa_pod*)(pod))->type) +#define SPA_POD_SIZE(pod) (sizeof(struct spa_pod) + SPA_POD_BODY_SIZE(pod)) +#define SPA_POD_CONTENTS_SIZE(type,pod) (SPA_POD_SIZE(pod)-sizeof(type)) + +#define SPA_POD_CONTENTS(type,pod) SPA_PTROFF((pod),sizeof(type),void) +#define SPA_POD_CONTENTS_CONST(type,pod) SPA_PTROFF((pod),sizeof(type),const void) +#define SPA_POD_BODY(pod) SPA_PTROFF((pod),sizeof(struct spa_pod),void) +#define SPA_POD_BODY_CONST(pod) SPA_PTROFF((pod),sizeof(struct spa_pod),const void) + +struct spa_pod { + uint32_t size; /* size of the body */ + uint32_t type; /* a basic id of enum spa_type */ +}; + +#define SPA_POD_VALUE(type,pod) (((type*)pod)->value) + +struct spa_pod_bool { + struct spa_pod pod; + int32_t value; + int32_t _padding; +}; + +struct spa_pod_id { + struct spa_pod pod; + uint32_t value; + int32_t _padding; +}; + +struct spa_pod_int { + struct spa_pod pod; + int32_t value; + int32_t _padding; +}; + +struct spa_pod_long { + struct spa_pod pod; + int64_t value; +}; + +struct spa_pod_float { + struct spa_pod pod; + float value; + int32_t _padding; +}; + +struct spa_pod_double { + struct spa_pod pod; + double value; +}; + +struct spa_pod_string { + struct spa_pod pod; + /* value here */ +}; + +struct spa_pod_bytes { + struct spa_pod pod; + /* value here */ +}; + +struct spa_pod_rectangle { + struct spa_pod pod; + struct spa_rectangle value; +}; + +struct spa_pod_fraction { + struct spa_pod pod; + struct spa_fraction value; +}; + +struct spa_pod_bitmap { + struct spa_pod pod; + /* array of uint8_t follows with the bitmap */ +}; + +#define SPA_POD_ARRAY_CHILD(arr) (&((struct spa_pod_array*)(arr))->body.child) +#define SPA_POD_ARRAY_VALUE_TYPE(arr) (SPA_POD_TYPE(SPA_POD_ARRAY_CHILD(arr))) +#define SPA_POD_ARRAY_VALUE_SIZE(arr) (SPA_POD_BODY_SIZE(SPA_POD_ARRAY_CHILD(arr))) +#define SPA_POD_ARRAY_N_VALUES(arr) (SPA_POD_ARRAY_VALUE_SIZE(arr) ? ((SPA_POD_BODY_SIZE(arr) - sizeof(struct spa_pod_array_body)) / SPA_POD_ARRAY_VALUE_SIZE(arr)) : 0) +#define SPA_POD_ARRAY_VALUES(arr) SPA_POD_CONTENTS(struct spa_pod_array, arr) + +struct spa_pod_array_body { + struct spa_pod child; + /* array with elements of child.size follows */ +}; + +struct spa_pod_array { + struct spa_pod pod; + struct spa_pod_array_body body; +}; + +#define SPA_POD_CHOICE_CHILD(choice) (&((struct spa_pod_choice*)(choice))->body.child) +#define SPA_POD_CHOICE_TYPE(choice) (((struct spa_pod_choice*)(choice))->body.type) +#define SPA_POD_CHOICE_FLAGS(choice) (((struct spa_pod_choice*)(choice))->body.flags) +#define SPA_POD_CHOICE_VALUE_TYPE(choice) (SPA_POD_TYPE(SPA_POD_CHOICE_CHILD(choice))) +#define SPA_POD_CHOICE_VALUE_SIZE(choice) (SPA_POD_BODY_SIZE(SPA_POD_CHOICE_CHILD(choice))) +#define SPA_POD_CHOICE_N_VALUES(choice) (SPA_POD_CHOICE_VALUE_SIZE(choice) ? ((SPA_POD_BODY_SIZE(choice) - sizeof(struct spa_pod_choice_body)) / SPA_POD_CHOICE_VALUE_SIZE(choice)) : 0) +#define SPA_POD_CHOICE_VALUES(choice) (SPA_POD_CONTENTS(struct spa_pod_choice, choice)) + +enum spa_choice_type { + SPA_CHOICE_None, /**< no choice, first value is current */ + SPA_CHOICE_Range, /**< range: default, min, max */ + SPA_CHOICE_Step, /**< range with step: default, min, max, step */ + SPA_CHOICE_Enum, /**< list: default, alternative,... */ + SPA_CHOICE_Flags, /**< flags: default, possible flags,... */ +}; + +struct spa_pod_choice_body { + uint32_t type; /**< type of choice, one of enum spa_choice_type */ + uint32_t flags; /**< extra flags */ + struct spa_pod child; + /* array with elements of child.size follows. Note that there might be more + * elements than required by \a type, which should be ignored. */ +}; + +struct spa_pod_choice { + struct spa_pod pod; + struct spa_pod_choice_body body; +}; + +struct spa_pod_struct { + struct spa_pod pod; + /* one or more spa_pod follow */ +}; + +#define SPA_POD_OBJECT_TYPE(obj) (((struct spa_pod_object*)(obj))->body.type) +#define SPA_POD_OBJECT_ID(obj) (((struct spa_pod_object*)(obj))->body.id) + +struct spa_pod_object_body { + uint32_t type; /**< one of enum spa_type */ + uint32_t id; /**< id of the object, depends on the object type */ + /* contents follow, series of spa_pod_prop */ +}; + +struct spa_pod_object { + struct spa_pod pod; + struct spa_pod_object_body body; +}; + +struct spa_pod_pointer_body { + uint32_t type; /**< pointer id, one of enum spa_type */ + uint32_t _padding; + const void *value; +}; + +struct spa_pod_pointer { + struct spa_pod pod; + struct spa_pod_pointer_body body; +}; + +struct spa_pod_fd { + struct spa_pod pod; + int64_t value; +}; + +#define SPA_POD_PROP_SIZE(prop) (sizeof(struct spa_pod_prop) + (prop)->value.size) + +/* props can be inside an object */ +struct spa_pod_prop { + uint32_t key; /**< key of property, list of valid keys depends on the + * object type */ +#define SPA_POD_PROP_FLAG_READONLY (1u<<0) /**< is read-only */ +#define SPA_POD_PROP_FLAG_HARDWARE (1u<<1) /**< some sort of hardware parameter */ +#define SPA_POD_PROP_FLAG_HINT_DICT (1u<<2) /**< contains a dictionary struct as + * (Struct( + * Int : n_items, + * (String : key, + * String : value)*)) */ +#define SPA_POD_PROP_FLAG_MANDATORY (1u<<3) /**< is mandatory */ +#define SPA_POD_PROP_FLAG_DONT_FIXATE (1u<<4) /**< choices need no fixation */ + uint32_t flags; /**< flags for property */ + struct spa_pod value; + /* value follows */ +}; + +#define SPA_POD_CONTROL_SIZE(ev) (sizeof(struct spa_pod_control) + (ev)->value.size) + +/* controls can be inside a sequence and mark timed values */ +struct spa_pod_control { + uint32_t offset; /**< media offset */ + uint32_t type; /**< type of control, enum spa_control_type */ + struct spa_pod value; /**< control value, depends on type */ + /* value contents follow */ +}; + +struct spa_pod_sequence_body { + uint32_t unit; + uint32_t pad; + /* series of struct spa_pod_control follows */ +}; + +/** a sequence of timed controls */ +struct spa_pod_sequence { + struct spa_pod pod; + struct spa_pod_sequence_body body; +}; + +/** + * \} + */ + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /* SPA_POD_H */ diff --git a/third_party/pipewire/spa/pod/vararg.h b/third_party/pipewire/spa/pod/vararg.h new file mode 100644 index 0000000000..53dc654047 --- /dev/null +++ b/third_party/pipewire/spa/pod/vararg.h @@ -0,0 +1,113 @@ +/* Simple Plugin API + * + * Copyright © 2019 Wim Taymans + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +#ifndef SPA_POD_VARARG_H +#define SPA_POD_VARARG_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include <stdarg.h> + +#include <spa/pod/pod.h> + +/** + * \addtogroup spa_pod + * \{ + */ + +#define SPA_POD_Prop(key,...) \ + key, ##__VA_ARGS__ + +#define SPA_POD_Control(offset,type,...) \ + offset, type, ##__VA_ARGS__ + +#define SPA_CHOICE_RANGE(def,min,max) 3,(def),(min),(max) +#define SPA_CHOICE_STEP(def,min,max,step) 4,(def),(min),(max),(step) +#define SPA_CHOICE_ENUM(n_vals,...) (n_vals),##__VA_ARGS__ +#define SPA_CHOICE_FLAGS(flags) 1, (flags) +#define SPA_CHOICE_BOOL(def) 3,(def),(def),!(def) + +#define SPA_POD_Bool(val) "b", val +#define SPA_POD_CHOICE_Bool(def) "?eb", SPA_CHOICE_BOOL(def) + +#define SPA_POD_Id(val) "I", val +#define SPA_POD_CHOICE_ENUM_Id(n_vals,...) "?eI", SPA_CHOICE_ENUM(n_vals, __VA_ARGS__) + +#define SPA_POD_Int(val) "i", val +#define SPA_POD_CHOICE_ENUM_Int(n_vals,...) "?ei", SPA_CHOICE_ENUM(n_vals, __VA_ARGS__) +#define SPA_POD_CHOICE_RANGE_Int(def,min,max) "?ri", SPA_CHOICE_RANGE(def, min, max) +#define SPA_POD_CHOICE_STEP_Int(def,min,max,step) "?si", SPA_CHOICE_STEP(def, min, max, step) +#define SPA_POD_CHOICE_FLAGS_Int(flags) "?fi", SPA_CHOICE_FLAGS(flags) + +#define SPA_POD_Long(val) "l", val +#define SPA_POD_CHOICE_ENUM_Long(n_vals,...) "?el", SPA_CHOICE_ENUM(n_vals, __VA_ARGS__) +#define SPA_POD_CHOICE_RANGE_Long(def,min,max) "?rl", SPA_CHOICE_RANGE(def, min, max) +#define SPA_POD_CHOICE_STEP_Long(def,min,max,step) "?sl", SPA_CHOICE_STEP(def, min, max, step) +#define SPA_POD_CHOICE_FLAGS_Long(flags) "?fl", SPA_CHOICE_FLAGS(flags) + +#define SPA_POD_Float(val) "f", val +#define SPA_POD_CHOICE_ENUM_Float(n_vals,...) "?ef", SPA_CHOICE_ENUM(n_vals, __VA_ARGS__) +#define SPA_POD_CHOICE_RANGE_Float(def,min,max) "?rf", SPA_CHOICE_RANGE(def, min, max) +#define SPA_POD_CHOICE_STEP_Float(def,min,max,step) "?sf", SPA_CHOICE_STEP(def, min, max, step) + +#define SPA_POD_Double(val) "d", val +#define SPA_POD_CHOICE_ENUM_Double(n_vals,...) "?ed", SPA_CHOICE_ENUM(n_vals, __VA_ARGS__) +#define SPA_POD_CHOICE_RANGE_Double(def,min,max) "?rd", SPA_CHOICE_RANGE(def, min, max) +#define SPA_POD_CHOICE_STEP_Double(def,min,max,step) "?sd", SPA_CHOICE_STEP(def, min, max, step) + +#define SPA_POD_String(val) "s",val +#define SPA_POD_Stringn(val,len) "S",val,len + +#define SPA_POD_Bytes(val,len) "y",val,len + +#define SPA_POD_Rectangle(val) "R",val +#define SPA_POD_CHOICE_ENUM_Rectangle(n_vals,...) "?eR", SPA_CHOICE_ENUM(n_vals, __VA_ARGS__) +#define SPA_POD_CHOICE_RANGE_Rectangle(def,min,max) "?rR", SPA_CHOICE_RANGE((def),(min),(max)) +#define SPA_POD_CHOICE_STEP_Rectangle(def,min,max,step) "?sR", SPA_CHOICE_STEP((def),(min),(max),(step)) + +#define SPA_POD_Fraction(val) "F",val +#define SPA_POD_CHOICE_ENUM_Fraction(n_vals,...) "?eF", SPA_CHOICE_ENUM(n_vals, __VA_ARGS__) +#define SPA_POD_CHOICE_RANGE_Fraction(def,min,max) "?rF", SPA_CHOICE_RANGE((def),(min),(max)) +#define SPA_POD_CHOICE_STEP_Fraction(def,min,max,step) "?sF", SPA_CHOICE_STEP(def, min, max, step) + +#define SPA_POD_Array(csize,ctype,n_vals,vals) "a", csize,ctype,n_vals,vals +#define SPA_POD_Pointer(type,val) "p", type,val +#define SPA_POD_Fd(val) "h", val +#define SPA_POD_None() "P", NULL +#define SPA_POD_Pod(val) "P", val +#define SPA_POD_PodObject(val) "O", val +#define SPA_POD_PodStruct(val) "T", val +#define SPA_POD_PodChoice(val) "V", val + +/** + * \} + */ + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /* SPA_POD_VARARG_H */ |