1 /*
2 Copyright (C) 1996-1997 Id Software, Inc.
3 
4 This program is free software; you can redistribute it and/or
5 modify it under the terms of the GNU General Public License
6 as published by the Free Software Foundation; either version 2
7 of the License, or (at your option) any later version.
8 
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
12 
13 See the GNU General Public License for more details.
14 
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
18 
19 */
20 #include "quakedef.h"
21 
22 #include <sys/param.h>
23 #include <sys/audioio.h>
24 #ifndef SUNOS
25 #	include <sys/endian.h>
26 #endif
27 #include <sys/ioctl.h>
28 
29 #include <fcntl.h>
30 #ifndef SUNOS
31 #	include <paths.h>
32 #endif
33 #include <unistd.h>
34 
35 #include "snd_main.h"
36 
37 
38 static int audio_fd = -1;
39 
40 
41 /*
42 ====================
43 SndSys_Init
44 
45 Create "snd_renderbuffer" with the proper sound format if the call is successful
46 May return a suggested format if the requested format isn't available
47 ====================
48 */
SndSys_Init(const snd_format_t * requested,snd_format_t * suggested)49 qboolean SndSys_Init (const snd_format_t* requested, snd_format_t* suggested)
50 {
51 	unsigned int i;
52 	const char *snddev;
53 	audio_info_t info;
54 
55 	// Open the audio device
56 #ifdef _PATH_SOUND
57 	snddev = _PATH_SOUND;
58 #elif defined(SUNOS)
59 	snddev = "/dev/audio";
60 #else
61 	snddev = "/dev/sound";
62 #endif
63 	audio_fd = open (snddev, O_WRONLY | O_NDELAY | O_NONBLOCK);
64 	if (audio_fd < 0)
65 	{
66 		Con_Printf("Can't open the sound device (%s)\n", snddev);
67 		return false;
68 	}
69 
70 	AUDIO_INITINFO (&info);
71 #ifdef AUMODE_PLAY	// NetBSD / OpenBSD
72 	info.mode = AUMODE_PLAY;
73 #endif
74 	info.play.sample_rate = requested->speed;
75 	info.play.channels = requested->channels;
76 	info.play.precision = requested->width * 8;
77 	if (requested->width == 1)
78 #ifdef SUNOS
79 		info.play.encoding = AUDIO_ENCODING_LINEAR8;
80 #else
81 		info.play.encoding = AUDIO_ENCODING_ULINEAR;
82 #endif
83 	else
84 #ifdef SUNOS
85 		info.play.encoding = AUDIO_ENCODING_LINEAR;
86 #else
87 #	if BYTE_ORDER == BIG_ENDIAN
88 		info.play.encoding = AUDIO_ENCODING_SLINEAR_BE;
89 #	else
90 		info.play.encoding = AUDIO_ENCODING_SLINEAR_LE;
91 #	endif
92 #endif
93 
94 	if (ioctl (audio_fd, AUDIO_SETINFO, &info) != 0)
95 	{
96 		Con_Printf("Can't set up the sound device (%s)\n", snddev);
97 		return false;
98 	}
99 
100 	// TODO: check the parameters with AUDIO_GETINFO
101 	// TODO: check AUDIO_ENCODINGFLAG_EMULATED with AUDIO_GETENC
102 
103 	snd_renderbuffer = Snd_CreateRingBuffer(requested, 0, NULL);
104 	return true;
105 }
106 
107 
108 /*
109 ====================
110 SndSys_Shutdown
111 
112 Stop the sound card, delete "snd_renderbuffer" and free its other resources
113 ====================
114 */
SndSys_Shutdown(void)115 void SndSys_Shutdown (void)
116 {
117 	if (audio_fd >= 0)
118 	{
119 		close(audio_fd);
120 		audio_fd = -1;
121 	}
122 
123 	if (snd_renderbuffer != NULL)
124 	{
125 		Mem_Free(snd_renderbuffer->ring);
126 		Mem_Free(snd_renderbuffer);
127 		snd_renderbuffer = NULL;
128 	}
129 }
130 
131 
132 /*
133 ====================
134 SndSys_Submit
135 
136 Submit the contents of "snd_renderbuffer" to the sound card
137 ====================
138 */
SndSys_Submit(void)139 void SndSys_Submit (void)
140 {
141 	unsigned int startoffset, factor, limit, nbframes;
142 	int written;
143 
144 	if (audio_fd < 0 ||
145 		snd_renderbuffer->startframe == snd_renderbuffer->endframe)
146 		return;
147 
148 	startoffset = snd_renderbuffer->startframe % snd_renderbuffer->maxframes;
149 	factor = snd_renderbuffer->format.width * snd_renderbuffer->format.channels;
150 	limit = snd_renderbuffer->maxframes - startoffset;
151 	nbframes = snd_renderbuffer->endframe - snd_renderbuffer->startframe;
152 	if (nbframes > limit)
153 	{
154 		written = write (audio_fd, &snd_renderbuffer->ring[startoffset * factor], limit * factor);
155 		if (written < 0)
156 		{
157 			Con_Printf("SndSys_Submit: audio write returned %d!\n", written);
158 			return;
159 		}
160 
161 		if (written % factor != 0)
162 			Sys_Error("SndSys_Submit: nb of bytes written (%d) isn't aligned to a frame sample!\n", written);
163 
164 		snd_renderbuffer->startframe += written / factor;
165 
166 		if ((unsigned int)written < limit * factor)
167 		{
168 			Con_Printf("SndSys_Submit: audio can't keep up! (%u < %u)\n", written, limit * factor);
169 			return;
170 		}
171 
172 		nbframes -= limit;
173 		startoffset = 0;
174 	}
175 
176 	written = write (audio_fd, &snd_renderbuffer->ring[startoffset * factor], nbframes * factor);
177 	if (written < 0)
178 	{
179 		Con_Printf("SndSys_Submit: audio write returned %d!\n", written);
180 		return;
181 	}
182 	snd_renderbuffer->startframe += written / factor;
183 }
184 
185 
186 /*
187 ====================
188 SndSys_GetSoundTime
189 
190 Returns the number of sample frames consumed since the sound started
191 ====================
192 */
SndSys_GetSoundTime(void)193 unsigned int SndSys_GetSoundTime (void)
194 {
195 	audio_info_t info;
196 
197 	if (ioctl (audio_fd, AUDIO_GETINFO, &info) < 0)
198 	{
199 		Con_Print("Error: can't get audio info\n");
200 		SndSys_Shutdown ();
201 		return 0;
202 	}
203 
204 	return info.play.samples;
205 }
206 
207 
208 /*
209 ====================
210 SndSys_LockRenderBuffer
211 
212 Get the exclusive lock on "snd_renderbuffer"
213 ====================
214 */
SndSys_LockRenderBuffer(void)215 qboolean SndSys_LockRenderBuffer (void)
216 {
217 	// Nothing to do
218 	return true;
219 }
220 
221 
222 /*
223 ====================
224 SndSys_UnlockRenderBuffer
225 
226 Release the exclusive lock on "snd_renderbuffer"
227 ====================
228 */
SndSys_UnlockRenderBuffer(void)229 void SndSys_UnlockRenderBuffer (void)
230 {
231 	// Nothing to do
232 }
233 
234 /*
235 ====================
236 SndSys_SendKeyEvents
237 
238 Send keyboard events originating from the sound system (e.g. MIDI)
239 ====================
240 */
SndSys_SendKeyEvents(void)241 void SndSys_SendKeyEvents(void)
242 {
243 	// not supported
244 }
245