SDL  2.0
SDL_artsaudio.c
Go to the documentation of this file.
1 /*
2  Simple DirectMedia Layer
3  Copyright (C) 1997-2018 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_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 
47 static const char *arts_library = SDL_AUDIO_DRIVER_ARTS_DYNAMIC;
48 static void *arts_handle = NULL;
49 
50 /* !!! FIXME: I hate this SDL_NAME clutter...it makes everything so messy! */
51 static int (*SDL_NAME(arts_init)) (void);
52 static void (*SDL_NAME(arts_free)) (void);
53 static arts_stream_t(*SDL_NAME(arts_play_stream)) (int rate, int bits,
54  int channels,
55  const char *name);
56 static int (*SDL_NAME(arts_stream_set)) (arts_stream_t s,
57  arts_parameter_t param, int value);
58 static int (*SDL_NAME(arts_stream_get)) (arts_stream_t s,
59  arts_parameter_t param);
60 static int (*SDL_NAME(arts_write)) (arts_stream_t s, const void *buffer,
61  int count);
62 static void (*SDL_NAME(arts_close_stream)) (arts_stream_t s);
63 static int (*SDL_NAME(arts_suspend))(void);
64 static int (*SDL_NAME(arts_suspended)) (void);
65 static const char *(*SDL_NAME(arts_error_text)) (int errorcode);
66 
67 #define SDL_ARTS_SYM(x) { #x, (void **) (char *) &SDL_NAME(x) }
68 static 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 
89 static void
90 UnloadARTSLibrary()
91 {
92  if (arts_handle != NULL) {
93  SDL_UnloadObject(arts_handle);
94  arts_handle = NULL;
95  }
96 }
97 
98 static int
99 LoadARTSLibrary(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 
124 static void
125 UnloadARTSLibrary()
126 {
127  return;
128 }
129 
130 static int
131 LoadARTSLibrary(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 */
139 static void
140 ARTS_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) {
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 
166 static void
167 ARTS_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) {
182  }
183 #ifdef DEBUG_AUDIO
184  fprintf(stderr, "Wrote %d bytes of audio data\n", written);
185 #endif
186 }
187 
188 static Uint8 *
189 ARTS_GetDeviceBuf(_THIS)
190 {
191  return (this->hidden->mixbuf);
192 }
193 
194 
195 static void
196 ARTS_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 
206 static int
207 ARTS_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 
218 static int
219 ARTS_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 */
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 
316 static void
317 ARTS_Deinitialize(void)
318 {
319  UnloadARTSLibrary();
320 }
321 
322 
323 static int
324 ARTS_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 
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: */
SDL_AudioFormat SDL_FirstAudioFormat(SDL_AudioFormat format)
Definition: SDL_audio.c:1584
GLdouble s
Definition: SDL_opengl.h:2063
static int ticks
Definition: testtimer.c:24
GLuint GLuint GLsizei count
Definition: SDL_opengl.h:1571
void(* PlayDevice)(_THIS)
Definition: SDL_sysaudio.h:73
void(* WaitDevice)(_THIS)
Definition: SDL_sysaudio.h:72
void SDL_OpenedAudioDeviceDisconnected(SDL_AudioDevice *device)
Definition: SDL_audio.c:449
Uint16 SDL_AudioFormat
Audio format flags.
Definition: SDL_audio.h:64
GLenum GLint GLenum GLsizei GLsizei GLsizei GLint GLsizei const void * bits
uint32_t Uint32
Definition: SDL_stdinc.h:181
#define SDL_LoadObject
#define SDL_UnloadObject
#define SDL_zerop(x)
Definition: SDL_stdinc.h:417
SDL_AudioFormat SDL_NextAudioFormat(void)
Definition: SDL_audio.c:1596
GLuint const GLchar * name
GLint GLint GLsizei GLsizei GLsizei GLint GLenum format
Definition: SDL_opengl.h:1572
SDL_AudioSpec spec
Definition: loopwave.c:31
SDL_bool retval
#define AUDIO_U8
Definition: SDL_audio.h:89
EGLImageKHR EGLint EGLint * handle
Definition: eglext.h:937
GLuint GLuint stream
Uint32 SDL_GetTicks(void)
Get the number of milliseconds since the SDL library initialization.
Uint8 channels
Definition: SDL_audio.h:181
#define _THIS
uint8_t Uint8
Definition: SDL_stdinc.h:157
#define SDL_free
void(* Deinitialize)(void)
Definition: SDL_sysaudio.h:83
GLsizei const GLfloat * value
void SDL_CalculateAudioSpec(SDL_AudioSpec *spec)
Definition: SDL_audio.c:1605
int32_t Sint32
Definition: SDL_stdinc.h:175
#define FUDGE_TICKS
Definition: SDL_artsaudio.h:49
#define SDL_Delay
return Display return Display Bool Bool int int int return Display XEvent Bool(*) XPointer return Display return Display Drawable _Xconst char unsigned int unsigned int return Display Pixmap Pixmap XColor XColor unsigned int unsigned int return Display _Xconst char char int char return Display Visual unsigned int int int char unsigned int unsigned int in i)
Definition: SDL_x11sym.h:50
Uint32 size
Definition: SDL_audio.h:185
int(* OpenDevice)(_THIS, void *handle, const char *devname, int iscapture)
Definition: SDL_sysaudio.h:68
#define NULL
Definition: begin_code.h:164
#define SDL_OutOfMemory()
Definition: SDL_error.h:52
GLuint buffer
#define SDL_NAME(X)
Definition: SDL_name.h:29
#define SDL_SetError
void(* CloseDevice)(_THIS)
Definition: SDL_sysaudio.h:79
GLenum func
SDL_AudioFormat format
Definition: SDL_audio.h:180
SDL_PRINTF_FORMAT_STRING const char int SDL_PRINTF_FORMAT_STRING const char int SDL_PRINTF_FORMAT_STRING const char int SDL_PRINTF_FORMAT_STRING const char const char SDL_SCANF_FORMAT_STRING const char return SDL_ThreadFunction const char void return Uint32 return Uint32 void
#define AUDIO_S16LSB
Definition: SDL_audio.h:92
Uint8 *(* GetDeviceBuf)(_THIS)
Definition: SDL_sysaudio.h:75
AudioBootStrap ARTS_bootstrap
#define SDL_arraysize(array)
Definition: SDL_stdinc.h:93
#define SDL_malloc
void * SDL_LoadFunction(void *handle, const char *name)
GLfloat param
#define SDL_TICKS_PASSED(A, B)
Compare SDL ticks values, and return true if A has passed B.
Definition: SDL_timer.h:56
#define SDL_memset