treewide: access the position information using helpers

Make sure we don't access out of bounds and that we use the helpers
wherever we can to access the position information.
This commit is contained in:
Wim Taymans 2025-10-21 13:06:25 +02:00
parent 8bbca3b8f3
commit 818d1435ce
25 changed files with 155 additions and 114 deletions

View file

@ -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 #define _FORMAT_BE(p, fmt) p ? SPA_AUDIO_FORMAT_UNKNOWN : SPA_AUDIO_FORMAT_ ## fmt ## _OE
#endif #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) { switch (channels) {
case 8: case 8:
position[6] = SPA_AUDIO_CHANNEL_SL; 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: case SPA_MEDIA_SUBTYPE_raw:
pw->requested.info.raw.channels = io->channels; pw->requested.info.raw.channels = io->channels;
pw->requested.info.raw.rate = io->rate; 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); fmt_str = spa_type_audio_format_to_short_name(pw->requested.info.raw.format);
pw->format = pw->requested; pw->format = pw->requested;
break; 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.bitorder = SPA_PARAM_BITORDER_msb;
pw->requested.info.dsd.channels = io->channels; pw->requested.info.dsd.channels = io->channels;
pw->requested.info.dsd.rate = io->rate * SPA_ABS(pw->requested.info.dsd.interleave); 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; pw->format = pw->requested;
/* we need to let the server decide these values */ /* we need to let the server decide these values */
pw->format.info.dsd.bitorder = 0; 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; snd_pcm_pipewire_t *pw = io->private_data;
unsigned int i; unsigned int i;
uint32_t *position; uint32_t *position, max_position;
switch (pw->requested.media_subtype) { switch (pw->requested.media_subtype) {
case SPA_MEDIA_SUBTYPE_raw: case SPA_MEDIA_SUBTYPE_raw:
pw->requested.info.raw.channels = map->channels; pw->requested.info.raw.channels = map->channels;
position = pw->requested.info.raw.position; position = pw->requested.info.raw.position;
max_position = SPA_N_ELEMENTS(pw->requested.info.raw.position);
break; break;
case SPA_MEDIA_SUBTYPE_dsd: case SPA_MEDIA_SUBTYPE_dsd:
pw->requested.info.dsd.channels = map->channels; pw->requested.info.dsd.channels = map->channels;
position = pw->requested.info.dsd.position; position = pw->requested.info.dsd.position;
max_position = SPA_N_ELEMENTS(pw->requested.info.dsd.position);
break; break;
default: default:
return -EINVAL; return -EINVAL;
} }
for (i = 0; i < map->channels; i++) { 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, pw_log_debug("map %d: %s / %s", i,
snd_pcm_chmap_name(map->pos[i]), snd_pcm_chmap_name(map->pos[i]),
spa_debug_type_find_short_name(spa_type_audio_channel, spa_debug_type_find_short_name(spa_type_audio_channel, pos));
position[i]));
} }
return 1; 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_pipewire_t *pw = io->private_data;
snd_pcm_chmap_t *map; snd_pcm_chmap_t *map;
uint32_t i, channels, *position; uint32_t i, channels, *position, max_position;
switch (pw->requested.media_subtype) { switch (pw->requested.media_subtype) {
case SPA_MEDIA_SUBTYPE_raw: case SPA_MEDIA_SUBTYPE_raw:
channels = pw->requested.info.raw.channels; channels = pw->requested.info.raw.channels;
position = pw->requested.info.raw.position; position = pw->requested.info.raw.position;
max_position = SPA_N_ELEMENTS(pw->requested.info.raw.position);
break; break;
case SPA_MEDIA_SUBTYPE_dsd: case SPA_MEDIA_SUBTYPE_dsd:
channels = pw->requested.info.dsd.channels; channels = pw->requested.info.dsd.channels;
position = pw->requested.info.dsd.position; position = pw->requested.info.dsd.position;
max_position = SPA_N_ELEMENTS(pw->requested.info.dsd.position);
break; break;
default: default:
return NULL; 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)); channels * sizeof(unsigned int));
map->channels = channels; map->channels = channels;
for (i = 0; i < channels; i++) 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; return map;
} }

View file

