summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/control/hcontrol.c4
-rw-r--r--src/mixer/mixer.c82
-rw-r--r--src/mixer/mixer_local.h2
3 files changed, 70 insertions, 18 deletions
diff --git a/src/control/hcontrol.c b/src/control/hcontrol.c
index 44938257..b7964d87 100644
--- a/src/control/hcontrol.c
+++ b/src/control/hcontrol.c
@@ -134,8 +134,10 @@ static int snd_hctl_elem_add(snd_hctl_t *hctl, snd_hctl_elem_t *elem)
snd_hctl_elem_t **h;
hctl->alloc += 32;
h = realloc(hctl->pelems, sizeof(*h) * hctl->alloc);
- if (!h)
+ if (!h) {
+ hctl->alloc -= 32;
return -ENOMEM;
+ }
hctl->pelems = h;
}
if (hctl->count == 0) {
diff --git a/src/mixer/mixer.c b/src/mixer/mixer.c
index 5d42d75f..2c67e79b 100644
--- a/src/mixer/mixer.c
+++ b/src/mixer/mixer.c
@@ -221,12 +221,61 @@ int snd_mixer_elem_throw_event(snd_mixer_elem_t *elem,
return 0;
}
+static int _snd_mixer_find_elem(snd_mixer_t *mixer, snd_mixer_elem_t *elem, int *dir)
+{
+ unsigned int l, u;
+ int c = 0;
+ int idx = -1;
+ assert(mixer && elem);
+ assert(mixer->compare);
+ l = 0;
+ u = mixer->count;
+ while (l < u) {
+ idx = (l + u) / 2;
+ c = mixer->compare(elem, mixer->pelems[idx]);
+ if (c < 0)
+ u = idx;
+ else if (c > 0)
+ l = idx + 1;
+ else
+ break;
+ }
+ *dir = c;
+ return idx;
+}
+
int snd_mixer_elem_add(snd_mixer_elem_t *elem, snd_mixer_class_t *class)
{
+ int dir, idx;
snd_mixer_t *mixer = class->mixer;
elem->class = class;
- list_add_tail(&elem->list, &mixer->elems);
+ if (mixer->count == mixer->alloc) {
+ snd_mixer_elem_t **m;
+ mixer->alloc += 32;
+ m = realloc(mixer->pelems, sizeof(*m) * mixer->alloc);
+ if (!m) {
+ mixer->alloc -= 32;
+ return -ENOMEM;
+ }
+ mixer->pelems = m;
+ }
+ if (mixer->count == 0) {
+ list_add_tail(&elem->list, &mixer->elems);
+ mixer->pelems[0] = elem;
+ } else {
+ idx = _snd_mixer_find_elem(mixer, elem, &dir);
+ assert(dir != 0);
+ if (dir > 0) {
+ list_add(&elem->list, &mixer->pelems[idx]->list);
+ } else {
+ list_add_tail(&elem->list, &mixer->pelems[idx]->list);
+ idx++;
+ }
+ memmove(mixer->pelems + idx + 1,
+ mixer->pelems + idx,
+ mixer->count - idx);
+ }
mixer->count++;
return snd_mixer_throw_event(mixer, SND_CTL_EVENT_ADD, elem);
}
@@ -234,11 +283,19 @@ int snd_mixer_elem_add(snd_mixer_elem_t *elem, snd_mixer_class_t *class)
int snd_mixer_elem_remove(snd_mixer_elem_t *elem)
{
snd_mixer_t *mixer = elem->class->mixer;
- int err;
+ int err, idx, dir;
+ unsigned int m;
+ assert(elem);
+ idx = _snd_mixer_find_elem(mixer, elem, &dir);
+ if (dir != 0)
+ return -EINVAL;
err = snd_mixer_elem_throw_event(elem, SND_CTL_EVENT_REMOVE);
list_del(&elem->list);
free(elem);
mixer->count--;
+ m = mixer->count - idx;
+ if (m > 0)
+ memmove(mixer->pelems + idx, mixer->pelems + idx + 1, m);
return err;
}
@@ -323,6 +380,10 @@ int snd_mixer_close(snd_mixer_t *mixer)
snd_mixer_class_unregister(c);
}
assert(list_empty(&mixer->elems));
+ if (mixer->pelems) {
+ free(mixer->pelems);
+ mixer->pelems = NULL;
+ }
while (!list_empty(&mixer->slaves)) {
int err;
snd_mixer_slave_t *s;
@@ -356,25 +417,12 @@ static int snd_mixer_sort(snd_mixer_t *mixer)
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);
+ qsort(mixer->pelems, 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);
+ list_add_tail(&mixer->pelems[k]->list, &mixer->elems);
return 0;
}
diff --git a/src/mixer/mixer_local.h b/src/mixer/mixer_local.h
index 0333ee3e..0e8dd9fe 100644
--- a/src/mixer/mixer_local.h
+++ b/src/mixer/mixer_local.h
@@ -71,7 +71,9 @@ struct _snd_mixer {
struct list_head slaves; /* list of all slaves */
struct list_head classes; /* list of all elem classes */
struct list_head elems; /* list of all elems */
+ snd_mixer_elem_t **pelems; /* array of all elems */
unsigned int count;
+ unsigned int alloc;
unsigned int events;
snd_mixer_callback_t callback;
void *callback_private;