mirror of
https://gitlab.freedesktop.org/pipewire/pipewire.git
synced 2025-10-31 22:25:38 -04:00
pulse-server: use channelmap
Convert to an from pulse enum to id in the message layer so that we can always just deal with native spa types. Use the channelmap in stream-restore Parse the channelmap from properties.
This commit is contained in:
parent
2b95afeddc
commit
f95f278067
5 changed files with 108 additions and 49 deletions
|
|
@ -135,7 +135,7 @@ static int do_extension_stream_restore_read(struct client *client, uint32_t comm
|
|||
if (key_to_name(item->key, name, sizeof(name)) < 0)
|
||||
continue;
|
||||
|
||||
pw_log_info("%s -> %s", item->key, name);
|
||||
pw_log_debug("%s -> %s: %s", item->key, name, item->value);
|
||||
|
||||
spa_json_init(&it[0], item->value, strlen(item->value));
|
||||
if (spa_json_enter_object(&it[0], &it[1]) <= 0)
|
||||
|
|
@ -151,6 +151,7 @@ static int do_extension_stream_restore_read(struct client *client, uint32_t comm
|
|||
continue;
|
||||
}
|
||||
else if (strncmp(value, "\"volumes\"", len) == 0) {
|
||||
vol = VOLUME_INIT;
|
||||
if (spa_json_enter_array(&it[1], &it[2]) <= 0)
|
||||
continue;
|
||||
|
||||
|
|
@ -159,6 +160,17 @@ static int do_extension_stream_restore_read(struct client *client, uint32_t comm
|
|||
break;
|
||||
}
|
||||
}
|
||||
else if (strncmp(value, "\"channels\"", len) == 0) {
|
||||
if (spa_json_enter_array(&it[1], &it[2]) <= 0)
|
||||
continue;
|
||||
|
||||
for (map.channels = 0; map.channels < CHANNELS_MAX; map.channels++) {
|
||||
char chname[16];
|
||||
if (spa_json_get_string(&it[2], chname, sizeof(chname)) <= 0)
|
||||
break;
|
||||
map.map[map.channels] = channel_name2id(chname);
|
||||
}
|
||||
}
|
||||
else if (strncmp(value, "\"target-node\"", len) == 0) {
|
||||
if (spa_json_get_string(&it[1], device_name, sizeof(device_name)) <= 0)
|
||||
continue;
|
||||
|
|
@ -191,7 +203,7 @@ static int do_extension_stream_restore_write(struct client *client, uint32_t com
|
|||
return -EPROTO;
|
||||
|
||||
while (m->offset < m->length) {
|
||||
const char *name, *device_name;
|
||||
const char *name, *device_name = NULL;
|
||||
struct channel_map map;
|
||||
struct volume vol;
|
||||
bool mute = false;
|
||||
|
|
@ -201,6 +213,9 @@ static int do_extension_stream_restore_write(struct client *client, uint32_t com
|
|||
size_t size;
|
||||
char key[1024];
|
||||
|
||||
spa_zero(map);
|
||||
spa_zero(vol);
|
||||
|
||||
message_get(m,
|
||||
TAG_STRING, &name,
|
||||
TAG_CHANNEL_MAP, &map,
|
||||
|
|
@ -214,18 +229,26 @@ static int do_extension_stream_restore_write(struct client *client, uint32_t com
|
|||
|
||||
f = open_memstream(&ptr, &size);
|
||||
fprintf(f, "{");
|
||||
fprintf(f, " \"mute\": %s ", mute ? "true" : "false");
|
||||
fprintf(f, ", \"volumes\": [");
|
||||
for (i = 0; i < vol.channels; i++)
|
||||
fprintf(f, "%s%f", (i == 0 ? " ":", "), vol.values[i]);
|
||||
fprintf(f, " ] ");
|
||||
fprintf(f, " \"mute\": %s", mute ? "true" : "false");
|
||||
if (vol.channels > 0) {
|
||||
fprintf(f, ", \"volumes\": [");
|
||||
for (i = 0; i < vol.channels; i++)
|
||||
fprintf(f, "%s%f", (i == 0 ? " ":", "), vol.values[i]);
|
||||
fprintf(f, " ]");
|
||||
}
|
||||
if (map.channels > 0) {
|
||||
fprintf(f, ", \"channels\": [");
|
||||
for (i = 0; i < map.channels; i++)
|
||||
fprintf(f, "%s\"%s\"", (i == 0 ? " ":", "), channel_id2name(map.map[i]));
|
||||
fprintf(f, " ]");
|
||||
}
|
||||
if (device_name != NULL && device_name[0])
|
||||
fprintf(f, ", \"target-node\": \"%s\"", device_name);
|
||||
fprintf(f, "}");
|
||||
fprintf(f, " }");
|
||||
fclose(f);
|
||||
|
||||
if (key_from_name(name, key, sizeof(key)) >= 0) {
|
||||
pw_log_info("%s -> %s", name, key);
|
||||
pw_log_debug("%s -> %s: %s", name, key, ptr);
|
||||
pw_manager_set_metadata(client->manager,
|
||||
client->metadata_routes,
|
||||
PW_ID_CORE, key, "Spa:String:JSON", "%s", ptr);
|
||||
|
|
|
|||
|
|
@ -72,21 +72,24 @@ static inline uint32_t format_pa2id(enum sample_format format)
|
|||
return audio_formats[format].format;
|
||||
}
|
||||
|
||||
static inline const char *format_pa2name(enum sample_format format)
|
||||
static inline const char *format_id2name(uint32_t format)
|
||||
{
|
||||
if (format < 0 || (size_t)format >= SPA_N_ELEMENTS(audio_formats))
|
||||
return "invalid";
|
||||
return audio_formats[format].name;
|
||||
int i;
|
||||
for (i = 0; spa_type_audio_format[i].name; i++) {
|
||||
if (spa_type_audio_format[i].type == format)
|
||||
return spa_debug_type_short_name(spa_type_audio_format[i].name);
|
||||
}
|
||||
return "UNKNOWN";
|
||||
}
|
||||
|
||||
static inline enum sample_format format_name2pa(const char *name, size_t size)
|
||||
static inline uint32_t format_paname2id(const char *name, size_t size)
|
||||
{
|
||||
size_t i;
|
||||
for (i = 0; i < SPA_N_ELEMENTS(audio_formats); i++) {
|
||||
if (strncmp(name, audio_formats[i].name, size) == 0)
|
||||
return i;
|
||||
return audio_formats[i].format;
|
||||
}
|
||||
return SAMPLE_INVALID;
|
||||
return SPA_AUDIO_FORMAT_UNKNOWN;
|
||||
}
|
||||
|
||||
static inline enum sample_format format_id2pa(uint32_t id)
|
||||
|
|
@ -100,26 +103,42 @@ static inline enum sample_format format_id2pa(uint32_t id)
|
|||
}
|
||||
|
||||
struct sample_spec {
|
||||
enum sample_format format;
|
||||
uint32_t format;
|
||||
uint32_t rate;
|
||||
uint8_t channels;
|
||||
};
|
||||
#define SAMPLE_SPEC_INIT (struct sample_spec) { \
|
||||
.format = SAMPLE_FLOAT32LE, \
|
||||
.format = SPA_AUDIO_FORMAT_F32, \
|
||||
.rate = 44100, \
|
||||
.channels = 2, \
|
||||
}
|
||||
|
||||
static inline uint32_t sample_spec_frame_size(const struct sample_spec *ss)
|
||||
{
|
||||
if (ss->format < 0 || (size_t)ss->format >= SPA_N_ELEMENTS(audio_formats))
|
||||
switch (ss->format) {
|
||||
case SPA_AUDIO_FORMAT_U8:
|
||||
return ss->channels;
|
||||
case SPA_AUDIO_FORMAT_S16_LE:
|
||||
case SPA_AUDIO_FORMAT_S16_BE:
|
||||
return 2 * ss->channels;
|
||||
case SPA_AUDIO_FORMAT_S24_LE:
|
||||
case SPA_AUDIO_FORMAT_S24_BE:
|
||||
return 3 * ss->channels;
|
||||
case SPA_AUDIO_FORMAT_F32_LE:
|
||||
case SPA_AUDIO_FORMAT_F32_BE:
|
||||
case SPA_AUDIO_FORMAT_S32_LE:
|
||||
case SPA_AUDIO_FORMAT_S32_BE:
|
||||
case SPA_AUDIO_FORMAT_S24_32_LE:
|
||||
case SPA_AUDIO_FORMAT_S24_32_BE:
|
||||
return 4 * ss->channels;
|
||||
default:
|
||||
return 0;
|
||||
return audio_formats[ss->format].size * ss->channels;
|
||||
}
|
||||
}
|
||||
|
||||
static inline bool sample_spec_valid(const struct sample_spec *ss)
|
||||
{
|
||||
return (ss->format < SAMPLE_MAX &&
|
||||
return (sample_spec_frame_size(ss) > 0 &&
|
||||
ss->rate > 0 && ss->rate <= RATE_MAX &&
|
||||
ss->channels > 0 && ss->channels <= CHANNELS_MAX);
|
||||
}
|
||||
|
|
@ -256,13 +275,13 @@ static const struct channel audio_channels[] = {
|
|||
|
||||
struct channel_map {
|
||||
uint8_t channels;
|
||||
enum channel_position map[CHANNELS_MAX];
|
||||
uint32_t map[CHANNELS_MAX];
|
||||
};
|
||||
|
||||
#define CHANNEL_MAP_INIT (struct channel_map) { \
|
||||
.channels = 2, \
|
||||
.map[0] = CHANNEL_POSITION_FRONT_LEFT, \
|
||||
.map[1] = CHANNEL_POSITION_FRONT_RIGHT, \
|
||||
.map[0] = SPA_AUDIO_CHANNEL_FL, \
|
||||
.map[1] = SPA_AUDIO_CHANNEL_FR, \
|
||||
}
|
||||
|
||||
static inline uint32_t channel_pa2id(enum channel_position channel)
|
||||
|
|
@ -272,11 +291,24 @@ static inline uint32_t channel_pa2id(enum channel_position channel)
|
|||
return audio_channels[channel].channel;
|
||||
}
|
||||
|
||||
static inline const char *channel_pa2name(enum channel_position channel)
|
||||
static inline const char *channel_id2name(uint32_t channel)
|
||||
{
|
||||
if (channel < 0 || (size_t)channel >= SPA_N_ELEMENTS(audio_channels))
|
||||
return "invalid";
|
||||
return audio_channels[channel].name;
|
||||
int i;
|
||||
for (i = 0; spa_type_audio_channel[i].name; i++) {
|
||||
if (spa_type_audio_channel[i].type == channel)
|
||||
return spa_debug_type_short_name(spa_type_audio_channel[i].name);
|
||||
}
|
||||
return "UNK";
|
||||
}
|
||||
|
||||
static inline uint32_t channel_name2id(const char *name)
|
||||
{
|
||||
int i;
|
||||
for (i = 0; spa_type_audio_channel[i].name; i++) {
|
||||
if (strcmp(name, spa_type_audio_channel[i].name) == 0)
|
||||
return spa_type_audio_channel[i].type;
|
||||
}
|
||||
return SPA_AUDIO_CHANNEL_UNKNOWN;
|
||||
}
|
||||
|
||||
static inline enum channel_position channel_id2pa(uint32_t id, uint32_t *aux)
|
||||
|
|
@ -290,14 +322,14 @@ static inline enum channel_position channel_id2pa(uint32_t id, uint32_t *aux)
|
|||
}
|
||||
|
||||
|
||||
static inline enum channel_position channel_name2pa(const char *name, size_t size)
|
||||
static inline uint32_t channel_paname2id(const char *name, size_t size)
|
||||
{
|
||||
size_t i;
|
||||
for (i = 0; i < SPA_N_ELEMENTS(audio_channels); i++) {
|
||||
if (strncmp(name, audio_channels[i].name, size) == 0)
|
||||
return i;
|
||||
return audio_channels[i].channel;
|
||||
}
|
||||
return CHANNEL_POSITION_INVALID;
|
||||
return SPA_AUDIO_CHANNEL_UNKNOWN;
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -305,7 +337,7 @@ static inline void channel_map_to_positions(const struct channel_map *map, uint3
|
|||
{
|
||||
int i;
|
||||
for (i = 0; i < map->channels; i++)
|
||||
pos[i] = channel_pa2id(map->map[i]);
|
||||
pos[i] = map->map[i];
|
||||
}
|
||||
|
||||
static inline bool channel_map_valid(const struct channel_map *map)
|
||||
|
|
@ -314,7 +346,7 @@ static inline bool channel_map_valid(const struct channel_map *map)
|
|||
if (map->channels == 0 || map->channels > CHANNELS_MAX)
|
||||
return false;
|
||||
for (i = 0; i < map->channels; i++)
|
||||
if (map->map[i] < 0 || map->map[i] >= CHANNEL_POSITION_MAX)
|
||||
if (map->map[i] >= CHANNEL_POSITION_MAX)
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
|
@ -349,7 +381,7 @@ static void format_info_clear(struct format_info *info)
|
|||
static int format_parse_param(const struct spa_pod *param, struct sample_spec *ss, struct channel_map *map)
|
||||
{
|
||||
struct spa_audio_info info = { 0 };
|
||||
uint32_t i, aux = 0;
|
||||
uint32_t i;
|
||||
|
||||
spa_format_parse(param, &info.media_type, &info.media_subtype);
|
||||
|
||||
|
|
@ -360,17 +392,14 @@ static int format_parse_param(const struct spa_pod *param, struct sample_spec *s
|
|||
return -ENOTSUP;
|
||||
}
|
||||
if (ss) {
|
||||
ss->format = format_id2pa(info.info.raw.format);
|
||||
if (ss->format == SAMPLE_INVALID)
|
||||
return -ENOTSUP;
|
||||
|
||||
ss->format = info.info.raw.format;
|
||||
ss->rate = info.info.raw.rate;
|
||||
ss->channels = info.info.raw.channels;
|
||||
}
|
||||
if (map) {
|
||||
map->channels = info.info.raw.channels;
|
||||
for (i = 0; i < map->channels; i++)
|
||||
map->map[i] = channel_id2pa(info.info.raw.position[i], &aux);
|
||||
map->map[i] = info.info.raw.position[i];
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -381,7 +410,7 @@ static const struct spa_pod *format_build_param(struct spa_pod_builder *b,
|
|||
struct spa_audio_info_raw info;
|
||||
|
||||
info = SPA_AUDIO_INFO_RAW_INIT(
|
||||
.format = format_pa2id(spec->format),
|
||||
.format = spec->format,
|
||||
.channels = spec->channels,
|
||||
.rate = spec->rate);
|
||||
if (map)
|
||||
|
|
@ -406,8 +435,8 @@ static const struct spa_pod *format_info_build_param(struct spa_pod_builder *b,
|
|||
if (str[0] != '\"')
|
||||
return NULL;
|
||||
size = strcspn(++str, "\"");
|
||||
ss.format = format_name2pa(str, size);
|
||||
if (ss.format == SAMPLE_INVALID)
|
||||
ss.format = format_paname2id(str, size);
|
||||
if (ss.format == SPA_AUDIO_FORMAT_UNKNOWN)
|
||||
return NULL;
|
||||
|
||||
if ((str = pw_properties_get(info->props, "format.rate")) == NULL)
|
||||
|
|
@ -421,7 +450,7 @@ static const struct spa_pod *format_info_build_param(struct spa_pod_builder *b,
|
|||
if ((str = pw_properties_get(info->props, "format.channel_map")) != NULL) {
|
||||
while ((*str == '\"' || *str == ',') &&
|
||||
(size = strcspn(++str, "\",")) > 0) {
|
||||
map.map[map.channels++] = channel_name2pa(str, size);
|
||||
map.map[map.channels++] = channel_paname2id(str, size);
|
||||
str += size;
|
||||
}
|
||||
if (map.channels == ss.channels)
|
||||
|
|
|
|||
|
|
@ -164,7 +164,7 @@ static int read_sample_spec(struct message *m, struct sample_spec *ss)
|
|||
uint8_t tmp;
|
||||
if ((res = read_u8(m, &tmp)) < 0)
|
||||
return res;
|
||||
ss->format = tmp;
|
||||
ss->format = format_pa2id(tmp);
|
||||
if ((res = read_u8(m, &ss->channels)) < 0)
|
||||
return res;
|
||||
return read_u32(m, &ss->rate);
|
||||
|
|
@ -264,7 +264,7 @@ static int read_channel_map(struct message *m, struct channel_map *map)
|
|||
for (i = 0; i < map->channels; i ++) {
|
||||
if ((res = read_u8(m, &tmp)) < 0)
|
||||
return res;
|
||||
map->map[i] = tmp;
|
||||
map->map[i] = channel_pa2id(tmp);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -498,7 +498,7 @@ static void write_64(struct message *m, uint8_t tag, uint64_t val)
|
|||
static void write_sample_spec(struct message *m, struct sample_spec *ss)
|
||||
{
|
||||
write_8(m, TAG_SAMPLE_SPEC);
|
||||
write_8(m, ss->format);
|
||||
write_8(m, format_id2pa(ss->format));
|
||||
write_8(m, ss->channels);
|
||||
write_32(m, ss->rate);
|
||||
}
|
||||
|
|
@ -527,10 +527,11 @@ static void write_timeval(struct message *m, struct timeval *tv)
|
|||
static void write_channel_map(struct message *m, struct channel_map *map)
|
||||
{
|
||||
uint8_t i;
|
||||
uint32_t aux = 0;
|
||||
write_8(m, TAG_CHANNEL_MAP);
|
||||
write_8(m, map->channels);
|
||||
for (i = 0; i < map->channels; i ++)
|
||||
write_8(m, map->map[i]);
|
||||
write_8(m, channel_id2pa(map->map[i], &aux));
|
||||
}
|
||||
|
||||
static void write_volume(struct message *m, float vol)
|
||||
|
|
@ -768,7 +769,7 @@ static int message_dump(enum spa_log_level level, struct message *m)
|
|||
if ((res = read_sample_spec(m, &ss)) < 0)
|
||||
return res;
|
||||
pw_log(level, "%u: ss: format:%s rate:%d channels:%u", o,
|
||||
format_pa2name(ss.format), ss.rate,
|
||||
format_id2name(ss.format), ss.rate,
|
||||
ss.channels);
|
||||
break;
|
||||
}
|
||||
|
|
@ -802,7 +803,7 @@ static int message_dump(enum spa_log_level level, struct message *m)
|
|||
return res;
|
||||
pw_log(level, "%u: channelmap: channels:%u", o, map.channels);
|
||||
for (i = 0; i < map.channels; i++)
|
||||
pw_log(level, " %d: %s", i, channel_pa2name(map.map[i]));
|
||||
pw_log(level, " %d: %s", i, channel_id2name(map.map[i]));
|
||||
break;
|
||||
}
|
||||
case TAG_CVOLUME:
|
||||
|
|
|
|||
|
|
@ -55,6 +55,7 @@
|
|||
#include <spa/utils/result.h>
|
||||
#include <spa/debug/dict.h>
|
||||
#include <spa/debug/mem.h>
|
||||
#include <spa/debug/types.h>
|
||||
#include <spa/param/audio/raw.h>
|
||||
#include <spa/pod/pod.h>
|
||||
#include <spa/param/audio/format-utils.h>
|
||||
|
|
|
|||
|
|
@ -35,6 +35,7 @@ struct volume {
|
|||
|
||||
struct volume_info {
|
||||
struct volume volume;
|
||||
struct channel_map map;
|
||||
bool mute;
|
||||
float level;
|
||||
float base;
|
||||
|
|
@ -87,6 +88,10 @@ static int volume_parse_param(const struct spa_pod *param, struct volume_info *i
|
|||
info->steps = 0x10000u * step;
|
||||
break;
|
||||
}
|
||||
case SPA_PROP_channelMap:
|
||||
info->map.channels = spa_pod_copy_array(&prop->value, SPA_TYPE_Id,
|
||||
info->map.map, SPA_AUDIO_MAX_CHANNELS);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue