~ubuntu-branches/ubuntu/hardy/openarena/hardy-backports

« back to all changes in this revision

Viewing changes to code/unix/linux_snd.c

  • Committer: Bazaar Package Importer
  • Author(s): Bruno "Fuddl" Kleinert
  • Date: 2007-01-20 12:28:09 UTC
  • Revision ID: james.westby@ubuntu.com-20070120122809-2yza5ojt7nqiyiam
Tags: upstream-0.6.0
ImportĀ upstreamĀ versionĀ 0.6.0

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
===========================================================================
 
3
Copyright (C) 1999-2005 Id Software, Inc.
 
4
 
 
5
This file is part of Quake III Arena source code.
 
6
 
 
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.
 
11
 
 
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.
 
16
 
 
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
===========================================================================
 
21
*/
 
22
 
 
23
#if !USE_SDL_SOUND
 
24
 
 
25
#include <unistd.h>
 
26
#include <fcntl.h>
 
27
#include <stdlib.h>
 
28
#include <sys/types.h>
 
29
#include <sys/ioctl.h>
 
30
#include <sys/mman.h>
 
31
#include <sys/shm.h>
 
32
#include <sys/wait.h>
 
33
#ifdef __linux__ // rb0101023 - guard this
 
34
#include <linux/soundcard.h>
 
35
#endif
 
36
#ifdef __FreeBSD__ // rb0101023 - added
 
37
#include <sys/soundcard.h>
 
38
#endif
 
39
#include <stdio.h>
 
40
 
 
41
#include "../qcommon/q_shared.h"
 
42
#include "../client/snd_local.h"
 
43
 
 
44
int audio_fd;
 
45
int snd_inited=0;
 
46
 
 
47
cvar_t *sndbits;
 
48
cvar_t *sndspeed;
 
49
cvar_t *sndchannels;
 
50
 
 
51
cvar_t *snddevice;
 
52
 
 
53
/* Some devices may work only with 48000 */
 
54
static int tryrates[] = { 22050, 11025, 44100, 48000, 8000 };
 
55
 
 
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)
 
59
{
 
60
  int *pDest;
 
61
  int i, iterate;
 
62
 
 
63
  if (!use_custom_memset)
 
64
  {
 
65
    Com_Memset(dest,val,count);
 
66
    return;
 
67
  }
 
68
  iterate = count / sizeof(int);
 
69
  pDest = (int*)dest;
 
70
  for(i=0; i<iterate; i++)
 
71
  {
 
72
    pDest[i] = val;
 
73
  }
 
74
}
 
75
 
 
76
qboolean SNDDMA_Init(void)
 
77
{
 
78
        int rc;
 
79
    int fmt;
 
80
        int tmp;
 
81
    int i;
 
82
    // char *s; // bk001204 - unused
 
83
        struct audio_buf_info info;
 
84
        int caps;
 
85
 
 
86
        if (snd_inited)
 
87
                return 1;
 
88
 
 
89
        if (!snddevice) {
 
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);
 
94
        }
 
95
 
 
96
        // open /dev/dsp, confirm capability to mmap, and get size of dma buffer
 
97
        if (!audio_fd) {
 
98
                audio_fd = open(snddevice->string, O_RDWR);
 
99
 
 
100
                if (audio_fd < 0) {
 
101
                        perror(snddevice->string);
 
102
                        Com_Printf("Could not open %s\n", snddevice->string);
 
103
                        return 0;
 
104
                        }
 
105
        }
 
106
 
 
107
        if (ioctl(audio_fd, SNDCTL_DSP_GETCAPS, &caps) == -1) {
 
108
                perror(snddevice->string);
 
109
        Com_Printf("Sound driver too old\n");
 
110
                close(audio_fd);
 
111
                return 0;
 
112
        }
 
113
 
 
114
        if (!(caps & DSP_CAP_TRIGGER) || !(caps & DSP_CAP_MMAP)) {
 
115
                Com_Printf("Sorry but your soundcard can't do this\n");
 
116
                close(audio_fd);
 
117
                return 0;
 
118
        }
 
119
 
 
120
 
 
121
        /* SNDCTL_DSP_GETOSPACE moved to be called later */
 
122
    
 
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) 
 
128
                        dma.samplebits = 16;
 
129
        else if (fmt & AFMT_U8) 
 
130
                        dma.samplebits = 8;
 
131
    }
 
132
 
 
133
        dma.speed = (int)sndspeed->value;
 
134
        if (!dma.speed) {
 
135
        for (i=0 ; i<sizeof(tryrates)/4 ; i++)
 
136
            if (!ioctl(audio_fd, SNDCTL_DSP_SPEED, &tryrates[i])) 
 
137
                                break;
 
138
        dma.speed = tryrates[i];
 
139
    }
 
140
 
 
141
        dma.channels = (int)sndchannels->value;
 
142
        if (dma.channels < 1 || dma.channels > 2)
 
143
                dma.channels = 2;
 
144
        
 
145
/*  mmap() call moved forward */
 
146
 
 
147
        tmp = 0;
 
148
        if (dma.channels == 2)
 
149
                tmp = 1;
 
150
    rc = ioctl(audio_fd, SNDCTL_DSP_STEREO, &tmp);
 
