sad

simple audio daemon
git clone git://git.2f30.org/sad
Log | Files | Refs | LICENSE

alsa.c (2595B)


      1 #include <sys/select.h>
      2 
      3 #include <alsa/asoundlib.h>
      4 #include <err.h>
      5 #include <limits.h>
      6 #include <stdio.h>
      7 
      8 #include "sad.h"
      9 
     10 static snd_pcm_t *hdl;
     11 static int framesize;
     12 static const char *device = "default"; /* TODO: make configurable? */
     13 int alsavolstatus = DEFAULTVOL;
     14 
     15 static int alsavol(int vol) {
     16   long min, max;
     17   snd_mixer_t *mixerhdl;
     18   snd_mixer_elem_t *elem;
     19   snd_mixer_selem_id_t *sid;
     20   const char *selem_name = "Master";
     21 
     22   if (snd_mixer_open(&mixerhdl, 0) < 0) {
     23     warnx("snd_mixer_open: failed");
     24     return -1;
     25   }
     26 
     27   if (snd_mixer_attach(mixerhdl, device) < 0) {
     28     warnx("snd_mixer_attach: failed");
     29     goto err0;
     30   }
     31 
     32   if (snd_mixer_selem_register(mixerhdl, NULL, NULL) < 0) {
     33     warnx("snd_mixer_selem_register: failed");
     34     goto err0;
     35   }
     36 
     37   if (snd_mixer_load(mixerhdl) < 0) {
     38     warnx("snd_mixer_load: failed");
     39     goto err0;
     40   }
     41 
     42   snd_mixer_selem_id_alloca(&sid);
     43   snd_mixer_selem_id_set_index(sid, 0);
     44   snd_mixer_selem_id_set_name(sid, selem_name);
     45   elem = snd_mixer_find_selem(mixerhdl, sid);
     46   if (!elem) {
     47     warnx("snd_mixer_find_selem: failed");
     48     goto err0;
     49   }
     50 
     51   snd_mixer_selem_get_playback_volume_range(elem, &min, &max);
     52   snd_mixer_selem_set_playback_volume_all(elem, vol * max / 100);
     53   alsavolstatus = vol;
     54 
     55   snd_mixer_close(mixerhdl);
     56   return 0;
     57 err0:
     58   snd_mixer_close(mixerhdl);
     59   return -1;
     60 }
     61 
     62 static int alsaopen(Format *fmt) {
     63   snd_pcm_format_t format = SND_PCM_FORMAT_S16_LE;
     64   int r;
     65 
     66   if (fmt->bits != 16) {
     67     warnx("unsupported number of bits");
     68     return -1;
     69   }
     70 
     71   if ((r = snd_pcm_open(&hdl, device, SND_PCM_STREAM_PLAYBACK, 0)) < 0) {
     72     warnx("snd_pcm_open: %s\n", snd_strerror(r));
     73     return -1;
     74   }
     75 
     76   if ((r = snd_pcm_set_params(hdl, format, SND_PCM_ACCESS_RW_INTERLEAVED,
     77                               fmt->channels, fmt->rate, 0, 500000)) < 0) {
     78     warnx("send_pcm_set_params: %s\n", snd_strerror(r));
     79     goto err0;
     80   }
     81 
     82   framesize = (fmt->bits + 7) / 8 * fmt->channels;
     83   return 0;
     84 
     85 err0:
     86   snd_pcm_close(hdl);
     87   hdl = NULL;
     88   return -1;
     89 }
     90 
     91 static int alsaplay(void *buf, size_t nbytes) {
     92   snd_pcm_sframes_t frames;
     93 
     94   frames = snd_pcm_writei(hdl, buf, nbytes / framesize);
     95   if (frames < 0)
     96     frames = snd_pcm_recover(hdl, frames, 0);
     97   if (frames < 0) {
     98     warnx("snd_pcm_writei failed: %s\n", snd_strerror(frames));
     99     return -1;
    100   }
    101   return frames;
    102 }
    103 
    104 static int alsaclose(void) {
    105   if (hdl)
    106     snd_pcm_close(hdl);
    107   hdl = NULL;
    108   return 0;
    109 }
    110 
    111 Output alsaoutput = {
    112     .volstatus = &alsavolstatus,
    113     .vol = alsavol,
    114     .open = alsaopen,
    115     .play = alsaplay,
    116     .close = alsaclose,
    117 };