Main Page | Class Hierarchy | Alphabetical List | Data Structures | Directories | File List | Data Fields | Globals

linux_snd.c

Go to the documentation of this file.
00001 /*
00002 ===========================================================================
00003 Copyright (C) 1999-2005 Id Software, Inc.
00004 
00005 This file is part of Quake III Arena source code.
00006 
00007 Quake III Arena source code is free software; you can redistribute it
00008 and/or modify it under the terms of the GNU General Public License as
00009 published by the Free Software Foundation; either version 2 of the License,
00010 or (at your option) any later version.
00011 
00012 Quake III Arena source code is distributed in the hope that it will be
00013 useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
00014 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00015 GNU General Public License for more details.
00016 
00017 You should have received a copy of the GNU General Public License
00018 along with Foobar; if not, write to the Free Software
00019 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
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 /* Some devices may work only with 48000 */
00051 static int tryrates[] = { 22050, 11025, 44100, 48000, 8000 };
00052 
00053 static qboolean use_custom_memset = qfalse;
00054 // https://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=371 
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     // char *s; // bk001204 - unused
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     // open /dev/dsp, confirm capability to mmap, and get size of dma buffer
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     /* SNDCTL_DSP_GETOSPACE moved to be called later */
00124     
00125     // set sample bits & speed
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 /*  mmap() call moved forward */
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     // memory map the dma buffer
00209 
00210   // TTimo 2001/10/08 added PROT_READ to the mmap
00211   // https://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=371
00212   // checking Alsa bug, doesn't allow dma alloc with PROT_READ?
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     // NOTE TTimo could add a variable to force using regular memset on systems that are known to be safe
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     // toggle the trigger & start her up
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 SNDDMA_Submit
00283 
00284 Send sound to device if buffer isn't really the dma buffer
00285 ===============
00286 */
00287 void SNDDMA_Submit(void)
00288 {
00289 }
00290 
00291 void SNDDMA_BeginPainting (void)
00292 {
00293 }

Generated on Thu Aug 25 12:38:04 2005 for Quake III Arena by  doxygen 1.3.9.1