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,&timestamp,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