zenilib  0.5.3.0
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Groups Pages
SDL_artsaudio.c
Go to the documentation of this file.
1 /*
2  Simple DirectMedia Layer
3  Copyright (C) 1997-2013 Sam Lantinga <slouken@libsdl.org>
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_config.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_audiomem.h"
36 #include "../SDL_audio_c.h"
37 #include "SDL_artsaudio.h"
38 
39 #ifdef SDL_AUDIO_DRIVER_ARTS_DYNAMIC
40 #include "SDL_name.h"
41 #include "SDL_loadso.h"
42 #else
43 #define SDL_NAME(X) X
44 #endif
45 
46 #ifdef SDL_AUDIO_DRIVER_ARTS_DYNAMIC
47 
48 static const char *arts_library = SDL_AUDIO_DRIVER_ARTS_DYNAMIC;
49 static void *arts_handle = NULL;
50 
51 /* !!! FIXME: I hate this SDL_NAME clutter...it makes everything so messy! */
52 static int (*SDL_NAME(arts_init)) (void);
53 static void (*SDL_NAME(arts_free)) (void);
54 static arts_stream_t(*SDL_NAME(arts_play_stream)) (int rate, int bits,
55  int channels,
56  const char *name);
57 static int (*SDL_NAME(arts_stream_set)) (arts_stream_t s,
58  arts_parameter_t param, int value);
59 static int (*SDL_NAME(arts_stream_get)) (arts_stream_t s,
60  arts_parameter_t param);
61 static int (*SDL_NAME(arts_write)) (arts_stream_t s, const void *buffer,
62  int count);
63 static void (*SDL_NAME(arts_close_stream)) (arts_stream_t s);
64 static int (*SDL_NAME(arts_suspend))(void);
65 static int (*SDL_NAME(arts_suspended)) (void);
66 static const char *(*SDL_NAME(arts_error_text)) (int errorcode);
67 
68 #define SDL_ARTS_SYM(x) { #x, (void **) (char *) &SDL_NAME(x) }
69 static struct
70 {
71  const char *name;
72  void **func;
73 } arts_functions[] = {
74 /* *INDENT-OFF* */
75  SDL_ARTS_SYM(arts_init),
76  SDL_ARTS_SYM(arts_free),
77  SDL_ARTS_SYM(arts_play_stream),
78  SDL_ARTS_SYM(arts_stream_set),
79  SDL_ARTS_SYM(arts_stream_get),
80  SDL_ARTS_SYM(arts_write),
81  SDL_ARTS_SYM(arts_close_stream),
82  SDL_ARTS_SYM(arts_suspend),
83  SDL_ARTS_SYM(arts_suspended),
84  SDL_ARTS_SYM(arts_error_text),
85 /* *INDENT-ON* */
86 };
87 
88 #undef SDL_ARTS_SYM
89 
90 static void
91 UnloadARTSLibrary()
92 {
93  if (arts_handle != NULL) {
94  SDL_UnloadObject(arts_handle);
95  arts_handle = NULL;
96  }
97 }
98 
99 static int
100 LoadARTSLibrary(void)
101 {
102  int i, retval = -1;
103 
104  if (arts_handle == NULL) {
105  arts_handle = SDL_LoadObject(arts_library);
106  if (arts_handle != NULL) {
107  retval = 0;
108  for (i = 0; i < SDL_arraysize(arts_functions); ++i) {
109  *arts_functions[i].func =
110  SDL_LoadFunction(arts_handle, arts_functions[i].name);
111  if (!*arts_functions[i].func) {
112  retval = -1;
113  UnloadARTSLibrary();
114  break;
115  }
116  }
117  }
118  }
119 
120  return retval;
121 }
122 
123 #else
124 
125 static void
126 UnloadARTSLibrary()
127 {
128  return;
129 }
130 
131 static int
132 LoadARTSLibrary(void)
133 {
134  return 0;
135 }
136 
137 #endif /* SDL_AUDIO_DRIVER_ARTS_DYNAMIC */
138 
139 /* This function waits until it is possible to write a full sound buffer */
140 static void
141 ARTS_WaitDevice(_THIS)
142 {
143  Sint32 ticks;
144 
145  /* Check to see if the thread-parent process is still alive */
146  {
147  static int cnt = 0;
148  /* Note that this only works with thread implementations
149  that use a different process id for each thread.
150  */
151  /* Check every 10 loops */
152  if (this->hidden->parent && (((++cnt) % 10) == 0)) {
153  if (kill(this->hidden->parent, 0) < 0 && errno == ESRCH) {
154  this->enabled = 0;
155  }
156  }
157  }
158 
159  /* Use timer for general audio synchronization */
160  ticks =
161  ((Sint32) (this->hidden->next_frame - SDL_GetTicks())) - FUDGE_TICKS;
162  if (ticks > 0) {
163  SDL_Delay(ticks);
164  }
165 }
166 
167 static void
168 ARTS_PlayDevice(_THIS)
169 {
170  /* Write the audio data */
171  int written = SDL_NAME(arts_write) (this->hidden->stream,
172  this->hidden->mixbuf,
173  this->hidden->mixlen);
174 
175  /* If timer synchronization is enabled, set the next write frame */
176  if (this->hidden->frame_ticks) {
177  this->hidden->next_frame += this->hidden->frame_ticks;
178  }
179 
180  /* If we couldn't write, assume fatal error for now */
181  if (written < 0) {
182  this->enabled = 0;
183  }
184 #ifdef DEBUG_AUDIO
185  fprintf(stderr, "Wrote %d bytes of audio data\n", written);
186 #endif
187 }
188 
189 static void
190 ARTS_WaitDone(_THIS)
191 {
192  /* !!! FIXME: camp here until buffer drains... SDL_Delay(???); */
193 }
194 
195 
196 static Uint8 *
197 ARTS_GetDeviceBuf(_THIS)
198 {
199  return (this->hidden->mixbuf);
200 }
201 
202 
203 static void
204 ARTS_CloseDevice(_THIS)
205 {
206  if (this->hidden != NULL) {
207  SDL_FreeAudioMem(this->hidden->mixbuf);
208  this->hidden->mixbuf = NULL;
209  if (this->hidden->stream) {
210  SDL_NAME(arts_close_stream) (this->hidden->stream);
211  this->hidden->stream = 0;
212  }
213  SDL_NAME(arts_free) ();
214  SDL_free(this->hidden);
215  this->hidden = NULL;
216  }
217 }
218 
219 static int
220 ARTS_Suspend(void)
221 {
222  const Uint32 abortms = SDL_GetTicks() + 3000; /* give up after 3 secs */
223  while ( (!SDL_NAME(arts_suspended)()) && (SDL_GetTicks() < abortms) ) {
224  if ( SDL_NAME(arts_suspend)() ) {
225  break;
226  }
227  }
228  return SDL_NAME(arts_suspended)();
229 }
230 
231 static int
232 ARTS_OpenDevice(_THIS, const char *devname, int iscapture)
233 {
234  int rc = 0;
235  int bits = 0, frag_spec = 0;
236  SDL_AudioFormat test_format = 0, format = 0;
237 
238  /* Initialize all variables that we clean on shutdown */
239  this->hidden = (struct SDL_PrivateAudioData *)
240  SDL_malloc((sizeof *this->hidden));
241  if (this->hidden == NULL) {
242  return SDL_OutOfMemory();
243  }
244  SDL_memset(this->hidden, 0, (sizeof *this->hidden));
245 
246  /* Try for a closest match on audio format */
247  for (test_format = SDL_FirstAudioFormat(this->spec.format);
248  !format && test_format;) {
249 #ifdef DEBUG_AUDIO
250  fprintf(stderr, "Trying format 0x%4.4x\n", test_format);
251 #endif
252  switch (test_format) {
253  case AUDIO_U8:
254  bits = 8;
255  format = 1;
256  break;
257  case AUDIO_S16LSB:
258  bits = 16;
259  format = 1;
260  break;
261  default:
262  format = 0;
263  break;
264  }
265  if (!format) {
266  test_format = SDL_NextAudioFormat();
267  }
268  }
269  if (format == 0) {
270  ARTS_CloseDevice(this);
271  return SDL_SetError("Couldn't find any hardware audio formats");
272  }
273  this->spec.format = test_format;
274 
275  if ((rc = SDL_NAME(arts_init) ()) != 0) {
276  ARTS_CloseDevice(this);
277  return SDL_SetError("Unable to initialize ARTS: %s",
278  SDL_NAME(arts_error_text) (rc));
279  }
280 
281  if (!ARTS_Suspend()) {
282  ARTS_CloseDevice(this);
283  return SDL_SetError("ARTS can not open audio device");
284  }
285 
286  this->hidden->stream = SDL_NAME(arts_play_stream) (this->spec.freq,
287  bits,
288  this->spec.channels,
289  "SDL");
290 
291  /* Play nothing so we have at least one write (server bug workaround). */
292  SDL_NAME(arts_write) (this->hidden->stream, "", 0);
293 
294  /* Calculate the final parameters for this audio specification */
295  SDL_CalculateAudioSpec(&this->spec);
296 
297  /* Determine the power of two of the fragment size */
298  for (frag_spec = 0; (0x01 << frag_spec) < this->spec.size; ++frag_spec);
299  if ((0x01 << frag_spec) != this->spec.size) {
300  ARTS_CloseDevice(this);
301  return SDL_SetError("Fragment size must be a power of two");
302  }
303  frag_spec |= 0x00020000; /* two fragments, for low latency */
304 
305 #ifdef ARTS_P_PACKET_SETTINGS
306  SDL_NAME(arts_stream_set) (this->hidden->stream,
307  ARTS_P_PACKET_SETTINGS, frag_spec);
308 #else
309  SDL_NAME(arts_stream_set) (this->hidden->stream, ARTS_P_PACKET_SIZE,
310  frag_spec & 0xffff);
311  SDL_NAME(arts_stream_set) (this->hidden->stream, ARTS_P_PACKET_COUNT,
312  frag_spec >> 16);
313 #endif
314  this->spec.size = SDL_NAME(arts_stream_get) (this->hidden->stream,
315  ARTS_P_PACKET_SIZE);
316 
317  /* Allocate mixing buffer */
318  this->hidden->mixlen = this->spec.size;
319  this->hidden->mixbuf = (Uint8 *) SDL_AllocAudioMem(this->hidden->mixlen);
320  if (this->hidden->mixbuf == NULL) {
321  ARTS_CloseDevice(this);
322  return SDL_OutOfMemory();
323  }
324  SDL_memset(this->hidden->mixbuf, this->spec.silence, this->spec.size);
325 
326  /* Get the parent process id (we're the parent of the audio thread) */
327  this->hidden->parent = getpid();
328 
329  /* We're ready to rock and roll. :-) */
330  return 0;
331 }
332 
333 
334 static void
335 ARTS_Deinitialize(void)
336 {
337  UnloadARTSLibrary();
338 }
339 
340 
341 static int
342 ARTS_Init(SDL_AudioDriverImpl * impl)
343 {
344  if (LoadARTSLibrary() < 0) {
345  return 0;
346  } else {
347  if (SDL_NAME(arts_init) () != 0) {
348  UnloadARTSLibrary();
349  SDL_SetError("ARTS: arts_init failed (no audio server?)");
350  return 0;
351  }
352 
353  /* Play a stream so aRts doesn't crash */
354  if (ARTS_Suspend()) {
355  arts_stream_t stream;
356  stream = SDL_NAME(arts_play_stream) (44100, 16, 2, "SDL");
357  SDL_NAME(arts_write) (stream, "", 0);
358  SDL_NAME(arts_close_stream) (stream);
359  }
360 
361  SDL_NAME(arts_free) ();
362  }
363 
364  /* Set the function pointers */
365  impl->OpenDevice = ARTS_OpenDevice;
366  impl->PlayDevice = ARTS_PlayDevice;
367  impl->WaitDevice = ARTS_WaitDevice;
368  impl->GetDeviceBuf = ARTS_GetDeviceBuf;
369  impl->CloseDevice = ARTS_CloseDevice;
370  impl->WaitDone = ARTS_WaitDone;
371  impl->Deinitialize = ARTS_Deinitialize;
372  impl->OnlyHasDefaultOutputDevice = 1;
373 
374  return 1; /* this audio target is available. */
375 }
376 
377 
379  "arts", "Analog RealTime Synthesizer", ARTS_Init, 0
380 };
381 
382 #endif /* SDL_AUDIO_DRIVER_ARTS */
383 
384 /* vi: set ts=4 sw=4 expandtab: */
void(* CloseDevice)(_THIS)
Definition: SDL_sysaudio.h:45
GLenum GLint param
Definition: gl2ext.h:1491
GLdouble s
Definition: glew.h:1376
SDL_AudioFormat SDL_FirstAudioFormat(SDL_AudioFormat format)
Definition: SDL_audio.c:1226
int32_t Sint32
A signed 32-bit integer type.
Definition: SDL_stdinc.h:141
GLvoid **typedef void(GLAPIENTRY *PFNGLGETVERTEXATTRIBDVPROC)(GLuint
Definition: glew.h:1824
void(* WaitDevice)(_THIS)
Definition: SDL_sysaudio.h:41
#define NULL
Definition: ftobjs.h:61
GLenum GLsizei const GLuint GLboolean enabled
Definition: glew.h:2538
GLuint GLuint stream
Definition: glew.h:6573
Uint8 *(* GetDeviceBuf)(_THIS)
Definition: SDL_sysaudio.h:43
#define SDL_FreeAudioMem
Definition: SDL_audiomem.h:24
DECLSPEC void SDLCALL SDL_free(void *mem)
EGLImageKHR EGLint * name
Definition: eglext.h:284
Uint16 SDL_AudioFormat
Audio format flags.
Definition: SDL_audio.h:64
#define bits
Definition: infblock.c:15
void(* WaitDone)(_THIS)
Definition: SDL_sysaudio.h:44
AudioBootStrap ARTS_bootstrap
GLenum func
Definition: SDL_opengl.h:5654
int(* OpenDevice)(_THIS, const char *devname, int iscapture)
Definition: SDL_sysaudio.h:39
SDL_AudioFormat SDL_NextAudioFormat(void)
Definition: SDL_audio.c:1238
uint32_t Uint32
An unsigned 32-bit integer type.
Definition: SDL_stdinc.h:145
void(* PlayDevice)(_THIS)
Definition: SDL_sysaudio.h:42
EGLContext EGLenum EGLClientBuffer buffer
Definition: eglext.h:87
DECLSPEC Uint32 SDLCALL SDL_GetTicks(void)
Get the number of milliseconds since the SDL library initialization.
Definition: SDL_systimer.c:44
#define AUDIO_U8
Definition: SDL_audio.h:89
int
Definition: SDL_systhread.c:37
#define _THIS
GLint GLsizei count
Definition: gl2ext.h:1011
DECLSPEC void *SDLCALL SDL_LoadObject(const char *sofile)
DECLSPEC void SDLCALL SDL_Delay(Uint32 ms)
Wait a specified number of milliseconds before returning.
Definition: SDL_systimer.c:70
DECLSPEC void *SDLCALL SDL_memset(void *dst, int c, size_t len)
Definition: SDL_string.c:261
DECLSPEC void SDLCALL SDL_UnloadObject(void *handle)
GLint GLenum GLsizei GLsizei GLsizei GLint GLenum format
Definition: gl2ext.h:845
DECLSPEC int SDLCALL SDL_SetError(const char *fmt,...)
Definition: SDL_error.c:53
DECLSPEC void *SDLCALL SDL_malloc(size_t size)
void SDL_CalculateAudioSpec(SDL_AudioSpec *spec)
Definition: SDL_audio.c:1247
void(* Deinitialize)(void)
Definition: SDL_sysaudio.h:48
#define SDL_AllocAudioMem
Definition: SDL_audiomem.h:23
#define FUDGE_TICKS
Definition: SDL_artsaudio.h:49
#define SDL_OutOfMemory()
Definition: SDL_error.h:52
#define SDL_arraysize(array)
Definition: SDL_stdinc.h:83
#define SDL_NAME(X)
Definition: SDL_name.h:9
EGLSurface EGLint void ** value
Definition: eglext.h:301
uint8_t Uint8
An unsigned 8-bit integer type.
Definition: SDL_stdinc.h:129
#define AUDIO_S16LSB
Definition: SDL_audio.h:92
int i
Definition: pngrutil.c:1377
DECLSPEC void *SDLCALL SDL_LoadFunction(void *handle, const char *name)