src/audio/fusionsound/SDL_fsaudio.c
author Sam Lantinga
Sat, 06 Oct 2012 12:16:32 -0700
changeset 6566 dd7e57847ea9
parent 6138 4c64952a58fb
child 6885 700f1b25f77f
permissions -rw-r--r--
Add flags to the vidmode debug output
     1 /*
     2   Simple DirectMedia Layer
     3   Copyright (C) 1997-2012 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_config.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)
    50 typedef 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 
    58 static const char *fs_library = SDL_AUDIO_DRIVER_FUSIONSOUND_DYNAMIC;
    59 static void *fs_handle = NULL;
    60 
    61 static DirectResult (*SDL_NAME(FusionSoundInit)) (int *argc, char *(*argv[]));
    62 static DirectResult (*SDL_NAME(FusionSoundCreate)) (IFusionSound **
    63                                                    ret_interface);
    64 
    65 #define SDL_FS_SYM(x) { #x, (void **) (char *) &SDL_NAME(x) }
    66 static 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 
    79 static void
    80 UnloadFusionSoundLibrary()
    81 {
    82     if (fs_handle != NULL) {
    83         SDL_UnloadObject(fs_handle);
    84         fs_handle = NULL;
    85     }
    86 }
    87 
    88 static int
    89 LoadFusionSoundLibrary(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 
   114 static void
   115 UnloadFusionSoundLibrary()
   116 {
   117     return;
   118 }
   119 
   120 static int
   121 LoadFusionSoundLibrary(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 */
   129 static void
   130 SDL_FS_WaitDevice(_THIS)
   131 {
   132     this->hidden->stream->Wait(this->hidden->stream,
   133                                this->hidden->mixsamples);
   134 }
   135 
   136 static void
   137 SDL_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 
   153 static void
   154 SDL_FS_WaitDone(_THIS)
   155 {
   156     this->hidden->stream->Wait(this->hidden->stream,
   157                                this->hidden->mixsamples * FUSION_BUFFERS);
   158 }
   159 
   160 
   161 static Uint8 *
   162 SDL_FS_GetDeviceBuf(_THIS)
   163 {
   164     return (this->hidden->mixbuf);
   165 }
   166 
   167 
   168 static void
   169 SDL_FS_CloseDevice(_THIS)
   170 {
   171     if (this->hidden != NULL) {
   172         if (this->hidden->mixbuf != NULL) {
   173             SDL_FreeAudioMem(this->hidden->mixbuf);
   174             this->hidden->mixbuf = NULL;
   175         }
   176         if (this->hidden->stream) {
   177             this->hidden->stream->Release(this->hidden->stream);
   178             this->hidden->stream = NULL;
   179         }
   180         if (this->hidden->fs) {
   181             this->hidden->fs->Release(this->hidden->fs);
   182             this->hidden->fs = NULL;
   183         }
   184         SDL_free(this->hidden);
   185         this->hidden = NULL;
   186     }
   187 }
   188 
   189 
   190 static int
   191 SDL_FS_OpenDevice(_THIS, const char *devname, int iscapture)
   192 {
   193     int bytes;
   194     SDL_AudioFormat test_format = 0, format = 0;
   195     FSSampleFormat fs_format;
   196     FSStreamDescription desc;
   197     DirectResult ret;
   198 
   199     /* Initialize all variables that we clean on shutdown */
   200     this->hidden = (struct SDL_PrivateAudioData *)
   201         SDL_malloc((sizeof *this->hidden));
   202     if (this->hidden == NULL) {
   203         SDL_OutOfMemory();
   204         return 0;
   205     }
   206     SDL_memset(this->hidden, 0, (sizeof *this->hidden));
   207 
   208     /* Try for a closest match on audio format */
   209     for (test_format = SDL_FirstAudioFormat(this->spec.format);
   210          !format && test_format;) {
   211 #ifdef DEBUG_AUDIO
   212         fprintf(stderr, "Trying format 0x%4.4x\n", test_format);
   213 #endif
   214         switch (test_format) {
   215         case AUDIO_U8:
   216             fs_format = FSSF_U8;
   217             bytes = 1;
   218             format = 1;
   219             break;
   220         case AUDIO_S16SYS:
   221             fs_format = FSSF_S16;
   222             bytes = 2;
   223             format = 1;
   224             break;
   225         case AUDIO_S32SYS:
   226             fs_format = FSSF_S32;
   227             bytes = 4;
   228             format = 1;
   229             break;
   230         case AUDIO_F32SYS:
   231             fs_format = FSSF_FLOAT;
   232             bytes = 4;
   233             format = 1;
   234             break;
   235         default:
   236             format = 0;
   237             break;
   238         }
   239         if (!format) {
   240             test_format = SDL_NextAudioFormat();
   241         }
   242     }
   243 
   244     if (format == 0) {
   245         SDL_FS_CloseDevice(this);
   246         SDL_SetError("Couldn't find any hardware audio formats");
   247         return 0;
   248     }
   249     this->spec.format = test_format;
   250 
   251     /* Retrieve the main sound interface. */
   252     ret = SDL_NAME(FusionSoundCreate) (&this->hidden->fs);
   253     if (ret) {
   254         SDL_FS_CloseDevice(this);
   255         SDL_SetError("Unable to initialize FusionSound: %d", ret);
   256         return 0;
   257     }
   258 
   259     this->hidden->mixsamples = this->spec.size / bytes / this->spec.channels;
   260 
   261     /* Fill stream description. */
   262     desc.flags = FSSDF_SAMPLERATE | FSSDF_BUFFERSIZE |
   263         FSSDF_CHANNELS | FSSDF_SAMPLEFORMAT | FSSDF_PREBUFFER;
   264     desc.samplerate = this->spec.freq;
   265     desc.buffersize = this->spec.size * FUSION_BUFFERS;
   266     desc.channels = this->spec.channels;
   267     desc.prebuffer = 10;
   268     desc.sampleformat = fs_format;
   269 
   270     ret =
   271         this->hidden->fs->CreateStream(this->hidden->fs, &desc,
   272                                        &this->hidden->stream);
   273     if (ret) {
   274         SDL_FS_CloseDevice(this);
   275         SDL_SetError("Unable to create FusionSoundStream: %d", ret);
   276         return 0;
   277     }
   278 
   279     /* See what we got */
   280     desc.flags = FSSDF_SAMPLERATE | FSSDF_BUFFERSIZE |
   281         FSSDF_CHANNELS | FSSDF_SAMPLEFORMAT;
   282     ret = this->hidden->stream->GetDescription(this->hidden->stream, &desc);
   283 
   284     this->spec.freq = desc.samplerate;
   285     this->spec.size =
   286         desc.buffersize / FUSION_BUFFERS * bytes * desc.channels;
   287     this->spec.channels = desc.channels;
   288 
   289     /* Calculate the final parameters for this audio specification */
   290     SDL_CalculateAudioSpec(&this->spec);
   291 
   292     /* Allocate mixing buffer */
   293     this->hidden->mixlen = this->spec.size;
   294     this->hidden->mixbuf = (Uint8 *) SDL_AllocAudioMem(this->hidden->mixlen);
   295     if (this->hidden->mixbuf == NULL) {
   296         SDL_FS_CloseDevice(this);
   297         SDL_OutOfMemory();
   298         return 0;
   299     }
   300     SDL_memset(this->hidden->mixbuf, this->spec.silence, this->spec.size);
   301 
   302     /* We're ready to rock and roll. :-) */
   303     return 1;
   304 }
   305 
   306 
   307 static void
   308 SDL_FS_Deinitialize(void)
   309 {
   310     UnloadFusionSoundLibrary();
   311 }
   312 
   313 
   314 static int
   315 SDL_FS_Init(SDL_AudioDriverImpl * impl)
   316 {
   317     if (LoadFusionSoundLibrary() < 0) {
   318         return 0;
   319     } else {
   320         DirectResult ret;
   321 
   322         ret = SDL_NAME(FusionSoundInit) (NULL, NULL);
   323         if (ret) {
   324             UnloadFusionSoundLibrary();
   325             SDL_SetError
   326                 ("FusionSound: SDL_FS_init failed (FusionSoundInit: %d)",
   327                  ret);
   328             return 0;
   329         }
   330     }
   331 
   332     /* Set the function pointers */
   333     impl->OpenDevice = SDL_FS_OpenDevice;
   334     impl->PlayDevice = SDL_FS_PlayDevice;
   335     impl->WaitDevice = SDL_FS_WaitDevice;
   336     impl->GetDeviceBuf = SDL_FS_GetDeviceBuf;
   337     impl->CloseDevice = SDL_FS_CloseDevice;
   338     impl->WaitDone = SDL_FS_WaitDone;
   339     impl->Deinitialize = SDL_FS_Deinitialize;
   340     impl->OnlyHasDefaultOutputDevice = 1;
   341 
   342     return 1;   /* this audio target is available. */
   343 }
   344 
   345 
   346 AudioBootStrap FUSIONSOUND_bootstrap = {
   347     "fusionsound", "FusionSound", SDL_FS_Init, 0
   348 };
   349 
   350 #endif /* SDL_AUDIO_DRIVER_FUSIONSOUND */
   351 
   352 /* vi: set ts=4 sw=4 expandtab: */