symbian-qemu-0.9.1-12/libsdl-trunk/src/audio/arts/SDL_artsaudio.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 a raw mixing buffer */
       
    25 
       
    26 #ifdef HAVE_SIGNAL_H
       
    27 #include <signal.h>
       
    28 #endif
       
    29 #include <unistd.h>
       
    30 
       
    31 #include "SDL_timer.h"
       
    32 #include "SDL_audio.h"
       
    33 #include "../SDL_audiomem.h"
       
    34 #include "../SDL_audio_c.h"
       
    35 #include "../SDL_audiodev_c.h"
       
    36 #include "SDL_artsaudio.h"
       
    37 
       
    38 #ifdef SDL_AUDIO_DRIVER_ARTS_DYNAMIC
       
    39 #include "SDL_name.h"
       
    40 #include "SDL_loadso.h"
       
    41 #else
       
    42 #define SDL_NAME(X)	X
       
    43 #endif
       
    44 
       
    45 /* The tag name used by artsc audio */
       
    46 #define ARTS_DRIVER_NAME         "arts"
       
    47 
       
    48 /* Audio driver functions */
       
    49 static int ARTS_OpenAudio(_THIS, SDL_AudioSpec *spec);
       
    50 static void ARTS_WaitAudio(_THIS);
       
    51 static void ARTS_PlayAudio(_THIS);
       
    52 static Uint8 *ARTS_GetAudioBuf(_THIS);
       
    53 static void ARTS_CloseAudio(_THIS);
       
    54 
       
    55 #ifdef SDL_AUDIO_DRIVER_ARTS_DYNAMIC
       
    56 
       
    57 static const char *arts_library = SDL_AUDIO_DRIVER_ARTS_DYNAMIC;
       
    58 static void *arts_handle = NULL;
       
    59 static int arts_loaded = 0;
       
    60 
       
    61 static int (*SDL_NAME(arts_init))(void);
       
    62 static void (*SDL_NAME(arts_free))(void);
       
    63 static arts_stream_t (*SDL_NAME(arts_play_stream))(int rate, int bits, int channels, const char *name);
       
    64 static int (*SDL_NAME(arts_stream_set))(arts_stream_t s, arts_parameter_t param, int value);
       
    65 static int (*SDL_NAME(arts_stream_get))(arts_stream_t s, arts_parameter_t param);
       
    66 static int (*SDL_NAME(arts_write))(arts_stream_t s, const void *buffer, int count);
       
    67 static void (*SDL_NAME(arts_close_stream))(arts_stream_t s);
       
    68 static int (*SDL_NAME(arts_suspended))(void);
       
    69 static const char *(*SDL_NAME(arts_error_text))(int errorcode);
       
    70 
       
    71 static struct {
       
    72 	const char *name;
       
    73 	void **func;
       
    74 } arts_functions[] = {
       
    75 	{ "arts_init",		(void **)&SDL_NAME(arts_init)		},
       
    76 	{ "arts_free",		(void **)&SDL_NAME(arts_free)		},
       
    77 	{ "arts_play_stream",	(void **)&SDL_NAME(arts_play_stream)	},
       
    78 	{ "arts_stream_set",	(void **)&SDL_NAME(arts_stream_set)	},
       
    79 	{ "arts_stream_get",	(void **)&SDL_NAME(arts_stream_get)	},
       
    80 	{ "arts_write",		(void **)&SDL_NAME(arts_write)		},
       
    81 	{ "arts_close_stream",	(void **)&SDL_NAME(arts_close_stream)	},
       
    82 	{ "arts_suspended",	(void **)&SDL_NAME(arts_suspended)	},
       
    83 	{ "arts_error_text",	(void **)&SDL_NAME(arts_error_text)	},
       
    84 };
       
    85 
       
    86 static void UnloadARTSLibrary()
       
    87 {
       
    88 	if ( arts_loaded ) {
       
    89 		SDL_UnloadObject(arts_handle);
       
    90 		arts_handle = NULL;
       
    91 		arts_loaded = 0;
       
    92 	}
       
    93 }
       
    94 
       
    95 static int LoadARTSLibrary(void)
       
    96 {
       
    97 	int i, retval = -1;
       
    98 
       
    99 	arts_handle = SDL_LoadObject(arts_library);
       
   100 	if ( arts_handle ) {
       
   101 		arts_loaded = 1;
       
   102 		retval = 0;
       
   103 		for ( i=0; i<SDL_arraysize(arts_functions); ++i ) {
       
   104 			*arts_functions[i].func = SDL_LoadFunction(arts_handle, arts_functions[i].name);
       
   105 			if ( !*arts_functions[i].func ) {
       
   106 				retval = -1;
       
   107 				UnloadARTSLibrary();
       
   108 				break;
       
   109 			}
       
   110 		}
       
   111 	}
       
   112 	return retval;
       
   113 }
       
   114 
       
   115 #else
       
   116 
       
   117 static void UnloadARTSLibrary()
       
   118 {
       
   119 	return;
       
   120 }
       
   121 
       
   122 static int LoadARTSLibrary(void)
       
   123 {
       
   124 	return 0;
       
   125 }
       
   126 
       
   127 #endif /* SDL_AUDIO_DRIVER_ARTS_DYNAMIC */
       
   128 
       
   129 /* Audio driver bootstrap functions */
       
   130 
       
   131 static int Audio_Available(void)
       
   132 {
       
   133 	int available = 0;
       
   134 
       
   135 	if ( LoadARTSLibrary() < 0 ) {
       
   136 		return available;
       
   137 	}
       
   138 	if ( SDL_NAME(arts_init)() == 0 ) {
       
   139 		if ( SDL_NAME(arts_suspended)() ) {
       
   140 			/* Play a stream so aRts doesn't crash */
       
   141 			arts_stream_t stream2;
       
   142 			stream2=SDL_NAME(arts_play_stream)(44100, 16, 2, "SDL");
       
   143 			SDL_NAME(arts_write)(stream2, "", 0);
       
   144 			SDL_NAME(arts_close_stream)(stream2);
       
   145 			available = 1;
       
   146 		}
       
   147 		SDL_NAME(arts_free)();
       
   148 	}
       
   149 	UnloadARTSLibrary();
       
   150 
       
   151 	return available;
       
   152 }
       
   153 
       
   154 static void Audio_DeleteDevice(SDL_AudioDevice *device)
       
   155 {
       
   156 	SDL_free(device->hidden);
       
   157 	SDL_free(device);
       
   158 	UnloadARTSLibrary();
       
   159 }
       
   160 
       
   161 static SDL_AudioDevice *Audio_CreateDevice(int devindex)
       
   162 {
       
   163 	SDL_AudioDevice *this;
       
   164 
       
   165 	/* Initialize all variables that we clean on shutdown */
       
   166 	LoadARTSLibrary();
       
   167 	this = (SDL_AudioDevice *)SDL_malloc(sizeof(SDL_AudioDevice));
       
   168 	if ( this ) {
       
   169 		SDL_memset(this, 0, (sizeof *this));
       
   170 		this->hidden = (struct SDL_PrivateAudioData *)
       
   171 				SDL_malloc((sizeof *this->hidden));
       
   172 	}
       
   173 	if ( (this == NULL) || (this->hidden == NULL) ) {
       
   174 		SDL_OutOfMemory();
       
   175 		if ( this ) {
       
   176 			SDL_free(this);
       
   177 		}
       
   178 		return(0);
       
   179 	}
       
   180 	SDL_memset(this->hidden, 0, (sizeof *this->hidden));
       
   181 	stream = 0;
       
   182 
       
   183 	/* Set the function pointers */
       
   184 	this->OpenAudio = ARTS_OpenAudio;
       
   185 	this->WaitAudio = ARTS_WaitAudio;
       
   186 	this->PlayAudio = ARTS_PlayAudio;
       
   187 	this->GetAudioBuf = ARTS_GetAudioBuf;
       
   188 	this->CloseAudio = ARTS_CloseAudio;
       
   189 
       
   190 	this->free = Audio_DeleteDevice;
       
   191 
       
   192 	return this;
       
   193 }
       
   194 
       
   195 AudioBootStrap ARTS_bootstrap = {
       
   196 	ARTS_DRIVER_NAME, "Analog Realtime Synthesizer",
       
   197 	Audio_Available, Audio_CreateDevice
       
   198 };
       
   199 
       
   200 /* This function waits until it is possible to write a full sound buffer */
       
   201 static void ARTS_WaitAudio(_THIS)
       
   202 {
       
   203 	Sint32 ticks;
       
   204 
       
   205 	/* Check to see if the thread-parent process is still alive */
       
   206 	{ static int cnt = 0;
       
   207 		/* Note that this only works with thread implementations 
       
   208 		   that use a different process id for each thread.
       
   209 		*/
       
   210 		if (parent && (((++cnt)%10) == 0)) { /* Check every 10 loops */
       
   211 			if ( kill(parent, 0) < 0 ) {
       
   212 				this->enabled = 0;
       
   213 			}
       
   214 		}
       
   215 	}
       
   216 
       
   217 	/* Use timer for general audio synchronization */
       
   218 	ticks = ((Sint32)(next_frame - SDL_GetTicks()))-FUDGE_TICKS;
       
   219 	if ( ticks > 0 ) {
       
   220 		SDL_Delay(ticks);
       
   221 	}
       
   222 }
       
   223 
       
   224 static void ARTS_PlayAudio(_THIS)
       
   225 {
       
   226 	int written;
       
   227 
       
   228 	/* Write the audio data */
       
   229 	written = SDL_NAME(arts_write)(stream, mixbuf, mixlen);
       
   230 	
       
   231 	/* If timer synchronization is enabled, set the next write frame */
       
   232 	if ( frame_ticks ) {
       
   233 		next_frame += frame_ticks;
       
   234 	}
       
   235 
       
   236 	/* If we couldn't write, assume fatal error for now */
       
   237 	if ( written < 0 ) {
       
   238 		this->enabled = 0;
       
   239 	}
       
   240 #ifdef DEBUG_AUDIO
       
   241 	fprintf(stderr, "Wrote %d bytes of audio data\n", written);
       
   242 #endif
       
   243 }
       
   244 
       
   245 static Uint8 *ARTS_GetAudioBuf(_THIS)
       
   246 {
       
   247 	return(mixbuf);
       
   248 }
       
   249 
       
   250 static void ARTS_CloseAudio(_THIS)
       
   251 {
       
   252 	if ( mixbuf != NULL ) {
       
   253 		SDL_FreeAudioMem(mixbuf);
       
   254 		mixbuf = NULL;
       
   255 	}
       
   256 	if ( stream ) {
       
   257 		SDL_NAME(arts_close_stream)(stream);
       
   258 		stream = 0;
       
   259 	}
       
   260 	SDL_NAME(arts_free)();
       
   261 }
       
   262 
       
   263 static int ARTS_OpenAudio(_THIS, SDL_AudioSpec *spec)
       
   264 {
       
   265 	int bits, frag_spec;
       
   266 	Uint16 test_format, format;
       
   267 	int error_code;
       
   268 
       
   269 	/* Reset the timer synchronization flag */
       
   270 	frame_ticks = 0.0;
       
   271 
       
   272 	mixbuf = NULL;
       
   273 
       
   274 	/* Try for a closest match on audio format */
       
   275 	format = 0;
       
   276 	bits = 0;
       
   277 	for ( test_format = SDL_FirstAudioFormat(spec->format);
       
   278 						! format && test_format; ) {
       
   279 #ifdef DEBUG_AUDIO
       
   280 		fprintf(stderr, "Trying format 0x%4.4x\n", test_format);
       
   281 #endif
       
   282 		switch ( test_format ) {
       
   283 			case AUDIO_U8:
       
   284 				bits = 8;
       
   285 				format = 1;
       
   286 				break;
       
   287 			case AUDIO_S16LSB:
       
   288 				bits = 16;
       
   289 				format = 1;
       
   290 				break;
       
   291 			default:
       
   292 				format = 0;
       
   293 				break;
       
   294 		}
       
   295 		if ( ! format ) {
       
   296 			test_format = SDL_NextAudioFormat();
       
   297 		}
       
   298 	}
       
   299 	if ( format == 0 ) {
       
   300 		SDL_SetError("Couldn't find any hardware audio formats");
       
   301 		return(-1);
       
   302 	}
       
   303 	spec->format = test_format;
       
   304 
       
   305 	error_code = SDL_NAME(arts_init)();
       
   306 	if ( error_code != 0 ) {
       
   307 		SDL_SetError("Unable to initialize ARTS: %s", SDL_NAME(arts_error_text)(error_code));
       
   308 		return(-1);
       
   309 	}
       
   310 	if ( ! SDL_NAME(arts_suspended)() ) {
       
   311 		SDL_SetError("ARTS can not open audio device");
       
   312 		return(-1);
       
   313 	}
       
   314 	stream = SDL_NAME(arts_play_stream)(spec->freq, bits, spec->channels, "SDL");
       
   315 
       
   316 	/* Calculate the final parameters for this audio specification */
       
   317 	SDL_CalculateAudioSpec(spec);
       
   318 
       
   319 	/* Determine the power of two of the fragment size */
       
   320 	for ( frag_spec = 0; (0x01<<frag_spec) < spec->size; ++frag_spec );
       
   321 	if ( (0x01<<frag_spec) != spec->size ) {
       
   322 		SDL_SetError("Fragment size must be a power of two");
       
   323 		return(-1);
       
   324 	}
       
   325 	frag_spec |= 0x00020000;	/* two fragments, for low latency */
       
   326 
       
   327 #ifdef ARTS_P_PACKET_SETTINGS
       
   328 	SDL_NAME(arts_stream_set)(stream, ARTS_P_PACKET_SETTINGS, frag_spec);
       
   329 #else
       
   330 	SDL_NAME(arts_stream_set)(stream, ARTS_P_PACKET_SIZE, frag_spec&0xffff);
       
   331 	SDL_NAME(arts_stream_set)(stream, ARTS_P_PACKET_COUNT, frag_spec>>16);
       
   332 #endif
       
   333 	spec->size = SDL_NAME(arts_stream_get)(stream, ARTS_P_PACKET_SIZE);
       
   334 
       
   335 	/* Allocate mixing buffer */
       
   336 	mixlen = spec->size;
       
   337 	mixbuf = (Uint8 *)SDL_AllocAudioMem(mixlen);
       
   338 	if ( mixbuf == NULL ) {
       
   339 		return(-1);
       
   340 	}
       
   341 	SDL_memset(mixbuf, spec->silence, spec->size);
       
   342 
       
   343 	/* Get the parent process id (we're the parent of the audio thread) */
       
   344 	parent = getpid();
       
   345 
       
   346 	/* We're ready to rock and roll. :-) */
       
   347 	return(0);
       
   348 }