Recently Written · git

sad

sad (2f30.org simple audio daemon) with a Cygwin/OSS port on branch cygwin

git clone https://github.com/equwal/sad

Log | Files | Refs


alsa.c (2595 bytes)

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