diff --git a/src/modules/module-protocol-pulse/quirks.c b/src/modules/module-protocol-pulse/quirks.c index f17345c77..d6c306822 100644 --- a/src/modules/module-protocol-pulse/quirks.c +++ b/src/modules/module-protocol-pulse/quirks.c @@ -22,21 +22,109 @@ * DEALINGS IN THE SOFTWARE. */ -#include "quirks.h" +#include + +#include #include -int client_update_quirks(struct client *client) -{ - const char *str; +#include "quirks.h" - if ((str = pw_properties_get(client->props, "application.process.binary")) != NULL && - spa_streq(str, "teams")) { - client->quirks |= QUIRK_FORCE_S16_FORMAT; - } - if ((str = pw_properties_get(client->props, "application.process.binary")) != NULL && - spa_streq(str, "firefox")) { - client->quirks |= QUIRK_REMOVE_CAPTURE_DONT_MOVE; +#define QUOTE(...) #__VA_ARGS__ + +static const char quirks_rules[] = +"# List of quirks" +"#" +"# All key/value pairs need to match before the quirks are applied." +"#" +"# Possible quirks:" +"# force-s16-info forces sink and source info as S16 format" +"# remove-capture-dont-move removes the capture DONT_MOVE flag" +"#\n" +"[" +" { application.process.binary = teams, quirks = [ force-s16-info ] }," +" { application.process.binary = firefox, quirks = [ remove-capture-dont-move ] }," +"]"; + +static uint64_t parse_quirks(const char *str) +{ + static const struct { const char *key; uint64_t value; } quirk_keys[] = { + { "force-s16-info", QUIRK_FORCE_S16_FORMAT }, + { "remove-capture-dont-move", QUIRK_REMOVE_CAPTURE_DONT_MOVE }, + }; + size_t i; + for (i = 0; i < SPA_N_ELEMENTS(quirk_keys); ++i) { + if (spa_streq(str, quirk_keys[i].key)) + return quirk_keys[i].value; } return 0; } + +static int match(const char *rules, struct spa_dict *dict, uint64_t *quirks) +{ + struct spa_json rules_json = SPA_JSON_INIT(rules, strlen(rules)); + struct spa_json rules_arr, it[2]; + + if (spa_json_enter_array(&rules_json, &rules_arr) <= 0) + return -EINVAL; + + while (spa_json_enter_object(&rules_arr, &it[0]) > 0) { + char key[256]; + int match = true; + uint64_t quirks_cur = 0; + + while (spa_json_get_string(&it[0], key, sizeof(key)-1) > 0) { + char val[4096]; + const char *str, *value; + int len; + bool success = false; + + if (spa_streq(key, "quirks")) { + if (spa_json_enter_array(&it[0], &it[1]) > 0) { + while (spa_json_get_string(&it[1], val, sizeof(val)-1) > 0) + quirks_cur |= parse_quirks(val); + } + continue; + } + if ((len = spa_json_next(&it[0], &value)) <= 0) + break; + + if (spa_json_is_null(value, len)) { + value = NULL; + } else { + spa_json_parse_string(value, SPA_MIN(len, (int)sizeof(val)-1), val); + value = val; + } + str = spa_dict_lookup(dict, key); + if (value == NULL) { + success = str == NULL; + } else if (str != NULL) { + if (value[0] == '~') { + regex_t r; + if (regcomp(&r, value+1, REG_EXTENDED | REG_NOSUB) == 0) { + if (regexec(&r, str, 0, NULL, 0) == 0) + success = true; + regfree(&r); + } + } else if (spa_streq(str, value)) { + success = true; + } + } + + if (!success) { + match = false; + break; + } + } + if (match) { + *quirks = quirks_cur; + return 1; + } + } + return 0; +} + +int client_update_quirks(struct client *client) +{ + return match(quirks_rules, &client->props->dict, &client->quirks); +}