src/audio/dsp/SDL_dspaudio.c
changeset 968 4675910b0b7b
parent 960 eec28a5278be
child 1037 c5dedfdb4e42
--- 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();