@ -29,7 +29,7 @@ extern "C" {
#endif #endif
SPA_API_AUDIO_RAW_UTILS uint32_t 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; uint32_t pos;
if (idx < SPA_AUDIO_MAX_CHANNELS) { 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; 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_API_AUDIO_RAW_UTILS int
spa_format_audio_raw_parse(const struct spa_pod *format, struct spa_audio_info_raw *info) spa_format_audio_raw_parse(const struct spa_pod *format, struct spa_audio_info_raw *info)

View file

@ -2046,11 +2046,12 @@ static int do_auto_port_config(struct impl *this, const char *str)
return -ENOENT; return -ENOENT;
if (format.media_subtype == SPA_MEDIA_SUBTYPE_raw) { 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) { 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; format.info.raw.position[i] = SPA_AUDIO_CHANNEL_START_Aux + i;
} else if (position == POSITION_UNKNOWN) { } 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; format.info.raw.position[i] = SPA_AUDIO_CHANNEL_UNKNOWN;
} }
} }

View file

@ -1150,7 +1150,7 @@ struct spa_filter_graph_events graph_events = {
}; };
static int setup_filter_graph(struct impl *this, struct filter_graph *g, 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; int res;
char rate_str[64], in_ports[64]; 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); snprintf(in_ports, sizeof(in_ports), "%d", channels);
g->n_inputs = channels; g->n_inputs = channels;
if (position) { if (position) {
memcpy(g->inputs_position, position, sizeof(uint32_t) * channels); uint32_t n_pos = SPA_MIN(channels, max_position);
memcpy(g->outputs_position, position, sizeof(uint32_t) * channels); 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; 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) 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) static int setup_filter_graphs(struct impl *impl, bool force)
{ {
int res; int res;
uint32_t channels, *position; uint32_t channels, *position, max_position;
struct dir *in, *out; struct dir *in, *out;
struct filter_graph *g, *t; 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; channels = in->format.info.raw.channels;
position = in->format.info.raw.position; 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); 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) { 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; continue;
if (force) if (force)
g->setup = false; 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; g->removing = true;
spa_log_warn(impl->log, "failed to activate graph %d: %s", g->order, spa_log_warn(impl->log, "failed to activate graph %d: %s", g->order,
spa_strerror(res)); spa_strerror(res));
} else { } else {
channels = g->n_outputs; channels = g->n_outputs;
position = g->outputs_position; position = g->outputs_position;
max_position = SPA_N_ELEMENTS(g->outputs_position);
impl->maxports = SPA_MAX(impl->maxports, channels); impl->maxports = SPA_MAX(impl->maxports, channels);
} }
} }
if ((res = ensure_tmp(impl)) < 0) if ((res = ensure_tmp(impl)) < 0)
return res; return res;
if ((res = setup_channelmix(impl, channels, position)) < 0) if ((res = setup_channelmix(impl, channels, position, max_position)) < 0)
return res; return res;
return 0; 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; this->dir[SPA_DIRECTION_OUTPUT].n_ports = dir->n_ports + 1;
for (i = 0; i < dir->n_ports; i++) { 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) if (this->monitor && direction == SPA_DIRECTION_INPUT)
init_port(this, SPA_DIRECTION_OUTPUT, i+1, init_port(this, SPA_DIRECTION_OUTPUT, i+1,
info->info.raw.position[i], true, true, false); pos, true, true, false);
} }
break; break;
} }
@ -2056,24 +2060,25 @@ static int setup_in_convert(struct impl *this)
dst_info.info.raw.channels, dst_info.info.raw.channels,
dst_info.info.raw.rate); 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); sizeof(uint32_t), int32_cmp);
for (i = 0; i < src_info.info.raw.channels; i++) { for (i = 0; i < src_info.info.raw.channels; i++) {
for (j = 0; j < dst_info.info.raw.channels; j++) { for (j = 0; j < dst_info.info.raw.channels; j++) {
if (src_info.info.raw.position[i] != uint32_t pi, pj;
dst_info.info.raw.position[j])
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; continue;
in->remap[i] = j; in->remap[i] = j;
if (i != j) if (i != j)
remap = true; remap = true;
spa_log_debug(this->log, "%p: channel %d (%d) -> %d (%s -> %s)", this, spa_log_debug(this->log, "%p: channel %d (%d) -> %d (%s -> %s)", this,
i, in->remap[i], j, i, in->remap[i], j,
spa_debug_type_find_short_name(spa_type_audio_channel, spa_debug_type_find_short_name(spa_type_audio_channel, pi),
src_info.info.raw.position[i]), spa_debug_type_find_short_name(spa_type_audio_channel, pj));
spa_debug_type_find_short_name(spa_type_audio_channel, spa_format_audio_raw_set_position(&dst_info.info.raw, j, -1);
dst_info.info.raw.position[j]));
dst_info.info.raw.position[j] = -1;
break; 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 (i = 0; i < p->n_channels; i++) {
for (j = i; j < target; j++) { 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, spa_log_debug(this->log, "%d %d: %d <-> %d", i, j,
p->channel_map[i], info->info.raw.position[j]); p->channel_map[i], pj);
if (p->channel_map[i] != info->info.raw.position[j]) if (p->channel_map[i] != pj)
continue; continue;
if (i != j) { if (i != j) {
SPA_SWAP(p->channel_map[i], p->channel_map[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; p->n_channels = target;
for (i = 0; i < p->n_channels; i++) 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) if (target == 0)
return 0; return 0;
@ -2182,17 +2188,17 @@ static void set_volume(struct impl *this)
this->params[IDX_Props].user++; 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; uint32_t i, idx = 0;
for (i = 0; i < channels; i++) for (i = 0; i < channels; i++)
idx += snprintf(str + idx, len - idx, "%s%s", i == 0 ? "" : " ", idx += snprintf(str + idx, len - idx, "%s%s", i == 0 ? "" : " ",
spa_debug_type_find_short_name(spa_type_audio_channel, spa_debug_type_find_short_name(spa_type_audio_channel,
position[i])); position[i % max_position]));
return str; 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 *in = &this->dir[SPA_DIRECTION_INPUT];
struct dir *out = &this->dir[SPA_DIRECTION_OUTPUT]; 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; dst_chan = out->format.info.raw.channels;
for (i = 0, src_mask = 0; i < src_chan; i++) { 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); src_mask |= 1ULL << (p < 64 ? p : 0);
} }
for (i = 0, dst_mask = 0; i < dst_chan; i++) { 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); dst_mask |= 1ULL << (p < 64 ? p : 0);
} }
spa_log_info(this->log, "in %s (%016"PRIx64")", format_position(str, sizeof(str), 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), 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_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), 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.channels,
dst_info.info.raw.rate); 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); sizeof(uint32_t), int32_cmp);
for (i = 0; i < src_info.info.raw.channels; i++) { for (i = 0; i < src_info.info.raw.channels; i++) {
for (j = 0; j < dst_info.info.raw.channels; j++) { for (j = 0; j < dst_info.info.raw.channels; j++) {
if (src_info.info.raw.position[i] != uint32_t pi, pj;
dst_info.info.raw.position[j])
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; continue;
out->remap[i] = j; out->remap[i] = j;
if (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, spa_log_debug(this->log, "%p: channel %d (%d) -> %d (%s -> %s)", this,
i, out->remap[i], j, i, out->remap[i], j,
spa_debug_type_find_short_name(spa_type_audio_channel, spa_debug_type_find_short_name(spa_type_audio_channel, pi),
src_info.info.raw.position[i]), spa_debug_type_find_short_name(spa_type_audio_channel, pj));
spa_debug_type_find_short_name(spa_type_audio_channel,
dst_info.info.raw.position[j])); spa_format_audio_raw_set_position(&dst_info.info.raw, j, -1);
dst_info.info.raw.position[j] = -1;
break; break;
} }
} }

View file

@ -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, 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, 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 channels = conf->channels;
const uint32_t location = OPUS_05_GET_LOCATION(*conf); 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]; const struct audio_location loc = audio_locations[i];
if (location & loc.mask) { if (location & loc.mask) {
if (permutation) uint32_t idx = permutation ? permutation[j] : j;
positions[permutation[j++]] = loc.position; if (idx < max_positions)
else positions[idx] = loc.position;
positions[j++] = 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; 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; 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; return -EINVAL;
spa_pod_builder_push_object(b, &f[0], SPA_TYPE_OBJECT_Format, id); 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; 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; 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 -EINVAL;
return 0; 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) if ((res = codec_validate_config(codec, flags, config, config_len, &config_info)) < 0)
goto error; goto error;
if ((res = get_mapping(codec, dir, surround_encoder, &this->streams, &this->coupled_streams, if ((res = get_mapping(codec, dir, surround_encoder, &this->streams, &this->coupled_streams,
&enc_mapping, NULL)) < 0) &enc_mapping, NULL, 0)) < 0)
goto error; goto error;
if (config_info.info.raw.channels != info->info.raw.channels) { if (config_info.info.raw.channels != info->info.raw.channels) {
res = -EINVAL; res = -EINVAL;

View file

@ -35,6 +35,7 @@
#include <spa/utils/string.h> #include <spa/utils/string.h>
#include <spa/utils/json.h> #include <spa/utils/json.h>
#include <spa-private/dbus-helpers.h> #include <spa-private/dbus-helpers.h>
#include <spa/param/audio/raw-utils.h>
#include <spa/param/audio/raw-json.h> #include <spa/param/audio/raw-json.h>
#include "codec-loader.h" #include "codec-loader.h"
@ -5038,8 +5039,8 @@ static DBusHandlerResult endpoint_set_configuration(DBusConnection *conn,
return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
} }
transport->n_channels = info.info.raw.channels; transport->n_channels = info.info.raw.channels;
memcpy(transport->channels, info.info.raw.position, spa_format_audio_raw_copy_positions(&info.info.raw,
transport->n_channels * sizeof(uint32_t)); transport->channels, SPA_N_ELEMENTS(transport->channels));
} else { } else {
transport->n_channels = 2; transport->n_channels = 2;
transport->channels[0] = SPA_AUDIO_CHANNEL_FL; transport->channels[0] = SPA_AUDIO_CHANNEL_FL;

View file

@ -26,6 +26,7 @@
#include <spa/pod/parser.h> #include <spa/pod/parser.h>
#include <spa/param/param.h> #include <spa/param/param.h>
#include <spa/param/audio/raw.h> #include <spa/param/audio/raw.h>
#include <spa/param/audio/raw-utils.h>
#include <spa/param/bluetooth/audio.h> #include <spa/param/bluetooth/audio.h>
#include <spa/param/bluetooth/type-info.h> #include <spa/param/bluetooth/type-info.h>
#include <spa/debug/pod.h> #include <spa/debug/pod.h>
@ -451,7 +452,8 @@ static int node_offload_set_active(struct node *node, bool active)
return res; 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; const struct media_codec *codec;
struct spa_audio_info info = { 0 }; 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; return;
} }
*n_channels = info.info.raw.channels; *n_channels = spa_format_audio_raw_copy_positions(&info.info.raw, channels, max_channels);
memcpy(channels, info.info.raw.position,
info.info.raw.channels * sizeof(uint32_t));
} }
static const char *get_channel_name(uint32_t channel) 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].active = true;
this->nodes[id].offload_acquired = false; this->nodes[id].offload_acquired = false;
this->nodes[id].a2dp_duplex = a2dp_duplex; 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) if (this->nodes[id].transport)
spa_hook_remove(&this->nodes[id].transport_listener); spa_hook_remove(&this->nodes[id].transport_listener);
this->nodes[id].transport = t; this->nodes[id].transport = t;

