Quake-2

Quake 2 GPL Source Release
Log | Files | Refs

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