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 };