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
static int ESD_OpenAudio(_THIS, SDL_AudioSpec * spec);
51
52
53
54
55
static void ESD_WaitAudio(_THIS);
static void ESD_PlayAudio(_THIS);
static Uint8 *ESD_GetAudioBuf(_THIS);
static void ESD_CloseAudio(_THIS);
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
66
67
68
69
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);
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
77
static void
UnloadESDLibrary()
78
{
79
80
81
82
83
if (esd_loaded) {
SDL_UnloadObject(esd_handle);
esd_handle = NULL;
esd_loaded = 0;
}
84
85
}
86
87
static int
LoadESDLibrary(void)
88
{
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
int i, retval = -1;
esd_handle = SDL_LoadObject(esd_library);
if (esd_handle) {
esd_loaded = 1;
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;
}
}
}
return retval;
106
107
108
109
}
#else
110
111
static void
UnloadESDLibrary()
112
{
113
return;
114
115
}
116
117
static int
LoadESDLibrary(void)
118
{
119
return 0;
120
121
}
122
#endif /* SDL_AUDIO_DRIVER_ESD_DYNAMIC */
123
124
125
/* Audio driver bootstrap functions */
126
127
static int
Audio_Available(void)
128
{
129
130
131
132
133
134
135
136
137
138
139
140
141
142
int connection;
int available;
available = 0;
if (LoadESDLibrary() < 0) {
return available;
}
connection = SDL_NAME(esd_open_sound) (NULL);
if (connection >= 0) {
available = 1;
SDL_NAME(esd_close) (connection);
}
UnloadESDLibrary();
return (available);
143
144
}
145
146
static void
Audio_DeleteDevice(SDL_AudioDevice * device)
147
{
148
149
150
SDL_free(device->hidden);
SDL_free(device);
UnloadESDLibrary();
151
152
}
153
154
static SDL_AudioDevice *
Audio_CreateDevice(int devindex)
155
{
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
SDL_AudioDevice *this;
/* Initialize all variables that we clean on shutdown */
LoadESDLibrary();
this = (SDL_AudioDevice *) SDL_malloc(sizeof(SDL_AudioDevice));
if (this) {
SDL_memset(this, 0, (sizeof *this));
this->hidden = (struct SDL_PrivateAudioData *)
SDL_malloc((sizeof *this->hidden));
}
if ((this == NULL) || (this->hidden == NULL)) {
SDL_OutOfMemory();
if (this) {
SDL_free(this);
}
return (0);
}
SDL_memset(this->hidden, 0, (sizeof *this->hidden));
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
195
static void
ESD_WaitAudio(_THIS)
196
{
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
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 */
if (kill(parent, 0) < 0) {
this->enabled = 0;
}
}
}
/* Use timer for general audio synchronization */
ticks = ((Sint32) (next_frame - SDL_GetTicks())) - FUDGE_TICKS;
if (ticks > 0) {
SDL_Delay(ticks);
}
217
218
}
219
220
static void
ESD_PlayAudio(_THIS)
221
{
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
int written;
/* Write the audio data, checking for EAGAIN on broken audio drivers */
do {
written = write(audio_fd, mixbuf, mixlen);
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 */
next_frame += frame_ticks;
/* If we couldn't write, assume fatal error for now */
if (written < 0) {
this->enabled = 0;
}
241
242
}
243
244
static Uint8 *
ESD_GetAudioBuf(_THIS)
245
{
246
return (mixbuf);
247
248
}
249
250
static void
ESD_CloseAudio(_THIS)
251
{
252
253
254
255
256
257
258
259
if (mixbuf != NULL) {
SDL_FreeAudioMem(mixbuf);
mixbuf = NULL;
}
if (audio_fd >= 0) {
SDL_NAME(esd_close) (audio_fd);
audio_fd = -1;
}
260
261
262
}
/* Try to get the name of the program */
263
264
static char *
get_progname(void)
265
{
266
char *progname = NULL;
267
#ifdef __LINUX__
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
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);
}
284
#endif
285
return (progname);
286
287
}
288
289
static int
ESD_OpenAudio(_THIS, SDL_AudioSpec * spec)
290
{
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
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:
SDL_SetError("Unsupported ESD audio format");
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
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
/* Open a connection to the ESD audio server */
audio_fd =
SDL_NAME(esd_play_stream) (format, spec->freq, NULL, get_progname());
if (audio_fd < 0) {
SDL_SetError("Couldn't open ESD connection");
return (-1);
}
/* Calculate the final parameters for this audio specification */
SDL_CalculateAudioSpec(spec);
frame_ticks = (float) (spec->samples * 1000) / spec->freq;
next_frame = SDL_GetTicks() + frame_ticks;
/* Allocate mixing buffer */
mixlen = spec->size;
mixbuf = (Uint8 *) SDL_AllocAudioMem(mixlen);
if (mixbuf == NULL) {
return (-1);
}
SDL_memset(mixbuf, spec->silence, spec->size);
/* Get the parent process id (we're the parent of the audio thread) */
parent = getpid();
/* We're ready to rock and roll. :-) */
return (0);
341
}
342
343
/* vi: set ts=4 sw=4 expandtab: */