--- a/src/audio/dsp/SDL_dspaudio.c Fri Nov 12 21:29:52 2004 +0000
+++ b/src/audio/dsp/SDL_dspaudio.c Fri Nov 12 21:39:04 2004 +0000
@@ -18,6 +18,9 @@
Sam Lantinga
slouken@libsdl.org
+
+ Modified in Oct 2004 by Hannu Savolainen
+ hannu@opensound.com
*/
#ifdef SAVE_RCSID
@@ -57,7 +60,6 @@
#define DSP_DRIVER_NAME "dsp"
/* Open the audio device for playback, and don't block if busy */
-/*#define USE_BLOCKING_WRITES*/
#define OPEN_FLAGS (O_WRONLY|O_NONBLOCK)
/* Audio driver functions */
@@ -130,94 +132,19 @@
/* This function waits until it is possible to write a full sound buffer */
static void DSP_WaitAudio(_THIS)
{
- /* Check to see if the thread-parent process is still alive */
- { static int cnt = 0;
- /* Note that this only works with thread implementations
- that use a different process id for each thread.
- */
- if (parent && (((++cnt)%10) == 0)) { /* Check every 10 loops */
- if ( kill(parent, 0) < 0 ) {
- this->enabled = 0;
- }
- }
- }
-
-#ifndef USE_BLOCKING_WRITES /* Not necessary when using blocking writes */
- /* See if we need to use timed audio synchronization */
- if ( frame_ticks ) {
- /* Use timer for general audio synchronization */
- Sint32 ticks;
-
- ticks = ((Sint32)(next_frame - SDL_GetTicks()))-FUDGE_TICKS;
- if ( ticks > 0 ) {
- SDL_Delay(ticks);
- }
- } else {
- /* Use select() for audio synchronization */
- fd_set fdset;
- struct timeval timeout;
-
- FD_ZERO(&fdset);
- FD_SET(audio_fd, &fdset);
- timeout.tv_sec = 10;
- timeout.tv_usec = 0;
-#ifdef DEBUG_AUDIO
- fprintf(stderr, "Waiting for audio to get ready\n");
-#endif
- if ( select(audio_fd+1, NULL, &fdset, NULL, &timeout) <= 0 ) {
- const char *message =
- "Audio timeout - buggy audio driver? (disabled)";
- /* In general we should never print to the screen,
- but in this case we have no other way of letting
- the user know what happened.
- */
- fprintf(stderr, "SDL: %s\n", message);
- this->enabled = 0;
- /* Don't try to close - may hang */
- audio_fd = -1;
-#ifdef DEBUG_AUDIO
- fprintf(stderr, "Done disabling audio\n");
-#endif
- }
-#ifdef DEBUG_AUDIO
- fprintf(stderr, "Ready!\n");
-#endif
- }
-#endif /* !USE_BLOCKING_WRITES */
+ /* Not needed at all since OSS handles waiting automagically */
}
static void DSP_PlayAudio(_THIS)
{
- int written, p=0;
-
- /* Write the audio data, checking for EAGAIN on broken audio drivers */
- do {
- written = write(audio_fd, &mixbuf[p], mixlen-p);
- if (written>0)
- p += written;
- if (written == -1 && errno != 0 && errno != EAGAIN && errno != EINTR)
- {
- /* Non recoverable error has occurred. It should be reported!!! */
- perror("audio");
- break;
- }
-
- if ( p < written || ((written < 0) && ((errno == 0) || (errno == EAGAIN))) ) {
- SDL_Delay(1); /* Let a little CPU time go by */
- }
- } while ( p < written );
-
- /* If timer synchronization is enabled, set the next write frame */
- if ( frame_ticks ) {
- next_frame += frame_ticks;
+ if (write(audio_fd, mixbuf, mixlen)==-1)
+ {
+ perror("Audio write");
+ this->enabled = 0;
}
- /* If we couldn't write, assume fatal error for now */
- if ( written < 0 ) {
- this->enabled = 0;
- }
#ifdef DEBUG_AUDIO
- fprintf(stderr, "Wrote %d bytes of audio data\n", written);
+ fprintf(stderr, "Wrote %d bytes of audio data\n", mixlen);
#endif
}
@@ -233,26 +160,128 @@
mixbuf = NULL;
}
if ( audio_fd >= 0 ) {
- int value;
- ioctl(audio_fd, SNDCTL_DSP_RESET, &value);
close(audio_fd);
audio_fd = -1;
}
}
-static int DSP_ReopenAudio(_THIS, const char *audiodev, int format,
- SDL_AudioSpec *spec)
+static int DSP_OpenAudio(_THIS, SDL_AudioSpec *spec)
{
- int frag_spec;
+ char audiodev[1024];
+ int format;
int value;
+ int frag_spec;
+ Uint16 test_format;
- /* Close and then reopen the audio device */
- close(audio_fd);
- audio_fd = open(audiodev, O_WRONLY, 0);
+ /* Open the audio device */
+ audio_fd = SDL_OpenAudioPath(audiodev, sizeof(audiodev), OPEN_FLAGS, 0);
if ( audio_fd < 0 ) {
SDL_SetError("Couldn't open %s: %s", audiodev, strerror(errno));
return(-1);
}
+ mixbuf = NULL;
+
+ /* Make the file descriptor use blocking writes with fcntl() */
+ { long flags;
+ flags = fcntl(audio_fd, F_GETFL);
+ flags &= ~O_NONBLOCK;
+ if ( fcntl(audio_fd, F_SETFL, flags) < 0 ) {
+ SDL_SetError("Couldn't set audio blocking mode");
+ return(-1);
+ }
+ }
+
+ /* Get a list of supported hardware formats */
+ if ( ioctl(audio_fd, SNDCTL_DSP_GETFMTS, &value) < 0 ) {
+ perror("SNDCTL_DSP_GETFMTS");
+ SDL_SetError("Couldn't get audio format list");
+ return(-1);
+ }
+
+ /* Try for a closest match on audio format */
+ format = 0;
+ for ( test_format = SDL_FirstAudioFormat(spec->format);
+ ! format && test_format; ) {
+#ifdef DEBUG_AUDIO
+ fprintf(stderr, "Trying format 0x%4.4x\n", test_format);
+#endif
+ switch ( test_format ) {
+ case AUDIO_U8:
+ if ( value & AFMT_U8 ) {
+ format = AFMT_U8;
+ }
+ break;
+ case AUDIO_S16LSB:
+ if ( value & AFMT_S16_LE ) {
+ format = AFMT_S16_LE;
+ }
+ break;
+ case AUDIO_S16MSB:
+ if ( value & AFMT_S16_BE ) {
+ format = AFMT_S16_BE;
+ }
+ break;
+#if 0
+/*
+ * These formats are not used by any real life systems so they are not
+ * needed here.
+ */
+ case AUDIO_S8:
+ if ( value & AFMT_S8 ) {
+ format = AFMT_S8;
+ }
+ break;
+ case AUDIO_U16LSB:
+ if ( value & AFMT_U16_LE ) {
+ format = AFMT_U16_LE;
+ }
+ break;
+ case AUDIO_U16MSB:
+ if ( value & AFMT_U16_BE ) {
+ format = AFMT_U16_BE;
+ }
+ break;
+#endif
+ default:
+ format = 0;
+ break;
+ }
+ if ( ! format ) {
+ test_format = SDL_NextAudioFormat();
+ }
+ }
+ if ( format == 0 ) {
+ SDL_SetError("Couldn't find any hardware audio formats");
+ return(-1);
+ }
+ spec->format = test_format;
+
+ /* Set the audio format */
+ value = format;
+ if ( (ioctl(audio_fd, SNDCTL_DSP_SETFMT, &value) < 0) ||
+ (value != format) ) {
+ perror("SNDCTL_DSP_SETFMT");
+ SDL_SetError("Couldn't set audio format");
+ return(-1);
+ }
+
+ /* Set the number of channels of output */
+ value = spec->channels;
+ if ( ioctl(audio_fd, SNDCTL_DSP_CHANNELS, &value) < 0 ) {
+ perror("SNDCTL_DSP_CHANNELS");
+ SDL_SetError("Cannot set the number of channels");
+ return(-1);
+ }
+ spec->channels = value;
+
+ /* Set the DSP frequency */
+ value = spec->freq;
+ if ( ioctl(audio_fd, SNDCTL_DSP_SPEED, &value) < 0 ) {
+ perror("SNDCTL_DSP_SPEED");
+ SDL_SetError("Couldn't set audio frequency");
+ return(-1);
+ }
+ spec->freq = value;
/* Calculate the final parameters for this audio specification */
SDL_CalculateAudioSpec(spec);
@@ -271,6 +300,7 @@
(frag_spec >> 16), 1<<(frag_spec&0xFFFF));
#endif
if ( ioctl(audio_fd, SNDCTL_DSP_SETFRAGMENT, &frag_spec) < 0 ) {
+ perror("SNDCTL_DSP_SETFRAGMENT");
fprintf(stderr, "Warning: Couldn't set audio fragment size\n");
}
#ifdef DEBUG_AUDIO
@@ -283,160 +313,6 @@
}
#endif
- /* Set the audio format */
- value = format;
- if ( (ioctl(audio_fd, SNDCTL_DSP_SETFMT, &value) < 0) ||
- (value != format) ) {
- SDL_SetError("Couldn't set audio format");
- return(-1);
- }
-
- /* Set the number of channels of output */
- value = spec->channels;
-#ifdef SNDCTL_DSP_CHANNELS
- if ( ioctl(audio_fd, SNDCTL_DSP_CHANNELS, &value) < 0 ) {
-#endif
- value = (spec->channels > 1);
- ioctl(audio_fd, SNDCTL_DSP_STEREO, &value);
- value = (value ? 2 : 1);
-#ifdef SNDCTL_DSP_CHANNELS
- }
-#endif
- if ( value != spec->channels ) {
- SDL_SetError("Couldn't set audio channels");
- return(-1);
- }
-
- /* Set the DSP frequency */
- value = spec->freq;
- if ( ioctl(audio_fd, SNDCTL_DSP_SPEED, &value) < 0 ) {
- SDL_SetError("Couldn't set audio frequency");
- return(-1);
- }
- spec->freq = value;
-
- /* We successfully re-opened the audio */
- return(0);
-}
-
-static int DSP_OpenAudio(_THIS, SDL_AudioSpec *spec)
-{
- char audiodev[1024];
- int format;
- int value;
- Uint16 test_format;
-
- /* Reset the timer synchronization flag */
- frame_ticks = 0.0;
-
- /* Open the audio device */
- audio_fd = SDL_OpenAudioPath(audiodev, sizeof(audiodev), OPEN_FLAGS, 0);
- if ( audio_fd < 0 ) {
- SDL_SetError("Couldn't open %s: %s", audiodev, strerror(errno));
- return(-1);
- }
- mixbuf = NULL;
-
-#ifdef USE_BLOCKING_WRITES
- /* Make the file descriptor use blocking writes with fcntl() */
- { long flags;
- flags = fcntl(audio_fd, F_GETFL);
- flags &= ~O_NONBLOCK;
- if ( fcntl(audio_fd, F_SETFL, flags) < 0 ) {
- SDL_SetError("Couldn't set audio blocking mode");
- return(-1);
- }
- }
-#endif
-
- /* Get a list of supported hardware formats */
- if ( ioctl(audio_fd, SNDCTL_DSP_GETFMTS, &value) < 0 ) {
- SDL_SetError("Couldn't get audio format list");
- return(-1);
- }
-
- /* Try for a closest match on audio format */
- format = 0;
- for ( test_format = SDL_FirstAudioFormat(spec->format);
- ! format && test_format; ) {
-#ifdef DEBUG_AUDIO
- fprintf(stderr, "Trying format 0x%4.4x\n", test_format);
-#endif
- switch ( test_format ) {
- case AUDIO_U8:
- if ( value & AFMT_U8 ) {
- format = AFMT_U8;
- }
- break;
- case AUDIO_S8:
- if ( value & AFMT_S8 ) {
- format = AFMT_S8;
- }
- break;
- case AUDIO_S16LSB:
- if ( value & AFMT_S16_LE ) {
- format = AFMT_S16_LE;
- }
- break;
- case AUDIO_S16MSB:
- if ( value & AFMT_S16_BE ) {
- format = AFMT_S16_BE;
- }
- break;
- case AUDIO_U16LSB:
- if ( value & AFMT_U16_LE ) {
- format = AFMT_U16_LE;
- }
- break;
- case AUDIO_U16MSB:
- if ( value & AFMT_U16_BE ) {
- format = AFMT_U16_BE;
- }
- break;
- default:
- format = 0;
- break;
- }
- if ( ! format ) {
- test_format = SDL_NextAudioFormat();
- }
- }
- if ( format == 0 ) {
- SDL_SetError("Couldn't find any hardware audio formats");
- return(-1);
- }
- spec->format = test_format;
-
- /* Set the audio format */
- value = format;
- if ( (ioctl(audio_fd, SNDCTL_DSP_SETFMT, &value) < 0) ||
- (value != format) ) {
- SDL_SetError("Couldn't set audio format");
- return(-1);
- }
-
- /* Set the number of channels of output */
- value = spec->channels;
-#ifdef SNDCTL_DSP_CHANNELS
- if ( ioctl(audio_fd, SNDCTL_DSP_CHANNELS, &value) < 0 ) {
-#endif
- value = (spec->channels > 1);
- ioctl(audio_fd, SNDCTL_DSP_STEREO, &value);
- value = (value ? 2 : 1);
-#ifdef SNDCTL_DSP_CHANNELS
- }
-#endif
- spec->channels = value;
-
- /* Because some drivers don't allow setting the buffer size
- after setting the format, we must re-open the audio device
- once we know what format and channels are supported
- */
- if ( DSP_ReopenAudio(this, audiodev, format, spec) < 0 ) {
- /* Error is set by DSP_ReopenAudio() */
- return(-1);
- }
-
/* Allocate mixing buffer */
mixlen = spec->size;
mixbuf = (Uint8 *)SDL_AllocAudioMem(mixlen);
@@ -445,17 +321,6 @@
}
memset(mixbuf, spec->silence, spec->size);
-#ifndef USE_BLOCKING_WRITES
- /* Check to see if we need to use select() workaround */
- { char *workaround;
- workaround = getenv("SDL_DSP_NOSELECT");
- if ( workaround ) {
- frame_ticks = (float)(spec->samples*1000)/spec->freq;
- next_frame = SDL_GetTicks()+frame_ticks;
- }
- }
-#endif /* !USE_BLOCKING_WRITES */
-
/* Get the parent process id (we're the parent of the audio thread) */
parent = getpid();