chiark / gitweb /
5eda4f7aebd098427c30a439fa8348d60ee9b23a
[chiark-utils.git] / cprogs / trivsoundd.c
1 /*
2  * triv-sound-d.c
3  * writebuffer adapted for sound-playing
4  *
5  * readbuffer and writebuffer are:
6  *  Copyright (C) 1997-1998,2000-2001 Ian Jackson <ian@chiark.greenend.org.uk>
7  *
8  * readbuffer is part of chiark backup, a system for backing up GNU/Linux and
9  * other UN*X-compatible machines, as used on chiark.greenend.org.uk.
10  * chiark backup is:
11  *  Copyright (C) 1997-1998,2000-2001 Ian Jackson <ian@chiark.greenend.org.uk>
12  *  Copyright (C) 1999 Peter Maydell <pmaydell@chiark.greenend.org.uk>
13  *
14  * This is free software; you can redistribute it and/or modify
15  * it under the terms of the GNU General Public License as
16  * published by the Free Software Foundation; either version 2,
17  * or (at your option) any later version.
18  *
19  * This is distributed in the hope that it will be useful, but
20  * WITHOUT ANY WARRANTY; without even the implied warranty of
21  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
22  * GNU General Public License for more details.
23  *
24  * You should have received a copy of the GNU General Public
25  * License along with this file; if not, write to the Free Software
26  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
27  *
28  */
29
30 #include "rwbuffer.h"
31
32 const char *progname= "trivsoundd";
33
34 static int maxstartdelay=60, maxbadaccept=10;
35
36 struct inqnode {
37   struct inqnode *next, *back;
38   time_t accepted;
39   int fd;
40 };
41
42 static struct { struct inqnode *head, *tail; } inq;
43 static int sdev;
44 static time_t now;
45
46 static void opensounddevice(void) {
47   int r;
48   char cbuf[200];
49   
50   sdev= open("/dev/dsp", O_WRONLY);
51   if (sdev<0) { perror("open sound device"); exit(8); }
52
53   snprintf(cbuf, sizeof(cbuf), "sox -t raw -s -w -r 44100 -c 2"
54            " - </dev/null -t ossdsp - >&%d", sdev);
55   r= system(cbuf);  if (r) { fprintf(stderr,"sox gave %d\n",r); exit(5); }
56 }
57
58 static void selectcopy(void) {
59   int slave= inq.head ? inq.head->fd : -1;
60   wrbufcore_prepselect(slave, sdev);
61   FD_SET(0,&readfds);
62   callselect();
63   wrbufcore_afterselect(slave, sdev);
64 }
65
66 static void expireoldconns(void) {
67   struct inqnode *searchold, *nextsearchold;
68       
69   for (searchold= inq.head ? inq.head->next : 0;
70        searchold;
71        searchold= nextsearchold) {
72     nextsearchold= searchold;
73     if (searchold->accepted < now-maxstartdelay) {
74       printf("expired %p\n",searchold);
75       LIST_UNLINK(inq,searchold);
76       free(searchold);
77     }
78   }
79 }
80
81 static void acceptnewconns(void) {
82   static int bad;
83   
84   int slave;
85   struct inqnode *new;
86
87   if (!FD_ISSET(0,&readfds)) return;
88
89   slave= accept(0,0,0);
90   if (slave < 0) {
91     if (!(errno == EINTR ||
92           errno == EAGAIN ||
93           errno == EWOULDBLOCK)) {
94       perror("accept");
95       bad++;
96       if (bad > maxbadaccept) {
97         fprintf(stderr,"accept failures repeating\n");
98         exit(4);
99       }
100     }
101     /* any transient error will just send us round again via select */
102     return;
103   }
104
105   bad= 0;
106   new= xmalloc(sizeof(struct inqnode));
107   new->accepted= now;
108   new->fd= slave;
109   LIST_LINK_TAIL(inq,new);
110
111   printf("accepted %p\n",new);
112 }
113
114 static void switchinput(void) {
115   struct inqnode *old;
116   if (!seeneof) return;
117   old= inq.head;
118   assert(old);
119   printf("finished %p\n",old);
120   close(old->fd);
121   LIST_UNLINK(inq,old);
122   free(old);
123   seeneof= 0;
124 }  
125
126 int main(int argc, const char *const *argv) {
127   assert(argv[0]);
128   if (argv[1]) { fputs("no arguments allowed\n",stderr); exit(12); }
129
130   buffersize= 44100*4* 5/*seconds*/;
131
132   opensounddevice();
133   nonblock(sdev,1);
134   nonblock(0,1);
135
136   startupcore();
137   wrbufcore_startup();
138   
139   printf("started\n");
140   for (;;) {
141     selectcopy();
142     if (time(&now)==(time_t)-1) { perror("time(2)"); exit(4); }
143     expireoldconns();
144     acceptnewconns();
145     switchinput();
146   }
147 }