diff options
Diffstat (limited to 'lib/libsalsa/main.c')
-rw-r--r-- | lib/libsalsa/main.c | 498 |
1 files changed, 498 insertions, 0 deletions
diff --git a/lib/libsalsa/main.c b/lib/libsalsa/main.c new file mode 100644 index 0000000..34c8c22 --- /dev/null +++ b/lib/libsalsa/main.c @@ -0,0 +1,498 @@ +/* + * Copyright (c) 2004 by Hannu Savolainen < hannu@opensound.com> + * + * Parts of the code is derived from the alsa-lib package that is + * copyrighted by Jaroslav Kysela and the other ALSA team members. + * + * This library is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 2.1 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ +#include "local.h" + +int mixer_fd = -1; +int alib_initialized = 0; + +oss_sysinfo sysinfo = { 0 }; +struct _snd_ctl +{ + oss_card_info info; + oss_audioinfo ainfo; +}; + +int alib_verbose = 0; + +int +alib_init (void) +{ + char *p; + char *devmixer; + + if ((devmixer=getenv("OSS_MIXERDEV"))==NULL) + devmixer = "/dev/mixer"; + + if ((p = getenv ("ALIB_DEBUG")) != NULL) + alib_verbose = atoi (p); + + if (mixer_fd == -1) + { + if ((mixer_fd = open (devmixer, O_RDONLY, 0)) == -1) + return -errno; + } + + if (ioctl (mixer_fd, SNDCTL_SYSINFO, &sysinfo) == -1) + { + perror ("SNDCTL_SYSINFO"); + return -errno; + } + + return 0; +} + +char alib_appname[64] = "salsa"; + +int +alib_appcheck (void) +{ + /* + * Some programs are known to support OSS at the same time with ALSA. + * Prevent them from using this library accidently. + */ + + static int done = 0; + + if (done) + return 1; + + done = 1; + + typedef struct + { + char *name, *msg, *action; + } prog_t; + + static const prog_t banned_programs[] = { + {"artsd", "Please use 'artsd -a oss' instead.", NULL}, + {"kcontrol", NULL, NULL}, + {"kmid", NULL, NULL}, + {"krec", NULL, NULL}, + {"kplay", NULL, NULL}, + {"kamix", "Please use ossxmix instead", NULL}, + {"qamix", "Please use ossxmix instead", NULL}, + NULL + }; + + static const char *whitelist[] = { + "esd", + "kmix", + "gnome-volume-control", + "artsd", + "xmms", + "alsaplayer", + "aplay", + "alsamixer", + "vkeybd", + NULL + }; + + FILE *f; + char tmp[64], *p, *cmd = tmp; + int i; + static int warned = 0; + + if ((f = fopen ("/proc/self/cmdline", "r")) == NULL) + return 1; + + if (fgets (tmp, sizeof (tmp) - 1, f) == NULL) + { + fclose (f); + return 1; + } + + fclose (f); + + p = cmd; + + while (*p && (*p != ' ' && *p != '\n')) + p++; + *p = 0; + + p = cmd = tmp; + while (*p) + { + if (*p == '/') + cmd = p + 1; + p++; + } + + strcpy (alib_appname, cmd); + + for (i = 0; i < strlen (alib_appname); i++) + if (alib_appname[i] < 'a' || alib_appname[i] > 'z') + if (alib_appname[i] < 'A' || alib_appname[i] > 'Z') + if (alib_appname[i] < '0' || alib_appname[i] > '9') + alib_appname[i] = '_'; + + for (i = 0; banned_programs[i].name != NULL; i++) + if (strcmp (banned_programs[i].name, cmd) == 0) + { + if (alib_verbose != 0) + { + return 1; + } + fprintf (stderr, + "\n\n************** WARNING ***********************\n"); + fprintf (stderr, "This program (%s) should not use ALSA emulation\n", + cmd); + if (banned_programs[i].msg != NULL) + fprintf (stderr, "%s\n", banned_programs[i].msg); + fprintf (stderr, + "**************************************************\n\n"); + + if (banned_programs[i].action != NULL) + { + if (fork () == 0) + { + exit (system (banned_programs[i].action)); + } + while (wait () != -1); + exit (1); + } + return 0; + } + + if (alib_verbose == 0) + { + int ok = 0; + + for (i = 0; !ok && whitelist[i] != NULL; i++) + if (strcmp (cmd, whitelist[i]) == 0) + ok = 1; + + + if (!ok) + return 0; + } + + if (!warned) + { + fprintf (stderr, + "\n\n******************** WARNING *******************************\n"); + fprintf (stderr, + "Warning! %s uses ALSA emulation instead of the native OSS API\n", + cmd); + fprintf (stderr, + "****************************************************************\n\n"); + } + warned = 1; + return 1; +} + +typedef struct _snd_ctl_card_info +{ + oss_card_info *info; +} snd_ctl_card_info_t; + +/** + * \brief Try to determine the next card. + * \param rcard pointer to card number + * \result zero if success, otherwise a negative error code + * + * Tries to determine the next card from given card number. + * If card number is -1, then the first available card is + * returned. If the result card number is -1, no more cards + * are available. + */ +int +snd_card_next (int *rcard) +{ + ALIB_INIT (); + if (!alib_appcheck ()) + return -ENODEV; + + if (*rcard == -1) + *rcard = 0; + else + *rcard = *rcard + 1; + + if (*rcard >= sysinfo.numcards) + { + *rcard = -1; + return 0; + } + + return 0; +} + +/** + * \brief Convert card string to an integer value. + * \param string String containing card identifier + * \return zero if success, otherwise a negative error code + * + * The accepted format is an integer value in ASCII representation + * or the card identifier (the id parameter for sound-card drivers). + */ +int +snd_card_get_index (const char *string) +{ + dbg_printf ("snd_card_get_index(%s)\n", string); + return -EINVAL; +} + +/** + * \brief Get card name from a CTL card info + * \param obj CTL card info + * \return card name + */ +const char * +snd_ctl_card_info_get_name (const snd_ctl_card_info_t * obj) +{ + return obj->info->longname; +} + +/** + * \brief get size of #snd_ctl_card_info_t + * \return size in bytes + */ +size_t +snd_ctl_card_info_sizeof () +{ + return sizeof (snd_ctl_card_info_t); +} + +/** + * \brief Opens a CTL + * \param ctlp Returned CTL handle + * \param name ASCII identifier of the CTL handle + * \param mode Open mode (see #SND_CTL_NONBLOCK, #SND_CTL_ASYNC) + * \return 0 on success otherwise a negative error code + */ +int +snd_ctl_open (snd_ctl_t ** ctlp, const char *name, int mode) +{ + int num; + snd_ctl_t *ctl; + + ALIB_INIT (); + if (!alib_appcheck ()) + return -ENODEV; + + *ctlp = NULL; + + if (strcmp (name, "default") == 0) + num = 0; + else + { + if (name[0] != 'h' && name[1] != 'w' && name[2] != ':') + return -ENOENT; + + if (sscanf (name + 3, "%d", &num) != 1) + return -ENOENT; + } + + if (num < 0 || num >= sysinfo.numcards) + return -ENXIO; + + + if ((ctl = malloc (sizeof (*ctl))) == NULL) + return -ENOMEM; + + memset (ctl, 0, sizeof (*ctl)); + ctl->info.card = num; + if (ioctl (mixer_fd, SNDCTL_CARDINFO, &ctl->info) == -1) + { + perror ("SNDCTL_CARDINFO"); + fprintf (stderr, "Mixer fd was %d\n", mixer_fd); + return -errno; + } + + *ctlp = ctl; + return 0; +} + +/** + * \brief close CTL handle + * \param ctl CTL handle + * \return 0 on success otherwise a negative error code + * + * Closes the specified CTL handle and frees all associated + * resources. + */ +int +snd_ctl_close (snd_ctl_t * ctl) +{ + free (ctl); + return 0; +} + +/** + * \brief Get card related information + * \param ctl CTL handle + * \param info Card info pointer + * \return 0 on success otherwise a negative error code + */ +int +snd_ctl_card_info (snd_ctl_t * ctl, snd_ctl_card_info_t * info) +{ + + memset (info, 0, sizeof (*info)); + info->info = &ctl->info; + + return 0; +} + +/** + * \brief Obtain the card name. + * \param card Card number + * \param name Result - card name corresponding to card number + * \result zero if success, otherwise a negative error code + */ +int +snd_card_get_name (int card, char **name) +{ + char tmp[256]; + + sprintf (tmp, "OSS%d", card); + + *name = strdup (tmp); + return 0; +} + +int +snd_card_get_longname (int card, char **name) +{ + oss_card_info ci; + + ci.card = card; + if (ioctl (mixer_fd, SNDCTL_CARDINFO, &ci) == -1) + return -errno; + + *name = strdup (ci.longname); + return 0; +} + +/** + * \brief Get next PCM device number + * \param ctl CTL handle + * \param device current device on entry and next device on return + * \return 0 on success otherwise a negative error code + */ +int +snd_ctl_pcm_next_device (snd_ctl_t * ctl, int *device) +{ + ALIB_INIT (); + + dbg_printf ("snd_ctl_pcm_next_device(%d)\n", *device); + + if (*device < 0) + *device = 0; + else + { + *device = *device + 1; + } + + while (1) + { + if (*device < 0 || *device >= sysinfo.numaudios) + { + *device = -1; + return 0; + } + + ctl->ainfo.dev = *device; + if (ioctl (mixer_fd, SNDCTL_AUDIOINFO, &ctl->ainfo) < 0) + return -errno; + + if (ctl->ainfo.card_number == ctl->info.card) + { + return 0; + } + + *device = *device + 1; + } + + *device = -1; + return 0; +} + +/** + * \brief Get info about a PCM device + * \param ctl CTL handle + * \param info PCM device id/info pointer + * \return 0 on success otherwise a negative error code + */ +int +snd_ctl_pcm_info (snd_ctl_t * ctl, snd_pcm_info_t * info) +{ + dbg_printf ("snd_ctl_pcm_info()\n"); + memset (info, 0, sizeof (*info)); + info->ainfo = &ctl->ainfo; + return 0; +} + +/** + * \brief Get card mixer name from a CTL card info + * \param obj CTL card info + * \return card mixer name + */ +const char * +snd_ctl_card_info_get_mixername (const snd_ctl_card_info_t * obj) +{ + return obj->info->longname; +} + +/** + * \brief Get info about a RawMidi device + * \param ctl CTL handle + * \param info RawMidi device id/info pointer + * \return 0 on success otherwise a negative error code + */ +int +snd_ctl_rawmidi_info (snd_ctl_t * ctl, snd_rawmidi_info_t * info) +{ + dbg_printf ("snd_ctl_rawmidi_info()\n"); + + return 0; +} + +/** + * \brief Get next RawMidi device number + * \param ctl CTL handle + * \param device current device on entry and next device on return + * \return 0 on success otherwise a negative error code + */ +int +snd_ctl_rawmidi_next_device (snd_ctl_t * ctl, int *device) +{ + dbg_printf ("snd_ctl_rawmidi_next_device()\n"); + + if (*device < 0) + *device = 0; + else + *device = -1; + + return 0; +} + +/** + * \brief Get card identifier from a CTL card info + * \param obj CTL card info + * \return card identifier + */ +const char * +snd_ctl_card_info_get_id (const snd_ctl_card_info_t * obj) +{ + dbg_printf ("snd_ctl_card_info_get_id()\n"); + + return "snd_ctl_card_info_get_id"; +} |