1 /*
2 * AfterStep Sound System - sound module for Wharf
3 *
4 * Copyright (c) 1996 by Alfredo Kojima
5 */
6 /*
7 * Todo:
8 * realtime audio mixing
9 * replace the Audio module
10 */
11 #include <stdlib.h>
12 #include <stdio.h>
13 #include <sys/stat.h>
14 #include <sys/types.h>
15 #include <sys/fcntl.h>
16 #include <sys/time.h>
17 #include <signal.h>
18 #include <unistd.h>
19 #define AUDIO_DEVICE "/dev/audio"
20
21 typedef struct LList {
22 struct LList *next;
23 struct LList *prev;
24 int data;
25 int timestamp;
26 } LList;
27
28 typedef struct SoundEntry {
29 char *data;
30 int size;
31 } SoundEntry;
32
33 /* timeout time for sound playing in seconds */
34 #define PLAY_TIMEOUT 1
35
36 /* table of audio data (not filenames) */
37 SoundEntry **SoundTable;
38
39 int LastSound=0;
40 char *SoundPlayer;
41
42 char *ProgName;
43 LList *PlayQueue=NULL, *OldestQueued=NULL;
44
45 int InPipe;
46
ckmalloc(size_t size)47 void *ckmalloc(size_t size)
48 {
49 void *tmp;
50
51 tmp=malloc(size);
52 if (tmp==NULL) {
53 fprintf(stderr,"%s: virtual memory exhausted.",ProgName);
54 exit(1);
55 }
56 return tmp;
57 }
58
59 /*
60 * Register --
61 * makes a new sound entry
62 */
Register(char * sound_file,int code)63 void Register(char *sound_file, int code)
64 {
65 int file;
66 struct stat stat_buf;
67
68 if (sound_file[0]=='.' && sound_file[1]==0) {
69 SoundTable[code]=ckmalloc(sizeof(SoundEntry));
70 SoundTable[code]->size = -1;
71 return; /* dummy sound */
72 }
73 if (stat(sound_file, &stat_buf)<0) {
74 fprintf(stderr,"%s: sound file %s not found\n",ProgName,
75 sound_file);
76 return;
77 }
78 SoundTable[code]=ckmalloc(sizeof(SoundEntry));
79 if (SoundPlayer!=NULL) {
80 SoundTable[code]->data=ckmalloc(strlen(sound_file));
81 SoundTable[code]->size=1;
82 strcpy(SoundTable[code]->data,sound_file);
83 return;
84 }
85 SoundTable[code]->data=ckmalloc(stat_buf.st_size);
86 file=open(sound_file, O_RDONLY);
87 if (file<0) {
88 fprintf(stderr,"%s: can't open sound file %s\n",ProgName, sound_file);
89 free(SoundTable[code]->data);
90 free(SoundTable[code]);
91 SoundTable[code]=NULL;
92 return;
93 }
94 SoundTable[code]->size=read(file,SoundTable[code]->data,stat_buf.st_size);
95 if (SoundTable[code]->size<1) {
96 fprintf(stderr,"%s: error reading sound file %s\n",ProgName,
97 sound_file);
98 free(SoundTable[code]->data);
99 free(SoundTable[code]);
100 close(file);
101 SoundTable[code]=NULL;
102 return;
103 }
104 close(file);
105 }
106
107 /*
108 * PlaySound --
109 * plays a sound
110 */
111
PlaySound(int sid)112 void PlaySound(int sid)
113 {
114 int audio=-1;
115 if ((sid < LastSound) && (SoundTable[sid]->size<=0)) return;
116 if ((sid>=LastSound) || (sid<0) || SoundTable[sid]==NULL) {
117 fprintf(stderr,"%s: request to play invalid sound received\n",
118 ProgName);
119 return;
120 }
121 if (SoundPlayer!=NULL) {
122 static char cmd[1024];
123 pid_t child;
124
125 child = fork();
126 if (child<0) return;
127 else if (child==0) {
128 execlp(SoundPlayer,SoundPlayer,SoundTable[sid]->data,NULL);
129 } else {
130 while (wait(NULL)<0);
131 }
132 /*
133 sprintf(cmd,"%s %s",SoundPlayer,SoundTable[sid]->data);
134 system(cmd);
135 */
136 return;
137 }
138 #if 0
139 audio = open(AUDIO_DEVICE,O_WRONLY|O_NONBLOCK);
140 if ((audio<0) && errno==EAGAIN) {
141 sleep(1);
142 audio = open(AUDIO_DEVICE,O_WRONLY|O_NONBLOCK);
143 if (audio<0) return;
144 }
145 write(audio, SoundTable[sid]->data,SoundTable[sid]->size);
146 close(audio);
147 audio=-1;
148 #endif
149 }
150
DoNothing(int foo)151 void DoNothing(int foo)
152 {
153 signal(SIGUSR1, DoNothing);
154 }
155
156 /*
157 * HandleRequest --
158 * play requested sound
159 * sound -1 is a quit command
160 *
161 * Note:
162 * Something not good will happed if a new play request
163 * arrives before exiting the handler
164 */
HandleRequest(int foo)165 void HandleRequest(int foo)
166 {
167 int sound, timestamp;
168 char *buffer;
169 LList *tmp;
170 /*
171 signal(SIGUSR1, DoNothing);
172 */
173 read(InPipe,&sound,sizeof(sound));
174 read(InPipe,×tamp,sizeof(timestamp));
175 if (sound<0) {
176 printf("exitting ASSound..\n");
177 exit(0);
178 }
179 if ((clock()-timestamp)<PLAY_TIMEOUT)
180 PlaySound(sound);
181 #if 0
182 tmp = ckmalloc(sizeof(LList));
183 tmp->data = sound;
184 tmp->timestamp = clock();
185 tmp->next = PlayQueue;
186 if (PlayQueue==NULL) {
187 OldestQueued = tmp;
188 tmp->prev = NULL;
189 } else {
190 PlayQueue->prev = tmp;
191 }
192 PlayQueue = tmp;
193 signal(SIGUSR1, HandleRequest);
194 #endif
195 }
196
197 /*
198 * Program startup.
199 * Arguments:
200 * argv[1] - pipe for reading data
201 * argv[2] - the name of the sound player to be used. ``-'' indicates
202 * internal player.
203 * argv[3]... - filenames of sound files with code n-3
204 */
main(int argc,char ** argv)205 int main(int argc, char **argv)
206 {
207 int i;
208
209 signal(SIGUSR1, HandleRequest);
210 ProgName=argv[0];
211 if (argc<4) {
212 fprintf(stderr, "%s can only be started by an AfterStep module\n",
213 ProgName);
214 exit(1);
215 }
216 SoundPlayer=argv[2];
217 if (SoundPlayer[0]=='-' && SoundPlayer[1]==0) {
218 SoundPlayer=NULL;
219 printf("%s:need a sound player.\n",ProgName);
220 }
221 SoundTable=ckmalloc(sizeof(SoundEntry *)*(argc-3));
222 for(i=3; i<argc; i++) {
223 Register(argv[i], i-3);
224 }
225 LastSound=i-3;
226 InPipe = atoi(argv[1]);
227 while(1) {
228 #if 0
229 LList *tmp;
230 while (OldestQueued!=NULL) {
231 if ((clock()-OldestQueued->timestamp) < PLAY_TIMEOUT)
232 PlaySound(OldestQueued->data);
233 tmp = OldestQueued->prev;
234 free(OldestQueued);
235 OldestQueued=tmp;
236 }
237 pause();
238 #endif
239 HandleRequest(0);
240 }
241 }
242
243