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 (mem_bigendian)
88 info.play.encoding = AUDIO_ENCODING_SLINEAR_BE;
89 else
90 info.play.encoding = AUDIO_ENCODING_SLINEAR_LE;
91 #endif
92
93 if (ioctl (audio_fd, AUDIO_SETINFO, &info) != 0)
94 {
95 Con_Printf("Can't set up the sound device (%s)\n", snddev);
96 return false;
97 }
98
99 // TODO: check the parameters with AUDIO_GETINFO
100 // TODO: check AUDIO_ENCODINGFLAG_EMULATED with AUDIO_GETENC
101
102 snd_renderbuffer = Snd_CreateRingBuffer(requested, 0, NULL);
103 return true;
104 }
105
106
107 /*
108 ====================
109 SndSys_Shutdown
110
111 Stop the sound card, delete "snd_renderbuffer" and free its other resources
112 ====================
113 */
SndSys_Shutdown(void)114 void SndSys_Shutdown (void)
115 {
116 if (audio_fd >= 0)
117 {
118 close(audio_fd);
119 audio_fd = -1;
120 }
121
122 if (snd_renderbuffer != NULL)
123 {
124 Mem_Free(snd_renderbuffer->ring);
125 Mem_Free(snd_renderbuffer);
126 snd_renderbuffer = NULL;
127 }
128 }
129
130
131 /*
132 ====================
133 SndSys_Submit
134
135 Submit the contents of "snd_renderbuffer" to the sound card
136 ====================
137 */
SndSys_Submit(void)138 void SndSys_Submit (void)
139 {
140 unsigned int startoffset, factor, limit, nbframes;
141 int written;
142
143 if (audio_fd < 0 ||
144 snd_renderbuffer->startframe == snd_renderbuffer->endframe)
145 return;
146
147 startoffset = snd_renderbuffer->startframe % snd_renderbuffer->maxframes;
148 factor = snd_renderbuffer->format.width * snd_renderbuffer->format.channels;
149 limit = snd_renderbuffer->maxframes - startoffset;
150 nbframes = snd_renderbuffer->endframe - snd_renderbuffer->startframe;
151 if (nbframes > limit)
152 {
153 written = write (audio_fd, &snd_renderbuffer->ring[startoffset * factor], limit * factor);
154 if (written < 0)
155 {
156 Con_Printf("SndSys_Submit: audio write returned %d!\n", written);
157 return;
158 }
159
160 if (written % factor != 0)
161 Sys_Error("SndSys_Submit: nb of bytes written (%d) isn't aligned to a frame sample!\n", written);
162
163 snd_renderbuffer->startframe += written / factor;
164
165 if ((unsigned int)written < limit * factor)
166 {
167 Con_Printf("SndSys_Submit: audio can't keep up! (%u < %u)\n", written, limit * factor);
168 return;
169 }
170
171 nbframes -= limit;
172 startoffset = 0;
173 }
174
175 written = write (audio_fd, &snd_renderbuffer->ring[startoffset * factor], nbframes * factor);
176 if (written < 0)
177 {
178 Con_Printf("SndSys_Submit: audio write returned %d!\n", written);
179 return;
180 }
181 snd_renderbuffer->startframe += written / factor;
182 }
183
184
185 /*
186 ====================
187 SndSys_GetSoundTime
188
189 Returns the number of sample frames consumed since the sound started
190 ====================
191 */
SndSys_GetSoundTime(void)192 unsigned int SndSys_GetSoundTime (void)
193 {
194 audio_info_t info;
195
196 if (ioctl (audio_fd, AUDIO_GETINFO, &info) < 0)
197 {
198 Con_Print("Error: can't get audio info\n");
199 SndSys_Shutdown ();
200 return 0;
201 }
202
203 return info.play.samples;
204 }
205
206
207 /*
208 ====================
209 SndSys_LockRenderBuffer
210
211 Get the exclusive lock on "snd_renderbuffer"
212 ====================
213 */
SndSys_LockRenderBuffer(void)214 qboolean SndSys_LockRenderBuffer (void)
215 {
216 // Nothing to do
217 return true;
218 }
219
220
221 /*
222 ====================
223 SndSys_UnlockRenderBuffer
224
225 Release the exclusive lock on "snd_renderbuffer"
226 ====================
227 */
SndSys_UnlockRenderBuffer(void)228 void SndSys_UnlockRenderBuffer (void)
229 {
230 // Nothing to do
231 }
232
233 /*
234 ====================
235 SndSys_SendKeyEvents
236
237 Send keyboard events originating from the sound system (e.g. MIDI)
238 ====================
239 */
SndSys_SendKeyEvents(void)240 void SndSys_SendKeyEvents(void)
241 {
242 // not supported
243 }
244