View file

@ -637,7 +637,7 @@ port_set_format(struct impl *this,
if (info.info.raw.rate == 0 || if (info.info.raw.rate == 0 ||
info.info.raw.channels == 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; return -EINVAL;
if (this->props.format != 0) { if (this->props.format != 0) {

View file

@ -454,8 +454,7 @@ static int port_set_format(void *object,
return -EINVAL; return -EINVAL;
if (info.info.raw.format != SPA_AUDIO_FORMAT_S16 || if (info.info.raw.format != SPA_AUDIO_FORMAT_S16 ||
info.info.raw.channels == 0 || info.info.raw.channels == 0)
info.info.raw.channels > SPA_N_ELEMENTS(info.info.raw.position))
return -EINVAL; return -EINVAL;
this->bpf = 2 * info.info.raw.channels; this->bpf = 2 * info.info.raw.channels;

View file

@ -268,8 +268,7 @@ static int port_set_format(void *object,
d->format.format != SPA_AUDIO_FORMAT_F32) d->format.format != SPA_AUDIO_FORMAT_F32)
return -EINVAL; return -EINVAL;
if (d->format.rate == 0 || if (d->format.rate == 0 ||
d->format.channels == 0 || d->format.channels == 0)
d->format.channels > SPA_N_ELEMENTS(d->format.position))
return -EINVAL; return -EINVAL;
} }

View file

@ -882,7 +882,10 @@ static int create_stream(struct stream_info *info)
for (i = 0; i < remap_info.channels; i++) { for (i = 0; i < remap_info.channels; i++) {
s->remap[i] = i; s->remap[i] = i;
for (j = 0; j < tmp_info.channels; j++) { 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; s->remap[i] = j;
break; break;
} }

View file

@ -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) if (spa_format_audio_raw_parse(param, &info) < 0)
return; return;
if (info.rate == 0 || if (info.rate == 0 ||
info.channels == 0 || info.channels == 0)
info.channels > SPA_N_ELEMENTS(info.position))
return; return;
break; break;
} }

View file

@ -1229,7 +1229,7 @@ static int probe_ffado_device(struct impl *impl)
} }
if (impl->source.info.channels != n_channels) { if (impl->source.info.channels != n_channels) {
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; 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) { if (impl->sink.info.channels != n_channels) {
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; impl->sink.info.position[i] = SPA_AUDIO_CHANNEL_AUX0 + i;
} }

View file

@ -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) && if (SPA_FLAG_IS_SET(dst->flags, SPA_AUDIO_FLAG_UNPOSITIONED) &&
!SPA_FLAG_IS_SET(src->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]; dst->position[i] = src->position[i];
SPA_FLAG_CLEAR(dst->flags, SPA_AUDIO_FLAG_UNPOSITIONED); SPA_FLAG_CLEAR(dst->flags, SPA_AUDIO_FLAG_UNPOSITIONED);
} }

