comparison src/audio/esd/SDL_esdaudio.c @ 0:74212992fb08

Initial revision
author Sam Lantinga <slouken@lokigames.com>
date Thu, 26 Apr 2001 16:45:43 +0000
parents
children e8157fcb3114
comparison
equal deleted inserted replaced
-1:000000000000 0:74212992fb08
1 /*
2 SDL - Simple DirectMedia Layer
3 Copyright (C) 1997, 1998, 1999, 2000, 2001 Sam Lantinga
4
5 This library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Library General Public
7 License as published by the Free Software Foundation; either
8 version 2 of the License, or (at your option) any later version.
9
10 This library is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Library General Public License for more details.
14
15 You should have received a copy of the GNU Library General Public
16 License along with this library; if not, write to the Free
17 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18
19 Sam Lantinga
20 slouken@devolution.com
21 */
22
23 #ifdef SAVE_RCSID
24 static char rcsid =
25 "@(#) $Id$";
26 #endif
27
28 /* Allow access to an ESD network stream mixing buffer */
29
30 #ifdef ESD_SUPPORT
31
32 #include <stdlib.h>
33 #include <stdio.h>
34 #include <string.h>
35 #include <errno.h>
36 #include <signal.h>
37 #include <unistd.h>
38
39 #include <esd.h>
40
41 #include "SDL_audio.h"
42 #include "SDL_error.h"
43 #include "SDL_audiomem.h"
44 #include "SDL_audio_c.h"
45 #include "SDL_timer.h"
46 #include "SDL_audiodev_c.h"
47 #include "SDL_esdaudio.h"
48
49 /* The tag name used by ESD audio */
50 #define ESD_DRIVER_NAME "esd"
51
52 /* Audio driver functions */
53 static int ESD_OpenAudio(_THIS, SDL_AudioSpec *spec);
54 static void ESD_WaitAudio(_THIS);
55 static void ESD_PlayAudio(_THIS);
56 static Uint8 *ESD_GetAudioBuf(_THIS);
57 static void ESD_CloseAudio(_THIS);
58
59 /* Audio driver bootstrap functions */
60
61 static int Audio_Available(void)
62 {
63 int connection;
64 int available;
65
66 available = 0;
67 connection = esd_open_sound(NULL);
68 if ( connection >= 0 ) {
69 available = 1;
70 esd_close(connection);
71 }
72 return(available);
73 }
74
75 static void Audio_DeleteDevice(SDL_AudioDevice *device)
76 {
77 free(device->hidden);
78 free(device);
79 }
80
81 static SDL_AudioDevice *Audio_CreateDevice(int devindex)
82 {
83 SDL_AudioDevice *this;
84
85 /* Initialize all variables that we clean on shutdown */
86 this = (SDL_AudioDevice *)malloc(sizeof(SDL_AudioDevice));
87 if ( this ) {
88 memset(this, 0, (sizeof *this));
89 this->hidden = (struct SDL_PrivateAudioData *)
90 malloc((sizeof *this->hidden));
91 }
92 if ( (this == NULL) || (this->hidden == NULL) ) {
93 SDL_OutOfMemory();
94 if ( this ) {
95 free(this);
96 }
97 return(0);
98 }
99 memset(this->hidden, 0, (sizeof *this->hidden));
100 audio_fd = -1;
101
102 /* Set the function pointers */
103 this->OpenAudio = ESD_OpenAudio;
104 this->WaitAudio = ESD_WaitAudio;
105 this->PlayAudio = ESD_PlayAudio;
106 this->GetAudioBuf = ESD_GetAudioBuf;
107 this->CloseAudio = ESD_CloseAudio;
108
109 this->free = Audio_DeleteDevice;
110
111 return this;
112 }
113
114 AudioBootStrap ESD_bootstrap = {
115 ESD_DRIVER_NAME, "Enlightened Sound Daemon",
116 Audio_Available, Audio_CreateDevice
117 };
118
119 /* This function waits until it is possible to write a full sound buffer */
120 static void ESD_WaitAudio(_THIS)
121 {
122 Sint32 ticks;
123
124 /* Check to see if the thread-parent process is still alive */
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 if (parent && (((++cnt)%10) == 0)) { /* Check every 10 loops */
130 if ( kill(parent, 0) < 0 ) {
131 this->enabled = 0;
132 }
133 }
134 }
135
136 /* Use timer for general audio synchronization */
137 ticks = ((Sint32)(next_frame - SDL_GetTicks()))-FUDGE_TICKS;
138 if ( ticks > 0 ) {
139 SDL_Delay(ticks);
140 }
141 }
142
143 static void ESD_PlayAudio(_THIS)
144 {
145 int written;
146
147 /* Write the audio data, checking for EAGAIN on broken audio drivers */
148 do {
149 written = write(audio_fd, mixbuf, mixlen);
150 if ( (written < 0) && ((errno == 0) || (errno == EAGAIN)) ) {
151 SDL_Delay(1); /* Let a little CPU time go by */
152 }
153 } while ( (written < 0) &&
154 ((errno == 0) || (errno == EAGAIN) || (errno == EINTR)) );
155
156 /* Set the next write frame */
157 next_frame += frame_ticks;
158
159 /* If we couldn't write, assume fatal error for now */
160 if ( written < 0 ) {
161 this->enabled = 0;
162 }
163 }
164
165 static Uint8 *ESD_GetAudioBuf(_THIS)
166 {
167 return(mixbuf);
168 }
169
170 static void ESD_CloseAudio(_THIS)
171 {
172 if ( mixbuf != NULL ) {
173 SDL_FreeAudioMem(mixbuf);
174 mixbuf = NULL;
175 }
176 if ( audio_fd >= 0 ) {
177 close(audio_fd);
178 audio_fd = -1;
179 }
180 }
181
182 /* Try to get the name of the program */
183 static char *get_progname(void)
184 {
185 char *progname = NULL;
186 #ifdef linux
187 FILE *fp;
188 static char temp[BUFSIZ];
189
190 sprintf(temp, "/proc/%d/cmdline", getpid());
191 fp = fopen(temp, "r");
192 if ( fp != NULL ) {
193 if ( fgets(temp, sizeof(temp)-1, fp) ) {
194 progname = strrchr(temp, '/');
195 if ( progname == NULL ) {
196 progname = temp;
197 } else {
198 progname = progname+1;
199 }
200 }
201 fclose(fp);
202 }
203 #endif
204 return(progname);
205 }
206
207 static int ESD_OpenAudio(_THIS, SDL_AudioSpec *spec)
208 {
209 esd_format_t format;
210
211 /* Convert audio spec to the ESD audio format */
212 format = (ESD_STREAM | ESD_PLAY);
213 switch ( spec->format & 0xFF ) {
214 case 8:
215 format |= ESD_BITS8;
216 break;
217 case 16:
218 format |= ESD_BITS16;
219 break;
220 default:
221 SDL_SetError("Unsupported ESD audio format");
222 return(-1);
223 }
224 if ( spec->channels == 1 ) {
225 format |= ESD_MONO;
226 } else {
227 format |= ESD_STEREO;
228 }
229 #if 0
230 spec->samples = ESD_BUF_SIZE; /* Darn, no way to change this yet */
231 #endif
232
233 /* Open a connection to the ESD audio server */
234 audio_fd = esd_play_stream(format, spec->freq, NULL, get_progname());
235 if ( audio_fd < 0 ) {
236 SDL_SetError("Couldn't open ESD connection");
237 return(-1);
238 }
239
240 /* Calculate the final parameters for this audio specification */
241 SDL_CalculateAudioSpec(spec);
242 frame_ticks = (float)(spec->samples*1000)/spec->freq;
243 next_frame = SDL_GetTicks()+frame_ticks;
244
245 /* Allocate mixing buffer */
246 mixlen = spec->size;
247 mixbuf = (Uint8 *)SDL_AllocAudioMem(mixlen);
248 if ( mixbuf == NULL ) {
249 return(-1);
250 }
251 memset(mixbuf, spec->silence, spec->size);
252
253 /* Get the parent process id (we're the parent of the audio thread) */
254 parent = getpid();
255
256 /* We're ready to rock and roll. :-) */
257 return(0);
258 }
259
260 #endif /* ESD_SUPPORT */