symbian-qemu-0.9.1-12/libsdl-trunk/src/audio/bsd/SDL_bsdaudio.c
changeset 1 2fb8b9db1c86
equal deleted inserted replaced
0:ffa851df0825 1:2fb8b9db1c86
       
     1 /*
       
     2     SDL - Simple DirectMedia Layer
       
     3     Copyright (C) 1997-2004 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 #include "SDL_config.h"
       
    23 
       
    24 /*
       
    25  * Driver for native OpenBSD/NetBSD audio(4).
       
    26  * vedge@vedge.com.ar.
       
    27  */
       
    28 
       
    29 #include <errno.h>
       
    30 #include <unistd.h>
       
    31 #include <fcntl.h>
       
    32 #include <sys/time.h>
       
    33 #include <sys/ioctl.h>
       
    34 #include <sys/stat.h>
       
    35 #include <sys/types.h>
       
    36 #include <sys/audioio.h>
       
    37 
       
    38 #include "SDL_timer.h"
       
    39 #include "SDL_audio.h"
       
    40 #include "../SDL_audiomem.h"
       
    41 #include "../SDL_audio_c.h"
       
    42 #include "../SDL_audiodev_c.h"
       
    43 #include "SDL_bsdaudio.h"
       
    44 
       
    45 /* The tag name used by NetBSD/OpenBSD audio */
       
    46 #ifdef __NetBSD__
       
    47 #define BSD_AUDIO_DRIVER_NAME         "netbsd"
       
    48 #define BSD_AUDIO_DRIVER_DESC         "Native NetBSD audio"
       
    49 #else
       
    50 #define BSD_AUDIO_DRIVER_NAME         "openbsd"
       
    51 #define BSD_AUDIO_DRIVER_DESC         "Native OpenBSD audio"
       
    52 #endif
       
    53 
       
    54 /* Open the audio device for playback, and don't block if busy */
       
    55 /* #define USE_BLOCKING_WRITES */
       
    56 
       
    57 /* Use timer for synchronization */
       
    58 /* #define USE_TIMER_SYNC */
       
    59 
       
    60 /* #define DEBUG_AUDIO */
       
    61 /* #define DEBUG_AUDIO_STREAM */
       
    62 
       
    63 #ifdef USE_BLOCKING_WRITES
       
    64 #define OPEN_FLAGS	O_WRONLY
       
    65 #else
       
    66 #define OPEN_FLAGS	(O_WRONLY|O_NONBLOCK)
       
    67 #endif
       
    68 
       
    69 /* Audio driver functions */
       
    70 static void OBSD_WaitAudio(_THIS);
       
    71 static int OBSD_OpenAudio(_THIS, SDL_AudioSpec *spec);
       
    72 static void OBSD_PlayAudio(_THIS);
       
    73 static Uint8 *OBSD_GetAudioBuf(_THIS);
       
    74 static void OBSD_CloseAudio(_THIS);
       
    75 
       
    76 #ifdef DEBUG_AUDIO
       
    77 static void OBSD_Status(_THIS);
       
    78 #endif
       
    79 
       
    80 /* Audio driver bootstrap functions */
       
    81 
       
    82 static int
       
    83 Audio_Available(void)
       
    84 {
       
    85     int fd;
       
    86     int available;
       
    87 
       
    88     available = 0;
       
    89     fd = SDL_OpenAudioPath(NULL, 0, OPEN_FLAGS, 0);
       
    90     if(fd >= 0) {
       
    91 	available = 1;
       
    92 	close(fd);
       
    93     }
       
    94     return(available);
       
    95 }
       
    96 
       
    97 static void
       
    98 Audio_DeleteDevice(SDL_AudioDevice *device)
       
    99 {
       
   100     SDL_free(device->hidden);
       
   101     SDL_free(device);
       
   102 }
       
   103 
       
   104 static SDL_AudioDevice
       
   105 *Audio_CreateDevice(int devindex)
       
   106 {
       
   107     SDL_AudioDevice *this;
       
   108 
       
   109     /* Initialize all variables that we clean on shutdown */
       
   110     this = (SDL_AudioDevice*)SDL_malloc(sizeof(SDL_AudioDevice));
       
   111     if(this) {
       
   112 	SDL_memset(this, 0, (sizeof *this));
       
   113 	this->hidden =
       
   114 	    (struct SDL_PrivateAudioData*)SDL_malloc((sizeof *this->hidden));
       
   115     }
       
   116     if((this == NULL) || (this->hidden == NULL)) {
       
   117 	SDL_OutOfMemory();
       
   118 	if(this) SDL_free(this);
       
   119 	return(0);
       
   120     }
       
   121     SDL_memset(this->hidden, 0, (sizeof *this->hidden));
       
   122     audio_fd = -1;
       
   123 
       
   124     /* Set the function pointers */
       
   125     this->OpenAudio = OBSD_OpenAudio;
       
   126     this->WaitAudio = OBSD_WaitAudio;
       
   127     this->PlayAudio = OBSD_PlayAudio;
       
   128     this->GetAudioBuf = OBSD_GetAudioBuf;
       
   129     this->CloseAudio = OBSD_CloseAudio;
       
   130 
       
   131     this->free = Audio_DeleteDevice;
       
   132     
       
   133     return this;
       
   134 }
       
   135 
       
   136 AudioBootStrap BSD_AUDIO_bootstrap = {
       
   137 	BSD_AUDIO_DRIVER_NAME, BSD_AUDIO_DRIVER_DESC,
       
   138 	Audio_Available, Audio_CreateDevice
       
   139 };
       
   140 
       
   141 /* This function waits until it is possible to write a full sound buffer */
       
   142 static void
       
   143 OBSD_WaitAudio(_THIS)
       
   144 {
       
   145 #ifndef USE_BLOCKING_WRITES /* Not necessary when using blocking writes */
       
   146 	/* See if we need to use timed audio synchronization */
       
   147 	if ( frame_ticks ) {
       
   148 		/* Use timer for general audio synchronization */
       
   149 		Sint32 ticks;
       
   150 
       
   151 		ticks = ((Sint32)(next_frame - SDL_GetTicks()))-FUDGE_TICKS;
       
   152 		if ( ticks > 0 ) {
       
   153 			SDL_Delay(ticks);
       
   154 		}
       
   155 	} else {
       
   156 		/* Use select() for audio synchronization */
       
   157 		fd_set fdset;
       
   158 		struct timeval timeout;
       
   159 
       
   160 		FD_ZERO(&fdset);
       
   161 		FD_SET(audio_fd, &fdset);
       
   162 		timeout.tv_sec = 10;
       
   163 		timeout.tv_usec = 0;
       
   164 #ifdef DEBUG_AUDIO
       
   165 		fprintf(stderr, "Waiting for audio to get ready\n");
       
   166 #endif
       
   167 		if ( select(audio_fd+1, NULL, &fdset, NULL, &timeout) <= 0 ) {
       
   168 			const char *message =
       
   169 			"Audio timeout - buggy audio driver? (disabled)";
       
   170 			/* In general we should never print to the screen,
       
   171 			   but in this case we have no other way of letting
       
   172 			   the user know what happened.
       
   173 			*/
       
   174 			fprintf(stderr, "SDL: %s\n", message);
       
   175 			this->enabled = 0;
       
   176 			/* Don't try to close - may hang */
       
   177 			audio_fd = -1;
       
   178 #ifdef DEBUG_AUDIO
       
   179 			fprintf(stderr, "Done disabling audio\n");
       
   180 #endif
       
   181 		}
       
   182 #ifdef DEBUG_AUDIO
       
   183 		fprintf(stderr, "Ready!\n");
       
   184 #endif
       
   185 	}
       
   186 #endif /* !USE_BLOCKING_WRITES */
       
   187 }
       
   188 
       
   189 static void
       
   190 OBSD_PlayAudio(_THIS)
       
   191 {
       
   192 	int written, p=0;
       
   193 
       
   194 	/* Write the audio data, checking for EAGAIN on broken audio drivers */
       
   195 	do {
       
   196 		written = write(audio_fd, &mixbuf[p], mixlen-p);
       
   197 		if (written>0)
       
   198 		   p += written;
       
   199 		if (written == -1 && errno != 0 && errno != EAGAIN && errno != EINTR)
       
   200 		{
       
   201 		   /* Non recoverable error has occurred. It should be reported!!! */
       
   202 		   perror("audio");
       
   203 		   break;
       
   204 		}
       
   205 
       
   206 		if ( p < written || ((written < 0) && ((errno == 0) || (errno == EAGAIN))) ) {
       
   207 			SDL_Delay(1);	/* Let a little CPU time go by */
       
   208 		}
       
   209 	} while ( p < written );
       
   210 
       
   211 	/* If timer synchronization is enabled, set the next write frame */
       
   212 	if ( frame_ticks ) {
       
   213 		next_frame += frame_ticks;
       
   214 	}
       
   215 
       
   216 	/* If we couldn't write, assume fatal error for now */
       
   217 	if ( written < 0 ) {
       
   218 		this->enabled = 0;
       
   219 	}
       
   220 #ifdef DEBUG_AUDIO
       
   221 	fprintf(stderr, "Wrote %d bytes of audio data\n", written);
       
   222 #endif
       
   223 }
       
   224 
       
   225 static Uint8
       
   226 *OBSD_GetAudioBuf(_THIS)
       
   227 {
       
   228     return(mixbuf);
       
   229 }
       
   230 
       
   231 static void
       
   232 OBSD_CloseAudio(_THIS)
       
   233 {
       
   234     if(mixbuf != NULL) {
       
   235 	SDL_FreeAudioMem(mixbuf);
       
   236 	mixbuf = NULL;
       
   237     }
       
   238     if(audio_fd >= 0) {
       
   239 	close(audio_fd);
       
   240 	audio_fd = -1;
       
   241     }
       
   242 }
       
   243 
       
   244 #ifdef DEBUG_AUDIO
       
   245 void
       
   246 OBSD_Status(_THIS)
       
   247 {
       
   248     audio_info_t info;
       
   249 
       
   250     if(ioctl(audio_fd, AUDIO_GETINFO, &info) < 0) {
       
   251 	fprintf(stderr,"AUDIO_GETINFO failed.\n");
       
   252 	return;
       
   253     }
       
   254 
       
   255     fprintf(stderr,"\n"
       
   256 "[play/record info]\n"
       
   257 "buffer size	:   %d bytes\n"
       
   258 "sample rate	:   %i Hz\n"
       
   259 "channels	:   %i\n"
       
   260 "precision	:   %i-bit\n"
       
   261 "encoding	:   0x%x\n"
       
   262 "seek		:   %i\n"
       
   263 "sample count	:   %i\n"
       
   264 "EOF count	:   %i\n"
       
   265 "paused		:   %s\n"
       
   266 "error occured	:   %s\n"
       
   267 "waiting		:   %s\n"
       
   268 "active		:   %s\n"
       
   269 "",
       
   270     info.play.buffer_size,
       
   271     info.play.sample_rate,
       
   272     info.play.channels,
       
   273     info.play.precision,
       
   274     info.play.encoding,
       
   275     info.play.seek,
       
   276     info.play.samples,
       
   277     info.play.eof,
       
   278     info.play.pause ? "yes" : "no",
       
   279     info.play.error ? "yes" : "no",
       
   280     info.play.waiting ? "yes" : "no",
       
   281     info.play.active ? "yes": "no");
       
   282 
       
   283     fprintf(stderr,"\n"
       
   284 "[audio info]\n"
       
   285 "monitor_gain	:   %i\n"
       
   286 "hw block size	:   %d bytes\n"
       
   287 "hi watermark	:   %i\n"
       
   288 "lo watermark	:   %i\n"
       
   289 "audio mode	:   %s\n"
       
   290 "",  
       
   291     info.monitor_gain,
       
   292     info.blocksize,
       
   293     info.hiwat, info.lowat,
       
   294     (info.mode == AUMODE_PLAY) ? "PLAY"
       
   295     : (info.mode = AUMODE_RECORD) ? "RECORD"
       
   296     : (info.mode == AUMODE_PLAY_ALL ? "PLAY_ALL"
       
   297     : "?"));
       
   298 }
       
   299 #endif /* DEBUG_AUDIO */
       
   300 
       
   301 static int
       
   302 OBSD_OpenAudio(_THIS, SDL_AudioSpec *spec)
       
   303 {
       
   304     char audiodev[64];
       
   305     Uint16 format;
       
   306     audio_info_t info;
       
   307 
       
   308     AUDIO_INITINFO(&info);
       
   309     
       
   310     /* Calculate the final parameters for this audio specification */
       
   311     SDL_CalculateAudioSpec(spec);
       
   312 
       
   313 #ifdef USE_TIMER_SYNC
       
   314     frame_ticks = 0.0;
       
   315 #endif
       
   316 
       
   317     /* Open the audio device */
       
   318     audio_fd = SDL_OpenAudioPath(audiodev, sizeof(audiodev), OPEN_FLAGS, 0);
       
   319     if(audio_fd < 0) {
       
   320 	SDL_SetError("Couldn't open %s: %s", audiodev, strerror(errno));
       
   321 	return(-1);
       
   322     }
       
   323     
       
   324     /* Set to play mode */
       
   325     info.mode = AUMODE_PLAY;
       
   326     if(ioctl(audio_fd, AUDIO_SETINFO, &info) < 0) {
       
   327 	SDL_SetError("Couldn't put device into play mode");
       
   328 	return(-1);
       
   329     }
       
   330     
       
   331     mixbuf = NULL;
       
   332     AUDIO_INITINFO(&info);
       
   333     for (format = SDL_FirstAudioFormat(spec->format); 
       
   334     	format; format = SDL_NextAudioFormat())
       
   335     {
       
   336 	switch(format) {
       
   337 	case AUDIO_U8:
       
   338 	    info.play.encoding = AUDIO_ENCODING_ULINEAR;
       
   339 	    info.play.precision = 8;
       
   340 	    break;
       
   341 	case AUDIO_S8:
       
   342 	    info.play.encoding = AUDIO_ENCODING_SLINEAR;
       
   343 	    info.play.precision = 8;
       
   344 	    break;
       
   345 	case AUDIO_S16LSB:
       
   346 	    info.play.encoding = AUDIO_ENCODING_SLINEAR_LE;
       
   347 	    info.play.precision = 16;
       
   348 	    break;
       
   349 	case AUDIO_S16MSB:
       
   350 	    info.play.encoding = AUDIO_ENCODING_SLINEAR_BE;
       
   351 	    info.play.precision = 16;
       
   352 	    break;
       
   353 	case AUDIO_U16LSB:
       
   354 	    info.play.encoding = AUDIO_ENCODING_ULINEAR_LE;
       
   355 	    info.play.precision = 16;
       
   356 	    break;
       
   357 	case AUDIO_U16MSB:
       
   358 	    info.play.encoding = AUDIO_ENCODING_ULINEAR_BE;
       
   359 	    info.play.precision = 16;
       
   360 	    break;
       
   361 	default:
       
   362 	    continue;
       
   363 	}
       
   364 	if (ioctl(audio_fd, AUDIO_SETINFO, &info) == 0)
       
   365 	    break;
       
   366     }
       
   367 
       
   368     if(!format) {
       
   369 	SDL_SetError("No supported encoding for 0x%x", spec->format);
       
   370 	return(-1);
       
   371     }
       
   372 
       
   373     spec->format = format;
       
   374 
       
   375     AUDIO_INITINFO(&info);
       
   376     info.play.channels = spec->channels;
       
   377     if (ioctl(audio_fd, AUDIO_SETINFO, &info) == -1)
       
   378     	spec->channels = 1;
       
   379     AUDIO_INITINFO(&info);
       
   380     info.play.sample_rate = spec->freq;
       
   381     info.blocksize = spec->size;
       
   382     info.hiwat = 5;
       
   383     info.lowat = 3;
       
   384     (void)ioctl(audio_fd, AUDIO_SETINFO, &info);
       
   385     (void)ioctl(audio_fd, AUDIO_GETINFO, &info);
       
   386     spec->freq  = info.play.sample_rate;
       
   387     /* Allocate mixing buffer */
       
   388     mixlen = spec->size;
       
   389     mixbuf = (Uint8*)SDL_AllocAudioMem(mixlen);
       
   390     if(mixbuf == NULL) {
       
   391 	return(-1);
       
   392     }
       
   393     SDL_memset(mixbuf, spec->silence, spec->size);
       
   394     
       
   395     /* Get the parent process id (we're the parent of the audio thread) */
       
   396     parent = getpid();
       
   397 
       
   398 #ifdef DEBUG_AUDIO
       
   399     OBSD_Status(this);
       
   400 #endif
       
   401 
       
   402     /* We're ready to rock and roll. :-) */
       
   403     return(0);
       
   404 }