SDL 2.0
SDL_artsaudio.c
Go to the documentation of this file.
1/*
2 Simple DirectMedia Layer
3 Copyright (C) 1997-2019 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
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{
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) {
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) {
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 */
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;
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: */
#define _THIS
#define FUDGE_TICKS
Definition: SDL_artsaudio.h:49
void SDL_CalculateAudioSpec(SDL_AudioSpec *spec)
Definition: SDL_audio.c:1668
SDL_AudioFormat SDL_FirstAudioFormat(SDL_AudioFormat format)
Definition: SDL_audio.c:1647
void SDL_OpenedAudioDeviceDisconnected(SDL_AudioDevice *device)
Definition: SDL_audio.c:486
SDL_AudioFormat SDL_NextAudioFormat(void)
Definition: SDL_audio.c:1659
#define AUDIO_S16LSB
Definition: SDL_audio.h:92
Uint16 SDL_AudioFormat
Audio format flags.
Definition: SDL_audio.h:64
#define AUDIO_U8
Definition: SDL_audio.h:89
#define SDL_SetError
#define SDL_memset
#define SDL_LoadObject
#define SDL_UnloadObject
#define SDL_malloc
#define SDL_free
#define SDL_Delay
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 SDL_OutOfMemory()
Definition: SDL_error.h:52
void * SDL_LoadFunction(void *handle, const char *name)
#define SDL_NAME(X)
Definition: SDL_name.h:29
GLuint GLuint GLsizei count
Definition: SDL_opengl.h:1571
GLdouble s
Definition: SDL_opengl.h:2063
GLint GLint GLsizei GLsizei GLsizei GLint GLenum format
Definition: SDL_opengl.h:1572
GLuint GLuint stream
GLenum func
GLfloat param
GLuint buffer
GLenum GLint GLenum GLsizei GLsizei GLsizei GLint GLsizei const void * bits
GLuint const GLchar * name
GLsizei const GLfloat * value
#define SDL_arraysize(array)
Definition: SDL_stdinc.h:115
uint32_t Uint32
Definition: SDL_stdinc.h:203
int32_t Sint32
Definition: SDL_stdinc.h:197
#define SDL_zerop(x)
Definition: SDL_stdinc.h:417
uint8_t Uint8
Definition: SDL_stdinc.h:179
AudioBootStrap ARTS_bootstrap
Uint32 SDL_GetTicks(void)
Get the number of milliseconds since the SDL library initialization.
#define SDL_TICKS_PASSED(A, B)
Compare SDL ticks values, and return true if A has passed B.
Definition: SDL_timer.h:56
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
#define NULL
Definition: begin_code.h:167
EGLImageKHR EGLint EGLint * handle
Definition: eglext.h:937
SDL_AudioSpec spec
Definition: loopwave.c:31
void(* PlayDevice)(_THIS)
Definition: SDL_sysaudio.h:73
void(* WaitDevice)(_THIS)
Definition: SDL_sysaudio.h:72
void(* CloseDevice)(_THIS)
Definition: SDL_sysaudio.h:78
void(* Deinitialize)(void)
Definition: SDL_sysaudio.h:82
int(* OpenDevice)(_THIS, void *handle, const char *devname, int iscapture)
Definition: SDL_sysaudio.h:68
Uint8 *(* GetDeviceBuf)(_THIS)
Definition: SDL_sysaudio.h:74
Uint32 size
Definition: SDL_audio.h:186
Uint8 channels
Definition: SDL_audio.h:182
SDL_AudioFormat format
Definition: SDL_audio.h:181
SDL_bool retval
static int ticks
Definition: testtimer.c:24