src/audio/fusionsound/SDL_fsaudio.c
author Sam Lantinga
Thu, 16 May 2013 00:43:22 -0700
changeset 7180 3733e68edbc3
parent 7038 7f22b9ba218f
child 7191 75360622e65f
permissions -rw-r--r--
Fixed bug 1846 - _allmul implementation in SDL_stdlib.c doesn't clean up the stack

Colin Barrett

I see this manifest itself (VS2012 x86) as:

"Run-Time Check Failure #0 - The value of ESP was not properly saved across a function call. This is usually a result of calling a function declared with one calling convention with a function pointer declared with a different calling convention."

in the first call to SDL_GetTicks in my application. The disassembly at the problem line is:

hires_now.QuadPart *= 1000;
00AD0792 push 0
00AD0794 push 3E8h
00AD0799 mov eax,dword ptr [ebp-10h]
00AD079C push eax
00AD079D mov ecx,dword ptr [hires_now]
00AD07A0 push ecx
00AD07A1 call _allmul (0AE7D40h)
00AD07A6 mov dword ptr [hires_now],eax
00AD07A9 mov dword ptr [ebp-10h],edx

Apparently _allmul should be popping the stack but isn't (other similar functions in SDL_stdlib.c - _alldiv and whatnot - DO pop the stack).

A 'ret 10h' at the end of _allmul appears to do the trick
     1 /*
     2   Simple DirectMedia Layer
     3   Copyright (C) 1997-2013 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         return SDL_OutOfMemory();
   204     }
   205     SDL_memset(this->hidden, 0, (sizeof *this->hidden));
   206 
   207     /* Try for a closest match on audio format */
   208     for (test_format = SDL_FirstAudioFormat(this->spec.format);
   209          !format && test_format;) {
   210 #ifdef DEBUG_AUDIO
   211         fprintf(stderr, "Trying format 0x%4.4x\n", test_format);
   212 #endif
   213         switch (test_format) {
   214         case AUDIO_U8:
   215             fs_format = FSSF_U8;
   216             bytes = 1;
   217             format = 1;
   218             break;
   219         case AUDIO_S16SYS:
   220             fs_format = FSSF_S16;
   221             bytes = 2;
   222             format = 1;
   223             break;
   224         case AUDIO_S32SYS:
   225             fs_format = FSSF_S32;
   226             bytes = 4;
   227             format = 1;
   228             break;
   229         case AUDIO_F32SYS:
   230             fs_format = FSSF_FLOAT;
   231             bytes = 4;
   232             format = 1;
   233             break;
   234         default:
   235             format = 0;
   236             break;
   237         }
   238         if (!format) {
   239             test_format = SDL_NextAudioFormat();
   240         }
   241     }
   242 
   243     if (format == 0) {
   244         SDL_FS_CloseDevice(this);
   245         return SDL_SetError("Couldn't find any hardware audio formats");
   246     }
   247     this->spec.format = test_format;
   248 
   249     /* Retrieve the main sound interface. */
   250     ret = SDL_NAME(FusionSoundCreate) (&this->hidden->fs);
   251     if (ret) {
   252         SDL_FS_CloseDevice(this);
   253         return SDL_SetError("Unable to initialize FusionSound: %d", ret);
   254     }
   255 
   256     this->hidden->mixsamples = this->spec.size / bytes / this->spec.channels;
   257 
   258     /* Fill stream description. */
   259     desc.flags = FSSDF_SAMPLERATE | FSSDF_BUFFERSIZE |
   260         FSSDF_CHANNELS | FSSDF_SAMPLEFORMAT | FSSDF_PREBUFFER;
   261     desc.samplerate = this->spec.freq;
   262     desc.buffersize = this->spec.size * FUSION_BUFFERS;
   263     desc.channels = this->spec.channels;
   264     desc.prebuffer = 10;
   265     desc.sampleformat = fs_format;
   266 
   267     ret =
   268         this->hidden->fs->CreateStream(this->hidden->fs, &desc,
   269                                        &this->hidden->stream);
   270     if (ret) {
   271         SDL_FS_CloseDevice(this);
   272         return SDL_SetError("Unable to create FusionSoundStream: %d", ret);
   273     }
   274 
   275     /* See what we got */
   276     desc.flags = FSSDF_SAMPLERATE | FSSDF_BUFFERSIZE |
   277         FSSDF_CHANNELS | FSSDF_SAMPLEFORMAT;
   278     ret = this->hidden->stream->GetDescription(this->hidden->stream, &desc);
   279 
   280     this->spec.freq = desc.samplerate;
   281     this->spec.size =
   282         desc.buffersize / FUSION_BUFFERS * bytes * desc.channels;
   283     this->spec.channels = desc.channels;
   284 
   285     /* Calculate the final parameters for this audio specification */
   286     SDL_CalculateAudioSpec(&this->spec);
   287 
   288     /* Allocate mixing buffer */
   289     this->hidden->mixlen = this->spec.size;
   290     this->hidden->mixbuf = (Uint8 *) SDL_AllocAudioMem(this->hidden->mixlen);
   291     if (this->hidden->mixbuf == NULL) {
   292         SDL_FS_CloseDevice(this);
   293         return SDL_OutOfMemory();
   294     }
   295     SDL_memset(this->hidden->mixbuf, this->spec.silence, this->spec.size);
   296 
   297     /* We're ready to rock and roll. :-) */
   298     return 0;
   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;   /* this audio target is available. */
   338 }
   339 
   340 
   341 AudioBootStrap FUSIONSOUND_bootstrap = {
   342     "fusionsound", "FusionSound", SDL_FS_Init, 0
   343 };
   344 
   345 #endif /* SDL_AUDIO_DRIVER_FUSIONSOUND */
   346 
   347 /* vi: set ts=4 sw=4 expandtab: */