mirror of
https://gitlab.freedesktop.org/pipewire/pipewire.git
synced 2025-10-29 05:40:27 -04:00
pulse-server: make sample format and channel_map configurable
Add an entry in the config file for default format and channel map. Use the defaults in the server_info request Use the defaults for the default channels and map in the modules.
This commit is contained in:
parent
877309bfbe
commit
b305f57e4d
5 changed files with 82 additions and 44 deletions
|
|
@ -40,6 +40,8 @@ context.modules = [
|
|||
#pulse.default.frag = 96000/48000 # 2 seconds
|
||||
#pulse.default.tlength = 96000/48000 # 2 seconds
|
||||
#pulse.min.quantum = 256/48000 # 5ms
|
||||
#pulse.default.format = "float32ne"
|
||||
#pulse.default.channel_map = "front-left,front-right"
|
||||
}
|
||||
}
|
||||
]
|
||||
|
|
|
|||
|
|
@ -79,13 +79,26 @@ static const struct format audio_formats[] = {
|
|||
[SAMPLE_S24_32LE] = { SAMPLE_S24_32LE, SPA_AUDIO_FORMAT_S24_32_LE, "s24-32le", 4 },
|
||||
[SAMPLE_S24_32BE] = { SAMPLE_S24_32BE, SPA_AUDIO_FORMAT_S24_32_BE, "s24-32be", 4 },
|
||||
|
||||
#if __BYTE_ORDER == __BIG_ENDIAN
|
||||
{ SAMPLE_S16BE, SPA_AUDIO_FORMAT_S16_BE, "s16ne", 2 },
|
||||
{ SAMPLE_FLOAT32BE, SPA_AUDIO_FORMAT_F32_BE, "float32ne", 4 },
|
||||
{ SAMPLE_S32BE, SPA_AUDIO_FORMAT_S32_BE, "s32ne", 4 },
|
||||
{ SAMPLE_S24BE, SPA_AUDIO_FORMAT_S24_BE, "s24ne", 3 },
|
||||
{ SAMPLE_S24_32BE, SPA_AUDIO_FORMAT_S24_32_BE, "s24-32ne", 4 },
|
||||
#elif __BYTE_ORDER == __LITTLE_ENDIAN
|
||||
{ SAMPLE_S16LE, SPA_AUDIO_FORMAT_S16_LE, "s16ne", 2 },
|
||||
{ SAMPLE_FLOAT32LE, SPA_AUDIO_FORMAT_F32_LE, "float32ne", 4 },
|
||||
{ SAMPLE_S32LE, SPA_AUDIO_FORMAT_S32_LE, "s32ne", 4 },
|
||||
{ SAMPLE_S24LE, SPA_AUDIO_FORMAT_S24_LE, "s24ne", 3 },
|
||||
{ SAMPLE_S24_32LE, SPA_AUDIO_FORMAT_S24_32_LE, "s24-32ne", 4 },
|
||||
#endif
|
||||
/* planar formats, we just report them as inteleaved */
|
||||
{ SAMPLE_U8, SPA_AUDIO_FORMAT_U8P, "u8", 1 },
|
||||
{ SAMPLE_S16NE, SPA_AUDIO_FORMAT_S16P, "s16", 2 },
|
||||
{ SAMPLE_S24_32NE, SPA_AUDIO_FORMAT_S24_32P, "s24-32", 4 },
|
||||
{ SAMPLE_S32NE, SPA_AUDIO_FORMAT_S32P, "s32", 4 },
|
||||
{ SAMPLE_S24NE, SPA_AUDIO_FORMAT_S24P, "s24", 3 },
|
||||
{ SAMPLE_FLOAT32NE, SPA_AUDIO_FORMAT_F32P, "float32", 4 },
|
||||
{ SAMPLE_U8, SPA_AUDIO_FORMAT_U8P, "u8ne", 1 },
|
||||
{ SAMPLE_S16NE, SPA_AUDIO_FORMAT_S16P, "s16ne", 2 },
|
||||
{ SAMPLE_S24_32NE, SPA_AUDIO_FORMAT_S24_32P, "s24-32ne", 4 },
|
||||
{ SAMPLE_S32NE, SPA_AUDIO_FORMAT_S32P, "s32ne", 4 },
|
||||
{ SAMPLE_S24NE, SPA_AUDIO_FORMAT_S24P, "s24ne", 3 },
|
||||
{ SAMPLE_FLOAT32NE, SPA_AUDIO_FORMAT_F32P, "float32ne", 4 },
|
||||
};
|
||||
|
||||
static inline uint32_t format_pa2id(enum sample_format format)
|
||||
|
|
@ -108,8 +121,9 @@ static inline const char *format_id2name(uint32_t format)
|
|||
static inline uint32_t format_paname2id(const char *name, size_t size)
|
||||
{
|
||||
size_t i;
|
||||
for (i = 0; i < SAMPLE_MAX; i++) {
|
||||
if (strncmp(name, audio_formats[i].name, size) == 0)
|
||||
for (i = 0; i < SPA_N_ELEMENTS(audio_formats); i++) {
|
||||
if (audio_formats[i].name != NULL &&
|
||||
strncmp(name, audio_formats[i].name, size) == 0)
|
||||
return audio_formats[i].id;
|
||||
}
|
||||
return SPA_AUDIO_FORMAT_UNKNOWN;
|
||||
|
|
@ -146,11 +160,6 @@ struct sample_spec {
|
|||
.rate = 0, \
|
||||
.channels = 0, \
|
||||
}
|
||||
#define SAMPLE_SPEC_DEFAULT (struct sample_spec) { \
|
||||
.format = SPA_AUDIO_FORMAT_F32, \
|
||||
.rate = 44100, \
|
||||
.channels = 2, \
|
||||
}
|
||||
|
||||
static inline uint32_t sample_spec_frame_size(const struct sample_spec *ss)
|
||||
{
|
||||
|
|
@ -325,11 +334,6 @@ struct channel_map {
|
|||
#define CHANNEL_MAP_INIT (struct channel_map) { \
|
||||
.channels = 0, \
|
||||
}
|
||||
#define CHANNEL_MAP_DEFAULT (struct channel_map) { \
|
||||
.channels = 2, \
|
||||
.map[0] = SPA_AUDIO_CHANNEL_FL, \
|
||||
.map[1] = SPA_AUDIO_CHANNEL_FR, \
|
||||
}
|
||||
|
||||
static inline uint32_t channel_pa2id(enum channel_position channel)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -264,7 +264,7 @@ static struct module *create_module_loopback(struct impl *impl, const char *argu
|
|||
info.channels = pw_properties_parse_int(str);
|
||||
pw_properties_set(props, "channels", NULL);
|
||||
} else {
|
||||
info.channels = 2;
|
||||
info.channels = impl->defs.sample_spec.channels;
|
||||
}
|
||||
if ((str = pw_properties_get(props, "rate")) != NULL) {
|
||||
info.rate = pw_properties_parse_int(str);
|
||||
|
|
@ -282,14 +282,15 @@ static struct module *create_module_loopback(struct impl *impl, const char *argu
|
|||
channel_map_to_positions(&map, info.position);
|
||||
pw_properties_set(props, "channel_map", NULL);
|
||||
} else {
|
||||
if (info.channels > 2)
|
||||
ERROR_RETURN("Mismatched channel map");
|
||||
|
||||
if (info.channels == 1) {
|
||||
if (info.channels == impl->defs.channel_map.channels) {
|
||||
channel_map_to_positions(&impl->defs.channel_map, info.position);
|
||||
} else if (info.channels == 1) {
|
||||
info.position[0] = SPA_AUDIO_CHANNEL_MONO;
|
||||
} else {
|
||||
} else if (info.channels == 2) {
|
||||
info.position[0] = SPA_AUDIO_CHANNEL_FL;
|
||||
info.position[1] = SPA_AUDIO_CHANNEL_FR;
|
||||
} else {
|
||||
ERROR_RETURN("Mismatched channel map");
|
||||
}
|
||||
/* TODO: pull in all of pa_channel_map_init_auto() */
|
||||
}
|
||||
|
|
|
|||
|
|
@ -122,6 +122,7 @@ static struct module *create_module_null_sink(struct impl *impl, const char *arg
|
|||
struct module_null_sink_data *d;
|
||||
struct pw_properties *props = NULL;
|
||||
const char *str;
|
||||
struct channel_map map = CHANNEL_MAP_INIT;
|
||||
int res;
|
||||
|
||||
props = pw_properties_new_dict(&SPA_DICT_INIT_ARRAY(module_null_sink_info));
|
||||
|
|
@ -145,27 +146,30 @@ static struct module *create_module_null_sink(struct impl *impl, const char *arg
|
|||
if ((str = pw_properties_get(props, "channels")) != NULL) {
|
||||
pw_properties_set(props, SPA_KEY_AUDIO_CHANNELS, str);
|
||||
pw_properties_set(props, "channels", NULL);
|
||||
} else {
|
||||
pw_properties_setf(props, SPA_KEY_AUDIO_CHANNELS, "%u",
|
||||
impl->defs.sample_spec.channels);
|
||||
}
|
||||
if ((str = pw_properties_get(props, "rate")) != NULL) {
|
||||
pw_properties_set(props, SPA_KEY_AUDIO_RATE, str);
|
||||
pw_properties_set(props, "rate", NULL);
|
||||
}
|
||||
if ((str = pw_properties_get(props, "channel_map")) != NULL) {
|
||||
struct channel_map map = CHANNEL_MAP_INIT;
|
||||
channel_map_parse(str, &map);
|
||||
pw_properties_set(props, "channel_map", NULL);
|
||||
} else {
|
||||
map = impl->defs.channel_map;
|
||||
}
|
||||
if (map.channels > 0) {
|
||||
uint32_t i;
|
||||
char *s, *p;
|
||||
|
||||
channel_map_parse(str, &map);
|
||||
p = s = alloca(map.channels * 6);
|
||||
|
||||
for (i = 0; i < map.channels; i++)
|
||||
p += snprintf(p, 6, "%s%s", i == 0 ? "" : ",",
|
||||
channel_id2name(map.map[i]));
|
||||
pw_properties_set(props, SPA_KEY_AUDIO_POSITION, s);
|
||||
pw_properties_set(props, "channel_map", NULL);
|
||||
} else if (pw_properties_get(props, SPA_KEY_AUDIO_POSITION) == NULL) {
|
||||
pw_properties_set(props, SPA_KEY_AUDIO_POSITION, "FL,FR");
|
||||
}
|
||||
|
||||
if ((str = pw_properties_get(props, PW_KEY_MEDIA_CLASS)) == NULL)
|
||||
pw_properties_set(props, PW_KEY_MEDIA_CLASS, "Audio/Sink");
|
||||
|
||||
|
|
|
|||
|
|
@ -92,9 +92,17 @@ struct stats {
|
|||
#define DEFAULT_DEFAULT_FRAG "96000/48000"
|
||||
#define DEFAULT_DEFAULT_TLENGTH "96000/48000"
|
||||
#define DEFAULT_MIN_QUANTUM "256/48000"
|
||||
#define DEFAULT_FORMAT "float32le"
|
||||
#define DEFAULT_CHANNEL_MAP "front-left,front-right"
|
||||
|
||||
#define MAX_FORMATS 32
|
||||
|
||||
#include "format.c"
|
||||
#include "volume.c"
|
||||
#include "message.c"
|
||||
#include "manager.h"
|
||||
#include "dbus-name.c"
|
||||
|
||||
struct defs {
|
||||
struct spa_fraction min_req;
|
||||
struct spa_fraction default_req;
|
||||
|
|
@ -102,14 +110,10 @@ struct defs {
|
|||
struct spa_fraction default_frag;
|
||||
struct spa_fraction default_tlength;
|
||||
struct spa_fraction min_quantum;
|
||||
struct sample_spec sample_spec;
|
||||
struct channel_map channel_map;
|
||||
};
|
||||
|
||||
#include "format.c"
|
||||
#include "volume.c"
|
||||
#include "message.c"
|
||||
#include "manager.h"
|
||||
#include "dbus-name.c"
|
||||
|
||||
#define NAME "pulse-server"
|
||||
|
||||
static bool debug_messages = false;
|
||||
|
|
@ -3669,19 +3673,15 @@ static int do_get_server_info(struct client *client, uint32_t command, uint32_t
|
|||
char name[256];
|
||||
const char *str;
|
||||
struct message *reply;
|
||||
struct sample_spec ss;
|
||||
struct channel_map map;
|
||||
uint32_t cookie;
|
||||
|
||||
pw_log_info(NAME" %p: [%s] GET_SERVER_INFO tag:%u", impl, client->name, tag);
|
||||
|
||||
ss = SAMPLE_SPEC_DEFAULT;
|
||||
map = CHANNEL_MAP_DEFAULT;
|
||||
|
||||
if (info != NULL) {
|
||||
if (info->props &&
|
||||
(str = spa_dict_lookup(info->props, "default.clock.rate")) != NULL)
|
||||
ss.rate = atoi(str);
|
||||
impl->defs.sample_spec.rate = atoi(str);
|
||||
cookie = info->cookie;
|
||||
} else {
|
||||
cookie = 0;
|
||||
|
|
@ -3695,7 +3695,7 @@ static int do_get_server_info(struct client *client, uint32_t command, uint32_t
|
|||
TAG_STRING, "14.0.0",
|
||||
TAG_STRING, pw_get_user_name(),
|
||||
TAG_STRING, pw_get_host_name(),
|
||||
TAG_SAMPLE_SPEC, &ss,
|
||||
TAG_SAMPLE_SPEC, &impl->defs.sample_spec,
|
||||
TAG_STRING, get_default(client, true), /* default sink name */
|
||||
TAG_STRING, get_default(client, false), /* default source name */
|
||||
TAG_U32, cookie, /* cookie */
|
||||
|
|
@ -3703,7 +3703,7 @@ static int do_get_server_info(struct client *client, uint32_t command, uint32_t
|
|||
|
||||
if (client->version >= 15) {
|
||||
message_put(reply,
|
||||
TAG_CHANNEL_MAP, &map,
|
||||
TAG_CHANNEL_MAP, &impl->defs.channel_map,
|
||||
TAG_INVALID);
|
||||
}
|
||||
return send_message(client, reply);
|
||||
|
|
@ -6357,6 +6357,30 @@ static int parse_frac(struct pw_properties *props, const char *key, const char *
|
|||
pw_log_info(NAME": defaults: %s = %u/%u", key, res->num, res->denom);
|
||||
return 0;
|
||||
}
|
||||
static int parse_channel_map(struct pw_properties *props, const char *key, const char *def,
|
||||
struct channel_map *res)
|
||||
{
|
||||
const char *str;
|
||||
if (props == NULL ||
|
||||
(str = pw_properties_get(props, key)) == NULL)
|
||||
str = def;
|
||||
channel_map_parse(str, res);
|
||||
pw_log_info(NAME": defaults: %s = %s", key, str);
|
||||
return 0;
|
||||
}
|
||||
static int parse_format(struct pw_properties *props, const char *key, const char *def,
|
||||
struct sample_spec *res)
|
||||
{
|
||||
const char *str;
|
||||
if (props == NULL ||
|
||||
(str = pw_properties_get(props, key)) == NULL)
|
||||
str = def;
|
||||
res->format = format_paname2id(str, strlen(str));
|
||||
if (res->format == SPA_AUDIO_FORMAT_UNKNOWN)
|
||||
res->format = SPA_AUDIO_FORMAT_F32;
|
||||
pw_log_info(NAME": defaults: %s = %s", key, str);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void load_defaults(struct defs *def, struct pw_properties *props)
|
||||
{
|
||||
|
|
@ -6366,6 +6390,9 @@ static void load_defaults(struct defs *def, struct pw_properties *props)
|
|||
parse_frac(props, "pulse.default.frag", DEFAULT_DEFAULT_FRAG, &def->default_frag);
|
||||
parse_frac(props, "pulse.default.tlength", DEFAULT_DEFAULT_TLENGTH, &def->default_tlength);
|
||||
parse_frac(props, "pulse.min.quantum", DEFAULT_MIN_QUANTUM, &def->min_quantum);
|
||||
parse_format(props, "pulse.default.format", DEFAULT_FORMAT, &def->sample_spec);
|
||||
parse_channel_map(props, "pulse.default.channel_map", DEFAULT_CHANNEL_MAP, &def->channel_map);
|
||||
def->sample_spec.channels = def->channel_map.channels;
|
||||
}
|
||||
|
||||
struct pw_protocol_pulse *pw_protocol_pulse_new(struct pw_context *context,
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue