1 #ifndef fooalsamixerhfoo 2 #define fooalsamixerhfoo 3 4 /*** 5 This file is part of PulseAudio. 6 7 Copyright 2004-2006 Lennart Poettering 8 Copyright 2006 Pierre Ossman <ossman@cendio.se> for Cendio AB 9 10 PulseAudio is free software; you can redistribute it and/or modify 11 it under the terms of the GNU Lesser General Public License as published 12 by the Free Software Foundation; either version 2.1 of the License, 13 or (at your option) any later version. 14 15 PulseAudio is distributed in the hope that it will be useful, but 16 WITHOUT ANY WARRANTY; without even the implied warranty of 17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 18 General Public License for more details. 19 20 You should have received a copy of the GNU Lesser General Public License 21 along with PulseAudio; if not, see <http://www.gnu.org/licenses/>. 22 ***/ 23 24 #include <alsa/asoundlib.h> 25 26 #include <pulse/sample.h> 27 #include <pulse/mainloop-api.h> 28 #include <pulse/channelmap.h> 29 #include <pulse/volume.h> 30 31 #include <pulsecore/llist.h> 32 #include <pulsecore/rtpoll.h> 33 34 typedef struct pa_alsa_fdlist pa_alsa_fdlist; 35 typedef struct pa_alsa_mixer pa_alsa_mixer; 36 typedef struct pa_alsa_mixer_pdata pa_alsa_mixer_pdata; 37 typedef struct pa_alsa_setting pa_alsa_setting; 38 typedef struct pa_alsa_mixer_id pa_alsa_mixer_id; 39 typedef struct pa_alsa_option pa_alsa_option; 40 typedef struct pa_alsa_element pa_alsa_element; 41 typedef struct pa_alsa_jack pa_alsa_jack; 42 typedef struct pa_alsa_path pa_alsa_path; 43 typedef struct pa_alsa_path_set pa_alsa_path_set; 44 typedef struct pa_alsa_mapping pa_alsa_mapping; 45 typedef struct pa_alsa_profile pa_alsa_profile; 46 typedef struct pa_alsa_decibel_fix pa_alsa_decibel_fix; 47 typedef struct pa_alsa_profile_set pa_alsa_profile_set; 48 typedef struct pa_alsa_port_data pa_alsa_port_data; 49 50 #include "alsa-util.h" 51 #include "alsa-ucm.h" 52 53 #define POSITION_MASK_CHANNELS 8 54 55 typedef enum pa_alsa_switch_use { 56 PA_ALSA_SWITCH_IGNORE, 57 PA_ALSA_SWITCH_MUTE, /* make this switch follow mute status */ 58 PA_ALSA_SWITCH_OFF, /* set this switch to 'off' unconditionally */ 59 PA_ALSA_SWITCH_ON, /* set this switch to 'on' unconditionally */ 60 PA_ALSA_SWITCH_SELECT /* allow the user to select switch status through a setting */ 61 } pa_alsa_switch_use_t; 62 63 typedef enum pa_alsa_volume_use { 64 PA_ALSA_VOLUME_IGNORE, 65 PA_ALSA_VOLUME_MERGE, /* merge this volume slider into the global volume slider */ 66 PA_ALSA_VOLUME_OFF, /* set this volume to minimal unconditionally */ 67 PA_ALSA_VOLUME_ZERO, /* set this volume to 0dB unconditionally */ 68 PA_ALSA_VOLUME_CONSTANT /* set this volume to a constant value unconditionally */ 69 } pa_alsa_volume_use_t; 70 71 typedef enum pa_alsa_enumeration_use { 72 PA_ALSA_ENUMERATION_IGNORE, 73 PA_ALSA_ENUMERATION_SELECT 74 } pa_alsa_enumeration_use_t; 75 76 typedef enum pa_alsa_required { 77 PA_ALSA_REQUIRED_IGNORE, 78 PA_ALSA_REQUIRED_SWITCH, 79 PA_ALSA_REQUIRED_VOLUME, 80 PA_ALSA_REQUIRED_ENUMERATION, 81 PA_ALSA_REQUIRED_ANY 82 } pa_alsa_required_t; 83 84 typedef enum pa_alsa_direction { 85 PA_ALSA_DIRECTION_ANY, 86 PA_ALSA_DIRECTION_OUTPUT, 87 PA_ALSA_DIRECTION_INPUT 88 } pa_alsa_direction_t; 89 90 /* A setting combines a couple of options into a single entity that 91 * may be selected. Only one setting can be active at the same 92 * time. */ 93 struct pa_alsa_setting { 94 pa_alsa_path *path; 95 PA_LLIST_FIELDS(pa_alsa_setting); 96 97 pa_idxset *options; 98 99 char *name; 100 char *description; 101 unsigned priority; 102 }; 103 104 /* An entry for one ALSA mixer */ 105 struct pa_alsa_mixer { 106 snd_mixer_t *mixer_handle; 107 int card_index; 108 pa_alsa_fdlist *fdl; 109 bool used_for_probe_only:1; 110 }; 111 112 /* ALSA mixer element identifier */ 113 struct pa_alsa_mixer_id { 114 char *name; 115 int index; 116 }; 117 118 char *pa_alsa_mixer_id_to_string(char *dst, size_t dst_len, pa_alsa_mixer_id *id); 119 120 /* An option belongs to an element and refers to one enumeration item 121 * of the element is an enumeration item, or a switch status if the 122 * element is a switch item. */ 123 struct pa_alsa_option { 124 pa_alsa_element *element; 125 PA_LLIST_FIELDS(pa_alsa_option); 126 127 char *alsa_name; 128 int alsa_idx; 129 130 char *name; 131 char *description; 132 unsigned priority; 133 134 pa_alsa_required_t required; 135 pa_alsa_required_t required_any; 136 pa_alsa_required_t required_absent; 137 }; 138 139 /* An element wraps one specific ALSA element. A series of elements 140 * make up a path (see below). If the element is an enumeration or switch 141 * element it may include a list of options. */ 142 struct pa_alsa_element { 143 pa_alsa_path *path; 144 PA_LLIST_FIELDS(pa_alsa_element); 145 146 struct pa_alsa_mixer_id alsa_id; 147 pa_alsa_direction_t direction; 148 149 pa_alsa_switch_use_t switch_use; 150 pa_alsa_volume_use_t volume_use; 151 pa_alsa_enumeration_use_t enumeration_use; 152 153 pa_alsa_required_t required; 154 pa_alsa_required_t required_any; 155 pa_alsa_required_t required_absent; 156 157 long constant_volume; 158 159 unsigned int override_map; 160 bool direction_try_other:1; 161 162 bool has_dB:1; 163 long min_volume, max_volume; 164 long volume_limit; /* -1 for no configured limit */ 165 double min_dB, max_dB; 166 167 pa_channel_position_mask_t masks[SND_MIXER_SCHN_LAST + 1][POSITION_MASK_CHANNELS]; 168 unsigned n_channels; 169 170 pa_channel_position_mask_t merged_mask; 171 172 PA_LLIST_HEAD(pa_alsa_option, options); 173 174 pa_alsa_decibel_fix *db_fix; 175 }; 176 177 struct pa_alsa_jack { 178 pa_alsa_path *path; 179 PA_LLIST_FIELDS(pa_alsa_jack); 180 181 snd_mixer_t *mixer_handle; 182 char *mixer_device_name; 183 184 struct pa_alsa_mixer_id alsa_id; 185 char *name; /* E g "Headphone" */ 186 bool has_control; /* is the jack itself present? */ 187 bool plugged_in; /* is this jack currently plugged in? */ 188 snd_mixer_elem_t *melem; /* Jack detection handle */ 189 pa_available_t state_unplugged, state_plugged; 190 191 pa_alsa_required_t required; 192 pa_alsa_required_t required_any; 193 pa_alsa_required_t required_absent; 194 195 pa_dynarray *ucm_devices; /* pa_alsa_ucm_device */ 196 pa_dynarray *ucm_hw_mute_devices; /* pa_alsa_ucm_device */ 197 198 bool append_pcm_to_name; 199 }; 200 201 pa_alsa_jack *pa_alsa_jack_new(pa_alsa_path *path, const char *mixer_device_name, const char *name, int index); 202 void pa_alsa_jack_free(pa_alsa_jack *jack); 203 void pa_alsa_jack_set_has_control(pa_alsa_jack *jack, bool has_control); 204 void pa_alsa_jack_set_plugged_in(pa_alsa_jack *jack, bool plugged_in); 205 void pa_alsa_jack_add_ucm_device(pa_alsa_jack *jack, pa_alsa_ucm_device *device); 206 void pa_alsa_jack_add_ucm_hw_mute_device(pa_alsa_jack *jack, pa_alsa_ucm_device *device); 207 208 /* A path wraps a series of elements into a single entity which can be 209 * used to control it as if it had a single volume slider, a single 210 * mute switch and a single list of selectable options. */ 211 struct pa_alsa_path { 212 pa_alsa_direction_t direction; 213 pa_device_port* port; 214 215 char *name; 216 char *description_key; 217 char *description; 218 char *availability_group; 219 pa_device_port_type_t device_port_type; 220 unsigned priority; 221 bool autodetect_eld_device; 222 pa_alsa_mixer *eld_mixer_handle; 223 int eld_device; 224 pa_proplist *proplist; 225 226 bool probed:1; 227 bool supported:1; 228 bool has_mute:1; 229 bool has_volume:1; 230 bool has_dB:1; 231 bool mute_during_activation:1; 232 /* These two are used during probing only */ 233 bool has_req_any:1; 234 bool req_any_present:1; 235 236 long min_volume, max_volume; 237 double min_dB, max_dB; 238 239 /* This is used during parsing only, as a shortcut so that we 240 * don't have to iterate the list all the time */ 241 pa_alsa_element *last_element; 242 pa_alsa_option *last_option; 243 pa_alsa_setting *last_setting; 244 pa_alsa_jack *last_jack; 245 246 PA_LLIST_HEAD(pa_alsa_element, elements); 247 PA_LLIST_HEAD(pa_alsa_setting, settings); 248 PA_LLIST_HEAD(pa_alsa_jack, jacks); 249 }; 250 251 /* A path set is simply a set of paths that are applicable to a 252 * device */ 253 struct pa_alsa_path_set { 254 pa_hashmap *paths; 255 pa_alsa_direction_t direction; 256 }; 257 258 void pa_alsa_setting_dump(pa_alsa_setting *s); 259 260 void pa_alsa_option_dump(pa_alsa_option *o); 261 void pa_alsa_jack_dump(pa_alsa_jack *j); 262 void pa_alsa_element_dump(pa_alsa_element *e); 263 264 pa_alsa_path *pa_alsa_path_new(const char *paths_dir, const char *fname, pa_alsa_direction_t direction); 265 pa_alsa_path *pa_alsa_path_synthesize(const char *element, pa_alsa_direction_t direction); 266 pa_alsa_element *pa_alsa_element_get(pa_alsa_path *p, const char *section, bool prefixed); 267 int pa_alsa_path_probe(pa_alsa_path *p, pa_alsa_mapping *mapping, snd_mixer_t *m, bool ignore_dB); 268 void pa_alsa_path_dump(pa_alsa_path *p); 269 int pa_alsa_path_get_volume(pa_alsa_path *p, snd_mixer_t *m, const pa_channel_map *cm, pa_cvolume *v); 270 int pa_alsa_path_get_mute(pa_alsa_path *path, snd_mixer_t *m, bool *muted); 271 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); 272 int pa_alsa_path_set_mute(pa_alsa_path *path, snd_mixer_t *m, bool muted); 273 int pa_alsa_path_select(pa_alsa_path *p, pa_alsa_setting *s, snd_mixer_t *m, bool device_is_muted); 274 void pa_alsa_path_set_callback(pa_alsa_path *p, snd_mixer_t *m, snd_mixer_elem_callback_t cb, void *userdata); 275 void pa_alsa_path_free(pa_alsa_path *p); 276 277 pa_alsa_path_set *pa_alsa_path_set_new(pa_alsa_mapping *m, pa_alsa_direction_t direction, const char *paths_dir); 278 void pa_alsa_path_set_dump(pa_alsa_path_set *s); 279 void pa_alsa_path_set_set_callback(pa_alsa_path_set *ps, snd_mixer_t *m, snd_mixer_elem_callback_t cb, void *userdata); 280 void pa_alsa_path_set_free(pa_alsa_path_set *s); 281 int pa_alsa_path_set_is_empty(pa_alsa_path_set *s); 282 283 struct pa_alsa_mapping { 284 pa_alsa_profile_set *profile_set; 285 286 char *name; 287 char *description; 288 char *description_key; 289 unsigned priority; 290 pa_alsa_direction_t direction; 291 /* These are copied over to the resultant sink/source */ 292 pa_proplist *proplist; 293 294 pa_sample_spec sample_spec; 295 pa_channel_map channel_map; 296 297 char **device_strings; 298 299 char **input_path_names; 300 char **output_path_names; 301 char **input_element; /* list of fallbacks */ 302 char **output_element; 303 pa_alsa_path_set *input_path_set; 304 pa_alsa_path_set *output_path_set; 305 306 unsigned supported; 307 bool exact_channels:1; 308 bool fallback:1; 309 310 /* The "y" in "hw:x,y". This is set to -1 before the device index has been 311 * queried, or if the query failed. */ 312 int hw_device_index; 313 314 /* Temporarily used during probing */ 315 snd_pcm_t *input_pcm; 316 snd_pcm_t *output_pcm; 317 318 pa_sink *sink; 319 pa_source *source; 320 321 /* ucm device context*/ 322 pa_alsa_ucm_mapping_context ucm_context; 323 }; 324 325 struct pa_alsa_profile { 326 pa_alsa_profile_set *profile_set; 327 328 char *name; 329 char *description; 330 char *description_key; 331 unsigned priority; 332 333 char *input_name; 334 char *output_name; 335 336 bool supported:1; 337 bool fallback_input:1; 338 bool fallback_output:1; 339 340 char **input_mapping_names; 341 char **output_mapping_names; 342 343 pa_idxset *input_mappings; 344 pa_idxset *output_mappings; 345 }; 346 347 struct pa_alsa_decibel_fix { 348 char *key; 349 350 pa_alsa_profile_set *profile_set; 351 352 char *name; /* Alsa volume element name. */ 353 int index; /* Alsa volume element index. */ 354 long min_step; 355 long max_step; 356 357 /* An array that maps alsa volume element steps to decibels. The steps can 358 * be used as indices to this array, after subtracting min_step from the 359 * real value. 360 * 361 * The values are actually stored as integers representing millibels, 362 * because that's the format the alsa API uses. */ 363 long *db_values; 364 }; 365 366 struct pa_alsa_profile_set { 367 pa_hashmap *mappings; 368 pa_hashmap *profiles; 369 pa_hashmap *decibel_fixes; 370 pa_hashmap *input_paths; 371 pa_hashmap *output_paths; 372 373 bool auto_profiles; 374 bool ignore_dB:1; 375 bool probed:1; 376 }; 377 378 void pa_alsa_mapping_dump(pa_alsa_mapping *m); 379 void pa_alsa_profile_dump(pa_alsa_profile *p); 380 void pa_alsa_decibel_fix_dump(pa_alsa_decibel_fix *db_fix); 381 pa_alsa_mapping *pa_alsa_mapping_get(pa_alsa_profile_set *ps, const char *name); 382 383 pa_alsa_profile_set* pa_alsa_profile_set_new(const char *fname, const pa_channel_map *bonus); 384 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); 385 void pa_alsa_profile_set_free(pa_alsa_profile_set *s); 386 void pa_alsa_profile_set_dump(pa_alsa_profile_set *s); 387 void pa_alsa_profile_set_drop_unsupported(pa_alsa_profile_set *s); 388 389 pa_alsa_fdlist *pa_alsa_fdlist_new(void); 390 void pa_alsa_fdlist_free(pa_alsa_fdlist *fdl); 391 int pa_alsa_fdlist_set_handle(pa_alsa_fdlist *fdl, snd_mixer_t *mixer_handle, snd_hctl_t *hctl_handle, pa_mainloop_api* m); 392 393 /* Alternative for handling alsa mixer events in io-thread. */ 394 395 pa_alsa_mixer_pdata *pa_alsa_mixer_pdata_new(void); 396 void pa_alsa_mixer_pdata_free(pa_alsa_mixer_pdata *pd); 397 int pa_alsa_set_mixer_rtpoll(struct pa_alsa_mixer_pdata *pd, snd_mixer_t *mixer, pa_rtpoll *rtp); 398 399 /* Data structure for inclusion in pa_device_port for alsa 400 * sinks/sources. This contains nothing that needs to be freed 401 * individually */ 402 struct pa_alsa_port_data { 403 pa_alsa_path *path; 404 pa_alsa_setting *setting; 405 bool suspend_when_unavailable; 406 }; 407 408 void pa_alsa_add_ports(void *sink_or_source_new_data, pa_alsa_path_set *ps, pa_card *card); 409 void pa_alsa_path_set_add_ports(pa_alsa_path_set *ps, pa_card_profile *cp, pa_hashmap *ports, pa_hashmap *extra, pa_core *core); 410 411 #endif 412