mirror of
https://gitlab.freedesktop.org/pipewire/pipewire.git
synced 2025-11-03 09:01:54 -05:00
pulse-server: Handle formats of virtual devices better
Virtual devices tend to start with partial fields set in the EnumFormat param (usually rate is missing). This causes virtual devices to be invisible until they are used in some way. Fix this by relaxing the parsing of EnumFormat and by falling back to the server defaults for the unspecified fields. Fixes #1413
This commit is contained in:
parent
3526e33fe1
commit
a9169cf491
6 changed files with 58 additions and 19 deletions
|
|
@ -232,7 +232,7 @@ uint32_t find_profile_id(struct pw_manager_object *card, const char *name)
|
||||||
}
|
}
|
||||||
|
|
||||||
void collect_device_info(struct pw_manager_object *device, struct pw_manager_object *card,
|
void collect_device_info(struct pw_manager_object *device, struct pw_manager_object *card,
|
||||||
struct device_info *dev_info, bool monitor)
|
struct device_info *dev_info, bool monitor, struct defs *defs)
|
||||||
{
|
{
|
||||||
struct pw_manager_param *p;
|
struct pw_manager_param *p;
|
||||||
|
|
||||||
|
|
@ -266,12 +266,14 @@ void collect_device_info(struct pw_manager_object *device, struct pw_manager_obj
|
||||||
{
|
{
|
||||||
struct spa_pod *copy = spa_pod_copy(p->param);
|
struct spa_pod *copy = spa_pod_copy(p->param);
|
||||||
spa_pod_fixate(copy);
|
spa_pod_fixate(copy);
|
||||||
format_parse_param(copy, &dev_info->ss, &dev_info->map);
|
format_parse_param(copy, &dev_info->ss, &dev_info->map,
|
||||||
|
&defs->sample_spec, &defs->channel_map);
|
||||||
free(copy);
|
free(copy);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case SPA_PARAM_Format:
|
case SPA_PARAM_Format:
|
||||||
format_parse_param(p->param, &dev_info->ss, &dev_info->map);
|
format_parse_param(p->param, &dev_info->ss, &dev_info->map,
|
||||||
|
NULL, NULL);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case SPA_PARAM_Props:
|
case SPA_PARAM_Props:
|
||||||
|
|
|
||||||
|
|
@ -32,6 +32,7 @@
|
||||||
#include <spa/param/bluetooth/audio.h>
|
#include <spa/param/bluetooth/audio.h>
|
||||||
#include <pipewire/pipewire.h>
|
#include <pipewire/pipewire.h>
|
||||||
|
|
||||||
|
#include "internal.h"
|
||||||
#include "format.h"
|
#include "format.h"
|
||||||
#include "volume.h"
|
#include "volume.h"
|
||||||
|
|
||||||
|
|
@ -79,7 +80,7 @@ struct device_info {
|
||||||
}
|
}
|
||||||
|
|
||||||
void collect_device_info(struct pw_manager_object *device, struct pw_manager_object *card,
|
void collect_device_info(struct pw_manager_object *device, struct pw_manager_object *card,
|
||||||
struct device_info *dev_info, bool monitor);
|
struct device_info *dev_info, bool monitor, struct defs *defs);
|
||||||
|
|
||||||
/* ========================================================================== */
|
/* ========================================================================== */
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -424,7 +424,27 @@ static enum encoding format_encoding_from_id(uint32_t id)
|
||||||
return ENCODING_ANY;
|
return ENCODING_ANY;
|
||||||
}
|
}
|
||||||
|
|
||||||
int format_parse_param(const struct spa_pod *param, struct sample_spec *ss, struct channel_map *map)
|
static inline int
|
||||||
|
audio_raw_parse_opt(const struct spa_pod *format, struct spa_audio_info_raw *info)
|
||||||
|
{
|
||||||
|
struct spa_pod *position = NULL;
|
||||||
|
int res;
|
||||||
|
info->flags = 0;
|
||||||
|
res = spa_pod_parse_object(format,
|
||||||
|
SPA_TYPE_OBJECT_Format, NULL,
|
||||||
|
SPA_FORMAT_AUDIO_format, SPA_POD_OPT_Id(&info->format),
|
||||||
|
SPA_FORMAT_AUDIO_rate, SPA_POD_OPT_Int(&info->rate),
|
||||||
|
SPA_FORMAT_AUDIO_channels, SPA_POD_OPT_Int(&info->channels),
|
||||||
|
SPA_FORMAT_AUDIO_position, SPA_POD_OPT_Pod(&position));
|
||||||
|
if (position == NULL ||
|
||||||
|
!spa_pod_copy_array(position, SPA_TYPE_Id, info->position, SPA_AUDIO_MAX_CHANNELS))
|
||||||
|
SPA_FLAG_SET(info->flags, SPA_AUDIO_FLAG_UNPOSITIONED);
|
||||||
|
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
int format_parse_param(const struct spa_pod *param, struct sample_spec *ss, struct channel_map *map,
|
||||||
|
const struct sample_spec *def_ss, const struct channel_map *def_map)
|
||||||
{
|
{
|
||||||
struct spa_audio_info info = { 0 };
|
struct spa_audio_info info = { 0 };
|
||||||
uint32_t i;
|
uint32_t i;
|
||||||
|
|
@ -437,8 +457,15 @@ int format_parse_param(const struct spa_pod *param, struct sample_spec *ss, stru
|
||||||
|
|
||||||
switch (info.media_subtype) {
|
switch (info.media_subtype) {
|
||||||
case SPA_MEDIA_SUBTYPE_raw:
|
case SPA_MEDIA_SUBTYPE_raw:
|
||||||
|
if (def_ss != NULL) {
|
||||||
|
if (ss != NULL)
|
||||||
|
*ss = *def_ss;
|
||||||
|
if (audio_raw_parse_opt(param, &info.info.raw) < 0)
|
||||||
|
return -ENOTSUP;
|
||||||
|
} else {
|
||||||
if (spa_format_audio_raw_parse(param, &info.info.raw) < 0)
|
if (spa_format_audio_raw_parse(param, &info.info.raw) < 0)
|
||||||
return -ENOTSUP;
|
return -ENOTSUP;
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
case SPA_MEDIA_SUBTYPE_iec958:
|
case SPA_MEDIA_SUBTYPE_iec958:
|
||||||
{
|
{
|
||||||
|
|
@ -458,8 +485,11 @@ int format_parse_param(const struct spa_pod *param, struct sample_spec *ss, stru
|
||||||
return -ENOTSUP;
|
return -ENOTSUP;
|
||||||
}
|
}
|
||||||
if (ss) {
|
if (ss) {
|
||||||
|
if (info.info.raw.format)
|
||||||
ss->format = info.info.raw.format;
|
ss->format = info.info.raw.format;
|
||||||
|
if (info.info.raw.rate)
|
||||||
ss->rate = info.info.raw.rate;
|
ss->rate = info.info.raw.rate;
|
||||||
|
if (info.info.raw.channels)
|
||||||
ss->channels = info.info.raw.channels;
|
ss->channels = info.info.raw.channels;
|
||||||
}
|
}
|
||||||
if (map) {
|
if (map) {
|
||||||
|
|
|
||||||
|
|
@ -205,7 +205,8 @@ 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);
|
||||||
|
|
||||||
int format_parse_param(const struct spa_pod *param, struct sample_spec *ss,
|
int format_parse_param(const struct spa_pod *param, struct sample_spec *ss,
|
||||||
struct channel_map *map);
|
struct channel_map *map, const struct sample_spec *def_ss,
|
||||||
|
const struct channel_map *def_map);
|
||||||
|
|
||||||
const struct spa_pod *format_build_param(struct spa_pod_builder *b, uint32_t id,
|
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);
|
const struct sample_spec *spec, const struct channel_map *map);
|
||||||
|
|
|
||||||
|
|
@ -233,6 +233,7 @@ static char* channel_map_snprint(char *s, size_t l, const struct channel_map *ma
|
||||||
static void get_service_data(struct module_zeroconf_publish_data *d,
|
static void get_service_data(struct module_zeroconf_publish_data *d,
|
||||||
struct service *s, struct pw_manager_object *o)
|
struct service *s, struct pw_manager_object *o)
|
||||||
{
|
{
|
||||||
|
struct impl *impl = d->module->impl;
|
||||||
bool is_sink = pw_manager_object_is_sink(o);
|
bool is_sink = pw_manager_object_is_sink(o);
|
||||||
bool is_source = pw_manager_object_is_source(o);
|
bool is_source = pw_manager_object_is_source(o);
|
||||||
struct pw_node_info *info = o->info;
|
struct pw_node_info *info = o->info;
|
||||||
|
|
@ -265,7 +266,7 @@ static void get_service_data(struct module_zeroconf_publish_data *d,
|
||||||
if (card)
|
if (card)
|
||||||
collect_card_info(card, &card_info);
|
collect_card_info(card, &card_info);
|
||||||
|
|
||||||
collect_device_info(o, card, &dev_info, false);
|
collect_device_info(o, card, &dev_info, false, &impl->defs);
|
||||||
|
|
||||||
if ((str = spa_dict_lookup(info->props, PW_KEY_DEVICE_API)) != NULL) {
|
if ((str = spa_dict_lookup(info->props, PW_KEY_DEVICE_API)) != NULL) {
|
||||||
if (pw_manager_object_is_sink(o))
|
if (pw_manager_object_is_sink(o))
|
||||||
|
|
|
||||||
|
|
@ -981,7 +981,7 @@ static void stream_param_changed(void *data, uint32_t id, const struct spa_pod *
|
||||||
if (id != SPA_PARAM_Format || param == NULL)
|
if (id != SPA_PARAM_Format || param == NULL)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if ((res = format_parse_param(param, &stream->ss, &stream->map)) < 0) {
|
if ((res = format_parse_param(param, &stream->ss, &stream->map, NULL, NULL)) < 0) {
|
||||||
pw_stream_set_error(stream->stream, res, "format not supported");
|
pw_stream_set_error(stream->stream, res, "format not supported");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
@ -2669,7 +2669,7 @@ static int do_set_volume(struct client *client, uint32_t command, uint32_t tag,
|
||||||
struct selector sel = { .id = card_id, .type = pw_manager_object_is_card, };
|
struct selector sel = { .id = card_id, .type = pw_manager_object_is_card, };
|
||||||
card = select_object(manager, &sel);
|
card = select_object(manager, &sel);
|
||||||
}
|
}
|
||||||
collect_device_info(o, card, &dev_info, is_monitor);
|
collect_device_info(o, card, &dev_info, is_monitor, &impl->defs);
|
||||||
|
|
||||||
if (dev_info.have_volume &&
|
if (dev_info.have_volume &&
|
||||||
volume_compare(&dev_info.volume_info.volume, &volume) == 0)
|
volume_compare(&dev_info.volume_info.volume, &volume) == 0)
|
||||||
|
|
@ -2735,7 +2735,7 @@ static int do_set_mute(struct client *client, uint32_t command, uint32_t tag, st
|
||||||
struct selector sel = { .id = card_id, .type = pw_manager_object_is_card, };
|
struct selector sel = { .id = card_id, .type = pw_manager_object_is_card, };
|
||||||
card = select_object(manager, &sel);
|
card = select_object(manager, &sel);
|
||||||
}
|
}
|
||||||
collect_device_info(o, card, &dev_info, is_monitor);
|
collect_device_info(o, card, &dev_info, is_monitor, &impl->defs);
|
||||||
|
|
||||||
if (dev_info.have_volume &&
|
if (dev_info.have_volume &&
|
||||||
dev_info.volume_info.mute == mute)
|
dev_info.volume_info.mute == mute)
|
||||||
|
|
@ -3406,6 +3406,7 @@ static int fill_card_info(struct client *client, struct message *m,
|
||||||
static int fill_sink_info(struct client *client, struct message *m,
|
static int fill_sink_info(struct client *client, struct message *m,
|
||||||
struct pw_manager_object *o)
|
struct pw_manager_object *o)
|
||||||
{
|
{
|
||||||
|
struct impl *impl = client->impl;
|
||||||
struct pw_node_info *info = o->info;
|
struct pw_node_info *info = o->info;
|
||||||
struct pw_manager *manager = client->manager;
|
struct pw_manager *manager = client->manager;
|
||||||
const char *name, *desc, *str;
|
const char *name, *desc, *str;
|
||||||
|
|
@ -3447,7 +3448,7 @@ static int fill_sink_info(struct client *client, struct message *m,
|
||||||
if (card)
|
if (card)
|
||||||
collect_card_info(card, &card_info);
|
collect_card_info(card, &card_info);
|
||||||
|
|
||||||
collect_device_info(o, card, &dev_info, false);
|
collect_device_info(o, card, &dev_info, false, &impl->defs);
|
||||||
|
|
||||||
if (!sample_spec_valid(&dev_info.ss) ||
|
if (!sample_spec_valid(&dev_info.ss) ||
|
||||||
!channel_map_valid(&dev_info.map) ||
|
!channel_map_valid(&dev_info.map) ||
|
||||||
|
|
@ -3576,6 +3577,7 @@ static int fill_sink_info(struct client *client, struct message *m,
|
||||||
static int fill_source_info(struct client *client, struct message *m,
|
static int fill_source_info(struct client *client, struct message *m,
|
||||||
struct pw_manager_object *o)
|
struct pw_manager_object *o)
|
||||||
{
|
{
|
||||||
|
struct impl *impl = client->impl;
|
||||||
struct pw_node_info *info = o->info;
|
struct pw_node_info *info = o->info;
|
||||||
struct pw_manager *manager = client->manager;
|
struct pw_manager *manager = client->manager;
|
||||||
bool is_monitor;
|
bool is_monitor;
|
||||||
|
|
@ -3622,7 +3624,7 @@ static int fill_source_info(struct client *client, struct message *m,
|
||||||
if (card)
|
if (card)
|
||||||
collect_card_info(card, &card_info);
|
collect_card_info(card, &card_info);
|
||||||
|
|
||||||
collect_device_info(o, card, &dev_info, is_monitor);
|
collect_device_info(o, card, &dev_info, is_monitor, &impl->defs);
|
||||||
|
|
||||||
if (!sample_spec_valid(&dev_info.ss) ||
|
if (!sample_spec_valid(&dev_info.ss) ||
|
||||||
!channel_map_valid(&dev_info.map) ||
|
!channel_map_valid(&dev_info.map) ||
|
||||||
|
|
@ -3740,6 +3742,7 @@ static const char *get_media_name(struct pw_node_info *info)
|
||||||
static int fill_sink_input_info(struct client *client, struct message *m,
|
static int fill_sink_input_info(struct client *client, struct message *m,
|
||||||
struct pw_manager_object *o)
|
struct pw_manager_object *o)
|
||||||
{
|
{
|
||||||
|
struct impl *impl = client->impl;
|
||||||
struct pw_node_info *info = o->info;
|
struct pw_node_info *info = o->info;
|
||||||
struct pw_manager *manager = client->manager;
|
struct pw_manager *manager = client->manager;
|
||||||
struct pw_manager_object *peer;
|
struct pw_manager_object *peer;
|
||||||
|
|
@ -3756,7 +3759,7 @@ static int fill_sink_input_info(struct client *client, struct message *m,
|
||||||
(str = spa_dict_lookup(info->props, PW_KEY_CLIENT_ID)) != NULL)
|
(str = spa_dict_lookup(info->props, PW_KEY_CLIENT_ID)) != NULL)
|
||||||
client_id = (uint32_t)atoi(str);
|
client_id = (uint32_t)atoi(str);
|
||||||
|
|
||||||
collect_device_info(o, NULL, &dev_info, false);
|
collect_device_info(o, NULL, &dev_info, false, &impl->defs);
|
||||||
|
|
||||||
if (!sample_spec_valid(&dev_info.ss) ||
|
if (!sample_spec_valid(&dev_info.ss) ||
|
||||||
!channel_map_valid(&dev_info.map) ||
|
!channel_map_valid(&dev_info.map) ||
|
||||||
|
|
@ -3810,6 +3813,7 @@ static int fill_sink_input_info(struct client *client, struct message *m,
|
||||||
static int fill_source_output_info(struct client *client, struct message *m,
|
static int fill_source_output_info(struct client *client, struct message *m,
|
||||||
struct pw_manager_object *o)
|
struct pw_manager_object *o)
|
||||||
{
|
{
|
||||||
|
struct impl *impl = client->impl;
|
||||||
struct pw_node_info *info = o->info;
|
struct pw_node_info *info = o->info;
|
||||||
struct pw_manager *manager = client->manager;
|
struct pw_manager *manager = client->manager;
|
||||||
struct pw_manager_object *peer;
|
struct pw_manager_object *peer;
|
||||||
|
|
@ -3827,7 +3831,7 @@ static int fill_source_output_info(struct client *client, struct message *m,
|
||||||
(str = spa_dict_lookup(info->props, PW_KEY_CLIENT_ID)) != NULL)
|
(str = spa_dict_lookup(info->props, PW_KEY_CLIENT_ID)) != NULL)
|
||||||
client_id = (uint32_t)atoi(str);
|
client_id = (uint32_t)atoi(str);
|
||||||
|
|
||||||
collect_device_info(o, NULL, &dev_info, false);
|
collect_device_info(o, NULL, &dev_info, false, &impl->defs);
|
||||||
|
|
||||||
if (!sample_spec_valid(&dev_info.ss) ||
|
if (!sample_spec_valid(&dev_info.ss) ||
|
||||||
!channel_map_valid(&dev_info.map) ||
|
!channel_map_valid(&dev_info.map) ||
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue