sdl

FORK: Simple Directmedia Layer
git clone https://git.neptards.moe/neptards/sdl.git
Log | Files | Refs

SDL_fsaudio.c (8730B)


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