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