2
===========================================================================
3
Copyright (C) 1999-2005 Id Software, Inc.
5
This file is part of Quake III Arena source code.
7
Quake III Arena source code is free software; you can redistribute it
8
and/or modify it under the terms of the GNU General Public License as
9
published by the Free Software Foundation; either version 2 of the License,
10
or (at your option) any later version.
12
Quake III Arena source code is distributed in the hope that it will be
13
useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
14
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15
GNU General Public License for more details.
17
You should have received a copy of the GNU General Public License
18
along with Quake III Arena source code; if not, write to the Free Software
19
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
20
===========================================================================
28
#include <sys/types.h>
29
#include <sys/ioctl.h>
33
#ifdef __linux__ // rb0101023 - guard this
34
#include <linux/soundcard.h>
36
#ifdef __FreeBSD__ // rb0101023 - added
37
#include <sys/soundcard.h>
41
#include "../qcommon/q_shared.h"
42
#include "../client/snd_local.h"
53
/* Some devices may work only with 48000 */
54
static int tryrates[] = { 22050, 11025, 44100, 48000, 8000 };
56
static qboolean use_custom_memset = qfalse;
57
// https://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=371
58
void Snd_Memset (void* dest, const int val, const size_t count)
63
if (!use_custom_memset)
65
Com_Memset(dest,val,count);
68
iterate = count / sizeof(int);
70
for(i=0; i<iterate; i++)
76
qboolean SNDDMA_Init(void)
82
// char *s; // bk001204 - unused
83
struct audio_buf_info info;
90
sndbits = Cvar_Get("sndbits", "16", CVAR_ARCHIVE);
91
sndspeed = Cvar_Get("sndspeed", "0", CVAR_ARCHIVE);
92
sndchannels = Cvar_Get("sndchannels", "2", CVAR_ARCHIVE);
93
snddevice = Cvar_Get("snddevice", "/dev/dsp", CVAR_ARCHIVE);
96
// open /dev/dsp, confirm capability to mmap, and get size of dma buffer
98
audio_fd = open(snddevice->string, O_RDWR);
101
perror(snddevice->string);
102
Com_Printf("Could not open %s\n", snddevice->string);
107
if (ioctl(audio_fd, SNDCTL_DSP_GETCAPS, &caps) == -1) {
108
perror(snddevice->string);
109
Com_Printf("Sound driver too old\n");
114
if (!(caps & DSP_CAP_TRIGGER) || !(caps & DSP_CAP_MMAP)) {
115
Com_Printf("Sorry but your soundcard can't do this\n");
121
/* SNDCTL_DSP_GETOSPACE moved to be called later */
123
// set sample bits & speed
124
dma.samplebits = (int)sndbits->value;
125
if (dma.samplebits != 16 && dma.samplebits != 8) {
126
ioctl(audio_fd, SNDCTL_DSP_GETFMTS, &fmt);
127
if (fmt & AFMT_S16_LE)
129
else if (fmt & AFMT_U8)
133
dma.speed = (int)sndspeed->value;
135
for (i=0 ; i<sizeof(tryrates)/4 ; i++)
136
if (!ioctl(audio_fd, SNDCTL_DSP_SPEED, &tryrates[i]))
138
dma.speed = tryrates[i];
141
dma.channels = (int)sndchannels->value;
142
if (dma.channels < 1 || dma.channels > 2)
145
/* mmap() call moved forward */
148
if (dma.channels == 2)
150
rc = ioctl(audio_fd, SNDCTL_DSP_STEREO, &tmp);
152
perror(snddevice->string);
153
Com_Printf("Could not set %s to stereo=%d", snddevice->string, dma.channels);
163
rc = ioctl(audio_fd, SNDCTL_DSP_SPEED, &dma.speed);
165
perror(snddevice->string);
166
Com_Printf("Could not set %s speed to %d", snddevice->string, dma.speed);
171
if (dma.samplebits == 16) {
173
rc = ioctl(audio_fd, SNDCTL_DSP_SETFMT, &rc);
175
perror(snddevice->string);
176
Com_Printf("Could not support 16-bit data. Try 8-bit.\n");
180
} else if (dma.samplebits == 8) {
182
rc = ioctl(audio_fd, SNDCTL_DSP_SETFMT, &rc);
184
perror(snddevice->string);
185
Com_Printf("Could not support 8-bit data.\n");
190
perror(snddevice->string);
191
Com_Printf("%d-bit sound not supported.", dma.samplebits);
196
if (ioctl(audio_fd, SNDCTL_DSP_GETOSPACE, &info)==-1) {
198
Com_Printf("Um, can't do GETOSPACE?\n");
203
dma.samples = info.fragstotal * info.fragsize / (dma.samplebits/8);
204
dma.submission_chunk = 1;
206
// memory map the dma buffer
208
// TTimo 2001/10/08 added PROT_READ to the mmap
209
// https://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=371
210
// checking Alsa bug, doesn't allow dma alloc with PROT_READ?
213
dma.buffer = (unsigned char *) mmap(NULL, info.fragstotal
214
* info.fragsize, PROT_WRITE|PROT_READ, MAP_FILE|MAP_SHARED, audio_fd, 0);
216
if (dma.buffer == MAP_FAILED)
218
Com_Printf("Could not mmap dma buffer PROT_WRITE|PROT_READ\n");
219
Com_Printf("trying mmap PROT_WRITE (with associated better compatibility / less performance code)\n");
220
dma.buffer = (unsigned char *) mmap(NULL, info.fragstotal
221
* info.fragsize, PROT_WRITE, MAP_FILE|MAP_SHARED, audio_fd, 0);
222
// NOTE TTimo could add a variable to force using regular memset on systems that are known to be safe
223
use_custom_memset = qtrue;
226
if (dma.buffer == MAP_FAILED) {
227
perror(snddevice->string);
228
Com_Printf("Could not mmap %s\n", snddevice->string);
233
// toggle the trigger & start her up
236
rc = ioctl(audio_fd, SNDCTL_DSP_SETTRIGGER, &tmp);
238
perror(snddevice->string);
239
Com_Printf("Could not toggle.\n");
244
tmp = PCM_ENABLE_OUTPUT;
245
rc = ioctl(audio_fd, SNDCTL_DSP_SETTRIGGER, &tmp);
247
perror(snddevice->string);
248
Com_Printf("Could not toggle.\n");
258
int SNDDMA_GetDMAPos(void)
260
struct count_info count;
262
if (!snd_inited) return 0;
264
if (ioctl(audio_fd, SNDCTL_DSP_GETOPTR, &count) == -1) {
265
perror(snddevice->string);
266
Com_Printf("Uh, sound dead.\n");
271
return count.ptr / (dma.samplebits / 8);
274
void SNDDMA_Shutdown(void)
282
Send sound to device if buffer isn't really the dma buffer
285
void SNDDMA_Submit(void)
289
void SNDDMA_BeginPainting (void)
293
#endif // !USE_SDL_SOUND