Skip to content

Commit

Permalink
Implement channel map query for ALSA PCM plug-in
Browse files Browse the repository at this point in the history
  • Loading branch information
arkq committed Sep 3, 2024
1 parent 3b295bb commit 4f0d8b0
Show file tree
Hide file tree
Showing 3 changed files with 140 additions and 22 deletions.
101 changes: 95 additions & 6 deletions src/asound/bluealsa-pcm.c
Original file line number Diff line number Diff line change
Expand Up @@ -580,17 +580,34 @@ static int bluealsa_hw_params(snd_pcm_ioplug_t *io, snd_pcm_hw_params_t *params)
debug2("Changing BlueALSA PCM configuration: %u ch, %u Hz -> %u ch, %u Hz",
pcm->ba_pcm.channels, pcm->ba_pcm.sampling, channels, sampling);

if (ba_dbus_pcm_select_codec(&pcm->dbus_ctx, pcm->ba_pcm.pcm_path,
pcm->ba_pcm.codec.name, pcm->ba_pcm_codec_config, pcm->ba_pcm_codec_config_len,
const char *codec_name = pcm->ba_pcm.codec.name;
if (!ba_dbus_pcm_select_codec(&pcm->dbus_ctx, pcm->ba_pcm.pcm_path,
codec_name, pcm->ba_pcm_codec_config, pcm->ba_pcm_codec_config_len,
channels, sampling, BA_PCM_SELECT_CODEC_FLAG_NONE, &err)) {
pcm->ba_pcm.channels = channels;
pcm->ba_pcm.sampling = sampling;
}
else {
SNDERR("Couldn't change BlueALSA PCM configuration: %s", err.message);
return -dbus_error_to_errno(&err);
}

/* After new codec selection, it is necessary to update the PCM data.
* We will do it the off-line manner (without server interaction) to
* speed up the process. */

pcm->ba_pcm.channels = channels;
pcm->ba_pcm.sampling = sampling;

for (size_t i = 0; i < pcm->ba_pcm_codecs.codecs_len; i++) {
const struct ba_pcm_codec *codec = &pcm->ba_pcm_codecs.codecs[i];
if (strcmp(codec->name, codec_name) == 0) {
for (size_t j = 0; j < ARRAYSIZE(codec->channel_maps); j++)
if (codec->channels[j] == channels) {
memcpy(pcm->ba_pcm.channel_map, codec->channel_maps[j],
sizeof(pcm->ba_pcm.channel_map));
break;
}
break;
}
}

}

#if BLUEALSA_HW_PARAMS_FIX
Expand Down Expand Up @@ -1133,6 +1150,76 @@ static int bluealsa_poll_revents(snd_pcm_ioplug_t *io, struct pollfd *pfd,
return -ENODEV;
}

static enum snd_pcm_chmap_position ba_channel_map_to_position(const char *tag) {

static const struct {
const char *tag;
enum snd_pcm_chmap_position pos;
} mapping[] = {
{ "MONO", SND_CHMAP_MONO },
{ "FL", SND_CHMAP_FL },
{ "FR", SND_CHMAP_FR },
{ "RL", SND_CHMAP_RL },
{ "RR", SND_CHMAP_RR },
{ "FC", SND_CHMAP_FC },
{ "LFE", SND_CHMAP_LFE },
{ "SL", SND_CHMAP_SL },
{ "SR", SND_CHMAP_SR },
};

for (size_t i = 0; i < ARRAYSIZE(mapping); i++)
if (strcmp(tag, mapping[i].tag) == 0)
return mapping[i].pos;
return SND_CHMAP_UNKNOWN;
}

static snd_pcm_chmap_query_t **bluealsa_query_chmaps(snd_pcm_ioplug_t *io) {
struct bluealsa_pcm *pcm = io->private_data;

const struct ba_pcm_codec *codec = &pcm->ba_pcm.codec;
for (size_t i = 0; i < pcm->ba_pcm_codecs.codecs_len; i++)
if (strcmp(pcm->ba_pcm_codecs.codecs[i].name, codec->name) == 0) {
codec = &pcm->ba_pcm_codecs.codecs[i];
break;
}

snd_pcm_chmap_query_t **maps;
if ((maps = malloc(sizeof(*maps) * (ARRAYSIZE(codec->channel_maps) + 1))) == NULL)
return NULL;

maps[ARRAYSIZE(codec->channel_maps)] = NULL;
for (size_t i = 0; i < ARRAYSIZE(codec->channel_maps); i++) {

unsigned int channels;
if ((channels = codec->channels[i]) == 0)
break;

maps[i] = malloc(sizeof(*maps[i]) + (channels * sizeof(*maps[i]->map.pos)));
maps[i]->type = SND_CHMAP_TYPE_FIXED;
maps[i]->map.channels = channels;

for (size_t j = 0; j < channels; j++)
maps[i]->map.pos[j] = ba_channel_map_to_position(codec->channel_maps[i][j]);

}

return maps;
}

static snd_pcm_chmap_t *bluealsa_get_chmap(snd_pcm_ioplug_t *io) {
struct bluealsa_pcm *pcm = io->private_data;

snd_pcm_chmap_t *map;
if ((map = malloc(sizeof(*map) + (io->channels * sizeof(*map->pos)))) == NULL)
return NULL;

map->channels = io->channels;
for (size_t i = 0; i < io->channels; i++)
map->pos[i] = ba_channel_map_to_position(pcm->ba_pcm.channel_map[i]);

return map;
}

static const snd_pcm_ioplug_callback_t bluealsa_callback = {
.start = bluealsa_start,
.stop = bluealsa_stop,
Expand All @@ -1149,6 +1236,8 @@ static const snd_pcm_ioplug_callback_t bluealsa_callback = {
.poll_descriptors_count = bluealsa_poll_descriptors_count,
.poll_descriptors = bluealsa_poll_descriptors,
.poll_revents = bluealsa_poll_revents,
.query_chmaps = bluealsa_query_chmaps,
.get_chmap = bluealsa_get_chmap,
};

static int str2bdaddr(const char *str, bdaddr_t *ba) {
Expand Down
59 changes: 43 additions & 16 deletions src/shared/dbus-client-pcm.c
Original file line number Diff line number Diff line change
Expand Up @@ -232,32 +232,54 @@ static void dbus_message_iter_get_codec_data(DBusMessageIter *variant,
static void dbus_message_iter_get_codec_supported_channels(DBusMessageIter *variant,
struct ba_pcm_codec *codec) {

DBusMessageIter iter;
unsigned char *data;
int len;
DBusMessageIter iter;
unsigned char *data;
int len;

dbus_message_iter_recurse(variant, &iter);
dbus_message_iter_get_fixed_array(&iter, &data, &len);
dbus_message_iter_recurse(variant, &iter);
dbus_message_iter_get_fixed_array(&iter, &data, &len);

len = MIN(len, ARRAYSIZE(codec->channels));
for (size_t i = 0; i < (size_t)len; i++)
codec->channels[i] = data[i];
len = MIN(len, ARRAYSIZE(codec->channels));
for (size_t i = 0; i < (size_t)len; i++)
codec->channels[i] = data[i];

}

static void dbus_message_iter_get_codec_supported_sampling(DBusMessageIter *variant,
struct ba_pcm_codec *codec) {

DBusMessageIter iter;
dbus_uint32_t *data;
int len;
DBusMessageIter iter;
dbus_uint32_t *data;
int len;

dbus_message_iter_recurse(variant, &iter);
dbus_message_iter_get_fixed_array(&iter, &data, &len);
dbus_message_iter_recurse(variant, &iter);
dbus_message_iter_get_fixed_array(&iter, &data, &len);

len = MIN(len, ARRAYSIZE(codec->sampling));
for (size_t i = 0; i < (size_t)len; i++)
codec->sampling[i] = data[i];
len = MIN(len, ARRAYSIZE(codec->sampling));
for (size_t i = 0; i < (size_t)len; i++)
codec->sampling[i] = data[i];

}

static void dbus_message_iter_get_codec_channel_maps(DBusMessageIter *variant,
struct ba_pcm_codec *codec) {

size_t i;
DBusMessageIter iter_array;
for (dbus_message_iter_recurse(variant, &iter_array), i = 0;
dbus_message_iter_get_arg_type(&iter_array) != DBUS_TYPE_INVALID;
dbus_message_iter_next(&iter_array)) {

const char *data[ARRAYSIZE(*codec->channel_maps)];
size_t length = ARRAYSIZE(data);

dbus_message_iter_array_get_strings(&iter_array, NULL, data, &length);

for (size_t j = 0; j < length; j++)
strncpy(codec->channel_maps[i][j], data[j], sizeof(codec->channel_maps[i][j]) - 1);

i++;
}

}

Expand Down Expand Up @@ -295,6 +317,11 @@ static dbus_bool_t ba_dbus_message_iter_pcm_codec_get_props_cb(const char *key,
goto fail;
dbus_message_iter_get_codec_supported_sampling(&variant, codec);
}
else if (strcmp(key, "ChannelMaps") == 0) {
if (type != (type_expected = DBUS_TYPE_ARRAY))
goto fail;
dbus_message_iter_get_codec_channel_maps(&variant, codec);
}

return TRUE;

Expand Down
2 changes: 2 additions & 0 deletions src/shared/dbus-client-pcm.h
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,8 @@ struct ba_pcm_codec {
unsigned char channels[8];
/* sampling frequencies supported by the codec */
dbus_uint32_t sampling[16];
/* channel maps associated with supported number of channels */
char channel_maps[8][8][5];
};

/**
Expand Down

0 comments on commit 4f0d8b0

Please sign in to comment.