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