sad

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

alsa.c (2384B)


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