This repository has been archived by the owner on Feb 11, 2021. It is now read-only.
/
SDL_esdaudio.c
343 lines (294 loc) · 8.25 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
36
#include "../SDL_audiomem.h"
#include "../SDL_audio_c.h"
#include "../SDL_audiodev_c.h"
37
38
#include "SDL_esdaudio.h"
39
#ifdef SDL_AUDIO_DRIVER_ESD_DYNAMIC
40
41
42
43
44
45
#include "SDL_name.h"
#include "SDL_loadso.h"
#else
#define SDL_NAME(X) X
#endif
46
47
48
49
/* The tag name used by ESD audio */
#define ESD_DRIVER_NAME "esd"
/* Audio driver functions */
50
51
52
53
54
static int ESD_OpenAudio(_THIS, SDL_AudioSpec * spec);
static void ESD_WaitAudio(_THIS);
static void ESD_PlayAudio(_THIS);
static Uint8 *ESD_GetAudioBuf(_THIS);
static void ESD_CloseAudio(_THIS);
55
56
#ifdef SDL_AUDIO_DRIVER_ESD_DYNAMIC
57
58
static const char *esd_library = SDL_AUDIO_DRIVER_ESD_DYNAMIC;
59
60
61
static void *esd_handle = NULL;
static int esd_loaded = 0;
62
63
64
65
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);
66
67
68
69
static struct
{
const char *name;
void **func;
70
} esd_functions[] = {
71
{
72
73
74
"esd_open_sound", (void **) &SDL_NAME(esd_open_sound)}, {
"esd_close", (void **) &SDL_NAME(esd_close)}, {
"esd_play_stream", (void **) &SDL_NAME(esd_play_stream)},};
75
76
static void
77
UnloadESDLibrary()
78
{
79
if (esd_loaded) {
80
SDL_UnloadObject(esd_handle);
81
82
83
esd_handle = NULL;
esd_loaded = 0;
}
84
85
}
86
static int
87
LoadESDLibrary(void)
88
{
89
90
int i, retval = -1;
91
esd_handle = SDL_LoadObject(esd_library);
92
93
94
if (esd_handle) {
esd_loaded = 1;
retval = 0;
95
for (i = 0; i < SDL_arraysize(esd_functions); ++i) {
96
*esd_functions[i].func =
97
SDL_LoadFunction(esd_handle, esd_functions[i].name);
98
99
if (!*esd_functions[i].func) {
retval = -1;
100
UnloadESDLibrary();
101
102
103
104
105
break;
}
}
}
return retval;
106
107
108
109
}
#else
110
static void
111
UnloadESDLibrary()
112
{
113
return;
114
115
}
116
static int
117
LoadESDLibrary(void)
118
{
119
return 0;
120
121
}
122
#endif /* SDL_AUDIO_DRIVER_ESD_DYNAMIC */
123
124
125
/* Audio driver bootstrap functions */
126
static int
127
Audio_Available(void)
128
{
129
130
131
132
int connection;
int available;
available = 0;
133
if (LoadESDLibrary() < 0) {
134
135
return available;
}
136
connection = SDL_NAME(esd_open_sound) (NULL);
137
138
if (connection >= 0) {
available = 1;
139
SDL_NAME(esd_close) (connection);
140
}
141
UnloadESDLibrary();
142
return (available);
143
144
}
145
static void
146
Audio_DeleteDevice(SDL_AudioDevice * device)
147
{
148
149
150
SDL_free(device->hidden);
SDL_free(device);
UnloadESDLibrary();
151
152
}
153
static SDL_AudioDevice *
154
Audio_CreateDevice(int devindex)
155
{
156
157
158
SDL_AudioDevice *this;
/* Initialize all variables that we clean on shutdown */
159
160
LoadESDLibrary();
this = (SDL_AudioDevice *) SDL_malloc(sizeof(SDL_AudioDevice));
161
if (this) {
162
SDL_memset(this, 0, (sizeof *this));
163
this->hidden = (struct SDL_PrivateAudioData *)
164
SDL_malloc((sizeof *this->hidden));
165
166
}
if ((this == NULL) || (this->hidden == NULL)) {
167
SDL_OutOfMemory();
168
if (this) {
169
SDL_free(this);
170
171
172
}
return (0);
}
173
SDL_memset(this->hidden, 0, (sizeof *this->hidden));
174
175
176
177
178
179
180
181
182
183
184
185
audio_fd = -1;
/* Set the function pointers */
this->OpenAudio = ESD_OpenAudio;
this->WaitAudio = ESD_WaitAudio;
this->PlayAudio = ESD_PlayAudio;
this->GetAudioBuf = ESD_GetAudioBuf;
this->CloseAudio = ESD_CloseAudio;
this->free = Audio_DeleteDevice;
return this;
186
187
188
}
AudioBootStrap ESD_bootstrap = {
189
190
ESD_DRIVER_NAME, "Enlightened Sound Daemon",
Audio_Available, Audio_CreateDevice
191
192
193
};
/* This function waits until it is possible to write a full sound buffer */
194
static void
195
ESD_WaitAudio(_THIS)
196
{
197
198
199
200
201
202
203
204
205
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.
*/
if (parent && (((++cnt) % 10) == 0)) { /* Check every 10 loops */
206
if (kill(parent, 0) < 0) {
207
208
209
210
211
212
this->enabled = 0;
}
}
}
/* Use timer for general audio synchronization */
213
ticks = ((Sint32) (next_frame - SDL_GetTicks())) - FUDGE_TICKS;
214
if (ticks > 0) {
215
SDL_Delay(ticks);
216
}
217
218
}
219
static void
220
ESD_PlayAudio(_THIS)
221
{
222
223
224
225
int written;
/* Write the audio data, checking for EAGAIN on broken audio drivers */
do {
226
written = write(audio_fd, mixbuf, mixlen);
227
if ((written < 0) && ((errno == 0) || (errno == EAGAIN))) {
228
SDL_Delay(1); /* Let a little CPU time go by */
229
230
231
232
233
234
235
236
237
238
239
240
}
}
while ((written < 0) &&
((errno == 0) || (errno == EAGAIN) || (errno == EINTR)));
/* Set the next write frame */
next_frame += frame_ticks;
/* If we couldn't write, assume fatal error for now */
if (written < 0) {
this->enabled = 0;
}
241
242
}
243
static Uint8 *
244
ESD_GetAudioBuf(_THIS)
245
{
246
return (mixbuf);
247
248
}
249
static void
250
ESD_CloseAudio(_THIS)
251
{
252
if (mixbuf != NULL) {
253
SDL_FreeAudioMem(mixbuf);
254
255
256
mixbuf = NULL;
}
if (audio_fd >= 0) {
257
SDL_NAME(esd_close) (audio_fd);
258
259
audio_fd = -1;
}
260
261
262
}
/* Try to get the name of the program */
263
static char *
264
get_progname(void)
265
{
266
char *progname = NULL;
267
#ifdef __LINUX__
268
269
270
FILE *fp;
static char temp[BUFSIZ];
271
272
SDL_snprintf(temp, SDL_arraysize(temp), "/proc/%d/cmdline", getpid());
fp = fopen(temp, "r");
273
if (fp != NULL) {
274
275
if (fgets(temp, sizeof(temp) - 1, fp)) {
progname = SDL_strrchr(temp, '/');
276
277
278
279
280
281
if (progname == NULL) {
progname = temp;
} else {
progname = progname + 1;
}
}
282
fclose(fp);
283
}
284
#endif
285
return (progname);
286
287
}
288
static int
289
ESD_OpenAudio(_THIS, SDL_AudioSpec * spec)
290
{
291
292
293
294
295
296
297
298
299
300
301
302
esd_format_t format;
/* Convert audio spec to the ESD audio format */
format = (ESD_STREAM | ESD_PLAY);
switch (spec->format & 0xFF) {
case 8:
format |= ESD_BITS8;
break;
case 16:
format |= ESD_BITS16;
break;
default:
303
SDL_SetError("Unsupported ESD audio format");
304
305
306
307
308
309
310
return (-1);
}
if (spec->channels == 1) {
format |= ESD_MONO;
} else {
format |= ESD_STEREO;
}
311
#if 0
312
spec->samples = ESD_BUF_SIZE; /* Darn, no way to change this yet */
313
314
#endif
315
316
/* Open a connection to the ESD audio server */
audio_fd =
317
SDL_NAME(esd_play_stream) (format, spec->freq, NULL, get_progname());
318
if (audio_fd < 0) {
319
SDL_SetError("Couldn't open ESD connection");
320
321
322
323
return (-1);
}
/* Calculate the final parameters for this audio specification */
324
SDL_CalculateAudioSpec(spec);
325
frame_ticks = (float) (spec->samples * 1000) / spec->freq;
326
next_frame = SDL_GetTicks() + frame_ticks;
327
328
329
/* Allocate mixing buffer */
mixlen = spec->size;
330
mixbuf = (Uint8 *) SDL_AllocAudioMem(mixlen);
331
332
333
if (mixbuf == NULL) {
return (-1);
}
334
SDL_memset(mixbuf, spec->silence, spec->size);
335
336
/* Get the parent process id (we're the parent of the audio thread) */
337
parent = getpid();
338
339
340
/* We're ready to rock and roll. :-) */
return (0);
341
}
342
343
/* vi: set ts=4 sw=4 expandtab: */