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 <unistd.h>
21 #include <fcntl.h>
22 #include <stdlib.h>
23 #include <sys/types.h>
24 #include <sys/ioctl.h>
25 #include <sys/mman.h>
26 #include <sys/shm.h>
27 #include <sys/wait.h>
28 #include <stdio.h>
29 #include <sys/audioio.h>
30 #include <errno.h>
31 #include "quakedef.h"
32 
33 int audio_fd;
34 int snd_inited;
35 
36 static int bufpos;
37 static int wbufp;
38 static audio_info_t info;
39 
40 #define BUFFER_SIZE		8192
41 
42 unsigned char dma_buffer[BUFFER_SIZE];
43 unsigned char pend_buffer[BUFFER_SIZE];
44 int pending;
45 
46 static int lastwrite = 0;
47 
SNDDMA_Init(void)48 qboolean SNDDMA_Init(void)
49 {
50 	int rc;
51 	int fmt;
52 	int tmp;
53 	int i;
54 	char *s;
55 	int caps;
56 
57 	if (snd_inited) {
58 		printf("Sound already init'd\n");
59 		return;
60 	}
61 
62 	shm = &sn;
63 	shm->splitbuffer = 0;
64 
65 	audio_fd = open("/dev/audio", O_WRONLY|O_NDELAY);
66 
67 	if (audio_fd < 0) {
68 		if (errno == EBUSY) {
69 			Con_Printf("Audio device is being used by another process\n");
70 		}
71 		perror("/dev/audio");
72 		Con_Printf("Could not open /dev/audio\n");
73 		return (0);
74 	}
75 
76 	if (ioctl(audio_fd, AUDIO_GETINFO, &info) < 0) {
77 		perror("/dev/audio");
78 		Con_Printf("Could not communicate with audio device.\n");
79 		close(audio_fd);
80 		return 0;
81 	}
82 
83 	//
84 	// set to nonblock
85 	//
86 	if (fcntl(audio_fd, F_SETFL, O_NONBLOCK) < 0) {
87 		perror("/dev/audio");
88 		close(audio_fd);
89 		return 0;
90 	}
91 
92 	AUDIO_INITINFO(&info);
93 
94 	shm->speed = 11025;
95 
96 	// try 16 bit stereo
97 	info.play.encoding = AUDIO_ENCODING_LINEAR;
98 	info.play.sample_rate = 11025;
99 	info.play.channels = 2;
100 	info.play.precision = 16;
101 
102 	if (ioctl(audio_fd, AUDIO_SETINFO, &info) < 0) {
103 		info.play.encoding = AUDIO_ENCODING_LINEAR;
104 		info.play.sample_rate = 11025;
105 		info.play.channels = 1;
106 		info.play.precision = 16;
107 		if (ioctl(audio_fd, AUDIO_SETINFO, &info) < 0) {
108 			Con_Printf("Incapable sound hardware.\n");
109 			close(audio_fd);
110 			return 0;
111 		}
112 		Con_Printf("16 bit mono sound initialized\n");
113 		shm->samplebits = 16;
114 		shm->channels = 1;
115 	} else { // 16 bit stereo
116 		Con_Printf("16 bit stereo sound initialized\n");
117 		shm->samplebits = 16;
118 		shm->channels = 2;
119 	}
120 
121 	shm->soundalive = true;
122 	shm->samples = sizeof(dma_buffer) / (shm->samplebits/8);
123 	shm->samplepos = 0;
124 	shm->submission_chunk = 1;
125 	shm->buffer = (unsigned char *)dma_buffer;
126 
127 	snd_inited = 1;
128 
129 	return 1;
130 }
131 
SNDDMA_GetDMAPos(void)132 int SNDDMA_GetDMAPos(void)
133 {
134 	if (!snd_inited)
135 		return (0);
136 
137 	if (ioctl(audio_fd, AUDIO_GETINFO, &info) < 0) {
138 		perror("/dev/audio");
139 		Con_Printf("Could not communicate with audio device.\n");
140 		close(audio_fd);
141 		snd_inited = 0;
142 		return (0);
143 	}
144 
145 	return ((info.play.samples*shm->channels) % shm->samples);
146 }
147 
SNDDMA_GetSamples(void)148 int SNDDMA_GetSamples(void)
149 {
150 	if (!snd_inited)
151 		return (0);
152 
153 	if (ioctl(audio_fd, AUDIO_GETINFO, &info) < 0) {
154 		perror("/dev/audio");
155 		Con_Printf("Could not communicate with audio device.\n");
156 		close(audio_fd);
157 		snd_inited = 0;
158 		return (0);
159 	}
160 
161 	return info.play.samples;
162 }
163 
SNDDMA_Shutdown(void)164 void SNDDMA_Shutdown(void)
165 {
166 	if (snd_inited) {
167 		close(audio_fd);
168 		snd_inited = 0;
169 	}
170 }
171 
172 /*
173 ==============
174 SNDDMA_Submit
175 
176 Send sound to device if buffer isn't really the dma buffer
177 ===============
178 */
SNDDMA_Submit(void)179 void SNDDMA_Submit(void)
180 {
181 	int samps;
182 	int bsize;
183 	int bytes, b;
184 	static unsigned char writebuf[1024];
185 	unsigned char *p;
186 	int idx;
187 	int stop = paintedtime;
188 	extern int soundtime;
189 
190 	if (paintedtime < wbufp)
191 		wbufp = 0; // reset
192 
193 	bsize = shm->channels * (shm->samplebits/8);
194 	bytes = (paintedtime - wbufp) * bsize;
195 
196 	if (!bytes)
197 		return;
198 
199 	if (bytes > sizeof(writebuf)) {
200 		bytes = sizeof(writebuf);
201 		stop = wbufp + bytes/bsize;
202 	}
203 
204 	p = writebuf;
205 	idx = (wbufp*bsize) & (BUFFER_SIZE - 1);
206 
207 	for (b = bytes; b; b--) {
208 		*p++ = dma_buffer[idx];
209 		idx = (idx + 1) & (BUFFER_SIZE - 1);
210 	}
211 
212 	wbufp = stop;
213 
214 	if (write(audio_fd, writebuf, bytes) < bytes)
215 		printf("audio can't keep up!\n");
216 
217 }
218 
219