src/audio/disk/SDL_diskaudio.c
changeset 68 ac6645260d31
child 86 13e4c612098d
equal deleted inserted replaced
67:3647c809813d 68:ac6645260d31
       
     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@devolution.com
       
    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 
       
    84 	available = 0;
       
    85 
       
    86     if (stat(fname, &statbuf) == 0)
       
    87         exists = 1;
       
    88 
       
    89     fd = open(fname, O_WRONLY | O_CREAT | O_APPEND, S_IRUSR | S_IWUSR);
       
    90 	if ( fd != -1 ) {
       
    91 		available = 1;
       
    92 		close(fd);
       
    93         if (!exists) {
       
    94             unlink(fname);
       
    95         }
       
    96 	}
       
    97 	return(available);
       
    98 #else
       
    99     return(1);
       
   100 #endif
       
   101 }
       
   102 
       
   103 static void DISKAUD_DeleteDevice(SDL_AudioDevice *device)
       
   104 {
       
   105 	free(device->hidden);
       
   106 	free(device);
       
   107 }
       
   108 
       
   109 static SDL_AudioDevice *DISKAUD_CreateDevice(int devindex)
       
   110 {
       
   111 	SDL_AudioDevice *this;
       
   112     const char *envr;
       
   113 
       
   114 	/* Initialize all variables that we clean on shutdown */
       
   115 	this = (SDL_AudioDevice *)malloc(sizeof(SDL_AudioDevice));
       
   116 	if ( this ) {
       
   117 		memset(this, 0, (sizeof *this));
       
   118 		this->hidden = (struct SDL_PrivateAudioData *)
       
   119 				malloc((sizeof *this->hidden));
       
   120 	}
       
   121 	if ( (this == NULL) || (this->hidden == NULL) ) {
       
   122 		SDL_OutOfMemory();
       
   123 		if ( this ) {
       
   124 			free(this);
       
   125 		}
       
   126 		return(0);
       
   127 	}
       
   128 	memset(this->hidden, 0, (sizeof *this->hidden));
       
   129 
       
   130     envr = getenv(DISKENVR_WRITEDELAY);
       
   131     this->hidden->write_delay = (envr) ? atoi(envr) : DISKDEFAULT_WRITEDELAY;
       
   132 
       
   133 	/* Set the function pointers */
       
   134 	this->OpenAudio = DISKAUD_OpenAudio;
       
   135 	this->WaitAudio = DISKAUD_WaitAudio;
       
   136 	this->PlayAudio = DISKAUD_PlayAudio;
       
   137 	this->GetAudioBuf = DISKAUD_GetAudioBuf;
       
   138 	this->CloseAudio = DISKAUD_CloseAudio;
       
   139 
       
   140 	this->free = DISKAUD_DeleteDevice;
       
   141 
       
   142 	return this;
       
   143 }
       
   144 
       
   145 AudioBootStrap DISKAUD_bootstrap = {
       
   146 	DISKAUD_DRIVER_NAME, "direct-to-disk audio",
       
   147 	DISKAUD_Available, DISKAUD_CreateDevice
       
   148 };
       
   149 
       
   150 /* This function waits until it is possible to write a full sound buffer */
       
   151 static void DISKAUD_WaitAudio(_THIS)
       
   152 {
       
   153     SDL_Delay(this->hidden->write_delay);
       
   154 }
       
   155 
       
   156 static void DISKAUD_PlayAudio(_THIS)
       
   157 {
       
   158 	int written;
       
   159 
       
   160 	/* Write the audio data, checking for EAGAIN on broken audio drivers */
       
   161 	do {
       
   162 		written = write(this->hidden->audio_fd,
       
   163                         this->hidden->mixbuf,
       
   164                         this->hidden->mixlen);
       
   165 		if ( (written < 0) && ((errno == 0) || (errno == EAGAIN)) ) {
       
   166 			SDL_Delay(1);	/* Let a little CPU time go by */
       
   167 		}
       
   168 	} while ( (written < 0) && 
       
   169 	          ((errno == 0) || (errno == EAGAIN) || (errno == EINTR)) );
       
   170 
       
   171 	/* If we couldn't write, assume fatal error for now */
       
   172 	if ( written < 0 ) {
       
   173 		this->enabled = 0;
       
   174 	}
       
   175 #ifdef DEBUG_AUDIO
       
   176 	fprintf(stderr, "Wrote %d bytes of audio data\n", written);
       
   177 #endif
       
   178 }
       
   179 
       
   180 static Uint8 *DISKAUD_GetAudioBuf(_THIS)
       
   181 {
       
   182 	return(this->hidden->mixbuf);
       
   183 }
       
   184 
       
   185 static void DISKAUD_CloseAudio(_THIS)
       
   186 {
       
   187 	if ( this->hidden->mixbuf != NULL ) {
       
   188 		SDL_FreeAudioMem(this->hidden->mixbuf);
       
   189 		this->hidden->mixbuf = NULL;
       
   190 	}
       
   191 	if ( this->hidden->audio_fd >= 0 ) {
       
   192 		close(this->hidden->audio_fd);
       
   193 		this->hidden->audio_fd = -1;
       
   194 	}
       
   195 }
       
   196 
       
   197 static int DISKAUD_OpenAudio(_THIS, SDL_AudioSpec *spec)
       
   198 {
       
   199     const char *fname = DISKAUD_GetOutputFilename();
       
   200 
       
   201 	/* Open the audio device */
       
   202     this->hidden->audio_fd = open(fname, O_WRONLY | O_CREAT, S_IRUSR | S_IWUSR);
       
   203 	if ( this->hidden->audio_fd < 0 ) {
       
   204 		SDL_SetError("Couldn't open %s: %s", fname, strerror(errno));
       
   205 		return(-1);
       
   206 	}
       
   207 
       
   208     fprintf(stderr, "WARNING: You are using the SDL disk writer"
       
   209                     " audio driver!\n Writing to file [%s].\n", fname);
       
   210 
       
   211 	/* Allocate mixing buffer */
       
   212 	this->hidden->mixlen = spec->size;
       
   213 	this->hidden->mixbuf = (Uint8 *) SDL_AllocAudioMem(this->hidden->mixlen);
       
   214 	if ( this->hidden->mixbuf == NULL ) {
       
   215 		return(-1);
       
   216 	}
       
   217 	memset(this->hidden->mixbuf, spec->silence, spec->size);
       
   218 
       
   219 	/* We're ready to rock and roll. :-) */
       
   220 	return(0);
       
   221 }
       
   222