X-Git-Url: http://git.xonotic.org/?p=xonotic%2Fdarkplaces.git;a=blobdiff_plain;f=snd_oss.c;h=05f91c92ff50ded803d3f5d9712294a692eece33;hp=4aa510395bf907554cc063b0c7aea962712647e8;hb=91342dd0a88d002a188418a4b0dd21957e0737b6;hpb=ff46d6ff516fda192c5adc55a5c9b82007545bd2 diff --git a/snd_oss.c b/snd_oss.c index 4aa51039..05f91c92 100644 --- a/snd_oss.c +++ b/snd_oss.c @@ -17,280 +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 "snd_main.h" -int audio_fd; -int snd_inited; -static int tryrates[] = {44100, 22051, 11025, 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 +==================== +*/ +qbool SndSys_Init (const snd_format_t* requested, snd_format_t* suggested) { - int rc; - int fmt; - int tmp; - int i; - char *s; - struct audio_buf_info info; - int caps; - int format16bit; - // LordHavoc: a quick patch to support big endian cpu, I hope - union + int flags, ioctl_param, prev_value; + unsigned int fragmentsize; + + Con_DPrint("SndSys_Init: using the OSS module\n"); + + // Check the requested sound format + if (requested->width < 1 || requested->width > 2) { - unsigned char c[2]; - unsigned short s; - } - endiantest; - endiantest.s = 1; - if (endiantest.c[1]) - format16bit = AFMT_S16_BE; - else - format16bit = AFMT_S16_LE; + Con_Printf("SndSys_Init: invalid sound width (%hu)\n", + requested->width); + + if (suggested != NULL) + { + memcpy(suggested, requested, sizeof(*suggested)); - snd_inited = 0; + if (requested->width < 1) + suggested->width = 1; + else + suggested->width = 2; + } + + return false; + } - // open /dev/dsp, confirm capability to mmap, and get size of dma buffer - audio_fd = open("/dev/dsp", O_RDWR); + // Open /dev/dsp + audio_fd = open("/dev/dsp", O_WRONLY); if (audio_fd < 0) { perror("/dev/dsp"); - Con_Print("Could not open /dev/dsp\n"); - return 0; + Con_Print("SndSys_Init: could not open /dev/dsp\n"); + return false; } - - if (ioctl(audio_fd, SNDCTL_DSP_RESET, 0) < 0) + + // Use non-blocking IOs if possible + flags = fcntl(audio_fd, F_GETFL); + if (flags != -1) { - perror("/dev/dsp"); - Con_Print("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"); } - - if (ioctl(audio_fd, SNDCTL_DSP_GETCAPS, &caps)==-1) + 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) { - perror("/dev/dsp"); - Con_Print("Sound driver too old\n"); - close(audio_fd); - return 0; + 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 (!(caps & DSP_CAP_TRIGGER) || !(caps & DSP_CAP_MMAP)) + // 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) { - Con_Print("Sorry but your soundcard can't do this\n"); - close(audio_fd); - return 0; - } + if (ioctl_param != prev_value && suggested != NULL) + { + memcpy(suggested, requested, sizeof(*suggested)); - if (ioctl(audio_fd, SNDCTL_DSP_GETOSPACE, &info)==-1) - { - perror("GETOSPACE"); - Con_Print("Um, can't do GETOSPACE?\n"); - close(audio_fd); - return 0; - } + if (ioctl_param == AFMT_S16_NE) + suggested->width = 2; + else + suggested->width = 1; + } - // 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]); + Con_Printf("SndSys_Init: could not set the sound width to %hu\n", + requested->width); + SndSys_Shutdown(); + return false; + } - if (shm->samplebits != 16 && shm->samplebits != 8) + // Set the sound channels + ioctl_param = requested->channels; + if (ioctl(audio_fd, SNDCTL_DSP_CHANNELS, &ioctl_param) == -1 || + ioctl_param != requested->channels) { - ioctl(audio_fd, SNDCTL_DSP_GETFMTS, &fmt); - if (fmt & format16bit) - shm->samplebits = 16; - else if (fmt & AFMT_U8) - shm->samplebits = 8; - } + if (ioctl_param != requested->channels && suggested != NULL) + { + memcpy(suggested, requested, sizeof(*suggested)); + suggested->channels = 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 + Con_Printf("SndSys_Init: could not set the number of channels to %hu\n", + requested->channels); + SndSys_Shutdown(); + return false; + } + + // Set the sound speed + ioctl_param = requested->speed; + if (ioctl(audio_fd, SNDCTL_DSP_SPEED, &ioctl_param) == -1 || + (unsigned int)ioctl_param != requested->speed) { - for (i = 0;i < (int) sizeof(tryrates) / 4;i++) - if (!ioctl(audio_fd, SNDCTL_DSP_SPEED, &tryrates[i])) - break; + if ((unsigned int)ioctl_param != requested->speed && suggested != NULL) + { + memcpy(suggested, requested, sizeof(*suggested)); + suggested->speed = ioctl_param; + } - shm->speed = 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); + old_osstime = 0; + osssoundtime = 0; + snd_renderbuffer = Snd_CreateRingBuffer(requested, 0, NULL); + return true; +} - // memory map the dma buffer - shm->bufferlength = info.fragstotal * info.fragsize; - shm->buffer = (unsigned char *) mmap(NULL, shm->bufferlength, PROT_READ|PROT_WRITE, MAP_FILE|MAP_SHARED, audio_fd, 0); - if (!shm->buffer || shm->buffer == (unsigned char *)-1) - { - perror("/dev/dsp"); - Con_Print("Could not mmap /dev/dsp\n"); - close(audio_fd); - return 0; - } - tmp = 0; - if (shm->channels == 2) - tmp = 1; +/* +==================== +SndSys_Shutdown - rc = ioctl(audio_fd, SNDCTL_DSP_STEREO, &tmp); - if (rc < 0) +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 set /dev/dsp to stereo=%d\n", shm->channels); + ioctl(audio_fd, SNDCTL_DSP_RESET, NULL); close(audio_fd); - return 0; + audio_fd = -1; } - if (tmp) - shm->channels = 2; - else - shm->channels = 1; - rc = ioctl(audio_fd, SNDCTL_DSP_SPEED, &shm->speed); - if (rc < 0) + if (snd_renderbuffer != NULL) { - perror("/dev/dsp"); - Con_Printf("Could not set /dev/dsp speed to %d\n", shm->speed); - close(audio_fd); - return 0; + Mem_Free(snd_renderbuffer->ring); + Mem_Free(snd_renderbuffer); + snd_renderbuffer = NULL; } +} - if (shm->samplebits == 16) - { - rc = format16bit; - rc = ioctl(audio_fd, SNDCTL_DSP_SETFMT, &rc); - if (rc < 0) - { - perror("/dev/dsp"); - Con_Print("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_Print("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.\n", 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 - tmp = 0; - rc = ioctl(audio_fd, SNDCTL_DSP_SETTRIGGER, &tmp); - if (rc < 0) + 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; + + if ((unsigned int)written < nb_bytes) { - perror("/dev/dsp"); - Con_Print("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_Print("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; - - snd_inited = 1; - return 1; + SndSys_Write (&snd_renderbuffer->ring[startoffset * factor], nbframes * factor); } -int SNDDMA_GetDMAPos(void) -{ - struct count_info count; +/* +==================== +SndSys_GetSoundTime - if (!snd_inited) return 0; +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 (ioctl(audio_fd, SNDCTL_DSP_GETOPTR, &count)==-1) + if (ioctl (audio_fd, SNDCTL_DSP_GETOPTR, &count) == -1) { - perror("/dev/dsp"); - Con_Print("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.ptr / (shm->samplebits / 8); + new_osstime = count.bytes / (snd_renderbuffer->format.width * snd_renderbuffer->format.channels); - return shm->samplepos; -} - -void SNDDMA_Shutdown(void) -{ - int tmp; - if (snd_inited) + if (new_osstime >= old_osstime) + timediff = new_osstime - old_osstime; + else { - // unmap the memory - munmap(shm->buffer, shm->bufferlength); - // stop the sound - tmp = 0; - ioctl(audio_fd, SNDCTL_DSP_SETTRIGGER, &tmp); - ioctl(audio_fd, SNDCTL_DSP_RESET, 0); - // close the device - close(audio_fd); - audio_fd = -1; - snd_inited = 0; + Con_Print ("SndSys_GetSoundTime: osstime wrapped\n"); + timediff = 0; } + + old_osstime = new_osstime; + osssoundtime += timediff; + return osssoundtime; } + /* -============== -SNDDMA_Submit +==================== +SndSys_LockRenderBuffer -Send sound to device if buffer isn't really the dma buffer -=============== +Get the exclusive lock on "snd_renderbuffer" +==================== */ -void SNDDMA_Submit(void) +qbool SndSys_LockRenderBuffer (void) { + // Nothing to do + return true; } -void *S_LockBuffer(void) + +/* +==================== +SndSys_UnlockRenderBuffer + +Release the exclusive lock on "snd_renderbuffer" +==================== +*/ +void SndSys_UnlockRenderBuffer (void) { - return shm->buffer; + // Nothing to do } -void S_UnlockBuffer(void) +/* +==================== +SndSys_SendKeyEvents + +Send keyboard events originating from the sound system (e.g. MIDI) +==================== +*/ +void SndSys_SendKeyEvents(void) { + // not supported } -