X-Git-Url: http://de.git.xonotic.org/?p=xonotic%2Fdarkplaces.git;a=blobdiff_plain;f=snd_oss.c;h=9926b800642fce99d9e6c569a34668b969e8945e;hp=4579e40d640c2352da25e4cdef47268c28224468;hb=2075ae43356d724bae305ce8fd36ea570718b14a;hpb=4483445507f0d342d8c7f183c74ecda391f3a73a diff --git a/snd_oss.c b/snd_oss.c index 4579e40d..9926b800 100644 --- a/snd_oss.c +++ b/snd_oss.c @@ -8,7 +8,7 @@ of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. @@ -17,253 +17,328 @@ along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ -#include + +// OSS module, used by Linux and FreeBSD + +#include "quakedef.h" + +#include #include -#include -#include #include -#include -#include -#include -#include -#include -#include "quakedef.h" +#include +#include + +#include "snd_main.h" -int audio_fd; -int snd_inited; -static int tryrates[] = { 11025, 22051, 44100, 8000 }; +#define NB_FRAGMENTS 4 -qboolean SNDDMA_Init(void) +static int audio_fd = -1; +static int old_osstime = 0; +static unsigned int osssoundtime; + + +/* +==================== +SndSys_Init + +Create "snd_renderbuffer" with the proper sound format if the call is successful +May return a suggested format if the requested format isn't available +==================== +*/ +qboolean SndSys_Init (const snd_format_t* requested, snd_format_t* suggested) { + int flags, ioctl_param, prev_value; + unsigned int fragmentsize; + + Con_DPrint("SndSys_Init: using the OSS module\n"); - int rc; - int fmt; - int tmp; - int i; - char *s; - struct audio_buf_info info; - int caps; + // Check the requested sound format + if (requested->width < 1 || requested->width > 2) + { + Con_Printf("SndSys_Init: invalid sound width (%hu)\n", + requested->width); - snd_inited = 0; + if (suggested != NULL) + { + memcpy(suggested, requested, sizeof(*suggested)); -// open /dev/dsp, confirm capability to mmap, and get size of dma buffer + if (requested->width < 1) + suggested->width = 1; + else + suggested->width = 2; + } + + return false; + } - audio_fd = open("/dev/dsp", O_RDWR); - if (audio_fd < 0) + // Open /dev/dsp + audio_fd = open("/dev/dsp", O_WRONLY); + if (audio_fd < 0) { perror("/dev/dsp"); - Con_Printf("Could not open /dev/dsp\n"); - return 0; + Con_Print("SndSys_Init: could not open /dev/dsp\n"); + return false; } - - rc = ioctl(audio_fd, SNDCTL_DSP_RESET, 0); - if (rc < 0) + + // Use non-blocking IOs if possible + flags = fcntl(audio_fd, F_GETFL); + if (flags != -1) { - perror("/dev/dsp"); - Con_Printf("Could not reset /dev/dsp\n"); - close(audio_fd); - return 0; + if (fcntl(audio_fd, F_SETFL, flags | O_NONBLOCK) == -1) + Con_Print("SndSys_Init : fcntl(F_SETFL, O_NONBLOCK) failed!\n"); } + else + Con_Print("SndSys_Init: fcntl(F_GETFL) failed!\n"); + + // Set the fragment size (up to "NB_FRAGMENTS" fragments of "fragmentsize" bytes) + fragmentsize = requested->speed * requested->channels * requested->width / 10; + fragmentsize = (unsigned int)ceilf((float)fragmentsize / (float)NB_FRAGMENTS); + fragmentsize = CeilPowerOf2(fragmentsize); + ioctl_param = (NB_FRAGMENTS << 16) | log2i(fragmentsize); + if (ioctl(audio_fd, SNDCTL_DSP_SETFRAGMENT, &ioctl_param) == -1) + { + Con_Print ("SndSys_Init: could not set the fragment size\n"); + SndSys_Shutdown (); + return false; + } + Con_Printf ("SndSys_Init: using %u fragments of %u bytes\n", + ioctl_param >> 16, 1 << (ioctl_param & 0xFFFF)); - if (ioctl(audio_fd, SNDCTL_DSP_GETCAPS, &caps)==-1) + // Set the sound width + if (requested->width == 1) + ioctl_param = AFMT_U8; + else + ioctl_param = AFMT_S16_NE; + prev_value = ioctl_param; + if (ioctl(audio_fd, SNDCTL_DSP_SETFMT, &ioctl_param) == -1 || + ioctl_param != prev_value) { - perror("/dev/dsp"); - Con_Printf("Sound driver too old\n"); - close(audio_fd); - return 0; + if (ioctl_param != prev_value && suggested != NULL) + { + memcpy(suggested, requested, sizeof(*suggested)); + + if (ioctl_param == AFMT_S16_NE) + suggested->width = 2; + else + suggested->width = 1; + } + + Con_Printf("SndSys_Init: could not set the sound width to %hu\n", + requested->width); + SndSys_Shutdown(); + return false; } - if (!(caps & DSP_CAP_TRIGGER) || !(caps & DSP_CAP_MMAP)) + // Set the sound channels + ioctl_param = requested->channels; + if (ioctl(audio_fd, SNDCTL_DSP_CHANNELS, &ioctl_param) == -1 || + ioctl_param != requested->channels) { - Con_Printf("Sorry but your soundcard can't do this\n"); - close(audio_fd); - return 0; + if (ioctl_param != requested->channels && suggested != NULL) + { + memcpy(suggested, requested, sizeof(*suggested)); + suggested->channels = ioctl_param; + } + + Con_Printf("SndSys_Init: could not set the number of channels to %hu\n", + requested->channels); + SndSys_Shutdown(); + return false; } - if (ioctl(audio_fd, SNDCTL_DSP_GETOSPACE, &info)==-1) - { - perror("GETOSPACE"); - Con_Printf("Um, can't do GETOSPACE?\n"); - close(audio_fd); - return 0; - } - - shm = &sn; - shm->splitbuffer = 0; - -// set sample bits & speed - - s = getenv("QUAKE_SOUND_SAMPLEBITS"); - if (s) shm->samplebits = atoi(s); - else if ((i = COM_CheckParm("-sndbits")) != 0) - shm->samplebits = atoi(com_argv[i+1]); - if (shm->samplebits != 16 && shm->samplebits != 8) - { - ioctl(audio_fd, SNDCTL_DSP_GETFMTS, &fmt); - if (fmt & AFMT_S16_LE) shm->samplebits = 16; - else if (fmt & AFMT_U8) shm->samplebits = 8; - } + // Set the sound speed + ioctl_param = requested->speed; + if (ioctl(audio_fd, SNDCTL_DSP_SPEED, &ioctl_param) == -1 || + (unsigned int)ioctl_param != requested->speed) + { + if ((unsigned int)ioctl_param != requested->speed && suggested != NULL) + { + memcpy(suggested, requested, sizeof(*suggested)); + suggested->speed = ioctl_param; + } - s = getenv("QUAKE_SOUND_SPEED"); - if (s) shm->speed = atoi(s); - else if ((i = COM_CheckParm("-sndspeed")) != 0) - shm->speed = atoi(com_argv[i+1]); - else - { - for (i=0 ; ispeed = tryrates[i]; - } + Con_Printf("SndSys_Init: could not set the sound speed to %u\n", + requested->speed); + SndSys_Shutdown(); + return false; + } - s = getenv("QUAKE_SOUND_CHANNELS"); - if (s) shm->channels = atoi(s); - else if ((i = COM_CheckParm("-sndmono")) != 0) - shm->channels = 1; - else if ((i = COM_CheckParm("-sndstereo")) != 0) - shm->channels = 2; - else shm->channels = 2; + // TOCHECK: I'm not sure which channel layout OSS uses for 5.1 and 7.1 + if (snd_channellayout.integer == SND_CHANNELLAYOUT_AUTO) + Cvar_SetValueQuick (&snd_channellayout, SND_CHANNELLAYOUT_ALSA); - shm->samples = info.fragstotal * info.fragsize / (shm->samplebits/8); - shm->submission_chunk = 1; + old_osstime = 0; + osssoundtime = 0; + snd_renderbuffer = Snd_CreateRingBuffer(requested, 0, NULL); + return true; +} -// memory map the dma buffer - shm->buffer = (unsigned char *) mmap(NULL, info.fragstotal - * info.fragsize, PROT_WRITE, MAP_FILE|MAP_SHARED, audio_fd, 0); - if (!shm->buffer || shm->buffer == (unsigned char *)-1) +/* +==================== +SndSys_Shutdown + +Stop the sound card, delete "snd_renderbuffer" and free its other resources +==================== +*/ +void SndSys_Shutdown (void) +{ + // Stop the sound and close the device + if (audio_fd >= 0) { - perror("/dev/dsp"); - Con_Printf("Could not mmap /dev/dsp\n"); + ioctl(audio_fd, SNDCTL_DSP_RESET, NULL); close(audio_fd); - return 0; + audio_fd = -1; } - tmp = 0; - if (shm->channels == 2) - tmp = 1; - rc = ioctl(audio_fd, SNDCTL_DSP_STEREO, &tmp); - if (rc < 0) - { - perror("/dev/dsp"); - Con_Printf("Could not set /dev/dsp to stereo=%d", shm->channels); - close(audio_fd); - return 0; - } - if (tmp) - shm->channels = 2; - else - shm->channels = 1; + if (snd_renderbuffer != NULL) + { + Mem_Free(snd_renderbuffer->ring); + Mem_Free(snd_renderbuffer); + snd_renderbuffer = NULL; + } +} - rc = ioctl(audio_fd, SNDCTL_DSP_SPEED, &shm->speed); - if (rc < 0) - { - perror("/dev/dsp"); - Con_Printf("Could not set /dev/dsp speed to %d", shm->speed); - close(audio_fd); - return 0; - } - if (shm->samplebits == 16) - { - rc = AFMT_S16_LE; - rc = ioctl(audio_fd, SNDCTL_DSP_SETFMT, &rc); - if (rc < 0) - { - perror("/dev/dsp"); - Con_Printf("Could not support 16-bit data. Try 8-bit.\n"); - close(audio_fd); - return 0; - } - } - else if (shm->samplebits == 8) - { - rc = AFMT_U8; - rc = ioctl(audio_fd, SNDCTL_DSP_SETFMT, &rc); - if (rc < 0) - { - perror("/dev/dsp"); - Con_Printf("Could not support 8-bit data.\n"); - close(audio_fd); - return 0; - } - } - else +/* +==================== +SndSys_Write +==================== +*/ +static int SndSys_Write (const unsigned char* buffer, unsigned int nb_bytes) +{ + int written; + unsigned int factor; + + written = write (audio_fd, buffer, nb_bytes); + if (written < 0) { - perror("/dev/dsp"); - Con_Printf("%d-bit sound not supported.", shm->samplebits); - close(audio_fd); - return 0; + if (errno != EAGAIN) + Con_Printf ("SndSys_Write: audio write returned %d! (errno= %d)\n", + written, errno); + return written; } -// toggle the trigger & start her up + factor = snd_renderbuffer->format.width * snd_renderbuffer->format.channels; + if (written % factor != 0) + Sys_Error ("SndSys_Write: nb of bytes written (%d) isn't aligned to a frame sample!\n", + written); + + snd_renderbuffer->startframe += written / factor; - tmp = 0; - rc = ioctl(audio_fd, SNDCTL_DSP_SETTRIGGER, &tmp); - if (rc < 0) + if ((unsigned int)written < nb_bytes) { - perror("/dev/dsp"); - Con_Printf("Could not toggle.\n"); - close(audio_fd); - return 0; + Con_DPrintf("SndSys_Submit: audio can't keep up! (%u < %u)\n", + written, nb_bytes); } - tmp = PCM_ENABLE_OUTPUT; - rc = ioctl(audio_fd, SNDCTL_DSP_SETTRIGGER, &tmp); - if (rc < 0) + + return written; +} + + +/* +==================== +SndSys_Submit + +Submit the contents of "snd_renderbuffer" to the sound card +==================== +*/ +void SndSys_Submit (void) +{ + unsigned int startoffset, factor, limit, nbframes; + int written; + + if (audio_fd < 0 || + snd_renderbuffer->startframe == snd_renderbuffer->endframe) + return; + + startoffset = snd_renderbuffer->startframe % snd_renderbuffer->maxframes; + factor = snd_renderbuffer->format.width * snd_renderbuffer->format.channels; + limit = snd_renderbuffer->maxframes - startoffset; + nbframes = snd_renderbuffer->endframe - snd_renderbuffer->startframe; + if (nbframes > limit) { - perror("/dev/dsp"); - Con_Printf("Could not toggle.\n"); - close(audio_fd); - return 0; + written = SndSys_Write (&snd_renderbuffer->ring[startoffset * factor], limit * factor); + if (written < 0 || (unsigned int)written < limit * factor) + return; + + nbframes -= limit; + startoffset = 0; } - shm->samplepos = 0; + SndSys_Write (&snd_renderbuffer->ring[startoffset * factor], nbframes * factor); +} - snd_inited = 1; - return 1; -} +/* +==================== +SndSys_GetSoundTime -int SNDDMA_GetDMAPos(void) +Returns the number of sample frames consumed since the sound started +==================== +*/ +unsigned int SndSys_GetSoundTime (void) { - struct count_info count; + int new_osstime; + unsigned int timediff; - if (!snd_inited) return 0; - - if (ioctl(audio_fd, SNDCTL_DSP_GETOPTR, &count)==-1) + if (ioctl (audio_fd, SNDCTL_DSP_GETOPTR, &count) == -1) { - perror("/dev/dsp"); - Con_Printf("Uh, sound dead.\n"); - close(audio_fd); - snd_inited = 0; + Con_Print ("SndSys_GetSoundTimeDiff: can't ioctl (SNDCTL_DSP_GETOPTR)\n"); return 0; } -// shm->samplepos = (count.bytes / (shm->samplebits / 8)) & (shm->samples-1); -// fprintf(stderr, "%d \r", count.ptr); - shm->samplepos = count.ptr / (shm->samplebits / 8); + new_osstime = count.bytes / (snd_renderbuffer->format.width * snd_renderbuffer->format.channels); - return shm->samplepos; + if (new_osstime >= old_osstime) + timediff = new_osstime - old_osstime; + else + { + Con_Print ("SndSys_GetSoundTime: osstime wrapped\n"); + timediff = 0; + } + old_osstime = new_osstime; + osssoundtime += timediff; + return osssoundtime; } -void SNDDMA_Shutdown(void) + +/* +==================== +SndSys_LockRenderBuffer + +Get the exclusive lock on "snd_renderbuffer" +==================== +*/ +qboolean SndSys_LockRenderBuffer (void) { - if (snd_inited) - { - close(audio_fd); - snd_inited = 0; - } + // Nothing to do + return true; } + /* -============== -SNDDMA_Submit +==================== +SndSys_UnlockRenderBuffer -Send sound to device if buffer isn't really the dma buffer -=============== +Release the exclusive lock on "snd_renderbuffer" +==================== */ -void SNDDMA_Submit(void) +void SndSys_UnlockRenderBuffer (void) { + // Nothing to do } +/* +==================== +SndSys_SendKeyEvents + +Send keyboard events originating from the sound system (e.g. MIDI) +==================== +*/ +void SndSys_SendKeyEvents(void) +{ + // not supported +}