SDL_fsaudio.c (9254B)
1/* 2 Simple DirectMedia Layer 3 Copyright (C) 1997-2014 Sam Lantinga <slouken@libsdl.org> 4 5 This software is provided 'as-is', without any express or implied 6 warranty. In no event will the authors be held liable for any damages 7 arising from the use of this software. 8 9 Permission is granted to anyone to use this software for any purpose, 10 including commercial applications, and to alter it and redistribute it 11 freely, subject to the following restrictions: 12 13 1. The origin of this software must not be misrepresented; you must not 14 claim that you wrote the original software. If you use this software 15 in a product, an acknowledgment in the product documentation would be 16 appreciated but is not required. 17 2. Altered source versions must be plainly marked as such, and must not be 18 misrepresented as being the original software. 19 3. This notice may not be removed or altered from any source distribution. 20*/ 21#include "../../SDL_internal.h" 22 23#if SDL_AUDIO_DRIVER_FUSIONSOUND 24 25/* Allow access to a raw mixing buffer */ 26 27#ifdef HAVE_SIGNAL_H 28#include <signal.h> 29#endif 30#include <unistd.h> 31 32#include "SDL_timer.h" 33#include "SDL_audio.h" 34#include "../SDL_audiomem.h" 35#include "../SDL_audio_c.h" 36#include "SDL_fsaudio.h" 37 38#include <fusionsound/fusionsound_version.h> 39 40/* #define SDL_AUDIO_DRIVER_FUSIONSOUND_DYNAMIC "libfusionsound.so" */ 41 42#ifdef SDL_AUDIO_DRIVER_FUSIONSOUND_DYNAMIC 43#include "SDL_name.h" 44#include "SDL_loadso.h" 45#else 46#define SDL_NAME(X) X 47#endif 48 49#if (FUSIONSOUND_MAJOR_VERSION == 1) && (FUSIONSOUND_MINOR_VERSION < 1) 50typedef DFBResult DirectResult; 51#endif 52 53/* Buffers to use - more than 2 gives a lot of latency */ 54#define FUSION_BUFFERS (2) 55 56#ifdef SDL_AUDIO_DRIVER_FUSIONSOUND_DYNAMIC 57 58static const char *fs_library = SDL_AUDIO_DRIVER_FUSIONSOUND_DYNAMIC; 59static void *fs_handle = NULL; 60 61static DirectResult (*SDL_NAME(FusionSoundInit)) (int *argc, char *(*argv[])); 62static DirectResult (*SDL_NAME(FusionSoundCreate)) (IFusionSound ** 63 ret_interface); 64 65#define SDL_FS_SYM(x) { #x, (void **) (char *) &SDL_NAME(x) } 66static struct 67{ 68 const char *name; 69 void **func; 70} fs_functions[] = { 71/* *INDENT-OFF* */ 72 SDL_FS_SYM(FusionSoundInit), 73 SDL_FS_SYM(FusionSoundCreate), 74/* *INDENT-ON* */ 75}; 76 77#undef SDL_FS_SYM 78 79static void 80UnloadFusionSoundLibrary() 81{ 82 if (fs_handle != NULL) { 83 SDL_UnloadObject(fs_handle); 84 fs_handle = NULL; 85 } 86} 87 88static int 89LoadFusionSoundLibrary(void) 90{ 91 int i, retval = -1; 92 93 if (fs_handle == NULL) { 94 fs_handle = SDL_LoadObject(fs_library); 95 if (fs_handle != NULL) { 96 retval = 0; 97 for (i = 0; i < SDL_arraysize(fs_functions); ++i) { 98 *fs_functions[i].func = 99 SDL_LoadFunction(fs_handle, fs_functions[i].name); 100 if (!*fs_functions[i].func) { 101 retval = -1; 102 UnloadFusionSoundLibrary(); 103 break; 104 } 105 } 106 } 107 } 108 109 return retval; 110} 111 112#else 113 114static void 115UnloadFusionSoundLibrary() 116{ 117 return; 118} 119 120static int 121LoadFusionSoundLibrary(void) 122{ 123 return 0; 124} 125 126#endif /* SDL_AUDIO_DRIVER_FUSIONSOUND_DYNAMIC */ 127 128/* This function waits until it is possible to write a full sound buffer */ 129static void 130SDL_FS_WaitDevice(_THIS) 131{ 132 this->hidden->stream->Wait(this->hidden->stream, 133 this->hidden->mixsamples); 134} 135 136static void 137SDL_FS_PlayDevice(_THIS) 138{ 139 DirectResult ret; 140 141 ret = this->hidden->stream->Write(this->hidden->stream, 142 this->hidden->mixbuf, 143 this->hidden->mixsamples); 144 /* If we couldn't write, assume fatal error for now */ 145 if (ret) { 146 this->enabled = 0; 147 } 148#ifdef DEBUG_AUDIO 149 fprintf(stderr, "Wrote %d bytes of audio data\n", this->hidden->mixlen); 150#endif 151} 152 153static void 154SDL_FS_WaitDone(_THIS) 155{ 156 this->hidden->stream->Wait(this->hidden->stream, 157 this->hidden->mixsamples * FUSION_BUFFERS); 158} 159 160 161static Uint8 * 162SDL_FS_GetDeviceBuf(_THIS) 163{ 164 return (this->hidden->mixbuf); 165} 166 167 168static void 169SDL_FS_CloseDevice(_THIS) 170{ 171 if (this->hidden != NULL) { 172 SDL_FreeAudioMem(this->hidden->mixbuf); 173 this->hidden->mixbuf = NULL; 174 if (this->hidden->stream) { 175 this->hidden->stream->Release(this->hidden->stream); 176 this->hidden->stream = NULL; 177 } 178 if (this->hidden->fs) { 179 this->hidden->fs->Release(this->hidden->fs); 180 this->hidden->fs = NULL; 181 } 182 SDL_free(this->hidden); 183 this->hidden = NULL; 184 } 185} 186 187 188static int 189SDL_FS_OpenDevice(_THIS, const char *devname, int iscapture) 190{ 191 int bytes; 192 SDL_AudioFormat test_format = 0, format = 0; 193 FSSampleFormat fs_format; 194 FSStreamDescription desc; 195 DirectResult ret; 196 197 /* Initialize all variables that we clean on shutdown */ 198 this->hidden = (struct SDL_PrivateAudioData *) 199 SDL_malloc((sizeof *this->hidden)); 200 if (this->hidden == NULL) { 201 return SDL_OutOfMemory(); 202 } 203 SDL_memset(this->hidden, 0, (sizeof *this->hidden)); 204 205 /* Try for a closest match on audio format */ 206 for (test_format = SDL_FirstAudioFormat(this->spec.format); 207 !format && test_format;) { 208#ifdef DEBUG_AUDIO 209 fprintf(stderr, "Trying format 0x%4.4x\n", test_format); 210#endif 211 switch (test_format) { 212 case AUDIO_U8: 213 fs_format = FSSF_U8; 214 bytes = 1; 215 format = 1; 216 break; 217 case AUDIO_S16SYS: 218 fs_format = FSSF_S16; 219 bytes = 2; 220 format = 1; 221 break; 222 case AUDIO_S32SYS: 223 fs_format = FSSF_S32; 224 bytes = 4; 225 format = 1; 226 break; 227 case AUDIO_F32SYS: 228 fs_format = FSSF_FLOAT; 229 bytes = 4; 230 format = 1; 231 break; 232 default: 233 format = 0; 234 break; 235 } 236 if (!format) { 237 test_format = SDL_NextAudioFormat(); 238 } 239 } 240 241 if (format == 0) { 242 SDL_FS_CloseDevice(this); 243 return SDL_SetError("Couldn't find any hardware audio formats"); 244 } 245 this->spec.format = test_format; 246 247 /* Retrieve the main sound interface. */ 248 ret = SDL_NAME(FusionSoundCreate) (&this->hidden->fs); 249 if (ret) { 250 SDL_FS_CloseDevice(this); 251 return SDL_SetError("Unable to initialize FusionSound: %d", ret); 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 return SDL_SetError("Unable to create FusionSoundStream: %d", ret); 271 } 272 273 /* See what we got */ 274 desc.flags = FSSDF_SAMPLERATE | FSSDF_BUFFERSIZE | 275 FSSDF_CHANNELS | FSSDF_SAMPLEFORMAT; 276 ret = this->hidden->stream->GetDescription(this->hidden->stream, &desc); 277 278 this->spec.freq = desc.samplerate; 279 this->spec.size = 280 desc.buffersize / FUSION_BUFFERS * bytes * desc.channels; 281 this->spec.channels = desc.channels; 282 283 /* Calculate the final parameters for this audio specification */ 284 SDL_CalculateAudioSpec(&this->spec); 285 286 /* Allocate mixing buffer */ 287 this->hidden->mixlen = this->spec.size; 288 this->hidden->mixbuf = (Uint8 *) SDL_AllocAudioMem(this->hidden->mixlen); 289 if (this->hidden->mixbuf == NULL) { 290 SDL_FS_CloseDevice(this); 291 return SDL_OutOfMemory(); 292 } 293 SDL_memset(this->hidden->mixbuf, this->spec.silence, this->spec.size); 294 295 /* We're ready to rock and roll. :-) */ 296 return 0; 297} 298 299 300static void 301SDL_FS_Deinitialize(void) 302{ 303 UnloadFusionSoundLibrary(); 304} 305 306 307static int 308SDL_FS_Init(SDL_AudioDriverImpl * impl) 309{ 310 if (LoadFusionSoundLibrary() < 0) { 311 return 0; 312 } else { 313 DirectResult ret; 314 315 ret = SDL_NAME(FusionSoundInit) (NULL, NULL); 316 if (ret) { 317 UnloadFusionSoundLibrary(); 318 SDL_SetError 319 ("FusionSound: SDL_FS_init failed (FusionSoundInit: %d)", 320 ret); 321 return 0; 322 } 323 } 324 325 /* Set the function pointers */ 326 impl->OpenDevice = SDL_FS_OpenDevice; 327 impl->PlayDevice = SDL_FS_PlayDevice; 328 impl->WaitDevice = SDL_FS_WaitDevice; 329 impl->GetDeviceBuf = SDL_FS_GetDeviceBuf; 330 impl->CloseDevice = SDL_FS_CloseDevice; 331 impl->WaitDone = SDL_FS_WaitDone; 332 impl->Deinitialize = SDL_FS_Deinitialize; 333 impl->OnlyHasDefaultOutputDevice = 1; 334 335 return 1; /* this audio target is available. */ 336} 337 338 339AudioBootStrap FUSIONSOUND_bootstrap = { 340 "fusionsound", "FusionSound", SDL_FS_Init, 0 341}; 342 343#endif /* SDL_AUDIO_DRIVER_FUSIONSOUND */ 344 345/* vi: set ts=4 sw=4 expandtab: */