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