mirror of
https://gitlab.freedesktop.org/pipewire/pipewire
synced 2024-09-20 00:11:31 +00:00
pipewire-pulse: enumerate iec958 formats for sinks
This commit is contained in:
parent
2e6f80f808
commit
bceb9a4b6e
|
@ -382,27 +382,41 @@ bool channel_map_valid(const struct channel_map *map)
|
|||
return true;
|
||||
}
|
||||
|
||||
struct encoding_info {
|
||||
const char *name;
|
||||
uint32_t id;
|
||||
};
|
||||
|
||||
static const char * const encoding_names[] = {
|
||||
[ENCODING_ANY] = "ANY",
|
||||
[ENCODING_PCM] = "PCM",
|
||||
[ENCODING_AC3_IEC61937] = "AC3-IEC61937",
|
||||
[ENCODING_EAC3_IEC61937] = "EAC3-IEC61937",
|
||||
[ENCODING_MPEG_IEC61937] = "MPEG-IEC61937",
|
||||
[ENCODING_DTS_IEC61937] = "DTS-IEC61937",
|
||||
[ENCODING_MPEG2_AAC_IEC61937] = "MPEG2-AAC-IEC61937",
|
||||
[ENCODING_TRUEHD_IEC61937] = "TRUEHD-IEC61937",
|
||||
[ENCODING_DTSHD_IEC61937] = "DTSHD-IEC61937",
|
||||
static const struct encoding_info encoding_names[] = {
|
||||
[ENCODING_ANY] = { "ANY", 0 },
|
||||
[ENCODING_PCM] = { "PCM", 0 },
|
||||
[ENCODING_AC3_IEC61937] = { "AC3-IEC61937", SPA_AUDIO_IEC958_CODEC_AC3 },
|
||||
[ENCODING_EAC3_IEC61937] = { "EAC3-IEC61937", SPA_AUDIO_IEC958_CODEC_EAC3 },
|
||||
[ENCODING_MPEG_IEC61937] = { "MPEG-IEC61937", SPA_AUDIO_IEC958_CODEC_MPEG },
|
||||
[ENCODING_DTS_IEC61937] = { "DTS-IEC61937", SPA_AUDIO_IEC958_CODEC_DTS },
|
||||
[ENCODING_MPEG2_AAC_IEC61937] = { "MPEG2-AAC-IEC61937", SPA_AUDIO_IEC958_CODEC_MPEG2_AAC },
|
||||
[ENCODING_TRUEHD_IEC61937] = { "TRUEHD-IEC61937", SPA_AUDIO_IEC958_CODEC_TRUEHD },
|
||||
[ENCODING_DTSHD_IEC61937] = { "DTSHD-IEC61937", SPA_AUDIO_IEC958_CODEC_DTSHD },
|
||||
};
|
||||
|
||||
const char *format_encoding2name(enum encoding enc)
|
||||
{
|
||||
if (enc >= 0 && enc < (int)SPA_N_ELEMENTS(encoding_names) &&
|
||||
encoding_names[enc] != NULL)
|
||||
return encoding_names[enc];
|
||||
encoding_names[enc].name != NULL)
|
||||
return encoding_names[enc].name;
|
||||
return "INVALID";
|
||||
}
|
||||
|
||||
static enum encoding format_encoding_from_id(uint32_t id)
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < (int)SPA_N_ELEMENTS(encoding_names); i++) {
|
||||
if (encoding_names[i].id == id)
|
||||
return i;
|
||||
}
|
||||
return ENCODING_ANY;
|
||||
}
|
||||
|
||||
int format_parse_param(const struct spa_pod *param, struct sample_spec *ss, struct channel_map *map)
|
||||
{
|
||||
struct spa_audio_info info = { 0 };
|
||||
|
@ -473,6 +487,126 @@ int format_info_from_spec(struct format_info *info, const struct sample_spec *ss
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int add_int(struct format_info *info, const char *k, struct spa_pod *param,
|
||||
uint32_t key)
|
||||
{
|
||||
const struct spa_pod_prop *prop;
|
||||
struct spa_pod *val;
|
||||
uint32_t i, n_values, choice;
|
||||
int32_t *values;
|
||||
|
||||
prop = spa_pod_find_prop(param, NULL, key);
|
||||
if (prop == NULL)
|
||||
return -ENOENT;
|
||||
|
||||
val = spa_pod_get_values(&prop->value, &n_values, &choice);
|
||||
if (val->type != SPA_TYPE_Int)
|
||||
return -ENOTSUP;
|
||||
|
||||
values = SPA_POD_BODY(val);
|
||||
|
||||
switch (choice) {
|
||||
case SPA_CHOICE_None:
|
||||
pw_properties_setf(info->props, k, "%d", values[0]);
|
||||
break;
|
||||
case SPA_CHOICE_Range:
|
||||
pw_properties_setf(info->props, k, "{ \"min\": %d, \"max\": %d }",
|
||||
values[1], values[2]);
|
||||
break;
|
||||
case SPA_CHOICE_Enum:
|
||||
{
|
||||
char *ptr;
|
||||
size_t size;
|
||||
FILE *f;
|
||||
|
||||
f = open_memstream(&ptr, &size);
|
||||
fprintf(f, "[");
|
||||
for (i = 1; i < n_values; i++)
|
||||
fprintf(f, "%s %d", i == 1 ? "" : ",", values[i]);
|
||||
fprintf(f, " ]");
|
||||
fclose(f);
|
||||
|
||||
pw_properties_set(info->props, k, ptr);
|
||||
free(ptr);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
return -ENOTSUP;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int format_info_pcm_from_param(struct format_info *info, struct spa_pod *param, uint32_t index)
|
||||
{
|
||||
if (index > 0)
|
||||
return -ENOENT;
|
||||
|
||||
info->encoding = ENCODING_PCM;
|
||||
/* don't add params here yet, pulseaudio doesn't do that either */
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int format_info_iec958_from_param(struct format_info *info, struct spa_pod *param, uint32_t index)
|
||||
{
|
||||
const struct spa_pod_prop *prop;
|
||||
struct spa_pod *val;
|
||||
uint32_t n_values, *values, choice;
|
||||
|
||||
prop = spa_pod_find_prop(param, NULL, SPA_FORMAT_AUDIO_iec958Codec);
|
||||
if (prop == NULL)
|
||||
return -ENOENT;
|
||||
|
||||
val = spa_pod_get_values(&prop->value, &n_values, &choice);
|
||||
if (val->type != SPA_TYPE_Id)
|
||||
return -ENOTSUP;
|
||||
|
||||
if (index >= n_values)
|
||||
return -ENOENT;
|
||||
|
||||
values = SPA_POD_BODY(val);
|
||||
|
||||
switch (choice) {
|
||||
case SPA_CHOICE_None:
|
||||
info->encoding = format_encoding_from_id(values[index]);
|
||||
break;
|
||||
case SPA_CHOICE_Enum:
|
||||
info->encoding = format_encoding_from_id(values[index+1]);
|
||||
break;
|
||||
default:
|
||||
return -ENOTSUP;
|
||||
}
|
||||
if ((info->props = pw_properties_new(NULL, NULL)) == NULL)
|
||||
return -errno;
|
||||
|
||||
add_int(info, "format.rate", param, SPA_FORMAT_AUDIO_rate);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int format_info_from_param(struct format_info *info, struct spa_pod *param, uint32_t index)
|
||||
{
|
||||
uint32_t media_type, media_subtype;
|
||||
int res;
|
||||
|
||||
if (spa_format_parse(param, &media_type, &media_subtype) < 0)
|
||||
return -ENOTSUP;
|
||||
|
||||
if (media_type != SPA_MEDIA_TYPE_audio)
|
||||
return -ENOTSUP;
|
||||
|
||||
switch(media_subtype) {
|
||||
case SPA_MEDIA_SUBTYPE_raw:
|
||||
res = format_info_pcm_from_param(info, param, index);
|
||||
break;
|
||||
case SPA_MEDIA_SUBTYPE_iec958:
|
||||
res = format_info_iec958_from_param(info, param, index);
|
||||
break;
|
||||
default:
|
||||
return -ENOTSUP;
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
int format_info_to_spec(const struct format_info *info, struct sample_spec *ss,
|
||||
struct channel_map *map)
|
||||
{
|
||||
|
|
|
@ -209,6 +209,11 @@ int format_parse_param(const struct spa_pod *param, struct sample_spec *ss,
|
|||
|
||||
const struct spa_pod *format_build_param(struct spa_pod_builder *b, uint32_t id,
|
||||
const struct sample_spec *spec, const struct channel_map *map);
|
||||
|
||||
int format_info_from_spec(struct format_info *info, const struct sample_spec *ss,
|
||||
const struct channel_map *map);
|
||||
int format_info_from_param(struct format_info *info, struct spa_pod *param, uint32_t index);
|
||||
|
||||
const struct spa_pod *format_info_build_param(struct spa_pod_builder *b, uint32_t id,
|
||||
const struct format_info *info, uint32_t *rate);
|
||||
|
||||
|
|
|
@ -3541,13 +3541,33 @@ static int fill_sink_info(struct client *client, struct message *m,
|
|||
TAG_INVALID);
|
||||
}
|
||||
if (client->version >= 21) {
|
||||
struct format_info info;
|
||||
spa_zero(info);
|
||||
info.encoding = ENCODING_PCM;
|
||||
struct pw_manager_param *p;
|
||||
struct format_info info[32];
|
||||
uint32_t i, n_info = 0;
|
||||
|
||||
spa_list_for_each(p, &o->param_list, link) {
|
||||
uint32_t index = 0;
|
||||
|
||||
if (p->id != SPA_PARAM_EnumFormat)
|
||||
continue;
|
||||
|
||||
while (n_info < SPA_N_ELEMENTS(info)) {
|
||||
spa_zero(info[n_info]);
|
||||
if (format_info_from_param(&info[n_info], p->param, index++) < 0)
|
||||
break;
|
||||
if (info[n_info].encoding == ENCODING_ANY)
|
||||
continue;
|
||||
n_info++;
|
||||
}
|
||||
}
|
||||
message_put(m,
|
||||
TAG_U8, 1, /* n_formats */
|
||||
TAG_FORMAT_INFO, &info,
|
||||
TAG_U8, n_info, /* n_formats */
|
||||
TAG_INVALID);
|
||||
for (i = 0; i < n_info; i++) {
|
||||
message_put(m,
|
||||
TAG_FORMAT_INFO, &info[i],
|
||||
TAG_INVALID);
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue