alsa: Add "exact-channels" mapping configurability

Allow a mapping to relax the exact channel restriction:

exact-channels = yes | no # If no, and the exact number of channels is not supported,
                          # allow device to be opened with another channel count

Signed-off-by: David Henningsson <david.henningsson@canonical.com>
This commit is contained in:
David Henningsson 2014-07-25 14:57:55 +02:00
parent afbe9605c6
commit be8311417c
3 changed files with 42 additions and 4 deletions

View file

@ -3368,6 +3368,7 @@ pa_alsa_mapping *pa_alsa_mapping_get(pa_alsa_profile_set *ps, const char *name)
m = pa_xnew0(pa_alsa_mapping, 1); m = pa_xnew0(pa_alsa_mapping, 1);
m->profile_set = ps; m->profile_set = ps;
m->exact_channels = true;
m->name = pa_xstrdup(name); m->name = pa_xstrdup(name);
pa_sample_spec_init(&m->sample_spec); pa_sample_spec_init(&m->sample_spec);
pa_channel_map_init(&m->channel_map); pa_channel_map_init(&m->channel_map);
@ -3485,6 +3486,30 @@ static int mapping_parse_paths(pa_config_parser_state *state) {
return 0; return 0;
} }
static int mapping_parse_exact_channels(pa_config_parser_state *state) {
pa_alsa_profile_set *ps;
pa_alsa_mapping *m;
int b;
pa_assert(state);
ps = state->userdata;
if (!(m = pa_alsa_mapping_get(ps, state->section))) {
pa_log("[%s:%u] %s invalid in section %s", state->filename, state->lineno, state->lvalue, state->section);
return -1;
}
if ((b = pa_parse_boolean(state->rvalue)) < 0) {
pa_log("[%s:%u] %s has invalid value '%s'", state->filename, state->lineno, state->lvalue, state->section);
return -1;
}
m->exact_channels = b;
return 0;
}
static int mapping_parse_element(pa_config_parser_state *state) { static int mapping_parse_element(pa_config_parser_state *state) {
pa_alsa_profile_set *ps; pa_alsa_profile_set *ps;
pa_alsa_mapping *m; pa_alsa_mapping *m;
@ -4156,6 +4181,7 @@ pa_alsa_profile_set* pa_alsa_profile_set_new(const char *fname, const pa_channel
{ "element-input", mapping_parse_element, NULL, NULL }, { "element-input", mapping_parse_element, NULL, NULL },
{ "element-output", mapping_parse_element, NULL, NULL }, { "element-output", mapping_parse_element, NULL, NULL },
{ "direction", mapping_parse_direction, NULL, NULL }, { "direction", mapping_parse_direction, NULL, NULL },
{ "exact-channels", mapping_parse_exact_channels, NULL, NULL },
/* Shared by [Mapping ...] and [Profile ...] */ /* Shared by [Mapping ...] and [Profile ...] */
{ "description", mapping_parse_description, NULL, NULL }, { "description", mapping_parse_description, NULL, NULL },
@ -4264,10 +4290,12 @@ static void profile_finalize_probing(pa_alsa_profile *to_be_finalized, pa_alsa_p
static snd_pcm_t* mapping_open_pcm(pa_alsa_mapping *m, static snd_pcm_t* mapping_open_pcm(pa_alsa_mapping *m,
const pa_sample_spec *ss, const pa_sample_spec *ss,
const char *dev_id, const char *dev_id,
bool exact_channels,
int mode, int mode,
unsigned default_n_fragments, unsigned default_n_fragments,
unsigned default_fragment_size_msec) { unsigned default_fragment_size_msec) {
snd_pcm_t* handle;
pa_sample_spec try_ss = *ss; pa_sample_spec try_ss = *ss;
pa_channel_map try_map = m->channel_map; pa_channel_map try_map = m->channel_map;
snd_pcm_uframes_t try_period_size, try_buffer_size; snd_pcm_uframes_t try_period_size, try_buffer_size;
@ -4279,10 +4307,17 @@ static snd_pcm_t* mapping_open_pcm(pa_alsa_mapping *m,
pa_frame_size(&try_ss); pa_frame_size(&try_ss);
try_buffer_size = default_n_fragments * try_period_size; try_buffer_size = default_n_fragments * try_period_size;
return pa_alsa_open_by_template( handle = pa_alsa_open_by_template(
m->device_strings, dev_id, NULL, &try_ss, m->device_strings, dev_id, NULL, &try_ss,
&try_map, mode, &try_period_size, &try_map, mode, &try_period_size,
&try_buffer_size, 0, NULL, NULL, true); &try_buffer_size, 0, NULL, NULL, exact_channels);
if (handle && !exact_channels && m->channel_map.channels != try_map.channels) {
char buf[PA_CHANNEL_MAP_SNPRINT_MAX];
pa_log_debug("Channel map for mapping '%s' permanently changed to '%s'", m->name,
pa_channel_map_snprint(buf, sizeof(buf), &try_map));
m->channel_map = try_map;
}
return handle;
} }
static void paths_drop_unused(pa_hashmap* h, pa_hashmap *keep) { static void paths_drop_unused(pa_hashmap* h, pa_hashmap *keep) {
@ -4365,7 +4400,7 @@ void pa_alsa_profile_set_probe(
continue; continue;
pa_log_debug("Checking for playback on %s (%s)", m->description, m->name); pa_log_debug("Checking for playback on %s (%s)", m->description, m->name);
if (!(m->output_pcm = mapping_open_pcm(m, ss, dev_id, if (!(m->output_pcm = mapping_open_pcm(m, ss, dev_id, m->exact_channels,
SND_PCM_STREAM_PLAYBACK, SND_PCM_STREAM_PLAYBACK,
default_n_fragments, default_n_fragments,
default_fragment_size_msec))) { default_fragment_size_msec))) {
@ -4386,7 +4421,7 @@ void pa_alsa_profile_set_probe(
continue; continue;
pa_log_debug("Checking for recording on %s (%s)", m->description, m->name); pa_log_debug("Checking for recording on %s (%s)", m->description, m->name);
if (!(m->input_pcm = mapping_open_pcm(m, ss, dev_id, if (!(m->input_pcm = mapping_open_pcm(m, ss, dev_id, m->exact_channels,
SND_PCM_STREAM_CAPTURE, SND_PCM_STREAM_CAPTURE,
default_n_fragments, default_n_fragments,
default_fragment_size_msec))) { default_fragment_size_msec))) {

View file

@ -264,6 +264,7 @@ struct pa_alsa_mapping {
pa_alsa_path_set *output_path_set; pa_alsa_path_set *output_path_set;
unsigned supported; unsigned supported;
bool exact_channels:1;
/* Temporarily used during probing */ /* Temporarily used during probing */
snd_pcm_t *input_pcm; snd_pcm_t *input_pcm;

View file

@ -55,6 +55,8 @@
; priority = ... ; priority = ...
; direction = any | input | output # Only useful for? ; direction = any | input | output # Only useful for?
; ;
; exact-channels = yes | no # If no, and the exact number of channels is not supported,
; # allow device to be opened with another channel count
; [Profile id] ; [Profile id]
; input-mappings = ... # Lists mappings for sources on this profile, those mapping must be ; input-mappings = ... # Lists mappings for sources on this profile, those mapping must be
; # defined in this file too ; # defined in this file too