mirror of
https://gitlab.freedesktop.org/pipewire/pipewire.git
synced 2025-10-29 05:40:27 -04:00
alsa: add audio.allowed-rates param
Add a construct and runtime param to limit the amount of allowed samplerates used by the node. Fixes #1932
This commit is contained in:
parent
c3725d5dde
commit
67dc97fa43
4 changed files with 107 additions and 13 deletions
|
|
@ -304,6 +304,8 @@ struct spa_audio_info_raw {
|
|||
#define SPA_KEY_AUDIO_RATE "audio.rate" /**< an audio sample rate as int */
|
||||
#define SPA_KEY_AUDIO_POSITION "audio.position" /**< channel positions as comma separated list
|
||||
* of channels ex. "FL,FR" */
|
||||
#define SPA_KEY_AUDIO_ALLOWED_RATES "audio.allowed-rates" /**< a list of allowed samplerates
|
||||
* ex. "[ 44100 48000 ]" */
|
||||
|
||||
struct spa_audio_info_dsp {
|
||||
enum spa_audio_format format; /*< format, one of the DSP formats in enum spa_audio_format_dsp */
|
||||
|
|
|
|||
|
|
@ -102,6 +102,10 @@ static int alsa_set_param(struct state *state, const char *k, const char *s)
|
|||
} else if (spa_streq(k, SPA_KEY_AUDIO_POSITION)) {
|
||||
spa_alsa_parse_position(&state->default_pos, s, strlen(s));
|
||||
fmt_change++;
|
||||
} else if (spa_streq(k, SPA_KEY_AUDIO_ALLOWED_RATES)) {
|
||||
state->n_allowed_rates = spa_alsa_parse_rates(state->allowed_rates,
|
||||
MAX_RATES, s, strlen(s));
|
||||
fmt_change++;
|
||||
} else if (spa_streq(k, "iec958.codecs")) {
|
||||
spa_alsa_parse_iec958_codecs(&state->iec958_codecs, s, strlen(s));
|
||||
fmt_change++;
|
||||
|
|
@ -152,6 +156,22 @@ static int position_to_string(struct channel_map *map, char *val, size_t len)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int uint32_array_to_string(uint32_t *vals, uint32_t n_vals, char *val, size_t len)
|
||||
{
|
||||
uint32_t i, o = 0;
|
||||
int r;
|
||||
o += snprintf(val, len, "[ ");
|
||||
for (i = 0; i < n_vals; i++) {
|
||||
r = snprintf(val+o, len-o, "%s%d", i == 0 ? "" : ", ", vals[i]);
|
||||
if (r < 0 || o + r >= len)
|
||||
return -ENOSPC;
|
||||
o += r;
|
||||
}
|
||||
if (len > o)
|
||||
o += snprintf(val+o, len-o, " ]");
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct spa_pod *spa_alsa_enum_propinfo(struct state *state,
|
||||
uint32_t idx, struct spa_pod_builder *b)
|
||||
{
|
||||
|
|
@ -197,6 +217,18 @@ struct spa_pod *spa_alsa_enum_propinfo(struct state *state,
|
|||
break;
|
||||
}
|
||||
case 4:
|
||||
{
|
||||
char buf[1024];
|
||||
uint32_array_to_string(state->allowed_rates, state->n_allowed_rates, buf, sizeof(buf));
|
||||
param = spa_pod_builder_add_object(b,
|
||||
SPA_TYPE_OBJECT_PropInfo, SPA_PARAM_PropInfo,
|
||||
SPA_PROP_INFO_name, SPA_POD_String(SPA_KEY_AUDIO_ALLOWED_RATES),
|
||||
SPA_PROP_INFO_description, SPA_POD_String("Audio Allowed Rates"),
|
||||
SPA_PROP_INFO_type, SPA_POD_String(buf),
|
||||
SPA_PROP_INFO_params, SPA_POD_Bool(true));
|
||||
break;
|
||||
}
|
||||
case 5:
|
||||
param = spa_pod_builder_add_object(b,
|
||||
SPA_TYPE_OBJECT_PropInfo, SPA_PARAM_PropInfo,
|
||||
SPA_PROP_INFO_name, SPA_POD_String("api.alsa.period-size"),
|
||||
|
|
@ -204,7 +236,7 @@ struct spa_pod *spa_alsa_enum_propinfo(struct state *state,
|
|||
SPA_PROP_INFO_type, SPA_POD_Int(state->default_period_size),
|
||||
SPA_PROP_INFO_params, SPA_POD_Bool(true));
|
||||
break;
|
||||
case 5:
|
||||
case 6:
|
||||
param = spa_pod_builder_add_object(b,
|
||||
SPA_TYPE_OBJECT_PropInfo, SPA_PARAM_PropInfo,
|
||||
SPA_PROP_INFO_name, SPA_POD_String("api.alsa.period-num"),
|
||||
|
|
@ -212,7 +244,7 @@ struct spa_pod *spa_alsa_enum_propinfo(struct state *state,
|
|||
SPA_PROP_INFO_type, SPA_POD_Int(state->default_period_num),
|
||||
SPA_PROP_INFO_params, SPA_POD_Bool(true));
|
||||
break;
|
||||
case 6:
|
||||
case 7:
|
||||
param = spa_pod_builder_add_object(b,
|
||||
SPA_TYPE_OBJECT_PropInfo, SPA_PARAM_PropInfo,
|
||||
SPA_PROP_INFO_name, SPA_POD_String("api.alsa.headroom"),
|
||||
|
|
@ -220,7 +252,7 @@ struct spa_pod *spa_alsa_enum_propinfo(struct state *state,
|
|||
SPA_PROP_INFO_type, SPA_POD_Int(state->default_headroom),
|
||||
SPA_PROP_INFO_params, SPA_POD_Bool(true));
|
||||
break;
|
||||
case 7:
|
||||
case 8:
|
||||
param = spa_pod_builder_add_object(b,
|
||||
SPA_TYPE_OBJECT_PropInfo, SPA_PARAM_PropInfo,
|
||||
SPA_PROP_INFO_name, SPA_POD_String("api.alsa.start-delay"),
|
||||
|
|
@ -228,7 +260,7 @@ struct spa_pod *spa_alsa_enum_propinfo(struct state *state,
|
|||
SPA_PROP_INFO_type, SPA_POD_Int(state->default_start_delay),
|
||||
SPA_PROP_INFO_params, SPA_POD_Bool(true));
|
||||
break;
|
||||
case 8:
|
||||
case 9:
|
||||
param = spa_pod_builder_add_object(b,
|
||||
SPA_TYPE_OBJECT_PropInfo, SPA_PARAM_PropInfo,
|
||||
SPA_PROP_INFO_name, SPA_POD_String("api.alsa.disable-mmap"),
|
||||
|
|
@ -236,7 +268,7 @@ struct spa_pod *spa_alsa_enum_propinfo(struct state *state,
|
|||
SPA_PROP_INFO_type, SPA_POD_Bool(state->disable_mmap),
|
||||
SPA_PROP_INFO_params, SPA_POD_Bool(true));
|
||||
break;
|
||||
case 9:
|
||||
case 10:
|
||||
param = spa_pod_builder_add_object(b,
|
||||
SPA_TYPE_OBJECT_PropInfo, SPA_PARAM_PropInfo,
|
||||
SPA_PROP_INFO_name, SPA_POD_String("api.alsa.disable-batch"),
|
||||
|
|
@ -244,7 +276,7 @@ struct spa_pod *spa_alsa_enum_propinfo(struct state *state,
|
|||
SPA_PROP_INFO_type, SPA_POD_Bool(state->disable_batch),
|
||||
SPA_PROP_INFO_params, SPA_POD_Bool(true));
|
||||
break;
|
||||
case 10:
|
||||
case 11:
|
||||
param = spa_pod_builder_add_object(b,
|
||||
SPA_TYPE_OBJECT_PropInfo, SPA_PARAM_PropInfo,
|
||||
SPA_PROP_INFO_name, SPA_POD_String("api.alsa.use-chmap"),
|
||||
|
|
@ -252,7 +284,7 @@ struct spa_pod *spa_alsa_enum_propinfo(struct state *state,
|
|||
SPA_PROP_INFO_type, SPA_POD_Bool(state->props.use_chmap),
|
||||
SPA_PROP_INFO_params, SPA_POD_Bool(true));
|
||||
break;
|
||||
case 11:
|
||||
case 12:
|
||||
param = spa_pod_builder_add_object(b,
|
||||
SPA_TYPE_OBJECT_PropInfo, SPA_PARAM_PropInfo,
|
||||
SPA_PROP_INFO_name, SPA_POD_String("api.alsa.multi-rate"),
|
||||
|
|
@ -260,7 +292,7 @@ struct spa_pod *spa_alsa_enum_propinfo(struct state *state,
|
|||
SPA_PROP_INFO_type, SPA_POD_Bool(state->multi_rate),
|
||||
SPA_PROP_INFO_params, SPA_POD_Bool(true));
|
||||
break;
|
||||
case 12:
|
||||
case 13:
|
||||
param = spa_pod_builder_add_object(b,
|
||||
SPA_TYPE_OBJECT_PropInfo, SPA_PARAM_PropInfo,
|
||||
SPA_PROP_INFO_name, SPA_POD_String("clock.name"),
|
||||
|
|
@ -297,6 +329,11 @@ int spa_alsa_add_prop_params(struct state *state, struct spa_pod_builder *b)
|
|||
spa_pod_builder_string(b, SPA_KEY_AUDIO_POSITION);
|
||||
spa_pod_builder_string(b, buf);
|
||||
|
||||
uint32_array_to_string(state->allowed_rates, state->n_allowed_rates,
|
||||
buf, sizeof(buf));
|
||||
spa_pod_builder_string(b, SPA_KEY_AUDIO_ALLOWED_RATES);
|
||||
spa_pod_builder_string(b, buf);
|
||||
|
||||
spa_pod_builder_string(b, "api.alsa.period-size");
|
||||
spa_pod_builder_int(b, state->default_period_size);
|
||||
|
||||
|
|
@ -674,6 +711,15 @@ static void sanitize_map(snd_pcm_chmap_t* map)
|
|||
}
|
||||
}
|
||||
|
||||
static bool uint32_array_contains(uint32_t *vals, uint32_t n_vals, uint32_t val)
|
||||
{
|
||||
uint32_t i;
|
||||
for (i = 0; i < n_vals; i++)
|
||||
if (vals[i] == val)
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
static int add_rate(struct state *state, uint32_t scale, bool all, uint32_t index, uint32_t *next,
|
||||
snd_pcm_hw_params_t *params, struct spa_pod_builder *b)
|
||||
{
|
||||
|
|
@ -705,11 +751,35 @@ static int add_rate(struct state *state, uint32_t scale, bool all, uint32_t inde
|
|||
if (rate == 0)
|
||||
rate = state->position ? state->position->clock.rate.denom : DEFAULT_RATE;
|
||||
|
||||
spa_pod_builder_int(b, SPA_CLAMP(rate, min, max) * scale);
|
||||
if (min != max) {
|
||||
spa_pod_builder_int(b, min * scale);
|
||||
spa_pod_builder_int(b, max * scale);
|
||||
choice->body.type = SPA_CHOICE_Range;
|
||||
if (state->n_allowed_rates > 0) {
|
||||
uint32_t i, v, last = 0, count = 0;
|
||||
|
||||
v = SPA_CLAMP(rate, min, max);
|
||||
if (uint32_array_contains(state->allowed_rates, state->n_allowed_rates, v)) {
|
||||
spa_pod_builder_int(b, v * scale);
|
||||
count++;
|
||||
}
|
||||
for (i = 0; i < state->n_allowed_rates; i++) {
|
||||
v = SPA_CLAMP(state->allowed_rates[i], min, max);
|
||||
if (v != last &&
|
||||
uint32_array_contains(state->allowed_rates, state->n_allowed_rates, v)) {
|
||||
spa_pod_builder_int(b, v * scale);
|
||||
if (count == 0)
|
||||
spa_pod_builder_int(b, v * scale);
|
||||
count++;
|
||||
}
|
||||
last = v;
|
||||
}
|
||||
if (count > 1)
|
||||
choice->body.type = SPA_CHOICE_Enum;
|
||||
} else {
|
||||
spa_pod_builder_int(b, SPA_CLAMP(rate, min, max) * scale);
|
||||
|
||||
if (min != max) {
|
||||
spa_pod_builder_int(b, min * scale);
|
||||
spa_pod_builder_int(b, max * scale);
|
||||
choice->body.type = SPA_CHOICE_Range;
|
||||
}
|
||||
}
|
||||
spa_pod_builder_pop(b, &f[0]);
|
||||
|
||||
|
|
|
|||
|
|
@ -55,6 +55,8 @@ extern "C" {
|
|||
#define MIN_LATENCY 16
|
||||
#define MAX_LATENCY 8192
|
||||
|
||||
#define MAX_RATES 16
|
||||
|
||||
#define DEFAULT_PERIOD 1024u
|
||||
#define DEFAULT_RATE 48000u
|
||||
#define DEFAULT_CHANNELS 2u
|
||||
|
|
@ -140,6 +142,8 @@ struct state {
|
|||
uint32_t default_format;
|
||||
unsigned int default_channels;
|
||||
unsigned int default_rate;
|
||||
uint32_t allowed_rates[MAX_RATES];
|
||||
uint32_t n_allowed_rates;
|
||||
struct channel_map default_pos;
|
||||
unsigned int disable_mmap;
|
||||
unsigned int disable_batch;
|
||||
|
|
@ -285,6 +289,22 @@ static inline void spa_alsa_parse_position(struct channel_map *map, const char *
|
|||
}
|
||||
}
|
||||
|
||||
static inline uint32_t spa_alsa_parse_rates(uint32_t *rates, uint32_t max, const char *val, size_t len)
|
||||
{
|
||||
struct spa_json it[2];
|
||||
char v[256];
|
||||
uint32_t count;
|
||||
|
||||
spa_json_init(&it[0], val, len);
|
||||
if (spa_json_enter_array(&it[0], &it[1]) <= 0)
|
||||
spa_json_init(&it[1], val, len);
|
||||
|
||||
count = 0;
|
||||
while (spa_json_get_string(&it[1], v, sizeof(v)) > 0 && count < max)
|
||||
rates[count++] = atoi(v);
|
||||
return count;
|
||||
}
|
||||
|
||||
static inline uint32_t spa_alsa_iec958_codec_from_name(const char *name)
|
||||
{
|
||||
int i;
|
||||
|
|
|
|||
|
|
@ -314,6 +314,8 @@ extern "C" {
|
|||
#define PW_KEY_AUDIO_RATE "audio.rate" /**< an audio samplerate */
|
||||
#define PW_KEY_AUDIO_CHANNELS "audio.channels" /**< number of audio channels */
|
||||
#define PW_KEY_AUDIO_FORMAT "audio.format" /**< an audio format. Ex: "S16LE" */
|
||||
#define PW_KEY_AUDIO_ALLOWED_RATES "audio.allowed-rates" /**< a list of allowed samplerates
|
||||
* ex. "[ 44100 48000 ]" */
|
||||
|
||||
/** video related properties */
|
||||
#define PW_KEY_VIDEO_RATE "video.framerate" /**< a video framerate */
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue