Mercurial > sdl-ios-xcode
comparison src/audio/fusionsound/SDL_fsaudio.c @ 2947:fec0db6c44b7
Date: Thu, 01 Jan 2009 21:32:12 +0100
From: Couriersud
Subject: Fusionsound audio driver
attached is a diff containing a audio driver for the FusionSound
library. This sound library is closely related to DirectFB and uses the
same transport (fusion) as DirectFB when running applications "remote",
i.e. over the network. As such, it natively redirects sound where
DirectFB redirects video. This may be handy for everyone using SDL over
DirectFB.
author | Sam Lantinga <slouken@libsdl.org> |
---|---|
date | Thu, 01 Jan 2009 21:34:22 +0000 |
parents | |
children | 816a7a65a59a |
comparison
equal
deleted
inserted
replaced
2946:29e1f863a844 | 2947:fec0db6c44b7 |
---|---|
1 /* | |
2 SDL - Simple DirectMedia Layer | |
3 Copyright (C) 1997-2009 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 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 Lesser General Public License for more details. | |
14 | |
15 You should have received a copy of the GNU Lesser General Public | |
16 License along with this library; if not, write to the Free Software | |
17 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 /* Allow access to a raw mixing buffer */ | |
25 | |
26 #ifdef HAVE_SIGNAL_H | |
27 #include <signal.h> | |
28 #endif | |
29 #include <unistd.h> | |
30 | |
31 #include "SDL_timer.h" | |
32 #include "SDL_audio.h" | |
33 #include "../SDL_audiomem.h" | |
34 #include "../SDL_audio_c.h" | |
35 #include "SDL_fsaudio.h" | |
36 | |
37 //#define SDL_AUDIO_DRIVER_FUSIONSOUND_DYNAMIC "libfusionsound.so" | |
38 | |
39 #ifdef SDL_AUDIO_DRIVER_FUSIONSOUND_DYNAMIC | |
40 #include "SDL_name.h" | |
41 #include "SDL_loadso.h" | |
42 #else | |
43 #define SDL_NAME(X) X | |
44 #endif | |
45 | |
46 /* The tag name used by fusionsoundc audio */ | |
47 #define SDL_FS_DRIVER_NAME "fusionsound" | |
48 /* Buffers to use - more than 2 gives a lot of latency */ | |
49 #define FUSION_BUFFERS (2) | |
50 | |
51 #ifdef SDL_AUDIO_DRIVER_FUSIONSOUND_DYNAMIC | |
52 | |
53 static const char *fs_library = SDL_AUDIO_DRIVER_FUSIONSOUND_DYNAMIC; | |
54 static void *fs_handle = NULL; | |
55 | |
56 static DirectResult(*SDL_NAME(FusionSoundInit)) (int *argc, char *(*argv[])); | |
57 static DirectResult(*SDL_NAME(FusionSoundCreate)) (IFusionSound ** | |
58 ret_interface); | |
59 | |
60 #define SDL_FS_SYM(x) { #x, (void **) (char *) &SDL_NAME(x) } | |
61 static struct | |
62 { | |
63 const char *name; | |
64 void **func; | |
65 } fs_functions[] = { | |
66 /* *INDENT-OFF* */ | |
67 SDL_FS_SYM(FusionSoundInit), | |
68 SDL_FS_SYM(FusionSoundCreate), | |
69 /* *INDENT-ON* */ | |
70 }; | |
71 | |
72 #undef SDL_FS_SYM | |
73 | |
74 static void | |
75 UnloadFusionSoundLibrary() | |
76 { | |
77 if (fs_handle != NULL) { | |
78 SDL_UnloadObject(fs_handle); | |
79 fs_handle = NULL; | |
80 } | |
81 } | |
82 | |
83 static int | |
84 LoadFusionSoundLibrary(void) | |
85 { | |
86 int i, retval = -1; | |
87 | |
88 if (fs_handle == NULL) { | |
89 fs_handle = SDL_LoadObject(fs_library); | |
90 if (fs_handle != NULL) { | |
91 retval = 0; | |
92 for (i = 0; i < SDL_arraysize(fs_functions); ++i) { | |
93 *fs_functions[i].func = | |
94 SDL_LoadFunction(fs_handle, fs_functions[i].name); | |
95 if (!*fs_functions[i].func) { | |
96 retval = -1; | |
97 UnloadFusionSoundLibrary(); | |
98 break; | |
99 } | |
100 } | |
101 } | |
102 } | |
103 | |
104 return retval; | |
105 } | |
106 | |
107 #else | |
108 | |
109 static void | |
110 UnloadFusionSoundLibrary() | |
111 { | |
112 return; | |
113 } | |
114 | |
115 static int | |
116 LoadFusionSoundLibrary(void) | |
117 { | |
118 return 0; | |
119 } | |
120 | |
121 #endif /* SDL_AUDIO_DRIVER_FUSIONSOUND_DYNAMIC */ | |
122 | |
123 /* This function waits until it is possible to write a full sound buffer */ | |
124 static void | |
125 SDL_FS_WaitDevice(_THIS) | |
126 { | |
127 this->hidden->stream->Wait(this->hidden->stream, | |
128 this->hidden->mixsamples); | |
129 } | |
130 | |
131 static void | |
132 SDL_FS_PlayDevice(_THIS) | |
133 { | |
134 DirectResult ret; | |
135 | |
136 ret = this->hidden->stream->Write(this->hidden->stream, | |
137 this->hidden->mixbuf, | |
138 this->hidden->mixsamples); | |
139 /* If we couldn't write, assume fatal error for now */ | |
140 if (ret) { | |
141 this->enabled = 0; | |
142 } | |
143 #ifdef DEBUG_AUDIO | |
144 fprintf(stderr, "Wrote %d bytes of audio data\n", this->hidden->mixlen); | |
145 #endif | |
146 } | |
147 | |
148 static void | |
149 SDL_FS_WaitDone(_THIS) | |
150 { | |
151 this->hidden->stream->Wait(this->hidden->stream, | |
152 this->hidden->mixsamples * FUSION_BUFFERS); | |
153 } | |
154 | |
155 | |
156 static Uint8 * | |
157 SDL_FS_GetDeviceBuf(_THIS) | |
158 { | |
159 return (this->hidden->mixbuf); | |
160 } | |
161 | |
162 | |
163 static void | |
164 SDL_FS_CloseDevice(_THIS) | |
165 { | |
166 if (this->hidden != NULL) { | |
167 if (this->hidden->mixbuf != NULL) { | |
168 SDL_FreeAudioMem(this->hidden->mixbuf); | |
169 this->hidden->mixbuf = NULL; | |
170 } | |
171 if (this->hidden->stream) { | |
172 this->hidden->stream->Release(this->hidden->stream); | |
173 this->hidden->stream = NULL; | |
174 } | |
175 if (this->hidden->fs) { | |
176 this->hidden->fs->Release(this->hidden->fs); | |
177 this->hidden->fs = NULL; | |
178 } | |
179 SDL_free(this->hidden); | |
180 this->hidden = NULL; | |
181 } | |
182 } | |
183 | |
184 | |
185 static int | |
186 SDL_FS_OpenDevice(_THIS, const char *devname, int iscapture) | |
187 { | |
188 int bytes; | |
189 SDL_AudioFormat test_format = 0, format = 0; | |
190 FSSampleFormat fs_format; | |
191 FSStreamDescription desc; | |
192 DirectResult ret; | |
193 | |
194 /* Initialize all variables that we clean on shutdown */ | |
195 this->hidden = (struct SDL_PrivateAudioData *) | |
196 SDL_malloc((sizeof *this->hidden)); | |
197 if (this->hidden == NULL) { | |
198 SDL_OutOfMemory(); | |
199 return 0; | |
200 } | |
201 SDL_memset(this->hidden, 0, (sizeof *this->hidden)); | |
202 | |
203 /* Try for a closest match on audio format */ | |
204 for (test_format = SDL_FirstAudioFormat(this->spec.format); | |
205 !format && test_format;) { | |
206 #ifdef DEBUG_AUDIO | |
207 fprintf(stderr, "Trying format 0x%4.4x\n", test_format); | |
208 #endif | |
209 switch (test_format) { | |
210 case AUDIO_U8: | |
211 fs_format = FSSF_U8; | |
212 bytes = 1; | |
213 format = 1; | |
214 break; | |
215 case AUDIO_S16SYS: | |
216 fs_format = FSSF_S16; | |
217 bytes = 2; | |
218 format = 1; | |
219 break; | |
220 case AUDIO_S32SYS: | |
221 fs_format = FSSF_S32; | |
222 bytes = 4; | |
223 format = 1; | |
224 break; | |
225 case AUDIO_F32SYS: | |
226 fs_format = FSSF_FLOAT; | |
227 bytes = 4; | |
228 format = 1; | |
229 break; | |
230 default: | |
231 format = 0; | |
232 break; | |
233 } | |
234 if (!format) { | |
235 test_format = SDL_NextAudioFormat(); | |
236 } | |
237 } | |
238 | |
239 if (format == 0) { | |
240 SDL_FS_CloseDevice(this); | |
241 SDL_SetError("Couldn't find any hardware audio formats"); | |
242 return 0; | |
243 } | |
244 this->spec.format = test_format; | |
245 | |
246 /* Retrieve the main sound interface. */ | |
247 ret = SDL_NAME(FusionSoundCreate) (&this->hidden->fs); | |
248 if (ret) { | |
249 SDL_FS_CloseDevice(this); | |
250 SDL_SetError("Unable to initialize FusionSound: %d", ret); | |
251 return 0; | |
252 } | |
253 | |
254 this->hidden->mixsamples = this->spec.size / bytes / this->spec.channels; | |
255 | |
256 /* Fill stream description. */ | |
257 desc.flags = FSSDF_SAMPLERATE | FSSDF_BUFFERSIZE | | |
258 FSSDF_CHANNELS | FSSDF_SAMPLEFORMAT | FSSDF_PREBUFFER; | |
259 desc.samplerate = this->spec.freq; | |
260 desc.buffersize = this->spec.size * FUSION_BUFFERS; | |
261 desc.channels = this->spec.channels; | |
262 desc.prebuffer = 10; | |
263 desc.sampleformat = fs_format; | |
264 | |
265 ret = | |
266 this->hidden->fs->CreateStream(this->hidden->fs, &desc, | |
267 &this->hidden->stream); | |
268 if (ret) { | |
269 SDL_FS_CloseDevice(this); | |
270 SDL_SetError("Unable to create FusionSoundStream: %d", ret); | |
271 return 0; | |
272 } | |
273 | |
274 /* See what we got */ | |
275 desc.flags = FSSDF_SAMPLERATE | FSSDF_BUFFERSIZE | | |
276 FSSDF_CHANNELS | FSSDF_SAMPLEFORMAT; | |
277 ret = this->hidden->stream->GetDescription(this->hidden->stream, &desc); | |
278 | |
279 this->spec.freq = desc.samplerate; | |
280 this->spec.size = | |
281 desc.buffersize / FUSION_BUFFERS * bytes * desc.channels; | |
282 this->spec.channels = desc.channels; | |
283 | |
284 /* Calculate the final parameters for this audio specification */ | |
285 SDL_CalculateAudioSpec(&this->spec); | |
286 | |
287 /* Allocate mixing buffer */ | |
288 this->hidden->mixlen = this->spec.size; | |
289 this->hidden->mixbuf = (Uint8 *) SDL_AllocAudioMem(this->hidden->mixlen); | |
290 if (this->hidden->mixbuf == NULL) { | |
291 SDL_FS_CloseDevice(this); | |
292 SDL_OutOfMemory(); | |
293 return 0; | |
294 } | |
295 SDL_memset(this->hidden->mixbuf, this->spec.silence, this->spec.size); | |
296 | |
297 /* We're ready to rock and roll. :-) */ | |
298 return 1; | |
299 } | |
300 | |
301 | |
302 static void | |
303 SDL_FS_Deinitialize(void) | |
304 { | |
305 UnloadFusionSoundLibrary(); | |
306 } | |
307 | |
308 | |
309 static int | |
310 SDL_FS_Init(SDL_AudioDriverImpl * impl) | |
311 { | |
312 if (LoadFusionSoundLibrary() < 0) { | |
313 return 0; | |
314 } else { | |
315 DirectResult ret; | |
316 | |
317 ret = SDL_NAME(FusionSoundInit) (NULL, NULL); | |
318 if (ret) { | |
319 UnloadFusionSoundLibrary(); | |
320 SDL_SetError | |
321 ("FusionSound: SDL_FS_init failed (FusionSoundInit: %d)", | |
322 ret); | |
323 return 0; | |
324 } | |
325 } | |
326 | |
327 /* Set the function pointers */ | |
328 impl->OpenDevice = SDL_FS_OpenDevice; | |
329 impl->PlayDevice = SDL_FS_PlayDevice; | |
330 impl->WaitDevice = SDL_FS_WaitDevice; | |
331 impl->GetDeviceBuf = SDL_FS_GetDeviceBuf; | |
332 impl->CloseDevice = SDL_FS_CloseDevice; | |
333 impl->WaitDone = SDL_FS_WaitDone; | |
334 impl->Deinitialize = SDL_FS_Deinitialize; | |
335 impl->OnlyHasDefaultOutputDevice = 1; | |
336 | |
337 return 1; | |
338 } | |
339 | |
340 | |
341 AudioBootStrap FUSIONSOUND_bootstrap = { | |
342 SDL_FS_DRIVER_NAME, "FusionSound", SDL_FS_Init, 0 | |
343 }; | |
344 | |
345 /* vi: set ts=4 sw=4 expandtab: */ |