symbian-qemu-0.9.1-12/libsdl-trunk/src/audio/esd/SDL_esdaudio.c
changeset 1 2fb8b9db1c86
equal deleted inserted replaced
0:ffa851df0825 1:2fb8b9db1c86
       
     1 /*
       
     2     SDL - Simple DirectMedia Layer
       
     3     Copyright (C) 1997-2006 Sam Lantinga
       
     4 
       
     5     This library is free software; you can redistribute it and/or
       
     6     modify it under the terms of the GNU Lesser General Public
       
     7     License as published by the Free Software Foundation; either
       
     8     version 2.1 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     Lesser General Public License for more details.
       
    14 
       
    15     You should have received a copy of the GNU Lesser General Public
       
    16     License along with this library; if not, write to the Free Software
       
    17     Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
       
    18 
       
    19     Sam Lantinga
       
    20     slouken@libsdl.org
       
    21 */
       
    22 #include "SDL_config.h"
       
    23 
       
    24 /* Allow access to an ESD network stream mixing buffer */
       
    25 
       
    26 #include <sys/types.h>
       
    27 #include <unistd.h>
       
    28 #include <signal.h>
       
    29 #include <errno.h>
       
    30 #include <esd.h>
       
    31 
       
    32 #include "SDL_timer.h"
       
    33 #include "SDL_audio.h"
       
    34 #include "../SDL_audiomem.h"
       
    35 #include "../SDL_audio_c.h"
       
    36 #include "../SDL_audiodev_c.h"
       
    37 #include "SDL_esdaudio.h"
       
    38 
       
    39 #ifdef SDL_AUDIO_DRIVER_ESD_DYNAMIC
       
    40 #include "SDL_name.h"
       
    41 #include "SDL_loadso.h"
       
    42 #else
       
    43 #define SDL_NAME(X)	X
       
    44 #endif
       
    45 
       
    46 /* The tag name used by ESD audio */
       
    47 #define ESD_DRIVER_NAME		"esd"
       
    48 
       
    49 /* Audio driver functions */
       
    50 static int ESD_OpenAudio(_THIS, SDL_AudioSpec *spec);
       
    51 static void ESD_WaitAudio(_THIS);
       
    52 static void ESD_PlayAudio(_THIS);
       
    53 static Uint8 *ESD_GetAudioBuf(_THIS);
       
    54 static void ESD_CloseAudio(_THIS);
       
    55 
       
    56 #ifdef SDL_AUDIO_DRIVER_ESD_DYNAMIC
       
    57 
       
    58 static const char *esd_library = SDL_AUDIO_DRIVER_ESD_DYNAMIC;
       
    59 static void *esd_handle = NULL;
       
    60 static int esd_loaded = 0;
       
    61 
       
    62 static int (*SDL_NAME(esd_open_sound))( const char *host );
       
    63 static int (*SDL_NAME(esd_close))( int esd );
       
    64 static int (*SDL_NAME(esd_play_stream))( esd_format_t format, int rate,
       
    65                                          const char *host, const char *name );
       
    66 static struct {
       
    67 	const char *name;
       
    68 	void **func;
       
    69 } esd_functions[] = {
       
    70 	{ "esd_open_sound",	(void **)&SDL_NAME(esd_open_sound)	},
       
    71 	{ "esd_close",		(void **)&SDL_NAME(esd_close)		},
       
    72 	{ "esd_play_stream",	(void **)&SDL_NAME(esd_play_stream)	},
       
    73 };
       
    74 
       
    75 static void UnloadESDLibrary()
       
    76 {
       
    77 	if ( esd_loaded ) {
       
    78 		SDL_UnloadObject(esd_handle);
       
    79 		esd_handle = NULL;
       
    80 		esd_loaded = 0;
       
    81 	}
       
    82 }
       
    83 
       
    84 static int LoadESDLibrary(void)
       
    85 {
       
    86 	int i, retval = -1;
       
    87 
       
    88 	esd_handle = SDL_LoadObject(esd_library);
       
    89 	if ( esd_handle ) {
       
    90 		esd_loaded = 1;
       
    91 		retval = 0;
       
    92 		for ( i=0; i<SDL_arraysize(esd_functions); ++i ) {
       
    93 			*esd_functions[i].func = SDL_LoadFunction(esd_handle, esd_functions[i].name);
       
    94 			if ( !*esd_functions[i].func ) {
       
    95 				retval = -1;
       
    96 				UnloadESDLibrary();
       
    97 				break;
       
    98 			}
       
    99 		}
       
   100 	}
       
   101 	return retval;
       
   102 }
       
   103 
       
   104 #else
       
   105 
       
   106 static void UnloadESDLibrary()
       
   107 {
       
   108 	return;
       
   109 }
       
   110 
       
   111 static int LoadESDLibrary(void)
       
   112 {
       
   113 	return 0;
       
   114 }
       
   115 
       
   116 #endif /* SDL_AUDIO_DRIVER_ESD_DYNAMIC */
       
   117 
       
   118 /* Audio driver bootstrap functions */
       
   119 
       
   120 static int Audio_Available(void)
       
   121 {
       
   122 	int connection;
       
   123 	int available;
       
   124 
       
   125 	available = 0;
       
   126 	if ( LoadESDLibrary() < 0 ) {
       
   127 		return available;
       
   128 	}
       
   129 	connection = SDL_NAME(esd_open_sound)(NULL);
       
   130 	if ( connection >= 0 ) {
       
   131 		available = 1;
       
   132 		SDL_NAME(esd_close)(connection);
       
   133 	}
       
   134 	UnloadESDLibrary();
       
   135 	return(available);
       
   136 }
       
   137 
       
   138 static void Audio_DeleteDevice(SDL_AudioDevice *device)
       
   139 {
       
   140 	SDL_free(device->hidden);
       
   141 	SDL_free(device);
       
   142 	UnloadESDLibrary();
       
   143 }
       
   144 
       
   145 static SDL_AudioDevice *Audio_CreateDevice(int devindex)
       
   146 {
       
   147 	SDL_AudioDevice *this;
       
   148 
       
   149 	/* Initialize all variables that we clean on shutdown */
       
   150 	LoadESDLibrary();
       
   151 	this = (SDL_AudioDevice *)SDL_malloc(sizeof(SDL_AudioDevice));
       
   152 	if ( this ) {
       
   153 		SDL_memset(this, 0, (sizeof *this));
       
   154 		this->hidden = (struct SDL_PrivateAudioData *)
       
   155 				SDL_malloc((sizeof *this->hidden));
       
   156 	}
       
   157 	if ( (this == NULL) || (this->hidden == NULL) ) {
       
   158 		SDL_OutOfMemory();
       
   159 		if ( this ) {
       
   160 			SDL_free(this);
       
   161 		}
       
   162 		return(0);
       
   163 	}
       
   164 	SDL_memset(this->hidden, 0, (sizeof *this->hidden));
       
   165 	audio_fd = -1;
       
   166 
       
   167 	/* Set the function pointers */
       
   168 	this->OpenAudio = ESD_OpenAudio;
       
   169 	this->WaitAudio = ESD_WaitAudio;
       
   170 	this->PlayAudio = ESD_PlayAudio;
       
   171 	this->GetAudioBuf = ESD_GetAudioBuf;
       
   172 	this->CloseAudio = ESD_CloseAudio;
       
   173 
       
   174 	this->free = Audio_DeleteDevice;
       
   175 
       
   176 	return this;
       
   177 }
       
   178 
       
   179 AudioBootStrap ESD_bootstrap = {
       
   180 	ESD_DRIVER_NAME, "Enlightened Sound Daemon",
       
   181 	Audio_Available, Audio_CreateDevice
       
   182 };
       
   183 
       
   184 /* This function waits until it is possible to write a full sound buffer */
       
   185 static void ESD_WaitAudio(_THIS)
       
   186 {
       
   187 	Sint32 ticks;
       
   188 
       
   189 	/* Check to see if the thread-parent process is still alive */
       
   190 	{ static int cnt = 0;
       
   191 		/* Note that this only works with thread implementations 
       
   192 		   that use a different process id for each thread.
       
   193 		*/
       
   194 		if (parent && (((++cnt)%10) == 0)) { /* Check every 10 loops */
       
   195 			if ( kill(parent, 0) < 0 ) {
       
   196 				this->enabled = 0;
       
   197 			}
       
   198 		}
       
   199 	}
       
   200 
       
   201 	/* Use timer for general audio synchronization */
       
   202 	ticks = ((Sint32)(next_frame - SDL_GetTicks()))-FUDGE_TICKS;
       
   203 	if ( ticks > 0 ) {
       
   204 		SDL_Delay(ticks);
       
   205 	}
       
   206 }
       
   207 
       
   208 static void ESD_PlayAudio(_THIS)
       
   209 {
       
   210 	int written;
       
   211 
       
   212 	/* Write the audio data, checking for EAGAIN on broken audio drivers */
       
   213 	do {
       
   214 		written = write(audio_fd, mixbuf, mixlen);
       
   215 		if ( (written < 0) && ((errno == 0) || (errno == EAGAIN)) ) {
       
   216 			SDL_Delay(1);	/* Let a little CPU time go by */
       
   217 		}
       
   218 	} while ( (written < 0) && 
       
   219 	          ((errno == 0) || (errno == EAGAIN) || (errno == EINTR)) );
       
   220 
       
   221 	/* Set the next write frame */
       
   222 	next_frame += frame_ticks;
       
   223 
       
   224 	/* If we couldn't write, assume fatal error for now */
       
   225 	if ( written < 0 ) {
       
   226 		this->enabled = 0;
       
   227 	}
       
   228 }
       
   229 
       
   230 static Uint8 *ESD_GetAudioBuf(_THIS)
       
   231 {
       
   232 	return(mixbuf);
       
   233 }
       
   234 
       
   235 static void ESD_CloseAudio(_THIS)
       
   236 {
       
   237 	if ( mixbuf != NULL ) {
       
   238 		SDL_FreeAudioMem(mixbuf);
       
   239 		mixbuf = NULL;
       
   240 	}
       
   241 	if ( audio_fd >= 0 ) {
       
   242 		SDL_NAME(esd_close)(audio_fd);
       
   243 		audio_fd = -1;
       
   244 	}
       
   245 }
       
   246 
       
   247 /* Try to get the name of the program */
       
   248 static char *get_progname(void)
       
   249 {
       
   250 	char *progname = NULL;
       
   251 #ifdef __LINUX__
       
   252 	FILE *fp;
       
   253 	static char temp[BUFSIZ];
       
   254 
       
   255 	SDL_snprintf(temp, SDL_arraysize(temp), "/proc/%d/cmdline", getpid());
       
   256 	fp = fopen(temp, "r");
       
   257 	if ( fp != NULL ) {
       
   258 		if ( fgets(temp, sizeof(temp)-1, fp) ) {
       
   259 			progname = SDL_strrchr(temp, '/');
       
   260 			if ( progname == NULL ) {
       
   261 				progname = temp;
       
   262 			} else {
       
   263 				progname = progname+1;
       
   264 			}
       
   265 		}
       
   266 		fclose(fp);
       
   267 	}
       
   268 #endif
       
   269 	return(progname);
       
   270 }
       
   271 
       
   272 static int ESD_OpenAudio(_THIS, SDL_AudioSpec *spec)
       
   273 {
       
   274 	esd_format_t format;
       
   275 
       
   276 	/* Convert audio spec to the ESD audio format */
       
   277 	format = (ESD_STREAM | ESD_PLAY);
       
   278 	switch ( spec->format & 0xFF ) {
       
   279 		case 8:
       
   280 			format |= ESD_BITS8;
       
   281 			break;
       
   282 		case 16:
       
   283 			format |= ESD_BITS16;
       
   284 			break;
       
   285 		default:
       
   286 			SDL_SetError("Unsupported ESD audio format");
       
   287 			return(-1);
       
   288 	}
       
   289 	if ( spec->channels == 1 ) {
       
   290 		format |= ESD_MONO;
       
   291 	} else {
       
   292 		format |= ESD_STEREO;
       
   293 	}
       
   294 #if 0
       
   295 	spec->samples = ESD_BUF_SIZE;	/* Darn, no way to change this yet */
       
   296 #endif
       
   297 
       
   298 	/* Open a connection to the ESD audio server */
       
   299 	audio_fd = SDL_NAME(esd_play_stream)(format, spec->freq, NULL, get_progname());
       
   300 	if ( audio_fd < 0 ) {
       
   301 		SDL_SetError("Couldn't open ESD connection");
       
   302 		return(-1);
       
   303 	}
       
   304 
       
   305 	/* Calculate the final parameters for this audio specification */
       
   306 	SDL_CalculateAudioSpec(spec);
       
   307 	frame_ticks = (float)(spec->samples*1000)/spec->freq;
       
   308 	next_frame = SDL_GetTicks()+frame_ticks;
       
   309 
       
   310 	/* Allocate mixing buffer */
       
   311 	mixlen = spec->size;
       
   312 	mixbuf = (Uint8 *)SDL_AllocAudioMem(mixlen);
       
   313 	if ( mixbuf == NULL ) {
       
   314 		return(-1);
       
   315 	}
       
   316 	SDL_memset(mixbuf, spec->silence, spec->size);
       
   317 
       
   318 	/* Get the parent process id (we're the parent of the audio thread) */
       
   319 	parent = getpid();
       
   320 
       
   321 	/* We're ready to rock and roll. :-) */
       
   322 	return(0);
       
   323 }