src/audio/alsa/SDL_alsa_audio.c
author Sam Lantinga <slouken@libsdl.org>
Mon, 29 May 2006 04:04:35 +0000
branchSDL-1.3
changeset 1668 4da1ee79c9af
parent 1664 cd3db072ba8a
child 1702 a7ad7081b977
permissions -rw-r--r--
more tweaking indent options
     1 /*
     2     SDL - Simple DirectMedia Layer
     3     Copyright (C) 1997-2004 Sam Lantinga
     4 
     5     This library is free software; you can redistribute it and/or
     6     modify it under the terms of the GNU Library General Public
     7     License as published by the Free Software Foundation; either
     8     version 2 of the License, or (at your option) any later version.
     9 
    10     This library is distributed in the hope that it will be useful,
    11     but WITHOUT ANY WARRANTY; without even the implied warranty of
    12     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
    13     Library General Public License for more details.
    14 
    15     You should have received a copy of the GNU Library General Public
    16     License along with this library; if not, write to the Free
    17     Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
    18 
    19     Sam Lantinga
    20     slouken@libsdl.org
    21 */
    22 #include "SDL_config.h"
    23 
    24 /* Allow access to a raw mixing buffer */
    25 
    26 #include <sys/types.h>
    27 #include <signal.h>             /* For kill() */
    28 
    29 #include "SDL_timer.h"
    30 #include "SDL_audio.h"
    31 #include "../SDL_audiomem.h"
    32 #include "../SDL_audio_c.h"
    33 #include "SDL_alsa_audio.h"
    34 
    35 #ifdef SDL_AUDIO_DRIVER_ALSA_DYNAMIC
    36 #include <dlfcn.h>
    37 #include "SDL_name.h"
    38 #include "SDL_loadso.h"
    39 #else
    40 #define SDL_NAME(X)	X
    41 #endif
    42 
    43 
    44 /* The tag name used by ALSA audio */
    45 #define DRIVER_NAME         "alsa"
    46 
    47 /* The default ALSA audio driver */
    48 #define DEFAULT_DEVICE	"default"
    49 
    50 /* Audio driver functions */
    51 static int ALSA_OpenAudio(_THIS, SDL_AudioSpec * spec);
    52 static void ALSA_WaitAudio(_THIS);
    53 static void ALSA_PlayAudio(_THIS);
    54 static Uint8 *ALSA_GetAudioBuf(_THIS);
    55 static void ALSA_CloseAudio(_THIS);
    56 
    57 #ifdef SDL_AUDIO_DRIVER_ALSA_DYNAMIC
    58 
    59 static const char *alsa_library = SDL_AUDIO_DRIVER_ALSA_DYNAMIC;
    60 static void *alsa_handle = NULL;
    61 static int alsa_loaded = 0;
    62 
    63 static int (*SDL_snd_pcm_open) (snd_pcm_t ** pcm, const char *name,
    64                                 snd_pcm_stream_t stream, int mode);
    65 static int (*SDL_NAME(snd_pcm_open)) (snd_pcm_t ** pcm, const char *name,
    66                                       snd_pcm_stream_t stream, int mode);
    67 static int (*SDL_NAME(snd_pcm_close)) (snd_pcm_t * pcm);
    68 static snd_pcm_sframes_t(*SDL_NAME(snd_pcm_writei)) (snd_pcm_t * pcm,
    69                                                      const void *buffer,
    70                                                      snd_pcm_uframes_t size);
    71 static int (*SDL_NAME(snd_pcm_resume)) (snd_pcm_t * pcm);
    72 static int (*SDL_NAME(snd_pcm_prepare)) (snd_pcm_t * pcm);
    73 static int (*SDL_NAME(snd_pcm_drain)) (snd_pcm_t * pcm);
    74 static const char *(*SDL_NAME(snd_strerror)) (int errnum);
    75 static size_t(*SDL_NAME(snd_pcm_hw_params_sizeof)) (void);
    76 static size_t(*SDL_NAME(snd_pcm_sw_params_sizeof)) (void);
    77 static int (*SDL_NAME(snd_pcm_hw_params_any)) (snd_pcm_t * pcm,
    78                                                snd_pcm_hw_params_t * params);
    79 static int (*SDL_NAME(snd_pcm_hw_params_set_access)) (snd_pcm_t * pcm,
    80                                                       snd_pcm_hw_params_t *
    81                                                       params,
    82                                                       snd_pcm_access_t
    83                                                       access);
    84 static int (*SDL_NAME(snd_pcm_hw_params_set_format)) (snd_pcm_t * pcm,
    85                                                       snd_pcm_hw_params_t *
    86                                                       params,
    87                                                       snd_pcm_format_t val);
    88 static int (*SDL_NAME(snd_pcm_hw_params_set_channels)) (snd_pcm_t * pcm,
    89                                                         snd_pcm_hw_params_t *
    90                                                         params,
    91                                                         unsigned int val);
    92 static int (*SDL_NAME(snd_pcm_hw_params_get_channels)) (const
    93                                                         snd_pcm_hw_params_t *
    94                                                         params);
    95 static unsigned int
    96     (*SDL_NAME(snd_pcm_hw_params_set_rate_near)) (snd_pcm_t *
    97                                                   pcm,
    98                                                   snd_pcm_hw_params_t
    99                                                   * params,
   100                                                   unsigned int val, int *dir);
   101 static snd_pcm_uframes_t
   102     (*SDL_NAME(snd_pcm_hw_params_set_period_size_near)) (snd_pcm_t * pcm,
   103                                                          snd_pcm_hw_params_t
   104                                                          * params,
   105                                                          snd_pcm_uframes_t
   106                                                          val, int *dir);
   107 static snd_pcm_sframes_t
   108     (*SDL_NAME(snd_pcm_hw_params_get_period_size)) (const
   109                                                     snd_pcm_hw_params_t
   110                                                     * params);
   111 static unsigned int
   112     (*SDL_NAME(snd_pcm_hw_params_set_periods_near)) (snd_pcm_t * pcm,
   113                                                      snd_pcm_hw_params_t
   114                                                      * params,
   115                                                      unsigned int val,
   116                                                      int *dir);
   117 static int (*SDL_NAME(snd_pcm_hw_params_get_periods)) (snd_pcm_hw_params_t *
   118                                                        params);
   119 static int (*SDL_NAME(snd_pcm_hw_params)) (snd_pcm_t * pcm,
   120                                            snd_pcm_hw_params_t * params);
   121 /*
   122 */
   123 static int (*SDL_NAME(snd_pcm_sw_params_current)) (snd_pcm_t * pcm,
   124                                                    snd_pcm_sw_params_t *
   125                                                    swparams);
   126 static int (*SDL_NAME(snd_pcm_sw_params_set_start_threshold)) (snd_pcm_t *
   127                                                                pcm,
   128                                                                snd_pcm_sw_params_t
   129                                                                * params,
   130                                                                snd_pcm_uframes_t
   131                                                                val);
   132 static int (*SDL_NAME(snd_pcm_sw_params_set_avail_min)) (snd_pcm_t * pcm,
   133                                                          snd_pcm_sw_params_t
   134                                                          * params,
   135                                                          snd_pcm_uframes_t
   136                                                          val);
   137 static int (*SDL_NAME(snd_pcm_sw_params)) (snd_pcm_t * pcm,
   138                                            snd_pcm_sw_params_t * params);
   139 static int (*SDL_NAME(snd_pcm_nonblock)) (snd_pcm_t * pcm, int nonblock);
   140 #define snd_pcm_hw_params_sizeof SDL_NAME(snd_pcm_hw_params_sizeof)
   141 #define snd_pcm_sw_params_sizeof SDL_NAME(snd_pcm_sw_params_sizeof)
   142 
   143 /* cast funcs to char* first, to please GCC's strict aliasing rules. */
   144 static struct
   145 {
   146     const char *name;
   147     void **func;
   148 } alsa_functions[] = {
   149     {
   150     "snd_pcm_open", (void **) (char *) &SDL_NAME(snd_pcm_open)}, {
   151     "snd_pcm_close", (void **) (char *) &SDL_NAME(snd_pcm_close)}, {
   152     "snd_pcm_writei", (void **) (char *) &SDL_NAME(snd_pcm_writei)}, {
   153     "snd_pcm_resume", (void **) (char *) &SDL_NAME(snd_pcm_resume)}, {
   154     "snd_pcm_prepare", (void **) (char *) &SDL_NAME(snd_pcm_prepare)}, {
   155     "snd_pcm_drain", (void **) (char *) &SDL_NAME(snd_pcm_drain)}, {
   156     "snd_strerror", (void **) (char *) &SDL_NAME(snd_strerror)}, {
   157     "snd_pcm_hw_params_sizeof",
   158             (void **) (char *) &SDL_NAME(snd_pcm_hw_params_sizeof)}, {
   159     "snd_pcm_sw_params_sizeof",
   160             (void **) (char *) &SDL_NAME(snd_pcm_sw_params_sizeof)}, {
   161     "snd_pcm_hw_params_any",
   162             (void **) (char *) &SDL_NAME(snd_pcm_hw_params_any)}, {
   163     "snd_pcm_hw_params_set_access",
   164             (void **) (char *) &SDL_NAME(snd_pcm_hw_params_set_access)}, {
   165     "snd_pcm_hw_params_set_format",
   166             (void **) (char *) &SDL_NAME(snd_pcm_hw_params_set_format)}, {
   167     "snd_pcm_hw_params_set_channels",
   168             (void **) (char *) &SDL_NAME(snd_pcm_hw_params_set_channels)}, {
   169     "snd_pcm_hw_params_get_channels",
   170             (void **) (char *) &SDL_NAME(snd_pcm_hw_params_get_channels)}, {
   171     "snd_pcm_hw_params_set_rate_near",
   172             (void **) (char *) &SDL_NAME(snd_pcm_hw_params_set_rate_near)}, {
   173         "snd_pcm_hw_params_set_period_size_near", (void **) (char *)
   174     &SDL_NAME(snd_pcm_hw_params_set_period_size_near)}, {
   175     "snd_pcm_hw_params_get_period_size",
   176             (void **) (char *) &SDL_NAME(snd_pcm_hw_params_get_period_size)},
   177     {
   178         "snd_pcm_hw_params_set_periods_near", (void **) (char *)
   179     &SDL_NAME(snd_pcm_hw_params_set_periods_near)}, {
   180     "snd_pcm_hw_params_get_periods",
   181             (void **) (char *) &SDL_NAME(snd_pcm_hw_params_get_periods)}, {
   182     "snd_pcm_hw_params", (void **) (char *) &SDL_NAME(snd_pcm_hw_params)}, {
   183     "snd_pcm_sw_params_current",
   184             (void **) (char *) &SDL_NAME(snd_pcm_sw_params_current)}, {
   185         "snd_pcm_sw_params_set_start_threshold", (void **) (char *)
   186     &SDL_NAME(snd_pcm_sw_params_set_start_threshold)}, {
   187     "snd_pcm_sw_params_set_avail_min",
   188             (void **) (char *) &SDL_NAME(snd_pcm_sw_params_set_avail_min)}, {
   189     "snd_pcm_sw_params", (void **) (char *) &SDL_NAME(snd_pcm_sw_params)}, {
   190 "snd_pcm_nonblock", (void **) (char *) &SDL_NAME(snd_pcm_nonblock)},};
   191 
   192 static void
   193 UnloadALSALibrary(void)
   194 {
   195     if (alsa_loaded) {
   196 /*		SDL_UnloadObject(alsa_handle);*/
   197         dlclose(alsa_handle);
   198         alsa_handle = NULL;
   199         alsa_loaded = 0;
   200     }
   201 }
   202 
   203 static int
   204 LoadALSALibrary(void)
   205 {
   206     int i, retval = -1;
   207 
   208 /*	alsa_handle = SDL_LoadObject(alsa_library);*/
   209     alsa_handle = dlopen(alsa_library, RTLD_NOW);
   210     if (alsa_handle) {
   211         alsa_loaded = 1;
   212         retval = 0;
   213         for (i = 0; i < SDL_arraysize(alsa_functions); i++) {
   214 /*			*alsa_functions[i].func = SDL_LoadFunction(alsa_handle,alsa_functions[i].name);*/
   215 #if HAVE_DLVSYM
   216             *alsa_functions[i].func =
   217                 dlvsym(alsa_handle, alsa_functions[i].name, "ALSA_0.9");
   218             if (!*alsa_functions[i].func)
   219 #endif
   220                 *alsa_functions[i].func =
   221                     dlsym(alsa_handle, alsa_functions[i].name);
   222             if (!*alsa_functions[i].func) {
   223                 retval = -1;
   224                 UnloadALSALibrary();
   225                 break;
   226             }
   227         }
   228     }
   229     return retval;
   230 }
   231 
   232 #else
   233 
   234 static void
   235 UnloadALSALibrary(void)
   236 {
   237     return;
   238 }
   239 
   240 static int
   241 LoadALSALibrary(void)
   242 {
   243     return 0;
   244 }
   245 
   246 #endif /* SDL_AUDIO_DRIVER_ALSA_DYNAMIC */
   247 
   248 static const char *
   249 get_audio_device(int channels)
   250 {
   251     const char *device;
   252 
   253     device = SDL_getenv("AUDIODEV");    /* Is there a standard variable name? */
   254     if (device == NULL) {
   255         if (channels == 6)
   256             device = "surround51";
   257         else if (channels == 4)
   258             device = "surround40";
   259         else
   260             device = DEFAULT_DEVICE;
   261     }
   262     return device;
   263 }
   264 
   265 /* Audio driver bootstrap functions */
   266 
   267 static int
   268 Audio_Available(void)
   269 {
   270     int available;
   271     int status;
   272     snd_pcm_t *handle;
   273 
   274     available = 0;
   275     if (LoadALSALibrary() < 0) {
   276         return available;
   277     }
   278     status =
   279         SDL_NAME(snd_pcm_open) (&handle, get_audio_device(2),
   280                                 SND_PCM_STREAM_PLAYBACK, SND_PCM_NONBLOCK);
   281     if (status >= 0) {
   282         available = 1;
   283         SDL_NAME(snd_pcm_close) (handle);
   284     }
   285     UnloadALSALibrary();
   286     return (available);
   287 }
   288 
   289 static void
   290 Audio_DeleteDevice(SDL_AudioDevice * device)
   291 {
   292     SDL_free(device->hidden);
   293     SDL_free(device);
   294     UnloadALSALibrary();
   295 }
   296 
   297 static SDL_AudioDevice *
   298 Audio_CreateDevice(int devindex)
   299 {
   300     SDL_AudioDevice *this;
   301 
   302     /* Initialize all variables that we clean on shutdown */
   303     LoadALSALibrary();
   304     this = (SDL_AudioDevice *) SDL_malloc(sizeof(SDL_AudioDevice));
   305     if (this) {
   306         SDL_memset(this, 0, (sizeof *this));
   307         this->hidden = (struct SDL_PrivateAudioData *)
   308             SDL_malloc((sizeof *this->hidden));
   309     }
   310     if ((this == NULL) || (this->hidden == NULL)) {
   311         SDL_OutOfMemory();
   312         if (this) {
   313             SDL_free(this);
   314         }
   315         return (0);
   316     }
   317     SDL_memset(this->hidden, 0, (sizeof *this->hidden));
   318 
   319     /* Set the function pointers */
   320     this->OpenAudio = ALSA_OpenAudio;
   321     this->WaitAudio = ALSA_WaitAudio;
   322     this->PlayAudio = ALSA_PlayAudio;
   323     this->GetAudioBuf = ALSA_GetAudioBuf;
   324     this->CloseAudio = ALSA_CloseAudio;
   325 
   326     this->free = Audio_DeleteDevice;
   327 
   328     return this;
   329 }
   330 
   331 AudioBootStrap ALSA_bootstrap = {
   332     DRIVER_NAME, "ALSA 0.9 PCM audio",
   333     Audio_Available, Audio_CreateDevice
   334 };
   335 
   336 /* This function waits until it is possible to write a full sound buffer */
   337 static void
   338 ALSA_WaitAudio(_THIS)
   339 {
   340     /* Check to see if the thread-parent process is still alive */
   341     {
   342         static int cnt = 0;
   343         /* Note that this only works with thread implementations 
   344            that use a different process id for each thread.
   345          */
   346         if (parent && (((++cnt) % 10) == 0)) {  /* Check every 10 loops */
   347             if (kill(parent, 0) < 0) {
   348                 this->enabled = 0;
   349             }
   350         }
   351     }
   352 }
   353 
   354 static void
   355 ALSA_PlayAudio(_THIS)
   356 {
   357     int status;
   358     int sample_len;
   359     signed short *sample_buf;
   360 
   361     sample_len = this->spec.samples;
   362     sample_buf = (signed short *) mixbuf;
   363     while (sample_len > 0) {
   364         status =
   365             SDL_NAME(snd_pcm_writei) (pcm_handle, sample_buf, sample_len);
   366         if (status < 0) {
   367             if (status == -EAGAIN) {
   368                 SDL_Delay(1);
   369                 continue;
   370             }
   371             if (status == -ESTRPIPE) {
   372                 do {
   373                     SDL_Delay(1);
   374                     status = SDL_NAME(snd_pcm_resume) (pcm_handle);
   375                 }
   376                 while (status == -EAGAIN);
   377             }
   378             if (status < 0) {
   379                 status = SDL_NAME(snd_pcm_prepare) (pcm_handle);
   380             }
   381             if (status < 0) {
   382                 /* Hmm, not much we can do - abort */
   383                 this->enabled = 0;
   384                 return;
   385             }
   386             continue;
   387         }
   388         sample_buf += status * this->spec.channels;
   389         sample_len -= status;
   390     }
   391 }
   392 
   393 static Uint8 *
   394 ALSA_GetAudioBuf(_THIS)
   395 {
   396     return (mixbuf);
   397 }
   398 
   399 static void
   400 ALSA_CloseAudio(_THIS)
   401 {
   402     if (mixbuf != NULL) {
   403         SDL_FreeAudioMem(mixbuf);
   404         mixbuf = NULL;
   405     }
   406     if (pcm_handle) {
   407         SDL_NAME(snd_pcm_drain) (pcm_handle);
   408         SDL_NAME(snd_pcm_close) (pcm_handle);
   409         pcm_handle = NULL;
   410     }
   411 }
   412 
   413 static int
   414 ALSA_OpenAudio(_THIS, SDL_AudioSpec * spec)
   415 {
   416     int status;
   417     snd_pcm_hw_params_t *hwparams;
   418     snd_pcm_sw_params_t *swparams;
   419     snd_pcm_format_t format;
   420     snd_pcm_uframes_t frames;
   421     Uint16 test_format;
   422 
   423     /* Open the audio device */
   424     /* Name of device should depend on # channels in spec */
   425     status =
   426         SDL_NAME(snd_pcm_open) (&pcm_handle,
   427                                 get_audio_device(spec->channels),
   428                                 SND_PCM_STREAM_PLAYBACK, SND_PCM_NONBLOCK);
   429 
   430     if (status < 0) {
   431         SDL_SetError("Couldn't open audio device: %s",
   432                      SDL_NAME(snd_strerror) (status));
   433         return (-1);
   434     }
   435 
   436     /* Figure out what the hardware is capable of */
   437     snd_pcm_hw_params_alloca(&hwparams);
   438     status = SDL_NAME(snd_pcm_hw_params_any) (pcm_handle, hwparams);
   439     if (status < 0) {
   440         SDL_SetError("Couldn't get hardware config: %s",
   441                      SDL_NAME(snd_strerror) (status));
   442         ALSA_CloseAudio(this);
   443         return (-1);
   444     }
   445 
   446     /* SDL only uses interleaved sample output */
   447     status =
   448         SDL_NAME(snd_pcm_hw_params_set_access) (pcm_handle, hwparams,
   449                                                 SND_PCM_ACCESS_RW_INTERLEAVED);
   450     if (status < 0) {
   451         SDL_SetError("Couldn't set interleaved access: %s",
   452                      SDL_NAME(snd_strerror) (status));
   453         ALSA_CloseAudio(this);
   454         return (-1);
   455     }
   456 
   457     /* Try for a closest match on audio format */
   458     status = -1;
   459     for (test_format = SDL_FirstAudioFormat(spec->format);
   460          test_format && (status < 0);) {
   461         switch (test_format) {
   462         case AUDIO_U8:
   463             format = SND_PCM_FORMAT_U8;
   464             break;
   465         case AUDIO_S8:
   466             format = SND_PCM_FORMAT_S8;
   467             break;
   468         case AUDIO_S16LSB:
   469             format = SND_PCM_FORMAT_S16_LE;
   470             break;
   471         case AUDIO_S16MSB:
   472             format = SND_PCM_FORMAT_S16_BE;
   473             break;
   474         case AUDIO_U16LSB:
   475             format = SND_PCM_FORMAT_U16_LE;
   476             break;
   477         case AUDIO_U16MSB:
   478             format = SND_PCM_FORMAT_U16_BE;
   479             break;
   480         default:
   481             format = 0;
   482             break;
   483         }
   484         if (format != 0) {
   485             status =
   486                 SDL_NAME(snd_pcm_hw_params_set_format) (pcm_handle,
   487                                                         hwparams, format);
   488         }
   489         if (status < 0) {
   490             test_format = SDL_NextAudioFormat();
   491         }
   492     }
   493     if (status < 0) {
   494         SDL_SetError("Couldn't find any hardware audio formats");
   495         ALSA_CloseAudio(this);
   496         return (-1);
   497     }
   498     spec->format = test_format;
   499 
   500     /* Set the number of channels */
   501     status =
   502         SDL_NAME(snd_pcm_hw_params_set_channels) (pcm_handle, hwparams,
   503                                                   spec->channels);
   504     if (status < 0) {
   505         status = SDL_NAME(snd_pcm_hw_params_get_channels) (hwparams);
   506         if ((status <= 0) || (status > 2)) {
   507             SDL_SetError("Couldn't set audio channels");
   508             ALSA_CloseAudio(this);
   509             return (-1);
   510         }
   511         spec->channels = status;
   512     }
   513 
   514     /* Set the audio rate */
   515     status =
   516         SDL_NAME(snd_pcm_hw_params_set_rate_near) (pcm_handle, hwparams,
   517                                                    spec->freq, NULL);
   518     if (status < 0) {
   519         SDL_SetError("Couldn't set audio frequency: %s",
   520                      SDL_NAME(snd_strerror) (status));
   521         ALSA_CloseAudio(this);
   522         return (-1);
   523     }
   524     spec->freq = status;
   525 
   526     /* Set the buffer size, in samples */
   527     frames = spec->samples;
   528     frames =
   529         SDL_NAME(snd_pcm_hw_params_set_period_size_near) (pcm_handle,
   530                                                           hwparams, frames,
   531                                                           NULL);
   532     spec->samples = frames;
   533     SDL_NAME(snd_pcm_hw_params_set_periods_near) (pcm_handle, hwparams, 2,
   534                                                   NULL);
   535 
   536     /* "set" the hardware with the desired parameters */
   537     status = SDL_NAME(snd_pcm_hw_params) (pcm_handle, hwparams);
   538     if (status < 0) {
   539         SDL_SetError("Couldn't set hardware audio parameters: %s",
   540                      SDL_NAME(snd_strerror) (status));
   541         ALSA_CloseAudio(this);
   542         return (-1);
   543     }
   544 
   545 /* This is useful for debugging... */
   546 /*
   547 { snd_pcm_sframes_t bufsize; int fragments;
   548    bufsize = SDL_NAME(snd_pcm_hw_params_get_period_size)(hwparams);
   549    fragments = SDL_NAME(snd_pcm_hw_params_get_periods)(hwparams);
   550 
   551    fprintf(stderr, "ALSA: bufsize = %ld, fragments = %d\n", bufsize, fragments);
   552 }
   553 */
   554 
   555     /* Set the software parameters */
   556     snd_pcm_sw_params_alloca(&swparams);
   557     status = SDL_NAME(snd_pcm_sw_params_current) (pcm_handle, swparams);
   558     if (status < 0) {
   559         SDL_SetError("Couldn't get software config: %s",
   560                      SDL_NAME(snd_strerror) (status));
   561         ALSA_CloseAudio(this);
   562         return (-1);
   563     }
   564     status =
   565         SDL_NAME(snd_pcm_sw_params_set_start_threshold) (pcm_handle,
   566                                                          swparams, 0);
   567     if (status < 0) {
   568         SDL_SetError("Couldn't set start threshold: %s",
   569                      SDL_NAME(snd_strerror) (status));
   570         ALSA_CloseAudio(this);
   571         return (-1);
   572     }
   573     status =
   574         SDL_NAME(snd_pcm_sw_params_set_avail_min) (pcm_handle, swparams,
   575                                                    frames);
   576     if (status < 0) {
   577         SDL_SetError("Couldn't set avail min: %s",
   578                      SDL_NAME(snd_strerror) (status));
   579         ALSA_CloseAudio(this);
   580         return (-1);
   581     }
   582     status = SDL_NAME(snd_pcm_sw_params) (pcm_handle, swparams);
   583     if (status < 0) {
   584         SDL_SetError("Couldn't set software audio parameters: %s",
   585                      SDL_NAME(snd_strerror) (status));
   586         ALSA_CloseAudio(this);
   587         return (-1);
   588     }
   589 
   590     /* Calculate the final parameters for this audio specification */
   591     SDL_CalculateAudioSpec(spec);
   592 
   593     /* Allocate mixing buffer */
   594     mixlen = spec->size;
   595     mixbuf = (Uint8 *) SDL_AllocAudioMem(mixlen);
   596     if (mixbuf == NULL) {
   597         ALSA_CloseAudio(this);
   598         return (-1);
   599     }
   600     SDL_memset(mixbuf, spec->silence, spec->size);
   601 
   602     /* Get the parent process id (we're the parent of the audio thread) */
   603     parent = getpid();
   604 
   605     /* Switch to blocking mode for playback */
   606     SDL_NAME(snd_pcm_nonblock) (pcm_handle, 0);
   607 
   608     /* We're ready to rock and roll. :-) */
   609     return (0);
   610 }
   611 
   612 /* vi: set ts=4 sw=4 expandtab: */