00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022 #include <unistd.h>
00023 #include <fcntl.h>
00024 #include <stdlib.h>
00025 #include <sys/types.h>
00026 #include <sys/ioctl.h>
00027 #include <sys/mman.h>
00028 #include <sys/shm.h>
00029 #include <sys/wait.h>
00030 #ifdef __linux__ // rb0101023 - guard this
00031 #include <linux/soundcard.h>
00032 #endif
00033 #ifdef __FreeBSD__ // rb0101023 - added
00034 #include <sys/soundcard.h>
00035 #endif
00036 #include <stdio.h>
00037
00038 #include "../game/q_shared.h"
00039 #include "../client/snd_local.h"
00040
00041 int audio_fd;
00042 int snd_inited=0;
00043
00044 cvar_t *sndbits;
00045 cvar_t *sndspeed;
00046 cvar_t *sndchannels;
00047
00048 cvar_t *snddevice;
00049
00050
00051 static int tryrates[] = { 22050, 11025, 44100, 48000, 8000 };
00052
00053 static qboolean use_custom_memset = qfalse;
00054
00055 void Snd_Memset (void* dest, const int val, const size_t count)
00056 {
00057 int *pDest;
00058 int i, iterate;
00059
00060 if (!use_custom_memset)
00061 {
00062 Com_Memset(dest,val,count);
00063 return;
00064 }
00065 iterate = count / sizeof(int);
00066 pDest = (int*)dest;
00067 for(i=0; i<iterate; i++)
00068 {
00069 pDest[i] = val;
00070 }
00071 }
00072
00073 qboolean SNDDMA_Init(void)
00074 {
00075 int rc;
00076 int fmt;
00077 int tmp;
00078 int i;
00079
00080 struct audio_buf_info info;
00081 int caps;
00082 extern uid_t saved_euid;
00083
00084 if (snd_inited)
00085 return 1;
00086
00087 if (!snddevice) {
00088 sndbits = Cvar_Get("sndbits", "16", CVAR_ARCHIVE);
00089 sndspeed = Cvar_Get("sndspeed", "0", CVAR_ARCHIVE);
00090 sndchannels = Cvar_Get("sndchannels", "2", CVAR_ARCHIVE);
00091 snddevice = Cvar_Get("snddevice", "/dev/dsp", CVAR_ARCHIVE);
00092 }
00093
00094
00095 if (!audio_fd) {
00096 seteuid(saved_euid);
00097
00098 audio_fd = open(snddevice->string, O_RDWR);
00099
00100 seteuid(getuid());
00101
00102 if (audio_fd < 0) {
00103 perror(snddevice->string);
00104 Com_Printf("Could not open %s\n", snddevice->string);
00105 return 0;
00106 }
00107 }
00108
00109 if (ioctl(audio_fd, SNDCTL_DSP_GETCAPS, &caps) == -1) {
00110 perror(snddevice->string);
00111 Com_Printf("Sound driver too old\n");
00112 close(audio_fd);
00113 return 0;
00114 }
00115
00116 if (!(caps & DSP_CAP_TRIGGER) || !(caps & DSP_CAP_MMAP)) {
00117 Com_Printf("Sorry but your soundcard can't do this\n");
00118 close(audio_fd);
00119 return 0;
00120 }
00121
00122
00123
00124
00125
00126 dma.samplebits = (int)sndbits->value;
00127 if (dma.samplebits != 16 && dma.samplebits != 8) {
00128 ioctl(audio_fd, SNDCTL_DSP_GETFMTS, &fmt);
00129 if (fmt & AFMT_S16_LE)
00130 dma.samplebits = 16;
00131 else if (fmt & AFMT_U8)
00132 dma.samplebits = 8;
00133 }
00134
00135 dma.speed = (int)sndspeed->value;
00136 if (!dma.speed) {
00137 for (i=0 ; i<sizeof(tryrates)/4 ; i++)
00138 if (!ioctl(audio_fd, SNDCTL_DSP_SPEED, &tryrates[i]))
00139 break;
00140 dma.speed = tryrates[i];
00141 }
00142
00143 dma.channels = (int)sndchannels->value;
00144 if (dma.channels < 1 || dma.channels > 2)
00145 dma.channels = 2;
00146
00147
00148
00149 tmp = 0;
00150 if (dma.channels == 2)
00151 tmp = 1;
00152 rc = ioctl(audio_fd, SNDCTL_DSP_STEREO, &tmp);
00153 if (rc < 0) {
00154 perror(snddevice->string);
00155 Com_Printf("Could not set %s to stereo=%d", snddevice->string, dma.channels);
00156 close(audio_fd);
00157 return 0;
00158 }
00159
00160 if (tmp)
00161 dma.channels = 2;
00162 else
00163 dma.channels = 1;
00164
00165 rc = ioctl(audio_fd, SNDCTL_DSP_SPEED, &dma.speed);
00166 if (rc < 0) {
00167 perror(snddevice->string);
00168 Com_Printf("Could not set %s speed to %d", snddevice->string, dma.speed);
00169 close(audio_fd);
00170 return 0;
00171 }
00172
00173 if (dma.samplebits == 16) {
00174 rc = AFMT_S16_LE;
00175 rc = ioctl(audio_fd, SNDCTL_DSP_SETFMT, &rc);
00176 if (rc < 0) {
00177 perror(snddevice->string);
00178 Com_Printf("Could not support 16-bit data. Try 8-bit.\n");
00179 close(audio_fd);
00180 return 0;
00181 }
00182 } else if (dma.samplebits == 8) {
00183 rc = AFMT_U8;
00184 rc = ioctl(audio_fd, SNDCTL_DSP_SETFMT, &rc);
00185 if (rc < 0) {
00186 perror(snddevice->string);
00187 Com_Printf("Could not support 8-bit data.\n");
00188 close(audio_fd);
00189 return 0;
00190 }
00191 } else {
00192 perror(snddevice->string);
00193 Com_Printf("%d-bit sound not supported.", dma.samplebits);
00194 close(audio_fd);
00195 return 0;
00196 }
00197
00198 if (ioctl(audio_fd, SNDCTL_DSP_GETOSPACE, &info)==-1) {
00199 perror("GETOSPACE");
00200 Com_Printf("Um, can't do GETOSPACE?\n");
00201 close(audio_fd);
00202 return 0;
00203 }
00204
00205 dma.samples = info.fragstotal * info.fragsize / (dma.samplebits/8);
00206 dma.submission_chunk = 1;
00207
00208
00209
00210
00211
00212
00213
00214 if (!dma.buffer)
00215 dma.buffer = (unsigned char *) mmap(NULL, info.fragstotal
00216 * info.fragsize, PROT_WRITE|PROT_READ, MAP_FILE|MAP_SHARED, audio_fd, 0);
00217
00218 if (dma.buffer == MAP_FAILED)
00219 {
00220 Com_Printf("Could not mmap dma buffer PROT_WRITE|PROT_READ\n");
00221 Com_Printf("trying mmap PROT_WRITE (with associated better compatibility / less performance code)\n");
00222 dma.buffer = (unsigned char *) mmap(NULL, info.fragstotal
00223 * info.fragsize, PROT_WRITE, MAP_FILE|MAP_SHARED, audio_fd, 0);
00224
00225 use_custom_memset = qtrue;
00226 }
00227
00228 if (dma.buffer == MAP_FAILED) {
00229 perror(snddevice->string);
00230 Com_Printf("Could not mmap %s\n", snddevice->string);
00231 close(audio_fd);
00232 return 0;
00233 }
00234
00235
00236
00237 tmp = 0;
00238 rc = ioctl(audio_fd, SNDCTL_DSP_SETTRIGGER, &tmp);
00239 if (rc < 0) {
00240 perror(snddevice->string);
00241 Com_Printf("Could not toggle.\n");
00242 close(audio_fd);
00243 return 0;
00244 }
00245
00246 tmp = PCM_ENABLE_OUTPUT;
00247 rc = ioctl(audio_fd, SNDCTL_DSP_SETTRIGGER, &tmp);
00248 if (rc < 0) {
00249 perror(snddevice->string);
00250 Com_Printf("Could not toggle.\n");
00251 close(audio_fd);
00252
00253 return 0;
00254 }
00255
00256 snd_inited = 1;
00257 return 1;
00258 }
00259
00260 int SNDDMA_GetDMAPos(void)
00261 {
00262 struct count_info count;
00263
00264 if (!snd_inited) return 0;
00265
00266 if (ioctl(audio_fd, SNDCTL_DSP_GETOPTR, &count) == -1) {
00267 perror(snddevice->string);
00268 Com_Printf("Uh, sound dead.\n");
00269 close(audio_fd);
00270 snd_inited = 0;
00271 return 0;
00272 }
00273 return count.ptr / (dma.samplebits / 8);
00274 }
00275
00276 void SNDDMA_Shutdown(void)
00277 {
00278 }
00279
00280
00281
00282
00283
00284
00285
00286
00287 void SNDDMA_Submit(void)
00288 {
00289 }
00290
00291 void SNDDMA_BeginPainting (void)
00292 {
00293 }