aboutsummaryrefslogtreecommitdiff
path: root/mixer.c
diff options
context:
space:
mode:
authorTaylor Holberton <taylorcholberton@gmail.com>2016-10-01 13:08:08 -0400
committerTaylor Holberton <taylorcholberton@gmail.com>2016-10-01 13:08:08 -0400
commit22ab7da256ceea13963f9383e065d2ef8bfb8f5d (patch)
tree369dc4e0430e4c602a731568511f66b5f82ae4d9 /mixer.c
parent626a822af99650a68e668fe8af3f06850866106f (diff)
put source files into src dir
Diffstat (limited to 'mixer.c')
-rw-r--r--mixer.c565
1 files changed, 0 insertions, 565 deletions
diff --git a/mixer.c b/mixer.c
deleted file mode 100644
index ac294ca..0000000
--- a/mixer.c
+++ /dev/null
@@ -1,565 +0,0 @@
-/* mixer.c
-**
-** Copyright 2011, The Android Open Source Project
-**
-** Redistribution and use in source and binary forms, with or without
-** modification, are permitted provided that the following conditions are met:
-** * Redistributions of source code must retain the above copyright
-** notice, this list of conditions and the following disclaimer.
-** * Redistributions in binary form must reproduce the above copyright
-** notice, this list of conditions and the following disclaimer in the
-** documentation and/or other materials provided with the distribution.
-** * Neither the name of The Android Open Source Project nor the names of
-** its contributors may be used to endorse or promote products derived
-** from this software without specific prior written permission.
-**
-** THIS SOFTWARE IS PROVIDED BY The Android Open Source Project ``AS IS'' AND
-** ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-** IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-** ARE DISCLAIMED. IN NO EVENT SHALL The Android Open Source Project BE LIABLE
-** FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
-** DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
-** SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
-** CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
-** LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
-** OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
-** DAMAGE.
-*/
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <stdint.h>
-#include <string.h>
-#include <unistd.h>
-#include <fcntl.h>
-#include <errno.h>
-#include <ctype.h>
-#include <limits.h>
-#include <time.h>
-
-#include <sys/ioctl.h>
-
-#include <linux/ioctl.h>
-#define __force
-#define __bitwise
-#define __user
-#include <sound/asound.h>
-
-#include <tinyalsa/asoundlib.h>
-
-struct mixer_ctl {
- struct mixer *mixer;
- struct snd_ctl_elem_info info;
- char **ename;
-};
-
-struct mixer {
- int fd;
- struct snd_ctl_card_info card_info;
- struct mixer_ctl *ctl;
- unsigned int count;
-};
-
-void mixer_close(struct mixer *mixer)
-{
- unsigned int n,m;
-
- if (!mixer)
- return;
-
- if (mixer->fd >= 0)
- close(mixer->fd);
-
- if (mixer->ctl) {
- for (n = 0; n < mixer->count; n++) {
- if (mixer->ctl[n].ename) {
- unsigned int max = mixer->ctl[n].info.value.enumerated.items;
- for (m = 0; m < max; m++)
- free(mixer->ctl[n].ename[m]);
- free(mixer->ctl[n].ename);
- }
- }
- free(mixer->ctl);
- }
-
- free(mixer);
-
- /* TODO: verify frees */
-}
-
-struct mixer *mixer_open(unsigned int card)
-{
- struct snd_ctl_elem_list elist;
- struct snd_ctl_elem_info tmp;
- struct snd_ctl_elem_id *eid = NULL;
- struct mixer *mixer = NULL;
- unsigned int n, m;
- int fd;
- char fn[256];
-
- snprintf(fn, sizeof(fn), "/dev/snd/controlC%u", card);
- fd = open(fn, O_RDWR);
- if (fd < 0)
- return 0;
-
- memset(&elist, 0, sizeof(elist));
- if (ioctl(fd, SNDRV_CTL_IOCTL_ELEM_LIST, &elist) < 0)
- goto fail;
-
- mixer = calloc(1, sizeof(*mixer));
- if (!mixer)
- goto fail;
-
- mixer->ctl = calloc(elist.count, sizeof(struct mixer_ctl));
- if (!mixer->ctl)
- goto fail;
-
- if (ioctl(fd, SNDRV_CTL_IOCTL_CARD_INFO, &mixer->card_info) < 0)
- goto fail;
-
- eid = calloc(elist.count, sizeof(struct snd_ctl_elem_id));
- if (!eid)
- goto fail;
-
- mixer->count = elist.count;
- mixer->fd = fd;
- elist.space = mixer->count;
- elist.pids = eid;
- if (ioctl(fd, SNDRV_CTL_IOCTL_ELEM_LIST, &elist) < 0)
- goto fail;
-
- for (n = 0; n < mixer->count; n++) {
- struct snd_ctl_elem_info *ei = &mixer->ctl[n].info;
- ei->id.numid = eid[n].numid;
- if (ioctl(fd, SNDRV_CTL_IOCTL_ELEM_INFO, ei) < 0)
- goto fail;
- mixer->ctl[n].mixer = mixer;
- if (ei->type == SNDRV_CTL_ELEM_TYPE_ENUMERATED) {
- char **enames = calloc(ei->value.enumerated.items, sizeof(char*));
- if (!enames)
- goto fail;
- mixer->ctl[n].ename = enames;
- for (m = 0; m < ei->value.enumerated.items; m++) {
- memset(&tmp, 0, sizeof(tmp));
- tmp.id.numid = ei->id.numid;
- tmp.value.enumerated.item = m;
- if (ioctl(fd, SNDRV_CTL_IOCTL_ELEM_INFO, &tmp) < 0)
- goto fail;
- enames[m] = strdup(tmp.value.enumerated.name);
- if (!enames[m])
- goto fail;
- }
- }
- }
-
- free(eid);
- return mixer;
-
-fail:
- /* TODO: verify frees in failure case */
- if (eid)
- free(eid);
- if (mixer)
- mixer_close(mixer);
- else if (fd >= 0)
- close(fd);
- return 0;
-}
-
-const char *mixer_get_name(struct mixer *mixer)
-{
- return (const char *)mixer->card_info.name;
-}
-
-unsigned int mixer_get_num_ctls(struct mixer *mixer)
-{
- if (!mixer)
- return 0;
-
- return mixer->count;
-}
-
-struct mixer_ctl *mixer_get_ctl(struct mixer *mixer, unsigned int id)
-{
- if (mixer && (id < mixer->count))
- return mixer->ctl + id;
-
- return NULL;
-}
-
-struct mixer_ctl *mixer_get_ctl_by_name(struct mixer *mixer, const char *name)
-{
- return mixer_get_ctl_by_name_and_index(mixer, name, 0);
-}
-
-struct mixer_ctl *mixer_get_ctl_by_name_and_index(struct mixer *mixer,
- const char *name,
- unsigned int index)
-{
- unsigned int n;
- struct mixer_ctl *ctl;
-
- if (!mixer)
- return NULL;
-
- ctl = mixer->ctl;
-
- for (n = 0; n < mixer->count; n++)
- if (!strcmp(name, (char*) ctl[n].info.id.name))
- if (index-- == 0)
- return mixer->ctl + n;
-
- return NULL;
-}
-
-void mixer_ctl_update(struct mixer_ctl *ctl)
-{
- ioctl(ctl->mixer->fd, SNDRV_CTL_IOCTL_ELEM_INFO, ctl->info);
-}
-
-unsigned int mixer_ctl_get_id(struct mixer_ctl *ctl)
-{
- if (!ctl)
- return UINT_MAX;
-
- /* numid values start at 1, return a 0-base value that
- * can be passed to mixer_get_ctl()
- */
- return ctl->info.id.numid - 1;
-}
-
-const char *mixer_ctl_get_name(struct mixer_ctl *ctl)
-{
- if (!ctl)
- return NULL;
-
- return (const char *)ctl->info.id.name;
-}
-
-enum mixer_ctl_type mixer_ctl_get_type(struct mixer_ctl *ctl)
-{
- if (!ctl)
- return MIXER_CTL_TYPE_UNKNOWN;
-
- switch (ctl->info.type) {
- case SNDRV_CTL_ELEM_TYPE_BOOLEAN: return MIXER_CTL_TYPE_BOOL;
- case SNDRV_CTL_ELEM_TYPE_INTEGER: return MIXER_CTL_TYPE_INT;
- case SNDRV_CTL_ELEM_TYPE_ENUMERATED: return MIXER_CTL_TYPE_ENUM;
- case SNDRV_CTL_ELEM_TYPE_BYTES: return MIXER_CTL_TYPE_BYTE;
- case SNDRV_CTL_ELEM_TYPE_IEC958: return MIXER_CTL_TYPE_IEC958;
- case SNDRV_CTL_ELEM_TYPE_INTEGER64: return MIXER_CTL_TYPE_INT64;
- default: return MIXER_CTL_TYPE_UNKNOWN;
- };
-}
-
-const char *mixer_ctl_get_type_string(struct mixer_ctl *ctl)
-{
- if (!ctl)
- return "";
-
- switch (ctl->info.type) {
- case SNDRV_CTL_ELEM_TYPE_BOOLEAN: return "BOOL";
- case SNDRV_CTL_ELEM_TYPE_INTEGER: return "INT";
- case SNDRV_CTL_ELEM_TYPE_ENUMERATED: return "ENUM";
- case SNDRV_CTL_ELEM_TYPE_BYTES: return "BYTE";
- case SNDRV_CTL_ELEM_TYPE_IEC958: return "IEC958";
- case SNDRV_CTL_ELEM_TYPE_INTEGER64: return "INT64";
- default: return "Unknown";
- };
-}
-
-unsigned int mixer_ctl_get_num_values(struct mixer_ctl *ctl)
-{
- if (!ctl)
- return 0;
-
- return ctl->info.count;
-}
-
-static int percent_to_int(struct snd_ctl_elem_info *ei, int percent)
-{
- if ((percent > 100) || (percent < 0)) {
- return -EINVAL;
- }
-
- int range = (ei->value.integer.max - ei->value.integer.min);
-
- return ei->value.integer.min + (range * percent) / 100;
-}
-
-static int int_to_percent(struct snd_ctl_elem_info *ei, int value)
-{
- int range = (ei->value.integer.max - ei->value.integer.min);
-
- if (range == 0)
- return 0;
-
- return ((value - ei->value.integer.min) / range) * 100;
-}
-
-int mixer_ctl_get_percent(struct mixer_ctl *ctl, unsigned int id)
-{
- if (!ctl || (ctl->info.type != SNDRV_CTL_ELEM_TYPE_INTEGER))
- return -EINVAL;
-
- return int_to_percent(&ctl->info, mixer_ctl_get_value(ctl, id));
-}
-
-int mixer_ctl_set_percent(struct mixer_ctl *ctl, unsigned int id, int percent)
-{
- if (!ctl || (ctl->info.type != SNDRV_CTL_ELEM_TYPE_INTEGER))
- return -EINVAL;
-
- return mixer_ctl_set_value(ctl, id, percent_to_int(&ctl->info, percent));
-}
-
-int mixer_ctl_get_value(struct mixer_ctl *ctl, unsigned int id)
-{
- struct snd_ctl_elem_value ev;
- int ret;
-
- if (!ctl || (id >= ctl->info.count))
- return -EINVAL;
-
- memset(&ev, 0, sizeof(ev));
- ev.id.numid = ctl->info.id.numid;
- ret = ioctl(ctl->mixer->fd, SNDRV_CTL_IOCTL_ELEM_READ, &ev);
- if (ret < 0)
- return ret;
-
- switch (ctl->info.type) {
- case SNDRV_CTL_ELEM_TYPE_BOOLEAN:
- return !!ev.value.integer.value[id];
-
- case SNDRV_CTL_ELEM_TYPE_INTEGER:
- return ev.value.integer.value[id];
-
- case SNDRV_CTL_ELEM_TYPE_ENUMERATED:
- return ev.value.enumerated.item[id];
-
- case SNDRV_CTL_ELEM_TYPE_BYTES:
- return ev.value.bytes.data[id];
-
- default:
- return -EINVAL;
- }
-
- return 0;
-}
-
-int mixer_ctl_get_array(struct mixer_ctl *ctl, void *array, size_t count)
-{
- struct snd_ctl_elem_value ev;
- int ret = 0;
- size_t size;
- void *source;
-
- if (!ctl || (count > ctl->info.count) || !count || !array)
- return -EINVAL;
-
- memset(&ev, 0, sizeof(ev));
- ev.id.numid = ctl->info.id.numid;
-
- switch (ctl->info.type) {
- case SNDRV_CTL_ELEM_TYPE_BOOLEAN:
- case SNDRV_CTL_ELEM_TYPE_INTEGER:
- ret = ioctl(ctl->mixer->fd, SNDRV_CTL_IOCTL_ELEM_READ, &ev);
- if (ret < 0)
- return ret;
- size = sizeof(ev.value.integer.value[0]);
- source = ev.value.integer.value;
- break;
-
- case SNDRV_CTL_ELEM_TYPE_BYTES:
- /* check if this is new bytes TLV */
- if (ctl->info.access & SNDRV_CTL_ELEM_ACCESS_TLV_READWRITE) {
- struct snd_ctl_tlv *tlv;
- int ret;
-
- if (count > SIZE_MAX - sizeof(*tlv))
- return -EINVAL;
- tlv = calloc(1, sizeof(*tlv) + count);
- if (!tlv)
- return -ENOMEM;
- tlv->numid = ctl->info.id.numid;
- tlv->length = count;
- ret = ioctl(ctl->mixer->fd, SNDRV_CTL_IOCTL_TLV_READ, tlv);
-
- source = tlv->tlv;
- memcpy(array, source, count);
-
- free(tlv);
-
- return ret;
- } else {
- ret = ioctl(ctl->mixer->fd, SNDRV_CTL_IOCTL_ELEM_READ, &ev);
- if (ret < 0)
- return ret;
- size = sizeof(ev.value.bytes.data[0]);
- source = ev.value.bytes.data;
- break;
- }
-
- default:
- return -EINVAL;
- }
-
- memcpy(array, source, size * count);
-
- return 0;
-}
-
-int mixer_ctl_set_value(struct mixer_ctl *ctl, unsigned int id, int value)
-{
- struct snd_ctl_elem_value ev;
- int ret;
-
- if (!ctl || (id >= ctl->info.count))
- return -EINVAL;
-
- memset(&ev, 0, sizeof(ev));
- ev.id.numid = ctl->info.id.numid;
- ret = ioctl(ctl->mixer->fd, SNDRV_CTL_IOCTL_ELEM_READ, &ev);
- if (ret < 0)
- return ret;
-
- switch (ctl->info.type) {
- case SNDRV_CTL_ELEM_TYPE_BOOLEAN:
- ev.value.integer.value[id] = !!value;
- break;
-
- case SNDRV_CTL_ELEM_TYPE_INTEGER:
- if ((value < mixer_ctl_get_range_min(ctl)) ||
- (value > mixer_ctl_get_range_max(ctl))) {
- return -EINVAL;
- }
-
- ev.value.integer.value[id] = value;
- break;
-
- case SNDRV_CTL_ELEM_TYPE_ENUMERATED:
- ev.value.enumerated.item[id] = value;
- break;
-
- case SNDRV_CTL_ELEM_TYPE_BYTES:
- ev.value.bytes.data[id] = value;
- break;
-
- default:
- return -EINVAL;
- }
-
- return ioctl(ctl->mixer->fd, SNDRV_CTL_IOCTL_ELEM_WRITE, &ev);
-}
-
-int mixer_ctl_set_array(struct mixer_ctl *ctl, const void *array, size_t count)
-{
- struct snd_ctl_elem_value ev;
- size_t size;
- void *dest;
-
- if (!ctl || (count > ctl->info.count) || !count || !array)
- return -EINVAL;
-
- memset(&ev, 0, sizeof(ev));
- ev.id.numid = ctl->info.id.numid;
-
- switch (ctl->info.type) {
- case SNDRV_CTL_ELEM_TYPE_BOOLEAN:
- case SNDRV_CTL_ELEM_TYPE_INTEGER:
- size = sizeof(ev.value.integer.value[0]);
- dest = ev.value.integer.value;
- break;
-
- case SNDRV_CTL_ELEM_TYPE_BYTES:
- /* check if this is new bytes TLV */
- if (ctl->info.access & SNDRV_CTL_ELEM_ACCESS_TLV_READWRITE) {
- struct snd_ctl_tlv *tlv;
- int ret = 0;
- if (count > SIZE_MAX - sizeof(*tlv))
- return -EINVAL;
- tlv = calloc(1, sizeof(*tlv) + count);
- if (!tlv)
- return -ENOMEM;
- tlv->numid = ctl->info.id.numid;
- tlv->length = count;
- memcpy(tlv->tlv, array, count);
-
- ret = ioctl(ctl->mixer->fd, SNDRV_CTL_IOCTL_TLV_WRITE, tlv);
- free(tlv);
-
- return ret;
- } else {
- size = sizeof(ev.value.bytes.data[0]);
- dest = ev.value.bytes.data;
- }
- break;
-
- default:
- return -EINVAL;
- }
-
- memcpy(dest, array, size * count);
-
- return ioctl(ctl->mixer->fd, SNDRV_CTL_IOCTL_ELEM_WRITE, &ev);
-}
-
-int mixer_ctl_get_range_min(struct mixer_ctl *ctl)
-{
- if (!ctl || (ctl->info.type != SNDRV_CTL_ELEM_TYPE_INTEGER))
- return -EINVAL;
-
- return ctl->info.value.integer.min;
-}
-
-int mixer_ctl_get_range_max(struct mixer_ctl *ctl)
-{
- if (!ctl || (ctl->info.type != SNDRV_CTL_ELEM_TYPE_INTEGER))
- return -EINVAL;
-
- return ctl->info.value.integer.max;
-}
-
-unsigned int mixer_ctl_get_num_enums(struct mixer_ctl *ctl)
-{
- if (!ctl)
- return 0;
-
- return ctl->info.value.enumerated.items;
-}
-
-const char *mixer_ctl_get_enum_string(struct mixer_ctl *ctl,
- unsigned int enum_id)
-{
- if (!ctl || (ctl->info.type != SNDRV_CTL_ELEM_TYPE_ENUMERATED) ||
- (enum_id >= ctl->info.value.enumerated.items))
- return NULL;
-
- return (const char *)ctl->ename[enum_id];
-}
-
-int mixer_ctl_set_enum_by_string(struct mixer_ctl *ctl, const char *string)
-{
- unsigned int i, num_enums;
- struct snd_ctl_elem_value ev;
- int ret;
-
- if (!ctl || (ctl->info.type != SNDRV_CTL_ELEM_TYPE_ENUMERATED))
- return -EINVAL;
-
- num_enums = ctl->info.value.enumerated.items;
- for (i = 0; i < num_enums; i++) {
- if (!strcmp(string, ctl->ename[i])) {
- memset(&ev, 0, sizeof(ev));
- ev.value.enumerated.item[0] = i;
- ev.id.numid = ctl->info.id.numid;
- ret = ioctl(ctl->mixer->fd, SNDRV_CTL_IOCTL_ELEM_WRITE, &ev);
- if (ret < 0)
- return ret;
- return 0;
- }
- }
-
- return -EINVAL;
-}
-