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