From f2c4452e8dcf2b92f789185e3057b1effb5a3100 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20=C3=85dahl?= Date: Thu, 22 Jan 2026 16:55:34 +0100 Subject: [PATCH] stream: Make capability device IDs an JSON object Also change the encoding of the byte array to use hexadecimal encoding, i.e. the byte array [100, 200] in becomes "64c8". --- doc/dox/internals/dma-buf.dox | 7 +++- src/examples/base64.h | 46 ----------------------- src/examples/utils.h | 60 ++++++++++++++++++++++++++++++ src/examples/video-play-fixate.c | 64 ++++++++++++++++++-------------- src/examples/video-src-fixate.c | 13 ++++--- 5 files changed, 110 insertions(+), 80 deletions(-) delete mode 100644 src/examples/base64.h create mode 100644 src/examples/utils.h diff --git a/doc/dox/internals/dma-buf.dox b/doc/dox/internals/dma-buf.dox index 7815a8c42..5042f285c 100644 --- a/doc/dox/internals/dma-buf.dox +++ b/doc/dox/internals/dma-buf.dox @@ -365,10 +365,13 @@ with. This can be used to reduce the amount of devices that are queried for form metadata, which can be a time consuming task, if devices needs to be woken up. To achieve this, the consumer adds another \ref SPA_PARAM_PeerCapability item with the key -\ref PW_CAPABILITY_DEVICE_IDS set to a string of base 64 encoded `dev_t` device IDs. +\ref PW_CAPABILITY_DEVICE_IDS set to a JSON object describing what device IDs are supported. + +This JSON object as of version 1 contains a single key "available-devices" that contain +a list of hexadecimal encoded `dev_t` device IDs. ``` - char *device_ids = ...; /* Base 64 encoding of a dev_t. */. + char *device_ids = "{\"available-devices\": [\"6464000000000000\",\"c8c8000000000000\"]}"; &SPA_DICT_ITEMS( SPA_DICT_ITEM(PW_CAPABILITY_DEVICE_ID_NEGOTIATION, "1"), SPA_DICT_ITEM(PW_CAPABILITY_DEVICE_IDS, device_ids))); diff --git a/src/examples/base64.h b/src/examples/base64.h deleted file mode 100644 index 50e6d64b2..000000000 --- a/src/examples/base64.h +++ /dev/null @@ -1,46 +0,0 @@ -/* PipeWire */ -/* SPDX-FileCopyrightText: Copyright © 2021 Wim Taymans */ -/* SPDX-License-Identifier: MIT */ - -static inline void base64_encode(const uint8_t *data, size_t len, char *enc, char pad) -{ - static const char tab[] = - "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; - size_t i; - for (i = 0; i < len; i += 3) { - uint32_t v; - v = data[i+0] << 16; - v |= (i+1 < len ? data[i+1] : 0) << 8; - v |= (i+2 < len ? data[i+2] : 0); - *enc++ = tab[(v >> (3*6)) & 0x3f]; - *enc++ = tab[(v >> (2*6)) & 0x3f]; - *enc++ = i+1 < len ? tab[(v >> (1*6)) & 0x3f] : pad; - *enc++ = i+2 < len ? tab[(v >> (0*6)) & 0x3f] : pad; - } - *enc = '\0'; -} - -static inline size_t base64_decode(const char *data, size_t len, uint8_t *dec) -{ - uint8_t tab[] = { - 62, -1, -1, -1, 63, 52, 53, 54, 55, 56, - 57, 58, 59, 60, 61, -1, -1, -1, -1, -1, - -1, -1, 0, 1, 2, 3, 4, 5, 6, 7, - 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, - 18, 19, 20, 21, 22, 23, 24, 25, -1, -1, - -1, -1, -1, -1, 26, 27, 28, 29, 30, 31, - 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, - 42, 43, 44, 45, 46, 47, 48, 49, 50, 51 }; - size_t i, j; - for (i = 0, j = 0; i < len; i += 4) { - uint32_t v; - v = tab[data[i+0]-43] << (3*6); - v |= tab[data[i+1]-43] << (2*6); - v |= (data[i+2] == '=' ? 0 : tab[data[i+2]-43]) << (1*6); - v |= (data[i+3] == '=' ? 0 : tab[data[i+3]-43]); - dec[j++] = (v >> 16) & 0xff; - if (data[i+2] != '=') dec[j++] = (v >> 8) & 0xff; - if (data[i+3] != '=') dec[j++] = v & 0xff; - } - return j; -} diff --git a/src/examples/utils.h b/src/examples/utils.h new file mode 100644 index 000000000..079f22d55 --- /dev/null +++ b/src/examples/utils.h @@ -0,0 +1,60 @@ +/* PipeWire */ +/* SPDX-FileCopyrightText: Copyright © 2026 Red Hat */ +/* SPDX-License-Identifier: MIT */ + +static inline char * +encode_hex(const uint8_t *data, size_t size) +{ + FILE *ms; + char *encoded = NULL; + size_t encoded_size = 0; + size_t i; + + ms = open_memstream(&encoded, &encoded_size); + for (i = 0; i < size; i++) { + fprintf(ms, "%02x", data[i]); + } + fclose(ms); + + return encoded; +} + +static inline int8_t +ascii_hex_to_hex(uint8_t ascii_hex) +{ + if (ascii_hex >= '0' && ascii_hex <= '9') + return ascii_hex - '0'; + else if (ascii_hex >= 'a' && ascii_hex <= 'f') + return ascii_hex - 'a' + 10; + else if (ascii_hex >= 'A' && ascii_hex <= 'F') + return ascii_hex - 'A' + 10; + else + return -1; +} + +static inline int +decode_hex(const char *encoded, uint8_t *data, size_t size) +{ + size_t length; + size_t i; + + length = strlen(encoded); + + if (size < (length / 2) * sizeof(uint8_t)) + return -1; + + i = 0; + while (i < length) { + int8_t top = ascii_hex_to_hex(encoded[i]); + int8_t bottom = ascii_hex_to_hex(encoded[i + 1]); + + if (top == -1 || bottom == -1) + return -1; + + uint8_t el = top << 4 | bottom; + data[i / 2] = el; + i += 2; + } + + return 1; +} diff --git a/src/examples/video-play-fixate.c b/src/examples/video-play-fixate.c index 2ee71a941..13b617a59 100644 --- a/src/examples/video-play-fixate.c +++ b/src/examples/video-play-fixate.c @@ -29,7 +29,7 @@ #include #include -#include "base64.h" +#include "utils.h" /* Comment out to test device ID negotation backward compatibility. */ #define SUPPORT_DEVICE_ID_NEGOTIATION 1 @@ -372,46 +372,56 @@ collect_device_ids(struct data *data, const char *json) int len; const char *value; struct spa_json sub; + char key[1024]; if ((len = spa_json_begin(&it, json, strlen(json), &value)) <= 0) { fprintf(stderr, "invalid device IDs value\n"); return; } - if (!spa_json_is_array(value, len)) { - fprintf(stderr, "device IDs not array\n"); + if (!spa_json_is_object(value, len)) { + fprintf(stderr, "device IDs not object\n"); return; } spa_json_enter(&it, &sub); - while ((len = spa_json_next(&sub, &value)) > 0) { - char *string; - union { - dev_t device_id; - uint8_t buffer[1024]; - } dec; + while ((len = spa_json_object_next(&sub, key, sizeof(key), &value)) > 0) { + struct spa_json devices_sub; - string = alloca(len + 1); - - if (!spa_json_is_string(value, len)) { - fprintf(stderr, "device ID not string\n"); + if (!spa_json_is_array(value, len)) { + fprintf(stderr, "available-devices not array\n"); return; } - if (spa_json_parse_string(value, len, string) <= 0) { - fprintf(stderr, "invalid device ID string\n"); - return; + spa_json_enter(&sub, &devices_sub); + while ((len = spa_json_next(&devices_sub, &value)) > 0) { + char *string; + union { + dev_t device_id; + uint8_t buffer[1024]; + } dec; + + string = alloca(len + 1); + + if (!spa_json_is_string(value, len)) { + fprintf(stderr, "device ID not string\n"); + return; + } + + if (spa_json_parse_string(value, len, string) <= 0) { + fprintf(stderr, "invalid device ID string\n"); + return; + } + + if (decode_hex(string, dec.buffer, sizeof (dec.buffer)) < 0) { + fprintf(stderr, "invalid device ID string\n"); + return; + } + + fprintf(stderr, "discovered device ID %u:%u\n", + major(dec.device_id), minor(dec.device_id)); + + data->device_ids[data->n_device_ids++] = dec.device_id; } - - if (base64_decode(string, strlen(string), - (uint8_t *)&dec.device_id) < sizeof(dev_t)) { - fprintf(stderr, "invalid device ID\n"); - return; - } - - fprintf(stderr, "discovered device ID %u:%u\n", - major(dec.device_id), minor(dec.device_id)); - - data->device_ids[data->n_device_ids++] = dec.device_id; } } diff --git a/src/examples/video-src-fixate.c b/src/examples/video-src-fixate.c index 0e072c27b..6d08074de 100644 --- a/src/examples/video-src-fixate.c +++ b/src/examples/video-src-fixate.c @@ -30,7 +30,7 @@ #include #include -#include "base64.h" +#include "utils.h" /* Comment out to test device ID negotation backward compatibility. */ #define SUPPORT_DEVICE_ID_NEGOTIATION 1 @@ -784,17 +784,20 @@ int main(int argc, char *argv[]) size_t i; ms = open_memstream(&device_ids, &device_ids_size); - fprintf(ms, "["); + fprintf(ms, "{\"available-devices\": ["); for (i = 0; i < SPA_N_ELEMENTS(devices); i++) { dev_t device_id = makedev(devices[i].major, devices[i].minor); - char device_id_encoded[256]; + char *device_id_encoded; + + device_id_encoded = encode_hex((const uint8_t *) &device_id, sizeof (device_id)); - base64_encode((const uint8_t *) &device_id, sizeof (device_id), device_id_encoded, '\0'); if (i > 0) fprintf(ms, ","); fprintf(ms, "\"%s\"", device_id_encoded); + + free(device_id_encoded); } - fprintf(ms, "]"); + fprintf(ms, "]}"); fclose(ms); #endif /* SUPPORT_DEVICE_IDS_LIST */