mirror of
https://gitlab.freedesktop.org/pipewire/pipewire.git
synced 2025-11-05 13:30:02 -05:00
Make allocparams into pod objects. This makes it easy to serialize, copy, create and intersect them. Add convenience macros for properties Add helper function to collect object properties.
308 lines
10 KiB
C
308 lines
10 KiB
C
/* Simple Plugin API
|
|
* Copyright (C) 2016 Wim Taymans <wim.taymans@gmail.com>
|
|
*
|
|
* This library is free software; you can redistribute it and/or
|
|
* modify it under the terms of the GNU Library General Public
|
|
* License as published by the Free Software Foundation; either
|
|
* version 2 of the License, or (at your option) any later version.
|
|
*
|
|
* This library is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
* Library General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU Library General Public
|
|
* License along with this library; if not, write to the
|
|
* Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
|
|
* Boston, MA 02110-1301, USA.
|
|
*/
|
|
|
|
#include <stdint.h>
|
|
#include <stddef.h>
|
|
#include <stdio.h>
|
|
#include <string.h>
|
|
|
|
#include <spa/props.h>
|
|
|
|
static int
|
|
compare_value (SpaPODType type, const void *r1, const void *r2)
|
|
{
|
|
switch (type) {
|
|
case SPA_POD_TYPE_INVALID:
|
|
return 0;
|
|
case SPA_POD_TYPE_BOOL:
|
|
return *(int32_t*)r1 == *(uint32_t*)r2;
|
|
case SPA_POD_TYPE_INT:
|
|
return *(int32_t*)r1 - *(int32_t*)r2;
|
|
case SPA_POD_TYPE_LONG:
|
|
return *(int64_t*)r1 - *(int64_t*)r2;
|
|
case SPA_POD_TYPE_FLOAT:
|
|
return *(float*)r1 - *(float*)r2;
|
|
case SPA_POD_TYPE_DOUBLE:
|
|
return *(double*)r1 - *(double*)r2;
|
|
case SPA_POD_TYPE_STRING:
|
|
return strcmp (r1, r2);
|
|
case SPA_POD_TYPE_RECTANGLE:
|
|
{
|
|
const SpaRectangle *rec1 = (SpaRectangle*)r1,
|
|
*rec2 = (SpaRectangle*)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_POD_TYPE_FRACTION:
|
|
{
|
|
const SpaFraction *f1 = (SpaFraction*)r1,
|
|
*f2 = (SpaFraction*)r2;
|
|
uint64_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 void
|
|
fix_default (SpaPODProp *prop)
|
|
{
|
|
void *val = SPA_MEMBER (prop, sizeof (SpaPODProp), void),
|
|
*alt = SPA_MEMBER (val, prop->body.value.size, void);
|
|
int i, nalt = SPA_POD_PROP_N_VALUES (prop) - 1;
|
|
|
|
switch (prop->body.flags & SPA_POD_PROP_RANGE_MASK) {
|
|
case SPA_POD_PROP_RANGE_NONE:
|
|
break;
|
|
case SPA_POD_PROP_RANGE_MIN_MAX:
|
|
case SPA_POD_PROP_RANGE_STEP:
|
|
if (compare_value (prop->body.value.type, val, alt) < 0)
|
|
memcpy (val, alt, prop->body.value.size);
|
|
alt = SPA_MEMBER (alt, prop->body.value.size, void);
|
|
if (compare_value (prop->body.value.type, val, alt) > 0)
|
|
memcpy (val, alt, prop->body.value.size);
|
|
break;
|
|
case SPA_POD_PROP_RANGE_ENUM:
|
|
{
|
|
void *best = NULL;
|
|
|
|
for (i = 0; i < nalt; i++) {
|
|
if (compare_value (prop->body.value.type, val, alt) == 0) {
|
|
best = alt;
|
|
break;
|
|
}
|
|
if (best == NULL)
|
|
best = alt;
|
|
alt = SPA_MEMBER (alt, prop->body.value.size, void);
|
|
}
|
|
if (best)
|
|
memcpy (val, best, prop->body.value.size);
|
|
|
|
if (nalt == 1) {
|
|
prop->body.flags &= ~SPA_POD_PROP_FLAG_UNSET;
|
|
prop->body.flags &= ~SPA_POD_PROP_RANGE_MASK;
|
|
prop->body.flags |= SPA_POD_PROP_RANGE_NONE;
|
|
}
|
|
break;
|
|
}
|
|
case SPA_POD_PROP_RANGE_FLAGS:
|
|
break;
|
|
}
|
|
}
|
|
|
|
static inline SpaPODProp *
|
|
find_prop (const SpaPOD *pod, uint32_t size, uint32_t key)
|
|
{
|
|
const SpaPOD *res;
|
|
SPA_POD_FOREACH (pod, size, res) {
|
|
if (res->type == SPA_POD_TYPE_PROP && ((SpaPODProp*)res)->body.key == key)
|
|
return (SpaPODProp *)res;
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
SpaResult
|
|
spa_props_filter (SpaPODBuilder *b,
|
|
const SpaPOD *props,
|
|
uint32_t props_size,
|
|
const SpaPOD *filter,
|
|
uint32_t filter_size)
|
|
{
|
|
int j, k;
|
|
const SpaPOD *pr;
|
|
|
|
SPA_POD_FOREACH (props, props_size, pr) {
|
|
SpaPODFrame f;
|
|
SpaPODProp *p1, *p2, *np;
|
|
int nalt1, nalt2;
|
|
void *alt1, *alt2, *a1, *a2;
|
|
uint32_t rt1, rt2;
|
|
|
|
if (pr->type != SPA_POD_TYPE_PROP)
|
|
continue;
|
|
|
|
p1 = (SpaPODProp *) pr;
|
|
|
|
if (filter == NULL || (p2 = find_prop (filter, filter_size, p1->body.key)) == NULL) {
|
|
/* no filter, copy the complete property */
|
|
spa_pod_builder_raw_padded (b, p1, SPA_POD_SIZE (p1));
|
|
continue;
|
|
}
|
|
|
|
/* incompatible property types */
|
|
if (p1->body.value.type != p2->body.value.type)
|
|
return SPA_RESULT_INCOMPATIBLE_PROPS;
|
|
|
|
rt1 = p1->body.flags & SPA_POD_PROP_RANGE_MASK;
|
|
rt2 = p2->body.flags & SPA_POD_PROP_RANGE_MASK;
|
|
|
|
/* else we filter. start with copying the property */
|
|
np = SPA_POD_BUILDER_DEREF (b,
|
|
spa_pod_builder_push_prop (b, &f, p1->body.key, SPA_POD_PROP_FLAG_READWRITE),
|
|
SpaPODProp);
|
|
/* default value */
|
|
spa_pod_builder_raw (b, &p1->body.value, sizeof (p1->body.value) + p1->body.value.size);
|
|
|
|
alt1 = SPA_MEMBER (p1, sizeof (SpaPODProp), void);
|
|
nalt1 = SPA_POD_PROP_N_VALUES (p1);
|
|
alt2 = SPA_MEMBER (p2, sizeof (SpaPODProp), void);
|
|
nalt2 = SPA_POD_PROP_N_VALUES (p2);
|
|
|
|
if (p1->body.flags & SPA_POD_PROP_FLAG_UNSET) {
|
|
alt1 = SPA_MEMBER (alt1, p1->body.value.size, void);
|
|
nalt1--;
|
|
} else {
|
|
nalt1 = 1;
|
|
}
|
|
|
|
if (p2->body.flags & SPA_POD_PROP_FLAG_UNSET) {
|
|
alt2 = SPA_MEMBER (alt2, p2->body.value.size, void);
|
|
nalt2--;
|
|
} else {
|
|
nalt2 = 1;
|
|
}
|
|
|
|
if ((rt1 == SPA_POD_PROP_RANGE_NONE && rt2 == SPA_POD_PROP_RANGE_NONE) ||
|
|
(rt1 == SPA_POD_PROP_RANGE_NONE && rt2 == SPA_POD_PROP_RANGE_ENUM) ||
|
|
(rt1 == SPA_POD_PROP_RANGE_ENUM && rt2 == SPA_POD_PROP_RANGE_NONE) ||
|
|
(rt1 == SPA_POD_PROP_RANGE_ENUM && rt2 == SPA_POD_PROP_RANGE_ENUM)) {
|
|
int n_copied = 0;
|
|
/* copy all equal values */
|
|
for (j = 0, a1 = alt1; j < nalt1; j++, a1 += p1->body.value.size) {
|
|
for (k = 0, a2 = alt2; k < nalt2; k++, a2 += p2->body.value.size) {
|
|
if (compare_value (p1->body.value.type, a1, a2) == 0) {
|
|
spa_pod_builder_raw (b, a1, p1->body.value.size);
|
|
n_copied++;
|
|
}
|
|
}
|
|
}
|
|
if (n_copied == 0)
|
|
return SPA_RESULT_INCOMPATIBLE_PROPS;
|
|
np->body.flags |= SPA_POD_PROP_RANGE_ENUM | SPA_POD_PROP_FLAG_UNSET;
|
|
}
|
|
|
|
if ((rt1 == SPA_POD_PROP_RANGE_NONE && rt2 == SPA_POD_PROP_RANGE_MIN_MAX) ||
|
|
(rt1 == SPA_POD_PROP_RANGE_ENUM && rt2 == SPA_POD_PROP_RANGE_MIN_MAX)) {
|
|
int n_copied = 0;
|
|
/* copy all values inside the range */
|
|
for (j = 0, a1 = alt1, a2 = alt2; j < nalt1; j++, a1 += p1->body.value.size) {
|
|
if (compare_value (p1->body.value.type, a1, a2) < 0)
|
|
continue;
|
|
if (compare_value (p1->body.value.type, a1, a2 + p2->body.value.size) > 0)
|
|
continue;
|
|
spa_pod_builder_raw (b, a1, p1->body.value.size);
|
|
n_copied++;
|
|
}
|
|
if (n_copied == 0)
|
|
return SPA_RESULT_INCOMPATIBLE_PROPS;
|
|
np->body.flags |= SPA_POD_PROP_RANGE_ENUM | SPA_POD_PROP_FLAG_UNSET;
|
|
}
|
|
|
|
if ((rt1 == SPA_POD_PROP_RANGE_NONE && rt2 == SPA_POD_PROP_RANGE_STEP) ||
|
|
(rt1 == SPA_POD_PROP_RANGE_ENUM && rt2 == SPA_POD_PROP_RANGE_STEP)) {
|
|
return SPA_RESULT_NOT_IMPLEMENTED;
|
|
}
|
|
|
|
if ((rt1 == SPA_POD_PROP_RANGE_MIN_MAX && rt2 == SPA_POD_PROP_RANGE_NONE) ||
|
|
(rt1 == SPA_POD_PROP_RANGE_MIN_MAX && rt2 == SPA_POD_PROP_RANGE_ENUM)) {
|
|
int n_copied = 0;
|
|
/* copy all values inside the range */
|
|
for (k = 0, a1 = alt1, a2 = alt2; k < nalt2; k++, a2 += p2->body.value.size) {
|
|
if (compare_value (p1->body.value.type, a2, a1) < 0)
|
|
continue;
|
|
if (compare_value (p1->body.value.type, a2, a1 + p1->body.value.size) > 0)
|
|
continue;
|
|
spa_pod_builder_raw (b, a2, p2->body.value.size);
|
|
n_copied++;
|
|
}
|
|
if (n_copied == 0)
|
|
return SPA_RESULT_INCOMPATIBLE_PROPS;
|
|
np->body.flags |= SPA_POD_PROP_RANGE_ENUM | SPA_POD_PROP_FLAG_UNSET;
|
|
}
|
|
|
|
if (rt1 == SPA_POD_PROP_RANGE_MIN_MAX && rt2 == SPA_POD_PROP_RANGE_MIN_MAX) {
|
|
if (compare_value (p1->body.value.type, alt1, alt2) < 0)
|
|
spa_pod_builder_raw (b, alt2, p2->body.value.size);
|
|
else
|
|
spa_pod_builder_raw (b, alt1, p1->body.value.size);
|
|
|
|
alt1 += p1->body.value.size;
|
|
alt2 += p2->body.value.size;
|
|
|
|
if (compare_value (p1->body.value.type, alt1, alt2) < 0)
|
|
spa_pod_builder_raw (b, alt1, p1->body.value.size);
|
|
else
|
|
spa_pod_builder_raw (b, alt2, p2->body.value.size);
|
|
|
|
np->body.flags |= SPA_POD_PROP_RANGE_MIN_MAX | SPA_POD_PROP_FLAG_UNSET;
|
|
}
|
|
|
|
if (rt1 == SPA_POD_PROP_RANGE_NONE && rt2 == SPA_POD_PROP_RANGE_FLAGS)
|
|
return SPA_RESULT_NOT_IMPLEMENTED;
|
|
|
|
if (rt1 == SPA_POD_PROP_RANGE_MIN_MAX && rt2 == SPA_POD_PROP_RANGE_STEP)
|
|
return SPA_RESULT_NOT_IMPLEMENTED;
|
|
|
|
if (rt1 == SPA_POD_PROP_RANGE_MIN_MAX && rt2 == SPA_POD_PROP_RANGE_FLAGS)
|
|
return SPA_RESULT_NOT_IMPLEMENTED;
|
|
|
|
if (rt1 == SPA_POD_PROP_RANGE_ENUM && rt2 == SPA_POD_PROP_RANGE_FLAGS)
|
|
return SPA_RESULT_NOT_IMPLEMENTED;
|
|
|
|
if (rt1 == SPA_POD_PROP_RANGE_STEP && rt2 == SPA_POD_PROP_RANGE_NONE)
|
|
return SPA_RESULT_NOT_IMPLEMENTED;
|
|
if (rt1 == SPA_POD_PROP_RANGE_STEP && rt2 == SPA_POD_PROP_RANGE_MIN_MAX)
|
|
return SPA_RESULT_NOT_IMPLEMENTED;
|
|
|
|
if (rt1 == SPA_POD_PROP_RANGE_STEP && rt2 == SPA_POD_PROP_RANGE_STEP)
|
|
return SPA_RESULT_NOT_IMPLEMENTED;
|
|
if (rt1 == SPA_POD_PROP_RANGE_STEP && rt2 == SPA_POD_PROP_RANGE_ENUM)
|
|
return SPA_RESULT_NOT_IMPLEMENTED;
|
|
if (rt1 == SPA_POD_PROP_RANGE_STEP && rt2 == SPA_POD_PROP_RANGE_FLAGS)
|
|
return SPA_RESULT_NOT_IMPLEMENTED;
|
|
|
|
if (rt1 == SPA_POD_PROP_RANGE_FLAGS && rt2 == SPA_POD_PROP_RANGE_NONE)
|
|
return SPA_RESULT_NOT_IMPLEMENTED;
|
|
if (rt1 == SPA_POD_PROP_RANGE_FLAGS && rt2 == SPA_POD_PROP_RANGE_MIN_MAX)
|
|
return SPA_RESULT_NOT_IMPLEMENTED;
|
|
if (rt1 == SPA_POD_PROP_RANGE_FLAGS && rt2 == SPA_POD_PROP_RANGE_STEP)
|
|
return SPA_RESULT_NOT_IMPLEMENTED;
|
|
if (rt1 == SPA_POD_PROP_RANGE_FLAGS && rt2 == SPA_POD_PROP_RANGE_ENUM)
|
|
return SPA_RESULT_NOT_IMPLEMENTED;
|
|
if (rt1 == SPA_POD_PROP_RANGE_FLAGS && rt2 == SPA_POD_PROP_RANGE_FLAGS)
|
|
return SPA_RESULT_NOT_IMPLEMENTED;
|
|
|
|
spa_pod_builder_pop (b, &f);
|
|
fix_default (np);
|
|
}
|
|
return SPA_RESULT_OK;
|
|
}
|