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