src/audio/fusionsound/SDL_fsaudio.c
author David Ludwig
Thu, 31 Dec 2015 01:54:11 -0500
changeset 9993 e05d46c27ce3
parent 9619 b94b6d0bff0f
child 9998 f67cf37e9cd4
permissions -rw-r--r--
WinRT: minor code-comment cleanups
     1 /*
     2   Simple DirectMedia Layer
     3   Copyright (C) 1997-2015 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)
    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         SDL_OpenedAudioDeviceDisconnected(this);
   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         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 
   188 static int
   189 SDL_FS_OpenDevice(_THIS, void *handle, 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 
   300 static void
   301 SDL_FS_Deinitialize(void)
   302 {
   303     UnloadFusionSoundLibrary();
   304 }
   305 
   306 
   307 static int
   308 SDL_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 
   339 AudioBootStrap 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: */