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


sad.c (3296 bytes)

1 #include <sys/select.h>
2 #include <sys/socket.h>
3 #include <sys/types.h>
4 #include <sys/un.h>
5 
6 #include <err.h>
7 #include <errno.h>
8 #include <fcntl.h>
9 #include <limits.h>
10 #include <signal.h>
11 #include <stdio.h>
12 #include <stdlib.h>
13 #include <string.h>
14 #include <unistd.h>
15 
16 #include "arg.h"
17 #include "sad.h"
18 
19 fd_set master;
20 fd_set rfds;
21 int fdmax;
22 char *argv0;
23 
24 static int listenfd = -1;
25 static volatile sig_atomic_t isrunning = 1;
26 static char *socketpath = "/tmp/sad-sock";
27 
28 static int servlisten(const char *name) {
29   struct sockaddr_un sun;
30   int fd, r;
31   socklen_t len;
32 
33   fd = socket(AF_UNIX, SOCK_STREAM, 0);
34   if (fd < 0)
35     err(1, "socket");
36 
37   unlink(name);
38 
39   memset(&sun, 0, sizeof(sun));
40   sun.sun_family = AF_UNIX;
41   strlcpy(sun.sun_path, name, sizeof(sun.sun_path));
42 
43   len = sizeof(sun);
44   r = bind(fd, (struct sockaddr *)&sun, len);
45   if (r < 0)
46     err(1, "bind");
47 
48   r = listen(fd, 5);
49   if (r < 0)
50     err(1, "listen");
51 
52   return fd;
53 }
54 
55 static int servaccept(int listenfd) {
56   struct sockaddr_un sun;
57   int clifd;
58   socklen_t len;
59 
60   len = sizeof(sun);
61   clifd = accept(listenfd, (struct sockaddr *)&sun, &len);
62   if (clifd < 0)
63     err(1, "accept");
64   return clifd;
65 }
66 
67 static void playaudio(void) {
68   Song *s;
69   unsigned char buf[4096];
70   int nbytes;
71 
72   s = getcursong();
73   if (!s)
74     return;
75 
76   switch (s->state) {
77   case PREPARE:
78     if (s->decoder->open(&s->fmt, s->path) < 0) {
79       s->state = NONE;
80       return;
81     }
82     s->state = PLAYING;
83     break;
84   case PLAYING:
85     if ((nbytes = s->decoder->decode(buf, sizeof(buf))) <= 0) {
86       playsong(picknextsong());
87       notify(EVSONGFINISHED);
88     } else {
89       playoutputs(&s->fmt, buf, nbytes);
90     }
91     break;
92   }
93 }
94 
95 static void sighandler(int signum) {
96   if (signum == SIGINT || signum == SIGTERM)
97     isrunning = 0;
98 }
99 
100 static void usage(void) {
101   fprintf(stderr, "usage: %s [-f sock]\n", argv0);
102   exit(1);
103 }
104 
105 int main(int argc, char *argv[]) {
106   struct sigaction sa;
107   struct timeval tv;
108   int clifd, n, i;
109 
110   ARGBEGIN {
111   case 'f':
112     socketpath = EARGF(usage());
113     break;
114   default:
115     usage();
116   }
117   ARGEND;
118 
119   memset(&sa, 0, sizeof(sa));
120   sa.sa_flags = SA_RESTART;
121   sa.sa_handler = sighandler;
122   sigaction(SIGTERM, &sa, NULL);
123   sigaction(SIGINT, &sa, NULL);
124 
125   FD_ZERO(&master);
126   FD_ZERO(&rfds);
127 
128   listenfd = servlisten(socketpath);
129   FD_SET(listenfd, &master);
130   fdmax = listenfd;
131 
132   initoutputs();
133   openoutputs();
134   initnotifier();
135 
136   playlistmode(REPEAT);
137 
138   while (isrunning) {
139     rfds = master;
140     tv.tv_sec = 0;
141     tv.tv_usec = 10000;
142     n = select(fdmax + 1, &rfds, NULL, NULL, &tv);
143     if (n < 0) {
144       if (errno == EINTR)
145         goto fini;
146       err(1, "select");
147     }
148 
149     playaudio();
150 
151     for (i = 0; i <= fdmax; i++) {
152       if (!FD_ISSET(i, &rfds))
153         continue;
154       if (i == listenfd) {
155         clifd = servaccept(listenfd);
156         FD_SET(clifd, &master);
157         if (clifd > fdmax)
158           fdmax = clifd;
159       } else {
160         if (docmd(i) < 0) {
161           close(i);
162           FD_CLR(i, &master);
163           removesubscriber(i);
164         }
165       }
166     }
167   }
168 fini:
169   for (i = 0; i <= fdmax; i++) {
170     if (FD_ISSET(i, &master)) {
171       close(i);
172       FD_CLR(i, &master);
173       removesubscriber(i);
174     }
175   }
176   if (listenfd != -1)
177     unlink(socketpath);
178   return 0;
179 }