src/audio/disk/SDL_diskaudio.c
author Sam Lantinga <slouken@libsdl.org>
Fri, 14 Dec 2001 12:38:15 +0000
changeset 252 e8157fcb3114
parent 86 13e4c612098d
child 297 f6ffac90895c
permissions -rw-r--r--
Updated the source with the correct e-mail address
     1 /*
     2     SDL - Simple DirectMedia Layer
     3     Copyright (C) 1997, 1998, 1999, 2000, 2001  Sam Lantinga
     4 
     5     This library is free software; you can redistribute it and/or
     6     modify it under the terms of the GNU Library General Public
     7     License as published by the Free Software Foundation; either
     8     version 2 of the License, or (at your option) any later version.
     9 
    10     This library is distributed in the hope that it will be useful,
    11     but WITHOUT ANY WARRANTY; without even the implied warranty of
    12     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
    13     Library General Public License for more details.
    14 
    15     You should have received a copy of the GNU Library General Public
    16     License along with this library; if not, write to the Free
    17     Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
    18 
    19     Sam Lantinga
    20     slouken@libsdl.org
    21 
    22     This file hacked^H^H^H^H^H^Hwritten by Ryan C. Gordon
    23         (icculus@linuxgames.com)
    24 */
    25 
    26 #ifdef SAVE_RCSID
    27 static char rcsid =
    28  "@(#) $Id$";
    29 #endif
    30 
    31 /* Output raw audio data to a file. */
    32 
    33 #include <stdlib.h>
    34 #include <stdio.h>
    35 #include <string.h>
    36 #include <errno.h>
    37 #include <unistd.h>
    38 #include <sys/stat.h>
    39 #include <sys/types.h>
    40 #include <sys/stat.h>
    41 #include <fcntl.h>
    42 
    43 
    44 #include "SDL_audio.h"
    45 #include "SDL_error.h"
    46 #include "SDL_audiomem.h"
    47 #include "SDL_audio_c.h"
    48 #include "SDL_timer.h"
    49 #include "SDL_audiodev_c.h"
    50 #include "SDL_diskaudio.h"
    51 
    52 /* The tag name used by DISK audio */
    53 #define DISKAUD_DRIVER_NAME         "disk"
    54 
    55 /* environment variables and defaults. */
    56 #define DISKENVR_OUTFILE         "SDL_DISKAUDIOFILE"
    57 #define DISKDEFAULT_OUTFILE      "sdlaudio.raw"
    58 #define DISKENVR_WRITEDELAY      "SDL_DISKAUDIODELAY"
    59 #define DISKDEFAULT_WRITEDELAY   150
    60 
    61 /* Audio driver functions */
    62 static int DISKAUD_OpenAudio(_THIS, SDL_AudioSpec *spec);
    63 static void DISKAUD_WaitAudio(_THIS);
    64 static void DISKAUD_PlayAudio(_THIS);
    65 static Uint8 *DISKAUD_GetAudioBuf(_THIS);
    66 static void DISKAUD_CloseAudio(_THIS);
    67 
    68 static const char *DISKAUD_GetOutputFilename(void)
    69 {
    70     const char *envr = getenv(DISKENVR_OUTFILE);
    71     return((envr != NULL) ? envr : DISKDEFAULT_OUTFILE);
    72 }
    73 
    74 /* Audio driver bootstrap functions */
    75 static int DISKAUD_Available(void)
    76 {
    77 #if 0
    78     int fd;
    79 	int available;
    80     int exists = 0;
    81     struct stat statbuf;
    82     const char *fname = DISKAUD_GetOutputFilename();
    83 	const char *envr = getenv("SDL_AUDIODRIVER");
    84 	available = 0;
    85 
    86 	if ((envr) && (strcmp(envr, DISKAUD_DRIVER_NAME) == 0)) {
    87 		if (stat(fname, &statbuf) == 0)
    88 			exists = 1;
    89 
    90 		fd = open(fname, O_WRONLY | O_CREAT | O_APPEND, S_IRUSR | S_IWUSR);
    91 		if ( fd != -1 ) {
    92 			available = 1;
    93 			close(fd);
    94 			if (!exists) {
    95 				unlink(fname);
    96 			}
    97 		}
    98 	}
    99 	return(available);
   100 #else
   101 	const char *envr = getenv("SDL_AUDIODRIVER");
   102 	if ((envr) && (strcmp(envr, DISKAUD_DRIVER_NAME) == 0)) {
   103 		return(1);
   104 	}
   105 
   106 	return(0);
   107 #endif
   108 }
   109 
   110 static void DISKAUD_DeleteDevice(SDL_AudioDevice *device)
   111 {
   112 	free(device->hidden);
   113 	free(device);
   114 }
   115 
   116 static SDL_AudioDevice *DISKAUD_CreateDevice(int devindex)
   117 {
   118 	SDL_AudioDevice *this;
   119     const char *envr;
   120 
   121 	/* Initialize all variables that we clean on shutdown */
   122 	this = (SDL_AudioDevice *)malloc(sizeof(SDL_AudioDevice));
   123 	if ( this ) {
   124 		memset(this, 0, (sizeof *this));
   125 		this->hidden = (struct SDL_PrivateAudioData *)
   126 				malloc((sizeof *this->hidden));
   127 	}
   128 	if ( (this == NULL) || (this->hidden == NULL) ) {
   129 		SDL_OutOfMemory();
   130 		if ( this ) {
   131 			free(this);
   132 		}
   133 		return(0);
   134 	}
   135 	memset(this->hidden, 0, (sizeof *this->hidden));
   136 
   137     envr = getenv(DISKENVR_WRITEDELAY);
   138     this->hidden->write_delay = (envr) ? atoi(envr) : DISKDEFAULT_WRITEDELAY;
   139 
   140 	/* Set the function pointers */
   141 	this->OpenAudio = DISKAUD_OpenAudio;
   142 	this->WaitAudio = DISKAUD_WaitAudio;
   143 	this->PlayAudio = DISKAUD_PlayAudio;
   144 	this->GetAudioBuf = DISKAUD_GetAudioBuf;
   145 	this->CloseAudio = DISKAUD_CloseAudio;
   146 
   147 	this->free = DISKAUD_DeleteDevice;
   148 
   149 	return this;
   150 }
   151 
   152 AudioBootStrap DISKAUD_bootstrap = {
   153 	DISKAUD_DRIVER_NAME, "direct-to-disk audio",
   154 	DISKAUD_Available, DISKAUD_CreateDevice
   155 };
   156 
   157 /* This function waits until it is possible to write a full sound buffer */
   158 static void DISKAUD_WaitAudio(_THIS)
   159 {
   160     SDL_Delay(this->hidden->write_delay);
   161 }
   162 
   163 static void DISKAUD_PlayAudio(_THIS)
   164 {
   165 	int written;
   166 
   167 	/* Write the audio data, checking for EAGAIN on broken audio drivers */
   168 	do {
   169 		written = write(this->hidden->audio_fd,
   170                         this->hidden->mixbuf,
   171                         this->hidden->mixlen);
   172 		if ( (written < 0) && ((errno == 0) || (errno == EAGAIN)) ) {
   173 			SDL_Delay(1);	/* Let a little CPU time go by */
   174 		}
   175 	} while ( (written < 0) && 
   176 	          ((errno == 0) || (errno == EAGAIN) || (errno == EINTR)) );
   177 
   178 	/* If we couldn't write, assume fatal error for now */
   179 	if ( written < 0 ) {
   180 		this->enabled = 0;
   181 	}
   182 #ifdef DEBUG_AUDIO
   183 	fprintf(stderr, "Wrote %d bytes of audio data\n", written);
   184 #endif
   185 }
   186 
   187 static Uint8 *DISKAUD_GetAudioBuf(_THIS)
   188 {
   189 	return(this->hidden->mixbuf);
   190 }
   191 
   192 static void DISKAUD_CloseAudio(_THIS)
   193 {
   194 	if ( this->hidden->mixbuf != NULL ) {
   195 		SDL_FreeAudioMem(this->hidden->mixbuf);
   196 		this->hidden->mixbuf = NULL;
   197 	}
   198 	if ( this->hidden->audio_fd >= 0 ) {
   199 		close(this->hidden->audio_fd);
   200 		this->hidden->audio_fd = -1;
   201 	}
   202 }
   203 
   204 static int DISKAUD_OpenAudio(_THIS, SDL_AudioSpec *spec)
   205 {
   206     const char *fname = DISKAUD_GetOutputFilename();
   207 
   208 	/* Open the audio device */
   209     this->hidden->audio_fd = open(fname, O_WRONLY | O_CREAT, S_IRUSR | S_IWUSR);
   210 	if ( this->hidden->audio_fd < 0 ) {
   211 		SDL_SetError("Couldn't open %s: %s", fname, strerror(errno));
   212 		return(-1);
   213 	}
   214 
   215     fprintf(stderr, "WARNING: You are using the SDL disk writer"
   216                     " audio driver!\n Writing to file [%s].\n", fname);
   217 
   218 	/* Allocate mixing buffer */
   219 	this->hidden->mixlen = spec->size;
   220 	this->hidden->mixbuf = (Uint8 *) SDL_AllocAudioMem(this->hidden->mixlen);
   221 	if ( this->hidden->mixbuf == NULL ) {
   222 		return(-1);
   223 	}
   224 	memset(this->hidden->mixbuf, spec->silence, spec->size);
   225 
   226 	/* We're ready to rock and roll. :-) */
   227 	return(0);
   228 }
   229