mirror of
https://gitlab.freedesktop.org/pipewire/pipewire.git
synced 2025-12-16 08:56:45 -05: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.frag = 96000/48000 # 2 seconds
|
||||||
#pulse.default.tlength = 96000/48000 # 2 seconds
|
#pulse.default.tlength = 96000/48000 # 2 seconds
|
||||||
#pulse.min.quantum = 256/48000 # 5ms
|
#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_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 },
|
[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 */
|
/* planar formats, we just report them as inteleaved */
|
||||||
{ SAMPLE_U8, SPA_AUDIO_FORMAT_U8P, "u8", 1 },
|
{ SAMPLE_U8, SPA_AUDIO_FORMAT_U8P, "u8ne", 1 },
|
||||||
{ SAMPLE_S16NE, SPA_AUDIO_FORMAT_S16P, "s16", 2 },
|
{ SAMPLE_S16NE, SPA_AUDIO_FORMAT_S16P, "s16ne", 2 },
|
||||||
{ SAMPLE_S24_32NE, SPA_AUDIO_FORMAT_S24_32P, "s24-32", 4 },
|
{ SAMPLE_S24_32NE, SPA_AUDIO_FORMAT_S24_32P, "s24-32ne", 4 },
|
||||||
{ SAMPLE_S32NE, SPA_AUDIO_FORMAT_S32P, "s32", 4 },
|
{ SAMPLE_S32NE, SPA_AUDIO_FORMAT_S32P, "s32ne", 4 },
|
||||||
{ SAMPLE_S24NE, SPA_AUDIO_FORMAT_S24P, "s24", 3 },
|
{ SAMPLE_S24NE, SPA_AUDIO_FORMAT_S24P, "s24ne", 3 },
|
||||||
{ SAMPLE_FLOAT32NE, SPA_AUDIO_FORMAT_F32P, "float32", 4 },
|
{ SAMPLE_FLOAT32NE, SPA_AUDIO_FORMAT_F32P, "float32ne", 4 },
|
||||||
};
|
};
|
||||||
|
|
||||||
static inline uint32_t format_pa2id(enum sample_format format)
|
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)
|
static inline uint32_t format_paname2id(const char *name, size_t size)
|
||||||
{
|
{
|
||||||
size_t i;
|
size_t i;
|
||||||
for (i = 0; i < SAMPLE_MAX; i++) {
|
for (i = 0; i < SPA_N_ELEMENTS(audio_formats); i++) {
|
||||||
if (strncmp(name, audio_formats[i].name, size) == 0)
|
if (audio_formats[i].name != NULL &&
|
||||||
|
strncmp(name, audio_formats[i].name, size) == 0)
|
||||||
return audio_formats[i].id;
|
return audio_formats[i].id;
|
||||||
}
|
}
|
||||||
return SPA_AUDIO_FORMAT_UNKNOWN;
|
return SPA_AUDIO_FORMAT_UNKNOWN;
|
||||||
|
|
@ -146,11 +160,6 @@ struct sample_spec {
|
||||||
.rate = 0, \
|
.rate = 0, \
|
||||||
.channels = 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)
|
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) { \
|
#define CHANNEL_MAP_INIT (struct channel_map) { \
|
||||||
.channels = 0, \
|
.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)
|
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);
|
info.channels = pw_properties_parse_int(str);
|
||||||
pw_properties_set(props, "channels", NULL);
|
pw_properties_set(props, "channels", NULL);
|
||||||
} else {
|
} else {
|
||||||
info.channels = 2;
|
info.channels = impl->defs.sample_spec.channels;
|
||||||
}
|
}
|
||||||
if ((str = pw_properties_get(props, "rate")) != NULL) {
|
if ((str = pw_properties_get(props, "rate")) != NULL) {
|
||||||
info.rate = pw_properties_parse_int(str);
|
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);
|
channel_map_to_positions(&map, info.position);
|
||||||
pw_properties_set(props, "channel_map", NULL);
|
pw_properties_set(props, "channel_map", NULL);
|
||||||
} else {
|
} else {
|
||||||
if (info.channels > 2)
|
if (info.channels == impl->defs.channel_map.channels) {
|
||||||
ERROR_RETURN("Mismatched channel map");
|
channel_map_to_positions(&impl->defs.channel_map, info.position);
|
||||||
|
} else if (info.channels == 1) {
|
||||||
if (info.channels == 1) {
|
|
||||||
info.position[0] = SPA_AUDIO_CHANNEL_MONO;
|
info.position[0] = SPA_AUDIO_CHANNEL_MONO;
|
||||||
} else {
|
} else if (info.channels == 2) {
|
||||||
info.position[0] = SPA_AUDIO_CHANNEL_FL;
|
info.position[0] = SPA_AUDIO_CHANNEL_FL;
|
||||||
info.position[1] = SPA_AUDIO_CHANNEL_FR;
|
info.position[1] = SPA_AUDIO_CHANNEL_FR;
|
||||||
|
} else {
|
||||||
|
ERROR_RETURN("Mismatched channel map");
|
||||||
}
|
}
|
||||||
/* TODO: pull in all of pa_channel_map_init_auto() */
|
/* 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 module_null_sink_data *d;
|
||||||
struct pw_properties *props = NULL;
|
struct pw_properties *props = NULL;
|
||||||
const char *str;
|
const char *str;
|
||||||
|
struct channel_map map = CHANNEL_MAP_INIT;
|
||||||
int res;
|
int res;
|
||||||
|
|
||||||
props = pw_properties_new_dict(&SPA_DICT_INIT_ARRAY(module_null_sink_info));
|
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) {
|
if ((str = pw_properties_get(props, "channels")) != NULL) {
|
||||||
pw_properties_set(props, SPA_KEY_AUDIO_CHANNELS, str);
|
pw_properties_set(props, SPA_KEY_AUDIO_CHANNELS, str);
|
||||||
pw_properties_set(props, "channels", NULL);
|
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) {
|
if ((str = pw_properties_get(props, "rate")) != NULL) {
|
||||||
pw_properties_set(props, SPA_KEY_AUDIO_RATE, str);
|
pw_properties_set(props, SPA_KEY_AUDIO_RATE, str);
|
||||||
pw_properties_set(props, "rate", NULL);
|
pw_properties_set(props, "rate", NULL);
|
||||||
}
|
}
|
||||||
if ((str = pw_properties_get(props, "channel_map")) != 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;
|
uint32_t i;
|
||||||
char *s, *p;
|
char *s, *p;
|
||||||
|
|
||||||
channel_map_parse(str, &map);
|
|
||||||
p = s = alloca(map.channels * 6);
|
p = s = alloca(map.channels * 6);
|
||||||
|
|
||||||
for (i = 0; i < map.channels; i++)
|
for (i = 0; i < map.channels; i++)
|
||||||
p += snprintf(p, 6, "%s%s", i == 0 ? "" : ",",
|
p += snprintf(p, 6, "%s%s", i == 0 ? "" : ",",
|
||||||
channel_id2name(map.map[i]));
|
channel_id2name(map.map[i]));
|
||||||
pw_properties_set(props, SPA_KEY_AUDIO_POSITION, s);
|
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)
|
if ((str = pw_properties_get(props, PW_KEY_MEDIA_CLASS)) == NULL)
|
||||||
pw_properties_set(props, PW_KEY_MEDIA_CLASS, "Audio/Sink");
|
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_FRAG "96000/48000"
|
||||||
#define DEFAULT_DEFAULT_TLENGTH "96000/48000"
|
#define DEFAULT_DEFAULT_TLENGTH "96000/48000"
|
||||||
#define DEFAULT_MIN_QUANTUM "256/48000"
|
#define DEFAULT_MIN_QUANTUM "256/48000"
|
||||||
|
#define DEFAULT_FORMAT "float32le"
|
||||||
|
#define DEFAULT_CHANNEL_MAP "front-left,front-right"
|
||||||
|
|
||||||
#define MAX_FORMATS 32
|
#define MAX_FORMATS 32
|
||||||
|
|
||||||
|
#include "format.c"
|
||||||
|
#include "volume.c"
|
||||||
|
#include "message.c"
|
||||||
|
#include "manager.h"
|
||||||
|
#include "dbus-name.c"
|
||||||
|
|
||||||
struct defs {
|
struct defs {
|
||||||
struct spa_fraction min_req;
|
struct spa_fraction min_req;
|
||||||
struct spa_fraction default_req;
|
struct spa_fraction default_req;
|
||||||
|
|
@ -102,14 +110,10 @@ struct defs {
|
||||||
struct spa_fraction default_frag;
|
struct spa_fraction default_frag;
|
||||||
struct spa_fraction default_tlength;
|
struct spa_fraction default_tlength;
|
||||||
struct spa_fraction min_quantum;
|
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"
|
#define NAME "pulse-server"
|
||||||
|
|
||||||
static bool debug_messages = false;
|
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];
|
char name[256];
|
||||||
const char *str;
|
const char *str;
|
||||||
struct message *reply;
|
struct message *reply;
|
||||||
struct sample_spec ss;
|
|
||||||
struct channel_map map;
|
|
||||||
uint32_t cookie;
|
uint32_t cookie;
|
||||||
|
|
||||||
pw_log_info(NAME" %p: [%s] GET_SERVER_INFO tag:%u", impl, client->name, tag);
|
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 != NULL) {
|
||||||
if (info->props &&
|
if (info->props &&
|
||||||
(str = spa_dict_lookup(info->props, "default.clock.rate")) != NULL)
|
(str = spa_dict_lookup(info->props, "default.clock.rate")) != NULL)
|
||||||
ss.rate = atoi(str);
|
impl->defs.sample_spec.rate = atoi(str);
|
||||||
cookie = info->cookie;
|
cookie = info->cookie;
|
||||||
} else {
|
} else {
|
||||||
cookie = 0;
|
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, "14.0.0",
|
||||||
TAG_STRING, pw_get_user_name(),
|
TAG_STRING, pw_get_user_name(),
|
||||||
TAG_STRING, pw_get_host_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, true), /* default sink name */
|
||||||
TAG_STRING, get_default(client, false), /* default source name */
|
TAG_STRING, get_default(client, false), /* default source name */
|
||||||
TAG_U32, cookie, /* cookie */
|
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) {
|
if (client->version >= 15) {
|
||||||
message_put(reply,
|
message_put(reply,
|
||||||
TAG_CHANNEL_MAP, &map,
|
TAG_CHANNEL_MAP, &impl->defs.channel_map,
|
||||||
TAG_INVALID);
|
TAG_INVALID);
|
||||||
}
|
}
|
||||||
return send_message(client, reply);
|
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);
|
pw_log_info(NAME": defaults: %s = %u/%u", key, res->num, res->denom);
|
||||||
return 0;
|
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)
|
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.frag", DEFAULT_DEFAULT_FRAG, &def->default_frag);
|
||||||
parse_frac(props, "pulse.default.tlength", DEFAULT_DEFAULT_TLENGTH, &def->default_tlength);
|
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_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,
|
struct pw_protocol_pulse *pw_protocol_pulse_new(struct pw_context *context,
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue