1#include <unistd.h>
2#include <fcntl.h>
3#include <stdlib.h>
4#include <sys/types.h>
5#include <sys/ioctl.h>
6#include <sys/mman.h>
7#include <sys/shm.h>
8#include <sys/wait.h>
9#include <linux/soundcard.h>
10#include <stdio.h>
11#include "quakedef.h"
12
13int audio_fd;
14int snd_inited;
15
16static int tryrates[] = { 11025, 22051, 44100, 8000 };
17
18qboolean SNDDMA_Init(void)
19{
20
21	int rc;
22    int fmt;
23	int tmp;
24    int i;
25    char *s;
26	struct audio_buf_info info;
27	int caps;
28
29	snd_inited = 0;
30
31// open /dev/dsp, confirm capability to mmap, and get size of dma buffer
32
33    audio_fd = open("/dev/dsp", O_RDWR);
34    if (audio_fd < 0)
35	{
36		perror("/dev/dsp");
37        Con_Printf("Could not open /dev/dsp\n");
38		return 0;
39	}
40
41    rc = ioctl(audio_fd, SNDCTL_DSP_RESET, 0);
42    if (rc < 0)
43	{
44		perror("/dev/dsp");
45		Con_Printf("Could not reset /dev/dsp\n");
46		close(audio_fd);
47		return 0;
48	}
49
50	if (ioctl(audio_fd, SNDCTL_DSP_GETCAPS, &caps)==-1)
51	{
52		perror("/dev/dsp");
53        Con_Printf("Sound driver too old\n");
54		close(audio_fd);
55		return 0;
56	}
57
58	if (!(caps & DSP_CAP_TRIGGER) || !(caps & DSP_CAP_MMAP))
59	{
60		Con_Printf("Sorry but your soundcard can't do this\n");
61		close(audio_fd);
62		return 0;
63	}
64
65    if (ioctl(audio_fd, SNDCTL_DSP_GETOSPACE, &info)==-1)
66    {
67        perror("GETOSPACE");
68		Con_Printf("Um, can't do GETOSPACE?\n");
69		close(audio_fd);
70		return 0;
71    }
72
73	shm = &sn;
74    shm->splitbuffer = 0;
75
76// set sample bits & speed
77
78    s = getenv("QUAKE_SOUND_SAMPLEBITS");
79    if (s) shm->samplebits = atoi(s);
80	else if ((i = COM_CheckParm("-sndbits")) != 0)
81		shm->samplebits = atoi(com_argv[i+1]);
82	if (shm->samplebits != 16 && shm->samplebits != 8)
83    {
84        ioctl(audio_fd, SNDCTL_DSP_GETFMTS, &fmt);
85        if (fmt & AFMT_S16_LE) shm->samplebits = 16;
86        else if (fmt & AFMT_U8) shm->samplebits = 8;
87    }
88
89    s = getenv("QUAKE_SOUND_SPEED");
90    if (s) shm->speed = atoi(s);
91	else if ((i = COM_CheckParm("-sndspeed")) != 0)
92		shm->speed = atoi(com_argv[i+1]);
93    else
94    {
95        for (i=0 ; i<sizeof(tryrates)/4 ; i++)
96            if (!ioctl(audio_fd, SNDCTL_DSP_SPEED, &tryrates[i])) break;
97        shm->speed = tryrates[i];
98    }
99
100    s = getenv("QUAKE_SOUND_CHANNELS");
101    if (s) shm->channels = atoi(s);
102	else if ((i = COM_CheckParm("-sndmono")) != 0)
103		shm->channels = 1;
104	else if ((i = COM_CheckParm("-sndstereo")) != 0)
105		shm->channels = 2;
106    else shm->channels = 2;
107
108	shm->samples = info.fragstotal * info.fragsize / (shm->samplebits/8);
109	shm->submission_chunk = 1;
110
111// memory map the dma buffer
112
113	shm->buffer = (unsigned char *) mmap(NULL, info.fragstotal
114		* info.fragsize, PROT_WRITE, MAP_FILE|MAP_SHARED, audio_fd, 0);
115	if (!shm->buffer)
116	{
117		perror("/dev/dsp");
118		Con_Printf("Could not mmap /dev/dsp\n");
119		close(audio_fd);
120		return 0;
121	}
122
123	tmp = 0;
124	if (shm->channels == 2)
125		tmp = 1;
126    rc = ioctl(audio_fd, SNDCTL_DSP_STEREO, &tmp);
127    if (rc < 0)
128    {
129		perror("/dev/dsp");
130        Con_Printf("Could not set /dev/dsp to stereo=%d", shm->channels);
131		close(audio_fd);
132        return 0;
133    }
134	if (tmp)
135		shm->channels = 2;
136	else
137		shm->channels = 1;
138
139    rc = ioctl(audio_fd, SNDCTL_DSP_SPEED, &shm->speed);
140    if (rc < 0)
141    {
142		perror("/dev/dsp");
143        Con_Printf("Could not set /dev/dsp speed to %d", shm->speed);
144		close(audio_fd);
145        return 0;
146    }
147
148    if (shm->samplebits == 16)
149    {
150        rc = AFMT_S16_LE;
151        rc = ioctl(audio_fd, SNDCTL_DSP_SETFMT, &rc);
152        if (rc < 0)
153		{
154			perror("/dev/dsp");
155			Con_Printf("Could not support 16-bit data.  Try 8-bit.\n");
156			close(audio_fd);
157			return 0;
158		}
159    }
160    else if (shm->samplebits == 8)
161    {
162        rc = AFMT_U8;
163        rc = ioctl(audio_fd, SNDCTL_DSP_SETFMT, &rc);
164        if (rc < 0)
165		{
166			perror("/dev/dsp");
167			Con_Printf("Could not support 8-bit data.\n");
168			close(audio_fd);
169			return 0;
170		}
171    }
172	else
173	{
174		perror("/dev/dsp");
175		Con_Printf("%d-bit sound not supported.", shm->samplebits);
176		close(audio_fd);
177		return 0;
178	}
179
180// toggle the trigger & start her up
181
182    tmp = 0;
183    rc  = ioctl(audio_fd, SNDCTL_DSP_SETTRIGGER, &tmp);
184	if (rc < 0)
185	{
186		perror("/dev/dsp");
187		Con_Printf("Could not toggle.\n");
188		close(audio_fd);
189		return 0;
190	}
191    tmp = PCM_ENABLE_OUTPUT;
192    rc = ioctl(audio_fd, SNDCTL_DSP_SETTRIGGER, &tmp);
193	if (rc < 0)
194	{
195		perror("/dev/dsp");
196		Con_Printf("Could not toggle.\n");
197		close(audio_fd);
198		return 0;
199	}
200
201	shm->samplepos = 0;
202
203	snd_inited = 1;
204	return 1;
205
206}
207
208int SNDDMA_GetDMAPos(void)
209{
210
211	struct count_info count;
212
213	if (!snd_inited) return 0;
214
215	if (ioctl(audio_fd, SNDCTL_DSP_GETOPTR, &count)==-1)
216	{
217		perror("/dev/dsp");
218		Con_Printf("Uh, sound dead.\n");
219		close(audio_fd);
220		snd_inited = 0;
221		return 0;
222	}
223//	shm->samplepos = (count.bytes / (shm->samplebits / 8)) & (shm->samples-1);
224//	fprintf(stderr, "%d    \r", count.ptr);
225	shm->samplepos = count.ptr / (shm->samplebits / 8);
226
227	return shm->samplepos;
228
229}
230
231void SNDDMA_Shutdown(void)
232{
233	if (snd_inited)
234	{
235		close(audio_fd);
236		snd_inited = 0;
237	}
238}
239
240/*
241==============
242SNDDMA_Submit
243
244Send sound to device if buffer isn't really the dma buffer
245===============
246*/
247void SNDDMA_Submit(void)
248{
249}
250
251