151
    if (rc < 0) {
 
152
                perror(snddevice->string);
 
153
        Com_Printf("Could not set %s to stereo=%d", snddevice->string, dma.channels);
 
154
                close(audio_fd);
 
155
        return 0;
 
156
    }
 
157
 
 
158
        if (tmp)
 
159
                dma.channels = 2;
 
160
        else
 
161
                dma.channels = 1;
 
162
 
 
163
    rc = ioctl(audio_fd, SNDCTL_DSP_SPEED, &dma.speed);
 
164
    if (rc < 0) {
 
165
                perror(snddevice->string);
 
166
        Com_Printf("Could not set %s speed to %d", snddevice->string, dma.speed);
 
167
                close(audio_fd);
 
168
        return 0;
 
169
    }
 
170
 
 
171
    if (dma.samplebits == 16) {
 
172
        rc = AFMT_S16_LE;
 
173
        rc = ioctl(audio_fd, SNDCTL_DSP_SETFMT, &rc);
 
174
        if (rc < 0) {
 
175
                        perror(snddevice->string);
 
176
                        Com_Printf("Could not support 16-bit data.  Try 8-bit.\n");
 
177
                        close(audio_fd);
 
178
                        return 0;
 
179
                }
 
180
    } else if (dma.samplebits == 8) {
 
181
        rc = AFMT_U8;
 
182
        rc = ioctl(audio_fd, SNDCTL_DSP_SETFMT, &rc);
 
183
        if (rc < 0) {
 
184
                        perror(snddevice->string);
 
185
                        Com_Printf("Could not support 8-bit data.\n");
 
186
                        close(audio_fd);
 
187
                        return 0;
 
188
                }
 
189
    } else {
 
190
                perror(snddevice->string);
 
191
                Com_Printf("%d-bit sound not supported.", dma.samplebits);
 
192
                close(audio_fd);
 
193
                return 0;
 
194
        }
 
195
 
 
196
    if (ioctl(audio_fd, SNDCTL_DSP_GETOSPACE, &info)==-1) {   
 
197
        perror("GETOSPACE");
 
198
                Com_Printf("Um, can't do GETOSPACE?\n");
 
199
                close(audio_fd);
 
200
                return 0;
 
201
    }
 
202
 
 
203
        dma.samples = info.fragstotal * info.fragsize / (dma.samplebits/8);
 
204
        dma.submission_chunk = 1;
 
205
 
 
206
        // memory map the dma buffer
 
207
 
 
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?
 
211
 
 
212
        if (!dma.buffer)
 
213
                dma.buffer = (unsigned char *) mmap(NULL, info.fragstotal
 
214
                        * info.fragsize, PROT_WRITE|PROT_READ, MAP_FILE|MAP_SHARED, audio_fd, 0);
 
215
 
 
216
  if (dma.buffer == MAP_FAILED)
 
217
  {
 
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;
 
224
  }
 
225
 
 
226
        if (dma.buffer == MAP_FAILED) {
 
227
                perror(snddevice->string);
 
228
                Com_Printf("Could not mmap %s\n", snddevice->string);
 
229
                close(audio_fd);
 
230
                return 0;
 
231
        }
 
232
 
 
233
        // toggle the trigger & start her up
 
234
 
 
235
  tmp = 0;
 
236
  rc  = ioctl(audio_fd, SNDCTL_DSP_SETTRIGGER, &tmp);
 
237
        if (rc < 0) {
 
238
                perror(snddevice->string);
 
239
                Com_Printf("Could not toggle.\n");
 
240
                close(audio_fd);
 
241
                return 0;
 
242
        }
 
243
 
 
244
  tmp = PCM_ENABLE_OUTPUT;
 
245
  rc = ioctl(audio_fd, SNDCTL_DSP_SETTRIGGER, &tmp);
 
246
        if (rc < 0) {
 
247
                perror(snddevice->string);
 
248
                Com_Printf("Could not toggle.\n");
 
249
                close(audio_fd);
 
250
 
 
251
                return 0;
 
252
        }
 
253
 
 
254
        snd_inited = 1;
 
255
        return 1;
 
256
}
 
257
 
 
258
int SNDDMA_GetDMAPos(void)
 
259
{
 
260
        struct count_info count;
 
261
 
 
262
        if (!snd_inited) return 0;
 
263
 
 
264
        if (ioctl(audio_fd, SNDCTL_DSP_GETOPTR, &count) == -1) {
 
265
                perror(snddevice->string);
 
266
                Com_Printf("Uh, sound dead.\n");
 
267
                close(audio_fd);
 
268
                snd_inited = 0;
 
269
                return 0;
 
270
        }
 
271
        return count.ptr / (dma.samplebits / 8);
 
272
}
 
273
 
 
274
void SNDDMA_Shutdown(void)
 
275
{
 
276
}
 
277
 
 
278
/*
 
279
==============
 
280
SNDDMA_Submit
 
281
 
 
282
Send sound to device if buffer isn't really the dma buffer
 
283
===============
 
284
*/
 
285
void SNDDMA_Submit(void)
 
286
{
 
287
}
 
288
 
 
289
void SNDDMA_BeginPainting (void)
 
290
{
 
291
}
 
292
 
 
293
#endif // !USE_SDL_SOUND
 
294