src/audio/directsound/SDL_directsound.c
author Sam Lantinga <slouken@libsdl.org>
Sun, 14 Jul 2013 18:17:28 -0700
changeset 7523 9e9ab1dc3811
parent 7461 489d2bbcf4aa
child 7663 53fe1b64eb2d
permissions -rw-r--r--
Fixed bug 1919 - Window icon disappears as soon as a renderer is created

Sebastian

Setting a window icon works just fine until a renderer is added to the window.
After adding the renderer the icon disappears.

Reproduce by:
- Take the example code from the wiki: http://wiki.libsdl.org/moin.fcg/SDL_SetWindowIcon

- Add the following two lines after SDL_FreeSurface(surface);
SDL_Delay(1000);
SDL_Renderer* ren = SDL_CreateRenderer(window, -1, SDL_RENDERER_ACCELERATED);

-compile and run

You will see the window icon correctly at first. After the Delay the Icon will disappear.
     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_DSOUND
    24 
    25 /* Allow access to a raw mixing buffer */
    26 
    27 #include "SDL_timer.h"
    28 #include "SDL_loadso.h"
    29 #include "SDL_audio.h"
    30 #include "../SDL_audio_c.h"
    31 #include "SDL_directsound.h"
    32 
    33 #ifndef WAVE_FORMAT_IEEE_FLOAT
    34 #define WAVE_FORMAT_IEEE_FLOAT 0x0003
    35 #endif
    36 
    37 /* DirectX function pointers for audio */
    38 static void* DSoundDLL = NULL;
    39 typedef HRESULT(WINAPI*fnDirectSoundCreate8)(LPGUID,LPDIRECTSOUND*,LPUNKNOWN);
    40 typedef HRESULT(WINAPI*fnDirectSoundEnumerateW)(LPDSENUMCALLBACKW, LPVOID);
    41 typedef HRESULT(WINAPI*fnDirectSoundCaptureEnumerateW)(LPDSENUMCALLBACKW,LPVOID);
    42 static fnDirectSoundCreate8 pDirectSoundCreate8 = NULL;
    43 static fnDirectSoundEnumerateW pDirectSoundEnumerateW = NULL;
    44 static fnDirectSoundCaptureEnumerateW pDirectSoundCaptureEnumerateW = NULL;
    45 
    46 static void
    47 DSOUND_Unload(void)
    48 {
    49     pDirectSoundCreate8 = NULL;
    50     pDirectSoundEnumerateW = NULL;
    51     pDirectSoundCaptureEnumerateW = NULL;
    52 
    53     if (DSoundDLL != NULL) {
    54         SDL_UnloadObject(DSoundDLL);
    55         DSoundDLL = NULL;
    56     }
    57 }
    58 
    59 
    60 static int
    61 DSOUND_Load(void)
    62 {
    63     int loaded = 0;
    64 
    65     DSOUND_Unload();
    66 
    67     DSoundDLL = SDL_LoadObject("DSOUND.DLL");
    68     if (DSoundDLL == NULL) {
    69         SDL_SetError("DirectSound: failed to load DSOUND.DLL");
    70     } else {
    71         /* Now make sure we have DirectX 8 or better... */
    72         #define DSOUNDLOAD(f) { \
    73             p##f = (fn##f) SDL_LoadFunction(DSoundDLL, #f); \
    74             if (!p##f) loaded = 0; \
    75         }
    76         loaded = 1;  /* will reset if necessary. */
    77         DSOUNDLOAD(DirectSoundCreate8);
    78         DSOUNDLOAD(DirectSoundEnumerateW);
    79         DSOUNDLOAD(DirectSoundCaptureEnumerateW);
    80         #undef DSOUNDLOAD
    81 
    82         if (!loaded) {
    83             SDL_SetError("DirectSound: System doesn't appear to have DX8.");
    84         }
    85     }
    86 
    87     if (!loaded) {
    88         DSOUND_Unload();
    89     }
    90 
    91     return loaded;
    92 }
    93 
    94 static __inline__ char *
    95 utf16_to_utf8(const WCHAR *S)
    96 {
    97     /* !!! FIXME: this should be UTF-16, not UCS-2! */
    98     return SDL_iconv_string("UTF-8", "UCS-2", (char *)(S),
    99                             (SDL_wcslen(S)+1)*sizeof(WCHAR));
   100 }
   101 
   102 static int
   103 SetDSerror(const char *function, int code)
   104 {
   105     static const char *error;
   106     static char errbuf[1024];
   107 
   108     errbuf[0] = 0;
   109     switch (code) {
   110     case E_NOINTERFACE:
   111         error = "Unsupported interface -- Is DirectX 8.0 or later installed?";
   112         break;
   113     case DSERR_ALLOCATED:
   114         error = "Audio device in use";
   115         break;
   116     case DSERR_BADFORMAT:
   117         error = "Unsupported audio format";
   118         break;
   119     case DSERR_BUFFERLOST:
   120         error = "Mixing buffer was lost";
   121         break;
   122     case DSERR_CONTROLUNAVAIL:
   123         error = "Control requested is not available";
   124         break;
   125     case DSERR_INVALIDCALL:
   126         error = "Invalid call for the current state";
   127         break;
   128     case DSERR_INVALIDPARAM:
   129         error = "Invalid parameter";
   130         break;
   131     case DSERR_NODRIVER:
   132         error = "No audio device found";
   133         break;
   134     case DSERR_OUTOFMEMORY:
   135         error = "Out of memory";
   136         break;
   137     case DSERR_PRIOLEVELNEEDED:
   138         error = "Caller doesn't have priority";
   139         break;
   140     case DSERR_UNSUPPORTED:
   141         error = "Function not supported";
   142         break;
   143     default:
   144         SDL_snprintf(errbuf, SDL_arraysize(errbuf),
   145                      "%s: Unknown DirectSound error: 0x%x", function, code);
   146         break;
   147     }
   148     if (!errbuf[0]) {
   149         SDL_snprintf(errbuf, SDL_arraysize(errbuf), "%s: %s", function,
   150                      error);
   151     }
   152     return SDL_SetError("%s", errbuf);
   153 }
   154 
   155 
   156 static BOOL CALLBACK
   157 FindAllDevs(LPGUID guid, LPCWSTR desc, LPCWSTR module, LPVOID data)
   158 {
   159     SDL_AddAudioDevice addfn = (SDL_AddAudioDevice) data;
   160     if (guid != NULL) {  /* skip default device */
   161         char *str = utf16_to_utf8(desc);
   162         if (str != NULL) {
   163             addfn(str);
   164             SDL_free(str);  /* addfn() makes a copy of this string. */
   165         }
   166     }
   167     return TRUE;  /* keep enumerating. */
   168 }
   169 
   170 static void
   171 DSOUND_DetectDevices(int iscapture, SDL_AddAudioDevice addfn)
   172 {
   173     if (iscapture) {
   174         pDirectSoundCaptureEnumerateW(FindAllDevs, addfn);
   175     } else {
   176         pDirectSoundEnumerateW(FindAllDevs, addfn);
   177     }
   178 }
   179 
   180 
   181 static void
   182 DSOUND_WaitDevice(_THIS)
   183 {
   184     DWORD status = 0;
   185     DWORD cursor = 0;
   186     DWORD junk = 0;
   187     HRESULT result = DS_OK;
   188 
   189     /* Semi-busy wait, since we have no way of getting play notification
   190        on a primary mixing buffer located in hardware (DirectX 5.0)
   191      */
   192     result = IDirectSoundBuffer_GetCurrentPosition(this->hidden->mixbuf,
   193                                                    &junk, &cursor);
   194     if (result != DS_OK) {
   195         if (result == DSERR_BUFFERLOST) {
   196             IDirectSoundBuffer_Restore(this->hidden->mixbuf);
   197         }
   198 #ifdef DEBUG_SOUND
   199         SetDSerror("DirectSound GetCurrentPosition", result);
   200 #endif
   201         return;
   202     }
   203 
   204     while ((cursor / this->hidden->mixlen) == this->hidden->lastchunk) {
   205         /* FIXME: find out how much time is left and sleep that long */
   206         SDL_Delay(1);
   207 
   208         /* Try to restore a lost sound buffer */
   209         IDirectSoundBuffer_GetStatus(this->hidden->mixbuf, &status);
   210         if ((status & DSBSTATUS_BUFFERLOST)) {
   211             IDirectSoundBuffer_Restore(this->hidden->mixbuf);
   212             IDirectSoundBuffer_GetStatus(this->hidden->mixbuf, &status);
   213             if ((status & DSBSTATUS_BUFFERLOST)) {
   214                 break;
   215             }
   216         }
   217         if (!(status & DSBSTATUS_PLAYING)) {
   218             result = IDirectSoundBuffer_Play(this->hidden->mixbuf, 0, 0,
   219                                              DSBPLAY_LOOPING);
   220             if (result == DS_OK) {
   221                 continue;
   222             }
   223 #ifdef DEBUG_SOUND
   224             SetDSerror("DirectSound Play", result);
   225 #endif
   226             return;
   227         }
   228 
   229         /* Find out where we are playing */
   230         result = IDirectSoundBuffer_GetCurrentPosition(this->hidden->mixbuf,
   231                                                        &junk, &cursor);
   232         if (result != DS_OK) {
   233             SetDSerror("DirectSound GetCurrentPosition", result);
   234             return;
   235         }
   236     }
   237 }
   238 
   239 static void
   240 DSOUND_PlayDevice(_THIS)
   241 {
   242     /* Unlock the buffer, allowing it to play */
   243     if (this->hidden->locked_buf) {
   244         IDirectSoundBuffer_Unlock(this->hidden->mixbuf,
   245                                   this->hidden->locked_buf,
   246                                   this->hidden->mixlen, NULL, 0);
   247     }
   248 
   249 }
   250 
   251 static Uint8 *
   252 DSOUND_GetDeviceBuf(_THIS)
   253 {
   254     DWORD cursor = 0;
   255     DWORD junk = 0;
   256     HRESULT result = DS_OK;
   257     DWORD rawlen = 0;
   258 
   259     /* Figure out which blocks to fill next */
   260     this->hidden->locked_buf = NULL;
   261     result = IDirectSoundBuffer_GetCurrentPosition(this->hidden->mixbuf,
   262                                                    &junk, &cursor);
   263     if (result == DSERR_BUFFERLOST) {
   264         IDirectSoundBuffer_Restore(this->hidden->mixbuf);
   265         result = IDirectSoundBuffer_GetCurrentPosition(this->hidden->mixbuf,
   266                                                        &junk, &cursor);
   267     }
   268     if (result != DS_OK) {
   269         SetDSerror("DirectSound GetCurrentPosition", result);
   270         return (NULL);
   271     }
   272     cursor /= this->hidden->mixlen;
   273 #ifdef DEBUG_SOUND
   274     /* Detect audio dropouts */
   275     {
   276         DWORD spot = cursor;
   277         if (spot < this->hidden->lastchunk) {
   278             spot += this->hidden->num_buffers;
   279         }
   280         if (spot > this->hidden->lastchunk + 1) {
   281             fprintf(stderr, "Audio dropout, missed %d fragments\n",
   282                     (spot - (this->hidden->lastchunk + 1)));
   283         }
   284     }
   285 #endif
   286     this->hidden->lastchunk = cursor;
   287     cursor = (cursor + 1) % this->hidden->num_buffers;
   288     cursor *= this->hidden->mixlen;
   289 
   290     /* Lock the audio buffer */
   291     result = IDirectSoundBuffer_Lock(this->hidden->mixbuf, cursor,
   292                                      this->hidden->mixlen,
   293                                      (LPVOID *) & this->hidden->locked_buf,
   294                                      &rawlen, NULL, &junk, 0);
   295     if (result == DSERR_BUFFERLOST) {
   296         IDirectSoundBuffer_Restore(this->hidden->mixbuf);
   297         result = IDirectSoundBuffer_Lock(this->hidden->mixbuf, cursor,
   298                                          this->hidden->mixlen,
   299                                          (LPVOID *) & this->
   300                                          hidden->locked_buf, &rawlen, NULL,
   301                                          &junk, 0);
   302     }
   303     if (result != DS_OK) {
   304         SetDSerror("DirectSound Lock", result);
   305         return (NULL);
   306     }
   307     return (this->hidden->locked_buf);
   308 }
   309 
   310 static void
   311 DSOUND_WaitDone(_THIS)
   312 {
   313     Uint8 *stream = DSOUND_GetDeviceBuf(this);
   314 
   315     /* Wait for the playing chunk to finish */
   316     if (stream != NULL) {
   317         SDL_memset(stream, this->spec.silence, this->hidden->mixlen);
   318         DSOUND_PlayDevice(this);
   319     }
   320     DSOUND_WaitDevice(this);
   321 
   322     /* Stop the looping sound buffer */
   323     IDirectSoundBuffer_Stop(this->hidden->mixbuf);
   324 }
   325 
   326 static void
   327 DSOUND_CloseDevice(_THIS)
   328 {
   329     if (this->hidden != NULL) {
   330         if (this->hidden->sound != NULL) {
   331             if (this->hidden->mixbuf != NULL) {
   332                 /* Clean up the audio buffer */
   333                 IDirectSoundBuffer_Release(this->hidden->mixbuf);
   334                 this->hidden->mixbuf = NULL;
   335             }
   336             IDirectSound_Release(this->hidden->sound);
   337             this->hidden->sound = NULL;
   338         }
   339 
   340         SDL_free(this->hidden);
   341         this->hidden = NULL;
   342     }
   343 }
   344 
   345 /* This function tries to create a secondary audio buffer, and returns the
   346    number of audio chunks available in the created buffer.
   347 */
   348 static int
   349 CreateSecondary(_THIS, HWND focus)
   350 {
   351     LPDIRECTSOUND sndObj = this->hidden->sound;
   352     LPDIRECTSOUNDBUFFER *sndbuf = &this->hidden->mixbuf;
   353     Uint32 chunksize = this->spec.size;
   354     const int numchunks = 8;
   355     HRESULT result = DS_OK;
   356     DSBUFFERDESC format;
   357     LPVOID pvAudioPtr1, pvAudioPtr2;
   358     DWORD dwAudioBytes1, dwAudioBytes2;
   359     WAVEFORMATEX wfmt;
   360 
   361     SDL_zero(wfmt);
   362 
   363     if (SDL_AUDIO_ISFLOAT(this->spec.format)) {
   364         wfmt.wFormatTag = WAVE_FORMAT_IEEE_FLOAT;
   365     } else {
   366         wfmt.wFormatTag = WAVE_FORMAT_PCM;
   367     }
   368 
   369     wfmt.wBitsPerSample = SDL_AUDIO_BITSIZE(this->spec.format);
   370     wfmt.nChannels = this->spec.channels;
   371     wfmt.nSamplesPerSec = this->spec.freq;
   372     wfmt.nBlockAlign = wfmt.nChannels * (wfmt.wBitsPerSample / 8);
   373     wfmt.nAvgBytesPerSec = wfmt.nSamplesPerSec * wfmt.nBlockAlign;
   374 
   375     /* Update the fragment size as size in bytes */
   376     SDL_CalculateAudioSpec(&this->spec);
   377 
   378     /* Try to set primary mixing privileges */
   379     if (focus) {
   380         result = IDirectSound_SetCooperativeLevel(sndObj,
   381                                                   focus, DSSCL_PRIORITY);
   382     } else {
   383         result = IDirectSound_SetCooperativeLevel(sndObj,
   384                                                   GetDesktopWindow(),
   385                                                   DSSCL_NORMAL);
   386     }
   387     if (result != DS_OK) {
   388         return SetDSerror("DirectSound SetCooperativeLevel", result);
   389     }
   390 
   391     /* Try to create the secondary buffer */
   392     SDL_zero(format);
   393     format.dwSize = sizeof(format);
   394     format.dwFlags = DSBCAPS_GETCURRENTPOSITION2;
   395     if (!focus) {
   396         format.dwFlags |= DSBCAPS_GLOBALFOCUS;
   397     } else {
   398         format.dwFlags |= DSBCAPS_STICKYFOCUS;
   399     }
   400     format.dwBufferBytes = numchunks * chunksize;
   401     if ((format.dwBufferBytes < DSBSIZE_MIN) ||
   402         (format.dwBufferBytes > DSBSIZE_MAX)) {
   403         return SDL_SetError("Sound buffer size must be between %d and %d",
   404                             DSBSIZE_MIN / numchunks, DSBSIZE_MAX / numchunks);
   405     }
   406     format.dwReserved = 0;
   407     format.lpwfxFormat = &wfmt;
   408     result = IDirectSound_CreateSoundBuffer(sndObj, &format, sndbuf, NULL);
   409     if (result != DS_OK) {
   410         return SetDSerror("DirectSound CreateSoundBuffer", result);
   411     }
   412     IDirectSoundBuffer_SetFormat(*sndbuf, &wfmt);
   413 
   414     /* Silence the initial audio buffer */
   415     result = IDirectSoundBuffer_Lock(*sndbuf, 0, format.dwBufferBytes,
   416                                      (LPVOID *) & pvAudioPtr1, &dwAudioBytes1,
   417                                      (LPVOID *) & pvAudioPtr2, &dwAudioBytes2,
   418                                      DSBLOCK_ENTIREBUFFER);
   419     if (result == DS_OK) {
   420         SDL_memset(pvAudioPtr1, this->spec.silence, dwAudioBytes1);
   421         IDirectSoundBuffer_Unlock(*sndbuf,
   422                                   (LPVOID) pvAudioPtr1, dwAudioBytes1,
   423                                   (LPVOID) pvAudioPtr2, dwAudioBytes2);
   424     }
   425 
   426     /* We're ready to go */
   427     return (numchunks);
   428 }
   429 
   430 typedef struct FindDevGUIDData
   431 {
   432     const char *devname;
   433     GUID guid;
   434     int found;
   435 } FindDevGUIDData;
   436 
   437 static BOOL CALLBACK
   438 FindDevGUID(LPGUID guid, LPCWSTR desc, LPCWSTR module, LPVOID _data)
   439 {
   440     if (guid != NULL) {  /* skip the default device. */
   441         FindDevGUIDData *data = (FindDevGUIDData *) _data;
   442         char *str = utf16_to_utf8(desc);
   443         const int match = (SDL_strcmp(str, data->devname) == 0);
   444         SDL_free(str);
   445         if (match) {
   446             data->found = 1;
   447             SDL_memcpy(&data->guid, guid, sizeof (data->guid));
   448             return FALSE;  /* found it! stop enumerating. */
   449         }
   450     }
   451     return TRUE;  /* keep enumerating. */
   452 }
   453 
   454 static int
   455 DSOUND_OpenDevice(_THIS, const char *devname, int iscapture)
   456 {
   457     HRESULT result;
   458     SDL_bool valid_format = SDL_FALSE;
   459     SDL_bool tried_format = SDL_FALSE;
   460     SDL_AudioFormat test_format = SDL_FirstAudioFormat(this->spec.format);
   461     FindDevGUIDData devguid;
   462     LPGUID guid = NULL;
   463 
   464     if (devname != NULL) {
   465         devguid.found = 0;
   466         devguid.devname = devname;
   467         if (iscapture)
   468             pDirectSoundCaptureEnumerateW(FindDevGUID, &devguid);
   469         else
   470             pDirectSoundEnumerateW(FindDevGUID, &devguid);
   471 
   472         if (!devguid.found) {
   473             return SDL_SetError("DirectSound: Requested device not found");
   474         }
   475         guid = &devguid.guid;
   476     }
   477 
   478     /* Initialize all variables that we clean on shutdown */
   479     this->hidden = (struct SDL_PrivateAudioData *)
   480         SDL_malloc((sizeof *this->hidden));
   481     if (this->hidden == NULL) {
   482         return SDL_OutOfMemory();
   483     }
   484     SDL_memset(this->hidden, 0, (sizeof *this->hidden));
   485 
   486     /* Open the audio device */
   487     result = pDirectSoundCreate8(guid, &this->hidden->sound, NULL);
   488     if (result != DS_OK) {
   489         DSOUND_CloseDevice(this);
   490         return SetDSerror("DirectSoundCreate", result);
   491     }
   492 
   493     while ((!valid_format) && (test_format)) {
   494         switch (test_format) {
   495         case AUDIO_U8:
   496         case AUDIO_S16:
   497         case AUDIO_S32:
   498         case AUDIO_F32:
   499             tried_format = SDL_TRUE;
   500             this->spec.format = test_format;
   501             this->hidden->num_buffers = CreateSecondary(this, NULL);
   502             if (this->hidden->num_buffers > 0) {
   503                 valid_format = SDL_TRUE;
   504             }
   505             break;
   506         }
   507         test_format = SDL_NextAudioFormat();
   508     }
   509 
   510     if (!valid_format) {
   511         DSOUND_CloseDevice(this);
   512         if (tried_format) {
   513             return -1;  // CreateSecondary() should have called SDL_SetError().
   514         }
   515         return SDL_SetError("DirectSound: Unsupported audio format");
   516     }
   517 
   518     /* The buffer will auto-start playing in DSOUND_WaitDevice() */
   519     this->hidden->mixlen = this->spec.size;
   520 
   521     return 0;                   /* good to go. */
   522 }
   523 
   524 
   525 static void
   526 DSOUND_Deinitialize(void)
   527 {
   528     DSOUND_Unload();
   529 }
   530 
   531 
   532 static int
   533 DSOUND_Init(SDL_AudioDriverImpl * impl)
   534 {
   535     if (!DSOUND_Load()) {
   536         return 0;
   537     }
   538 
   539     /* Set the function pointers */
   540     impl->DetectDevices = DSOUND_DetectDevices;
   541     impl->OpenDevice = DSOUND_OpenDevice;
   542     impl->PlayDevice = DSOUND_PlayDevice;
   543     impl->WaitDevice = DSOUND_WaitDevice;
   544     impl->WaitDone = DSOUND_WaitDone;
   545     impl->GetDeviceBuf = DSOUND_GetDeviceBuf;
   546     impl->CloseDevice = DSOUND_CloseDevice;
   547     impl->Deinitialize = DSOUND_Deinitialize;
   548 
   549     return 1;   /* this audio target is available. */
   550 }
   551 
   552 AudioBootStrap DSOUND_bootstrap = {
   553     "directsound", "DirectSound", DSOUND_Init, 0
   554 };
   555 
   556 #endif /* SDL_AUDIO_DRIVER_DSOUND */
   557 
   558 /* vi: set ts=4 sw=4 expandtab: */