View file

@ -524,7 +524,7 @@ static void make_stream_ports(struct stream *s)
if (i < s->info.channels) { if (i < s->info.channels) {
str = spa_debug_type_find_short_name(spa_type_audio_channel, 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) if (str)
snprintf(name, sizeof(name), "%s_%s", prefix, str); snprintf(name, sizeof(name), "%s_%s", prefix, str);
else else

View file

@ -538,8 +538,7 @@ static void param_format_changed(struct impl *impl, const struct spa_pod *param,
spa_zero(info); spa_zero(info);
if (param != NULL) { if (param != NULL) {
if (spa_format_audio_raw_parse(param, &info) < 0 || if (spa_format_audio_raw_parse(param, &info) < 0 ||
info.channels == 0 || info.channels == 0)
info.channels > SPA_N_ELEMENTS(info.position))
return; return;
if ((impl->info.format != 0 && impl->info.format != info.format) || 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 != 0 &&
(impl->info.channels != info.channels || (impl->info.channels != info.channels ||
memcmp(impl->info.position, info.position, 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]; uint8_t buffer[1024];
struct spa_pod_builder b; struct spa_pod_builder b;
const struct spa_pod *params[1]; const struct spa_pod *params[1];

View file

@ -442,7 +442,7 @@ static void make_stream_ports(struct stream *s)
if (i < s->info.channels) { if (i < s->info.channels) {
str = spa_debug_type_find_short_name(spa_type_audio_channel, 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( props = pw_properties_new(
PW_KEY_FORMAT_DSP, "32 bit float mono audio", PW_KEY_FORMAT_DSP, "32 bit float mono audio",
PW_KEY_AUDIO_CHANNEL, str ? str : "UNK", 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; impl->sink.info.rate = peer->params.sample_rate;
if ((uint32_t)peer->params.send_audio_channels != impl->sink.info.channels) { if ((uint32_t)peer->params.send_audio_channels != impl->sink.info.channels) {
impl->sink.info.channels = SPA_MIN(peer->params.send_audio_channels, impl->sink.info.channels = peer->params.send_audio_channels;
(int)SPA_N_ELEMENTS(impl->sink.info.position));
for (i = 0; i < impl->sink.info.channels; i++) 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; impl->source.n_ports = peer->params.recv_audio_channels + peer->params.recv_midi_channels;
if (impl->source.n_ports > MAX_PORTS) { 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; impl->source.info.rate = peer->params.sample_rate;
if ((uint32_t)peer->params.recv_audio_channels != impl->source.info.channels) { if ((uint32_t)peer->params.recv_audio_channels != impl->source.info.channels) {
impl->source.info.channels = SPA_MIN(peer->params.recv_audio_channels, impl->source.info.channels = peer->params.recv_audio_channels;
(int)SPA_N_ELEMENTS(impl->source.info.position));
for (i = 0; i < impl->source.info.channels; i++) 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->samplerate = peer->params.sample_rate;
impl->period_size = peer->params.period_size; impl->period_size = peer->params.period_size;

View file

@ -602,7 +602,7 @@ static void make_stream_ports(struct stream *s)
if (i < s->info.channels) { if (i < s->info.channels) {
str = spa_debug_type_find_short_name(spa_type_audio_channel, 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( props = pw_properties_new(
PW_KEY_FORMAT_DSP, "32 bit float mono audio", 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.n_ports = peer->params.recv_audio_channels + peer->params.recv_midi_channels;
follower->source.info.rate = peer->params.sample_rate; follower->source.info.rate = peer->params.sample_rate;
if ((uint32_t)peer->params.recv_audio_channels != follower->source.info.channels) { if ((uint32_t)peer->params.recv_audio_channels != follower->source.info.channels) {
follower->source.info.channels = SPA_MIN(peer->params.recv_audio_channels, follower->source.info.channels = peer->params.recv_audio_channels;
(int)SPA_N_ELEMENTS(follower->source.info.position));
for (i = 0; i < follower->source.info.channels; i++) 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.n_ports = peer->params.send_audio_channels + peer->params.send_midi_channels;
follower->sink.info.rate = peer->params.sample_rate; follower->sink.info.rate = peer->params.sample_rate;
if ((uint32_t)peer->params.send_audio_channels != follower->sink.info.channels) { if ((uint32_t)peer->params.send_audio_channels != follower->sink.info.channels) {
follower->sink.info.channels = SPA_MIN(peer->params.send_audio_channels, follower->sink.info.channels = peer->params.send_audio_channels;
(int)SPA_N_ELEMENTS(follower->sink.info.position));
for (i = 0; i < follower->sink.info.channels; i++) 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) { if (follower->source.n_ports > MAX_PORTS || follower->sink.n_ports > MAX_PORTS) {

View file

@ -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++) for (i = 0; i < channels; i++)
pos[i] = map->map[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; info.info.raw.rate = 48000;
if (info.info.raw.format == 0 || if (info.info.raw.format == 0 ||
info.info.raw.rate == 0 || info.info.raw.rate == 0 ||
info.info.raw.channels == 0 || info.info.raw.channels == 0)
info.info.raw.channels > SPA_N_ELEMENTS(info.info.raw.position))
return -ENOTSUP; return -ENOTSUP;
} }
break; break;
@ -586,7 +585,7 @@ int format_parse_param(const struct spa_pod *param, bool collect,
if (info.info.raw.channels) { if (info.info.raw.channels) {
map->channels = SPA_MIN(info.info.raw.channels, CHANNELS_MAX); map->channels = SPA_MIN(info.info.raw.channels, CHANNELS_MAX);
for (i = 0; i < map->channels; i++) 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; 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); SPA_FORMAT_AUDIO_channels, SPA_POD_Int(spec->channels), 0);
if (map && map->channels == spec->channels) { if (map && map->channels == spec->channels) {
uint32_t positions[SPA_AUDIO_MAX_CHANNELS]; uint32_t positions[spec->channels];
channel_map_to_positions(map, positions); channel_map_to_positions(map, positions, spec->channels);
spa_pod_builder_add(b, SPA_FORMAT_AUDIO_position, spa_pod_builder_add(b, SPA_FORMAT_AUDIO_position,
SPA_POD_Array(sizeof(uint32_t), SPA_TYPE_Id, SPA_POD_Array(sizeof(uint32_t), SPA_TYPE_Id,
spec->channels, positions), 0); spec->channels, positions), 0);

View file

@ -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); const char *channel_id2paname(uint32_t id, uint32_t *aux);
uint32_t channel_paname2id(const char *name, size_t size); 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); void channel_map_parse(const char *str, struct channel_map *map);
bool channel_map_valid(const 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); void channel_map_parse_position(const char *str, struct channel_map *map);

View file

@ -12,6 +12,7 @@
#include <spa/utils/list.h> #include <spa/utils/list.h>
#include <spa/utils/hook.h> #include <spa/utils/hook.h>
#include <spa/utils/string.h> #include <spa/utils/string.h>
#include <spa/param/audio/raw-utils.h>
#include <pipewire/log.h> #include <pipewire/log.h>
#include <pipewire/map.h> #include <pipewire/map.h>
#include <pipewire/properties.h> #include <pipewire/properties.h>
@ -226,14 +227,15 @@ int module_args_to_audioinfo_keys(struct impl *impl, struct pw_properties *props
info->channels, map.channels); info->channels, map.channels);
return -EINVAL; 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); pw_properties_set(props, key_channel_map, NULL);
} else { } else {
if (info->channels == 0) if (info->channels == 0)
info->channels = impl->defs.sample_spec.channels; info->channels = impl->defs.sample_spec.channels;
if (info->channels == impl->defs.channel_map.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) { } else if (info->channels == 1) {
info->position[0] = SPA_AUDIO_CHANNEL_MONO; info->position[0] = SPA_AUDIO_CHANNEL_MONO;
} else if (info->channels == 2) { } else if (info->channels == 2) {
@ -242,7 +244,7 @@ int module_args_to_audioinfo_keys(struct impl *impl, struct pw_properties *props
} else { } else {
/* FIXME add more mappings */ /* FIXME add more mappings */
for (i = 0; i < info->channels; i++) 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) if (info->position[0] == SPA_AUDIO_CHANNEL_UNKNOWN)
info->flags |= SPA_AUDIO_FLAG_UNPOSITIONED; 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); p = s = alloca(info->channels * 8);
for (i = 0; i < info->channels; i++) for (i = 0; i < info->channels; i++)
p += spa_scnprintf(p, 8, "%s%s", i == 0 ? "" : ", ", 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); pw_properties_setf(props, SPA_KEY_AUDIO_POSITION, "[ %s ]", s);
} }
} }

View file

@ -754,7 +754,8 @@ static int create_pulse_stream(struct impl *impl)
map.channels = impl->info.channels; map.channels = impl->info.channels;
for (i = 0; i < map.channels; i++) 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"), snprintf(stream_name, sizeof(stream_name), _("Tunnel for %s@%s"),
pw_get_user_name(), pw_get_host_name()); pw_get_user_name(), pw_get_host_name());

View file

@ -215,16 +215,16 @@ static const struct spa_audio_layout_info layouts[] = {
{ SPA_AUDIO_LAYOUT_7_1 }, { 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) { SPA_FOR_EACH_ELEMENT_VAR(layouts, l) {
if (l->n_channels == channels) { 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]; position[i] = l->position[i];
return; 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; 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: case SPA_MEDIA_SUBTYPE_raw:
parse_audio_info(props, &impl->info.info.raw); parse_audio_info(props, &impl->info.info.raw);
if (SPA_FLAG_IS_SET(impl->info.info.raw.flags, SPA_AUDIO_FLAG_UNPOSITIONED)) 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->stream_info = impl->info;
impl->format_info = find_audio_format_info(&impl->info); impl->format_info = find_audio_format_info(&impl->info);
if (impl->format_info == NULL) { if (impl->format_info == NULL) {

View file

@ -192,7 +192,7 @@ static void pw_properties_from_avahi_string(const char *key, const char *value,
spa_zero(channel_map); spa_zero(channel_map);
channel_map_parse(value, &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 = s = alloca(4 + channel_map.channels * 8);
p += spa_scnprintf(p, 2, "["); p += spa_scnprintf(p, 2, "[");

View file

@ -2347,9 +2347,11 @@ int main(int argc, char *argv[])
.rate = data.rate, .rate = data.rate,
.channels = data.channels); .channels = data.channels);
if (data.channelmap.n_channels) if (data.channelmap.n_channels) {
memcpy(info.position, data.channelmap.channels, data.channels * sizeof(int)); 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); params[n_params++] = spa_format_audio_raw_build(&b, SPA_PARAM_EnumFormat, &info);
break; break;
} }