mirror of
https://gitlab.freedesktop.org/pulseaudio/pulseaudio.git
synced 2025-10-29 05:40:23 -04:00
alsa: Integrate UCM basic functions
UCM basic functions will provide another way to handle the alsa mixer and controls. That means alsa card module will make use of alsa ucm configurations provided by various audio systems instead of mixer and paths configurations provided by PA. PA profiles come from UCM verb, PA sinks/sources and ports come from UCM devices. In case the proper UCM configurations are found, ucm branches are activated, or we will still fall through to the original way. Signed-off-by: Feng Wei <wei.feng@freescale.com>
This commit is contained in:
parent
7369a53ab5
commit
c19d108219
8 changed files with 1687 additions and 37 deletions
|
|
@ -1628,6 +1628,7 @@ module_coreaudio_device_la_LIBADD = $(MODULE_LIBADD)
|
|||
|
||||
libalsa_util_la_SOURCES = \
|
||||
modules/alsa/alsa-util.c modules/alsa/alsa-util.h \
|
||||
modules/alsa/alsa-ucm.c modules/alsa/alsa-ucm.h \
|
||||
modules/alsa/alsa-mixer.c modules/alsa/alsa-mixer.h \
|
||||
modules/alsa/alsa-sink.c modules/alsa/alsa-sink.h \
|
||||
modules/alsa/alsa-source.c modules/alsa/alsa-source.h \
|
||||
|
|
|
|||
|
|
@ -3271,6 +3271,8 @@ static void mapping_free(pa_alsa_mapping *m) {
|
|||
pa_assert(!m->input_pcm);
|
||||
pa_assert(!m->output_pcm);
|
||||
|
||||
pa_alsa_ucm_mapping_context_free(&m->ucm_context);
|
||||
|
||||
pa_xfree(m);
|
||||
}
|
||||
|
||||
|
|
@ -3343,7 +3345,7 @@ void pa_alsa_profile_set_free(pa_alsa_profile_set *ps) {
|
|||
pa_xfree(ps);
|
||||
}
|
||||
|
||||
static pa_alsa_mapping *mapping_get(pa_alsa_profile_set *ps, const char *name) {
|
||||
pa_alsa_mapping *pa_alsa_mapping_get(pa_alsa_profile_set *ps, const char *name) {
|
||||
pa_alsa_mapping *m;
|
||||
|
||||
if (!pa_startswith(name, "Mapping "))
|
||||
|
|
@ -3412,7 +3414,7 @@ static int mapping_parse_device_strings(pa_config_parser_state *state) {
|
|||
|
||||
ps = state->userdata;
|
||||
|
||||
if (!(m = mapping_get(ps, state->section))) {
|
||||
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;
|
||||
}
|
||||
|
|
@ -3434,7 +3436,7 @@ static int mapping_parse_channel_map(pa_config_parser_state *state) {
|
|||
|
||||
ps = state->userdata;
|
||||
|
||||
if (!(m = mapping_get(ps, state->section))) {
|
||||
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;
|
||||
}
|
||||
|
|
@ -3455,7 +3457,7 @@ static int mapping_parse_paths(pa_config_parser_state *state) {
|
|||
|
||||
ps = state->userdata;
|
||||
|
||||
if (!(m = mapping_get(ps, state->section))) {
|
||||
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;
|
||||
}
|
||||
|
|
@ -3479,7 +3481,7 @@ static int mapping_parse_element(pa_config_parser_state *state) {
|
|||
|
||||
ps = state->userdata;
|
||||
|
||||
if (!(m = mapping_get(ps, state->section))) {
|
||||
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;
|
||||
}
|
||||
|
|
@ -3503,7 +3505,7 @@ static int mapping_parse_direction(pa_config_parser_state *state) {
|
|||
|
||||
ps = state->userdata;
|
||||
|
||||
if (!(m = mapping_get(ps, state->section))) {
|
||||
if (!(m = pa_alsa_mapping_get(ps, state->section))) {
|
||||
pa_log("[%s:%u] Section name %s invalid.", state->filename, state->lineno, state->section);
|
||||
return -1;
|
||||
}
|
||||
|
|
@ -3531,7 +3533,7 @@ static int mapping_parse_description(pa_config_parser_state *state) {
|
|||
|
||||
ps = state->userdata;
|
||||
|
||||
if ((m = mapping_get(ps, state->section))) {
|
||||
if ((m = pa_alsa_mapping_get(ps, state->section))) {
|
||||
pa_xfree(m->description);
|
||||
m->description = pa_xstrdup(state->rvalue);
|
||||
} else if ((p = profile_get(ps, state->section))) {
|
||||
|
|
@ -3560,7 +3562,7 @@ static int mapping_parse_priority(pa_config_parser_state *state) {
|
|||
return -1;
|
||||
}
|
||||
|
||||
if ((m = mapping_get(ps, state->section)))
|
||||
if ((m = pa_alsa_mapping_get(ps, state->section)))
|
||||
m->priority = prio;
|
||||
else if ((p = profile_get(ps, state->section)))
|
||||
p->priority = prio;
|
||||
|
|
@ -4361,17 +4363,7 @@ void pa_alsa_profile_set_probe(
|
|||
/* Clean up */
|
||||
profile_finalize_probing(last, NULL);
|
||||
|
||||
PA_HASHMAP_FOREACH(p, ps->profiles, state)
|
||||
if (!p->supported) {
|
||||
pa_hashmap_remove(ps->profiles, p->name);
|
||||
profile_free(p);
|
||||
}
|
||||
|
||||
PA_HASHMAP_FOREACH(m, ps->mappings, state)
|
||||
if (m->supported <= 0) {
|
||||
pa_hashmap_remove(ps->mappings, m->name);
|
||||
mapping_free(m);
|
||||
}
|
||||
pa_alsa_profile_set_drop_unsupported(ps);
|
||||
|
||||
paths_drop_unsupported(ps->input_paths);
|
||||
paths_drop_unsupported(ps->output_paths);
|
||||
|
|
@ -4406,6 +4398,26 @@ void pa_alsa_profile_set_dump(pa_alsa_profile_set *ps) {
|
|||
pa_alsa_decibel_fix_dump(db_fix);
|
||||
}
|
||||
|
||||
void pa_alsa_profile_set_drop_unsupported(pa_alsa_profile_set *ps) {
|
||||
pa_alsa_profile *p;
|
||||
pa_alsa_mapping *m;
|
||||
void *state;
|
||||
|
||||
PA_HASHMAP_FOREACH(p, ps->profiles, state) {
|
||||
if (!p->supported) {
|
||||
pa_hashmap_remove(ps->profiles, p->name);
|
||||
profile_free(p);
|
||||
}
|
||||
}
|
||||
|
||||
PA_HASHMAP_FOREACH(m, ps->mappings, state) {
|
||||
if (m->supported <= 0) {
|
||||
pa_hashmap_remove(ps->mappings, m->name);
|
||||
mapping_free(m);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static pa_device_port* device_port_alsa_init(pa_hashmap *ports,
|
||||
const char* name,
|
||||
const char* description,
|
||||
|
|
|
|||
|
|
@ -48,6 +48,7 @@ typedef struct pa_alsa_profile_set pa_alsa_profile_set;
|
|||
typedef struct pa_alsa_port_data pa_alsa_port_data;
|
||||
|
||||
#include "alsa-util.h"
|
||||
#include "alsa-ucm.h"
|
||||
|
||||
typedef enum pa_alsa_switch_use {
|
||||
PA_ALSA_SWITCH_IGNORE,
|
||||
|
|
@ -265,6 +266,9 @@ struct pa_alsa_mapping {
|
|||
|
||||
pa_sink *sink;
|
||||
pa_source *source;
|
||||
|
||||
/* ucm device context*/
|
||||
pa_alsa_ucm_mapping_context ucm_context;
|
||||
};
|
||||
|
||||
struct pa_alsa_profile {
|
||||
|
|
@ -314,11 +318,13 @@ struct pa_alsa_profile_set {
|
|||
void pa_alsa_mapping_dump(pa_alsa_mapping *m);
|
||||
void pa_alsa_profile_dump(pa_alsa_profile *p);
|
||||
void pa_alsa_decibel_fix_dump(pa_alsa_decibel_fix *db_fix);
|
||||
pa_alsa_mapping *pa_alsa_mapping_get(pa_alsa_profile_set *ps, const char *name);
|
||||
|
||||
pa_alsa_profile_set* pa_alsa_profile_set_new(const char *fname, const pa_channel_map *bonus);
|
||||
void pa_alsa_profile_set_probe(pa_alsa_profile_set *ps, const char *dev_id, const pa_sample_spec *ss, unsigned default_n_fragments, unsigned default_fragment_size_msec);
|
||||
void pa_alsa_profile_set_free(pa_alsa_profile_set *s);
|
||||
void pa_alsa_profile_set_dump(pa_alsa_profile_set *s);
|
||||
void pa_alsa_profile_set_drop_unsupported(pa_alsa_profile_set *s);
|
||||
|
||||
snd_mixer_t *pa_alsa_open_mixer_for_pcm(snd_pcm_t *pcm, char **ctl_device, snd_hctl_t **hctl);
|
||||
|
||||
|
|
|
|||
|
|
@ -153,6 +153,9 @@ struct userdata {
|
|||
pa_hook_slot *reserve_slot;
|
||||
pa_reserve_monitor_wrapper *monitor;
|
||||
pa_hook_slot *monitor_slot;
|
||||
|
||||
/* ucm context */
|
||||
pa_alsa_ucm_mapping_context *ucm_context;
|
||||
};
|
||||
|
||||
static void userdata_free(struct userdata *u);
|
||||
|
|
@ -1450,6 +1453,16 @@ static void mixer_volume_init(struct userdata *u) {
|
|||
}
|
||||
}
|
||||
|
||||
static int sink_set_port_ucm_cb(pa_sink *s, pa_device_port *p) {
|
||||
struct userdata *u = s->userdata;
|
||||
|
||||
pa_assert(u);
|
||||
pa_assert(p);
|
||||
pa_assert(u->ucm_context);
|
||||
|
||||
return pa_alsa_ucm_set_port(u->ucm_context, p, TRUE);
|
||||
}
|
||||
|
||||
static int sink_set_port_cb(pa_sink *s, pa_device_port *p) {
|
||||
struct userdata *u = s->userdata;
|
||||
pa_alsa_port_data *data;
|
||||
|
|
@ -1884,7 +1897,6 @@ fail:
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
static int setup_mixer(struct userdata *u, pa_bool_t ignore_dB) {
|
||||
pa_bool_t need_mixer_callback = FALSE;
|
||||
|
||||
|
|
@ -2071,6 +2083,10 @@ pa_sink *pa_alsa_sink_new(pa_module *m, pa_modargs *ma, const char*driver, pa_ca
|
|||
TRUE);
|
||||
u->smoother_interval = SMOOTHER_MIN_INTERVAL;
|
||||
|
||||
/* use ucm */
|
||||
if (mapping && mapping->ucm_context.ucm)
|
||||
u->ucm_context = &mapping->ucm_context;
|
||||
|
||||
dev_id = pa_modargs_get_value(
|
||||
ma, "device_id",
|
||||
pa_modargs_get_value(ma, "device", DEFAULT_DEVICE));
|
||||
|
|
@ -2171,7 +2187,8 @@ pa_sink *pa_alsa_sink_new(pa_module *m, pa_modargs *ma, const char*driver, pa_ca
|
|||
/* ALSA might tweak the sample spec, so recalculate the frame size */
|
||||
frame_size = pa_frame_size(&ss);
|
||||
|
||||
find_mixer(u, mapping, pa_modargs_get_value(ma, "control", NULL), ignore_dB);
|
||||
if (!u->ucm_context)
|
||||
find_mixer(u, mapping, pa_modargs_get_value(ma, "control", NULL), ignore_dB);
|
||||
|
||||
pa_sink_new_data_init(&data);
|
||||
data.driver = driver;
|
||||
|
|
@ -2217,7 +2234,9 @@ pa_sink *pa_alsa_sink_new(pa_module *m, pa_modargs *ma, const char*driver, pa_ca
|
|||
goto fail;
|
||||
}
|
||||
|
||||
if (u->mixer_path_set)
|
||||
if (u->ucm_context)
|
||||
pa_alsa_ucm_add_ports(&data.ports, data.proplist, u->ucm_context, TRUE, card);
|
||||
else if (u->mixer_path_set)
|
||||
pa_alsa_add_ports(&data, u->mixer_path_set, card);
|
||||
|
||||
u->sink = pa_sink_new(m->core, &data, PA_SINK_HARDWARE | PA_SINK_LATENCY | (u->use_tsched ? PA_SINK_DYNAMIC_LATENCY : 0) |
|
||||
|
|
@ -2245,7 +2264,10 @@ pa_sink *pa_alsa_sink_new(pa_module *m, pa_modargs *ma, const char*driver, pa_ca
|
|||
if (u->use_tsched)
|
||||
u->sink->update_requested_latency = sink_update_requested_latency_cb;
|
||||
u->sink->set_state = sink_set_state_cb;
|
||||
u->sink->set_port = sink_set_port_cb;
|
||||
if (u->ucm_context)
|
||||
u->sink->set_port = sink_set_port_ucm_cb;
|
||||
else
|
||||
u->sink->set_port = sink_set_port_cb;
|
||||
if (u->sink->alternate_sample_rate)
|
||||
u->sink->update_rate = sink_update_rate_cb;
|
||||
u->sink->userdata = u;
|
||||
|
|
@ -2284,7 +2306,10 @@ pa_sink *pa_alsa_sink_new(pa_module *m, pa_modargs *ma, const char*driver, pa_ca
|
|||
if (update_sw_params(u) < 0)
|
||||
goto fail;
|
||||
|
||||
if (setup_mixer(u, ignore_dB) < 0)
|
||||
if (u->ucm_context) {
|
||||
if (u->sink->active_port && pa_alsa_ucm_set_port(u->ucm_context, u->sink->active_port, TRUE) < 0)
|
||||
goto fail;
|
||||
} else if (setup_mixer(u, ignore_dB) < 0)
|
||||
goto fail;
|
||||
|
||||
pa_alsa_dump(PA_LOG_DEBUG, u->pcm_handle);
|
||||
|
|
|
|||
|
|
@ -137,6 +137,9 @@ struct userdata {
|
|||
pa_hook_slot *reserve_slot;
|
||||
pa_reserve_monitor_wrapper *monitor;
|
||||
pa_hook_slot *monitor_slot;
|
||||
|
||||
/* ucm context */
|
||||
pa_alsa_ucm_mapping_context *ucm_context;
|
||||
};
|
||||
|
||||
static void userdata_free(struct userdata *u);
|
||||
|
|
@ -1353,6 +1356,16 @@ static void mixer_volume_init(struct userdata *u) {
|
|||
}
|
||||
}
|
||||
|
||||
static int source_set_port_ucm_cb(pa_source *s, pa_device_port *p) {
|
||||
struct userdata *u = s->userdata;
|
||||
|
||||
pa_assert(u);
|
||||
pa_assert(p);
|
||||
pa_assert(u->ucm_context);
|
||||
|
||||
return pa_alsa_ucm_set_port(u->ucm_context, p, FALSE);
|
||||
}
|
||||
|
||||
static int source_set_port_cb(pa_source *s, pa_device_port *p) {
|
||||
struct userdata *u = s->userdata;
|
||||
pa_alsa_port_data *data;
|
||||
|
|
@ -1800,6 +1813,10 @@ pa_source *pa_alsa_source_new(pa_module *m, pa_modargs *ma, const char*driver, p
|
|||
TRUE);
|
||||
u->smoother_interval = SMOOTHER_MIN_INTERVAL;
|
||||
|
||||
/* use ucm */
|
||||
if (mapping && mapping->ucm_context.ucm)
|
||||
u->ucm_context = &mapping->ucm_context;
|
||||
|
||||
dev_id = pa_modargs_get_value(
|
||||
ma, "device_id",
|
||||
pa_modargs_get_value(ma, "device", DEFAULT_DEVICE));
|
||||
|
|
@ -1896,7 +1913,8 @@ pa_source *pa_alsa_source_new(pa_module *m, pa_modargs *ma, const char*driver, p
|
|||
/* ALSA might tweak the sample spec, so recalculate the frame size */
|
||||
frame_size = pa_frame_size(&ss);
|
||||
|
||||
find_mixer(u, mapping, pa_modargs_get_value(ma, "control", NULL), ignore_dB);
|
||||
if (!u->ucm_context)
|
||||
find_mixer(u, mapping, pa_modargs_get_value(ma, "control", NULL), ignore_dB);
|
||||
|
||||
pa_source_new_data_init(&data);
|
||||
data.driver = driver;
|
||||
|
|
@ -1942,7 +1960,9 @@ pa_source *pa_alsa_source_new(pa_module *m, pa_modargs *ma, const char*driver, p
|
|||
goto fail;
|
||||
}
|
||||
|
||||
if (u->mixer_path_set)
|
||||
if (u->ucm_context)
|
||||
pa_alsa_ucm_add_ports(&data.ports, data.proplist, u->ucm_context, FALSE, card);
|
||||
else if (u->mixer_path_set)
|
||||
pa_alsa_add_ports(&data, u->mixer_path_set, card);
|
||||
|
||||
u->source = pa_source_new(m->core, &data, PA_SOURCE_HARDWARE|PA_SOURCE_LATENCY|(u->use_tsched ? PA_SOURCE_DYNAMIC_LATENCY : 0));
|
||||
|
|
@ -1969,7 +1989,10 @@ pa_source *pa_alsa_source_new(pa_module *m, pa_modargs *ma, const char*driver, p
|
|||
if (u->use_tsched)
|
||||
u->source->update_requested_latency = source_update_requested_latency_cb;
|
||||
u->source->set_state = source_set_state_cb;
|
||||
u->source->set_port = source_set_port_cb;
|
||||
if (u->ucm_context)
|
||||
u->source->set_port = source_set_port_ucm_cb;
|
||||
else
|
||||
u->source->set_port = source_set_port_cb;
|
||||
if (u->source->alternate_sample_rate)
|
||||
u->source->update_rate = source_update_rate_cb;
|
||||
u->source->userdata = u;
|
||||
|
|
@ -2001,7 +2024,10 @@ pa_source *pa_alsa_source_new(pa_module *m, pa_modargs *ma, const char*driver, p
|
|||
if (update_sw_params(u) < 0)
|
||||
goto fail;
|
||||
|
||||
if (setup_mixer(u, ignore_dB) < 0)
|
||||
if (u->ucm_context) {
|
||||
if (u->source->active_port && pa_alsa_ucm_set_port(u->ucm_context, u->source->active_port, FALSE) < 0)
|
||||
goto fail;
|
||||
} else if (setup_mixer(u, ignore_dB) < 0)
|
||||
goto fail;
|
||||
|
||||
pa_alsa_dump(PA_LOG_DEBUG, u->pcm_handle);
|
||||
|
|
|
|||
1370
src/modules/alsa/alsa-ucm.c
Normal file
1370
src/modules/alsa/alsa-ucm.c
Normal file
File diff suppressed because it is too large
Load diff
167
src/modules/alsa/alsa-ucm.h
Normal file
167
src/modules/alsa/alsa-ucm.h
Normal file
|
|
@ -0,0 +1,167 @@
|
|||
#ifndef fooalsaucmhfoo
|
||||
#define fooalsaucmhfoo
|
||||
|
||||
/***
|
||||
This file is part of PulseAudio.
|
||||
|
||||
Copyright 2011 Wolfson Microelectronics PLC
|
||||
Author Margarita Olaya <magi@slimlogic.co.uk>
|
||||
Copyright 2012 Feng Wei <wei.feng@freescale.com>, Freescale Ltd.
|
||||
|
||||
PulseAudio is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser General Public License as published
|
||||
by the Free Software Foundation; either version 2.1 of the License,
|
||||
or (at your option) any later version.
|
||||
|
||||
PulseAudio is distributed in the hope that it will be useful, but
|
||||
WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with PulseAudio; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
|
||||
USA.
|
||||
***/
|
||||
|
||||
#include <use-case.h>
|
||||
|
||||
#include "alsa-mixer.h"
|
||||
|
||||
/** For devices: List of verbs, devices or modifiers available */
|
||||
#define PA_ALSA_PROP_UCM_NAME "alsa.ucm.name"
|
||||
|
||||
/** For devices: List of supported devices per verb*/
|
||||
#define PA_ALSA_PROP_UCM_DESCRIPTION "alsa.ucm.description"
|
||||
|
||||
/** For devices: Playback device name e.g PlaybackPCM */
|
||||
#define PA_ALSA_PROP_UCM_SINK "alsa.ucm.sink"
|
||||
|
||||
/** For devices: Capture device name e.g CapturePCM*/
|
||||
#define PA_ALSA_PROP_UCM_SOURCE "alsa.ucm.source"
|
||||
|
||||
/** For devices: Playback roles */
|
||||
#define PA_ALSA_PROP_UCM_PLAYBACK_ROLES "alsa.ucm.playback.roles"
|
||||
|
||||
/** For devices: Playback control volume ID string. e.g PlaybackVolume */
|
||||
#define PA_ALSA_PROP_UCM_PLAYBACK_VOLUME "alsa.ucm.playback.volume"
|
||||
|
||||
/** For devices: Playback switch e.g PlaybackSwitch */
|
||||
#define PA_ALSA_PROP_UCM_PLAYBACK_SWITCH "alsa.ucm.playback.switch"
|
||||
|
||||
/** For devices: Playback priority */
|
||||
#define PA_ALSA_PROP_UCM_PLAYBACK_PRIORITY "alsa.ucm.playback.priority"
|
||||
|
||||
/** For devices: Playback channels */
|
||||
#define PA_ALSA_PROP_UCM_PLAYBACK_CHANNELS "alsa.ucm.playback.channels"
|
||||
|
||||
/** For devices: Capture roles */
|
||||
#define PA_ALSA_PROP_UCM_CAPTURE_ROLES "alsa.ucm.capture.roles"
|
||||
|
||||
/** For devices: Capture controls volume ID string. e.g CaptureVolume */
|
||||
#define PA_ALSA_PROP_UCM_CAPTURE_VOLUME "alsa.ucm.capture.volume"
|
||||
|
||||
/** For devices: Capture switch e.g CaptureSwitch */
|
||||
#define PA_ALSA_PROP_UCM_CAPTURE_SWITCH "alsa.ucm.capture.switch"
|
||||
|
||||
/** For devices: Capture priority */
|
||||
#define PA_ALSA_PROP_UCM_CAPTURE_PRIORITY "alsa.ucm.capture.priority"
|
||||
|
||||
/** For devices: Capture channels */
|
||||
#define PA_ALSA_PROP_UCM_CAPTURE_CHANNELS "alsa.ucm.capture.channels"
|
||||
|
||||
/** For devices: Quality of Service */
|
||||
#define PA_ALSA_PROP_UCM_QOS "alsa.ucm.qos"
|
||||
|
||||
typedef struct pa_alsa_ucm_verb pa_alsa_ucm_verb;
|
||||
typedef struct pa_alsa_ucm_modifier pa_alsa_ucm_modifier;
|
||||
typedef struct pa_alsa_ucm_device pa_alsa_ucm_device;
|
||||
typedef struct pa_alsa_ucm_config pa_alsa_ucm_config;
|
||||
typedef struct pa_alsa_ucm_mapping_context pa_alsa_ucm_mapping_context;
|
||||
|
||||
int pa_alsa_ucm_query_profiles(pa_alsa_ucm_config *ucm, int card_index);
|
||||
pa_alsa_profile_set* pa_alsa_ucm_add_profile_set(pa_alsa_ucm_config *ucm, pa_channel_map *default_channel_map);
|
||||
int pa_alsa_ucm_set_profile(pa_alsa_ucm_config *ucm, const char *new_profile, const char *old_profile);
|
||||
|
||||
int pa_alsa_ucm_get_verb(snd_use_case_mgr_t *uc_mgr, const char *verb_name, const char *verb_desc, pa_alsa_ucm_verb **p_verb);
|
||||
|
||||
void pa_alsa_ucm_add_ports(
|
||||
pa_hashmap **hash,
|
||||
pa_proplist *proplist,
|
||||
pa_alsa_ucm_mapping_context *context,
|
||||
bool is_sink,
|
||||
pa_card *card);
|
||||
void pa_alsa_ucm_add_ports_combination(
|
||||
pa_hashmap *hash,
|
||||
pa_alsa_ucm_mapping_context *context,
|
||||
bool is_sink,
|
||||
pa_hashmap *ports,
|
||||
pa_card_profile *cp,
|
||||
pa_core *core);
|
||||
int pa_alsa_ucm_set_port(pa_alsa_ucm_mapping_context *context, pa_device_port *port, bool is_sink);
|
||||
|
||||
void pa_alsa_ucm_free(pa_alsa_ucm_config *ucm);
|
||||
void pa_alsa_ucm_mapping_context_free(pa_alsa_ucm_mapping_context *context);
|
||||
|
||||
/* UCM - Use Case Manager is available on some audio cards */
|
||||
|
||||
struct pa_alsa_ucm_device {
|
||||
PA_LLIST_FIELDS(pa_alsa_ucm_device);
|
||||
|
||||
pa_proplist *proplist;
|
||||
|
||||
unsigned playback_priority;
|
||||
unsigned capture_priority;
|
||||
|
||||
unsigned playback_channels;
|
||||
unsigned capture_channels;
|
||||
|
||||
pa_alsa_mapping *playback_mapping;
|
||||
pa_alsa_mapping *capture_mapping;
|
||||
|
||||
pa_idxset *conflicting_devices;
|
||||
pa_idxset *supported_devices;
|
||||
};
|
||||
|
||||
struct pa_alsa_ucm_modifier {
|
||||
PA_LLIST_FIELDS(pa_alsa_ucm_modifier);
|
||||
|
||||
pa_proplist *proplist;
|
||||
|
||||
int n_confdev;
|
||||
int n_suppdev;
|
||||
|
||||
const char **conflicting_devices;
|
||||
const char **supported_devices;
|
||||
|
||||
pa_direction_t action_direction;
|
||||
|
||||
char *media_role;
|
||||
};
|
||||
|
||||
struct pa_alsa_ucm_verb {
|
||||
PA_LLIST_FIELDS(pa_alsa_ucm_verb);
|
||||
|
||||
pa_proplist *proplist;
|
||||
|
||||
PA_LLIST_HEAD(pa_alsa_ucm_device, devices);
|
||||
PA_LLIST_HEAD(pa_alsa_ucm_modifier, modifiers);
|
||||
};
|
||||
|
||||
struct pa_alsa_ucm_config {
|
||||
pa_core *core;
|
||||
snd_use_case_mgr_t *ucm_mgr;
|
||||
pa_alsa_ucm_verb *active_verb;
|
||||
|
||||
PA_LLIST_HEAD(pa_alsa_ucm_verb, verbs);
|
||||
};
|
||||
|
||||
struct pa_alsa_ucm_mapping_context {
|
||||
pa_alsa_ucm_config *ucm;
|
||||
pa_direction_t direction;
|
||||
|
||||
pa_idxset *ucm_devices;
|
||||
pa_idxset *ucm_modifiers;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
@ -37,6 +37,7 @@
|
|||
#endif
|
||||
|
||||
#include "alsa-util.h"
|
||||
#include "alsa-ucm.h"
|
||||
#include "alsa-sink.h"
|
||||
#include "alsa-source.h"
|
||||
#include "module-alsa-card-symdef.h"
|
||||
|
|
@ -69,6 +70,7 @@ PA_MODULE_USAGE(
|
|||
"deferred_volume=<Synchronize software and hardware volume changes to avoid momentary jumps?> "
|
||||
"profile_set=<profile set configuration file> "
|
||||
"paths_dir=<directory containing the path configuration files> "
|
||||
"use_ucm=<load use case manager> "
|
||||
);
|
||||
|
||||
static const char* const valid_modargs[] = {
|
||||
|
|
@ -95,6 +97,7 @@ static const char* const valid_modargs[] = {
|
|||
"deferred_volume",
|
||||
"profile_set",
|
||||
"paths_dir",
|
||||
"use_ucm",
|
||||
NULL
|
||||
};
|
||||
|
||||
|
|
@ -117,6 +120,10 @@ struct userdata {
|
|||
pa_modargs *modargs;
|
||||
|
||||
pa_alsa_profile_set *profile_set;
|
||||
|
||||
/* ucm stuffs */
|
||||
pa_bool_t use_ucm;
|
||||
pa_alsa_ucm_config ucm;
|
||||
};
|
||||
|
||||
struct profile_data {
|
||||
|
|
@ -143,7 +150,10 @@ static void add_profiles(struct userdata *u, pa_hashmap *h, pa_hashmap *ports) {
|
|||
cp->n_sinks = pa_idxset_size(ap->output_mappings);
|
||||
|
||||
PA_IDXSET_FOREACH(m, ap->output_mappings, idx) {
|
||||
pa_alsa_path_set_add_ports(m->output_path_set, cp, ports, NULL, u->core);
|
||||
if (u->use_ucm)
|
||||
pa_alsa_ucm_add_ports_combination(NULL, &m->ucm_context, TRUE, ports, cp, u->core);
|
||||
else
|
||||
pa_alsa_path_set_add_ports(m->output_path_set, cp, ports, NULL, u->core);
|
||||
if (m->channel_map.channels > cp->max_sink_channels)
|
||||
cp->max_sink_channels = m->channel_map.channels;
|
||||
}
|
||||
|
|
@ -153,7 +163,10 @@ static void add_profiles(struct userdata *u, pa_hashmap *h, pa_hashmap *ports) {
|
|||
cp->n_sources = pa_idxset_size(ap->input_mappings);
|
||||
|
||||
PA_IDXSET_FOREACH(m, ap->input_mappings, idx) {
|
||||
pa_alsa_path_set_add_ports(m->input_path_set, cp, ports, NULL, u->core);
|
||||
if (u->use_ucm)
|
||||
pa_alsa_ucm_add_ports_combination(NULL, &m->ucm_context, FALSE, ports, cp, u->core);
|
||||
else
|
||||
pa_alsa_path_set_add_ports(m->input_path_set, cp, ports, NULL, u->core);
|
||||
if (m->channel_map.channels > cp->max_source_channels)
|
||||
cp->max_source_channels = m->channel_map.channels;
|
||||
}
|
||||
|
|
@ -222,6 +235,13 @@ static int card_set_profile(pa_card *c, pa_card_profile *new_profile) {
|
|||
am->source = NULL;
|
||||
}
|
||||
|
||||
/* if UCM is available for this card then update the verb */
|
||||
if (u->use_ucm) {
|
||||
if (pa_alsa_ucm_set_profile(&u->ucm, nd->profile ? nd->profile->name : NULL,
|
||||
od->profile ? od->profile->name : NULL) < 0)
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (nd->profile && nd->profile->output_mappings)
|
||||
PA_IDXSET_FOREACH(am, nd->profile->output_mappings, idx) {
|
||||
|
||||
|
|
@ -259,11 +279,20 @@ static void init_profile(struct userdata *u) {
|
|||
uint32_t idx;
|
||||
pa_alsa_mapping *am;
|
||||
struct profile_data *d;
|
||||
pa_alsa_ucm_config *ucm = &u->ucm;
|
||||
|
||||
pa_assert(u);
|
||||
|
||||
d = PA_CARD_PROFILE_DATA(u->card->active_profile);
|
||||
|
||||
if (d->profile && u->use_ucm) {
|
||||
/* Set initial verb */
|
||||
if (pa_alsa_ucm_set_profile(ucm, d->profile->name, NULL) < 0) {
|
||||
pa_log("Failed to set ucm profile %s", d->profile->name);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (d->profile && d->profile->output_mappings)
|
||||
PA_IDXSET_FOREACH(am, d->profile->output_mappings, idx)
|
||||
am->sink = pa_alsa_sink_new(u->module, u->modargs, __FILE__, u->card, am);
|
||||
|
|
@ -439,6 +468,9 @@ int pa__init(pa_module *m) {
|
|||
u->device_id = pa_xstrdup(pa_modargs_get_value(ma, "device_id", DEFAULT_DEVICE_ID));
|
||||
u->modargs = ma;
|
||||
|
||||
u->use_ucm = TRUE;
|
||||
u->ucm.core = m->core;
|
||||
|
||||
if ((u->alsa_card_index = snd_card_get_index(u->device_id)) < 0) {
|
||||
pa_log("Card '%s' doesn't exist: %s", u->device_id, pa_alsa_strerror(u->alsa_card_index));
|
||||
goto fail;
|
||||
|
|
@ -456,17 +488,26 @@ int pa__init(pa_module *m) {
|
|||
}
|
||||
}
|
||||
|
||||
pa_modargs_get_value_boolean(ma, "use_ucm", &u->use_ucm);
|
||||
if (u->use_ucm && !pa_alsa_ucm_query_profiles(&u->ucm, u->alsa_card_index)) {
|
||||
pa_log_info("Found UCM profiles");
|
||||
|
||||
u->profile_set = pa_alsa_ucm_add_profile_set(&u->ucm, &u->core->default_channel_map);
|
||||
}
|
||||
else {
|
||||
u->use_ucm = FALSE;
|
||||
#ifdef HAVE_UDEV
|
||||
fn = pa_udev_get_property(u->alsa_card_index, "PULSE_PROFILE_SET");
|
||||
fn = pa_udev_get_property(u->alsa_card_index, "PULSE_PROFILE_SET");
|
||||
#endif
|
||||
|
||||
if (pa_modargs_get_value(ma, "profile_set", NULL)) {
|
||||
pa_xfree(fn);
|
||||
fn = pa_xstrdup(pa_modargs_get_value(ma, "profile_set", NULL));
|
||||
}
|
||||
if (pa_modargs_get_value(ma, "profile_set", NULL)) {
|
||||
pa_xfree(fn);
|
||||
fn = pa_xstrdup(pa_modargs_get_value(ma, "profile_set", NULL));
|
||||
}
|
||||
|
||||
u->profile_set = pa_alsa_profile_set_new(fn, &u->core->default_channel_map);
|
||||
pa_xfree(fn);
|
||||
u->profile_set = pa_alsa_profile_set_new(fn, &u->core->default_channel_map);
|
||||
pa_xfree(fn);
|
||||
}
|
||||
|
||||
u->profile_set->ignore_dB = ignore_dB;
|
||||
|
||||
|
|
@ -613,6 +654,8 @@ void pa__done(pa_module*m) {
|
|||
if (u->profile_set)
|
||||
pa_alsa_profile_set_free(u->profile_set);
|
||||
|
||||
pa_alsa_ucm_free(&u->ucm);
|
||||
|
||||
pa_xfree(u->device_id);
|
||||
pa_xfree(u);
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue