1 /*
2  * XBoing - An X11 blockout style computer game
3  *
4  * (c) Copyright 1993, 1994, 1995, Justin C. Kibell, All Rights Reserved
5  *
6  * The X Consortium, and any party obtaining a copy of these files from
7  * the X Consortium, directly or indirectly, is granted, free of charge, a
8  * full and unrestricted irrevocable, world-wide, paid up, royalty-free,
9  * nonexclusive right and license to deal in this software and
10  * documentation files (the "Software"), including without limitation the
11  * rights to use, copy, modify, merge, publish, distribute, sublicense,
12  * and/or sell copies of the Software, and to permit persons who receive
13  * copies from any such party to do so.  This license includes without
14  * limitation a license to do the foregoing actions under any patents of
15  * the party supplying this software to the X Consortium.
16  *
17  * In no event shall the author be liable to any party for direct, indirect,
18  * special, incidental, or consequential damages arising out of the use of
19  * this software and its documentation, even if the author has been advised
20  * of the possibility of such damage.
21  *
22  * The author specifically disclaims any warranties, including, but not limited
23  * to, the implied warranties of merchantability and fitness for a particular
24  * purpose.  The software provided hereunder is on an "AS IS" basis, and the
25  * author has no obligation to provide maintenance, support, updates,
26  * enhancements, or modifications.
27  */
28 
29 /*
30  * =========================================================================
31  *
32  * $Id: AFaudio.c,v 1.1.1.1 1994/12/16 01:36:56 jck Exp $
33  * $Source: /usr5/legends/jck/xb/master/xboing/audio/AFaudio.c,v $
34  * $Revision: 1.1.1.1 $
35  * $Date: 1994/12/16 01:36:56 $
36  *
37  * $Log: AFaudio.c,v $
38  * Revision 1.1.1.1  1994/12/16  01:36:56  jck
39  * The XBoing distribution requires configuration management. This is why the
40  * cvs utility is being used. This is the initial import of all source etc..
41  *
42  *
43  * =========================================================================
44  */
45 
46 /*
47  * Audiofile format -
48  *
49  * Original code from Andrew Leahy <A.Leahy@st.nepean.uws.edu.au>
50  *
51  * Revised by Wes Whitnah <wesw@orca.wv.tek.com>
52  *
53  *    - File now compiles!
54  *    - Correctly determine audio server connection per
55  *      the AudioFile spec.  Checks for AUDIOFILE environment
56  *      variable, but defaults to the X display if none set.
57  *      AUDIOFILE environment variable is *NOT* a requirement.
58  *    - Correctly determine which AudioFile device to connect to.
59  *      Looks for a uLaw device, which may not be device zero.
60  *    - Verify sound files and strip header before sending
61  *      sound clip to the audio server.  Reduces clicks.
62  *    - Clean up error checking and recovery in various places.
63  *    - Removed unused variables and dead code.
64  *
65  * Revised again by Wes Whitnah <wesw@orca.wv.tek.com> - Sep 1994
66  */
67 
68 /*
69  *  Include file dependencies:
70  */
71 
72 #include <stdio.h>
73 #include <fcntl.h>
74 #include <X11/Xlib.h>
75 #include "include/error.h"
76 #include "AFlib.h"
77 
78 /*
79  * Internal macro definitions:
80  */
81 
82 #define BUFFER_SIZE				(1024 * 4)
83 
84 /*
85  *  Internal type declarations:
86  */
87 
88 typedef struct
89 {
90 	unsigned	magic;				/* Magic number		  */
91 	unsigned	sample_rate;		/* Samples per second	  */
92 	unsigned	samples_per_unit;	/* Samples per unit	  */
93 	unsigned	bytes_per_unit;		/* Bytes per sample unit  */
94 	unsigned	channels;			/* # interleaved channels */
95 	unsigned	encoding;			/* Date encoding format	  */
96 } Sun_Audio_Hdr;
97 
98 /*
99  * Internal variable declarations:
100  */
101 
102 static char			*buf;
103 static char			errorString[255];
104 static AC			ac;
105 static AFAudioConn	*aud;
106 
107 
108 #if NeedFunctionPrototypes
FindPlayDevice(AFAudioConn * aud,int rate,AEncodeType type,int nchan)109 static int FindPlayDevice(AFAudioConn *aud, int rate,
110 	AEncodeType type, int nchan)
111 #else
112 static int FindPlayDevice(aud, rate, type, nchan)
113 	AFAudioConn	*aud;
114 	int		rate;
115 	AEncodeType	type;
116 	int		nchan;
117 #endif
118 {
119     AFDeviceDescriptor	*aDev;
120     int			ndevices;
121     int			i;
122 
123     ndevices = ANumberOfAudioDevices(aud);
124 
125     /*
126      * Iterate through all of the devices until we find a match.
127      * Make sure device is not connected to the phone.
128      */
129 
130     for (i = 0; i < ndevices; i++)
131     {
132 		aDev = AAudioDeviceDescriptor(aud, i);
133 		if (aDev->inputsFromPhone == 0
134 	    	&& aDev->outputsToPhone == 0
135 	    	&& aDev->playSampleFreq == rate
136 	    	&& aDev->playBufType == type
137 	    	&& aDev->playNchannels == nchan)
138 		{
139 			/* match found */
140 	    	return i;
141 		}
142     }
143 
144     /* No match found. */
145     return -1;
146 }
147 
148 #if NeedFunctionPrototypes
SetUpAudioSystem(Display * display)149 int SetUpAudioSystem(Display *display)
150 #else
151 int SetUpAudioSystem(display)
152 	Display *display;
153 #endif
154 {
155     AFSetACAttributes 	attributes;
156     int 		device;
157     char 		*server;
158     int			audiofile_set = True;
159 
160     /*
161      * Determine which audio server should be used.
162      * AudioFile uses the following search sequence:
163      *   1) AUDIOFILE environment variable, if set
164      *   2) DISPLAY environment variable, if set
165      */
166 
167     if ((server = (char *) getenv("AUDIOFILE")) == NULL)
168     {
169 		audiofile_set = False;
170 
171 		/*
172 	 	 * Use XDisplayString() in case user added the
173 	 	 * -display switch to the command line.
174 	 	 */
175 		if ((server = XDisplayString(display)) == NULL)
176 		{
177 		    sprintf(errorString, "Cannot find an audio server name.");
178 		    NormalMessage(errorString);
179 		    sprintf(errorString,
180 			    "Try setting the AUDIOFILE environment variable.");
181 		    NormalMessage(errorString);
182 		    return False;
183 		}
184     }
185 
186     /*
187      * Establish a connection to the audio server.
188      */
189     if ((aud = AFOpenAudioConn(server)) == NULL)
190     {
191 		sprintf(errorString,
192 			"Cannot open a connection to audio server %s.", server);
193 		NormalMessage(errorString);
194 
195 		if (!audiofile_set)
196 		{
197 	   		sprintf(errorString,
198 		    	"Try setting the AUDIOFILE environment variable.");
199 	   		NormalMessage(errorString);
200 		}
201 
202 		return False;
203     }
204 
205     /*
206      * Try to find a device that can play ulaw samples.
207      */
208 
209     if ((device = FindPlayDevice(aud, 8000, MU255, 1)) == -1)
210     {
211 		sprintf(errorString, "Couldn't find a ulaw audio device.");
212 		ErrorMessage(errorString);
213 		AFCloseAudioConn(aud);
214 		return False;
215     }
216 
217     /*
218      * Initialize player.
219      */
220 
221     attributes.preempt 			= Mix;
222     attributes.start_timeout 	= 0;
223     attributes.end_silence 		= 0;
224     attributes.play_gain 		= 0;
225     attributes.rec_gain 		= 0;
226 
227     ac = AFCreateAC(aud, device, ACPlayGain, &attributes);
228 
229     if ((buf = (char *) malloc(BUFFER_SIZE)) == NULL)
230     {
231 		sprintf(errorString, "Couldn't allocate a play buffer.");
232 		ErrorMessage(errorString);
233 		AFFreeAC(ac);
234 		AFCloseAudioConn(aud);
235 		return False;
236     }
237 
238     /*
239      * Success in opening the audio device.
240      */
241     return True;
242 }
243 
244 #if NeedFunctionPrototypes
flushAudioDevice(void)245 static void flushAudioDevice(void)
246 #else
247 static void flushAudioDevice()
248 #endif
249 {
250     /* Not needed */
251 }
252 
253 #if NeedFunctionPrototypes
FreeAudioSystem(void)254 void FreeAudioSystem(void)
255 #else
256 void FreeAudioSystem()
257 #endif
258 {
259     /* Close connection to the audiofile sound server */
260     AFFreeAC(ac);
261     AFCloseAudioConn(aud);
262 
263     /* Free memory buffer */
264     if (buf != (char *) NULL) free(buf);
265 }
266 
267 #if NeedFunctionPrototypes
SetMaximumVolume(int Volume)268 void SetMaximumVolume(int Volume)
269 #else
270 void SetMaximumVolume(Volume)
271 	int Volume;
272 #endif
273 {
274     /* Not needed */
275 }
276 
277 #if NeedFunctionPrototypes
GetMaximumVolume(void)278 int GetMaximumVolume(void)
279 #else
280 int GetMaximumVolume()
281 #endif
282 {
283     return 0;
284 }
285 
286 #if NeedFunctionPrototypes
playSoundFile(char * filename,int volume)287 void playSoundFile(char *filename, int volume)
288 #else
289 void playSoundFile(filename, volume)
290 	char *filename;
291 	int volume;
292 #endif
293 {
294     int			fd;
295     char		soundfile[1024];
296     char		*str;
297     int			nbytes;
298     ATime		t, act, nact;
299     Sun_Audio_Hdr	header;
300 
301     /*
302      * Construct the sounds file path.
303      */
304     if ((str = (char *)getenv("XBOING_SOUND_DIR")) != NULL)
305 		sprintf(soundfile, "%s/%s.au", str, filename);
306     else
307 		sprintf(soundfile, "%s/%s.au", SOUNDS_DIR, filename);
308 
309     /*
310      * Open the sound file for reading.
311      */
312     if ((fd = open(soundfile, O_RDONLY, 0)) < 0)
313     {
314 		sprintf(errorString, "Unable to open sound file %s .", soundfile);
315 		WarningMessage(errorString);
316 		return;
317     }
318 
319     /*
320      * Assume we have a Sun audio file, and strip the header.
321      */
322     if (read(fd, (char *)&header, sizeof(Sun_Audio_Hdr))
323 		< sizeof(Sun_Audio_Hdr))
324     {
325 		sprintf(errorString, "Unable to play sound file %s .", soundfile);
326 		WarningMessage(errorString);
327 		(void) close(fd);
328 		return;
329     }
330 
331     /*
332      * Send the audio clip data to the audio server.
333      */
334     if ((nbytes = read(fd, (char *) buf, BUFFER_SIZE)) <= 0)
335     {
336 		(void) close(fd);
337 		return;
338     }
339 
340     t = AFGetTime(ac);
341 
342     do
343     {
344 		nact = AFPlaySamples(ac, t, nbytes, buf);
345 		act = nact;
346 		t += nbytes;
347     } while ((nbytes = read(fd, buf, BUFFER_SIZE)) != 0);
348 
349     /*
350      * Close the sound file
351      */
352     (void) close(fd);
353 }
354 
355 #if NeedFunctionPrototypes
audioDeviceEvents(void)356 void audioDeviceEvents(void)
357 #else
358 void audioDeviceEvents()
359 #endif
360 {
361     /* None to do */
362 }
363