zenilib  0.5.3.0
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Groups Pages
SDL_esdaudio.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_ESD
24 
25 /* Allow access to an ESD network stream mixing buffer */
26 
27 #include <sys/types.h>
28 #include <unistd.h>
29 #include <signal.h>
30 #include <errno.h>
31 #include <esd.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_esdaudio.h"
38 
39 #ifdef SDL_AUDIO_DRIVER_ESD_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_ESD_DYNAMIC
47 
48 static const char *esd_library = SDL_AUDIO_DRIVER_ESD_DYNAMIC;
49 static void *esd_handle = NULL;
50 
51 static int (*SDL_NAME(esd_open_sound)) (const char *host);
52 static int (*SDL_NAME(esd_close)) (int esd);
53 static int (*SDL_NAME(esd_play_stream)) (esd_format_t format, int rate,
54  const char *host, const char *name);
55 
56 #define SDL_ESD_SYM(x) { #x, (void **) (char *) &SDL_NAME(x) }
57 static struct
58 {
59  const char *name;
60  void **func;
61 } const esd_functions[] = {
62  SDL_ESD_SYM(esd_open_sound),
63  SDL_ESD_SYM(esd_close), SDL_ESD_SYM(esd_play_stream),
64 };
65 
66 #undef SDL_ESD_SYM
67 
68 static void
69 UnloadESDLibrary()
70 {
71  if (esd_handle != NULL) {
72  SDL_UnloadObject(esd_handle);
73  esd_handle = NULL;
74  }
75 }
76 
77 static int
78 LoadESDLibrary(void)
79 {
80  int i, retval = -1;
81 
82  if (esd_handle == NULL) {
83  esd_handle = SDL_LoadObject(esd_library);
84  if (esd_handle) {
85  retval = 0;
86  for (i = 0; i < SDL_arraysize(esd_functions); ++i) {
87  *esd_functions[i].func =
88  SDL_LoadFunction(esd_handle, esd_functions[i].name);
89  if (!*esd_functions[i].func) {
90  retval = -1;
91  UnloadESDLibrary();
92  break;
93  }
94  }
95  }
96  }
97  return retval;
98 }
99 
100 #else
101 
102 static void
103 UnloadESDLibrary()
104 {
105  return;
106 }
107 
108 static int
109 LoadESDLibrary(void)
110 {
111  return 0;
112 }
113 
114 #endif /* SDL_AUDIO_DRIVER_ESD_DYNAMIC */
115 
116 
117 /* This function waits until it is possible to write a full sound buffer */
118 static void
119 ESD_WaitDevice(_THIS)
120 {
121  Sint32 ticks;
122 
123  /* Check to see if the thread-parent process is still alive */
124  {
125  static int cnt = 0;
126  /* Note that this only works with thread implementations
127  that use a different process id for each thread.
128  */
129  /* Check every 10 loops */
130  if (this->hidden->parent && (((++cnt) % 10) == 0)) {
131  if (kill(this->hidden->parent, 0) < 0 && errno == ESRCH) {
132  this->enabled = 0;
133  }
134  }
135  }
136 
137  /* Use timer for general audio synchronization */
138  ticks =
139  ((Sint32) (this->hidden->next_frame - SDL_GetTicks())) - FUDGE_TICKS;
140  if (ticks > 0) {
141  SDL_Delay(ticks);
142  }
143 }
144 
145 static void
146 ESD_PlayDevice(_THIS)
147 {
148  int written = 0;
149 
150  /* Write the audio data, checking for EAGAIN on broken audio drivers */
151  do {
152  written = write(this->hidden->audio_fd,
153  this->hidden->mixbuf, this->hidden->mixlen);
154  if ((written < 0) && ((errno == 0) || (errno == EAGAIN))) {
155  SDL_Delay(1); /* Let a little CPU time go by */
156  }
157  } while ((written < 0) &&
158  ((errno == 0) || (errno == EAGAIN) || (errno == EINTR)));
159 
160  /* Set the next write frame */
161  this->hidden->next_frame += this->hidden->frame_ticks;
162 
163  /* If we couldn't write, assume fatal error for now */
164  if (written < 0) {
165  this->enabled = 0;
166  }
167 }
168 
169 static Uint8 *
170 ESD_GetDeviceBuf(_THIS)
171 {
172  return (this->hidden->mixbuf);
173 }
174 
175 static void
176 ESD_CloseDevice(_THIS)
177 {
178  if (this->hidden != NULL) {
179  SDL_FreeAudioMem(this->hidden->mixbuf);
180  this->hidden->mixbuf = NULL;
181  if (this->hidden->audio_fd >= 0) {
182  SDL_NAME(esd_close) (this->hidden->audio_fd);
183  this->hidden->audio_fd = -1;
184  }
185 
186  SDL_free(this->hidden);
187  this->hidden = NULL;
188  }
189 }
190 
191 /* Try to get the name of the program */
192 static char *
193 get_progname(void)
194 {
195  char *progname = NULL;
196 #ifdef __LINUX__
197  FILE *fp;
198  static char temp[BUFSIZ];
199 
200  SDL_snprintf(temp, SDL_arraysize(temp), "/proc/%d/cmdline", getpid());
201  fp = fopen(temp, "r");
202  if (fp != NULL) {
203  if (fgets(temp, sizeof(temp) - 1, fp)) {
204  progname = SDL_strrchr(temp, '/');
205  if (progname == NULL) {
206  progname = temp;
207  } else {
208  progname = progname + 1;
209  }
210  }
211  fclose(fp);
212  }
213 #endif
214  return (progname);
215 }
216 
217 
218 static int
219 ESD_OpenDevice(_THIS, const char *devname, int iscapture)
220 {
221  esd_format_t format = (ESD_STREAM | ESD_PLAY);
222  SDL_AudioFormat test_format = 0;
223  int found = 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_memset(this->hidden, 0, (sizeof *this->hidden));
232  this->hidden->audio_fd = -1;
233 
234  /* Convert audio spec to the ESD audio format */
235  /* Try for a closest match on audio format */
236  for (test_format = SDL_FirstAudioFormat(this->spec.format);
237  !found && test_format; test_format = SDL_NextAudioFormat()) {
238 #ifdef DEBUG_AUDIO
239  fprintf(stderr, "Trying format 0x%4.4x\n", test_format);
240 #endif
241  found = 1;
242  switch (test_format) {
243  case AUDIO_U8:
244  format |= ESD_BITS8;
245  break;
246  case AUDIO_S16SYS:
247  format |= ESD_BITS16;
248  break;
249  default:
250  found = 0;
251  break;
252  }
253  }
254 
255  if (!found) {
256  ESD_CloseDevice(this);
257  return SDL_SetError("Couldn't find any hardware audio formats");
258  }
259 
260  if (this->spec.channels == 1) {
261  format |= ESD_MONO;
262  } else {
263  format |= ESD_STEREO;
264  }
265 #if 0
266  this->spec.samples = ESD_BUF_SIZE; /* Darn, no way to change this yet */
267 #endif
268 
269  /* Open a connection to the ESD audio server */
270  this->hidden->audio_fd =
271  SDL_NAME(esd_play_stream) (format, this->spec.freq, NULL,
272  get_progname());
273 
274  if (this->hidden->audio_fd < 0) {
275  ESD_CloseDevice(this);
276  return SDL_SetError("Couldn't open ESD connection");
277  }
278 
279  /* Calculate the final parameters for this audio specification */
280  SDL_CalculateAudioSpec(&this->spec);
281  this->hidden->frame_ticks =
282  (float) (this->spec.samples * 1000) / this->spec.freq;
283  this->hidden->next_frame = SDL_GetTicks() + this->hidden->frame_ticks;
284 
285  /* Allocate mixing buffer */
286  this->hidden->mixlen = this->spec.size;
287  this->hidden->mixbuf = (Uint8 *) SDL_AllocAudioMem(this->hidden->mixlen);
288  if (this->hidden->mixbuf == NULL) {
289  ESD_CloseDevice(this);
290  return SDL_OutOfMemory();
291  }
292  SDL_memset(this->hidden->mixbuf, this->spec.silence, this->spec.size);
293 
294  /* Get the parent process id (we're the parent of the audio thread) */
295  this->hidden->parent = getpid();
296 
297  /* We're ready to rock and roll. :-) */
298  return 0;
299 }
300 
301 static void
302 ESD_Deinitialize(void)
303 {
304  UnloadESDLibrary();
305 }
306 
307 static int
308 ESD_Init(SDL_AudioDriverImpl * impl)
309 {
310  if (LoadESDLibrary() < 0) {
311  return 0;
312  } else {
313  int connection = 0;
314 
315  /* Don't start ESD if it's not running */
316  SDL_setenv("ESD_NO_SPAWN", "1", 0);
317 
318  connection = SDL_NAME(esd_open_sound) (NULL);
319  if (connection < 0) {
320  UnloadESDLibrary();
321  SDL_SetError("ESD: esd_open_sound failed (no audio server?)");
322  return 0;
323  }
324  SDL_NAME(esd_close) (connection);
325  }
326 
327  /* Set the function pointers */
328  impl->OpenDevice = ESD_OpenDevice;
329  impl->PlayDevice = ESD_PlayDevice;
330  impl->WaitDevice = ESD_WaitDevice;
331  impl->GetDeviceBuf = ESD_GetDeviceBuf;
332  impl->CloseDevice = ESD_CloseDevice;
333  impl->Deinitialize = ESD_Deinitialize;
334  impl->OnlyHasDefaultOutputDevice = 1;
335 
336  return 1; /* this audio target is available. */
337 }
338 
339 
341  "esd", "Enlightened Sound Daemon", ESD_Init, 0
342 };
343 
344 #endif /* SDL_AUDIO_DRIVER_ESD */
345 
346 /* vi: set ts=4 sw=4 expandtab: */
void(* CloseDevice)(_THIS)
Definition: SDL_sysaudio.h:45
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
void(* WaitDevice)(_THIS)
Definition: SDL_sysaudio.h:41
#define NULL
Definition: ftobjs.h:61
DECLSPEC int SDLCALL SDL_snprintf(char *text, size_t maxlen, const char *fmt,...)
Definition: SDL_string.c:1277
GLenum GLsizei const GLuint GLboolean enabled
Definition: glew.h:2538
Uint8 *(* GetDeviceBuf)(_THIS)
Definition: SDL_sysaudio.h:43
#define SDL_FreeAudioMem
Definition: SDL_audiomem.h:24
DECLSPEC char *SDLCALL SDL_strrchr(const char *str, int c)
Definition: SDL_string.c:593
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 AUDIO_S16SYS
Definition: SDL_audio.h:123
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
void(* PlayDevice)(_THIS)
Definition: SDL_sysaudio.h:42
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
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
uint8_t Uint8
An unsigned 8-bit integer type.
Definition: SDL_stdinc.h:129
AudioBootStrap ESD_bootstrap
int i
Definition: pngrutil.c:1377
DECLSPEC int SDLCALL SDL_setenv(const char *name, const char *value, int overwrite)
Definition: SDL_getenv.c:85
DECLSPEC void *SDLCALL SDL_LoadFunction(void *handle, const char *name)