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