diff --git a/spa/plugins/alsa/alsa-pcm-sink.c b/spa/plugins/alsa/alsa-pcm-sink.c index 06210911e..d63e7c076 100644 --- a/spa/plugins/alsa/alsa-pcm-sink.c +++ b/spa/plugins/alsa/alsa-pcm-sink.c @@ -785,33 +785,27 @@ impl_init(const struct spa_handle_factory *factory, snd_config_update_free_global(); for (i = 0; info && i < info->n_items; i++) { + const char *k = info->items[i].key; const char *s = info->items[i].value; - if (!strcmp(info->items[i].key, SPA_KEY_API_ALSA_PATH)) { - snprintf(this->props.device, 63, "%s", info->items[i].value); - } else if (!strcmp(info->items[i].key, SPA_KEY_AUDIO_CHANNELS)) { - this->default_channels = atoi(info->items[i].value); - } else if (!strcmp(info->items[i].key, SPA_KEY_AUDIO_RATE)) { - this->default_rate = atoi(info->items[i].value); - } else if (!strcmp(info->items[i].key, SPA_KEY_AUDIO_FORMAT)) { - this->default_format = spa_alsa_format_from_name(info->items[i].value, 128); - } else if (!strcmp(info->items[i].key, SPA_KEY_AUDIO_POSITION)) { - size_t len; - while (*s && this->default_pos.channels < SPA_AUDIO_MAX_CHANNELS) { - if ((len = strcspn(s, ",")) == 0) - break; - this->default_pos.pos[this->default_pos.channels++] = - spa_alsa_channel_from_name(s, len); - s += len + strspn(s+len, ","); - } - } else if (!strcmp(info->items[i].key, "api.alsa.period-size")) { - this->default_period_size = atoi(info->items[i].value); - } else if (!strcmp(info->items[i].key, "api.alsa.headroom")) { - this->default_headroom = atoi(info->items[i].value); - } else if (!strcmp(info->items[i].key, "api.alsa.disable-mmap")) { + if (!strcmp(k, SPA_KEY_API_ALSA_PATH)) { + snprintf(this->props.device, 63, "%s", s); + } else if (!strcmp(k, SPA_KEY_AUDIO_CHANNELS)) { + this->default_channels = atoi(s); + } else if (!strcmp(k, SPA_KEY_AUDIO_RATE)) { + this->default_rate = atoi(s); + } else if (!strcmp(k, SPA_KEY_AUDIO_FORMAT)) { + this->default_format = spa_alsa_format_from_name(s, strlen(s)); + } else if (!strcmp(k, SPA_KEY_AUDIO_POSITION)) { + spa_alsa_parse_position(&this->default_pos, s, strlen(s)); + } else if (!strcmp(k, "api.alsa.period-size")) { + this->default_period_size = atoi(s); + } else if (!strcmp(k, "api.alsa.headroom")) { + this->default_headroom = atoi(s); + } else if (!strcmp(k, "api.alsa.disable-mmap")) { this->disable_mmap = (strcmp(s, "true") == 0 || atoi(s) == 1); - } else if (!strcmp(info->items[i].key, "api.alsa.disable-batch")) { + } else if (!strcmp(k, "api.alsa.disable-batch")) { this->disable_batch = (strcmp(s, "true") == 0 || atoi(s) == 1); - } else if (!strcmp(info->items[i].key, "api.alsa.use-chmap")) { + } else if (!strcmp(k, "api.alsa.use-chmap")) { this->props.use_chmap = (strcmp(s, "true") == 0 || atoi(s) == 1); } } diff --git a/spa/plugins/alsa/alsa-pcm-source.c b/spa/plugins/alsa/alsa-pcm-source.c index 393f450e6..a33450d7a 100644 --- a/spa/plugins/alsa/alsa-pcm-source.c +++ b/spa/plugins/alsa/alsa-pcm-source.c @@ -805,33 +805,27 @@ impl_init(const struct spa_handle_factory *factory, snd_config_update_free_global(); for (i = 0; info && i < info->n_items; i++) { + const char *k = info->items[i].key; const char *s = info->items[i].value; - if (!strcmp(info->items[i].key, SPA_KEY_API_ALSA_PATH)) { - snprintf(this->props.device, 63, "%s", info->items[i].value); - } else if (!strcmp(info->items[i].key, SPA_KEY_AUDIO_CHANNELS)) { - this->default_channels = atoi(info->items[i].value); - } else if (!strcmp(info->items[i].key, SPA_KEY_AUDIO_RATE)) { - this->default_rate = atoi(info->items[i].value); - } else if (!strcmp(info->items[i].key, SPA_KEY_AUDIO_FORMAT)) { - this->default_format = spa_alsa_format_from_name(info->items[i].value, 128); - } else if (!strcmp(info->items[i].key, SPA_KEY_AUDIO_POSITION)) { - size_t len; - while (*s && this->default_pos.channels < SPA_AUDIO_MAX_CHANNELS) { - if ((len = strcspn(s, ",")) == 0) - break; - this->default_pos.pos[this->default_pos.channels++] = - spa_alsa_channel_from_name(s, len); - s += len + strspn(s+len, ","); - } - } else if (!strcmp(info->items[i].key, "api.alsa.period-size")) { - this->default_period_size = atoi(info->items[i].value); - } else if (!strcmp(info->items[i].key, "api.alsa.headroom")) { - this->default_headroom = atoi(info->items[i].value); - } else if (!strcmp(info->items[i].key, "api.alsa.disable-mmap")) { + if (!strcmp(k, SPA_KEY_API_ALSA_PATH)) { + snprintf(this->props.device, 63, "%s", s); + } else if (!strcmp(k, SPA_KEY_AUDIO_CHANNELS)) { + this->default_channels = atoi(s); + } else if (!strcmp(k, SPA_KEY_AUDIO_RATE)) { + this->default_rate = atoi(s); + } else if (!strcmp(k, SPA_KEY_AUDIO_FORMAT)) { + this->default_format = spa_alsa_format_from_name(s, strlen(s)); + } else if (!strcmp(k, SPA_KEY_AUDIO_POSITION)) { + spa_alsa_parse_position(&this->default_pos, s, strlen(s)); + } else if (!strcmp(k, "api.alsa.period-size")) { + this->default_period_size = atoi(s); + } else if (!strcmp(k, "api.alsa.headroom")) { + this->default_headroom = atoi(s); + } else if (!strcmp(k, "api.alsa.disable-mmap")) { this->disable_mmap = (strcmp(s, "true") == 0 || atoi(s) == 1); - } else if (!strcmp(info->items[i].key, "api.alsa.disable-batch")) { + } else if (!strcmp(k, "api.alsa.disable-batch")) { this->disable_batch = (strcmp(s, "true") == 0 || atoi(s) == 1); - } else if (!strcmp(info->items[i].key, "api.alsa.use-chmap")) { + } else if (!strcmp(k, "api.alsa.use-chmap")) { this->props.use_chmap = (strcmp(s, "true") == 0 || atoi(s) == 1); } } diff --git a/spa/plugins/alsa/alsa-pcm.h b/spa/plugins/alsa/alsa-pcm.h index d477987a3..798ba95dc 100644 --- a/spa/plugins/alsa/alsa-pcm.h +++ b/spa/plugins/alsa/alsa-pcm.h @@ -38,6 +38,7 @@ extern "C" { #include #include #include +#include #include #include @@ -216,6 +217,23 @@ static inline uint32_t spa_alsa_channel_from_name(const char *name, size_t len) return SPA_AUDIO_CHANNEL_UNKNOWN; } +static inline void spa_alsa_parse_position(struct channel_map *map, const char *val, size_t len) +{ + struct spa_json it[2]; + char v[256]; + int l; + + spa_json_init(&it[0], val, len); + if (spa_json_enter_array(&it[0], &it[1]) <= 0) + spa_json_init(&it[1], val, len); + + map->channels = 0; + while ((l = spa_json_get_string(&it[1], v, sizeof(v))) > 0 && + map->channels < SPA_AUDIO_MAX_CHANNELS) { + map->pos[map->channels++] = spa_alsa_channel_from_name(v, l); + } +} + #ifdef __cplusplus } /* extern "C" */ #endif diff --git a/spa/plugins/audioconvert/channelmix.c b/spa/plugins/audioconvert/channelmix.c index ba021b876..8064fdc90 100644 --- a/spa/plugins/audioconvert/channelmix.c +++ b/spa/plugins/audioconvert/channelmix.c @@ -31,6 +31,7 @@ #include #include #include +#include #include #include #include @@ -1235,6 +1236,24 @@ static uint32_t channel_from_name(const char *name, size_t len) return SPA_AUDIO_CHANNEL_UNKNOWN; } +static inline uint32_t parse_position(uint32_t *pos, const char *val, size_t len) +{ + struct spa_json it[2]; + char v[256]; + int l; + uint32_t i = 0; + + spa_json_init(&it[0], val, len); + if (spa_json_enter_array(&it[0], &it[1]) <= 0) + spa_json_init(&it[1], val, len); + + while ((l = spa_json_get_string(&it[1], v, sizeof(v))) > 0 && + i < SPA_AUDIO_MAX_CHANNELS) { + pos[i++] = channel_from_name(v, l); + } + return i; +} + static int impl_init(const struct spa_handle_factory *factory, struct spa_handle *handle, @@ -1244,7 +1263,7 @@ impl_init(const struct spa_handle_factory *factory, { struct impl *this; struct port *port; - const char *str; + uint32_t i; spa_return_val_if_fail(factory != NULL, -EINVAL); spa_return_val_if_fail(handle != NULL, -EINVAL); @@ -1264,29 +1283,22 @@ impl_init(const struct spa_handle_factory *factory, props_reset(&this->props); - if (info != NULL) { - if ((str = spa_dict_lookup(info, "channelmix.normalize")) != NULL && - (strcmp(str, "true") == 0 || atoi(str) != 0)) + for (i = 0; info && i < info->n_items; i++) { + const char *k = info->items[i].key; + const char *s = info->items[i].value; + if (strcmp(k, "channelmix.normalize") == 0 && + (strcmp(s, "true") == 0 || atoi(s) != 0)) this->mix.options |= CHANNELMIX_OPTION_NORMALIZE; - if ((str = spa_dict_lookup(info, "channelmix.mix-lfe")) != NULL && - (strcmp(str, "true") == 0 || atoi(str) != 0)) + if (strcmp(k, "channelmix.mix-lfe") == 0 && + (strcmp(s, "true") == 0 || atoi(s) != 0)) this->mix.options |= CHANNELMIX_OPTION_MIX_LFE; - if ((str = spa_dict_lookup(info, "channelmix.upmix")) != NULL && - (strcmp(str, "true") == 0 || atoi(str) != 0)) + if (strcmp(k, "channelmix.upmix") == 0 && + (strcmp(s, "true") == 0 || atoi(s) != 0)) this->mix.options |= CHANNELMIX_OPTION_UPMIX; - if ((str = spa_dict_lookup(info, "channelmix.lfe-cutoff")) != NULL) - this->mix.lfe_cutoff = atoi(str); - if ((str = spa_dict_lookup(info, SPA_KEY_AUDIO_POSITION)) != NULL) { - size_t len; - const char *p = str; - while (*p && this->props.n_channels < SPA_AUDIO_MAX_CHANNELS) { - if ((len = strcspn(p, ",")) == 0) - break; - this->props.channel_map[this->props.n_channels++] = - channel_from_name(p, len); - p += len + strspn(p+len, ","); - } - } + if (strcmp(k, "channelmix.lfe-cutoff") == 0) + this->mix.lfe_cutoff = atoi(s); + if (strcmp(k, SPA_KEY_AUDIO_POSITION) == 0) + this->props.n_channels = parse_position(this->props.channel_map, s, strlen(s)); } this->props.n_channel_volumes = this->props.n_channels; diff --git a/spa/plugins/support/null-audio-sink.c b/spa/plugins/support/null-audio-sink.c index f4f830874..3275af150 100644 --- a/spa/plugins/support/null-audio-sink.c +++ b/spa/plugins/support/null-audio-sink.c @@ -34,6 +34,7 @@ #include #include #include +#include #include #include #include @@ -733,6 +734,23 @@ static uint32_t channel_from_name(const char *name, size_t len) return SPA_AUDIO_CHANNEL_UNKNOWN; } +static inline void parse_position(struct impl *this, const char *val, size_t len) +{ + struct spa_json it[2]; + char v[256]; + int l; + + spa_json_init(&it[0], val, len); + if (spa_json_enter_array(&it[0], &it[1]) <= 0) + spa_json_init(&it[1], val, len); + + this->props.n_pos = 0; + while ((l = spa_json_get_string(&it[1], v, sizeof(v))) > 0 && + this->props.n_pos < SPA_AUDIO_MAX_CHANNELS) { + this->props.pos[this->props.n_pos++] = channel_from_name(v, l); + } +} + static int impl_init(const struct spa_handle_factory *factory, struct spa_handle *handle, @@ -809,19 +827,14 @@ impl_init(const struct spa_handle_factory *factory, spa_loop_add_source(this->data_loop, &this->timer_source); for (i = 0; info && i < info->n_items; i++) { - if (!strcmp(info->items[i].key, SPA_KEY_AUDIO_CHANNELS)) { - this->props.channels = atoi(info->items[i].value); - } else if (!strcmp(info->items[i].key, SPA_KEY_AUDIO_RATE)) { - this->props.rate = atoi(info->items[i].value); - } else if (!strcmp(info->items[i].key, SPA_KEY_AUDIO_POSITION)) { - size_t len; - const char *p = info->items[i].value; - while (*p && this->props.n_pos < SPA_AUDIO_MAX_CHANNELS) { - if ((len = strcspn(p, ",")) == 0) - break; - this->props.pos[this->props.n_pos++] = channel_from_name(p, len); - p += len + strspn(p+len, ","); - } + const char *k = info->items[i].key; + const char *s = info->items[i].value; + if (!strcmp(k, SPA_KEY_AUDIO_CHANNELS)) { + this->props.channels = atoi(s); + } else if (!strcmp(k, SPA_KEY_AUDIO_RATE)) { + this->props.rate = atoi(s); + } else if (!strcmp(k, SPA_KEY_AUDIO_POSITION)) { + parse_position(this, s, strlen(s)); } } if (this->props.n_pos > 0) diff --git a/spa/tests/test-json.c b/spa/tests/test-json.c index 47f343cdf..d03a20a37 100644 --- a/spa/tests/test-json.c +++ b/spa/tests/test-json.c @@ -169,10 +169,35 @@ static void test_encode(void) spa_assert(strcmp(result, "\x04\x05\x1f\x20\x01\x7f\x90") == 0); } +static void test_array(char *str, char **vals) +{ + struct spa_json it[2]; + char val[256]; + int i, len; + + spa_json_init(&it[0], str, strlen(str)); + if (spa_json_enter_array(&it[0], &it[1]) <= 0) + spa_json_init(&it[1], str, strlen(str)); + for (i = 0; vals[i]; i++) { + spa_assert((len = spa_json_get_string(&it[1], val, sizeof(val))) > 0); + spa_assert(strcmp(val, vals[i]) == 0); + } +} + +static void test_arrays(void) +{ + test_array("FL,FR", (char *[]){ "FL", "FR", NULL }); + test_array(" FL , FR ", (char *[]){ "FL", "FR", NULL }); + test_array("[ FL , FR ]", (char *[]){ "FL", "FR", NULL }); + test_array("[FL FR]", (char *[]){ "FL", "FR", NULL }); + test_array("FL FR", (char *[]){ "FL", "FR", NULL }); +} + int main(int argc, char *argv[]) { test_abi(); test_parse(); test_encode(); + test_arrays(); return 0; }