OUTPUT_DIRECTORY = doxygen
GENERATE_LATEX = NO
GENERATE_MAN = NO
-INPUT = ../include/asoundlib.h ../src
+INPUT = ../../alsa-driver/include/asound.h ../include/asoundlib.h ../src
FILE_PATTERNS = *.c *.h
#EXAMPLE_PATH = example_test.cpp
QUIET = NO
-EXTRACT_ALL = NO
+EXTRACT_ALL = YES
EXTRACT_STATIC = YES
-#PREDEFINED = DOC_PUBLIC
+RECURSIVE = YES
+PREDEFINED = DOC_PUBLIC
int snd_hctl_nonblock(snd_hctl_t *hctl, int nonblock);
int snd_hctl_async(snd_hctl_t *hctl, int sig, pid_t pid);
int snd_hctl_poll_descriptor(snd_hctl_t *hctl);
-unsigned int snd_hctl_get_count(snd_hctl_t *ctl);
-void snd_hctl_set_compare(snd_hctl_t *hctl, snd_hctl_compare_t hsort);
+unsigned int snd_hctl_get_count(snd_hctl_t *hctl);
+int snd_hctl_set_compare(snd_hctl_t *hctl, snd_hctl_compare_t hsort);
snd_hctl_elem_t *snd_hctl_first_elem(snd_hctl_t *hctl);
snd_hctl_elem_t *snd_hctl_last_elem(snd_hctl_t *hctl);
-snd_hctl_elem_t *snd_hctl_find_elem(snd_hctl_t *ctl, const snd_ctl_elem_id_t *id);
-void snd_hctl_set_callback(snd_hctl_t *ctl, snd_hctl_callback_t callback);
-void snd_hctl_set_callback_private(snd_hctl_t *ctl, void *data);
-void *snd_hctl_get_callback_private(snd_hctl_t *ctl);
-int snd_hctl_load(snd_hctl_t *ctl);
-int snd_hctl_free(snd_hctl_t *ctl);
-int snd_hctl_handle_event(snd_hctl_t *ctl, snd_ctl_event_t *event);
-int snd_hctl_handle_events(snd_hctl_t *ctl);
+snd_hctl_elem_t *snd_hctl_find_elem(snd_hctl_t *hctl, const snd_ctl_elem_id_t *id);
+void snd_hctl_set_callback(snd_hctl_t *hctl, snd_hctl_callback_t callback);
+void snd_hctl_set_callback_private(snd_hctl_t *hctl, void *data);
+void *snd_hctl_get_callback_private(snd_hctl_t *hctl);
+int snd_hctl_load(snd_hctl_t *hctl);
+int snd_hctl_free(snd_hctl_t *hctl);
+int snd_hctl_handle_event(snd_hctl_t *hctl, snd_ctl_event_t *event);
+int snd_hctl_handle_events(snd_hctl_t *hctl);
const char *snd_hctl_name(snd_hctl_t *hctl);
snd_ctl_type_t snd_hctl_type(snd_hctl_t *hctl);
int snd_hctl_elem_read(snd_hctl_elem_t *elem, snd_ctl_elem_value_t * value);
int snd_hctl_elem_write(snd_hctl_elem_t *elem, snd_ctl_elem_value_t * value);
+snd_hctl_t *snd_hctl_elem_get_handle(snd_hctl_elem_t *elem);
+
#ifdef __cplusplus
}
#endif
int snd_mixer_detach(snd_mixer_t *mixer, const char *name);
int snd_mixer_poll_descriptor(snd_mixer_t *mixer, const char *name);
int snd_mixer_load(snd_mixer_t *mixer);
-void snd_mixer_set_compare(snd_hctl_t *hctl, snd_mixer_compare_t hsort);
+int snd_mixer_set_compare(snd_mixer_t *mixer, snd_mixer_compare_t msort);
snd_mixer_elem_t *snd_mixer_elem_next(snd_mixer_elem_t *elem);
snd_mixer_elem_t *snd_mixer_elem_prev(snd_mixer_elem_t *helem);
unsigned int k;
int compar(const void *a, const void *b) {
return hctl->compare(*(const snd_hctl_elem_t **) a,
- *(const snd_hctl_elem_t **) b);
+ *(const snd_hctl_elem_t **) b);
}
assert(hctl);
assert(hctl->compare);
list_add_tail(&hctl->pelems[k]->list, &hctl->elems);
}
-void snd_hctl_set_compare(snd_hctl_t *hctl, snd_hctl_compare_t hsort)
+int snd_hctl_set_compare(snd_hctl_t *hctl, snd_hctl_compare_t hsort)
{
assert(hctl);
hctl->compare = hsort == NULL ? snd_hctl_compare_default : hsort;
snd_hctl_sort(hctl);
+ return 0;
}
#define NOT_FOUND 1000000000
return snd_ctl_elem_write(elem->hctl->ctl, value);
}
+snd_hctl_t *snd_hctl_elem_get_handle(snd_hctl_elem_t *elem)
+{
+ assert(elem);
+ return elem->hctl;
+}
} snd_mixer_elem_bag_t;
+
+static int snd_mixer_compare_default(const snd_mixer_elem_t *c1,
+ const snd_mixer_elem_t *c2);
+
+
int snd_mixer_open(snd_mixer_t **mixerp)
{
snd_mixer_t *mixer;
INIT_LIST_HEAD(&mixer->slaves);
INIT_LIST_HEAD(&mixer->classes);
INIT_LIST_HEAD(&mixer->elems);
+ mixer->compare = snd_mixer_compare_default;
*mixerp = mixer;
return 0;
}
{
snd_mixer_t *mixer = class->mixer;
elem->class = class;
+
list_add_tail(&elem->list, &mixer->elems);
mixer->count++;
return snd_mixer_throw_event(mixer, SND_CTL_EVENT_ADD, elem);
return res;
}
+static int snd_mixer_compare_default(const snd_mixer_elem_t *c1,
+ const snd_mixer_elem_t *c2)
+{
+ int d = c1->compare_weight - c2->compare_weight;
+ if (d)
+ return d;
+ assert(c1->class && c1->class->compare);
+ assert(c2->class && c2->class->compare);
+ assert(c1->class == c2->class);
+ return c1->class->compare(c1, c2);
+}
+
+static int snd_mixer_sort(snd_mixer_t *mixer)
+{
+ unsigned int k;
+ int compar(const void *a, const void *b) {
+ return mixer->compare(*(const snd_mixer_elem_t **) a,
+ *(const snd_mixer_elem_t **) b);
+ }
+ snd_mixer_elem_t **ptr;
+ struct list_head *pos, *next;
+
+ assert(mixer);
+ assert(mixer->compare);
+ ptr = malloc(sizeof(snd_mixer_elem_t) * mixer->count);
+ if (ptr == NULL)
+ return -ENOMEM;
+ k = 0;
+ list_for_each(pos, next, &mixer->elems) {
+ snd_mixer_elem_t *e;
+ e = list_entry(pos, snd_mixer_elem_t, list);
+ ptr[k++] = e;
+ }
+ INIT_LIST_HEAD(&mixer->elems);
+ qsort(ptr, mixer->count, sizeof(snd_mixer_elem_t), compar);
+ for (k = 0; k < mixer->count; k++)
+ list_add_tail(&ptr[k]->list, &mixer->elems);
+ free(ptr);
+ return 0;
+}
+
+int snd_mixer_set_compare(snd_mixer_t *mixer, snd_mixer_compare_t msort)
+{
+ snd_mixer_compare_t msort_old;
+ int err;
+
+ assert(mixer);
+ msort_old = mixer->compare;
+ mixer->compare = msort == NULL ? snd_mixer_compare_default : msort;
+ if ((err = snd_mixer_sort(mixer)) < 0) {
+ mixer->compare = msort_old;
+ return err;
+ }
+ return 0;
+}
+
int snd_mixer_poll_descriptor(snd_mixer_t *mixer, const char *name)
{
struct list_head *pos, *next;
#define bag_iterator_entry(i) (list_entry((i), bag1_t, list)->ptr)
#define bag_for_each(pos, next, bag) list_for_each(pos, next, bag)
+#define MIXER_COMPARE_WEIGHT_SIMPLE_BASE 0
+#define MIXER_COMPARE_WEIGHT_NEXT_BASE 10000000
+#define MIXER_COMPARE_WEIGHT_NOT_FOUND 1000000000
+
struct _snd_mixer_class {
struct list_head list;
snd_mixer_t *mixer;
snd_hctl_elem_t *helem, snd_mixer_elem_t *melem);
void *private_data;
void (*private_free)(snd_mixer_class_t *class);
+ snd_mixer_compare_t compare;
};
struct _snd_mixer_elem {
snd_mixer_elem_callback_t callback;
void *callback_private;
bag_t helems;
+ int compare_weight; /* compare weight (reversed) */
};
struct _snd_mixer {
unsigned int events;
snd_mixer_callback_t callback;
void *callback_private;
+ snd_mixer_compare_t compare;
};
struct _snd_mixer_selem_id {
return lname;
}
-#if 0
-static const char *get_long_name(const char *sname)
-{
- struct mixer_name_table *p;
- for (p = name_table; p->longname; p++) {
- if (!strcmp(sname, p->shortname))
- return p->longname;
- }
- return sname;
-}
-
-static const char *simple_elems[] = {
- "Master Mono",
- "Master Digital",
- "Master",
- "Tone Control - Bass",
- "Tone Control - Treble",
- "Synth Tone Control - Bass",
- "Synth Tone Control - Treble",
- "PCM",
- "Surround",
- "Synth",
- "FM",
- "Wave",
- "Music",
- "DSP",
- "Line",
- "CD",
- "Mic",
- "Video",
- "Phone",
- "PC Speaker",
- "Aux",
- "Mono Output",
- "Mono",
- "Playback",
- "Capture Boost",
- "Capture",
- NULL
-};
-#endif
+static int get_compare_weight(const char *name, int index)
+{
+ static char *names[] = {
+ "Master Mono",
+ "Master Digital",
+ "Master",
+ "Tone Control - Bass",
+ "Tone Control - Treble",
+ "Synth Tone Control - Bass",
+ "Synth Tone Control - Treble",
+ "PCM",
+ "Surround",
+ "Synth",
+ "FM",
+ "Wave",
+ "Music",
+ "DSP",
+ "Line",
+ "CD",
+ "Mic",
+ "Video",
+ "Phone",
+ "PC Speaker",
+ "Aux",
+ "Mono Output",
+ "Mono",
+ "Playback",
+ "Capture Boost",
+ "Capture",
+ NULL
+ };
+ int res;
+
+ for (res = 0; names[res] != NULL; res++)
+ if (!strcmp(name, names[res]))
+ return MIXER_COMPARE_WEIGHT_SIMPLE_BASE +
+ (res * 1000) + index;
+ return MIXER_COMPARE_WEIGHT_NOT_FOUND;
+}
static int selem_info(snd_mixer_elem_t *elem,
snd_mixer_selem_info_t *info)
const char *suffix;
selem_ctl_type_t type;
} suffixes[] = {
- { " Playback Switch", CTL_PLAYBACK_SWITCH},
+ {" Playback Switch", CTL_PLAYBACK_SWITCH},
{" Playback Route", CTL_PLAYBACK_ROUTE},
{" Playback Volume", CTL_PLAYBACK_VOLUME},
{" Capture Switch", CTL_CAPTURE_SWITCH},
err = snd_mixer_elem_attach(melem, helem);
if (err < 0)
return err;
+ melem->compare_weight = get_compare_weight(simple->id.name, simple->id.index);
err = simple_update(melem);
assert(err >= 0);
if (new)
err = snd_hctl_elem_info(helem, info);
assert(err >= 0);
n = snd_ctl_elem_info_get_item_name(info);
-#if 0
- /* FIXME: es18xx has both Mix and Master */
- if (strcmp(n, "Mix") == 0)
- n = "Master";
- else if (strcmp(n, "Mono Mix") == 0)
- n = "Master Mono";
-#endif
+ if (!strcmp(n, "Mix") || !strcmp(n, "Mono Mix")) {
+ snd_hctl_t *hctl;
+ hctl = snd_hctl_elem_get_handle(helem);
+ if (hctl != NULL) {
+ snd_ctl_elem_id_t *eid;
+ snd_ctl_elem_id_alloca(&eid);
+ snd_ctl_elem_id_set_interface(eid, SND_CTL_ELEM_IFACE_MIXER);
+ if (!strcmp(n, "Mix")) {
+ snd_ctl_elem_id_set_name(eid, "Mix");
+ if (snd_hctl_find_elem(hctl, eid) == NULL)
+ n = "Master";
+ } else if (!strcmp(n, "Mono Mix")) {
+ snd_ctl_elem_id_set_name(eid, "Mono Mix");
+ if (snd_hctl_find_elem(hctl, eid) == NULL)
+ n = "Master Mono";
+ }
+ }
+ }
err = simple_add1(class, n, helem, CTL_CAPTURE_SOURCE, k);
if (err < 0)
return err;
return 0;
}
+static int simple_compare(const snd_mixer_elem_t *c1, const snd_mixer_elem_t *c2)
+{
+ selem_t *s1 = c1->private_data;
+ selem_t *s2 = c2->private_data;
+ return strcmp(s1->id.name, s2->id.name);
+}
+
int snd_mixer_selem_register(snd_mixer_t *mixer, snd_mixer_class_t **classp)
{
snd_mixer_class_t *class = calloc(1, sizeof(*class));
if (!class)
return -ENOMEM;
class->event = simple_event;
+ class->compare = simple_compare;
err = snd_mixer_class_register(class, mixer);
if (err < 0) {
free(class);