diff --git a/pipewire-alsa/alsa-plugins/pcm_pipewire.c b/pipewire-alsa/alsa-plugins/pcm_pipewire.c index 4b91e82c0..27495a296 100644 --- a/pipewire-alsa/alsa-plugins/pcm_pipewire.c +++ b/pipewire-alsa/alsa-plugins/pcm_pipewire.c @@ -643,8 +643,11 @@ static int snd_pcm_pipewire_pause(snd_pcm_ioplug_t * io, int enable) #define _FORMAT_BE(p, fmt) p ? SPA_AUDIO_FORMAT_UNKNOWN : SPA_AUDIO_FORMAT_ ## fmt ## _OE #endif -static int set_default_channels(uint32_t channels, uint32_t position[8]) +static int set_default_channels(uint32_t channels, uint32_t *position, uint32_t max_position) { + if (max_position < 8) + return -ENOSPC; + switch (channels) { case 8: position[6] = SPA_AUDIO_CHANNEL_SL; @@ -772,7 +775,8 @@ static int snd_pcm_pipewire_hw_params(snd_pcm_ioplug_t * io, case SPA_MEDIA_SUBTYPE_raw: pw->requested.info.raw.channels = io->channels; pw->requested.info.raw.rate = io->rate; - set_default_channels(io->channels, pw->requested.info.raw.position); + set_default_channels(io->channels, pw->requested.info.raw.position, + SPA_N_ELEMENTS(pw->requested.info.raw.position)); fmt_str = spa_type_audio_format_to_short_name(pw->requested.info.raw.format); pw->format = pw->requested; break; @@ -780,7 +784,8 @@ static int snd_pcm_pipewire_hw_params(snd_pcm_ioplug_t * io, pw->requested.info.dsd.bitorder = SPA_PARAM_BITORDER_msb; pw->requested.info.dsd.channels = io->channels; pw->requested.info.dsd.rate = io->rate * SPA_ABS(pw->requested.info.dsd.interleave); - set_default_channels(io->channels, pw->requested.info.dsd.position); + set_default_channels(io->channels, pw->requested.info.dsd.position, + SPA_N_ELEMENTS(pw->requested.info.dsd.position)); pw->format = pw->requested; /* we need to let the server decide these values */ pw->format.info.dsd.bitorder = 0; @@ -902,26 +907,29 @@ static int snd_pcm_pipewire_set_chmap(snd_pcm_ioplug_t * io, { snd_pcm_pipewire_t *pw = io->private_data; unsigned int i; - uint32_t *position; + uint32_t *position, max_position; switch (pw->requested.media_subtype) { case SPA_MEDIA_SUBTYPE_raw: pw->requested.info.raw.channels = map->channels; position = pw->requested.info.raw.position; + max_position = SPA_N_ELEMENTS(pw->requested.info.raw.position); break; case SPA_MEDIA_SUBTYPE_dsd: pw->requested.info.dsd.channels = map->channels; position = pw->requested.info.dsd.position; + max_position = SPA_N_ELEMENTS(pw->requested.info.dsd.position); break; default: return -EINVAL; } for (i = 0; i < map->channels; i++) { - position[i] = chmap_to_channel(map->pos[i]); + uint32_t pos = chmap_to_channel(map->pos[i]); + if (i < max_position) + position[i] = pos; pw_log_debug("map %d: %s / %s", i, snd_pcm_chmap_name(map->pos[i]), - spa_debug_type_find_short_name(spa_type_audio_channel, - position[i])); + spa_debug_type_find_short_name(spa_type_audio_channel, pos)); } return 1; } @@ -930,16 +938,18 @@ static snd_pcm_chmap_t * snd_pcm_pipewire_get_chmap(snd_pcm_ioplug_t * io) { snd_pcm_pipewire_t *pw = io->private_data; snd_pcm_chmap_t *map; - uint32_t i, channels, *position; + uint32_t i, channels, *position, max_position; switch (pw->requested.media_subtype) { case SPA_MEDIA_SUBTYPE_raw: channels = pw->requested.info.raw.channels; position = pw->requested.info.raw.position; + max_position = SPA_N_ELEMENTS(pw->requested.info.raw.position); break; case SPA_MEDIA_SUBTYPE_dsd: channels = pw->requested.info.dsd.channels; position = pw->requested.info.dsd.position; + max_position = SPA_N_ELEMENTS(pw->requested.info.dsd.position); break; default: return NULL; @@ -949,7 +959,7 @@ static snd_pcm_chmap_t * snd_pcm_pipewire_get_chmap(snd_pcm_ioplug_t * io) channels * sizeof(unsigned int)); map->channels = channels; for (i = 0; i < channels; i++) - map->pos[i] = channel_to_chmap(position[i]); + map->pos[i] = channel_to_chmap(position[i % max_position]); return map; } diff --git a/spa/include/spa/param/audio/raw-utils.h b/spa/include/spa/param/audio/raw-utils.h index 1f1dfe45d..03d6e3ac9 100644 --- a/spa/include/spa/param/audio/raw-utils.h +++ b/spa/include/spa/param/audio/raw-utils.h @@ -29,7 +29,7 @@ extern "C" { #endif SPA_API_AUDIO_RAW_UTILS uint32_t -spa_format_audio_get_position(struct spa_audio_info_raw *info, uint32_t idx) +spa_format_audio_raw_get_position(const struct spa_audio_info_raw *info, uint32_t idx) { uint32_t pos; if (idx < SPA_AUDIO_MAX_CHANNELS) { @@ -41,6 +41,21 @@ spa_format_audio_get_position(struct spa_audio_info_raw *info, uint32_t idx) } return pos; } +SPA_API_AUDIO_RAW_UTILS void +spa_format_audio_raw_set_position(struct spa_audio_info_raw *info, uint32_t idx, uint32_t position) +{ + if (idx < SPA_AUDIO_MAX_CHANNELS) + info->position[idx] = position; +} + +SPA_API_AUDIO_RAW_UTILS uint32_t +spa_format_audio_raw_copy_positions(const struct spa_audio_info_raw *info, uint32_t *position, uint32_t max_position) +{ + uint32_t i, n_pos = SPA_MIN(info->channels, max_position); + for (i = 0; i < n_pos; i++) + position[i] = spa_format_audio_raw_get_position(info, i); + return n_pos; +} SPA_API_AUDIO_RAW_UTILS int spa_format_audio_raw_parse(const struct spa_pod *format, struct spa_audio_info_raw *info) diff --git a/spa/plugins/audioconvert/audioadapter.c b/spa/plugins/audioconvert/audioadapter.c index 0891462a2..26cb4af74 100644 --- a/spa/plugins/audioconvert/audioadapter.c +++ b/spa/plugins/audioconvert/audioadapter.c @@ -2046,11 +2046,12 @@ static int do_auto_port_config(struct impl *this, const char *str) return -ENOENT; if (format.media_subtype == SPA_MEDIA_SUBTYPE_raw) { + uint32_t n_pos = SPA_MIN(SPA_AUDIO_MAX_CHANNELS, format.info.raw.channels); if (position == POSITION_AUX) { - for (i = 0; i < format.info.raw.channels; i++) + for (i = 0; i < n_pos; i++) format.info.raw.position[i] = SPA_AUDIO_CHANNEL_START_Aux + i; } else if (position == POSITION_UNKNOWN) { - for (i = 0; i < format.info.raw.channels; i++) + for (i = 0; i < n_pos; i++) format.info.raw.position[i] = SPA_AUDIO_CHANNEL_UNKNOWN; } } diff --git a/spa/plugins/audioconvert/audioconvert.c b/spa/plugins/audioconvert/audioconvert.c index 2ff270fb1..b91a46ff8 100644 --- a/spa/plugins/audioconvert/audioconvert.c +++ b/spa/plugins/audioconvert/audioconvert.c @@ -1150,7 +1150,7 @@ struct spa_filter_graph_events graph_events = { }; static int setup_filter_graph(struct impl *this, struct filter_graph *g, - uint32_t channels, uint32_t *position) + uint32_t channels, uint32_t *position, uint32_t max_position) { int res; char rate_str[64], in_ports[64]; @@ -1165,8 +1165,9 @@ static int setup_filter_graph(struct impl *this, struct filter_graph *g, snprintf(in_ports, sizeof(in_ports), "%d", channels); g->n_inputs = channels; if (position) { - memcpy(g->inputs_position, position, sizeof(uint32_t) * channels); - memcpy(g->outputs_position, position, sizeof(uint32_t) * channels); + uint32_t n_pos = SPA_MIN(channels, max_position); + memcpy(g->inputs_position, position, sizeof(uint32_t) * n_pos); + memcpy(g->outputs_position, position, sizeof(uint32_t) * n_pos); } } @@ -1181,7 +1182,7 @@ static int setup_filter_graph(struct impl *this, struct filter_graph *g, return res; } -static int setup_channelmix(struct impl *this, uint32_t channels, uint32_t *position); +static int setup_channelmix(struct impl *this, uint32_t channels, uint32_t *position, uint32_t max_position); static void free_tmp(struct impl *this) { @@ -1263,7 +1264,7 @@ static int ensure_tmp(struct impl *this) static int setup_filter_graphs(struct impl *impl, bool force) { int res; - uint32_t channels, *position; + uint32_t channels, *position, max_position; struct dir *in, *out; struct filter_graph *g, *t; @@ -1272,6 +1273,7 @@ static int setup_filter_graphs(struct impl *impl, bool force) channels = in->format.info.raw.channels; position = in->format.info.raw.position; + max_position = SPA_N_ELEMENTS(in->format.info.raw.position); impl->maxports = SPA_MAX(in->format.info.raw.channels, out->format.info.raw.channels); spa_list_for_each_safe(g, t, &impl->active_graphs, link) { @@ -1279,19 +1281,20 @@ static int setup_filter_graphs(struct impl *impl, bool force) continue; if (force) g->setup = false; - if ((res = setup_filter_graph(impl, g, channels, position)) < 0) { + if ((res = setup_filter_graph(impl, g, channels, position, max_position)) < 0) { g->removing = true; spa_log_warn(impl->log, "failed to activate graph %d: %s", g->order, spa_strerror(res)); } else { channels = g->n_outputs; position = g->outputs_position; + max_position = SPA_N_ELEMENTS(g->outputs_position); impl->maxports = SPA_MAX(impl->maxports, channels); } } if ((res = ensure_tmp(impl)) < 0) return res; - if ((res = setup_channelmix(impl, channels, position)) < 0) + if ((res = setup_channelmix(impl, channels, position, max_position)) < 0) return res; return 0; @@ -1896,10 +1899,11 @@ static int reconfigure_mode(struct impl *this, enum spa_param_port_config_mode m this->dir[SPA_DIRECTION_OUTPUT].n_ports = dir->n_ports + 1; for (i = 0; i < dir->n_ports; i++) { - init_port(this, direction, i, info->info.raw.position[i], true, false, false); + uint32_t pos = spa_format_audio_raw_get_position(&info->info.raw, i); + init_port(this, direction, i, pos, true, false, false); if (this->monitor && direction == SPA_DIRECTION_INPUT) init_port(this, SPA_DIRECTION_OUTPUT, i+1, - info->info.raw.position[i], true, true, false); + pos, true, true, false); } break; } @@ -2056,24 +2060,25 @@ static int setup_in_convert(struct impl *this) dst_info.info.raw.channels, dst_info.info.raw.rate); - qsort(dst_info.info.raw.position, dst_info.info.raw.channels, + qsort(dst_info.info.raw.position, SPA_MIN(dst_info.info.raw.channels, SPA_AUDIO_MAX_CHANNELS), sizeof(uint32_t), int32_cmp); for (i = 0; i < src_info.info.raw.channels; i++) { for (j = 0; j < dst_info.info.raw.channels; j++) { - if (src_info.info.raw.position[i] != - dst_info.info.raw.position[j]) + uint32_t pi, pj; + + pi = spa_format_audio_raw_get_position(&src_info.info.raw, i); + pj = spa_format_audio_raw_get_position(&dst_info.info.raw, j); + if (pi != pj) continue; in->remap[i] = j; if (i != j) remap = true; spa_log_debug(this->log, "%p: channel %d (%d) -> %d (%s -> %s)", this, i, in->remap[i], j, - spa_debug_type_find_short_name(spa_type_audio_channel, - src_info.info.raw.position[i]), - spa_debug_type_find_short_name(spa_type_audio_channel, - dst_info.info.raw.position[j])); - dst_info.info.raw.position[j] = -1; + spa_debug_type_find_short_name(spa_type_audio_channel, pi), + spa_debug_type_find_short_name(spa_type_audio_channel, pj)); + spa_format_audio_raw_set_position(&dst_info.info.raw, j, -1); break; } } @@ -2121,9 +2126,10 @@ static int remap_volumes(struct impl *this, const struct spa_audio_info *info) for (i = 0; i < p->n_channels; i++) { for (j = i; j < target; j++) { + uint32_t pj = spa_format_audio_raw_get_position(&info->info.raw, j); spa_log_debug(this->log, "%d %d: %d <-> %d", i, j, - p->channel_map[i], info->info.raw.position[j]); - if (p->channel_map[i] != info->info.raw.position[j]) + p->channel_map[i], pj); + if (p->channel_map[i] != pj) continue; if (i != j) { SPA_SWAP(p->channel_map[i], p->channel_map[j]); @@ -2136,7 +2142,7 @@ static int remap_volumes(struct impl *this, const struct spa_audio_info *info) } p->n_channels = target; for (i = 0; i < p->n_channels; i++) - p->channel_map[i] = info->info.raw.position[i]; + p->channel_map[i] = spa_format_audio_raw_get_position(&info->info.raw, i); if (target == 0) return 0; @@ -2182,17 +2188,17 @@ static void set_volume(struct impl *this) this->params[IDX_Props].user++; } -static char *format_position(char *str, size_t len, uint32_t channels, uint32_t *position) +static char *format_position(char *str, size_t len, uint32_t channels, uint32_t *position, uint32_t max_position) { uint32_t i, idx = 0; for (i = 0; i < channels; i++) idx += snprintf(str + idx, len - idx, "%s%s", i == 0 ? "" : " ", spa_debug_type_find_short_name(spa_type_audio_channel, - position[i])); + position[i % max_position])); return str; } -static int setup_channelmix(struct impl *this, uint32_t channels, uint32_t *position) +static int setup_channelmix(struct impl *this, uint32_t channels, uint32_t *position, uint32_t max_position) { struct dir *in = &this->dir[SPA_DIRECTION_INPUT]; struct dir *out = &this->dir[SPA_DIRECTION_OUTPUT]; @@ -2205,18 +2211,18 @@ static int setup_channelmix(struct impl *this, uint32_t channels, uint32_t *posi dst_chan = out->format.info.raw.channels; for (i = 0, src_mask = 0; i < src_chan; i++) { - p = position[i]; + p = position[i % max_position]; src_mask |= 1ULL << (p < 64 ? p : 0); } for (i = 0, dst_mask = 0; i < dst_chan; i++) { - p = out->format.info.raw.position[i]; + p = spa_format_audio_raw_get_position(&out->format.info.raw, i); dst_mask |= 1ULL << (p < 64 ? p : 0); } spa_log_info(this->log, "in %s (%016"PRIx64")", format_position(str, sizeof(str), - src_chan, position), src_mask); + src_chan, position, max_position), src_mask); spa_log_info(this->log, "out %s (%016"PRIx64")", format_position(str, sizeof(str), - dst_chan, out->format.info.raw.position), dst_mask); + dst_chan, out->format.info.raw.position, SPA_AUDIO_MAX_CHANNELS), dst_mask); spa_log_info(this->log, "%p: %s/%d@%d->%s/%d@%d %08"PRIx64":%08"PRIx64, this, spa_debug_type_find_name(spa_type_audio_format, SPA_AUDIO_FORMAT_DSP_F32), @@ -2344,13 +2350,16 @@ static int setup_out_convert(struct impl *this) dst_info.info.raw.channels, dst_info.info.raw.rate); - qsort(src_info.info.raw.position, src_info.info.raw.channels, + qsort(src_info.info.raw.position, SPA_MIN(src_info.info.raw.channels, SPA_AUDIO_MAX_CHANNELS), sizeof(uint32_t), int32_cmp); for (i = 0; i < src_info.info.raw.channels; i++) { for (j = 0; j < dst_info.info.raw.channels; j++) { - if (src_info.info.raw.position[i] != - dst_info.info.raw.position[j]) + uint32_t pi, pj; + + pi = spa_format_audio_raw_get_position(&src_info.info.raw, i); + pj = spa_format_audio_raw_get_position(&dst_info.info.raw, j); + if (pi != pj) continue; out->remap[i] = j; if (i != j) @@ -2358,11 +2367,10 @@ static int setup_out_convert(struct impl *this) spa_log_debug(this->log, "%p: channel %d (%d) -> %d (%s -> %s)", this, i, out->remap[i], j, - spa_debug_type_find_short_name(spa_type_audio_channel, - src_info.info.raw.position[i]), - spa_debug_type_find_short_name(spa_type_audio_channel, - dst_info.info.raw.position[j])); - dst_info.info.raw.position[j] = -1; + spa_debug_type_find_short_name(spa_type_audio_channel, pi), + spa_debug_type_find_short_name(spa_type_audio_channel, pj)); + + spa_format_audio_raw_set_position(&dst_info.info.raw, j, -1); break; } } diff --git a/spa/plugins/bluez5/a2dp-codec-opus.c b/spa/plugins/bluez5/a2dp-codec-opus.c index d9cdc9a0e..7a330e8e0 100644 --- a/spa/plugins/bluez5/a2dp-codec-opus.c +++ b/spa/plugins/bluez5/a2dp-codec-opus.c @@ -497,7 +497,7 @@ static void get_default_bitrates(const struct media_codec *codec, bool bidi, int static int get_mapping(const struct media_codec *codec, const a2dp_opus_05_direction_t *conf, bool use_surround_encoder, uint8_t *streams_ret, uint8_t *coupled_streams_ret, - const uint8_t **surround_mapping, uint32_t *positions) + const uint8_t **surround_mapping, uint32_t *positions, uint32_t max_positions) { const uint32_t channels = conf->channels; const uint32_t location = OPUS_05_GET_LOCATION(*conf); @@ -544,13 +544,13 @@ static int get_mapping(const struct media_codec *codec, const a2dp_opus_05_direc const struct audio_location loc = audio_locations[i]; if (location & loc.mask) { - if (permutation) - positions[permutation[j++]] = loc.position; - else - positions[j++] = loc.position; + uint32_t idx = permutation ? permutation[j] : j; + if (idx < max_positions) + positions[idx] = loc.position; + j++; } } - for (i = SPA_AUDIO_CHANNEL_START_Aux; j < channels; ++i, ++j) + for (i = SPA_AUDIO_CHANNEL_START_Aux; j < channels && j < max_positions; ++i, ++j) positions[j] = i; } @@ -785,7 +785,7 @@ static int codec_enum_config(const struct media_codec *codec, uint32_t flags, dir = !is_duplex_codec(codec) ? &conf.main : &conf.bidi; - if (get_mapping(codec, dir, surround_encoder, NULL, NULL, NULL, position) < 0) + if (get_mapping(codec, dir, surround_encoder, NULL, NULL, NULL, position, MAX_CHANNELS) < 0) return -EINVAL; spa_pod_builder_push_object(b, &f[0], SPA_TYPE_OBJECT_Format, id); @@ -837,9 +837,10 @@ static int codec_validate_config(const struct media_codec *codec, uint32_t flags } info->info.raw.channels = dir1->channels; - if (get_mapping(codec, dir1, surround_encoder, NULL, NULL, NULL, info->info.raw.position) < 0) + if (get_mapping(codec, dir1, surround_encoder, NULL, NULL, NULL, + info->info.raw.position, SPA_N_ELEMENTS(info->info.raw.position)) < 0) return -EINVAL; - if (get_mapping(codec, dir2, surround_encoder, NULL, NULL, NULL, NULL) < 0) + if (get_mapping(codec, dir2, surround_encoder, NULL, NULL, NULL, NULL, 0) < 0) return -EINVAL; return 0; @@ -930,7 +931,7 @@ static void *codec_init(const struct media_codec *codec, uint32_t flags, if ((res = codec_validate_config(codec, flags, config, config_len, &config_info)) < 0) goto error; if ((res = get_mapping(codec, dir, surround_encoder, &this->streams, &this->coupled_streams, - &enc_mapping, NULL)) < 0) + &enc_mapping, NULL, 0)) < 0) goto error; if (config_info.info.raw.channels != info->info.raw.channels) { res = -EINVAL; diff --git a/spa/plugins/bluez5/bluez5-dbus.c b/spa/plugins/bluez5/bluez5-dbus.c index d4305c535..2e92696bc 100644 --- a/spa/plugins/bluez5/bluez5-dbus.c +++ b/spa/plugins/bluez5/bluez5-dbus.c @@ -35,6 +35,7 @@ #include #include #include +#include #include #include "codec-loader.h" @@ -5038,8 +5039,8 @@ static DBusHandlerResult endpoint_set_configuration(DBusConnection *conn, return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; } transport->n_channels = info.info.raw.channels; - memcpy(transport->channels, info.info.raw.position, - transport->n_channels * sizeof(uint32_t)); + spa_format_audio_raw_copy_positions(&info.info.raw, + transport->channels, SPA_N_ELEMENTS(transport->channels)); } else { transport->n_channels = 2; transport->channels[0] = SPA_AUDIO_CHANNEL_FL; diff --git a/spa/plugins/bluez5/bluez5-device.c b/spa/plugins/bluez5/bluez5-device.c index aee6d8cab..838bb54f3 100644 --- a/spa/plugins/bluez5/bluez5-device.c +++ b/spa/plugins/bluez5/bluez5-device.c @@ -26,6 +26,7 @@ #include #include #include +#include #include #include #include @@ -451,7 +452,8 @@ static int node_offload_set_active(struct node *node, bool active) return res; } -static void get_channels(struct spa_bt_transport *t, bool a2dp_duplex, uint32_t *n_channels, uint32_t *channels) +static void get_channels(struct spa_bt_transport *t, bool a2dp_duplex, uint32_t *n_channels, uint32_t *channels, + uint32_t max_channels) { const struct media_codec *codec; struct spa_audio_info info = { 0 }; @@ -473,9 +475,7 @@ static void get_channels(struct spa_bt_transport *t, bool a2dp_duplex, uint32_t return; } - *n_channels = info.info.raw.channels; - memcpy(channels, info.info.raw.position, - info.info.raw.channels * sizeof(uint32_t)); + *n_channels = spa_format_audio_raw_copy_positions(&info.info.raw, channels, max_channels); } static const char *get_channel_name(uint32_t channel) @@ -686,7 +686,7 @@ static void emit_node(struct impl *this, struct spa_bt_transport *t, this->nodes[id].active = true; this->nodes[id].offload_acquired = false; this->nodes[id].a2dp_duplex = a2dp_duplex; - get_channels(t, a2dp_duplex, &this->nodes[id].n_channels, this->nodes[id].channels); + get_channels(t, a2dp_duplex, &this->nodes[id].n_channels, this->nodes[id].channels, MAX_CHANNELS); if (this->nodes[id].transport) spa_hook_remove(&this->nodes[id].transport_listener); this->nodes[id].transport = t; diff --git a/spa/plugins/support/null-audio-sink.c b/spa/plugins/support/null-audio-sink.c index 27ae8d0f0..acaec6f7b 100644 --- a/spa/plugins/support/null-audio-sink.c +++ b/spa/plugins/support/null-audio-sink.c @@ -637,7 +637,7 @@ port_set_format(struct impl *this, if (info.info.raw.rate == 0 || info.info.raw.channels == 0 || - info.info.raw.channels > SPA_N_ELEMENTS(info.info.raw.position)) + info.info.raw.channels > MAX_CHANNELS) return -EINVAL; if (this->props.format != 0) { diff --git a/spa/plugins/volume/volume.c b/spa/plugins/volume/volume.c index 7881703db..0c750a96a 100644 --- a/spa/plugins/volume/volume.c +++ b/spa/plugins/volume/volume.c @@ -454,8 +454,7 @@ static int port_set_format(void *object, return -EINVAL; if (info.info.raw.format != SPA_AUDIO_FORMAT_S16 || - info.info.raw.channels == 0 || - info.info.raw.channels > SPA_N_ELEMENTS(info.info.raw.position)) + info.info.raw.channels == 0) return -EINVAL; this->bpf = 2 * info.info.raw.channels; diff --git a/src/examples/export-source.c b/src/examples/export-source.c index 3d3859273..a0e983de1 100644 --- a/src/examples/export-source.c +++ b/src/examples/export-source.c @@ -268,8 +268,7 @@ static int port_set_format(void *object, d->format.format != SPA_AUDIO_FORMAT_F32) return -EINVAL; if (d->format.rate == 0 || - d->format.channels == 0 || - d->format.channels > SPA_N_ELEMENTS(d->format.position)) + d->format.channels == 0) return -EINVAL; } diff --git a/src/modules/module-combine-stream.c b/src/modules/module-combine-stream.c index 54a98970b..a9dec8c2b 100644 --- a/src/modules/module-combine-stream.c +++ b/src/modules/module-combine-stream.c @@ -882,7 +882,10 @@ static int create_stream(struct stream_info *info) for (i = 0; i < remap_info.channels; i++) { s->remap[i] = i; for (j = 0; j < tmp_info.channels; j++) { - if (tmp_info.position[j] == remap_info.position[i]) { + uint32_t pj, pi; + pj = spa_format_audio_raw_get_position(&tmp_info, j); + pi = spa_format_audio_raw_get_position(&remap_info, i); + if (pj == pi) { s->remap[i] = j; break; } diff --git a/src/modules/module-example-filter.c b/src/modules/module-example-filter.c index 92f1f38cb..6dcb155cc 100644 --- a/src/modules/module-example-filter.c +++ b/src/modules/module-example-filter.c @@ -298,8 +298,7 @@ static void capture_param_changed(void *data, uint32_t id, const struct spa_pod if (spa_format_audio_raw_parse(param, &info) < 0) return; if (info.rate == 0 || - info.channels == 0 || - info.channels > SPA_N_ELEMENTS(info.position)) + info.channels == 0) return; break; } diff --git a/src/modules/module-ffado-driver.c b/src/modules/module-ffado-driver.c index db6fe8b71..521899433 100644 --- a/src/modules/module-ffado-driver.c +++ b/src/modules/module-ffado-driver.c @@ -1229,7 +1229,7 @@ static int probe_ffado_device(struct impl *impl) } if (impl->source.info.channels != n_channels) { impl->source.info.channels = n_channels; - for (i = 0; i < SPA_MIN(impl->source.info.channels, MAX_CHANNELS); i++) + for (i = 0; i < SPA_MIN(impl->source.info.channels, SPA_AUDIO_MAX_CHANNELS); i++) impl->source.info.position[i] = SPA_AUDIO_CHANNEL_AUX0 + i; } @@ -1255,7 +1255,7 @@ static int probe_ffado_device(struct impl *impl) } if (impl->sink.info.channels != n_channels) { impl->sink.info.channels = n_channels; - for (i = 0; i < SPA_MIN(impl->sink.info.channels, MAX_CHANNELS); i++) + for (i = 0; i < SPA_MIN(impl->sink.info.channels, SPA_AUDIO_MAX_CHANNELS); i++) impl->sink.info.position[i] = SPA_AUDIO_CHANNEL_AUX0 + i; } diff --git a/src/modules/module-filter-chain.c b/src/modules/module-filter-chain.c index 84b70d651..cdfcd0ecf 100644 --- a/src/modules/module-filter-chain.c +++ b/src/modules/module-filter-chain.c @@ -1691,7 +1691,7 @@ static void copy_position(struct spa_audio_info_raw *dst, const struct spa_audio { if (SPA_FLAG_IS_SET(dst->flags, SPA_AUDIO_FLAG_UNPOSITIONED) && !SPA_FLAG_IS_SET(src->flags, SPA_AUDIO_FLAG_UNPOSITIONED)) { - for (uint32_t i = 0; i < src->channels; i++) + for (uint32_t i = 0; i < SPA_MIN(src->channels, SPA_AUDIO_MAX_CHANNELS); i++) dst->position[i] = src->position[i]; SPA_FLAG_CLEAR(dst->flags, SPA_AUDIO_FLAG_UNPOSITIONED); } diff --git a/src/modules/module-jack-tunnel.c b/src/modules/module-jack-tunnel.c index f5066abc4..0e1b3c3fb 100644 --- a/src/modules/module-jack-tunnel.c +++ b/src/modules/module-jack-tunnel.c @@ -524,7 +524,7 @@ static void make_stream_ports(struct stream *s) if (i < s->info.channels) { str = spa_debug_type_find_short_name(spa_type_audio_channel, - s->info.position[i]); + spa_format_audio_raw_get_position(&s->info, i)); if (str) snprintf(name, sizeof(name), "%s_%s", prefix, str); else diff --git a/src/modules/module-loopback.c b/src/modules/module-loopback.c index ce1da189d..365e6c5b9 100644 --- a/src/modules/module-loopback.c +++ b/src/modules/module-loopback.c @@ -538,8 +538,7 @@ static void param_format_changed(struct impl *impl, const struct spa_pod *param, spa_zero(info); if (param != NULL) { if (spa_format_audio_raw_parse(param, &info) < 0 || - info.channels == 0 || - info.channels > SPA_N_ELEMENTS(info.position)) + info.channels == 0) return; if ((impl->info.format != 0 && impl->info.format != info.format) || @@ -547,7 +546,7 @@ static void param_format_changed(struct impl *impl, const struct spa_pod *param, (impl->info.channels != 0 && (impl->info.channels != info.channels || memcmp(impl->info.position, info.position, - info.channels * sizeof(uint32_t)) != 0))) { + SPA_MIN(info.channels, SPA_AUDIO_MAX_CHANNELS) * sizeof(uint32_t)) != 0))) { uint8_t buffer[1024]; struct spa_pod_builder b; const struct spa_pod *params[1]; diff --git a/src/modules/module-netjack2-driver.c b/src/modules/module-netjack2-driver.c index f1aefaa35..5e3149b41 100644 --- a/src/modules/module-netjack2-driver.c +++ b/src/modules/module-netjack2-driver.c @@ -442,7 +442,7 @@ static void make_stream_ports(struct stream *s) if (i < s->info.channels) { str = spa_debug_type_find_short_name(spa_type_audio_channel, - s->info.position[i % SPA_N_ELEMENTS(s->info.position)]); + spa_format_audio_raw_get_position(&s->info, i)); props = pw_properties_new( PW_KEY_FORMAT_DSP, "32 bit float mono audio", PW_KEY_AUDIO_CHANNEL, str ? str : "UNK", @@ -863,10 +863,10 @@ static int handle_follower_setup(struct impl *impl, struct nj2_session_params *p } impl->sink.info.rate = peer->params.sample_rate; if ((uint32_t)peer->params.send_audio_channels != impl->sink.info.channels) { - impl->sink.info.channels = SPA_MIN(peer->params.send_audio_channels, - (int)SPA_N_ELEMENTS(impl->sink.info.position)); + impl->sink.info.channels = peer->params.send_audio_channels; for (i = 0; i < impl->sink.info.channels; i++) - impl->sink.info.position[i] = SPA_AUDIO_CHANNEL_AUX0 + i; + spa_format_audio_raw_set_position(&impl->sink.info, i, + SPA_AUDIO_CHANNEL_AUX0 + i); } impl->source.n_ports = peer->params.recv_audio_channels + peer->params.recv_midi_channels; if (impl->source.n_ports > MAX_PORTS) { @@ -875,10 +875,10 @@ static int handle_follower_setup(struct impl *impl, struct nj2_session_params *p } impl->source.info.rate = peer->params.sample_rate; if ((uint32_t)peer->params.recv_audio_channels != impl->source.info.channels) { - impl->source.info.channels = SPA_MIN(peer->params.recv_audio_channels, - (int)SPA_N_ELEMENTS(impl->source.info.position)); + impl->source.info.channels = peer->params.recv_audio_channels; for (i = 0; i < impl->source.info.channels; i++) - impl->source.info.position[i] = SPA_AUDIO_CHANNEL_AUX0 + i; + spa_format_audio_raw_set_position(&impl->source.info, i, + SPA_AUDIO_CHANNEL_AUX0 + i); } impl->samplerate = peer->params.sample_rate; impl->period_size = peer->params.period_size; diff --git a/src/modules/module-netjack2-manager.c b/src/modules/module-netjack2-manager.c index 6b3285305..454632c8f 100644 --- a/src/modules/module-netjack2-manager.c +++ b/src/modules/module-netjack2-manager.c @@ -602,7 +602,7 @@ static void make_stream_ports(struct stream *s) if (i < s->info.channels) { str = spa_debug_type_find_short_name(spa_type_audio_channel, - s->info.position[i]); + spa_format_audio_raw_get_position(&s->info, i)); props = pw_properties_new( PW_KEY_FORMAT_DSP, "32 bit float mono audio", @@ -1026,18 +1026,18 @@ static int handle_follower_available(struct impl *impl, struct nj2_session_param follower->source.n_ports = peer->params.recv_audio_channels + peer->params.recv_midi_channels; follower->source.info.rate = peer->params.sample_rate; if ((uint32_t)peer->params.recv_audio_channels != follower->source.info.channels) { - follower->source.info.channels = SPA_MIN(peer->params.recv_audio_channels, - (int)SPA_N_ELEMENTS(follower->source.info.position)); + follower->source.info.channels = peer->params.recv_audio_channels; for (i = 0; i < follower->source.info.channels; i++) - follower->source.info.position[i] = SPA_AUDIO_CHANNEL_AUX0 + i; + spa_format_audio_raw_set_position(&follower->source.info, i, + SPA_AUDIO_CHANNEL_AUX0 + i); } follower->sink.n_ports = peer->params.send_audio_channels + peer->params.send_midi_channels; follower->sink.info.rate = peer->params.sample_rate; if ((uint32_t)peer->params.send_audio_channels != follower->sink.info.channels) { - follower->sink.info.channels = SPA_MIN(peer->params.send_audio_channels, - (int)SPA_N_ELEMENTS(follower->sink.info.position)); + follower->sink.info.channels = peer->params.send_audio_channels; for (i = 0; i < follower->sink.info.channels; i++) - follower->sink.info.position[i] = SPA_AUDIO_CHANNEL_AUX0 + i; + spa_format_audio_raw_set_position(&follower->sink.info, i, + SPA_AUDIO_CHANNEL_AUX0 + i); } if (follower->source.n_ports > MAX_PORTS || follower->sink.n_ports > MAX_PORTS) { diff --git a/src/modules/module-protocol-pulse/format.c b/src/modules/module-protocol-pulse/format.c index 189e60f17..8c417446f 100644 --- a/src/modules/module-protocol-pulse/format.c +++ b/src/modules/module-protocol-pulse/format.c @@ -348,9 +348,9 @@ uint32_t channel_paname2id(const char *name, size_t size) } -void channel_map_to_positions(const struct channel_map *map, uint32_t *pos) +void channel_map_to_positions(const struct channel_map *map, uint32_t *pos, uint32_t max_pos) { - uint32_t i, channels = SPA_MIN(map->channels, SPA_AUDIO_MAX_CHANNELS); + uint32_t i, channels = SPA_MIN(map->channels, max_pos); for (i = 0; i < channels; i++) pos[i] = map->map[i]; } @@ -535,8 +535,7 @@ int format_parse_param(const struct spa_pod *param, bool collect, info.info.raw.rate = 48000; if (info.info.raw.format == 0 || info.info.raw.rate == 0 || - info.info.raw.channels == 0 || - info.info.raw.channels > SPA_N_ELEMENTS(info.info.raw.position)) + info.info.raw.channels == 0) return -ENOTSUP; } break; @@ -586,7 +585,7 @@ int format_parse_param(const struct spa_pod *param, bool collect, if (info.info.raw.channels) { map->channels = SPA_MIN(info.info.raw.channels, CHANNELS_MAX); for (i = 0; i < map->channels; i++) - map->map[i] = info.info.raw.position[i]; + map->map[i] = spa_format_audio_raw_get_position(&info.info.raw, i); } } return 0; @@ -634,8 +633,8 @@ const struct spa_pod *format_build_param(struct spa_pod_builder *b, uint32_t id, SPA_FORMAT_AUDIO_channels, SPA_POD_Int(spec->channels), 0); if (map && map->channels == spec->channels) { - uint32_t positions[SPA_AUDIO_MAX_CHANNELS]; - channel_map_to_positions(map, positions); + uint32_t positions[spec->channels]; + channel_map_to_positions(map, positions, spec->channels); spa_pod_builder_add(b, SPA_FORMAT_AUDIO_position, SPA_POD_Array(sizeof(uint32_t), SPA_TYPE_Id, spec->channels, positions), 0); diff --git a/src/modules/module-protocol-pulse/format.h b/src/modules/module-protocol-pulse/format.h index d564b1822..41cfb4f9d 100644 --- a/src/modules/module-protocol-pulse/format.h +++ b/src/modules/module-protocol-pulse/format.h @@ -196,7 +196,7 @@ enum channel_position channel_id2pa(uint32_t id, uint32_t *aux); const char *channel_id2paname(uint32_t id, uint32_t *aux); uint32_t channel_paname2id(const char *name, size_t size); -void channel_map_to_positions(const struct channel_map *map, uint32_t *pos); +void channel_map_to_positions(const struct channel_map *map, uint32_t *pos, uint32_t max_pos); void channel_map_parse(const char *str, struct channel_map *map); bool channel_map_valid(const struct channel_map *map); void channel_map_parse_position(const char *str, struct channel_map *map); diff --git a/src/modules/module-protocol-pulse/module.c b/src/modules/module-protocol-pulse/module.c index a0de01d0d..58bcce52b 100644 --- a/src/modules/module-protocol-pulse/module.c +++ b/src/modules/module-protocol-pulse/module.c @@ -12,6 +12,7 @@ #include #include #include +#include #include #include #include @@ -226,14 +227,15 @@ int module_args_to_audioinfo_keys(struct impl *impl, struct pw_properties *props info->channels, map.channels); return -EINVAL; } - channel_map_to_positions(&map, info->position); + channel_map_to_positions(&map, info->position, SPA_N_ELEMENTS(info->position)); pw_properties_set(props, key_channel_map, NULL); } else { if (info->channels == 0) info->channels = impl->defs.sample_spec.channels; if (info->channels == impl->defs.channel_map.channels) { - channel_map_to_positions(&impl->defs.channel_map, info->position); + channel_map_to_positions(&impl->defs.channel_map, + info->position, SPA_N_ELEMENTS(info->position)); } else if (info->channels == 1) { info->position[0] = SPA_AUDIO_CHANNEL_MONO; } else if (info->channels == 2) { @@ -242,7 +244,7 @@ int module_args_to_audioinfo_keys(struct impl *impl, struct pw_properties *props } else { /* FIXME add more mappings */ for (i = 0; i < info->channels; i++) - info->position[i] = SPA_AUDIO_CHANNEL_UNKNOWN; + spa_format_audio_raw_set_position(info, i, SPA_AUDIO_CHANNEL_UNKNOWN); } if (info->position[0] == SPA_AUDIO_CHANNEL_UNKNOWN) info->flags |= SPA_AUDIO_FLAG_UNPOSITIONED; @@ -288,7 +290,7 @@ void audioinfo_to_properties(struct spa_audio_info_raw *info, struct pw_properti p = s = alloca(info->channels * 8); for (i = 0; i < info->channels; i++) p += spa_scnprintf(p, 8, "%s%s", i == 0 ? "" : ", ", - channel_id2name(info->position[i])); + channel_id2name(spa_format_audio_raw_get_position(info, i))); pw_properties_setf(props, SPA_KEY_AUDIO_POSITION, "[ %s ]", s); } } diff --git a/src/modules/module-pulse-tunnel.c b/src/modules/module-pulse-tunnel.c index afda6f484..8849f7190 100644 --- a/src/modules/module-pulse-tunnel.c +++ b/src/modules/module-pulse-tunnel.c @@ -754,7 +754,8 @@ static int create_pulse_stream(struct impl *impl) map.channels = impl->info.channels; for (i = 0; i < map.channels; i++) - map.map[i] = (pa_channel_position_t)channel_id2pa(impl->info.position[i], &aux); + map.map[i] = (pa_channel_position_t)channel_id2pa( + spa_format_audio_raw_get_position(&impl->info, i), &aux); snprintf(stream_name, sizeof(stream_name), _("Tunnel for %s@%s"), pw_get_user_name(), pw_get_host_name()); diff --git a/src/modules/module-vban/stream.c b/src/modules/module-vban/stream.c index 3a7a31827..4ae0eacd1 100644 --- a/src/modules/module-vban/stream.c +++ b/src/modules/module-vban/stream.c @@ -215,16 +215,16 @@ static const struct spa_audio_layout_info layouts[] = { { SPA_AUDIO_LAYOUT_7_1 }, }; -static void default_layout(uint32_t channels, uint32_t *position) +static void default_layout(uint32_t channels, uint32_t *position, uint32_t max_position) { SPA_FOR_EACH_ELEMENT_VAR(layouts, l) { if (l->n_channels == channels) { - for (uint32_t i = 0; i < l->n_channels; i++) + for (uint32_t i = 0; i < l->n_channels && i < max_position; i++) position[i] = l->position[i]; return; } } - for (uint32_t i = 0; i < channels; i++) + for (uint32_t i = 0; i < channels && i < max_position; i++) position[i] = SPA_AUDIO_CHANNEL_AUX0 + i; } @@ -276,7 +276,9 @@ struct vban_stream *vban_stream_new(struct pw_core *core, case SPA_MEDIA_SUBTYPE_raw: parse_audio_info(props, &impl->info.info.raw); if (SPA_FLAG_IS_SET(impl->info.info.raw.flags, SPA_AUDIO_FLAG_UNPOSITIONED)) - default_layout(impl->info.info.raw.channels, impl->info.info.raw.position); + default_layout(impl->info.info.raw.channels, + impl->info.info.raw.position, + SPA_N_ELEMENTS(impl->info.info.raw.position)); impl->stream_info = impl->info; impl->format_info = find_audio_format_info(&impl->info); if (impl->format_info == NULL) { diff --git a/src/modules/module-zeroconf-discover.c b/src/modules/module-zeroconf-discover.c index e165a1174..35e48279b 100644 --- a/src/modules/module-zeroconf-discover.c +++ b/src/modules/module-zeroconf-discover.c @@ -192,7 +192,7 @@ static void pw_properties_from_avahi_string(const char *key, const char *value, spa_zero(channel_map); channel_map_parse(value, &channel_map); - channel_map_to_positions(&channel_map, pos); + channel_map_to_positions(&channel_map, pos, CHANNELS_MAX); p = s = alloca(4 + channel_map.channels * 8); p += spa_scnprintf(p, 2, "["); diff --git a/src/tools/pw-cat.c b/src/tools/pw-cat.c index 0fefa2377..52789d421 100644 --- a/src/tools/pw-cat.c +++ b/src/tools/pw-cat.c @@ -2347,9 +2347,11 @@ int main(int argc, char *argv[]) .rate = data.rate, .channels = data.channels); - if (data.channelmap.n_channels) - memcpy(info.position, data.channelmap.channels, data.channels * sizeof(int)); - + if (data.channelmap.n_channels) { + uint32_t i, n_pos = SPA_MIN(data.channels, SPA_N_ELEMENTS(info.position)); + for (i = 0; i < n_pos; i++) + info.position[i] = data.channelmap.channels[i]; + } params[n_params++] = spa_format_audio_raw_build(&b, SPA_PARAM_EnumFormat, &info); break; }