This repository has been archived by the owner on Feb 11, 2021. It is now read-only.
/
SDL_esdaudio.c
353 lines (299 loc) · 9.04 KB
1
2
/*
SDL - Simple DirectMedia Layer
3
Copyright (C) 1997-2006 Sam Lantinga
4
5
This library is free software; you can redistribute it and/or
6
modify it under the terms of the GNU Lesser General Public
7
License as published by the Free Software Foundation; either
8
version 2.1 of the License, or (at your option) any later version.
9
10
11
12
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13
Lesser General Public License for more details.
14
15
16
17
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
18
19
Sam Lantinga
20
slouken@libsdl.org
21
*/
22
#include "SDL_config.h"
23
24
25
/* Allow access to an ESD network stream mixing buffer */
26
27
28
#include <sys/types.h>
#include <unistd.h>
#include <signal.h>
29
30
31
#include <errno.h>
#include <esd.h>
32
#include "SDL_timer.h"
33
#include "SDL_audio.h"
34
35
#include "../SDL_audiomem.h"
#include "../SDL_audio_c.h"
36
37
#include "SDL_esdaudio.h"
38
#ifdef SDL_AUDIO_DRIVER_ESD_DYNAMIC
39
40
41
42
43
44
#include "SDL_name.h"
#include "SDL_loadso.h"
#else
#define SDL_NAME(X) X
#endif
45
46
47
/* The tag name used by ESD audio */
#define ESD_DRIVER_NAME "esd"
48
#ifdef SDL_AUDIO_DRIVER_ESD_DYNAMIC
49
50
static const char *esd_library = SDL_AUDIO_DRIVER_ESD_DYNAMIC;
51
52
static void *esd_handle = NULL;
53
54
55
56
static int (*SDL_NAME(esd_open_sound)) (const char *host);
static int (*SDL_NAME(esd_close)) (int esd);
static int (*SDL_NAME(esd_play_stream)) (esd_format_t format, int rate,
const char *host, const char *name);
57
58
#define SDL_ESD_SYM(x) { #x, (void **) (char *) &SDL_NAME(x) }
59
60
61
62
static struct
{
const char *name;
void **func;
63
} esd_functions[] = {
64
65
66
67
68
SDL_ESD_SYM(esd_open_sound),
SDL_ESD_SYM(esd_close),
SDL_ESD_SYM(esd_play_stream),
};
#undef SDL_ESD_SYM
69
70
71
static void
UnloadESDLibrary()
72
{
73
if (esd_handle != NULL) {
74
75
76
SDL_UnloadObject(esd_handle);
esd_handle = NULL;
}
77
78
}
79
80
static int
LoadESDLibrary(void)
81
{
82
83
int i, retval = -1;
84
85
86
87
88
89
90
91
92
93
94
95
if (esd_handle == NULL) {
esd_handle = SDL_LoadObject(esd_library);
if (esd_handle) {
retval = 0;
for (i = 0; i < SDL_arraysize(esd_functions); ++i) {
*esd_functions[i].func =
SDL_LoadFunction(esd_handle, esd_functions[i].name);
if (!*esd_functions[i].func) {
retval = -1;
UnloadESDLibrary();
break;
}
96
97
98
99
}
}
}
return retval;
100
101
102
103
}
#else
104
105
static void
UnloadESDLibrary()
106
{
107
return;
108
109
}
110
111
static int
LoadESDLibrary(void)
112
{
113
return 0;
114
115
}
116
#endif /* SDL_AUDIO_DRIVER_ESD_DYNAMIC */
117
118
119
/* This function waits until it is possible to write a full sound buffer */
120
static void
121
ESD_WaitDevice(_THIS)
122
{
123
124
125
126
127
128
129
130
Sint32 ticks;
/* Check to see if the thread-parent process is still alive */
{
static int cnt = 0;
/* Note that this only works with thread implementations
that use a different process id for each thread.
*/
131
132
133
/* Check every 10 loops */
if (this->hidden->parent && (((++cnt) % 10) == 0)) {
if (kill(this->hidden->parent, 0) < 0) {
134
135
136
137
138
139
this->enabled = 0;
}
}
}
/* Use timer for general audio synchronization */
140
ticks = ((Sint32) (this->hidden->next_frame-SDL_GetTicks())) - FUDGE_TICKS;
141
142
143
if (ticks > 0) {
SDL_Delay(ticks);
}
144
145
}
146
static void
147
ESD_PlayDevice(_THIS)
148
{
149
int written = 0;
150
151
152
/* Write the audio data, checking for EAGAIN on broken audio drivers */
do {
153
154
155
written = write(this->hidden->audio_fd,
this->hidden->mixbuf,
this->hidden->mixlen);
156
157
158
159
160
161
162
163
if ((written < 0) && ((errno == 0) || (errno == EAGAIN))) {
SDL_Delay(1); /* Let a little CPU time go by */
}
}
while ((written < 0) &&
((errno == 0) || (errno == EAGAIN) || (errno == EINTR)));
/* Set the next write frame */
164
this->hidden->next_frame += this->hidden->frame_ticks;
165
166
167
168
169
/* If we couldn't write, assume fatal error for now */
if (written < 0) {
this->enabled = 0;
}
170
171
}
172
static Uint8 *
173
ESD_GetDeviceBuf(_THIS)
174
{
175
return (this->hidden->mixbuf);
176
177
}
178
static void
179
ESD_CloseDevice(_THIS)
180
{
181
182
183
184
185
186
187
188
189
190
191
192
if (this->hidden != NULL) {
if (this->hidden->mixbuf != NULL) {
SDL_FreeAudioMem(this->hidden->mixbuf);
this->hidden->mixbuf = NULL;
}
if (this->hidden->audio_fd >= 0) {
SDL_NAME(esd_close) (this->hidden->audio_fd);
this->hidden->audio_fd = -1;
}
SDL_free(this->hidden);
this->hidden = NULL;
193
}
194
195
196
}
/* Try to get the name of the program */
197
198
static char *
get_progname(void)
199
{
200
char *progname = NULL;
201
#ifdef __LINUX__
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
FILE *fp;
static char temp[BUFSIZ];
SDL_snprintf(temp, SDL_arraysize(temp), "/proc/%d/cmdline", getpid());
fp = fopen(temp, "r");
if (fp != NULL) {
if (fgets(temp, sizeof(temp) - 1, fp)) {
progname = SDL_strrchr(temp, '/');
if (progname == NULL) {
progname = temp;
} else {
progname = progname + 1;
}
}
fclose(fp);
}
218
#endif
219
return (progname);
220
221
}
222
223
static int
224
ESD_OpenDevice(_THIS, const char *devname, int iscapture)
225
{
226
227
228
229
230
231
232
233
234
235
236
237
238
esd_format_t format = (ESD_STREAM | ESD_PLAY);
SDL_AudioFormat test_format = 0;
int found = 0;
/* Initialize all variables that we clean on shutdown */
this->hidden = (struct SDL_PrivateAudioData *)
SDL_malloc((sizeof *this->hidden));
if (this->hidden == NULL) {
SDL_OutOfMemory();
return 0;
}
SDL_memset(this->hidden, 0, (sizeof *this->hidden));
this->hidden->audio_fd = -1;
239
240
/* Convert audio spec to the ESD audio format */
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
/* Try for a closest match on audio format */
for (test_format = SDL_FirstAudioFormat(this->spec.format);
!found && test_format; test_format = SDL_NextAudioFormat()) {
#ifdef DEBUG_AUDIO
fprintf(stderr, "Trying format 0x%4.4x\n", test_format);
#endif
found = 1;
switch (test_format) {
case AUDIO_U8:
format |= ESD_BITS8;
break;
case AUDIO_S16SYS:
format |= ESD_BITS16;
break;
default:
found = 0;
break;
}
259
}
260
261
262
263
264
265
266
267
if (!found) {
ESD_CloseDevice(this);
SDL_SetError("Couldn't find any hardware audio formats");
return 0;
}
if (this->spec.channels == 1) {
268
269
270
271
format |= ESD_MONO;
} else {
format |= ESD_STEREO;
}
272
#if 0
273
this->spec.samples = ESD_BUF_SIZE; /* Darn, no way to change this yet */
274
275
#endif
276
/* Open a connection to the ESD audio server */
277
278
279
280
281
this->hidden->audio_fd =
SDL_NAME(esd_play_stream)(format,this->spec.freq,NULL,get_progname());
if (this->hidden->audio_fd < 0) {
ESD_CloseDevice(this);
282
SDL_SetError("Couldn't open ESD connection");
283
return 0;
284
285
286
}
/* Calculate the final parameters for this audio specification */
287
288
289
SDL_CalculateAudioSpec(&this->spec);
this->hidden->frame_ticks = (float) (this->spec.samples*1000) / this->spec.freq;
this->hidden->next_frame = SDL_GetTicks() + this->hidden->frame_ticks;
290
291
/* Allocate mixing buffer */
292
293
294
295
296
297
this->hidden->mixlen = this->spec.size;
this->hidden->mixbuf = (Uint8 *) SDL_AllocAudioMem(this->hidden->mixlen);
if (this->hidden->mixbuf == NULL) {
ESD_CloseDevice(this);
SDL_OutOfMemory();
return 0;
298
}
299
SDL_memset(this->hidden->mixbuf, this->spec.silence, this->spec.size);
300
301
/* Get the parent process id (we're the parent of the audio thread) */
302
this->hidden->parent = getpid();
303
304
/* We're ready to rock and roll. :-) */
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
return 1;
}
static void
ESD_Deinitialize(void)
{
UnloadESDLibrary();
}
static int
ESD_Init(SDL_AudioDriverImpl *impl)
{
if (LoadESDLibrary() < 0) {
return 0;
} else {
int connection = 0;
/* Don't start ESD if it's not running */
if (SDL_getenv("ESD_NO_SPAWN") == NULL) {
SDL_putenv("ESD_NO_SPAWN=1");
}
connection = SDL_NAME(esd_open_sound) (NULL);
if (connection < 0) {
UnloadESDLibrary();
SDL_SetError("ESD: esd_open_sound failed (no audio server?)");
return 0;
}
SDL_NAME(esd_close) (connection);
}
/* Set the function pointers */
impl->OpenDevice = ESD_OpenDevice;
impl->PlayDevice = ESD_PlayDevice;
impl->WaitDevice = ESD_WaitDevice;
impl->GetDeviceBuf = ESD_GetDeviceBuf;
impl->CloseDevice = ESD_CloseDevice;
impl->Deinitialize = ESD_Deinitialize;
impl->OnlyHasDefaultOutputDevice = 1;
return 1;
346
}
347
348
349
350
351
352
AudioBootStrap ESD_bootstrap = {
ESD_DRIVER_NAME, "Enlightened Sound Daemon", ESD_Init, 0
};
353
/* vi: set ts=4 sw=4 expandtab: */