src/audio/qsa/SDL_qsa_audio.c
author Sam Lantinga <slouken@libsdl.org>
Sun, 14 Jul 2013 18:17:28 -0700
changeset 7523 9e9ab1dc3811
parent 7038 7f22b9ba218f
child 7719 31b5f9ff36ca
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 
    22 #include "SDL_config.h"
    23 
    24 #if SDL_AUDIO_DRIVER_QSA
    25 
    26 #include <errno.h>
    27 #include <unistd.h>
    28 #include <fcntl.h>
    29 #include <signal.h>
    30 #include <sys/types.h>
    31 #include <sys/time.h>
    32 #include <sched.h>
    33 #include <sys/select.h>
    34 #include <sys/neutrino.h>
    35 #include <sys/asoundlib.h>
    36 
    37 #include "SDL_timer.h"
    38 #include "SDL_audio.h"
    39 #include "../SDL_audiomem.h"
    40 #include "../SDL_audio_c.h"
    41 #include "SDL_qsa_audio.h"
    42 
    43 /* default channel communication parameters */
    44 #define DEFAULT_CPARAMS_RATE   44100
    45 #define DEFAULT_CPARAMS_VOICES 1
    46 
    47 #define DEFAULT_CPARAMS_FRAG_SIZE 4096
    48 #define DEFAULT_CPARAMS_FRAGS_MIN 1
    49 #define DEFAULT_CPARAMS_FRAGS_MAX 1
    50 
    51 #define QSA_NO_WORKAROUNDS  0x00000000
    52 #define QSA_MMAP_WORKAROUND 0x00000001
    53 
    54 struct BuggyCards
    55 {
    56     char *cardname;
    57     unsigned long bugtype;
    58 };
    59 
    60 #define QSA_WA_CARDS             3
    61 #define QSA_MAX_CARD_NAME_LENGTH 33
    62 
    63 struct BuggyCards buggycards[QSA_WA_CARDS] = {
    64     {"Sound Blaster Live!", QSA_MMAP_WORKAROUND},
    65     {"Vortex 8820", QSA_MMAP_WORKAROUND},
    66     {"Vortex 8830", QSA_MMAP_WORKAROUND},
    67 };
    68 
    69 /* List of found devices */
    70 #define QSA_MAX_DEVICES       32
    71 #define QSA_MAX_NAME_LENGTH   81+16     /* Hardcoded in QSA, can't be changed */
    72 
    73 typedef struct _QSA_Device
    74 {
    75     char name[QSA_MAX_NAME_LENGTH];     /* Long audio device name for SDL  */
    76     int cardno;
    77     int deviceno;
    78 } QSA_Device;
    79 
    80 QSA_Device qsa_playback_device[QSA_MAX_DEVICES];
    81 uint32_t qsa_playback_devices;
    82 
    83 QSA_Device qsa_capture_device[QSA_MAX_DEVICES];
    84 uint32_t qsa_capture_devices;
    85 
    86 static inline int
    87 QSA_SetError(const char *fn, int status)
    88 {
    89     return SDL_SetError("QSA: %s() failed: %s", fn, snd_strerror(status));
    90 }
    91 
    92 /* card names check to apply the workarounds */
    93 static int
    94 QSA_CheckBuggyCards(_THIS, unsigned long checkfor)
    95 {
    96     char scardname[QSA_MAX_CARD_NAME_LENGTH];
    97     int it;
    98 
    99     if (snd_card_get_name
   100         (this->hidden->cardno, scardname, QSA_MAX_CARD_NAME_LENGTH - 1) < 0) {
   101         return 0;
   102     }
   103 
   104     for (it = 0; it < QSA_WA_CARDS; it++) {
   105         if (SDL_strcmp(buggycards[it].cardname, scardname) == 0) {
   106             if (buggycards[it].bugtype == checkfor) {
   107                 return 1;
   108             }
   109         }
   110     }
   111 
   112     return 0;
   113 }
   114 
   115 /* !!! FIXME: does this need to be here? Does the SDL version not work? */
   116 static void
   117 QSA_ThreadInit(_THIS)
   118 {
   119     struct sched_param param;
   120     int status;
   121 
   122     /* Increase default 10 priority to 25 to avoid jerky sound */
   123     status = SchedGet(0, 0, &param);
   124     param.sched_priority = param.sched_curpriority + 15;
   125     status = SchedSet(0, 0, SCHED_NOCHANGE, &param);
   126 }
   127 
   128 /* PCM channel parameters initialize function */
   129 static void
   130 QSA_InitAudioParams(snd_pcm_channel_params_t * cpars)
   131 {
   132     SDL_memset(cpars, 0, sizeof(snd_pcm_channel_params_t));
   133 
   134     cpars->channel = SND_PCM_CHANNEL_PLAYBACK;
   135     cpars->mode = SND_PCM_MODE_BLOCK;
   136     cpars->start_mode = SND_PCM_START_DATA;
   137     cpars->stop_mode = SND_PCM_STOP_STOP;
   138     cpars->format.format = SND_PCM_SFMT_S16_LE;
   139     cpars->format.interleave = 1;
   140     cpars->format.rate = DEFAULT_CPARAMS_RATE;
   141     cpars->format.voices = DEFAULT_CPARAMS_VOICES;
   142     cpars->buf.block.frag_size = DEFAULT_CPARAMS_FRAG_SIZE;
   143     cpars->buf.block.frags_min = DEFAULT_CPARAMS_FRAGS_MIN;
   144     cpars->buf.block.frags_max = DEFAULT_CPARAMS_FRAGS_MAX;
   145 }
   146 
   147 /* This function waits until it is possible to write a full sound buffer */
   148 static void
   149 QSA_WaitDevice(_THIS)
   150 {
   151     fd_set wfds;
   152     fd_set rfds;
   153     int selectret;
   154     struct timeval timeout;
   155 
   156     if (!this->hidden->iscapture) {
   157         FD_ZERO(&wfds);
   158         FD_SET(this->hidden->audio_fd, &wfds);
   159     } else {
   160         FD_ZERO(&rfds);
   161         FD_SET(this->hidden->audio_fd, &rfds);
   162     }
   163 
   164     do {
   165         /* Setup timeout for playing one fragment equal to 2 seconds          */
   166         /* If timeout occured than something wrong with hardware or driver    */
   167         /* For example, Vortex 8820 audio driver stucks on second DAC because */
   168         /* it doesn't exist !                                                 */
   169         timeout.tv_sec = 2;
   170         timeout.tv_usec = 0;
   171         this->hidden->timeout_on_wait = 0;
   172 
   173         if (!this->hidden->iscapture) {
   174             selectret =
   175                 select(this->hidden->audio_fd + 1, NULL, &wfds, NULL,
   176                        &timeout);
   177         } else {
   178             selectret =
   179                 select(this->hidden->audio_fd + 1, &rfds, NULL, NULL,
   180                        &timeout);
   181         }
   182 
   183         switch (selectret) {
   184         case -1:
   185             {
   186                 SDL_SetError("QSA: select() failed: %s", strerror(errno));
   187                 return;
   188             }
   189             break;
   190         case 0:
   191             {
   192                 SDL_SetError("QSA: timeout on buffer waiting occured");
   193                 this->hidden->timeout_on_wait = 1;
   194                 return;
   195             }
   196             break;
   197         default:
   198             {
   199                 if (!this->hidden->iscapture) {
   200                     if (FD_ISSET(this->hidden->audio_fd, &wfds)) {
   201                         return;
   202                     }
   203                 } else {
   204                     if (FD_ISSET(this->hidden->audio_fd, &rfds)) {
   205                         return;
   206                     }
   207                 }
   208             }
   209             break;
   210         }
   211     } while (1);
   212 }
   213 
   214 static void
   215 QSA_PlayDevice(_THIS)
   216 {
   217     snd_pcm_channel_status_t cstatus;
   218     int written;
   219     int status;
   220     int towrite;
   221     void *pcmbuffer;
   222 
   223     if ((!this->enabled) || (!this->hidden)) {
   224         return;
   225     }
   226 
   227     towrite = this->spec.size;
   228     pcmbuffer = this->hidden->pcm_buf;
   229 
   230     /* Write the audio data, checking for EAGAIN (buffer full) and underrun */
   231     do {
   232         written =
   233             snd_pcm_plugin_write(this->hidden->audio_handle, pcmbuffer,
   234                                  towrite);
   235         if (written != towrite) {
   236             /* Check if samples playback got stuck somewhere in hardware or in */
   237             /* the audio device driver */
   238             if ((errno == EAGAIN) && (written == 0)) {
   239                 if (this->hidden->timeout_on_wait != 0) {
   240                     SDL_SetError("QSA: buffer playback timeout");
   241                     return;
   242                 }
   243             }
   244 
   245             /* Check for errors or conditions */
   246             if ((errno == EAGAIN) || (errno == EWOULDBLOCK)) {
   247                 /* Let a little CPU time go by and try to write again */
   248                 SDL_Delay(1);
   249 
   250                 /* if we wrote some data */
   251                 towrite -= written;
   252                 pcmbuffer += written * this->spec.channels;
   253                 continue;
   254             } else {
   255                 if ((errno == EINVAL) || (errno == EIO)) {
   256                     SDL_memset(&cstatus, 0, sizeof(cstatus));
   257                     if (!this->hidden->iscapture) {
   258                         cstatus.channel = SND_PCM_CHANNEL_PLAYBACK;
   259                     } else {
   260                         cstatus.channel = SND_PCM_CHANNEL_CAPTURE;
   261                     }
   262 
   263                     status =
   264                         snd_pcm_plugin_status(this->hidden->audio_handle,
   265                                               &cstatus);
   266                     if (status < 0) {
   267                         QSA_SetError("snd_pcm_plugin_status", status);
   268                         return;
   269                     }
   270 
   271                     if ((cstatus.status == SND_PCM_STATUS_UNDERRUN) ||
   272                         (cstatus.status == SND_PCM_STATUS_READY)) {
   273                         if (!this->hidden->iscapture) {
   274                             status =
   275                                 snd_pcm_plugin_prepare(this->hidden->
   276                                                        audio_handle,
   277                                                        SND_PCM_CHANNEL_PLAYBACK);
   278                         } else {
   279                             status =
   280                                 snd_pcm_plugin_prepare(this->hidden->
   281                                                        audio_handle,
   282                                                        SND_PCM_CHANNEL_CAPTURE);
   283                         }
   284                         if (status < 0) {
   285                             QSA_SetError("snd_pcm_plugin_prepare", status);
   286                             return;
   287                         }
   288                     }
   289                     continue;
   290                 } else {
   291                     return;
   292                 }
   293             }
   294         } else {
   295             /* we wrote all remaining data */
   296             towrite -= written;
   297             pcmbuffer += written * this->spec.channels;
   298         }
   299     } while ((towrite > 0) && (this->enabled));
   300 
   301     /* If we couldn't write, assume fatal error for now */
   302     if (towrite != 0) {
   303         this->enabled = 0;
   304     }
   305 }
   306 
   307 static Uint8 *
   308 QSA_GetDeviceBuf(_THIS)
   309 {
   310     return this->hidden->pcm_buf;
   311 }
   312 
   313 static void
   314 QSA_CloseDevice(_THIS)
   315 {
   316     if (this->hidden != NULL) {
   317         if (this->hidden->audio_handle != NULL) {
   318             if (!this->hidden->iscapture) {
   319                 /* Finish playing available samples */
   320                 snd_pcm_plugin_flush(this->hidden->audio_handle,
   321                                      SND_PCM_CHANNEL_PLAYBACK);
   322             } else {
   323                 /* Cancel unread samples during capture */
   324                 snd_pcm_plugin_flush(this->hidden->audio_handle,
   325                                      SND_PCM_CHANNEL_CAPTURE);
   326             }
   327             snd_pcm_close(this->hidden->audio_handle);
   328             this->hidden->audio_handle = NULL;
   329         }
   330 
   331         if (this->hidden->pcm_buf != NULL) {
   332             SDL_FreeAudioMem(this->hidden->pcm_buf);
   333             this->hidden->pcm_buf = NULL;
   334         }
   335 
   336         SDL_free(this->hidden);
   337         this->hidden = NULL;
   338     }
   339 }
   340 
   341 static int
   342 QSA_OpenDevice(_THIS, const char *devname, int iscapture)
   343 {
   344     int status = 0;
   345     int format = 0;
   346     SDL_AudioFormat test_format = 0;
   347     int found = 0;
   348     snd_pcm_channel_setup_t csetup;
   349     snd_pcm_channel_params_t cparams;
   350 
   351     /* Initialize all variables that we clean on shutdown */
   352     this->hidden =
   353         (struct SDL_PrivateAudioData *) SDL_calloc(1,
   354                                                    (sizeof
   355                                                     (struct
   356                                                      SDL_PrivateAudioData)));
   357     if (this->hidden == NULL) {
   358         return SDL_OutOfMemory();
   359     }
   360     SDL_memset(this->hidden, 0, sizeof(struct SDL_PrivateAudioData));
   361 
   362     /* Initialize channel transfer parameters to default */
   363     QSA_InitAudioParams(&cparams);
   364 
   365     /* Initialize channel direction: capture or playback */
   366     this->hidden->iscapture = iscapture;
   367 
   368     /* Find deviceid and cardid by device name for playback */
   369     if ((!this->hidden->iscapture) && (devname != NULL)) {
   370         uint32_t device;
   371         int32_t status;
   372 
   373         /* Search in the playback devices */
   374         device = 0;
   375         do {
   376             status = SDL_strcmp(qsa_playback_device[device].name, devname);
   377             if (status == 0) {
   378                 /* Found requested device */
   379                 this->hidden->deviceno = qsa_playback_device[device].deviceno;
   380                 this->hidden->cardno = qsa_playback_device[device].cardno;
   381                 break;
   382             }
   383             device++;
   384             if (device >= qsa_playback_devices) {
   385                 QSA_CloseDevice(this);
   386                 return SDL_SetError("No such playback device");
   387             }
   388         } while (1);
   389     }
   390 
   391     /* Find deviceid and cardid by device name for capture */
   392     if ((this->hidden->iscapture) && (devname != NULL)) {
   393         /* Search in the capture devices */
   394         uint32_t device;
   395         int32_t status;
   396 
   397         /* Searching in the playback devices */
   398         device = 0;
   399         do {
   400             status = SDL_strcmp(qsa_capture_device[device].name, devname);
   401             if (status == 0) {
   402                 /* Found requested device */
   403                 this->hidden->deviceno = qsa_capture_device[device].deviceno;
   404                 this->hidden->cardno = qsa_capture_device[device].cardno;
   405                 break;
   406             }
   407             device++;
   408             if (device >= qsa_capture_devices) {
   409                 QSA_CloseDevice(this);
   410                 return SDL_SetError("No such capture device");
   411             }
   412         } while (1);
   413     }
   414 
   415     /* Check if SDL requested default audio device */
   416     if (devname == NULL) {
   417         /* Open system default audio device */
   418         if (!this->hidden->iscapture) {
   419             status = snd_pcm_open_preferred(&this->hidden->audio_handle,
   420                                             &this->hidden->cardno,
   421                                             &this->hidden->deviceno,
   422                                             SND_PCM_OPEN_PLAYBACK);
   423         } else {
   424             status = snd_pcm_open_preferred(&this->hidden->audio_handle,
   425                                             &this->hidden->cardno,
   426                                             &this->hidden->deviceno,
   427                                             SND_PCM_OPEN_CAPTURE);
   428         }
   429     } else {
   430         /* Open requested audio device */
   431         if (!this->hidden->iscapture) {
   432             status =
   433                 snd_pcm_open(&this->hidden->audio_handle,
   434                              this->hidden->cardno, this->hidden->deviceno,
   435                              SND_PCM_OPEN_PLAYBACK);
   436         } else {
   437             status =
   438                 snd_pcm_open(&this->hidden->audio_handle,
   439                              this->hidden->cardno, this->hidden->deviceno,
   440                              SND_PCM_OPEN_CAPTURE);
   441         }
   442     }
   443 
   444     /* Check if requested device is opened */
   445     if (status < 0) {
   446         this->hidden->audio_handle = NULL;
   447         QSA_CloseDevice(this);
   448         return QSA_SetError("snd_pcm_open", status);
   449     }
   450 
   451     if (!QSA_CheckBuggyCards(this, QSA_MMAP_WORKAROUND)) {
   452         /* Disable QSA MMAP plugin for buggy audio drivers */
   453         status =
   454             snd_pcm_plugin_set_disable(this->hidden->audio_handle,
   455                                        PLUGIN_DISABLE_MMAP);
   456         if (status < 0) {
   457             QSA_CloseDevice(this);
   458             return QSA_SetError("snd_pcm_plugin_set_disable", status);
   459         }
   460     }
   461 
   462     /* Try for a closest match on audio format */
   463     format = 0;
   464     /* can't use format as SND_PCM_SFMT_U8 = 0 in qsa */
   465     found = 0;
   466 
   467     for (test_format = SDL_FirstAudioFormat(this->spec.format); !found;) {
   468         /* if match found set format to equivalent QSA format */
   469         switch (test_format) {
   470         case AUDIO_U8:
   471             {
   472                 format = SND_PCM_SFMT_U8;
   473                 found = 1;
   474             }
   475             break;
   476         case AUDIO_S8:
   477             {
   478                 format = SND_PCM_SFMT_S8;
   479                 found = 1;
   480             }
   481             break;
   482         case AUDIO_S16LSB:
   483             {
   484                 format = SND_PCM_SFMT_S16_LE;
   485                 found = 1;
   486             }
   487             break;
   488         case AUDIO_S16MSB:
   489             {
   490                 format = SND_PCM_SFMT_S16_BE;
   491                 found = 1;
   492             }
   493             break;
   494         case AUDIO_U16LSB:
   495             {
   496                 format = SND_PCM_SFMT_U16_LE;
   497                 found = 1;
   498             }
   499             break;
   500         case AUDIO_U16MSB:
   501             {
   502                 format = SND_PCM_SFMT_U16_BE;
   503                 found = 1;
   504             }
   505             break;
   506         case AUDIO_S32LSB:
   507             {
   508                 format = SND_PCM_SFMT_S32_LE;
   509                 found = 1;
   510             }
   511             break;
   512         case AUDIO_S32MSB:
   513             {
   514                 format = SND_PCM_SFMT_S32_BE;
   515                 found = 1;
   516             }
   517             break;
   518         case AUDIO_F32LSB:
   519             {
   520                 format = SND_PCM_SFMT_FLOAT_LE;
   521                 found = 1;
   522             }
   523             break;
   524         case AUDIO_F32MSB:
   525             {
   526                 format = SND_PCM_SFMT_FLOAT_BE;
   527                 found = 1;
   528             }
   529             break;
   530         default:
   531             {
   532                 break;
   533             }
   534         }
   535 
   536         if (!found) {
   537             test_format = SDL_NextAudioFormat();
   538         }
   539     }
   540 
   541     /* assumes test_format not 0 on success */
   542     if (test_format == 0) {
   543         QSA_CloseDevice(this);
   544         return SDL_SetError("QSA: Couldn't find any hardware audio formats");
   545     }
   546 
   547     this->spec.format = test_format;
   548 
   549     /* Set the audio format */
   550     cparams.format.format = format;
   551 
   552     /* Set mono/stereo/4ch/6ch/8ch audio */
   553     cparams.format.voices = this->spec.channels;
   554 
   555     /* Set rate */
   556     cparams.format.rate = this->spec.freq;
   557 
   558     /* Setup the transfer parameters according to cparams */
   559     status = snd_pcm_plugin_params(this->hidden->audio_handle, &cparams);
   560     if (status < 0) {
   561         QSA_CloseDevice(this);
   562         return QSA_SetError("snd_pcm_channel_params", status);
   563     }
   564 
   565     /* Make sure channel is setup right one last time */
   566     SDL_memset(&csetup, 0, sizeof(csetup));
   567     if (!this->hidden->iscapture) {
   568         csetup.channel = SND_PCM_CHANNEL_PLAYBACK;
   569     } else {
   570         csetup.channel = SND_PCM_CHANNEL_CAPTURE;
   571     }
   572 
   573     /* Setup an audio channel */
   574     if (snd_pcm_plugin_setup(this->hidden->audio_handle, &csetup) < 0) {
   575         QSA_CloseDevice(this);
   576         return SDL_SetError("QSA: Unable to setup channel");
   577     }
   578 
   579     /* Calculate the final parameters for this audio specification */
   580     SDL_CalculateAudioSpec(&this->spec);
   581 
   582     this->hidden->pcm_len = this->spec.size;
   583 
   584     if (this->hidden->pcm_len == 0) {
   585         this->hidden->pcm_len =
   586             csetup.buf.block.frag_size * this->spec.channels *
   587             (snd_pcm_format_width(format) / 8);
   588     }
   589 
   590     /*
   591      * Allocate memory to the audio buffer and initialize with silence
   592      *  (Note that buffer size must be a multiple of fragment size, so find
   593      *  closest multiple)
   594      */
   595     this->hidden->pcm_buf =
   596         (Uint8 *) SDL_AllocAudioMem(this->hidden->pcm_len);
   597     if (this->hidden->pcm_buf == NULL) {
   598         QSA_CloseDevice(this);
   599         return SDL_OutOfMemory();
   600     }
   601     SDL_memset(this->hidden->pcm_buf, this->spec.silence,
   602                this->hidden->pcm_len);
   603 
   604     /* get the file descriptor */
   605     if (!this->hidden->iscapture) {
   606         this->hidden->audio_fd =
   607             snd_pcm_file_descriptor(this->hidden->audio_handle,
   608                                     SND_PCM_CHANNEL_PLAYBACK);
   609     } else {
   610         this->hidden->audio_fd =
   611             snd_pcm_file_descriptor(this->hidden->audio_handle,
   612                                     SND_PCM_CHANNEL_CAPTURE);
   613     }
   614 
   615     if (this->hidden->audio_fd < 0) {
   616         QSA_CloseDevice(this);
   617         return QSA_SetError("snd_pcm_file_descriptor", status);
   618     }
   619 
   620     /* Prepare an audio channel */
   621     if (!this->hidden->iscapture) {
   622         /* Prepare audio playback */
   623         status =
   624             snd_pcm_plugin_prepare(this->hidden->audio_handle,
   625                                    SND_PCM_CHANNEL_PLAYBACK);
   626     } else {
   627         /* Prepare audio capture */
   628         status =
   629             snd_pcm_plugin_prepare(this->hidden->audio_handle,
   630                                    SND_PCM_CHANNEL_CAPTURE);
   631     }
   632 
   633     if (status < 0) {
   634         QSA_CloseDevice(this);
   635         return QSA_SetError("snd_pcm_plugin_prepare", status);
   636     }
   637 
   638     /* We're really ready to rock and roll. :-) */
   639     return 0;
   640 }
   641 
   642 static void
   643 QSA_DetectDevices(int iscapture, SDL_AddAudioDevice addfn)
   644 {
   645     uint32_t it;
   646     uint32_t cards;
   647     uint32_t devices;
   648     int32_t status;
   649 
   650     /* Detect amount of available devices       */
   651     /* this value can be changed in the runtime */
   652     cards = snd_cards();
   653 
   654     /* If io-audio manager is not running we will get 0 as number */
   655     /* of available audio devices                                 */
   656     if (cards == 0) {
   657         /* We have no any available audio devices */
   658         return;
   659     }
   660 
   661     /* Find requested devices by type */
   662     if (!iscapture) {
   663         /* Playback devices enumeration requested */
   664         for (it = 0; it < cards; it++) {
   665             devices = 0;
   666             do {
   667                 status =
   668                     snd_card_get_longname(it,
   669                                           qsa_playback_device
   670                                           [qsa_playback_devices].name,
   671                                           QSA_MAX_NAME_LENGTH);
   672                 if (status == EOK) {
   673                     snd_pcm_t *handle;
   674 
   675                     /* Add device number to device name */
   676                     sprintf(qsa_playback_device[qsa_playback_devices].name +
   677                             SDL_strlen(qsa_playback_device
   678                                        [qsa_playback_devices].name), " d%d",
   679                             devices);
   680 
   681                     /* Store associated card number id */
   682                     qsa_playback_device[qsa_playback_devices].cardno = it;
   683 
   684                     /* Check if this device id could play anything */
   685                     status =
   686                         snd_pcm_open(&handle, it, devices,
   687                                      SND_PCM_OPEN_PLAYBACK);
   688                     if (status == EOK) {
   689                         qsa_playback_device[qsa_playback_devices].deviceno =
   690                             devices;
   691                         status = snd_pcm_close(handle);
   692                         if (status == EOK) {
   693                             addfn(qsa_playback_device[qsa_playback_devices].name);
   694                             qsa_playback_devices++;
   695                         }
   696                     } else {
   697                         /* Check if we got end of devices list */
   698                         if (status == -ENOENT) {
   699                             break;
   700                         }
   701                     }
   702                 } else {
   703                     break;
   704                 }
   705 
   706                 /* Check if we reached maximum devices count */
   707                 if (qsa_playback_devices >= QSA_MAX_DEVICES) {
   708                     break;
   709                 }
   710                 devices++;
   711             } while (1);
   712 
   713             /* Check if we reached maximum devices count */
   714             if (qsa_playback_devices >= QSA_MAX_DEVICES) {
   715                 break;
   716             }
   717         }
   718     } else {
   719         /* Capture devices enumeration requested */
   720         for (it = 0; it < cards; it++) {
   721             devices = 0;
   722             do {
   723                 status =
   724                     snd_card_get_longname(it,
   725                                           qsa_capture_device
   726                                           [qsa_capture_devices].name,
   727                                           QSA_MAX_NAME_LENGTH);
   728                 if (status == EOK) {
   729                     snd_pcm_t *handle;
   730 
   731                     /* Add device number to device name */
   732                     sprintf(qsa_capture_device[qsa_capture_devices].name +
   733                             SDL_strlen(qsa_capture_device
   734                                        [qsa_capture_devices].name), " d%d",
   735                             devices);
   736 
   737                     /* Store associated card number id */
   738                     qsa_capture_device[qsa_capture_devices].cardno = it;
   739 
   740                     /* Check if this device id could play anything */
   741                     status =
   742                         snd_pcm_open(&handle, it, devices,
   743                                      SND_PCM_OPEN_CAPTURE);
   744                     if (status == EOK) {
   745                         qsa_capture_device[qsa_capture_devices].deviceno =
   746                             devices;
   747                         status = snd_pcm_close(handle);
   748                         if (status == EOK) {
   749                             addfn(qsa_capture_device[qsa_capture_devices].name);
   750                             qsa_capture_devices++;
   751                         }
   752                     } else {
   753                         /* Check if we got end of devices list */
   754                         if (status == -ENOENT) {
   755                             break;
   756                         }
   757                     }
   758 
   759                     /* Check if we reached maximum devices count */
   760                     if (qsa_capture_devices >= QSA_MAX_DEVICES) {
   761                         break;
   762                     }
   763                 } else {
   764                     break;
   765                 }
   766                 devices++;
   767             } while (1);
   768 
   769             /* Check if we reached maximum devices count */
   770             if (qsa_capture_devices >= QSA_MAX_DEVICES) {
   771                 break;
   772             }
   773         }
   774     }
   775 }
   776 
   777 static void
   778 QSA_WaitDone(_THIS)
   779 {
   780     if (!this->hidden->iscapture) {
   781         if (this->hidden->audio_handle != NULL) {
   782             /* Wait till last fragment is played and stop channel */
   783             snd_pcm_plugin_flush(this->hidden->audio_handle,
   784                                  SND_PCM_CHANNEL_PLAYBACK);
   785         }
   786     } else {
   787         if (this->hidden->audio_handle != NULL) {
   788             /* Discard all unread data and stop channel */
   789             snd_pcm_plugin_flush(this->hidden->audio_handle,
   790                                  SND_PCM_CHANNEL_CAPTURE);
   791         }
   792     }
   793 }
   794 
   795 static void
   796 QSA_Deinitialize(void)
   797 {
   798     /* Clear devices array on shutdown */
   799     SDL_memset(qsa_playback_device, 0x00,
   800                sizeof(QSA_Device) * QSA_MAX_DEVICES);
   801     SDL_memset(qsa_capture_device, 0x00,
   802                sizeof(QSA_Device) * QSA_MAX_DEVICES);
   803     qsa_playback_devices = 0;
   804     qsa_capture_devices = 0;
   805 }
   806 
   807 static int
   808 QSA_Init(SDL_AudioDriverImpl * impl)
   809 {
   810     snd_pcm_t *handle = NULL;
   811     int32_t status = 0;
   812 
   813     /* Clear devices array */
   814     SDL_memset(qsa_playback_device, 0x00,
   815                sizeof(QSA_Device) * QSA_MAX_DEVICES);
   816     SDL_memset(qsa_capture_device, 0x00,
   817                sizeof(QSA_Device) * QSA_MAX_DEVICES);
   818     qsa_playback_devices = 0;
   819     qsa_capture_devices = 0;
   820 
   821     /* Set function pointers                                     */
   822     /* DeviceLock and DeviceUnlock functions are used default,   */
   823     /* provided by SDL, which uses pthread_mutex for lock/unlock */
   824     impl->DetectDevices = QSA_DetectDevices;
   825     impl->OpenDevice = QSA_OpenDevice;
   826     impl->ThreadInit = QSA_ThreadInit;
   827     impl->WaitDevice = QSA_WaitDevice;
   828     impl->PlayDevice = QSA_PlayDevice;
   829     impl->GetDeviceBuf = QSA_GetDeviceBuf;
   830     impl->CloseDevice = QSA_CloseDevice;
   831     impl->WaitDone = QSA_WaitDone;
   832     impl->Deinitialize = QSA_Deinitialize;
   833     impl->LockDevice = NULL;
   834     impl->UnlockDevice = NULL;
   835 
   836     impl->OnlyHasDefaultOutputDevice = 0;
   837     impl->ProvidesOwnCallbackThread = 0;
   838     impl->SkipMixerLock = 0;
   839     impl->HasCaptureSupport = 1;
   840     impl->OnlyHasDefaultOutputDevice = 0;
   841     impl->OnlyHasDefaultInputDevice = 0;
   842 
   843     /* Check if io-audio manager is running or not */
   844     status = snd_cards();
   845     if (status == 0) {
   846         /* if no, return immediately */
   847         return 1;
   848     }
   849 
   850     return 1;   /* this audio target is available. */
   851 }
   852 
   853 AudioBootStrap QSAAUDIO_bootstrap = {
   854     "qsa", "QNX QSA Audio", QSA_Init, 0
   855 };
   856 
   857 #endif /* SDL_AUDIO_DRIVER_QSA */
   858 
   859 /* vi: set ts=4 sw=4 expandtab: */