Atlas - SDL_artsaudio.c
Home / ext / SDL2 / src / audio / arts Lines: 3 | Size: 10609 bytes [Download] [Show on GitHub] [Search similar files] [Raw] [Raw (proxy)][FILE BEGIN]1/* 2 Simple DirectMedia Layer 3 Copyright (C) 1997-2018 Sam Lantinga <[email protected]> 4 5 This software is provided 'as-is', without any express or implied 6 warranty. In no event will the authors be held liable for any damages 7 arising from the use of this software. 8 9 Permission is granted to anyone to use this software for any purpose, 10 including commercial applications, and to alter it and redistribute it 11 freely, subject to the following restrictions: 12 13 1. The origin of this software must not be misrepresented; you must not 14 claim that you wrote the original software. If you use this software 15 in a product, an acknowledgment in the product documentation would be 16 appreciated but is not required. 17 2. Altered source versions must be plainly marked as such, and must not be 18 misrepresented as being the original software. 19 3. This notice may not be removed or altered from any source distribution. 20*/ 21#include "../../SDL_internal.h" 22 23#if SDL_AUDIO_DRIVER_ARTS 24 25/* Allow access to a raw mixing buffer */ 26 27#ifdef HAVE_SIGNAL_H 28#include <signal.h> 29#endif 30#include <unistd.h> 31#include <errno.h> 32 33#include "SDL_timer.h" 34#include "SDL_audio.h" 35#include "../SDL_audio_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#ifdef SDL_AUDIO_DRIVER_ARTS_DYNAMIC 46 47static const char *arts_library = SDL_AUDIO_DRIVER_ARTS_DYNAMIC; 48static void *arts_handle = NULL; 49 50/* !!! FIXME: I hate this SDL_NAME clutter...it makes everything so messy! */ 51static int (*SDL_NAME(arts_init)) (void); 52static void (*SDL_NAME(arts_free)) (void); 53static arts_stream_t(*SDL_NAME(arts_play_stream)) (int rate, int bits, 54 int channels, 55 const char *name); 56static int (*SDL_NAME(arts_stream_set)) (arts_stream_t s, 57 arts_parameter_t param, int value); 58static int (*SDL_NAME(arts_stream_get)) (arts_stream_t s, 59 arts_parameter_t param); 60static int (*SDL_NAME(arts_write)) (arts_stream_t s, const void *buffer, 61 int count); 62static void (*SDL_NAME(arts_close_stream)) (arts_stream_t s); 63static int (*SDL_NAME(arts_suspend))(void); 64static int (*SDL_NAME(arts_suspended)) (void); 65static const char *(*SDL_NAME(arts_error_text)) (int errorcode); 66 67#define SDL_ARTS_SYM(x) { #x, (void **) (char *) &SDL_NAME(x) } 68static struct 69{ 70 const char *name; 71 void **func; 72} arts_functions[] = { 73/* *INDENT-OFF* */ 74 SDL_ARTS_SYM(arts_init), 75 SDL_ARTS_SYM(arts_free), 76 SDL_ARTS_SYM(arts_play_stream), 77 SDL_ARTS_SYM(arts_stream_set), 78 SDL_ARTS_SYM(arts_stream_get), 79 SDL_ARTS_SYM(arts_write), 80 SDL_ARTS_SYM(arts_close_stream), 81 SDL_ARTS_SYM(arts_suspend), 82 SDL_ARTS_SYM(arts_suspended), 83 SDL_ARTS_SYM(arts_error_text), 84/* *INDENT-ON* */ 85}; 86 87#undef SDL_ARTS_SYM 88 89static void 90UnloadARTSLibrary() 91{ 92 if (arts_handle != NULL) { 93 SDL_UnloadObject(arts_handle); 94 arts_handle = NULL; 95 } 96} 97 98static int 99LoadARTSLibrary(void) 100{ 101 int i, retval = -1; 102 103 if (arts_handle == NULL) { 104 arts_handle = SDL_LoadObject(arts_library); 105 if (arts_handle != NULL) { 106 retval = 0; 107 for (i = 0; i < SDL_arraysize(arts_functions); ++i) { 108 *arts_functions[i].func = 109 SDL_LoadFunction(arts_handle, arts_functions[i].name); 110 if (!*arts_functions[i].func) { 111 retval = -1; 112 UnloadARTSLibrary(); 113 break; 114 } 115 } 116 } 117 } 118 119 return retval; 120} 121 122#else 123 124static void 125UnloadARTSLibrary() 126{ 127 return; 128} 129 130static int 131LoadARTSLibrary(void) 132{ 133 return 0; 134} 135 136#endif /* SDL_AUDIO_DRIVER_ARTS_DYNAMIC */ 137 138/* This function waits until it is possible to write a full sound buffer */ 139static void 140ARTS_WaitDevice(_THIS) 141{ 142 Sint32 ticks; 143 144 /* Check to see if the thread-parent process is still alive */ 145 { 146 static int cnt = 0; 147 /* Note that this only works with thread implementations 148 that use a different process id for each thread. 149 */ 150 /* Check every 10 loops */ 151 if (this->hidden->parent && (((++cnt) % 10) == 0)) { 152 if (kill(this->hidden->parent, 0) < 0 && errno == ESRCH) { 153 SDL_OpenedAudioDeviceDisconnected(this); 154 } 155 } 156 } 157 158 /* Use timer for general audio synchronization */ 159 ticks = 160 ((Sint32) (this->hidden->next_frame - SDL_GetTicks())) - FUDGE_TICKS; 161 if (ticks > 0) { 162 SDL_Delay(ticks); 163 } 164} 165 166static void 167ARTS_PlayDevice(_THIS) 168{ 169 /* Write the audio data */ 170 int written = SDL_NAME(arts_write) (this->hidden->stream, 171 this->hidden->mixbuf, 172 this->hidden->mixlen); 173 174 /* If timer synchronization is enabled, set the next write frame */ 175 if (this->hidden->frame_ticks) { 176 this->hidden->next_frame += this->hidden->frame_ticks; 177 } 178 179 /* If we couldn't write, assume fatal error for now */ 180 if (written < 0) { 181 SDL_OpenedAudioDeviceDisconnected(this); 182 } 183#ifdef DEBUG_AUDIO 184 fprintf(stderr, "Wrote %d bytes of audio data\n", written); 185#endif 186} 187 188static Uint8 * 189ARTS_GetDeviceBuf(_THIS) 190{ 191 return (this->hidden->mixbuf); 192} 193 194 195static void 196ARTS_CloseDevice(_THIS) 197{ 198 if (this->hidden->stream) { 199 SDL_NAME(arts_close_stream) (this->hidden->stream); 200 } 201 SDL_NAME(arts_free) (); 202 SDL_free(this->hidden->mixbuf); 203 SDL_free(this->hidden); 204} 205 206static int 207ARTS_Suspend(void) 208{ 209 const Uint32 abortms = SDL_GetTicks() + 3000; /* give up after 3 secs */ 210 while ( (!SDL_NAME(arts_suspended)()) && !SDL_TICKS_PASSED(SDL_GetTicks(), abortms) ) { 211 if ( SDL_NAME(arts_suspend)() ) { 212 break; 213 } 214 } 215 return SDL_NAME(arts_suspended)(); 216} 217 218static int 219ARTS_OpenDevice(_THIS, void *handle, const char *devname, int iscapture) 220{ 221 int rc = 0; 222 int bits = 0, frag_spec = 0; 223 SDL_AudioFormat test_format = 0, format = 0; 224 225 /* Initialize all variables that we clean on shutdown */ 226 this->hidden = (struct SDL_PrivateAudioData *) 227 SDL_malloc((sizeof *this->hidden)); 228 if (this->hidden == NULL) { 229 return SDL_OutOfMemory(); 230 } 231 SDL_zerop(this->hidden); 232 233 /* Try for a closest match on audio format */ 234 for (test_format = SDL_FirstAudioFormat(this->spec.format); 235 !format && test_format;) { 236#ifdef DEBUG_AUDIO 237 fprintf(stderr, "Trying format 0x%4.4x\n", test_format); 238#endif 239 switch (test_format) { 240 case AUDIO_U8: 241 bits = 8; 242 format = 1; 243 break; 244 case AUDIO_S16LSB: 245 bits = 16; 246 format = 1; 247 break; 248 default: 249 format = 0; 250 break; 251 } 252 if (!format) { 253 test_format = SDL_NextAudioFormat(); 254 } 255 } 256 if (format == 0) { 257 return SDL_SetError("Couldn't find any hardware audio formats"); 258 } 259 this->spec.format = test_format; 260 261 if ((rc = SDL_NAME(arts_init) ()) != 0) { 262 return SDL_SetError("Unable to initialize ARTS: %s", 263 SDL_NAME(arts_error_text) (rc)); 264 } 265 266 if (!ARTS_Suspend()) { 267 return SDL_SetError("ARTS can not open audio device"); 268 } 269 270 this->hidden->stream = SDL_NAME(arts_play_stream) (this->spec.freq, 271 bits, 272 this->spec.channels, 273 "SDL"); 274 275 /* Play nothing so we have at least one write (server bug workaround). */ 276 SDL_NAME(arts_write) (this->hidden->stream, "", 0); 277 278 /* Calculate the final parameters for this audio specification */ 279 SDL_CalculateAudioSpec(&this->spec); 280 281 /* Determine the power of two of the fragment size */ 282 for (frag_spec = 0; (0x01 << frag_spec) < this->spec.size; ++frag_spec); 283 if ((0x01 << frag_spec) != this->spec.size) { 284 return SDL_SetError("Fragment size must be a power of two"); 285 } 286 frag_spec |= 0x00020000; /* two fragments, for low latency */ 287 288#ifdef ARTS_P_PACKET_SETTINGS 289 SDL_NAME(arts_stream_set) (this->hidden->stream, 290 ARTS_P_PACKET_SETTINGS, frag_spec); 291#else 292 SDL_NAME(arts_stream_set) (this->hidden->stream, ARTS_P_PACKET_SIZE, 293 frag_spec & 0xffff); 294 SDL_NAME(arts_stream_set) (this->hidden->stream, ARTS_P_PACKET_COUNT, 295 frag_spec >> 16); 296#endif 297 this->spec.size = SDL_NAME(arts_stream_get) (this->hidden->stream, 298 ARTS_P_PACKET_SIZE); 299 300 /* Allocate mixing buffer */ 301 this->hidden->mixlen = this->spec.size; 302 this->hidden->mixbuf = (Uint8 *) SDL_malloc(this->hidden->mixlen); 303 if (this->hidden->mixbuf == NULL) { 304 return SDL_OutOfMemory(); 305 } 306 SDL_memset(this->hidden->mixbuf, this->spec.silence, this->spec.size); 307 308 /* Get the parent process id (we're the parent of the audio thread) */ 309 this->hidden->parent = getpid(); 310 311 /* We're ready to rock and roll. :-) */ 312 return 0; 313} 314 315 316static void 317ARTS_Deinitialize(void) 318{ 319 UnloadARTSLibrary(); 320} 321 322 323static int 324ARTS_Init(SDL_AudioDriverImpl * impl) 325{ 326 if (LoadARTSLibrary() < 0) { 327 return 0; 328 } else { 329 if (SDL_NAME(arts_init) () != 0) { 330 UnloadARTSLibrary(); 331 SDL_SetError("ARTS: arts_init failed (no audio server?)"); 332 return 0; 333 } 334 335 /* Play a stream so aRts doesn't crash */ 336 if (ARTS_Suspend()) { 337 arts_stream_t stream; 338 stream = SDL_NAME(arts_play_stream) (44100, 16, 2, "SDL"); 339 SDL_NAME(arts_write) (stream, "", 0); 340 SDL_NAME(arts_close_stream) (stream); 341 } 342 343 SDL_NAME(arts_free) (); 344 } 345 346 /* Set the function pointers */ 347 impl->OpenDevice = ARTS_OpenDevice; 348 impl->PlayDevice = ARTS_PlayDevice; 349 impl->WaitDevice = ARTS_WaitDevice; 350 impl->GetDeviceBuf = ARTS_GetDeviceBuf; 351 impl->CloseDevice = ARTS_CloseDevice; 352 impl->Deinitialize = ARTS_Deinitialize; 353 impl->OnlyHasDefaultOutputDevice = 1; 354 355 return 1; /* this audio target is available. */ 356} 357 358 359AudioBootStrap ARTS_bootstrap = { 360 "arts", "Analog RealTime Synthesizer", ARTS_Init, 0 361}; 362 363#endif /* SDL_AUDIO_DRIVER_ARTS */ 364 365/* vi: set ts=4 sw=4 expandtab: */ 366[FILE END](C) 2025 0x4248 (C) 2025 4248 Media and 4248 Systems, All part of 0x4248 See LICENCE files for more information. Not all files are by 0x4248 always check Licencing.