pipewire/spa/plugins/alsa/acp/alsa-mixer.h

460 lines
14 KiB
C
Raw Normal View History

#ifndef fooalsamixerhfoo
#define fooalsamixerhfoo
/***
This file is part of PulseAudio.
Copyright 2004-2006 Lennart Poettering
Copyright 2006 Pierre Ossman <ossman@cendio.se> for Cendio AB
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, see <http://www.gnu.org/licenses/>.
***/
#include <alsa/asoundlib.h>
typedef struct pa_alsa_mixer pa_alsa_mixer;
typedef struct pa_alsa_setting pa_alsa_setting;
typedef struct pa_alsa_mixer_id pa_alsa_mixer_id;
typedef struct pa_alsa_option pa_alsa_option;
typedef struct pa_alsa_element pa_alsa_element;
typedef struct pa_alsa_jack pa_alsa_jack;
typedef struct pa_alsa_path pa_alsa_path;
typedef struct pa_alsa_path_set pa_alsa_path_set;
typedef struct pa_alsa_mapping pa_alsa_mapping;
typedef struct pa_alsa_profile pa_alsa_profile;
typedef struct pa_alsa_decibel_fix pa_alsa_decibel_fix;
typedef struct pa_alsa_profile_set pa_alsa_profile_set;
typedef struct pa_alsa_port_data pa_alsa_port_data;
typedef struct pa_alsa_profile pa_alsa_profile;
typedef struct pa_alsa_profile pa_card_profile;
typedef struct pa_alsa_device pa_alsa_device;
2021-01-05 10:08:31 +01:00
#define POSITION_MASK_CHANNELS 8
typedef enum pa_alsa_switch_use {
PA_ALSA_SWITCH_IGNORE,
PA_ALSA_SWITCH_MUTE, /* make this switch follow mute status */
PA_ALSA_SWITCH_OFF, /* set this switch to 'off' unconditionally */
PA_ALSA_SWITCH_ON, /* set this switch to 'on' unconditionally */
PA_ALSA_SWITCH_SELECT /* allow the user to select switch status through a setting */
} pa_alsa_switch_use_t;
typedef enum pa_alsa_volume_use {
PA_ALSA_VOLUME_IGNORE,
PA_ALSA_VOLUME_MERGE, /* merge this volume slider into the global volume slider */
PA_ALSA_VOLUME_OFF, /* set this volume to minimal unconditionally */
PA_ALSA_VOLUME_ZERO, /* set this volume to 0dB unconditionally */
PA_ALSA_VOLUME_CONSTANT /* set this volume to a constant value unconditionally */
} pa_alsa_volume_use_t;
typedef enum pa_alsa_enumeration_use {
PA_ALSA_ENUMERATION_IGNORE,
PA_ALSA_ENUMERATION_SELECT
} pa_alsa_enumeration_use_t;
typedef enum pa_alsa_required {
PA_ALSA_REQUIRED_IGNORE,
PA_ALSA_REQUIRED_SWITCH,
PA_ALSA_REQUIRED_VOLUME,
PA_ALSA_REQUIRED_ENUMERATION,
PA_ALSA_REQUIRED_ANY
} pa_alsa_required_t;
typedef enum pa_alsa_direction {
PA_ALSA_DIRECTION_ANY,
PA_ALSA_DIRECTION_OUTPUT,
PA_ALSA_DIRECTION_INPUT
} pa_alsa_direction_t;
#include "acp.h"
#include "device-port.h"
#include "alsa-util.h"
#include "alsa-ucm.h"
#include "card.h"
/* A setting combines a couple of options into a single entity that
* may be selected. Only one setting can be active at the same
* time. */
struct pa_alsa_setting {
pa_alsa_path *path;
PA_LLIST_FIELDS(pa_alsa_setting);
pa_idxset *options;
char *name;
char *description;
unsigned priority;
};
/* An entry for one ALSA mixer */
struct pa_alsa_mixer {
2022-01-03 17:21:28 +01:00
struct pa_alsa_mixer *alias;
snd_mixer_t *mixer_handle;
bool used_for_poll:1;
bool used_for_probe_only:1;
};
/* ALSA mixer element identifier */
struct pa_alsa_mixer_id {
char *name;
int index;
};
2021-01-05 10:08:31 +01:00
char *pa_alsa_mixer_id_to_string(char *dst, size_t dst_len, pa_alsa_mixer_id *id);
/* An option belongs to an element and refers to one enumeration item
* of the element is an enumeration item, or a switch status if the
* element is a switch item. */
struct pa_alsa_option {
pa_alsa_element *element;
PA_LLIST_FIELDS(pa_alsa_option);
char *alsa_name;
int alsa_idx;
char *name;
char *description;
unsigned priority;
pa_alsa_required_t required;
pa_alsa_required_t required_any;
pa_alsa_required_t required_absent;
};
/* An element wraps one specific ALSA element. A series of elements
* make up a path (see below). If the element is an enumeration or switch
* element it may include a list of options. */
struct pa_alsa_element {
pa_alsa_path *path;
PA_LLIST_FIELDS(pa_alsa_element);
struct pa_alsa_mixer_id alsa_id;
pa_alsa_direction_t direction;
pa_alsa_switch_use_t switch_use;
pa_alsa_volume_use_t volume_use;
pa_alsa_enumeration_use_t enumeration_use;
pa_alsa_required_t required;
pa_alsa_required_t required_any;
pa_alsa_required_t required_absent;
long constant_volume;
2021-01-05 10:08:31 +01:00
unsigned int override_map;
bool direction_try_other:1;
bool has_dB:1;
long min_volume, max_volume;
long volume_limit; /* -1 for no configured limit */
double min_dB, max_dB;
2021-01-05 10:08:31 +01:00
pa_channel_position_mask_t masks[SND_MIXER_SCHN_LAST + 1][POSITION_MASK_CHANNELS];
unsigned n_channels;
pa_channel_position_mask_t merged_mask;
PA_LLIST_HEAD(pa_alsa_option, options);
pa_alsa_decibel_fix *db_fix;
};
struct pa_alsa_jack {
pa_alsa_path *path;
PA_LLIST_FIELDS(pa_alsa_jack);
snd_mixer_t *mixer_handle;
char *mixer_device_name;
2021-01-05 10:08:31 +01:00
struct pa_alsa_mixer_id alsa_id;
char *name; /* E g "Headphone" */
bool has_control; /* is the jack itself present? */
bool plugged_in; /* is this jack currently plugged in? */
snd_mixer_elem_t *melem; /* Jack detection handle */
pa_available_t state_unplugged, state_plugged;
pa_alsa_required_t required;
pa_alsa_required_t required_any;
pa_alsa_required_t required_absent;
pa_dynarray *ucm_devices; /* pa_alsa_ucm_device */
pa_dynarray *ucm_hw_mute_devices; /* pa_alsa_ucm_device */
bool append_pcm_to_name;
};
2021-01-05 10:08:31 +01:00
pa_alsa_jack *pa_alsa_jack_new(pa_alsa_path *path, const char *mixer_device_name, const char *name, int index);
void pa_alsa_jack_free(pa_alsa_jack *jack);
void pa_alsa_jack_set_has_control(pa_alsa_jack *jack, bool has_control);
void pa_alsa_jack_set_plugged_in(pa_alsa_jack *jack, bool plugged_in);
void pa_alsa_jack_add_ucm_device(pa_alsa_jack *jack, pa_alsa_ucm_device *device);
void pa_alsa_jack_add_ucm_hw_mute_device(pa_alsa_jack *jack, pa_alsa_ucm_device *device);
/* A path wraps a series of elements into a single entity which can be
* used to control it as if it had a single volume slider, a single
* mute switch and a single list of selectable options. */
struct pa_alsa_path {
pa_alsa_direction_t direction;
pa_device_port* port;
char *name;
char *description_key;
char *description;
char *availability_group;
pa_device_port_type_t device_port_type;
unsigned priority;
bool autodetect_eld_device;
pa_alsa_mixer *eld_mixer_handle;
int eld_device;
pa_proplist *proplist;
bool probed:1;
bool supported:1;
bool has_mute:1;
bool has_volume:1;
bool has_dB:1;
bool mute_during_activation:1;
/* These two are used during probing only */
bool has_req_any:1;
bool req_any_present:1;
long min_volume, max_volume;
double min_dB, max_dB;
/* This is used during parsing only, as a shortcut so that we
* don't have to iterate the list all the time */
pa_alsa_element *last_element;
pa_alsa_option *last_option;
pa_alsa_setting *last_setting;
pa_alsa_jack *last_jack;
PA_LLIST_HEAD(pa_alsa_element, elements);
PA_LLIST_HEAD(pa_alsa_setting, settings);
PA_LLIST_HEAD(pa_alsa_jack, jacks);
};
/* A path set is simply a set of paths that are applicable to a
* device */
struct pa_alsa_path_set {
pa_hashmap *paths;
pa_alsa_direction_t direction;
};
void pa_alsa_setting_dump(pa_alsa_setting *s);
void pa_alsa_option_dump(pa_alsa_option *o);
void pa_alsa_jack_dump(pa_alsa_jack *j);
void pa_alsa_element_dump(pa_alsa_element *e);
pa_alsa_path *pa_alsa_path_new(const char *paths_dir, const char *fname, pa_alsa_direction_t direction);
pa_alsa_path *pa_alsa_path_synthesize(const char *element, pa_alsa_direction_t direction);
pa_alsa_element *pa_alsa_element_get(pa_alsa_path *p, const char *section, bool prefixed);
int pa_alsa_path_probe(pa_alsa_path *p, pa_alsa_mapping *mapping, snd_mixer_t *m, bool ignore_dB);
void pa_alsa_path_dump(pa_alsa_path *p);
int pa_alsa_path_get_volume(pa_alsa_path *p, snd_mixer_t *m, const pa_channel_map *cm, pa_cvolume *v);
int pa_alsa_path_get_mute(pa_alsa_path *path, snd_mixer_t *m, bool *muted);
int pa_alsa_path_set_volume(pa_alsa_path *path, snd_mixer_t *m, const pa_channel_map *cm, pa_cvolume *v, bool deferred_volume, bool write_to_hw);
int pa_alsa_path_set_mute(pa_alsa_path *path, snd_mixer_t *m, bool muted);
int pa_alsa_path_select(pa_alsa_path *p, pa_alsa_setting *s, snd_mixer_t *m, bool device_is_muted);
void pa_alsa_path_set_callback(pa_alsa_path *p, snd_mixer_t *m, snd_mixer_elem_callback_t cb, void *userdata);
void pa_alsa_path_free(pa_alsa_path *p);
pa_alsa_path_set *pa_alsa_path_set_new(pa_alsa_mapping *m, pa_alsa_direction_t direction, const char *paths_dir);
void pa_alsa_path_set_dump(pa_alsa_path_set *s);
void pa_alsa_path_set_set_callback(pa_alsa_path_set *ps, snd_mixer_t *m, snd_mixer_elem_callback_t cb, void *userdata);
void pa_alsa_path_set_free(pa_alsa_path_set *s);
int pa_alsa_path_set_is_empty(pa_alsa_path_set *s);
struct pa_alsa_device {
struct acp_device device;
pa_card *card;
pa_alsa_direction_t direction;
pa_proplist *proplist;
pa_alsa_mapping *mapping;
pa_alsa_ucm_mapping_context *ucm_context;
pa_hashmap *ports;
pa_dynarray port_array;
pa_device_port *active_port;
snd_mixer_t *mixer_handle;
pa_alsa_path_set *mixer_path_set;
pa_alsa_path *mixer_path;
snd_pcm_t *pcm_handle;
unsigned muted:1;
unsigned decibel_volume:1;
pa_cvolume real_volume;
pa_cvolume hardware_volume;
pa_cvolume soft_volume;
pa_volume_t base_volume;
unsigned n_volume_steps;
int (*read_volume)(pa_alsa_device *dev);
int (*read_mute)(pa_alsa_device *dev);
void (*set_volume)(pa_alsa_device *dev, const pa_cvolume *v);
void (*set_mute)(pa_alsa_device *dev, bool m);
};
struct pa_alsa_mapping {
pa_alsa_profile_set *profile_set;
char *name;
char *description;
2020-07-28 10:16:47 +02:00
char *description_key;
unsigned priority;
pa_alsa_direction_t direction;
/* These are copied over to the resultant sink/source */
pa_proplist *proplist;
pa_sample_spec sample_spec;
pa_channel_map channel_map;
char **device_strings;
char **input_path_names;
char **output_path_names;
char **input_element; /* list of fallbacks */
char **output_element;
pa_alsa_path_set *input_path_set;
pa_alsa_path_set *output_path_set;
unsigned supported;
bool exact_channels:1;
bool fallback:1;
/* The "y" in "hw:x,y". This is set to -1 before the device index has been
* queried, or if the query failed. */
int hw_device_index;
/* Temporarily used during probing */
snd_pcm_t *input_pcm;
snd_pcm_t *output_pcm;
pa_proplist *input_proplist;
pa_proplist *output_proplist;
pa_alsa_device output;
pa_alsa_device input;
Revert "alsa: UCM conflicting devices changes" If needs some more work This reverts commit aae770f18b7f6c94195fb3f2e2a61308029086af. This reverts commit 2216956e05689079db5ec05f793158e6479060da. This reverts commit 1d3c4501eff3392e0cd858d980c742c7f88c95e7. This reverts commit c7ca02460761273de0d1a8432c5defaafed43664. This reverts commit 8e4a5f5d5ed3d8b3081956f451c85c23aa74fc15. This reverts commit 8b20675ad12bc9daea84f6d4314ec12fccf5882c. This reverts commit ebe6f8b51a31ff7bd71d560991a12283f710b937. This reverts commit 4b97da1277b709e9749b568319f5eb403ff0f362. This reverts commit 7c46a656c734d4688cac229cd9d49af5ad0609fa. This reverts commit 96ed03e1fc5b1f0a287069c42031d7961239c896. This reverts commit 43770c533c71bfaf2c7e82d47d50bfd0533b53e0. This reverts commit ccb2fce05452185858d22de06d659452702f05d8. This reverts commit 93d0ddc8b327f9aaf11d71193f1d50d64bf1144b. This reverts commit 815e8c8fa09a88269b674786a152fe36849b933d. This reverts commit 97b99a0f7c2dd059c08c6ccd143cc1be06111ad1. This reverts commit 7e4d87402b17cd881e9140c37285b175c622ea24. This reverts commit 168b3ee22c1545b738634c4ae89ae4afbaf68cc4. This reverts commit 5128cdba319a2ced0f2e559ad594b8cbeb97a072. This reverts commit 31cde774c54931109da99bc452c858a208d94d6c. This reverts commit b02c8ba153f21459f1a120d4c1ca1bde6a98f4fb. This reverts commit 68ac72d09857901a33be22922669fc8674a4ab9c. This reverts commit 96cfc9bc1ac63414e7b3a6b928be5a29c03e1431. This reverts commit e2d642a20b1bc4e70f7273ddfc3da376a342e10f. This reverts commit 80fc80c34348bdc247bb1a12bcc174db772208a4. This reverts commit 3a68905c7c45677f64213ff563fd68bce6d14a9f. This reverts commit 7e64680a65e4dc2c755e79e55f43f7596b31e1d9. This reverts commit 8d1e38a2816e113121f2355a5827b0a681a3d41b. This reverts commit 591188195c60bb0bba4019d76547ece5386496ac. This reverts commit 973fe0cb79c9ef508778c7a2bb98bdfebeb70dfe. This reverts commit 4d08c9ad609d47c16d03ae3d5230c14d8d52f49e. This reverts commit 3dce92e58090de98e9f1470d9ba69da1f1b590db. This reverts commit 6b5e232c5c4a8e3d2d1c442c87ab03cc40350978. This reverts commit b1286c62c90167d6f6b6c17ad9bdfbb5d0254f60.
2023-04-12 12:30:56 +02:00
/* ucm device context*/
pa_alsa_ucm_mapping_context ucm_context;
};
struct pa_alsa_profile {
struct acp_card_profile profile;
pa_alsa_profile_set *profile_set;
char *name;
char *description;
char *description_key;
unsigned priority;
char *input_name;
char *output_name;
bool supported:1;
bool fallback_input:1;
bool fallback_output:1;
char **input_mapping_names;
char **output_mapping_names;
pa_idxset *input_mappings;
pa_idxset *output_mappings;
struct {
pa_dynarray devices;
} out;
};
struct pa_alsa_decibel_fix {
char *key;
pa_alsa_profile_set *profile_set;
char *name; /* Alsa volume element name. */
int index; /* Alsa volume element index. */
long min_step;
long max_step;
/* An array that maps alsa volume element steps to decibels. The steps can
* be used as indices to this array, after subtracting min_step from the
* real value.
*
* The values are actually stored as integers representing millibels,
* because that's the format the alsa API uses. */
long *db_values;
};
struct pa_alsa_profile_set {
pa_hashmap *mappings;
pa_hashmap *profiles;
pa_hashmap *decibel_fixes;
pa_hashmap *input_paths;
pa_hashmap *output_paths;
bool auto_profiles;
bool ignore_dB:1;
bool probed:1;
};
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);
void pa_alsa_mapping_free (pa_alsa_mapping *m);
void pa_alsa_profile_free (pa_alsa_profile *p);
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, pa_hashmap *mixers, 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);
void pa_alsa_mixer_use_for_poll(pa_hashmap *mixers, snd_mixer_t *mixer_handle);
#if 0
pa_alsa_fdlist *pa_alsa_fdlist_new(void);
void pa_alsa_fdlist_free(pa_alsa_fdlist *fdl);
int pa_alsa_fdlist_set_handle(pa_alsa_fdlist *fdl, snd_mixer_t *mixer_handle, snd_hctl_t *hctl_handle, pa_mainloop_api* m);
/* Alternative for handling alsa mixer events in io-thread. */
pa_alsa_mixer_pdata *pa_alsa_mixer_pdata_new(void);
void pa_alsa_mixer_pdata_free(pa_alsa_mixer_pdata *pd);
int pa_alsa_set_mixer_rtpoll(struct pa_alsa_mixer_pdata *pd, snd_mixer_t *mixer, pa_rtpoll *rtp);
#endif
/* Data structure for inclusion in pa_device_port for alsa
* sinks/sources. This contains nothing that needs to be freed
* individually */
struct pa_alsa_port_data {
pa_alsa_path *path;
pa_alsa_setting *setting;
bool suspend_when_unavailable;
};
void pa_alsa_add_ports(pa_hashmap *ports, pa_alsa_path_set *ps, pa_card *card);
void pa_alsa_path_set_add_ports(pa_alsa_path_set *ps, pa_alsa_profile *cp, pa_hashmap *ports, pa_hashmap *extra, pa_core *core);
#endif