gearmulator

Emulation of classic VA synths of the late 90s/2000s that are based on Motorola 56300 family DSPs
Log | Files | Refs | Submodules | README | LICENSE

pa_linux_alsa.c (173649B)


      1 /*
      2  * $Id$
      3  * PortAudio Portable Real-Time Audio Library
      4  * Latest Version at: http://www.portaudio.com
      5  * ALSA implementation by Joshua Haberman and Arve Knudsen
      6  *
      7  * Copyright (c) 2002 Joshua Haberman <joshua@haberman.com>
      8  * Copyright (c) 2005-2009 Arve Knudsen <arve.knudsen@gmail.com>
      9  * Copyright (c) 2008 Kevin Kofler <kevin.kofler@chello.at>
     10  *
     11  * Based on the Open Source API proposed by Ross Bencina
     12  * Copyright (c) 1999-2002 Ross Bencina, Phil Burk
     13  *
     14  * Permission is hereby granted, free of charge, to any person obtaining
     15  * a copy of this software and associated documentation files
     16  * (the "Software"), to deal in the Software without restriction,
     17  * including without limitation the rights to use, copy, modify, merge,
     18  * publish, distribute, sublicense, and/or sell copies of the Software,
     19  * and to permit persons to whom the Software is furnished to do so,
     20  * subject to the following conditions:
     21  *
     22  * The above copyright notice and this permission notice shall be
     23  * included in all copies or substantial portions of the Software.
     24  *
     25  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
     26  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
     27  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
     28  * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
     29  * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
     30  * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
     31  * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
     32  */
     33 
     34 /*
     35  * The text above constitutes the entire PortAudio license; however,
     36  * the PortAudio community also makes the following non-binding requests:
     37  *
     38  * Any person wishing to distribute modifications to the Software is
     39  * requested to send the modifications to the original developer so that
     40  * they can be incorporated into the canonical version. It is also
     41  * requested that these non-binding requests be included along with the
     42  * license above.
     43  */
     44 
     45 /**
     46  @file
     47  @ingroup hostapi_src
     48 */
     49 
     50 #define ALSA_PCM_NEW_HW_PARAMS_API
     51 #define ALSA_PCM_NEW_SW_PARAMS_API
     52 #include <alsa/asoundlib.h>
     53 #undef ALSA_PCM_NEW_HW_PARAMS_API
     54 #undef ALSA_PCM_NEW_SW_PARAMS_API
     55 
     56 #include <sys/poll.h>
     57 #include <string.h> /* strlen() */
     58 #include <limits.h>
     59 #include <math.h>
     60 #include <pthread.h>
     61 #include <signal.h>
     62 #include <time.h>
     63 #include <sys/mman.h>
     64 #include <signal.h> /* For sig_atomic_t */
     65 #ifdef PA_ALSA_DYNAMIC
     66     #include <dlfcn.h> /* For dlXXX functions */
     67 #endif
     68 
     69 #include "portaudio.h"
     70 #include "pa_util.h"
     71 #include "pa_unix_util.h"
     72 #include "pa_allocation.h"
     73 #include "pa_hostapi.h"
     74 #include "pa_stream.h"
     75 #include "pa_cpuload.h"
     76 #include "pa_process.h"
     77 #include "pa_endianness.h"
     78 #include "pa_debugprint.h"
     79 
     80 #include "pa_linux_alsa.h"
     81 
     82 /* Add missing define (for compatibility with older ALSA versions) */
     83 #ifndef SND_PCM_TSTAMP_ENABLE
     84     #define SND_PCM_TSTAMP_ENABLE SND_PCM_TSTAMP_MMAP
     85 #endif
     86 
     87 /* Combine version elements into a single (unsigned) integer */
     88 #define ALSA_VERSION_INT(major, minor, subminor)  ((major << 16) | (minor << 8) | subminor)
     89 
     90 /* The acceptable tolerance of sample rate set, to that requested (as a ratio, eg 50 is 2%, 100 is 1%) */
     91 #define RATE_MAX_DEVIATE_RATIO 100
     92 
     93 /* Defines Alsa function types and pointers to these functions. */
     94 #define _PA_DEFINE_FUNC(x)  typedef typeof(x) x##_ft; static x##_ft *alsa_##x = 0
     95 
     96 /* Alloca helper. */
     97 #define __alsa_snd_alloca(ptr,type) do { size_t __alsa_alloca_size = alsa_##type##_sizeof(); (*ptr) = (type##_t *) alloca(__alsa_alloca_size); memset(*ptr, 0, __alsa_alloca_size); } while (0)
     98 
     99 _PA_DEFINE_FUNC(snd_pcm_open);
    100 _PA_DEFINE_FUNC(snd_pcm_close);
    101 _PA_DEFINE_FUNC(snd_pcm_nonblock);
    102 _PA_DEFINE_FUNC(snd_pcm_frames_to_bytes);
    103 _PA_DEFINE_FUNC(snd_pcm_prepare);
    104 _PA_DEFINE_FUNC(snd_pcm_start);
    105 _PA_DEFINE_FUNC(snd_pcm_resume);
    106 _PA_DEFINE_FUNC(snd_pcm_wait);
    107 _PA_DEFINE_FUNC(snd_pcm_state);
    108 _PA_DEFINE_FUNC(snd_pcm_avail_update);
    109 _PA_DEFINE_FUNC(snd_pcm_areas_silence);
    110 _PA_DEFINE_FUNC(snd_pcm_mmap_begin);
    111 _PA_DEFINE_FUNC(snd_pcm_mmap_commit);
    112 _PA_DEFINE_FUNC(snd_pcm_readi);
    113 _PA_DEFINE_FUNC(snd_pcm_readn);
    114 _PA_DEFINE_FUNC(snd_pcm_writei);
    115 _PA_DEFINE_FUNC(snd_pcm_writen);
    116 _PA_DEFINE_FUNC(snd_pcm_drain);
    117 _PA_DEFINE_FUNC(snd_pcm_recover);
    118 _PA_DEFINE_FUNC(snd_pcm_drop);
    119 _PA_DEFINE_FUNC(snd_pcm_area_copy);
    120 _PA_DEFINE_FUNC(snd_pcm_poll_descriptors);
    121 _PA_DEFINE_FUNC(snd_pcm_poll_descriptors_count);
    122 _PA_DEFINE_FUNC(snd_pcm_poll_descriptors_revents);
    123 _PA_DEFINE_FUNC(snd_pcm_format_size);
    124 _PA_DEFINE_FUNC(snd_pcm_link);
    125 _PA_DEFINE_FUNC(snd_pcm_delay);
    126 
    127 _PA_DEFINE_FUNC(snd_pcm_hw_params_sizeof);
    128 _PA_DEFINE_FUNC(snd_pcm_hw_params_malloc);
    129 _PA_DEFINE_FUNC(snd_pcm_hw_params_free);
    130 _PA_DEFINE_FUNC(snd_pcm_hw_params_any);
    131 _PA_DEFINE_FUNC(snd_pcm_hw_params_set_access);
    132 _PA_DEFINE_FUNC(snd_pcm_hw_params_set_format);
    133 _PA_DEFINE_FUNC(snd_pcm_hw_params_set_channels);
    134 //_PA_DEFINE_FUNC(snd_pcm_hw_params_set_periods_near);
    135 _PA_DEFINE_FUNC(snd_pcm_hw_params_set_rate_near); //!!!
    136 _PA_DEFINE_FUNC(snd_pcm_hw_params_set_rate);
    137 _PA_DEFINE_FUNC(snd_pcm_hw_params_set_rate_resample);
    138 //_PA_DEFINE_FUNC(snd_pcm_hw_params_set_buffer_time_near);
    139 _PA_DEFINE_FUNC(snd_pcm_hw_params_set_buffer_size);
    140 _PA_DEFINE_FUNC(snd_pcm_hw_params_set_buffer_size_near); //!!!
    141 _PA_DEFINE_FUNC(snd_pcm_hw_params_set_buffer_size_min);
    142 //_PA_DEFINE_FUNC(snd_pcm_hw_params_set_period_time_near);
    143 _PA_DEFINE_FUNC(snd_pcm_hw_params_set_period_size_near);
    144 _PA_DEFINE_FUNC(snd_pcm_hw_params_set_periods_integer);
    145 _PA_DEFINE_FUNC(snd_pcm_hw_params_set_periods_min);
    146 
    147 _PA_DEFINE_FUNC(snd_pcm_hw_params_get_buffer_size);
    148 //_PA_DEFINE_FUNC(snd_pcm_hw_params_get_period_size);
    149 //_PA_DEFINE_FUNC(snd_pcm_hw_params_get_access);
    150 //_PA_DEFINE_FUNC(snd_pcm_hw_params_get_periods);
    151 //_PA_DEFINE_FUNC(snd_pcm_hw_params_get_rate);
    152 _PA_DEFINE_FUNC(snd_pcm_hw_params_get_channels_min);
    153 _PA_DEFINE_FUNC(snd_pcm_hw_params_get_channels_max);
    154 
    155 _PA_DEFINE_FUNC(snd_pcm_hw_params_test_period_size);
    156 _PA_DEFINE_FUNC(snd_pcm_hw_params_test_format);
    157 _PA_DEFINE_FUNC(snd_pcm_hw_params_test_access);
    158 _PA_DEFINE_FUNC(snd_pcm_hw_params_dump);
    159 _PA_DEFINE_FUNC(snd_pcm_hw_params);
    160 
    161 _PA_DEFINE_FUNC(snd_pcm_hw_params_get_periods_min);
    162 _PA_DEFINE_FUNC(snd_pcm_hw_params_get_periods_max);
    163 _PA_DEFINE_FUNC(snd_pcm_hw_params_set_period_size);
    164 _PA_DEFINE_FUNC(snd_pcm_hw_params_get_period_size_min);
    165 _PA_DEFINE_FUNC(snd_pcm_hw_params_get_period_size_max);
    166 _PA_DEFINE_FUNC(snd_pcm_hw_params_get_buffer_size_max);
    167 _PA_DEFINE_FUNC(snd_pcm_hw_params_get_rate_min);
    168 _PA_DEFINE_FUNC(snd_pcm_hw_params_get_rate_max);
    169 _PA_DEFINE_FUNC(snd_pcm_hw_params_get_rate_numden);
    170 #define alsa_snd_pcm_hw_params_alloca(ptr) __alsa_snd_alloca(ptr, snd_pcm_hw_params)
    171 
    172 _PA_DEFINE_FUNC(snd_pcm_sw_params_sizeof);
    173 _PA_DEFINE_FUNC(snd_pcm_sw_params_malloc);
    174 _PA_DEFINE_FUNC(snd_pcm_sw_params_current);
    175 _PA_DEFINE_FUNC(snd_pcm_sw_params_set_avail_min);
    176 _PA_DEFINE_FUNC(snd_pcm_sw_params);
    177 _PA_DEFINE_FUNC(snd_pcm_sw_params_free);
    178 _PA_DEFINE_FUNC(snd_pcm_sw_params_set_start_threshold);
    179 _PA_DEFINE_FUNC(snd_pcm_sw_params_set_stop_threshold);
    180 _PA_DEFINE_FUNC(snd_pcm_sw_params_get_boundary);
    181 _PA_DEFINE_FUNC(snd_pcm_sw_params_set_silence_threshold);
    182 _PA_DEFINE_FUNC(snd_pcm_sw_params_set_silence_size);
    183 _PA_DEFINE_FUNC(snd_pcm_sw_params_set_xfer_align);
    184 _PA_DEFINE_FUNC(snd_pcm_sw_params_set_tstamp_mode);
    185 #define alsa_snd_pcm_sw_params_alloca(ptr) __alsa_snd_alloca(ptr, snd_pcm_sw_params)
    186 
    187 _PA_DEFINE_FUNC(snd_pcm_info);
    188 _PA_DEFINE_FUNC(snd_pcm_info_sizeof);
    189 _PA_DEFINE_FUNC(snd_pcm_info_malloc);
    190 _PA_DEFINE_FUNC(snd_pcm_info_free);
    191 _PA_DEFINE_FUNC(snd_pcm_info_set_device);
    192 _PA_DEFINE_FUNC(snd_pcm_info_set_subdevice);
    193 _PA_DEFINE_FUNC(snd_pcm_info_set_stream);
    194 _PA_DEFINE_FUNC(snd_pcm_info_get_name);
    195 _PA_DEFINE_FUNC(snd_pcm_info_get_card);
    196 #define alsa_snd_pcm_info_alloca(ptr) __alsa_snd_alloca(ptr, snd_pcm_info)
    197 
    198 _PA_DEFINE_FUNC(snd_ctl_pcm_next_device);
    199 _PA_DEFINE_FUNC(snd_ctl_pcm_info);
    200 _PA_DEFINE_FUNC(snd_ctl_open);
    201 _PA_DEFINE_FUNC(snd_ctl_close);
    202 _PA_DEFINE_FUNC(snd_ctl_card_info_malloc);
    203 _PA_DEFINE_FUNC(snd_ctl_card_info_free);
    204 _PA_DEFINE_FUNC(snd_ctl_card_info);
    205 _PA_DEFINE_FUNC(snd_ctl_card_info_sizeof);
    206 _PA_DEFINE_FUNC(snd_ctl_card_info_get_name);
    207 #define alsa_snd_ctl_card_info_alloca(ptr) __alsa_snd_alloca(ptr, snd_ctl_card_info)
    208 
    209 _PA_DEFINE_FUNC(snd_config);
    210 _PA_DEFINE_FUNC(snd_config_update);
    211 _PA_DEFINE_FUNC(snd_config_search);
    212 _PA_DEFINE_FUNC(snd_config_iterator_entry);
    213 _PA_DEFINE_FUNC(snd_config_iterator_first);
    214 _PA_DEFINE_FUNC(snd_config_iterator_end);
    215 _PA_DEFINE_FUNC(snd_config_iterator_next);
    216 _PA_DEFINE_FUNC(snd_config_get_string);
    217 _PA_DEFINE_FUNC(snd_config_get_id);
    218 _PA_DEFINE_FUNC(snd_config_update_free_global);
    219 
    220 _PA_DEFINE_FUNC(snd_pcm_status);
    221 _PA_DEFINE_FUNC(snd_pcm_status_sizeof);
    222 _PA_DEFINE_FUNC(snd_pcm_status_get_tstamp);
    223 _PA_DEFINE_FUNC(snd_pcm_status_get_state);
    224 _PA_DEFINE_FUNC(snd_pcm_status_get_trigger_tstamp);
    225 _PA_DEFINE_FUNC(snd_pcm_status_get_delay);
    226 #define alsa_snd_pcm_status_alloca(ptr) __alsa_snd_alloca(ptr, snd_pcm_status)
    227 
    228 _PA_DEFINE_FUNC(snd_card_next);
    229 _PA_DEFINE_FUNC(snd_asoundlib_version);
    230 _PA_DEFINE_FUNC(snd_strerror);
    231 _PA_DEFINE_FUNC(snd_output_stdio_attach);
    232 
    233 #define alsa_snd_config_for_each(pos, next, node)\
    234     for (pos = alsa_snd_config_iterator_first(node),\
    235          next = alsa_snd_config_iterator_next(pos);\
    236          pos != alsa_snd_config_iterator_end(node); pos = next, next = alsa_snd_config_iterator_next(pos))
    237 
    238 #undef _PA_DEFINE_FUNC
    239 
    240 /* Redefine 'PA_ALSA_PATHNAME' to a different Alsa library name if desired. */
    241 #ifndef PA_ALSA_PATHNAME
    242     #define PA_ALSA_PATHNAME "libasound.so"
    243 #endif
    244 static const char *g_AlsaLibName = PA_ALSA_PATHNAME;
    245 
    246 /* Handle to dynamically loaded library. */
    247 static void *g_AlsaLib = NULL;
    248 
    249 #ifdef PA_ALSA_DYNAMIC
    250 
    251 #define _PA_LOCAL_IMPL(x) __pa_local_##x
    252 
    253 int _PA_LOCAL_IMPL(snd_pcm_hw_params_set_rate_near) (snd_pcm_t *pcm, snd_pcm_hw_params_t *params, unsigned int *val, int *dir)
    254 {
    255     int ret;
    256 
    257     if(( ret = alsa_snd_pcm_hw_params_set_rate(pcm, params, (*val), (*dir)) ) < 0 )
    258         return ret;
    259 
    260     return 0;
    261 }
    262 
    263 int _PA_LOCAL_IMPL(snd_pcm_hw_params_set_buffer_size_near) (snd_pcm_t *pcm, snd_pcm_hw_params_t *params, snd_pcm_uframes_t *val)
    264 {
    265     int ret;
    266 
    267     if(( ret = alsa_snd_pcm_hw_params_set_buffer_size(pcm, params, (*val)) ) < 0 )
    268         return ret;
    269 
    270     return 0;
    271 }
    272 
    273 int _PA_LOCAL_IMPL(snd_pcm_hw_params_set_period_size_near) (snd_pcm_t *pcm, snd_pcm_hw_params_t *params, snd_pcm_uframes_t *val, int *dir)
    274 {
    275     int ret;
    276 
    277     if(( ret = alsa_snd_pcm_hw_params_set_period_size(pcm, params, (*val), (*dir)) ) < 0 )
    278         return ret;
    279 
    280     return 0;
    281 }
    282 
    283 int _PA_LOCAL_IMPL(snd_pcm_hw_params_get_channels_min) (const snd_pcm_hw_params_t *params, unsigned int *val)
    284 {
    285     (*val) = 1;
    286     return 0;
    287 }
    288 
    289 int _PA_LOCAL_IMPL(snd_pcm_hw_params_get_channels_max) (const snd_pcm_hw_params_t *params, unsigned int *val)
    290 {
    291     (*val) = 2;
    292     return 0;
    293 }
    294 
    295 int _PA_LOCAL_IMPL(snd_pcm_hw_params_get_periods_min) (const snd_pcm_hw_params_t *params, unsigned int *val, int *dir)
    296 {
    297     (*val) = 2;
    298     return 0;
    299 }
    300 
    301 int _PA_LOCAL_IMPL(snd_pcm_hw_params_get_periods_max) (const snd_pcm_hw_params_t *params, unsigned int *val, int *dir)
    302 {
    303     (*val) = 8;
    304     return 0;
    305 }
    306 
    307 int _PA_LOCAL_IMPL(snd_pcm_hw_params_get_period_size_min) (const snd_pcm_hw_params_t *params, snd_pcm_uframes_t *frames, int *dir)
    308 {
    309     (*frames) = 64;
    310     return 0;
    311 }
    312 
    313 int _PA_LOCAL_IMPL(snd_pcm_hw_params_get_period_size_max) (const snd_pcm_hw_params_t *params, snd_pcm_uframes_t *frames, int *dir)
    314 {
    315     (*frames) = 512;
    316     return 0;
    317 }
    318 
    319 int _PA_LOCAL_IMPL(snd_pcm_hw_params_get_buffer_size_max) (const snd_pcm_hw_params_t *params, snd_pcm_uframes_t *val)
    320 {
    321     int ret;
    322     int dir                = 0;
    323     snd_pcm_uframes_t pmax = 0;
    324     unsigned int      pcnt = 0;
    325 
    326     if(( ret = _PA_LOCAL_IMPL(snd_pcm_hw_params_get_period_size_max)(params, &pmax, &dir) ) < 0 )
    327         return ret;
    328     if(( ret = _PA_LOCAL_IMPL(snd_pcm_hw_params_get_periods_max)(params, &pcnt, &dir) ) < 0 )
    329         return ret;
    330 
    331     (*val) = pmax * pcnt;
    332     return 0;
    333 }
    334 
    335 int _PA_LOCAL_IMPL(snd_pcm_hw_params_get_rate_min) (const snd_pcm_hw_params_t *params, unsigned int *val, int *dir)
    336 {
    337     (*val) = 44100;
    338     return 0;
    339 }
    340 
    341 int _PA_LOCAL_IMPL(snd_pcm_hw_params_get_rate_max) (const snd_pcm_hw_params_t *params, unsigned int *val, int *dir)
    342 {
    343     (*val) = 44100;
    344     return 0;
    345 }
    346 
    347 #endif // PA_ALSA_DYNAMIC
    348 
    349 /* Trying to load Alsa library dynamically if 'PA_ALSA_DYNAMIC' is defined, othervise
    350    will link during compilation.
    351 */
    352 static int PaAlsa_LoadLibrary()
    353 {
    354 #ifdef PA_ALSA_DYNAMIC
    355 
    356     PA_DEBUG(( "%s: loading ALSA library file - %s\n", __FUNCTION__, g_AlsaLibName ));
    357 
    358     dlerror();
    359     g_AlsaLib = dlopen(g_AlsaLibName, (RTLD_NOW|RTLD_GLOBAL) );
    360     if (g_AlsaLib == NULL)
    361     {
    362         PA_DEBUG(( "%s: failed dlopen() ALSA library file - %s, error: %s\n", __FUNCTION__, g_AlsaLibName, dlerror() ));
    363         return 0;
    364     }
    365 
    366     PA_DEBUG(( "%s: loading ALSA API\n", __FUNCTION__ ));
    367 
    368     #define _PA_LOAD_FUNC(x) do {             \
    369         alsa_##x = dlsym( g_AlsaLib, #x );      \
    370         if( alsa_##x == NULL ) {               \
    371             PA_DEBUG(( "%s: symbol [%s] not found in - %s, error: %s\n", __FUNCTION__, #x, g_AlsaLibName, dlerror() )); }\
    372         } while(0)
    373 
    374 #else
    375 
    376     #define _PA_LOAD_FUNC(x) alsa_##x = &x
    377 
    378 #endif
    379 
    380     _PA_LOAD_FUNC(snd_pcm_open);
    381     _PA_LOAD_FUNC(snd_pcm_close);
    382     _PA_LOAD_FUNC(snd_pcm_nonblock);
    383     _PA_LOAD_FUNC(snd_pcm_frames_to_bytes);
    384     _PA_LOAD_FUNC(snd_pcm_prepare);
    385     _PA_LOAD_FUNC(snd_pcm_start);
    386     _PA_LOAD_FUNC(snd_pcm_resume);
    387     _PA_LOAD_FUNC(snd_pcm_wait);
    388     _PA_LOAD_FUNC(snd_pcm_state);
    389     _PA_LOAD_FUNC(snd_pcm_avail_update);
    390     _PA_LOAD_FUNC(snd_pcm_areas_silence);
    391     _PA_LOAD_FUNC(snd_pcm_mmap_begin);
    392     _PA_LOAD_FUNC(snd_pcm_mmap_commit);
    393     _PA_LOAD_FUNC(snd_pcm_readi);
    394     _PA_LOAD_FUNC(snd_pcm_readn);
    395     _PA_LOAD_FUNC(snd_pcm_writei);
    396     _PA_LOAD_FUNC(snd_pcm_writen);
    397     _PA_LOAD_FUNC(snd_pcm_drain);
    398     _PA_LOAD_FUNC(snd_pcm_recover);
    399     _PA_LOAD_FUNC(snd_pcm_drop);
    400     _PA_LOAD_FUNC(snd_pcm_area_copy);
    401     _PA_LOAD_FUNC(snd_pcm_poll_descriptors);
    402     _PA_LOAD_FUNC(snd_pcm_poll_descriptors_count);
    403     _PA_LOAD_FUNC(snd_pcm_poll_descriptors_revents);
    404     _PA_LOAD_FUNC(snd_pcm_format_size);
    405     _PA_LOAD_FUNC(snd_pcm_link);
    406     _PA_LOAD_FUNC(snd_pcm_delay);
    407 
    408     _PA_LOAD_FUNC(snd_pcm_hw_params_sizeof);
    409     _PA_LOAD_FUNC(snd_pcm_hw_params_malloc);
    410     _PA_LOAD_FUNC(snd_pcm_hw_params_free);
    411     _PA_LOAD_FUNC(snd_pcm_hw_params_any);
    412     _PA_LOAD_FUNC(snd_pcm_hw_params_set_access);
    413     _PA_LOAD_FUNC(snd_pcm_hw_params_set_format);
    414     _PA_LOAD_FUNC(snd_pcm_hw_params_set_channels);
    415 //    _PA_LOAD_FUNC(snd_pcm_hw_params_set_periods_near);
    416     _PA_LOAD_FUNC(snd_pcm_hw_params_set_rate_near);
    417     _PA_LOAD_FUNC(snd_pcm_hw_params_set_rate);
    418     _PA_LOAD_FUNC(snd_pcm_hw_params_set_rate_resample);
    419 //    _PA_LOAD_FUNC(snd_pcm_hw_params_set_buffer_time_near);
    420     _PA_LOAD_FUNC(snd_pcm_hw_params_set_buffer_size);
    421     _PA_LOAD_FUNC(snd_pcm_hw_params_set_buffer_size_near);
    422     _PA_LOAD_FUNC(snd_pcm_hw_params_set_buffer_size_min);
    423 //    _PA_LOAD_FUNC(snd_pcm_hw_params_set_period_time_near);
    424     _PA_LOAD_FUNC(snd_pcm_hw_params_set_period_size_near);
    425     _PA_LOAD_FUNC(snd_pcm_hw_params_set_periods_integer);
    426     _PA_LOAD_FUNC(snd_pcm_hw_params_set_periods_min);
    427 
    428     _PA_LOAD_FUNC(snd_pcm_hw_params_get_buffer_size);
    429 //    _PA_LOAD_FUNC(snd_pcm_hw_params_get_period_size);
    430 //    _PA_LOAD_FUNC(snd_pcm_hw_params_get_access);
    431 //    _PA_LOAD_FUNC(snd_pcm_hw_params_get_periods);
    432 //    _PA_LOAD_FUNC(snd_pcm_hw_params_get_rate);
    433     _PA_LOAD_FUNC(snd_pcm_hw_params_get_channels_min);
    434     _PA_LOAD_FUNC(snd_pcm_hw_params_get_channels_max);
    435 
    436     _PA_LOAD_FUNC(snd_pcm_hw_params_test_period_size);
    437     _PA_LOAD_FUNC(snd_pcm_hw_params_test_format);
    438     _PA_LOAD_FUNC(snd_pcm_hw_params_test_access);
    439     _PA_LOAD_FUNC(snd_pcm_hw_params_dump);
    440     _PA_LOAD_FUNC(snd_pcm_hw_params);
    441 
    442     _PA_LOAD_FUNC(snd_pcm_hw_params_get_periods_min);
    443     _PA_LOAD_FUNC(snd_pcm_hw_params_get_periods_max);
    444     _PA_LOAD_FUNC(snd_pcm_hw_params_set_period_size);
    445     _PA_LOAD_FUNC(snd_pcm_hw_params_get_period_size_min);
    446     _PA_LOAD_FUNC(snd_pcm_hw_params_get_period_size_max);
    447     _PA_LOAD_FUNC(snd_pcm_hw_params_get_buffer_size_max);
    448     _PA_LOAD_FUNC(snd_pcm_hw_params_get_rate_min);
    449     _PA_LOAD_FUNC(snd_pcm_hw_params_get_rate_max);
    450     _PA_LOAD_FUNC(snd_pcm_hw_params_get_rate_numden);
    451 
    452     _PA_LOAD_FUNC(snd_pcm_sw_params_sizeof);
    453     _PA_LOAD_FUNC(snd_pcm_sw_params_malloc);
    454     _PA_LOAD_FUNC(snd_pcm_sw_params_current);
    455     _PA_LOAD_FUNC(snd_pcm_sw_params_set_avail_min);
    456     _PA_LOAD_FUNC(snd_pcm_sw_params);
    457     _PA_LOAD_FUNC(snd_pcm_sw_params_free);
    458     _PA_LOAD_FUNC(snd_pcm_sw_params_set_start_threshold);
    459     _PA_LOAD_FUNC(snd_pcm_sw_params_set_stop_threshold);
    460     _PA_LOAD_FUNC(snd_pcm_sw_params_get_boundary);
    461     _PA_LOAD_FUNC(snd_pcm_sw_params_set_silence_threshold);
    462     _PA_LOAD_FUNC(snd_pcm_sw_params_set_silence_size);
    463     _PA_LOAD_FUNC(snd_pcm_sw_params_set_xfer_align);
    464     _PA_LOAD_FUNC(snd_pcm_sw_params_set_tstamp_mode);
    465 
    466     _PA_LOAD_FUNC(snd_pcm_info);
    467     _PA_LOAD_FUNC(snd_pcm_info_sizeof);
    468     _PA_LOAD_FUNC(snd_pcm_info_malloc);
    469     _PA_LOAD_FUNC(snd_pcm_info_free);
    470     _PA_LOAD_FUNC(snd_pcm_info_set_device);
    471     _PA_LOAD_FUNC(snd_pcm_info_set_subdevice);
    472     _PA_LOAD_FUNC(snd_pcm_info_set_stream);
    473     _PA_LOAD_FUNC(snd_pcm_info_get_name);
    474     _PA_LOAD_FUNC(snd_pcm_info_get_card);
    475 
    476     _PA_LOAD_FUNC(snd_ctl_pcm_next_device);
    477     _PA_LOAD_FUNC(snd_ctl_pcm_info);
    478     _PA_LOAD_FUNC(snd_ctl_open);
    479     _PA_LOAD_FUNC(snd_ctl_close);
    480     _PA_LOAD_FUNC(snd_ctl_card_info_malloc);
    481     _PA_LOAD_FUNC(snd_ctl_card_info_free);
    482     _PA_LOAD_FUNC(snd_ctl_card_info);
    483     _PA_LOAD_FUNC(snd_ctl_card_info_sizeof);
    484     _PA_LOAD_FUNC(snd_ctl_card_info_get_name);
    485 
    486     _PA_LOAD_FUNC(snd_config);
    487     _PA_LOAD_FUNC(snd_config_update);
    488     _PA_LOAD_FUNC(snd_config_search);
    489     _PA_LOAD_FUNC(snd_config_iterator_entry);
    490     _PA_LOAD_FUNC(snd_config_iterator_first);
    491     _PA_LOAD_FUNC(snd_config_iterator_end);
    492     _PA_LOAD_FUNC(snd_config_iterator_next);
    493     _PA_LOAD_FUNC(snd_config_get_string);
    494     _PA_LOAD_FUNC(snd_config_get_id);
    495     _PA_LOAD_FUNC(snd_config_update_free_global);
    496 
    497     _PA_LOAD_FUNC(snd_pcm_status);
    498     _PA_LOAD_FUNC(snd_pcm_status_sizeof);
    499     _PA_LOAD_FUNC(snd_pcm_status_get_tstamp);
    500     _PA_LOAD_FUNC(snd_pcm_status_get_state);
    501     _PA_LOAD_FUNC(snd_pcm_status_get_trigger_tstamp);
    502     _PA_LOAD_FUNC(snd_pcm_status_get_delay);
    503 
    504     _PA_LOAD_FUNC(snd_card_next);
    505     _PA_LOAD_FUNC(snd_asoundlib_version);
    506     _PA_LOAD_FUNC(snd_strerror);
    507     _PA_LOAD_FUNC(snd_output_stdio_attach);
    508 #undef _PA_LOAD_FUNC
    509 
    510 #ifdef PA_ALSA_DYNAMIC
    511     PA_DEBUG(( "%s: loaded ALSA API - ok\n", __FUNCTION__ ));
    512 
    513 #define _PA_VALIDATE_LOAD_REPLACEMENT(x)\
    514     do {\
    515         if( alsa_##x == NULL )\
    516         {\
    517             alsa_##x = &_PA_LOCAL_IMPL(x);\
    518             PA_DEBUG(( "%s: replacing [%s] with local implementation\n", __FUNCTION__, #x ));\
    519         }\
    520     } while (0)
    521 
    522     _PA_VALIDATE_LOAD_REPLACEMENT(snd_pcm_hw_params_set_rate_near);
    523     _PA_VALIDATE_LOAD_REPLACEMENT(snd_pcm_hw_params_set_buffer_size_near);
    524     _PA_VALIDATE_LOAD_REPLACEMENT(snd_pcm_hw_params_set_period_size_near);
    525     _PA_VALIDATE_LOAD_REPLACEMENT(snd_pcm_hw_params_get_channels_min);
    526     _PA_VALIDATE_LOAD_REPLACEMENT(snd_pcm_hw_params_get_channels_max);
    527     _PA_VALIDATE_LOAD_REPLACEMENT(snd_pcm_hw_params_get_periods_min);
    528     _PA_VALIDATE_LOAD_REPLACEMENT(snd_pcm_hw_params_get_periods_max);
    529     _PA_VALIDATE_LOAD_REPLACEMENT(snd_pcm_hw_params_get_period_size_min);
    530     _PA_VALIDATE_LOAD_REPLACEMENT(snd_pcm_hw_params_get_period_size_max);
    531     _PA_VALIDATE_LOAD_REPLACEMENT(snd_pcm_hw_params_get_buffer_size_max);
    532     _PA_VALIDATE_LOAD_REPLACEMENT(snd_pcm_hw_params_get_rate_min);
    533     _PA_VALIDATE_LOAD_REPLACEMENT(snd_pcm_hw_params_get_rate_max);
    534 
    535 #undef _PA_LOCAL_IMPL
    536 #undef _PA_VALIDATE_LOAD_REPLACEMENT
    537 
    538 #endif // PA_ALSA_DYNAMIC
    539 
    540     return 1;
    541 }
    542 
    543 void PaAlsa_SetLibraryPathName( const char *pathName )
    544 {
    545 #ifdef PA_ALSA_DYNAMIC
    546     g_AlsaLibName = pathName;
    547 #else
    548     (void)pathName;
    549 #endif
    550 }
    551 
    552 /* Close handle to Alsa library. */
    553 static void PaAlsa_CloseLibrary()
    554 {
    555 #ifdef PA_ALSA_DYNAMIC
    556     dlclose(g_AlsaLib);
    557     g_AlsaLib = NULL;
    558 #endif
    559 }
    560 
    561 /* Check return value of ALSA function, and map it to PaError */
    562 #define ENSURE_(expr, code) \
    563     do { \
    564         int __pa_unsure_error_id;\
    565         if( UNLIKELY( (__pa_unsure_error_id = (expr)) < 0 ) ) \
    566         { \
    567             /* PaUtil_SetLastHostErrorInfo should only be used in the main thread */ \
    568             if( (code) == paUnanticipatedHostError && pthread_equal( pthread_self(), paUnixMainThread) ) \
    569             { \
    570                 PaUtil_SetLastHostErrorInfo( paALSA, __pa_unsure_error_id, alsa_snd_strerror( __pa_unsure_error_id ) ); \
    571             } \
    572             PaUtil_DebugPrint( "Expression '" #expr "' failed in '" __FILE__ "', line: " STRINGIZE( __LINE__ ) "\n" ); \
    573             if( (code) == paUnanticipatedHostError ) \
    574                 PA_DEBUG(( "Host error description: %s\n", alsa_snd_strerror( __pa_unsure_error_id ) )); \
    575             result = (code); \
    576             goto error; \
    577         } \
    578     } while (0)
    579 
    580 #define ASSERT_CALL_(expr, success) \
    581     do {\
    582         int __pa_assert_error_id;\
    583         __pa_assert_error_id = (expr);\
    584         assert( success == __pa_assert_error_id );\
    585     } while (0)
    586 
    587 static int numPeriods_ = 4;
    588 static int busyRetries_ = 100;
    589 
    590 int PaAlsa_SetNumPeriods( int numPeriods )
    591 {
    592     numPeriods_ = numPeriods;
    593     return paNoError;
    594 }
    595 
    596 typedef enum
    597 {
    598     StreamDirection_In,
    599     StreamDirection_Out
    600 } StreamDirection;
    601 
    602 typedef struct
    603 {
    604     PaSampleFormat hostSampleFormat;
    605     int numUserChannels, numHostChannels;
    606     int userInterleaved, hostInterleaved;
    607     int canMmap;
    608     void *nonMmapBuffer;
    609     unsigned int nonMmapBufferSize;
    610     PaDeviceIndex device;     /* Keep the device index */
    611     int deviceIsPlug; /* Distinguish plug types from direct 'hw:' devices */
    612     int useReventFix; /* Alsa older than 1.0.16, plug devices need a fix */
    613 
    614     snd_pcm_t *pcm;
    615     snd_pcm_uframes_t framesPerPeriod, alsaBufferSize;
    616     snd_pcm_format_t nativeFormat;
    617     unsigned int nfds;
    618     int ready;  /* Marked ready from poll */
    619     void **userBuffers;
    620     snd_pcm_uframes_t offset;
    621     StreamDirection streamDir;
    622 
    623     snd_pcm_channel_area_t *channelAreas;  /* Needed for channel adaption */
    624 } PaAlsaStreamComponent;
    625 
    626 /* Implementation specific stream structure */
    627 typedef struct PaAlsaStream
    628 {
    629     PaUtilStreamRepresentation streamRepresentation;
    630     PaUtilCpuLoadMeasurer cpuLoadMeasurer;
    631     PaUtilBufferProcessor bufferProcessor;
    632     PaUnixThread thread;
    633 
    634     unsigned long framesPerUserBuffer, maxFramesPerHostBuffer;
    635 
    636     int primeBuffers;
    637     int callbackMode;              /* bool: are we running in callback mode? */
    638     int pcmsSynced;                /* Have we successfully synced pcms */
    639     int rtSched;
    640 
    641     /* the callback thread uses these to poll the sound device(s), waiting
    642      * for data to be ready/available */
    643     struct pollfd* pfds;
    644     int pollTimeout;
    645 
    646     /* Used in communication between threads */
    647     volatile sig_atomic_t callback_finished; /* bool: are we in the "callback finished" state? */
    648     volatile sig_atomic_t callbackAbort;    /* Drop frames? */
    649     volatile sig_atomic_t isActive;         /* Is stream in active state? (Between StartStream and StopStream || !paContinue) */
    650     PaUnixMutex stateMtx;                   /* Used to synchronize access to stream state */
    651 
    652     int neverDropInput;
    653 
    654     PaTime underrun;
    655     PaTime overrun;
    656 
    657     PaAlsaStreamComponent capture, playback;
    658 }
    659 PaAlsaStream;
    660 
    661 /* PaAlsaHostApiRepresentation - host api datastructure specific to this implementation */
    662 
    663 typedef struct PaAlsaHostApiRepresentation
    664 {
    665     PaUtilHostApiRepresentation baseHostApiRep;
    666     PaUtilStreamInterface callbackStreamInterface;
    667     PaUtilStreamInterface blockingStreamInterface;
    668 
    669     PaUtilAllocationGroup *allocations;
    670 
    671     PaHostApiIndex hostApiIndex;
    672     PaUint32 alsaLibVersion; /* Retrieved from the library at run-time */
    673 }
    674 PaAlsaHostApiRepresentation;
    675 
    676 typedef struct PaAlsaDeviceInfo
    677 {
    678     PaDeviceInfo baseDeviceInfo;
    679     char *alsaName;
    680     int isPlug;
    681     int minInputChannels;
    682     int minOutputChannels;
    683 }
    684 PaAlsaDeviceInfo;
    685 
    686 /* prototypes for functions declared in this file */
    687 
    688 static void Terminate( struct PaUtilHostApiRepresentation *hostApi );
    689 static PaError IsFormatSupported( struct PaUtilHostApiRepresentation *hostApi,
    690                                   const PaStreamParameters *inputParameters,
    691                                   const PaStreamParameters *outputParameters,
    692                                   double sampleRate );
    693 static PaError OpenStream( struct PaUtilHostApiRepresentation *hostApi,
    694                            PaStream** s,
    695                            const PaStreamParameters *inputParameters,
    696                            const PaStreamParameters *outputParameters,
    697                            double sampleRate,
    698                            unsigned long framesPerBuffer,
    699                            PaStreamFlags streamFlags,
    700                            PaStreamCallback *callback,
    701                            void *userData );
    702 static PaError CloseStream( PaStream* stream );
    703 static PaError StartStream( PaStream *stream );
    704 static PaError StopStream( PaStream *stream );
    705 static PaError AbortStream( PaStream *stream );
    706 static PaError IsStreamStopped( PaStream *s );
    707 static PaError IsStreamActive( PaStream *stream );
    708 static PaTime GetStreamTime( PaStream *stream );
    709 static double GetStreamCpuLoad( PaStream* stream );
    710 static PaError BuildDeviceList( PaAlsaHostApiRepresentation *hostApi );
    711 static int SetApproximateSampleRate( snd_pcm_t *pcm, snd_pcm_hw_params_t *hwParams, double sampleRate );
    712 static int GetExactSampleRate( snd_pcm_hw_params_t *hwParams, double *sampleRate );
    713 static PaUint32 PaAlsaVersionNum(void);
    714 
    715 /* Callback prototypes */
    716 static void *CallbackThreadFunc( void *userData );
    717 
    718 /* Blocking prototypes */
    719 static signed long GetStreamReadAvailable( PaStream* s );
    720 static signed long GetStreamWriteAvailable( PaStream* s );
    721 static PaError ReadStream( PaStream* stream, void *buffer, unsigned long frames );
    722 static PaError WriteStream( PaStream* stream, const void *buffer, unsigned long frames );
    723 
    724 
    725 static const PaAlsaDeviceInfo *GetDeviceInfo( const PaUtilHostApiRepresentation *hostApi, int device )
    726 {
    727     return (const PaAlsaDeviceInfo *)hostApi->deviceInfos[device];
    728 }
    729 
    730 /** Uncommented because AlsaErrorHandler is unused for anything good yet. If AlsaErrorHandler is
    731     to be used, do not forget to register this callback in PaAlsa_Initialize, and unregister in Terminate.
    732 */
    733 /*static void AlsaErrorHandler(const char *file, int line, const char *function, int err, const char *fmt, ...)
    734 {
    735 }*/
    736 
    737 PaError PaAlsa_Initialize( PaUtilHostApiRepresentation **hostApi, PaHostApiIndex hostApiIndex )
    738 {
    739     PaError result = paNoError;
    740     PaAlsaHostApiRepresentation *alsaHostApi = NULL;
    741 
    742     /* Try loading Alsa library. */
    743     if (!PaAlsa_LoadLibrary())
    744         return paHostApiNotFound;
    745 
    746     PA_UNLESS( alsaHostApi = (PaAlsaHostApiRepresentation*) PaUtil_AllocateMemory(
    747                 sizeof(PaAlsaHostApiRepresentation) ), paInsufficientMemory );
    748     PA_UNLESS( alsaHostApi->allocations = PaUtil_CreateAllocationGroup(), paInsufficientMemory );
    749     alsaHostApi->hostApiIndex = hostApiIndex;
    750     alsaHostApi->alsaLibVersion = PaAlsaVersionNum();
    751 
    752     *hostApi = (PaUtilHostApiRepresentation*)alsaHostApi;
    753     (*hostApi)->info.structVersion = 1;
    754     (*hostApi)->info.type = paALSA;
    755     (*hostApi)->info.name = "ALSA";
    756 
    757     (*hostApi)->Terminate = Terminate;
    758     (*hostApi)->OpenStream = OpenStream;
    759     (*hostApi)->IsFormatSupported = IsFormatSupported;
    760 
    761     /** If AlsaErrorHandler is to be used, do not forget to unregister callback pointer in
    762         Terminate function.
    763     */
    764     /*ENSURE_( snd_lib_error_set_handler(AlsaErrorHandler), paUnanticipatedHostError );*/
    765 
    766     PA_ENSURE( BuildDeviceList( alsaHostApi ) );
    767 
    768     PaUtil_InitializeStreamInterface( &alsaHostApi->callbackStreamInterface,
    769                                       CloseStream, StartStream,
    770                                       StopStream, AbortStream,
    771                                       IsStreamStopped, IsStreamActive,
    772                                       GetStreamTime, GetStreamCpuLoad,
    773                                       PaUtil_DummyRead, PaUtil_DummyWrite,
    774                                       PaUtil_DummyGetReadAvailable,
    775                                       PaUtil_DummyGetWriteAvailable );
    776 
    777     PaUtil_InitializeStreamInterface( &alsaHostApi->blockingStreamInterface,
    778                                       CloseStream, StartStream,
    779                                       StopStream, AbortStream,
    780                                       IsStreamStopped, IsStreamActive,
    781                                       GetStreamTime, PaUtil_DummyGetCpuLoad,
    782                                       ReadStream, WriteStream,
    783                                       GetStreamReadAvailable,
    784                                       GetStreamWriteAvailable );
    785 
    786     PA_ENSURE( PaUnixThreading_Initialize() );
    787 
    788     return result;
    789 
    790 error:
    791     if( alsaHostApi )
    792     {
    793         if( alsaHostApi->allocations )
    794         {
    795             PaUtil_FreeAllAllocations( alsaHostApi->allocations );
    796             PaUtil_DestroyAllocationGroup( alsaHostApi->allocations );
    797         }
    798 
    799         PaUtil_FreeMemory( alsaHostApi );
    800     }
    801 
    802     return result;
    803 }
    804 
    805 static void Terminate( struct PaUtilHostApiRepresentation *hostApi )
    806 {
    807     PaAlsaHostApiRepresentation *alsaHostApi = (PaAlsaHostApiRepresentation*)hostApi;
    808 
    809     assert( hostApi );
    810 
    811     /** See AlsaErrorHandler and PaAlsa_Initialize for details.
    812     */
    813     /*snd_lib_error_set_handler(NULL);*/
    814 
    815     if( alsaHostApi->allocations )
    816     {
    817         PaUtil_FreeAllAllocations( alsaHostApi->allocations );
    818         PaUtil_DestroyAllocationGroup( alsaHostApi->allocations );
    819     }
    820 
    821     PaUtil_FreeMemory( alsaHostApi );
    822     alsa_snd_config_update_free_global();
    823 
    824     /* Close Alsa library. */
    825     PaAlsa_CloseLibrary();
    826 }
    827 
    828 /** Determine max channels and default latencies.
    829  *
    830  * This function provides functionality to grope an opened (might be opened for capture or playback) pcm device for
    831  * traits like max channels, suitable default latencies and default sample rate. Upon error, max channels is set to zero,
    832  * and a suitable result returned. The device is closed before returning.
    833  */
    834 static PaError GropeDevice( snd_pcm_t* pcm, int isPlug, StreamDirection mode, int openBlocking,
    835         PaAlsaDeviceInfo* devInfo )
    836 {
    837     PaError result = paNoError;
    838     snd_pcm_hw_params_t *hwParams;
    839     snd_pcm_uframes_t alsaBufferFrames, alsaPeriodFrames;
    840     unsigned int minChans, maxChans;
    841     int* minChannels, * maxChannels;
    842     double * defaultLowLatency, * defaultHighLatency, * defaultSampleRate =
    843         &devInfo->baseDeviceInfo.defaultSampleRate;
    844     double defaultSr = *defaultSampleRate;
    845     int dir;
    846 
    847     assert( pcm );
    848 
    849     PA_DEBUG(( "%s: collecting info ..\n", __FUNCTION__ ));
    850 
    851     if( StreamDirection_In == mode )
    852     {
    853         minChannels = &devInfo->minInputChannels;
    854         maxChannels = &devInfo->baseDeviceInfo.maxInputChannels;
    855         defaultLowLatency = &devInfo->baseDeviceInfo.defaultLowInputLatency;
    856         defaultHighLatency = &devInfo->baseDeviceInfo.defaultHighInputLatency;
    857     }
    858     else
    859     {
    860         minChannels = &devInfo->minOutputChannels;
    861         maxChannels = &devInfo->baseDeviceInfo.maxOutputChannels;
    862         defaultLowLatency = &devInfo->baseDeviceInfo.defaultLowOutputLatency;
    863         defaultHighLatency = &devInfo->baseDeviceInfo.defaultHighOutputLatency;
    864     }
    865 
    866     ENSURE_( alsa_snd_pcm_nonblock( pcm, 0 ), paUnanticipatedHostError );
    867 
    868     alsa_snd_pcm_hw_params_alloca( &hwParams );
    869     alsa_snd_pcm_hw_params_any( pcm, hwParams );
    870 
    871     if( defaultSr >= 0 )
    872     {
    873         /* Could be that the device opened in one mode supports samplerates that the other mode wont have,
    874          * so try again .. */
    875         if( SetApproximateSampleRate( pcm, hwParams, defaultSr ) < 0 )
    876         {
    877             defaultSr = -1.;
    878             alsa_snd_pcm_hw_params_any( pcm, hwParams ); /* Clear any params (rate) that might have been set */
    879             PA_DEBUG(( "%s: Original default samplerate failed, trying again ..\n", __FUNCTION__ ));
    880         }
    881     }
    882 
    883     if( defaultSr < 0. )           /* Default sample rate not set */
    884     {
    885         unsigned int sampleRate = 44100;        /* Will contain approximate rate returned by alsa-lib */
    886 
    887         /* Don't allow rate resampling when probing for the default rate (but ignore if this call fails) */
    888         alsa_snd_pcm_hw_params_set_rate_resample( pcm, hwParams, 0 );
    889         if( alsa_snd_pcm_hw_params_set_rate_near( pcm, hwParams, &sampleRate, NULL ) < 0 )
    890         {
    891             result = paUnanticipatedHostError;
    892             goto error;
    893         }
    894         ENSURE_( GetExactSampleRate( hwParams, &defaultSr ), paUnanticipatedHostError );
    895     }
    896 
    897     ENSURE_( alsa_snd_pcm_hw_params_get_channels_min( hwParams, &minChans ), paUnanticipatedHostError );
    898     ENSURE_( alsa_snd_pcm_hw_params_get_channels_max( hwParams, &maxChans ), paUnanticipatedHostError );
    899     assert( maxChans <= INT_MAX );
    900     assert( maxChans > 0 );    /* Weird linking issue could cause wrong version of ALSA symbols to be called,
    901                                    resulting in zeroed values */
    902 
    903     /* XXX: Limit to sensible number (ALSA plugins accept a crazy amount of channels)? */
    904     if( isPlug && maxChans > 128 )
    905     {
    906         maxChans = 128;
    907         PA_DEBUG(( "%s: Limiting number of plugin channels to %u\n", __FUNCTION__, maxChans ));
    908     }
    909 
    910     /* TWEAKME:
    911      * Giving values for default min and max latency is not straightforward.
    912      *  * for low latency, we want to give the lowest value that will work reliably.
    913      *      This varies based on the sound card, kernel, CPU, etc.  Better to give
    914      *      sub-optimal latency than to give a number too low and cause dropouts.
    915      *  * for high latency we want to give a large enough value that dropouts are basically impossible.
    916      *      This doesn't really require as much tweaking, since providing too large a number will
    917      *      just cause us to select the nearest setting that will work at stream config time.
    918      */
    919     /* Try low latency values, (sometimes the buffer & period that result are larger) */
    920     alsaBufferFrames = 512;
    921     alsaPeriodFrames = 128;
    922     ENSURE_( alsa_snd_pcm_hw_params_set_buffer_size_near( pcm, hwParams, &alsaBufferFrames ), paUnanticipatedHostError );
    923     ENSURE_( alsa_snd_pcm_hw_params_set_period_size_near( pcm, hwParams, &alsaPeriodFrames, &dir ), paUnanticipatedHostError );
    924     *defaultLowLatency = (double) (alsaBufferFrames - alsaPeriodFrames) / defaultSr;
    925 
    926     /* Base the high latency case on values four times larger */
    927     alsaBufferFrames = 2048;
    928     alsaPeriodFrames = 512;
    929     /* Have to reset hwParams, to set new buffer size; need to also set sample rate again */
    930     ENSURE_( alsa_snd_pcm_hw_params_any( pcm, hwParams ), paUnanticipatedHostError );
    931     ENSURE_( SetApproximateSampleRate( pcm, hwParams, defaultSr ), paUnanticipatedHostError );
    932     ENSURE_( alsa_snd_pcm_hw_params_set_buffer_size_near( pcm, hwParams, &alsaBufferFrames ), paUnanticipatedHostError );
    933     ENSURE_( alsa_snd_pcm_hw_params_set_period_size_near( pcm, hwParams, &alsaPeriodFrames, &dir ), paUnanticipatedHostError );
    934     *defaultHighLatency = (double) (alsaBufferFrames - alsaPeriodFrames) / defaultSr;
    935 
    936     *minChannels = (int)minChans;
    937     *maxChannels = (int)maxChans;
    938     *defaultSampleRate = defaultSr;
    939 
    940 end:
    941     alsa_snd_pcm_close( pcm );
    942     return result;
    943 
    944 error:
    945     goto end;
    946 }
    947 
    948 /* Initialize device info with invalid values (maxInputChannels and maxOutputChannels are set to zero since these indicate
    949  * whether input/output is available) */
    950 static void InitializeDeviceInfo( PaDeviceInfo *deviceInfo )
    951 {
    952     deviceInfo->structVersion = -1;
    953     deviceInfo->name = NULL;
    954     deviceInfo->hostApi = -1;
    955     deviceInfo->maxInputChannels = 0;
    956     deviceInfo->maxOutputChannels = 0;
    957     deviceInfo->defaultLowInputLatency = -1.;
    958     deviceInfo->defaultLowOutputLatency = -1.;
    959     deviceInfo->defaultHighInputLatency = -1.;
    960     deviceInfo->defaultHighOutputLatency = -1.;
    961     deviceInfo->defaultSampleRate = -1.;
    962 }
    963 
    964 
    965 /* Retrieve the version of the runtime Alsa-lib, as a single number equivalent to
    966  * SND_LIB_VERSION.  Only a version string is available ("a.b.c") so this has to be converted.
    967  * Assume 'a' and 'b' are single digits only.
    968  */
    969 static PaUint32 PaAlsaVersionNum(void)
    970 {
    971     char* verStr;
    972     PaUint32 verNum;
    973 
    974     verStr = (char*) alsa_snd_asoundlib_version();
    975     verNum = ALSA_VERSION_INT( atoi(verStr), atoi(verStr + 2), atoi(verStr + 4) );
    976     PA_DEBUG(( "ALSA version (build): " SND_LIB_VERSION_STR "\nALSA version (runtime): %s\n", verStr ));
    977 
    978     return verNum;
    979 }
    980 
    981 
    982 /* Helper struct */
    983 typedef struct
    984 {
    985     char *alsaName;
    986     char *name;
    987     int isPlug;
    988     int hasPlayback;
    989     int hasCapture;
    990 } HwDevInfo;
    991 
    992 
    993 HwDevInfo predefinedNames[] = {
    994     { "center_lfe", NULL, 0, 1, 0 },
    995 /* { "default", NULL, 0, 1, 1 }, */
    996     { "dmix", NULL, 0, 1, 0 },
    997 /* { "dpl", NULL, 0, 1, 0 }, */
    998 /* { "dsnoop", NULL, 0, 0, 1 }, */
    999     { "front", NULL, 0, 1, 0 },
   1000     { "iec958", NULL, 0, 1, 0 },
   1001 /* { "modem", NULL, 0, 1, 0 }, */
   1002     { "rear", NULL, 0, 1, 0 },
   1003     { "side", NULL, 0, 1, 0 },
   1004 /*     { "spdif", NULL, 0, 0, 0 }, */
   1005     { "surround40", NULL, 0, 1, 0 },
   1006     { "surround41", NULL, 0, 1, 0 },
   1007     { "surround50", NULL, 0, 1, 0 },
   1008     { "surround51", NULL, 0, 1, 0 },
   1009     { "surround71", NULL, 0, 1, 0 },
   1010 
   1011     { "AndroidPlayback_Earpiece_normal",         NULL, 0, 1, 0 },
   1012     { "AndroidPlayback_Speaker_normal",          NULL, 0, 1, 0 },
   1013     { "AndroidPlayback_Bluetooth_normal",        NULL, 0, 1, 0 },
   1014     { "AndroidPlayback_Headset_normal",          NULL, 0, 1, 0 },
   1015     { "AndroidPlayback_Speaker_Headset_normal",  NULL, 0, 1, 0 },
   1016     { "AndroidPlayback_Bluetooth-A2DP_normal",   NULL, 0, 1, 0 },
   1017     { "AndroidPlayback_ExtraDockSpeaker_normal", NULL, 0, 1, 0 },
   1018     { "AndroidPlayback_TvOut_normal",            NULL, 0, 1, 0 },
   1019 
   1020     { "AndroidRecord_Microphone",                NULL, 0, 0, 1 },
   1021     { "AndroidRecord_Earpiece_normal",           NULL, 0, 0, 1 },
   1022     { "AndroidRecord_Speaker_normal",            NULL, 0, 0, 1 },
   1023     { "AndroidRecord_Headset_normal",            NULL, 0, 0, 1 },
   1024     { "AndroidRecord_Bluetooth_normal",          NULL, 0, 0, 1 },
   1025     { "AndroidRecord_Speaker_Headset_normal",    NULL, 0, 0, 1 },
   1026 
   1027     { NULL, NULL, 0, 1, 0 }
   1028 };
   1029 
   1030 static const HwDevInfo *FindDeviceName( const char *name )
   1031 {
   1032     int i;
   1033 
   1034     for( i = 0; predefinedNames[i].alsaName; i++ )
   1035     {
   1036         if( strcmp( name, predefinedNames[i].alsaName ) == 0 )
   1037         {
   1038             return &predefinedNames[i];
   1039         }
   1040     }
   1041 
   1042     return NULL;
   1043 }
   1044 
   1045 static PaError PaAlsa_StrDup( PaAlsaHostApiRepresentation *alsaApi,
   1046         char **dst,
   1047         const char *src)
   1048 {
   1049     PaError result = paNoError;
   1050     int len = strlen( src ) + 1;
   1051 
   1052     /* PA_DEBUG(("PaStrDup %s %d\n", src, len)); */
   1053 
   1054     PA_UNLESS( *dst = (char *)PaUtil_GroupAllocateMemory( alsaApi->allocations, len ),
   1055             paInsufficientMemory );
   1056     strncpy( *dst, src, len );
   1057 
   1058 error:
   1059     return result;
   1060 }
   1061 
   1062 /* Disregard some standard plugins
   1063  */
   1064 static int IgnorePlugin( const char *pluginId )
   1065 {
   1066     static const char *ignoredPlugins[] = {"hw", "plughw", "plug", "dsnoop", "tee",
   1067         "file", "null", "shm", "cards", "rate_convert", NULL};
   1068     int i = 0;
   1069     while( ignoredPlugins[i] )
   1070     {
   1071         if( !strcmp( pluginId, ignoredPlugins[i] ) )
   1072         {
   1073             return 1;
   1074         }
   1075         ++i;
   1076     }
   1077 
   1078     return 0;
   1079 }
   1080 
   1081 /* Skip past parts at the beginning of a (pcm) info name that are already in the card name, to avoid duplication */
   1082 static char *SkipCardDetailsInName( char *infoSkipName, char *cardRefName )
   1083 {
   1084     char *lastSpacePosn = infoSkipName;
   1085 
   1086     /* Skip matching chars; but only in chunks separated by ' ' (not part words etc), so track lastSpacePosn */
   1087     while( *cardRefName )
   1088     {
   1089         while( *infoSkipName && *cardRefName && *infoSkipName == *cardRefName)
   1090         {
   1091             infoSkipName++;
   1092             cardRefName++;
   1093             if( *infoSkipName == ' ' || *infoSkipName == '\0' )
   1094                 lastSpacePosn = infoSkipName;
   1095         }
   1096         infoSkipName = lastSpacePosn;
   1097         /* Look for another chunk; post-increment means ends pointing to next char */
   1098         while( *cardRefName && ( *cardRefName++ != ' ' ));
   1099     }
   1100     if( *infoSkipName == '\0' )
   1101         return "-"; /* The 2 names were identical; instead of a nul-string, return a marker string */
   1102 
   1103     /* Now want to move to the first char after any spaces */
   1104     while( *lastSpacePosn && *lastSpacePosn == ' ' )
   1105         lastSpacePosn++;
   1106     /* Skip a single separator char if present in the remaining pcm name; (pa will add its own) */
   1107     if(( *lastSpacePosn == '-' || *lastSpacePosn == ':' ) && *(lastSpacePosn + 1) == ' ' )
   1108         lastSpacePosn += 2;
   1109 
   1110     return lastSpacePosn;
   1111 }
   1112 
   1113 /** Open PCM device.
   1114  *
   1115  * Wrapper around alsa_snd_pcm_open which may repeatedly retry opening a device if it is busy, for
   1116  * a certain time. This is because dmix may temporarily hold on to a device after it (dmix)
   1117  * has been opened and closed.
   1118  * @param mode: Open mode (e.g., SND_PCM_BLOCKING).
   1119  * @param waitOnBusy: Retry opening busy device for up to one second?
   1120  **/
   1121 static int OpenPcm( snd_pcm_t **pcmp, const char *name, snd_pcm_stream_t stream, int mode, int waitOnBusy )
   1122 {
   1123     int ret, tries = 0, maxTries = waitOnBusy ? busyRetries_ : 0;
   1124 
   1125     ret = alsa_snd_pcm_open( pcmp, name, stream, mode );
   1126 
   1127     for( tries = 0; tries < maxTries && -EBUSY == ret; ++tries )
   1128     {
   1129         Pa_Sleep( 10 );
   1130         ret = alsa_snd_pcm_open( pcmp, name, stream, mode );
   1131         if( -EBUSY != ret )
   1132         {
   1133             PA_DEBUG(( "%s: Successfully opened initially busy device after %d tries\n", __FUNCTION__, tries ));
   1134         }
   1135     }
   1136     if( -EBUSY == ret )
   1137     {
   1138         PA_DEBUG(( "%s: Failed to open busy device '%s'\n", __FUNCTION__, name ));
   1139     }
   1140     else
   1141     {
   1142         if( ret < 0 )
   1143             PA_DEBUG(( "%s: Opened device '%s' ptr[%p] - result: [%d:%s]\n", __FUNCTION__, name, *pcmp, ret, alsa_snd_strerror(ret) ));
   1144     }
   1145 
   1146     return ret;
   1147 }
   1148 
   1149 static PaError FillInDevInfo( PaAlsaHostApiRepresentation *alsaApi, HwDevInfo* deviceHwInfo, int blocking,
   1150         PaAlsaDeviceInfo* devInfo, int* devIdx )
   1151 {
   1152     PaError result = 0;
   1153     PaDeviceInfo *baseDeviceInfo = &devInfo->baseDeviceInfo;
   1154     snd_pcm_t *pcm = NULL;
   1155     PaUtilHostApiRepresentation *baseApi = &alsaApi->baseHostApiRep;
   1156 
   1157     PA_DEBUG(( "%s: Filling device info for: %s\n", __FUNCTION__, deviceHwInfo->name ));
   1158 
   1159     /* Zero fields */
   1160     InitializeDeviceInfo( baseDeviceInfo );
   1161 
   1162     /* To determine device capabilities, we must open the device and query the
   1163      * hardware parameter configuration space */
   1164 
   1165     /* Query capture */
   1166     if( deviceHwInfo->hasCapture &&
   1167         OpenPcm( &pcm, deviceHwInfo->alsaName, SND_PCM_STREAM_CAPTURE, blocking, 0 ) >= 0 )
   1168     {
   1169         if( GropeDevice( pcm, deviceHwInfo->isPlug, StreamDirection_In, blocking, devInfo ) != paNoError )
   1170         {
   1171             /* Error */
   1172             PA_DEBUG(( "%s: Failed groping %s for capture\n", __FUNCTION__, deviceHwInfo->alsaName ));
   1173             goto end;
   1174         }
   1175     }
   1176 
   1177     /* Query playback */
   1178     if( deviceHwInfo->hasPlayback &&
   1179         OpenPcm( &pcm, deviceHwInfo->alsaName, SND_PCM_STREAM_PLAYBACK, blocking, 0 ) >= 0 )
   1180     {
   1181         if( GropeDevice( pcm, deviceHwInfo->isPlug, StreamDirection_Out, blocking, devInfo ) != paNoError )
   1182         {
   1183             /* Error */
   1184             PA_DEBUG(( "%s: Failed groping %s for playback\n", __FUNCTION__, deviceHwInfo->alsaName ));
   1185             goto end;
   1186         }
   1187     }
   1188 
   1189     baseDeviceInfo->structVersion = 2;
   1190     baseDeviceInfo->hostApi = alsaApi->hostApiIndex;
   1191     baseDeviceInfo->name = deviceHwInfo->name;
   1192     devInfo->alsaName = deviceHwInfo->alsaName;
   1193     devInfo->isPlug = deviceHwInfo->isPlug;
   1194 
   1195     /* A: Storing pointer to PaAlsaDeviceInfo object as pointer to PaDeviceInfo object.
   1196      * Should now be safe to add device info, unless the device supports neither capture nor playback
   1197      */
   1198     if( baseDeviceInfo->maxInputChannels > 0 || baseDeviceInfo->maxOutputChannels > 0 )
   1199     {
   1200         /* Make device default if there isn't already one or it is the ALSA "default" device */
   1201         if( ( baseApi->info.defaultInputDevice == paNoDevice ||
   1202             !strcmp( deviceHwInfo->alsaName, "default" ) ) && baseDeviceInfo->maxInputChannels > 0 )
   1203         {
   1204             baseApi->info.defaultInputDevice = *devIdx;
   1205             PA_DEBUG(( "Default input device: %s\n", deviceHwInfo->name ));
   1206         }
   1207         if( ( baseApi->info.defaultOutputDevice == paNoDevice ||
   1208             !strcmp( deviceHwInfo->alsaName, "default" ) ) && baseDeviceInfo->maxOutputChannels > 0 )
   1209         {
   1210             baseApi->info.defaultOutputDevice = *devIdx;
   1211             PA_DEBUG(( "Default output device: %s\n", deviceHwInfo->name ));
   1212         }
   1213         PA_DEBUG(( "%s: Adding device %s: %d\n", __FUNCTION__, deviceHwInfo->name, *devIdx ));
   1214         baseApi->deviceInfos[*devIdx] = (PaDeviceInfo *) devInfo;
   1215         (*devIdx) += 1;
   1216     }
   1217     else
   1218     {
   1219         PA_DEBUG(( "%s: Skipped device: %s, all channels == 0\n", __FUNCTION__, deviceHwInfo->name ));
   1220     }
   1221 
   1222 end:
   1223     return result;
   1224 }
   1225 
   1226 /* Build PaDeviceInfo list, ignore devices for which we cannot determine capabilities (possibly busy, sigh) */
   1227 static PaError BuildDeviceList( PaAlsaHostApiRepresentation *alsaApi )
   1228 {
   1229     PaUtilHostApiRepresentation *baseApi = &alsaApi->baseHostApiRep;
   1230     PaAlsaDeviceInfo *deviceInfoArray;
   1231     int cardIdx = -1, devIdx = 0;
   1232     snd_ctl_card_info_t *cardInfo;
   1233     PaError result = paNoError;
   1234     size_t numDeviceNames = 0, maxDeviceNames = 1, i;
   1235     HwDevInfo *hwDevInfos = NULL;
   1236     snd_config_t *topNode = NULL;
   1237     snd_pcm_info_t *pcmInfo;
   1238     int res;
   1239     int blocking = SND_PCM_NONBLOCK;
   1240     int usePlughw = 0;
   1241     char *hwPrefix = "";
   1242     char alsaCardName[50];
   1243 #ifdef PA_ENABLE_DEBUG_OUTPUT
   1244     PaTime startTime = PaUtil_GetTime();
   1245 #endif
   1246 
   1247     if( getenv( "PA_ALSA_INITIALIZE_BLOCK" ) && atoi( getenv( "PA_ALSA_INITIALIZE_BLOCK" ) ) )
   1248         blocking = 0;
   1249 
   1250     /* If PA_ALSA_PLUGHW is 1 (non-zero), use the plughw: pcm throughout instead of hw: */
   1251     if( getenv( "PA_ALSA_PLUGHW" ) && atoi( getenv( "PA_ALSA_PLUGHW" ) ) )
   1252     {
   1253         usePlughw = 1;
   1254         hwPrefix = "plug";
   1255         PA_DEBUG(( "%s: Using Plughw\n", __FUNCTION__ ));
   1256     }
   1257 
   1258     /* These two will be set to the first working input and output device, respectively */
   1259     baseApi->info.defaultInputDevice = paNoDevice;
   1260     baseApi->info.defaultOutputDevice = paNoDevice;
   1261 
   1262     /* Gather info about hw devices
   1263 
   1264      * alsa_snd_card_next() modifies the integer passed to it to be:
   1265      *      the index of the first card if the parameter is -1
   1266      *      the index of the next card if the parameter is the index of a card
   1267      *      -1 if there are no more cards
   1268      *
   1269      * The function itself returns 0 if it succeeded. */
   1270     cardIdx = -1;
   1271     alsa_snd_ctl_card_info_alloca( &cardInfo );
   1272     alsa_snd_pcm_info_alloca( &pcmInfo );
   1273     while( alsa_snd_card_next( &cardIdx ) == 0 && cardIdx >= 0 )
   1274     {
   1275         char *cardName;
   1276         int devIdx = -1;
   1277         snd_ctl_t *ctl;
   1278         char buf[50];
   1279 
   1280         snprintf( alsaCardName, sizeof (alsaCardName), "hw:%d", cardIdx );
   1281 
   1282         /* Acquire name of card */
   1283         if( alsa_snd_ctl_open( &ctl, alsaCardName, 0 ) < 0 )
   1284         {
   1285             /* Unable to open card :( */
   1286             PA_DEBUG(( "%s: Unable to open device %s\n", __FUNCTION__, alsaCardName ));
   1287             continue;
   1288         }
   1289         alsa_snd_ctl_card_info( ctl, cardInfo );
   1290 
   1291         PA_ENSURE( PaAlsa_StrDup( alsaApi, &cardName, alsa_snd_ctl_card_info_get_name( cardInfo )) );
   1292 
   1293         while( alsa_snd_ctl_pcm_next_device( ctl, &devIdx ) == 0 && devIdx >= 0 )
   1294         {
   1295             char *alsaDeviceName, *deviceName, *infoName;
   1296             size_t len;
   1297             int hasPlayback = 0, hasCapture = 0;
   1298 
   1299             snprintf( buf, sizeof (buf), "%s%s,%d", hwPrefix, alsaCardName, devIdx );
   1300 
   1301             /* Obtain info about this particular device */
   1302             alsa_snd_pcm_info_set_device( pcmInfo, devIdx );
   1303             alsa_snd_pcm_info_set_subdevice( pcmInfo, 0 );
   1304             alsa_snd_pcm_info_set_stream( pcmInfo, SND_PCM_STREAM_CAPTURE );
   1305             if( alsa_snd_ctl_pcm_info( ctl, pcmInfo ) >= 0 )
   1306             {
   1307                 hasCapture = 1;
   1308             }
   1309 
   1310             alsa_snd_pcm_info_set_stream( pcmInfo, SND_PCM_STREAM_PLAYBACK );
   1311             if( alsa_snd_ctl_pcm_info( ctl, pcmInfo ) >= 0 )
   1312             {
   1313                 hasPlayback = 1;
   1314             }
   1315 
   1316             if( !hasPlayback && !hasCapture )
   1317             {
   1318                 /* Error */
   1319                 continue;
   1320             }
   1321 
   1322             infoName = SkipCardDetailsInName( (char *)alsa_snd_pcm_info_get_name( pcmInfo ), cardName );
   1323 
   1324             /* The length of the string written by snprintf plus terminating 0 */
   1325             len = snprintf( NULL, 0, "%s: %s (%s)", cardName, infoName, buf ) + 1;
   1326             PA_UNLESS( deviceName = (char *)PaUtil_GroupAllocateMemory( alsaApi->allocations, len ),
   1327                     paInsufficientMemory );
   1328             snprintf( deviceName, len, "%s: %s (%s)", cardName, infoName, buf );
   1329 
   1330             ++numDeviceNames;
   1331             if( !hwDevInfos || numDeviceNames > maxDeviceNames )
   1332             {
   1333                 maxDeviceNames *= 2;
   1334                 PA_UNLESS( hwDevInfos = (HwDevInfo *) realloc( hwDevInfos, maxDeviceNames * sizeof (HwDevInfo) ),
   1335                         paInsufficientMemory );
   1336             }
   1337 
   1338             PA_ENSURE( PaAlsa_StrDup( alsaApi, &alsaDeviceName, buf ) );
   1339 
   1340             hwDevInfos[ numDeviceNames - 1 ].alsaName = alsaDeviceName;
   1341             hwDevInfos[ numDeviceNames - 1 ].name = deviceName;
   1342             hwDevInfos[ numDeviceNames - 1 ].isPlug = usePlughw;
   1343             hwDevInfos[ numDeviceNames - 1 ].hasPlayback = hasPlayback;
   1344             hwDevInfos[ numDeviceNames - 1 ].hasCapture = hasCapture;
   1345         }
   1346         alsa_snd_ctl_close( ctl );
   1347     }
   1348 
   1349     /* Iterate over plugin devices */
   1350     if( NULL == (*alsa_snd_config) )
   1351     {
   1352         /* alsa_snd_config_update is called implicitly by some functions, if this hasn't happened snd_config will be NULL (bleh) */
   1353         ENSURE_( alsa_snd_config_update(), paUnanticipatedHostError );
   1354         PA_DEBUG(( "Updating snd_config\n" ));
   1355     }
   1356     assert( *alsa_snd_config );
   1357     if( ( res = alsa_snd_config_search( *alsa_snd_config, "pcm", &topNode ) ) >= 0 )
   1358     {
   1359         snd_config_iterator_t i, next;
   1360 
   1361         alsa_snd_config_for_each( i, next, topNode )
   1362         {
   1363             const char *tpStr = "unknown", *idStr = NULL;
   1364             int err = 0;
   1365 
   1366             char *alsaDeviceName, *deviceName;
   1367             const HwDevInfo *predefined = NULL;
   1368             snd_config_t *n = alsa_snd_config_iterator_entry( i ), * tp = NULL;;
   1369 
   1370             if( (err = alsa_snd_config_search( n, "type", &tp )) < 0 )
   1371             {
   1372                 if( -ENOENT != err )
   1373                 {
   1374                     ENSURE_(err, paUnanticipatedHostError);
   1375                 }
   1376             }
   1377             else
   1378             {
   1379                 ENSURE_( alsa_snd_config_get_string( tp, &tpStr ), paUnanticipatedHostError );
   1380             }
   1381             ENSURE_( alsa_snd_config_get_id( n, &idStr ), paUnanticipatedHostError );
   1382             if( IgnorePlugin( idStr ) )
   1383             {
   1384                 PA_DEBUG(( "%s: Ignoring ALSA plugin device [%s] of type [%s]\n", __FUNCTION__, idStr, tpStr ));
   1385                 continue;
   1386             }
   1387             PA_DEBUG(( "%s: Found plugin [%s] of type [%s]\n", __FUNCTION__, idStr, tpStr ));
   1388 
   1389             PA_UNLESS( alsaDeviceName = (char*)PaUtil_GroupAllocateMemory( alsaApi->allocations,
   1390                                                             strlen(idStr) + 6 ), paInsufficientMemory );
   1391             strcpy( alsaDeviceName, idStr );
   1392             PA_UNLESS( deviceName = (char*)PaUtil_GroupAllocateMemory( alsaApi->allocations,
   1393                                                             strlen(idStr) + 1 ), paInsufficientMemory );
   1394             strcpy( deviceName, idStr );
   1395 
   1396             ++numDeviceNames;
   1397             if( !hwDevInfos || numDeviceNames > maxDeviceNames )
   1398             {
   1399                 maxDeviceNames *= 2;
   1400                 PA_UNLESS( hwDevInfos = (HwDevInfo *) realloc( hwDevInfos, maxDeviceNames * sizeof (HwDevInfo) ),
   1401                         paInsufficientMemory );
   1402             }
   1403 
   1404             predefined = FindDeviceName( alsaDeviceName );
   1405 
   1406             hwDevInfos[numDeviceNames - 1].alsaName = alsaDeviceName;
   1407             hwDevInfos[numDeviceNames - 1].name     = deviceName;
   1408             hwDevInfos[numDeviceNames - 1].isPlug   = 1;
   1409 
   1410             if( predefined )
   1411             {
   1412                 hwDevInfos[numDeviceNames - 1].hasPlayback = predefined->hasPlayback;
   1413                 hwDevInfos[numDeviceNames - 1].hasCapture  = predefined->hasCapture;
   1414             }
   1415             else
   1416             {
   1417                 hwDevInfos[numDeviceNames - 1].hasPlayback = 1;
   1418                 hwDevInfos[numDeviceNames - 1].hasCapture  = 1;
   1419             }
   1420         }
   1421     }
   1422     else
   1423         PA_DEBUG(( "%s: Iterating over ALSA plugins failed: %s\n", __FUNCTION__, alsa_snd_strerror( res ) ));
   1424 
   1425     /* allocate deviceInfo memory based on the number of devices */
   1426     PA_UNLESS( baseApi->deviceInfos = (PaDeviceInfo**)PaUtil_GroupAllocateMemory(
   1427             alsaApi->allocations, sizeof(PaDeviceInfo*) * (numDeviceNames) ), paInsufficientMemory );
   1428 
   1429     /* allocate all device info structs in a contiguous block */
   1430     PA_UNLESS( deviceInfoArray = (PaAlsaDeviceInfo*)PaUtil_GroupAllocateMemory(
   1431             alsaApi->allocations, sizeof(PaAlsaDeviceInfo) * numDeviceNames ), paInsufficientMemory );
   1432 
   1433     /* Loop over list of cards, filling in info. If a device is deemed unavailable (can't get name),
   1434      * it's ignored.
   1435      *
   1436      * Note that we do this in two stages. This is a workaround owing to the fact that the 'dmix'
   1437      * plugin may cause the underlying hardware device to be busy for a short while even after it
   1438      * (dmix) is closed. The 'default' plugin may also point to the dmix plugin, so the same goes
   1439      * for this.
   1440      */
   1441     PA_DEBUG(( "%s: Filling device info for %d devices\n", __FUNCTION__, numDeviceNames ));
   1442     for( i = 0, devIdx = 0; i < numDeviceNames; ++i )
   1443     {
   1444         PaAlsaDeviceInfo* devInfo = &deviceInfoArray[i];
   1445         HwDevInfo* hwInfo = &hwDevInfos[i];
   1446         if( !strcmp( hwInfo->name, "dmix" ) || !strcmp( hwInfo->name, "default" ) )
   1447         {
   1448             continue;
   1449         }
   1450 
   1451         PA_ENSURE( FillInDevInfo( alsaApi, hwInfo, blocking, devInfo, &devIdx ) );
   1452     }
   1453     assert( devIdx < numDeviceNames );
   1454     /* Now inspect 'dmix' and 'default' plugins */
   1455     for( i = 0; i < numDeviceNames; ++i )
   1456     {
   1457         PaAlsaDeviceInfo* devInfo = &deviceInfoArray[i];
   1458         HwDevInfo* hwInfo = &hwDevInfos[i];
   1459         if( strcmp( hwInfo->name, "dmix" ) && strcmp( hwInfo->name, "default" ) )
   1460         {
   1461             continue;
   1462         }
   1463 
   1464         PA_ENSURE( FillInDevInfo( alsaApi, hwInfo, blocking, devInfo, &devIdx ) );
   1465     }
   1466     free( hwDevInfos );
   1467 
   1468     baseApi->info.deviceCount = devIdx;   /* Number of successfully queried devices */
   1469 
   1470 #ifdef PA_ENABLE_DEBUG_OUTPUT
   1471     PA_DEBUG(( "%s: Building device list took %f seconds\n", __FUNCTION__, PaUtil_GetTime() - startTime ));
   1472 #endif
   1473 
   1474 end:
   1475     return result;
   1476 
   1477 error:
   1478     /* No particular action */
   1479     goto end;
   1480 }
   1481 
   1482 /* Check against known device capabilities */
   1483 static PaError ValidateParameters( const PaStreamParameters *parameters, PaUtilHostApiRepresentation *hostApi, StreamDirection mode )
   1484 {
   1485     PaError result = paNoError;
   1486     int maxChans;
   1487     const PaAlsaDeviceInfo *deviceInfo = NULL;
   1488     assert( parameters );
   1489 
   1490     if( parameters->device != paUseHostApiSpecificDeviceSpecification )
   1491     {
   1492         assert( parameters->device < hostApi->info.deviceCount );
   1493         PA_UNLESS( parameters->hostApiSpecificStreamInfo == NULL, paBadIODeviceCombination );
   1494         deviceInfo = GetDeviceInfo( hostApi, parameters->device );
   1495     }
   1496     else
   1497     {
   1498         const PaAlsaStreamInfo *streamInfo = parameters->hostApiSpecificStreamInfo;
   1499 
   1500         PA_UNLESS( parameters->device == paUseHostApiSpecificDeviceSpecification, paInvalidDevice );
   1501         PA_UNLESS( streamInfo->size == sizeof (PaAlsaStreamInfo) && streamInfo->version == 1,
   1502                 paIncompatibleHostApiSpecificStreamInfo );
   1503         PA_UNLESS( streamInfo->deviceString != NULL, paInvalidDevice );
   1504 
   1505         /* Skip further checking */
   1506         return paNoError;
   1507     }
   1508 
   1509     assert( deviceInfo );
   1510     assert( parameters->hostApiSpecificStreamInfo == NULL );
   1511     maxChans = ( StreamDirection_In == mode ? deviceInfo->baseDeviceInfo.maxInputChannels :
   1512         deviceInfo->baseDeviceInfo.maxOutputChannels );
   1513     PA_UNLESS( parameters->channelCount <= maxChans, paInvalidChannelCount );
   1514 
   1515 error:
   1516     return result;
   1517 }
   1518 
   1519 /* Given an open stream, what sample formats are available? */
   1520 static PaSampleFormat GetAvailableFormats( snd_pcm_t *pcm )
   1521 {
   1522     PaSampleFormat available = 0;
   1523     snd_pcm_hw_params_t *hwParams;
   1524     alsa_snd_pcm_hw_params_alloca( &hwParams );
   1525 
   1526     alsa_snd_pcm_hw_params_any( pcm, hwParams );
   1527 
   1528     if( alsa_snd_pcm_hw_params_test_format( pcm, hwParams, SND_PCM_FORMAT_FLOAT ) >= 0)
   1529         available |= paFloat32;
   1530 
   1531     if( alsa_snd_pcm_hw_params_test_format( pcm, hwParams, SND_PCM_FORMAT_S32 ) >= 0)
   1532         available |= paInt32;
   1533 
   1534 #ifdef PA_LITTLE_ENDIAN
   1535     if( alsa_snd_pcm_hw_params_test_format( pcm, hwParams, SND_PCM_FORMAT_S24_3LE ) >= 0)
   1536         available |= paInt24;
   1537 #elif defined PA_BIG_ENDIAN
   1538     if( alsa_snd_pcm_hw_params_test_format( pcm, hwParams, SND_PCM_FORMAT_S24_3BE ) >= 0)
   1539         available |= paInt24;
   1540 #endif
   1541 
   1542     if( alsa_snd_pcm_hw_params_test_format( pcm, hwParams, SND_PCM_FORMAT_S16 ) >= 0)
   1543         available |= paInt16;
   1544 
   1545     if( alsa_snd_pcm_hw_params_test_format( pcm, hwParams, SND_PCM_FORMAT_U8 ) >= 0)
   1546         available |= paUInt8;
   1547 
   1548     if( alsa_snd_pcm_hw_params_test_format( pcm, hwParams, SND_PCM_FORMAT_S8 ) >= 0)
   1549         available |= paInt8;
   1550 
   1551     return available;
   1552 }
   1553 
   1554 /* Output to console all formats supported by device */
   1555 static void LogAllAvailableFormats( snd_pcm_t *pcm )
   1556 {
   1557     PaSampleFormat available = 0;
   1558     snd_pcm_hw_params_t *hwParams;
   1559     alsa_snd_pcm_hw_params_alloca( &hwParams );
   1560 
   1561     alsa_snd_pcm_hw_params_any( pcm, hwParams );
   1562 
   1563     PA_DEBUG(( " --- Supported Formats ---\n" ));
   1564 
   1565     if( alsa_snd_pcm_hw_params_test_format( pcm, hwParams, SND_PCM_FORMAT_S8 ) >= 0)
   1566         PA_DEBUG(( "SND_PCM_FORMAT_S8\n" ));
   1567     if( alsa_snd_pcm_hw_params_test_format( pcm, hwParams, SND_PCM_FORMAT_U8 ) >= 0)
   1568         PA_DEBUG(( "SND_PCM_FORMAT_U8\n" ));
   1569 
   1570     if( alsa_snd_pcm_hw_params_test_format( pcm, hwParams, SND_PCM_FORMAT_S16_LE ) >= 0)
   1571         PA_DEBUG(( "SND_PCM_FORMAT_S16_LE\n" ));
   1572     if( alsa_snd_pcm_hw_params_test_format( pcm, hwParams, SND_PCM_FORMAT_S16_BE ) >= 0)
   1573         PA_DEBUG(( "SND_PCM_FORMAT_S16_BE\n" ));
   1574 
   1575     if( alsa_snd_pcm_hw_params_test_format( pcm, hwParams, SND_PCM_FORMAT_U16_LE ) >= 0)
   1576         PA_DEBUG(( "SND_PCM_FORMAT_U16_LE\n" ));
   1577     if( alsa_snd_pcm_hw_params_test_format( pcm, hwParams, SND_PCM_FORMAT_U16_BE ) >= 0)
   1578         PA_DEBUG(( "SND_PCM_FORMAT_U16_BE\n" ));
   1579 
   1580     if( alsa_snd_pcm_hw_params_test_format( pcm, hwParams, SND_PCM_FORMAT_S24_LE ) >= 0)
   1581         PA_DEBUG(( "SND_PCM_FORMAT_S24_LE\n" ));
   1582     if( alsa_snd_pcm_hw_params_test_format( pcm, hwParams, SND_PCM_FORMAT_S24_BE ) >= 0)
   1583         PA_DEBUG(( "SND_PCM_FORMAT_S24_BE\n" ));
   1584 
   1585     if( alsa_snd_pcm_hw_params_test_format( pcm, hwParams, SND_PCM_FORMAT_U24_LE ) >= 0)
   1586         PA_DEBUG(( "SND_PCM_FORMAT_U24_LE\n" ));
   1587     if( alsa_snd_pcm_hw_params_test_format( pcm, hwParams, SND_PCM_FORMAT_U24_BE ) >= 0)
   1588         PA_DEBUG(( "SND_PCM_FORMAT_U24_BE\n" ));
   1589 
   1590     if( alsa_snd_pcm_hw_params_test_format( pcm, hwParams, SND_PCM_FORMAT_FLOAT_LE ) >= 0)
   1591         PA_DEBUG(( "SND_PCM_FORMAT_FLOAT_LE\n" ));
   1592     if( alsa_snd_pcm_hw_params_test_format( pcm, hwParams, SND_PCM_FORMAT_FLOAT_BE ) >= 0)
   1593         PA_DEBUG(( "SND_PCM_FORMAT_FLOAT_BE\n" ));
   1594 
   1595     if( alsa_snd_pcm_hw_params_test_format( pcm, hwParams, SND_PCM_FORMAT_FLOAT64_LE ) >= 0)
   1596         PA_DEBUG(( "SND_PCM_FORMAT_FLOAT64_LE\n" ));
   1597     if( alsa_snd_pcm_hw_params_test_format( pcm, hwParams, SND_PCM_FORMAT_FLOAT64_BE ) >= 0)
   1598         PA_DEBUG(( "SND_PCM_FORMAT_FLOAT64_BE\n" ));
   1599 
   1600     if( alsa_snd_pcm_hw_params_test_format( pcm, hwParams, SND_PCM_FORMAT_IEC958_SUBFRAME_LE ) >= 0)
   1601         PA_DEBUG(( "SND_PCM_FORMAT_IEC958_SUBFRAME_LE\n" ));
   1602     if( alsa_snd_pcm_hw_params_test_format( pcm, hwParams, SND_PCM_FORMAT_IEC958_SUBFRAME_BE ) >= 0)
   1603         PA_DEBUG(( "SND_PCM_FORMAT_IEC958_SUBFRAME_BE\n" ));
   1604 
   1605     if( alsa_snd_pcm_hw_params_test_format( pcm, hwParams, SND_PCM_FORMAT_MU_LAW ) >= 0)
   1606         PA_DEBUG(( "SND_PCM_FORMAT_MU_LAW\n" ));
   1607     if( alsa_snd_pcm_hw_params_test_format( pcm, hwParams, SND_PCM_FORMAT_A_LAW ) >= 0)
   1608         PA_DEBUG(( "SND_PCM_FORMAT_A_LAW\n" ));
   1609 
   1610     if( alsa_snd_pcm_hw_params_test_format( pcm, hwParams, SND_PCM_FORMAT_IMA_ADPCM ) >= 0)
   1611         PA_DEBUG(( "SND_PCM_FORMAT_IMA_ADPCM\n" ));
   1612     if( alsa_snd_pcm_hw_params_test_format( pcm, hwParams, SND_PCM_FORMAT_MPEG ) >= 0)
   1613         PA_DEBUG(( "SND_PCM_FORMAT_MPEG\n" ));
   1614 
   1615     if( alsa_snd_pcm_hw_params_test_format( pcm, hwParams, SND_PCM_FORMAT_GSM ) >= 0)
   1616         PA_DEBUG(( "SND_PCM_FORMAT_GSM\n" ));
   1617     if( alsa_snd_pcm_hw_params_test_format( pcm, hwParams, SND_PCM_FORMAT_SPECIAL ) >= 0)
   1618         PA_DEBUG(( "SND_PCM_FORMAT_SPECIAL\n" ));
   1619 
   1620     if( alsa_snd_pcm_hw_params_test_format( pcm, hwParams, SND_PCM_FORMAT_S24_3LE ) >= 0)
   1621         PA_DEBUG(( "SND_PCM_FORMAT_S24_3LE\n" ));
   1622     if( alsa_snd_pcm_hw_params_test_format( pcm, hwParams, SND_PCM_FORMAT_S24_3BE ) >= 0)
   1623         PA_DEBUG(( "SND_PCM_FORMAT_S24_3BE\n" ));
   1624 
   1625     if( alsa_snd_pcm_hw_params_test_format( pcm, hwParams, SND_PCM_FORMAT_U24_3LE ) >= 0)
   1626         PA_DEBUG(( "SND_PCM_FORMAT_U24_3LE\n" ));
   1627     if( alsa_snd_pcm_hw_params_test_format( pcm, hwParams, SND_PCM_FORMAT_U24_3BE ) >= 0)
   1628         PA_DEBUG(( "SND_PCM_FORMAT_U24_3BE\n" ));
   1629 
   1630     if( alsa_snd_pcm_hw_params_test_format( pcm, hwParams, SND_PCM_FORMAT_S20_3LE ) >= 0)
   1631         PA_DEBUG(( "SND_PCM_FORMAT_S20_3LE\n" ));
   1632     if( alsa_snd_pcm_hw_params_test_format( pcm, hwParams, SND_PCM_FORMAT_S20_3BE ) >= 0)
   1633         PA_DEBUG(( "SND_PCM_FORMAT_S20_3BE\n" ));
   1634 
   1635     if( alsa_snd_pcm_hw_params_test_format( pcm, hwParams, SND_PCM_FORMAT_U20_3LE ) >= 0)
   1636         PA_DEBUG(( "SND_PCM_FORMAT_U20_3LE\n" ));
   1637     if( alsa_snd_pcm_hw_params_test_format( pcm, hwParams, SND_PCM_FORMAT_U20_3BE ) >= 0)
   1638         PA_DEBUG(( "SND_PCM_FORMAT_U20_3BE\n" ));
   1639 
   1640     if( alsa_snd_pcm_hw_params_test_format( pcm, hwParams, SND_PCM_FORMAT_S18_3LE ) >= 0)
   1641         PA_DEBUG(( "SND_PCM_FORMAT_S18_3LE\n" ));
   1642     if( alsa_snd_pcm_hw_params_test_format( pcm, hwParams, SND_PCM_FORMAT_S18_3BE ) >= 0)
   1643         PA_DEBUG(( "SND_PCM_FORMAT_S18_3BE\n" ));
   1644 
   1645     if( alsa_snd_pcm_hw_params_test_format( pcm, hwParams, SND_PCM_FORMAT_U18_3LE ) >= 0)
   1646         PA_DEBUG(( "SND_PCM_FORMAT_U18_3LE\n" ));
   1647     if( alsa_snd_pcm_hw_params_test_format( pcm, hwParams, SND_PCM_FORMAT_U18_3BE ) >= 0)
   1648         PA_DEBUG(( "SND_PCM_FORMAT_U18_3BE\n" ));
   1649 
   1650     if( alsa_snd_pcm_hw_params_test_format( pcm, hwParams, SND_PCM_FORMAT_S16 ) >= 0)
   1651         PA_DEBUG(( "SND_PCM_FORMAT_S16\n" ));
   1652     if( alsa_snd_pcm_hw_params_test_format( pcm, hwParams, SND_PCM_FORMAT_U16 ) >= 0)
   1653         PA_DEBUG(( "SND_PCM_FORMAT_U16\n" ));
   1654 
   1655     if( alsa_snd_pcm_hw_params_test_format( pcm, hwParams, SND_PCM_FORMAT_S24 ) >= 0)
   1656         PA_DEBUG(( "SND_PCM_FORMAT_S24\n" ));
   1657     if( alsa_snd_pcm_hw_params_test_format( pcm, hwParams, SND_PCM_FORMAT_U24 ) >= 0)
   1658         PA_DEBUG(( "SND_PCM_FORMAT_U24\n" ));
   1659 
   1660     if( alsa_snd_pcm_hw_params_test_format( pcm, hwParams, SND_PCM_FORMAT_S32 ) >= 0)
   1661         PA_DEBUG(( "SND_PCM_FORMAT_S32\n" ));
   1662     if( alsa_snd_pcm_hw_params_test_format( pcm, hwParams, SND_PCM_FORMAT_U32 ) >= 0)
   1663         PA_DEBUG(( "SND_PCM_FORMAT_U32\n" ));
   1664 
   1665     if( alsa_snd_pcm_hw_params_test_format( pcm, hwParams, SND_PCM_FORMAT_FLOAT ) >= 0)
   1666         PA_DEBUG(( "SND_PCM_FORMAT_FLOAT\n" ));
   1667     if( alsa_snd_pcm_hw_params_test_format( pcm, hwParams, SND_PCM_FORMAT_FLOAT64 ) >= 0)
   1668         PA_DEBUG(( "SND_PCM_FORMAT_FLOAT64\n" ));
   1669 
   1670     if( alsa_snd_pcm_hw_params_test_format( pcm, hwParams, SND_PCM_FORMAT_IEC958_SUBFRAME ) >= 0)
   1671         PA_DEBUG(( "SND_PCM_FORMAT_IEC958_SUBFRAME\n" ));
   1672 
   1673     PA_DEBUG(( " -------------------------\n" ));
   1674 }
   1675 
   1676 static snd_pcm_format_t Pa2AlsaFormat( PaSampleFormat paFormat )
   1677 {
   1678     switch( paFormat )
   1679     {
   1680         case paFloat32:
   1681             return SND_PCM_FORMAT_FLOAT;
   1682 
   1683         case paInt16:
   1684             return SND_PCM_FORMAT_S16;
   1685 
   1686         case paInt24:
   1687 #ifdef PA_LITTLE_ENDIAN
   1688             return SND_PCM_FORMAT_S24_3LE;
   1689 #elif defined PA_BIG_ENDIAN
   1690             return SND_PCM_FORMAT_S24_3BE;
   1691 #endif
   1692 
   1693         case paInt32:
   1694             return SND_PCM_FORMAT_S32;
   1695 
   1696         case paInt8:
   1697             return SND_PCM_FORMAT_S8;
   1698 
   1699         case paUInt8:
   1700             return SND_PCM_FORMAT_U8;
   1701 
   1702         default:
   1703             return SND_PCM_FORMAT_UNKNOWN;
   1704     }
   1705 }
   1706 
   1707 /** Open an ALSA pcm handle.
   1708  *
   1709  * The device to be open can be specified by name in a custom PaAlsaStreamInfo struct, or it will be by
   1710  * the Portaudio device number supplied in the stream parameters.
   1711  */
   1712 static PaError AlsaOpen( const PaUtilHostApiRepresentation *hostApi, const PaStreamParameters *params, StreamDirection
   1713         streamDir, snd_pcm_t **pcm )
   1714 {
   1715     PaError result = paNoError;
   1716     int ret;
   1717     const char* deviceName = "";
   1718     const PaAlsaDeviceInfo *deviceInfo = NULL;
   1719     PaAlsaStreamInfo *streamInfo = (PaAlsaStreamInfo *)params->hostApiSpecificStreamInfo;
   1720 
   1721     if( !streamInfo )
   1722     {
   1723         deviceInfo = GetDeviceInfo( hostApi, params->device );
   1724         deviceName = deviceInfo->alsaName;
   1725     }
   1726     else
   1727         deviceName = streamInfo->deviceString;
   1728 
   1729     PA_DEBUG(( "%s: Opening device %s\n", __FUNCTION__, deviceName ));
   1730     if( (ret = OpenPcm( pcm, deviceName, streamDir == StreamDirection_In ? SND_PCM_STREAM_CAPTURE : SND_PCM_STREAM_PLAYBACK,
   1731                     SND_PCM_NONBLOCK, 1 )) < 0 )
   1732     {
   1733         /* Not to be closed */
   1734         *pcm = NULL;
   1735         ENSURE_( ret, -EBUSY == ret ? paDeviceUnavailable : paBadIODeviceCombination );
   1736     }
   1737     ENSURE_( alsa_snd_pcm_nonblock( *pcm, 0 ), paUnanticipatedHostError );
   1738 
   1739 end:
   1740     return result;
   1741 
   1742 error:
   1743     goto end;
   1744 }
   1745 
   1746 static PaError TestParameters( const PaUtilHostApiRepresentation *hostApi, const PaStreamParameters *parameters,
   1747         double sampleRate, StreamDirection streamDir )
   1748 {
   1749     PaError result = paNoError;
   1750     snd_pcm_t *pcm = NULL;
   1751     PaSampleFormat availableFormats;
   1752     /* We are able to adapt to a number of channels less than what the device supports */
   1753     unsigned int numHostChannels;
   1754     PaSampleFormat hostFormat;
   1755     snd_pcm_hw_params_t *hwParams;
   1756     alsa_snd_pcm_hw_params_alloca( &hwParams );
   1757 
   1758     if( !parameters->hostApiSpecificStreamInfo )
   1759     {
   1760         const PaAlsaDeviceInfo *devInfo = GetDeviceInfo( hostApi, parameters->device );
   1761         numHostChannels = PA_MAX( parameters->channelCount, StreamDirection_In == streamDir ?
   1762                 devInfo->minInputChannels : devInfo->minOutputChannels );
   1763     }
   1764     else
   1765         numHostChannels = parameters->channelCount;
   1766 
   1767     PA_ENSURE( AlsaOpen( hostApi, parameters, streamDir, &pcm ) );
   1768 
   1769     alsa_snd_pcm_hw_params_any( pcm, hwParams );
   1770 
   1771     if( SetApproximateSampleRate( pcm, hwParams, sampleRate ) < 0 )
   1772     {
   1773         result = paInvalidSampleRate;
   1774         goto error;
   1775     }
   1776 
   1777     if( alsa_snd_pcm_hw_params_set_channels( pcm, hwParams, numHostChannels ) < 0 )
   1778     {
   1779         result = paInvalidChannelCount;
   1780         goto error;
   1781     }
   1782 
   1783     /* See if we can find a best possible match */
   1784     availableFormats = GetAvailableFormats( pcm );
   1785     PA_ENSURE( hostFormat = PaUtil_SelectClosestAvailableFormat( availableFormats, parameters->sampleFormat ) );
   1786 
   1787     /* Some specific hardware (reported: Audio8 DJ) can fail with assertion during this step. */
   1788     ENSURE_( alsa_snd_pcm_hw_params_set_format( pcm, hwParams, Pa2AlsaFormat( hostFormat ) ), paUnanticipatedHostError );
   1789 
   1790     {
   1791         /* It happens that this call fails because the device is busy */
   1792         int ret = 0;
   1793         if( ( ret = alsa_snd_pcm_hw_params( pcm, hwParams ) ) < 0 )
   1794         {
   1795             if( -EINVAL == ret )
   1796             {
   1797                 /* Don't know what to return here */
   1798                 result = paBadIODeviceCombination;
   1799                 goto error;
   1800             }
   1801             else if( -EBUSY == ret )
   1802             {
   1803                 result = paDeviceUnavailable;
   1804                 PA_DEBUG(( "%s: Device is busy\n", __FUNCTION__ ));
   1805             }
   1806             else
   1807             {
   1808                 result = paUnanticipatedHostError;
   1809             }
   1810 
   1811             ENSURE_( ret, result );
   1812         }
   1813     }
   1814 
   1815 end:
   1816     if( pcm )
   1817     {
   1818         alsa_snd_pcm_close( pcm );
   1819     }
   1820     return result;
   1821 
   1822 error:
   1823     goto end;
   1824 }
   1825 
   1826 static PaError IsFormatSupported( struct PaUtilHostApiRepresentation *hostApi,
   1827                                   const PaStreamParameters *inputParameters,
   1828                                   const PaStreamParameters *outputParameters,
   1829                                   double sampleRate )
   1830 {
   1831     int inputChannelCount = 0, outputChannelCount = 0;
   1832     PaSampleFormat inputSampleFormat, outputSampleFormat;
   1833     PaError result = paFormatIsSupported;
   1834 
   1835     if( inputParameters )
   1836     {
   1837         PA_ENSURE( ValidateParameters( inputParameters, hostApi, StreamDirection_In ) );
   1838 
   1839         inputChannelCount = inputParameters->channelCount;
   1840         inputSampleFormat = inputParameters->sampleFormat;
   1841     }
   1842 
   1843     if( outputParameters )
   1844     {
   1845         PA_ENSURE( ValidateParameters( outputParameters, hostApi, StreamDirection_Out ) );
   1846 
   1847         outputChannelCount = outputParameters->channelCount;
   1848         outputSampleFormat = outputParameters->sampleFormat;
   1849     }
   1850 
   1851     if( inputChannelCount )
   1852     {
   1853         if( ( result = TestParameters( hostApi, inputParameters, sampleRate, StreamDirection_In ) )
   1854                 != paNoError )
   1855             goto error;
   1856     }
   1857     if ( outputChannelCount )
   1858     {
   1859         if( ( result = TestParameters( hostApi, outputParameters, sampleRate, StreamDirection_Out ) )
   1860                 != paNoError )
   1861             goto error;
   1862     }
   1863 
   1864     return paFormatIsSupported;
   1865 
   1866 error:
   1867     return result;
   1868 }
   1869 
   1870 
   1871 static PaError PaAlsaStreamComponent_Initialize( PaAlsaStreamComponent *self, PaAlsaHostApiRepresentation *alsaApi,
   1872         const PaStreamParameters *params, StreamDirection streamDir, int callbackMode )
   1873 {
   1874     PaError result = paNoError;
   1875     PaSampleFormat userSampleFormat = params->sampleFormat, hostSampleFormat = paNoError;
   1876     assert( params->channelCount > 0 );
   1877 
   1878     /* Make sure things have an initial value */
   1879     memset( self, 0, sizeof (PaAlsaStreamComponent) );
   1880 
   1881     if( NULL == params->hostApiSpecificStreamInfo )
   1882     {
   1883         const PaAlsaDeviceInfo *devInfo = GetDeviceInfo( &alsaApi->baseHostApiRep, params->device );
   1884         self->numHostChannels = PA_MAX( params->channelCount, StreamDirection_In == streamDir ? devInfo->minInputChannels
   1885                 : devInfo->minOutputChannels );
   1886         self->deviceIsPlug = devInfo->isPlug;
   1887         PA_DEBUG(( "%s: Host Chans %c %i\n", __FUNCTION__, streamDir == StreamDirection_In ? 'C' : 'P', self->numHostChannels ));
   1888     }
   1889     else
   1890     {
   1891         /* We're blissfully unaware of the minimum channelCount */
   1892         self->numHostChannels = params->channelCount;
   1893         /* Check if device name does not start with hw: to determine if it is a 'plug' device */
   1894         if( strncmp( "hw:", ((PaAlsaStreamInfo *)params->hostApiSpecificStreamInfo)->deviceString, 3 ) != 0  )
   1895             self->deviceIsPlug = 1; /* An Alsa plug device, not a direct hw device */
   1896     }
   1897     if( self->deviceIsPlug && alsaApi->alsaLibVersion < ALSA_VERSION_INT( 1, 0, 16 ) )
   1898         self->useReventFix = 1; /* Prior to Alsa1.0.16, plug devices may stutter without this fix */
   1899 
   1900     self->device = params->device;
   1901 
   1902     PA_ENSURE( AlsaOpen( &alsaApi->baseHostApiRep, params, streamDir, &self->pcm ) );
   1903     self->nfds = alsa_snd_pcm_poll_descriptors_count( self->pcm );
   1904 
   1905     PA_ENSURE( hostSampleFormat = PaUtil_SelectClosestAvailableFormat( GetAvailableFormats( self->pcm ), userSampleFormat ) );
   1906 
   1907     self->hostSampleFormat = hostSampleFormat;
   1908     self->nativeFormat = Pa2AlsaFormat( hostSampleFormat );
   1909     self->hostInterleaved = self->userInterleaved = !( userSampleFormat & paNonInterleaved );
   1910     self->numUserChannels = params->channelCount;
   1911     self->streamDir = streamDir;
   1912     self->canMmap = 0;
   1913     self->nonMmapBuffer = NULL;
   1914     self->nonMmapBufferSize = 0;
   1915 
   1916     if( !callbackMode && !self->userInterleaved )
   1917     {
   1918         /* Pre-allocate non-interleaved user provided buffers */
   1919         PA_UNLESS( self->userBuffers = PaUtil_AllocateMemory( sizeof (void *) * self->numUserChannels ),
   1920                 paInsufficientMemory );
   1921     }
   1922 
   1923 error:
   1924 
   1925     /* Log all available formats. */
   1926     if ( hostSampleFormat == paSampleFormatNotSupported )
   1927     {
   1928         LogAllAvailableFormats( self->pcm );
   1929         PA_DEBUG(( "%s: Please provide the log output to PortAudio developers, your hardware does not have any sample format implemented yet.\n", __FUNCTION__ ));
   1930     }
   1931 
   1932     return result;
   1933 }
   1934 
   1935 static void PaAlsaStreamComponent_Terminate( PaAlsaStreamComponent *self )
   1936 {
   1937     alsa_snd_pcm_close( self->pcm );
   1938     PaUtil_FreeMemory( self->userBuffers ); /* (Ptr can be NULL; PaUtil_FreeMemory includes a NULL check) */
   1939     PaUtil_FreeMemory( self->nonMmapBuffer );
   1940 }
   1941 
   1942 /*
   1943 static int nearbyint_(float value) {
   1944     if(  value - (int)value > .5 )
   1945         return (int)ceil( value );
   1946     return (int)floor( value );
   1947 }
   1948 */
   1949 
   1950 /** Initiate configuration, preparing for determining a period size suitable for both capture and playback components.
   1951  *
   1952  */
   1953 static PaError PaAlsaStreamComponent_InitialConfigure( PaAlsaStreamComponent *self, const PaStreamParameters *params,
   1954         int primeBuffers, snd_pcm_hw_params_t *hwParams, double *sampleRate )
   1955 {
   1956     /* Configuration consists of setting all of ALSA's parameters.
   1957      * These parameters come in two flavors: hardware parameters
   1958      * and software paramters.  Hardware parameters will affect
   1959      * the way the device is initialized, software parameters
   1960      * affect the way ALSA interacts with me, the user-level client.
   1961      */
   1962 
   1963     PaError result = paNoError;
   1964     snd_pcm_access_t accessMode, alternateAccessMode;
   1965     int dir = 0;
   1966     snd_pcm_t *pcm = self->pcm;
   1967     double sr = *sampleRate;
   1968     unsigned int minPeriods = 2;
   1969 
   1970     /* self->framesPerPeriod = framesPerHostBuffer; */
   1971 
   1972     /* ... fill up the configuration space with all possibile
   1973      * combinations of parameters this device will accept */
   1974     ENSURE_( alsa_snd_pcm_hw_params_any( pcm, hwParams ), paUnanticipatedHostError );
   1975 
   1976     ENSURE_( alsa_snd_pcm_hw_params_set_periods_integer( pcm, hwParams ), paUnanticipatedHostError );
   1977     /* I think there should be at least 2 periods (even though ALSA doesn't appear to enforce this) */
   1978     dir = 0;
   1979     ENSURE_( alsa_snd_pcm_hw_params_set_periods_min( pcm, hwParams, &minPeriods, &dir ), paUnanticipatedHostError );
   1980 
   1981     if( self->userInterleaved )
   1982     {
   1983         accessMode          = SND_PCM_ACCESS_MMAP_INTERLEAVED;
   1984         alternateAccessMode = SND_PCM_ACCESS_MMAP_NONINTERLEAVED;
   1985 
   1986         /* test if MMAP supported */
   1987         self->canMmap = alsa_snd_pcm_hw_params_test_access( pcm, hwParams, accessMode ) >= 0 ||
   1988                         alsa_snd_pcm_hw_params_test_access( pcm, hwParams, alternateAccessMode ) >= 0;
   1989 
   1990         PA_DEBUG(( "%s: device MMAP SND_PCM_ACCESS_MMAP_INTERLEAVED: %s\n", __FUNCTION__, ( alsa_snd_pcm_hw_params_test_access( pcm, hwParams, accessMode ) >= 0 ? "YES" : "NO" ) ));
   1991         PA_DEBUG(( "%s: device MMAP SND_PCM_ACCESS_MMAP_NONINTERLEAVED: %s\n", __FUNCTION__, ( alsa_snd_pcm_hw_params_test_access( pcm, hwParams, alternateAccessMode ) >= 0 ? "YES" : "NO" ) ));
   1992 
   1993         if( !self->canMmap )
   1994         {
   1995             accessMode          = SND_PCM_ACCESS_RW_INTERLEAVED;
   1996             alternateAccessMode = SND_PCM_ACCESS_RW_NONINTERLEAVED;
   1997         }
   1998     }
   1999     else
   2000     {
   2001         accessMode          = SND_PCM_ACCESS_MMAP_NONINTERLEAVED;
   2002         alternateAccessMode = SND_PCM_ACCESS_MMAP_INTERLEAVED;
   2003 
   2004         /* test if MMAP supported */
   2005         self->canMmap = alsa_snd_pcm_hw_params_test_access( pcm, hwParams, accessMode ) >= 0 ||
   2006                         alsa_snd_pcm_hw_params_test_access( pcm, hwParams, alternateAccessMode ) >= 0;
   2007 
   2008         PA_DEBUG((" %s: device MMAP SND_PCM_ACCESS_MMAP_NONINTERLEAVED: %s\n", __FUNCTION__, ( alsa_snd_pcm_hw_params_test_access( pcm, hwParams, accessMode ) >= 0 ? "YES" : "NO" ) ));
   2009         PA_DEBUG(( "%s: device MMAP SND_PCM_ACCESS_MMAP_INTERLEAVED: %s\n", __FUNCTION__, ( alsa_snd_pcm_hw_params_test_access( pcm, hwParams, alternateAccessMode ) >= 0 ? "YES" : "NO" ) ));
   2010 
   2011         if( !self->canMmap )
   2012         {
   2013             accessMode          = SND_PCM_ACCESS_RW_NONINTERLEAVED;
   2014             alternateAccessMode = SND_PCM_ACCESS_RW_INTERLEAVED;
   2015         }
   2016     }
   2017 
   2018     PA_DEBUG(( "%s: device can MMAP: %s\n", __FUNCTION__, ( self->canMmap ? "YES" : "NO" ) ));
   2019 
   2020     /* If requested access mode fails, try alternate mode */
   2021     if( alsa_snd_pcm_hw_params_set_access( pcm, hwParams, accessMode ) < 0 )
   2022     {
   2023         int err = 0;
   2024         if( ( err = alsa_snd_pcm_hw_params_set_access( pcm, hwParams, alternateAccessMode )) < 0 )
   2025         {
   2026             result = paUnanticipatedHostError;
   2027             PaUtil_SetLastHostErrorInfo( paALSA, err, alsa_snd_strerror( err ) );
   2028             goto error;
   2029         }
   2030         /* Flip mode */
   2031         self->hostInterleaved = !self->userInterleaved;
   2032     }
   2033 
   2034     /* Some specific hardware (reported: Audio8 DJ) can fail with assertion during this step. */
   2035     ENSURE_( alsa_snd_pcm_hw_params_set_format( pcm, hwParams, self->nativeFormat ), paUnanticipatedHostError );
   2036 
   2037     if( ( result = SetApproximateSampleRate( pcm, hwParams, sr )) != paUnanticipatedHostError )
   2038     {
   2039         ENSURE_( GetExactSampleRate( hwParams, &sr ), paUnanticipatedHostError );
   2040         if( result == paInvalidSampleRate ) /* From the SetApproximateSampleRate() call above */
   2041         { /* The sample rate was returned as 'out of tolerance' of the one requested */
   2042             PA_DEBUG(( "%s: Wanted %.3f, closest sample rate was %.3f\n", __FUNCTION__, sampleRate, sr ));
   2043             PA_ENSURE( paInvalidSampleRate );
   2044         }
   2045     }
   2046     else
   2047     {
   2048        PA_ENSURE( paUnanticipatedHostError );
   2049     }
   2050 
   2051     ENSURE_( alsa_snd_pcm_hw_params_set_channels( pcm, hwParams, self->numHostChannels ), paInvalidChannelCount );
   2052 
   2053     *sampleRate = sr;
   2054 
   2055 end:
   2056     return result;
   2057 
   2058 error:
   2059     /* No particular action */
   2060     goto end;
   2061 }
   2062 
   2063 /** Finish the configuration of the component's ALSA device.
   2064  *
   2065  * As part of this method, the component's alsaBufferSize attribute will be set.
   2066  * @param latency: The latency for this component.
   2067  */
   2068 static PaError PaAlsaStreamComponent_FinishConfigure( PaAlsaStreamComponent *self, snd_pcm_hw_params_t* hwParams,
   2069         const PaStreamParameters *params, int primeBuffers, double sampleRate, PaTime* latency )
   2070 {
   2071     PaError result = paNoError;
   2072     snd_pcm_sw_params_t* swParams;
   2073     snd_pcm_uframes_t bufSz = 0;
   2074     *latency = -1.;
   2075 
   2076     alsa_snd_pcm_sw_params_alloca( &swParams );
   2077 
   2078     bufSz = params->suggestedLatency * sampleRate + self->framesPerPeriod;
   2079     ENSURE_( alsa_snd_pcm_hw_params_set_buffer_size_near( self->pcm, hwParams, &bufSz ), paUnanticipatedHostError );
   2080 
   2081     /* Set the parameters! */
   2082     {
   2083         int r = alsa_snd_pcm_hw_params( self->pcm, hwParams );
   2084 #ifdef PA_ENABLE_DEBUG_OUTPUT
   2085         if( r < 0 )
   2086         {
   2087             snd_output_t *output = NULL;
   2088             alsa_snd_output_stdio_attach( &output, stderr, 0 );
   2089             alsa_snd_pcm_hw_params_dump( hwParams, output );
   2090         }
   2091 #endif
   2092         ENSURE_( r, paUnanticipatedHostError );
   2093     }
   2094     if( alsa_snd_pcm_hw_params_get_buffer_size != NULL )
   2095     {
   2096         ENSURE_( alsa_snd_pcm_hw_params_get_buffer_size( hwParams, &self->alsaBufferSize ), paUnanticipatedHostError );
   2097     }
   2098     else
   2099     {
   2100         self->alsaBufferSize = bufSz;
   2101     }
   2102 
   2103     /* Latency in seconds */
   2104     *latency = (self->alsaBufferSize - self->framesPerPeriod) / sampleRate;
   2105 
   2106     /* Now software parameters... */
   2107     ENSURE_( alsa_snd_pcm_sw_params_current( self->pcm, swParams ), paUnanticipatedHostError );
   2108 
   2109     ENSURE_( alsa_snd_pcm_sw_params_set_start_threshold( self->pcm, swParams, self->framesPerPeriod ), paUnanticipatedHostError );
   2110     ENSURE_( alsa_snd_pcm_sw_params_set_stop_threshold( self->pcm, swParams, self->alsaBufferSize ), paUnanticipatedHostError );
   2111 
   2112     /* Silence buffer in the case of underrun */
   2113     if( !primeBuffers ) /* XXX: Make sense? */
   2114     {
   2115         snd_pcm_uframes_t boundary;
   2116         ENSURE_( alsa_snd_pcm_sw_params_get_boundary( swParams, &boundary ), paUnanticipatedHostError );
   2117         ENSURE_( alsa_snd_pcm_sw_params_set_silence_threshold( self->pcm, swParams, 0 ), paUnanticipatedHostError );
   2118         ENSURE_( alsa_snd_pcm_sw_params_set_silence_size( self->pcm, swParams, boundary ), paUnanticipatedHostError );
   2119     }
   2120 
   2121     ENSURE_( alsa_snd_pcm_sw_params_set_avail_min( self->pcm, swParams, self->framesPerPeriod ), paUnanticipatedHostError );
   2122     ENSURE_( alsa_snd_pcm_sw_params_set_xfer_align( self->pcm, swParams, 1 ), paUnanticipatedHostError );
   2123     ENSURE_( alsa_snd_pcm_sw_params_set_tstamp_mode( self->pcm, swParams, SND_PCM_TSTAMP_ENABLE ), paUnanticipatedHostError );
   2124 
   2125     /* Set the parameters! */
   2126     ENSURE_( alsa_snd_pcm_sw_params( self->pcm, swParams ), paUnanticipatedHostError );
   2127 
   2128 error:
   2129     return result;
   2130 }
   2131 
   2132 static PaError PaAlsaStream_Initialize( PaAlsaStream *self, PaAlsaHostApiRepresentation *alsaApi, const PaStreamParameters *inParams,
   2133         const PaStreamParameters *outParams, double sampleRate, unsigned long framesPerUserBuffer, PaStreamCallback callback,
   2134         PaStreamFlags streamFlags, void *userData )
   2135 {
   2136     PaError result = paNoError;
   2137     assert( self );
   2138 
   2139     memset( self, 0, sizeof( PaAlsaStream ) );
   2140 
   2141     if( NULL != callback )
   2142     {
   2143         PaUtil_InitializeStreamRepresentation( &self->streamRepresentation,
   2144                                                &alsaApi->callbackStreamInterface,
   2145                                                callback, userData );
   2146         self->callbackMode = 1;
   2147     }
   2148     else
   2149     {
   2150         PaUtil_InitializeStreamRepresentation( &self->streamRepresentation,
   2151                                                &alsaApi->blockingStreamInterface,
   2152                                                NULL, userData );
   2153     }
   2154 
   2155     self->framesPerUserBuffer = framesPerUserBuffer;
   2156     self->neverDropInput = streamFlags & paNeverDropInput;
   2157     /* XXX: Ignore paPrimeOutputBuffersUsingStreamCallback untill buffer priming is fully supported in pa_process.c */
   2158     /*
   2159     if( outParams & streamFlags & paPrimeOutputBuffersUsingStreamCallback )
   2160         self->primeBuffers = 1;
   2161         */
   2162     memset( &self->capture, 0, sizeof (PaAlsaStreamComponent) );
   2163     memset( &self->playback, 0, sizeof (PaAlsaStreamComponent) );
   2164     if( inParams )
   2165     {
   2166         PA_ENSURE( PaAlsaStreamComponent_Initialize( &self->capture, alsaApi, inParams, StreamDirection_In, NULL != callback ) );
   2167     }
   2168     if( outParams )
   2169     {
   2170         PA_ENSURE( PaAlsaStreamComponent_Initialize( &self->playback, alsaApi, outParams, StreamDirection_Out, NULL != callback ) );
   2171     }
   2172 
   2173     assert( self->capture.nfds || self->playback.nfds );
   2174 
   2175     PA_UNLESS( self->pfds = (struct pollfd*)PaUtil_AllocateMemory( ( self->capture.nfds +
   2176                     self->playback.nfds ) * sizeof( struct pollfd ) ), paInsufficientMemory );
   2177 
   2178     PaUtil_InitializeCpuLoadMeasurer( &self->cpuLoadMeasurer, sampleRate );
   2179     ASSERT_CALL_( PaUnixMutex_Initialize( &self->stateMtx ), paNoError );
   2180 
   2181 error:
   2182     return result;
   2183 }
   2184 
   2185 /** Free resources associated with stream, and eventually stream itself.
   2186  *
   2187  * Frees allocated memory, and terminates individual StreamComponents.
   2188  */
   2189 static void PaAlsaStream_Terminate( PaAlsaStream *self )
   2190 {
   2191     assert( self );
   2192 
   2193     if( self->capture.pcm )
   2194     {
   2195         PaAlsaStreamComponent_Terminate( &self->capture );
   2196     }
   2197     if( self->playback.pcm )
   2198     {
   2199         PaAlsaStreamComponent_Terminate( &self->playback );
   2200     }
   2201 
   2202     PaUtil_FreeMemory( self->pfds );
   2203     ASSERT_CALL_( PaUnixMutex_Terminate( &self->stateMtx ), paNoError );
   2204 
   2205     PaUtil_FreeMemory( self );
   2206 }
   2207 
   2208 /** Calculate polling timeout
   2209  *
   2210  * @param frames Time to wait
   2211  * @return Polling timeout in milliseconds
   2212  */
   2213 static int CalculatePollTimeout( const PaAlsaStream *stream, unsigned long frames )
   2214 {
   2215     assert( stream->streamRepresentation.streamInfo.sampleRate > 0.0 );
   2216     /* Period in msecs, rounded up */
   2217     return (int)ceil( 1000 * frames / stream->streamRepresentation.streamInfo.sampleRate );
   2218 }
   2219 
   2220 /** Align value in backward direction.
   2221  *
   2222  * @param v: Value to align.
   2223  * @param align: Alignment.
   2224  */
   2225 static unsigned long PaAlsa_AlignBackward(unsigned long v, unsigned long align)
   2226 {
   2227     return ( v - ( align ? v % align : 0 ) );
   2228 }
   2229 
   2230 /** Align value in forward direction.
   2231  *
   2232  * @param v: Value to align.
   2233  * @param align: Alignment.
   2234  */
   2235 static unsigned long PaAlsa_AlignForward(unsigned long v, unsigned long align)
   2236 {
   2237     unsigned long remainder = ( align ? ( v % align ) : 0);
   2238     return ( remainder != 0 ? v + ( align - remainder ) : v );
   2239 }
   2240 
   2241 /** Get size of host buffer maintained from the number of user frames, sample rate and suggested latency. Minimum double buffering
   2242  *  is maintained to allow 100% CPU usage inside user callback.
   2243  *
   2244  * @param userFramesPerBuffer: User buffer size in number of frames.
   2245  * @param suggestedLatency: User provided desired latency.
   2246  * @param sampleRate: Sample rate.
   2247  */
   2248 static unsigned long PaAlsa_GetFramesPerHostBuffer(unsigned long userFramesPerBuffer, PaTime suggestedLatency, double sampleRate)
   2249 {
   2250     unsigned long frames = userFramesPerBuffer + PA_MAX( userFramesPerBuffer, (unsigned long)( suggestedLatency * sampleRate ) );
   2251     return frames;
   2252 }
   2253 
   2254 /** Determine size per host buffer.
   2255  *
   2256  * During this method call, the component's framesPerPeriod attribute gets computed, and the corresponding period size
   2257  * gets configured for the device.
   2258  * @param accurate: If the configured period size is non-integer, this will be set to 0.
   2259  */
   2260 static PaError PaAlsaStreamComponent_DetermineFramesPerBuffer( PaAlsaStreamComponent* self, const PaStreamParameters* params,
   2261         unsigned long framesPerUserBuffer, double sampleRate, snd_pcm_hw_params_t* hwParams, int* accurate )
   2262 {
   2263     PaError result = paNoError;
   2264     unsigned long bufferSize, framesPerHostBuffer;
   2265     int dir = 0;
   2266 
   2267     /* Calculate host buffer size */
   2268     bufferSize = PaAlsa_GetFramesPerHostBuffer(framesPerUserBuffer, params->suggestedLatency, sampleRate);
   2269 
   2270     /* Log */
   2271     PA_DEBUG(( "%s: user-buffer (frames)           = %lu\n", __FUNCTION__, framesPerUserBuffer ));
   2272     PA_DEBUG(( "%s: user-buffer (sec)              = %f\n",  __FUNCTION__, (double)(framesPerUserBuffer / sampleRate) ));
   2273     PA_DEBUG(( "%s: suggested latency (sec)        = %f\n",  __FUNCTION__, params->suggestedLatency ));
   2274     PA_DEBUG(( "%s: suggested host buffer (frames) = %lu\n", __FUNCTION__, bufferSize ));
   2275     PA_DEBUG(( "%s: suggested host buffer (sec)    = %f\n",  __FUNCTION__, (double)(bufferSize / sampleRate) ));
   2276 
   2277 #ifdef PA_ALSA_USE_OBSOLETE_HOST_BUFFER_CALC
   2278 
   2279     if( framesPerUserBuffer != paFramesPerBufferUnspecified )
   2280     {
   2281         /* Preferably the host buffer size should be a multiple of the user buffer size */
   2282 
   2283         if( bufferSize > framesPerUserBuffer )
   2284         {
   2285             snd_pcm_uframes_t remainder = bufferSize % framesPerUserBuffer;
   2286             if( remainder > framesPerUserBuffer / 2. )
   2287                 bufferSize += framesPerUserBuffer - remainder;
   2288             else
   2289                 bufferSize -= remainder;
   2290 
   2291             assert( bufferSize % framesPerUserBuffer == 0 );
   2292         }
   2293         else if( framesPerUserBuffer % bufferSize != 0 )
   2294         {
   2295             /*  Find a good compromise between user specified latency and buffer size */
   2296             if( bufferSize > framesPerUserBuffer * .75 )
   2297             {
   2298                 bufferSize = framesPerUserBuffer;
   2299             }
   2300             else
   2301             {
   2302                 snd_pcm_uframes_t newSz = framesPerUserBuffer;
   2303                 while( newSz / 2 >= bufferSize )
   2304                 {
   2305                     if( framesPerUserBuffer % (newSz / 2) != 0 )
   2306                     {
   2307                         /* No use dividing any further */
   2308                         break;
   2309                     }
   2310                     newSz /= 2;
   2311                 }
   2312                 bufferSize = newSz;
   2313             }
   2314 
   2315             assert( framesPerUserBuffer % bufferSize == 0 );
   2316         }
   2317     }
   2318 
   2319 #endif
   2320 
   2321     {
   2322         unsigned numPeriods = numPeriods_, maxPeriods = 0, minPeriods = numPeriods_;
   2323 
   2324         /* It may be that the device only supports 2 periods for instance */
   2325         dir = 0;
   2326         ENSURE_( alsa_snd_pcm_hw_params_get_periods_min( hwParams, &minPeriods, &dir ), paUnanticipatedHostError );
   2327         ENSURE_( alsa_snd_pcm_hw_params_get_periods_max( hwParams, &maxPeriods, &dir ), paUnanticipatedHostError );
   2328         assert( maxPeriods > 1 );
   2329 
   2330         /* Clamp to min/max */
   2331         numPeriods = PA_MIN(maxPeriods, PA_MAX(minPeriods, numPeriods));
   2332 
   2333         PA_DEBUG(( "%s: periods min = %lu, max = %lu, req = %lu \n", __FUNCTION__, minPeriods, maxPeriods, numPeriods ));
   2334 
   2335 #ifndef PA_ALSA_USE_OBSOLETE_HOST_BUFFER_CALC
   2336 
   2337         /* Calculate period size */
   2338         framesPerHostBuffer = (bufferSize / numPeriods);
   2339 
   2340         /* Align & test size */
   2341         if( framesPerUserBuffer != paFramesPerBufferUnspecified )
   2342         {
   2343             /* Align to user buffer size */
   2344             framesPerHostBuffer = PaAlsa_AlignForward(framesPerHostBuffer, framesPerUserBuffer);
   2345 
   2346             /* Test (borrowed from older implementation) */
   2347             if( framesPerHostBuffer < framesPerUserBuffer )
   2348             {
   2349                 assert( framesPerUserBuffer % framesPerHostBuffer == 0 );
   2350                 if( alsa_snd_pcm_hw_params_test_period_size( self->pcm, hwParams, framesPerHostBuffer, 0 ) < 0 )
   2351                 {
   2352                     if( alsa_snd_pcm_hw_params_test_period_size( self->pcm, hwParams, framesPerHostBuffer * 2, 0 ) == 0 )
   2353                         framesPerHostBuffer *= 2;
   2354                     else if( alsa_snd_pcm_hw_params_test_period_size( self->pcm, hwParams, framesPerHostBuffer / 2, 0 ) == 0 )
   2355                         framesPerHostBuffer /= 2;
   2356                 }
   2357             }
   2358             else
   2359             {
   2360                 assert( framesPerHostBuffer % framesPerUserBuffer == 0 );
   2361                 if( alsa_snd_pcm_hw_params_test_period_size( self->pcm, hwParams, framesPerHostBuffer, 0 ) < 0 )
   2362                 {
   2363                     if( alsa_snd_pcm_hw_params_test_period_size( self->pcm, hwParams, framesPerHostBuffer + framesPerUserBuffer, 0 ) == 0 )
   2364                         framesPerHostBuffer += framesPerUserBuffer;
   2365                     else if( alsa_snd_pcm_hw_params_test_period_size( self->pcm, hwParams, framesPerHostBuffer - framesPerUserBuffer, 0 ) == 0 )
   2366                         framesPerHostBuffer -= framesPerUserBuffer;
   2367                 }
   2368             }
   2369         }
   2370 #endif
   2371 
   2372 #ifdef PA_ALSA_USE_OBSOLETE_HOST_BUFFER_CALC
   2373 
   2374         if( framesPerUserBuffer != paFramesPerBufferUnspecified )
   2375         {
   2376             /* Try to get a power-of-two of the user buffer size. */
   2377             framesPerHostBuffer = framesPerUserBuffer;
   2378             if( framesPerHostBuffer < bufferSize )
   2379             {
   2380                 while( bufferSize / framesPerHostBuffer > numPeriods )
   2381                 {
   2382                     framesPerHostBuffer *= 2;
   2383                 }
   2384                 /* One extra period is preferrable to one less (should be more robust) */
   2385                 if( bufferSize / framesPerHostBuffer < numPeriods )
   2386                 {
   2387                     framesPerHostBuffer /= 2;
   2388                 }
   2389             }
   2390             else
   2391             {
   2392                 while( bufferSize / framesPerHostBuffer < numPeriods )
   2393                 {
   2394                     if( framesPerUserBuffer % ( framesPerHostBuffer / 2 ) != 0 )
   2395                     {
   2396                         /* Can't be divided any further */
   2397                         break;
   2398                     }
   2399                     framesPerHostBuffer /= 2;
   2400                 }
   2401             }
   2402 
   2403             if( framesPerHostBuffer < framesPerUserBuffer )
   2404             {
   2405                 assert( framesPerUserBuffer % framesPerHostBuffer == 0 );
   2406                 if( alsa_snd_pcm_hw_params_test_period_size( self->pcm, hwParams, framesPerHostBuffer, 0 ) < 0 )
   2407                 {
   2408                     if( alsa_snd_pcm_hw_params_test_period_size( self->pcm, hwParams, framesPerHostBuffer * 2, 0 ) == 0 )
   2409                         framesPerHostBuffer *= 2;
   2410                     else if( alsa_snd_pcm_hw_params_test_period_size( self->pcm, hwParams, framesPerHostBuffer / 2, 0 ) == 0 )
   2411                         framesPerHostBuffer /= 2;
   2412                 }
   2413             }
   2414             else
   2415             {
   2416                 assert( framesPerHostBuffer % framesPerUserBuffer == 0 );
   2417                 if( alsa_snd_pcm_hw_params_test_period_size( self->pcm, hwParams, framesPerHostBuffer, 0 ) < 0 )
   2418                 {
   2419                     if( alsa_snd_pcm_hw_params_test_period_size( self->pcm, hwParams, framesPerHostBuffer + framesPerUserBuffer, 0 ) == 0 )
   2420                         framesPerHostBuffer += framesPerUserBuffer;
   2421                     else if( alsa_snd_pcm_hw_params_test_period_size( self->pcm, hwParams, framesPerHostBuffer - framesPerUserBuffer, 0 ) == 0 )
   2422                         framesPerHostBuffer -= framesPerUserBuffer;
   2423                 }
   2424             }
   2425         }
   2426         else
   2427         {
   2428             framesPerHostBuffer = bufferSize / numPeriods;
   2429         }
   2430 
   2431         /* non-mmap mode needs a reasonably-sized buffer or it'll stutter */
   2432         if( !self->canMmap && framesPerHostBuffer < 2048 )
   2433             framesPerHostBuffer = 2048;
   2434 #endif
   2435         PA_DEBUG(( "%s: suggested host buffer period   = %lu \n", __FUNCTION__, framesPerHostBuffer ));
   2436     }
   2437 
   2438     {
   2439         /* Get min/max period sizes and adjust our chosen */
   2440         snd_pcm_uframes_t min = 0, max = 0, minmax_diff;
   2441         ENSURE_( alsa_snd_pcm_hw_params_get_period_size_min( hwParams, &min, NULL ), paUnanticipatedHostError );
   2442         ENSURE_( alsa_snd_pcm_hw_params_get_period_size_max( hwParams, &max, NULL ), paUnanticipatedHostError );
   2443         minmax_diff = max - min;
   2444 
   2445         if( framesPerHostBuffer < min )
   2446         {
   2447             PA_DEBUG(( "%s: The determined period size (%lu) is less than minimum (%lu)\n", __FUNCTION__, framesPerHostBuffer, min ));
   2448             framesPerHostBuffer = (( minmax_diff == 2 ) ? min + 1 : min );
   2449         }
   2450         else if( framesPerHostBuffer > max )
   2451         {
   2452             PA_DEBUG(( "%s: The determined period size (%lu) is greater than maximum (%lu)\n", __FUNCTION__, framesPerHostBuffer, max ));
   2453             framesPerHostBuffer = (( minmax_diff == 2 ) ? max - 1 : max );
   2454         }
   2455 
   2456         PA_DEBUG(( "%s: device period minimum          = %lu\n", __FUNCTION__, min ));
   2457         PA_DEBUG(( "%s: device period maximum          = %lu\n", __FUNCTION__, max ));
   2458         PA_DEBUG(( "%s: host buffer period             = %lu\n", __FUNCTION__, framesPerHostBuffer ));
   2459         PA_DEBUG(( "%s: host buffer period latency     = %f\n", __FUNCTION__, (double)( framesPerHostBuffer / sampleRate ) ));
   2460 
   2461         /* Try setting period size */
   2462         dir = 0;
   2463         ENSURE_( alsa_snd_pcm_hw_params_set_period_size_near( self->pcm, hwParams, &framesPerHostBuffer, &dir ), paUnanticipatedHostError );
   2464         if( dir != 0 )
   2465         {
   2466             PA_DEBUG(( "%s: The configured period size is non-integer.\n", __FUNCTION__, dir ));
   2467             *accurate = 0;
   2468         }
   2469     }
   2470 
   2471     /* Set result */
   2472     self->framesPerPeriod = framesPerHostBuffer;
   2473 
   2474 error:
   2475     return result;
   2476 }
   2477 
   2478 /* We need to determine how many frames per host buffer (period) to use.  Our
   2479  * goals are to provide the best possible performance, but also to
   2480  * honor the requested latency settings as closely as we can. Therefore this
   2481  * decision is based on:
   2482  *
   2483  *   - the period sizes that playback and/or capture support.  The
   2484  *     host buffer size has to be one of these.
   2485  *   - the number of periods that playback and/or capture support.
   2486  *
   2487  * We want to make period_size*(num_periods-1) to be as close as possible
   2488  * to latency*rate for both playback and capture.
   2489  *
   2490  * This method will determine suitable period sizes for capture and playback handles, and report the maximum number of
   2491  * frames per host buffer. The latter is relevant, in case we should be so unfortunate that the period size differs
   2492  * between capture and playback. If this should happen, the stream's hostBufferSizeMode attribute will be set to
   2493  * paUtilBoundedHostBufferSize, because the best we can do is limit the size of individual host buffers to the upper
   2494  * bound. The size of host buffers scheduled for processing should only matter if the user has specified a buffer size,
   2495  * but when he/she does we must strive for an optimal configuration. By default we'll opt for a fixed host buffer size,
   2496  * which should be fine if the period size is the same for capture and playback. In general, if there is a specified user
   2497  * buffer size, this method tries it best to determine a period size which is a multiple of the user buffer size.
   2498  *
   2499  * The framesPerPeriod attributes of the individual capture and playback components of the stream are set to corresponding
   2500  * values determined here. Since these should be reported as
   2501  *
   2502  * This is one of those blocks of code that will just take a lot of
   2503  * refinement to be any good.
   2504  *
   2505  * In the full-duplex case it is possible that the routine was unable
   2506  * to find a number of frames per buffer acceptable to both devices
   2507  * TODO: Implement an algorithm to find the value closest to acceptance
   2508  * by both devices, to minimize difference between period sizes?
   2509  *
   2510  * @param determinedFramesPerHostBuffer: The determined host buffer size.
   2511  */
   2512 static PaError PaAlsaStream_DetermineFramesPerBuffer( PaAlsaStream* self, double sampleRate, const PaStreamParameters* inputParameters,
   2513         const PaStreamParameters* outputParameters, unsigned long framesPerUserBuffer, snd_pcm_hw_params_t* hwParamsCapture,
   2514         snd_pcm_hw_params_t* hwParamsPlayback, PaUtilHostBufferSizeMode* hostBufferSizeMode )
   2515 {
   2516     PaError result = paNoError;
   2517     unsigned long framesPerHostBuffer = 0;
   2518     int dir = 0;
   2519     int accurate = 1;
   2520     unsigned numPeriods = numPeriods_;
   2521 
   2522     if( self->capture.pcm && self->playback.pcm )
   2523     {
   2524         if( framesPerUserBuffer == paFramesPerBufferUnspecified )
   2525         {
   2526             /* Come up with a common desired latency */
   2527             snd_pcm_uframes_t desiredBufSz, e, minPeriodSize, maxPeriodSize, optimalPeriodSize, periodSize,
   2528                               minCapture, minPlayback, maxCapture, maxPlayback;
   2529 
   2530             dir = 0;
   2531             ENSURE_( alsa_snd_pcm_hw_params_get_period_size_min( hwParamsCapture, &minCapture, &dir ), paUnanticipatedHostError );
   2532             dir = 0;
   2533             ENSURE_( alsa_snd_pcm_hw_params_get_period_size_min( hwParamsPlayback, &minPlayback, &dir ), paUnanticipatedHostError );
   2534             dir = 0;
   2535             ENSURE_( alsa_snd_pcm_hw_params_get_period_size_max( hwParamsCapture, &maxCapture, &dir ), paUnanticipatedHostError );
   2536             dir = 0;
   2537             ENSURE_( alsa_snd_pcm_hw_params_get_period_size_max( hwParamsPlayback, &maxPlayback, &dir ), paUnanticipatedHostError );
   2538             minPeriodSize = PA_MAX( minPlayback, minCapture );
   2539             maxPeriodSize = PA_MIN( maxPlayback, maxCapture );
   2540             PA_UNLESS( minPeriodSize <= maxPeriodSize, paBadIODeviceCombination );
   2541 
   2542             desiredBufSz = (snd_pcm_uframes_t)( PA_MIN( outputParameters->suggestedLatency, inputParameters->suggestedLatency )
   2543                     * sampleRate );
   2544             /* Clamp desiredBufSz */
   2545             {
   2546                 snd_pcm_uframes_t maxBufferSize;
   2547                 snd_pcm_uframes_t maxBufferSizeCapture, maxBufferSizePlayback;
   2548                 ENSURE_( alsa_snd_pcm_hw_params_get_buffer_size_max( hwParamsCapture, &maxBufferSizeCapture ), paUnanticipatedHostError );
   2549                 ENSURE_( alsa_snd_pcm_hw_params_get_buffer_size_max( hwParamsPlayback, &maxBufferSizePlayback ), paUnanticipatedHostError );
   2550                 maxBufferSize = PA_MIN( maxBufferSizeCapture, maxBufferSizePlayback );
   2551 
   2552                 desiredBufSz = PA_MIN( desiredBufSz, maxBufferSize );
   2553             }
   2554 
   2555             /* Find the closest power of 2 */
   2556             e = ilogb( minPeriodSize );
   2557             if( minPeriodSize & ( minPeriodSize - 1 ) )
   2558                 e += 1;
   2559             periodSize = (snd_pcm_uframes_t)pow( 2, e );
   2560 
   2561             while( periodSize <= maxPeriodSize )
   2562             {
   2563                 if( alsa_snd_pcm_hw_params_test_period_size( self->playback.pcm, hwParamsPlayback, periodSize, 0 ) >= 0 &&
   2564                         alsa_snd_pcm_hw_params_test_period_size( self->capture.pcm, hwParamsCapture, periodSize, 0 ) >= 0 )
   2565                 {
   2566                     /* OK! */
   2567                     break;
   2568                 }
   2569 
   2570                 periodSize *= 2;
   2571             }
   2572 
   2573             optimalPeriodSize = PA_MAX( desiredBufSz / numPeriods, minPeriodSize );
   2574             optimalPeriodSize = PA_MIN( optimalPeriodSize, maxPeriodSize );
   2575 
   2576             /* Find the closest power of 2 */
   2577             e = ilogb( optimalPeriodSize );
   2578             if( optimalPeriodSize & (optimalPeriodSize - 1) )
   2579                 e += 1;
   2580             optimalPeriodSize = (snd_pcm_uframes_t)pow( 2, e );
   2581 
   2582             while( optimalPeriodSize >= periodSize )
   2583             {
   2584                 if( alsa_snd_pcm_hw_params_test_period_size( self->capture.pcm, hwParamsCapture, optimalPeriodSize, 0 )
   2585                         >= 0 && alsa_snd_pcm_hw_params_test_period_size( self->playback.pcm, hwParamsPlayback,
   2586                             optimalPeriodSize, 0 ) >= 0 )
   2587                 {
   2588                     break;
   2589                 }
   2590                 optimalPeriodSize /= 2;
   2591             }
   2592 
   2593             if( optimalPeriodSize > periodSize )
   2594                 periodSize = optimalPeriodSize;
   2595 
   2596             if( periodSize <= maxPeriodSize )
   2597             {
   2598                 /* Looks good, the periodSize _should_ be acceptable by both devices */
   2599                 ENSURE_( alsa_snd_pcm_hw_params_set_period_size( self->capture.pcm, hwParamsCapture, periodSize, 0 ),
   2600                         paUnanticipatedHostError );
   2601                 ENSURE_( alsa_snd_pcm_hw_params_set_period_size( self->playback.pcm, hwParamsPlayback, periodSize, 0 ),
   2602                         paUnanticipatedHostError );
   2603                 self->capture.framesPerPeriod = self->playback.framesPerPeriod = periodSize;
   2604                 framesPerHostBuffer = periodSize;
   2605             }
   2606             else
   2607             {
   2608                 /* Unable to find a common period size, oh well */
   2609                 optimalPeriodSize = PA_MAX( desiredBufSz / numPeriods, minPeriodSize );
   2610                 optimalPeriodSize = PA_MIN( optimalPeriodSize, maxPeriodSize );
   2611 
   2612                 self->capture.framesPerPeriod = optimalPeriodSize;
   2613                 dir = 0;
   2614                 ENSURE_( alsa_snd_pcm_hw_params_set_period_size_near( self->capture.pcm, hwParamsCapture, &self->capture.framesPerPeriod, &dir ),
   2615                         paUnanticipatedHostError );
   2616                 self->playback.framesPerPeriod = optimalPeriodSize;
   2617                 dir = 0;
   2618                 ENSURE_( alsa_snd_pcm_hw_params_set_period_size_near( self->playback.pcm, hwParamsPlayback, &self->playback.framesPerPeriod, &dir ),
   2619                         paUnanticipatedHostError );
   2620                 framesPerHostBuffer = PA_MAX( self->capture.framesPerPeriod, self->playback.framesPerPeriod );
   2621                 *hostBufferSizeMode = paUtilBoundedHostBufferSize;
   2622             }
   2623         }
   2624         else
   2625         {
   2626             /* We choose the simple route and determine a suitable number of frames per buffer for one component of
   2627              * the stream, then we hope that this will work for the other component too (it should!).
   2628              */
   2629 
   2630             unsigned maxPeriods = 0;
   2631             PaAlsaStreamComponent* first = &self->capture, * second = &self->playback;
   2632             const PaStreamParameters* firstStreamParams = inputParameters;
   2633             snd_pcm_hw_params_t* firstHwParams = hwParamsCapture, * secondHwParams = hwParamsPlayback;
   2634 
   2635             dir = 0;
   2636             ENSURE_( alsa_snd_pcm_hw_params_get_periods_max( hwParamsPlayback, &maxPeriods, &dir ), paUnanticipatedHostError );
   2637             if( maxPeriods < numPeriods )
   2638             {
   2639                 /* The playback component is trickier to get right, try that first */
   2640                 first = &self->playback;
   2641                 second = &self->capture;
   2642                 firstStreamParams = outputParameters;
   2643                 firstHwParams = hwParamsPlayback;
   2644                 secondHwParams = hwParamsCapture;
   2645             }
   2646 
   2647             PA_ENSURE( PaAlsaStreamComponent_DetermineFramesPerBuffer( first, firstStreamParams, framesPerUserBuffer,
   2648                         sampleRate, firstHwParams, &accurate ) );
   2649 
   2650             second->framesPerPeriod = first->framesPerPeriod;
   2651             dir = 0;
   2652             ENSURE_( alsa_snd_pcm_hw_params_set_period_size_near( second->pcm, secondHwParams, &second->framesPerPeriod, &dir ),
   2653                     paUnanticipatedHostError );
   2654             if( self->capture.framesPerPeriod == self->playback.framesPerPeriod )
   2655             {
   2656                 framesPerHostBuffer = self->capture.framesPerPeriod;
   2657             }
   2658             else
   2659             {
   2660                 framesPerHostBuffer = PA_MAX( self->capture.framesPerPeriod, self->playback.framesPerPeriod );
   2661                 *hostBufferSizeMode = paUtilBoundedHostBufferSize;
   2662             }
   2663         }
   2664     }
   2665     else    /* half-duplex is a slightly simpler case */
   2666     {
   2667         if( self->capture.pcm )
   2668         {
   2669             PA_ENSURE( PaAlsaStreamComponent_DetermineFramesPerBuffer( &self->capture, inputParameters, framesPerUserBuffer,
   2670                         sampleRate, hwParamsCapture, &accurate) );
   2671             framesPerHostBuffer = self->capture.framesPerPeriod;
   2672         }
   2673         else
   2674         {
   2675             assert( self->playback.pcm );
   2676             PA_ENSURE( PaAlsaStreamComponent_DetermineFramesPerBuffer( &self->playback, outputParameters, framesPerUserBuffer,
   2677                         sampleRate, hwParamsPlayback, &accurate ) );
   2678             framesPerHostBuffer = self->playback.framesPerPeriod;
   2679         }
   2680     }
   2681 
   2682     PA_UNLESS( framesPerHostBuffer != 0, paInternalError );
   2683     self->maxFramesPerHostBuffer = framesPerHostBuffer;
   2684 
   2685     if( !self->playback.canMmap || !accurate )
   2686     {
   2687         /* Don't know the exact size per host buffer */
   2688         *hostBufferSizeMode = paUtilBoundedHostBufferSize;
   2689         /* Raise upper bound */
   2690         if( !accurate )
   2691             ++self->maxFramesPerHostBuffer;
   2692     }
   2693 
   2694 error:
   2695     return result;
   2696 }
   2697 
   2698 /** Set up ALSA stream parameters.
   2699  *
   2700  */
   2701 static PaError PaAlsaStream_Configure( PaAlsaStream *self, const PaStreamParameters *inParams, const PaStreamParameters*
   2702         outParams, double sampleRate, unsigned long framesPerUserBuffer, double* inputLatency, double* outputLatency,
   2703         PaUtilHostBufferSizeMode* hostBufferSizeMode )
   2704 {
   2705     PaError result = paNoError;
   2706     double realSr = sampleRate;
   2707     snd_pcm_hw_params_t* hwParamsCapture, * hwParamsPlayback;
   2708 
   2709     alsa_snd_pcm_hw_params_alloca( &hwParamsCapture );
   2710     alsa_snd_pcm_hw_params_alloca( &hwParamsPlayback );
   2711 
   2712     if( self->capture.pcm )
   2713         PA_ENSURE( PaAlsaStreamComponent_InitialConfigure( &self->capture, inParams, self->primeBuffers, hwParamsCapture,
   2714                     &realSr ) );
   2715     if( self->playback.pcm )
   2716         PA_ENSURE( PaAlsaStreamComponent_InitialConfigure( &self->playback, outParams, self->primeBuffers, hwParamsPlayback,
   2717                     &realSr ) );
   2718 
   2719     PA_ENSURE( PaAlsaStream_DetermineFramesPerBuffer( self, realSr, inParams, outParams, framesPerUserBuffer,
   2720                 hwParamsCapture, hwParamsPlayback, hostBufferSizeMode ) );
   2721 
   2722     if( self->capture.pcm )
   2723     {
   2724         assert( self->capture.framesPerPeriod != 0 );
   2725         PA_ENSURE( PaAlsaStreamComponent_FinishConfigure( &self->capture, hwParamsCapture, inParams, self->primeBuffers, realSr,
   2726                     inputLatency ) );
   2727         PA_DEBUG(( "%s: Capture period size: %lu, latency: %f\n", __FUNCTION__, self->capture.framesPerPeriod, *inputLatency ));
   2728     }
   2729     if( self->playback.pcm )
   2730     {
   2731         assert( self->playback.framesPerPeriod != 0 );
   2732         PA_ENSURE( PaAlsaStreamComponent_FinishConfigure( &self->playback, hwParamsPlayback, outParams, self->primeBuffers, realSr,
   2733                     outputLatency ) );
   2734         PA_DEBUG(( "%s: Playback period size: %lu, latency: %f\n", __FUNCTION__, self->playback.framesPerPeriod, *outputLatency ));
   2735     }
   2736 
   2737     /* Should be exact now */
   2738     self->streamRepresentation.streamInfo.sampleRate = realSr;
   2739 
   2740     /* this will cause the two streams to automatically start/stop/prepare in sync.
   2741      * We only need to execute these operations on one of the pair.
   2742      * A: We don't want to do this on a blocking stream.
   2743      */
   2744     if( self->callbackMode && self->capture.pcm && self->playback.pcm )
   2745     {
   2746         int err = alsa_snd_pcm_link( self->capture.pcm, self->playback.pcm );
   2747         if( err == 0 )
   2748             self->pcmsSynced = 1;
   2749         else
   2750             PA_DEBUG(( "%s: Unable to sync pcms: %s\n", __FUNCTION__, alsa_snd_strerror( err ) ));
   2751     }
   2752 
   2753     {
   2754         unsigned long minFramesPerHostBuffer = PA_MIN( self->capture.pcm ? self->capture.framesPerPeriod : ULONG_MAX,
   2755             self->playback.pcm ? self->playback.framesPerPeriod : ULONG_MAX );
   2756         self->pollTimeout = CalculatePollTimeout( self, minFramesPerHostBuffer );    /* Period in msecs, rounded up */
   2757 
   2758         /* Time before watchdog unthrottles realtime thread == 1/4 of period time in msecs */
   2759         /* self->threading.throttledSleepTime = (unsigned long) (minFramesPerHostBuffer / sampleRate / 4 * 1000); */
   2760     }
   2761 
   2762     if( self->callbackMode )
   2763     {
   2764         /* If the user expects a certain number of frames per callback we will either have to rely on block adaption
   2765          * (framesPerHostBuffer is not an integer multiple of framesPerPeriod) or we can simply align the number
   2766          * of host buffer frames with what the user specified */
   2767         if( self->framesPerUserBuffer != paFramesPerBufferUnspecified )
   2768         {
   2769             /* self->alignFrames = 1; */
   2770 
   2771             /* Unless the ratio between number of host and user buffer frames is an integer we will have to rely
   2772              * on block adaption */
   2773         /*
   2774             if( framesPerHostBuffer % framesPerPeriod != 0 || (self->capture.pcm && self->playback.pcm &&
   2775                         self->capture.framesPerPeriod != self->playback.framesPerPeriod) )
   2776                 self->useBlockAdaption = 1;
   2777             else
   2778                 self->alignFrames = 1;
   2779         */
   2780         }
   2781     }
   2782 
   2783 error:
   2784     return result;
   2785 }
   2786 
   2787 static PaError OpenStream( struct PaUtilHostApiRepresentation *hostApi,
   2788                            PaStream** s,
   2789                            const PaStreamParameters *inputParameters,
   2790                            const PaStreamParameters *outputParameters,
   2791                            double sampleRate,
   2792                            unsigned long framesPerBuffer,
   2793                            PaStreamFlags streamFlags,
   2794                            PaStreamCallback* callback,
   2795                            void *userData )
   2796 {
   2797     PaError result = paNoError;
   2798     PaAlsaHostApiRepresentation *alsaHostApi = (PaAlsaHostApiRepresentation*)hostApi;
   2799     PaAlsaStream *stream = NULL;
   2800     PaSampleFormat hostInputSampleFormat = 0, hostOutputSampleFormat = 0;
   2801     PaSampleFormat inputSampleFormat = 0, outputSampleFormat = 0;
   2802     int numInputChannels = 0, numOutputChannels = 0;
   2803     PaTime inputLatency, outputLatency;
   2804     /* Operate with fixed host buffer size by default, since other modes will invariably lead to block adaption */
   2805     /* XXX: Use Bounded by default? Output tends to get stuttery with Fixed ... */
   2806     PaUtilHostBufferSizeMode hostBufferSizeMode = paUtilFixedHostBufferSize;
   2807 
   2808     if( ( streamFlags & paPlatformSpecificFlags ) != 0 )
   2809         return paInvalidFlag;
   2810 
   2811     if( inputParameters )
   2812     {
   2813         PA_ENSURE( ValidateParameters( inputParameters, hostApi, StreamDirection_In ) );
   2814 
   2815         numInputChannels = inputParameters->channelCount;
   2816         inputSampleFormat = inputParameters->sampleFormat;
   2817     }
   2818     if( outputParameters )
   2819     {
   2820         PA_ENSURE( ValidateParameters( outputParameters, hostApi, StreamDirection_Out ) );
   2821 
   2822         numOutputChannels = outputParameters->channelCount;
   2823         outputSampleFormat = outputParameters->sampleFormat;
   2824     }
   2825 
   2826     /* XXX: Why do we support this anyway? */
   2827     if( framesPerBuffer == paFramesPerBufferUnspecified && getenv( "PA_ALSA_PERIODSIZE" ) != NULL )
   2828     {
   2829         PA_DEBUG(( "%s: Getting framesPerBuffer (Alsa period-size) from environment\n", __FUNCTION__ ));
   2830         framesPerBuffer = atoi( getenv("PA_ALSA_PERIODSIZE") );
   2831     }
   2832 
   2833     PA_UNLESS( stream = (PaAlsaStream*)PaUtil_AllocateMemory( sizeof(PaAlsaStream) ), paInsufficientMemory );
   2834     PA_ENSURE( PaAlsaStream_Initialize( stream, alsaHostApi, inputParameters, outputParameters, sampleRate,
   2835                 framesPerBuffer, callback, streamFlags, userData ) );
   2836 
   2837     PA_ENSURE( PaAlsaStream_Configure( stream, inputParameters, outputParameters, sampleRate, framesPerBuffer,
   2838                 &inputLatency, &outputLatency, &hostBufferSizeMode ) );
   2839     hostInputSampleFormat = stream->capture.hostSampleFormat | (!stream->capture.hostInterleaved ? paNonInterleaved : 0);
   2840     hostOutputSampleFormat = stream->playback.hostSampleFormat | (!stream->playback.hostInterleaved ? paNonInterleaved : 0);
   2841 
   2842     PA_ENSURE( PaUtil_InitializeBufferProcessor( &stream->bufferProcessor,
   2843                     numInputChannels, inputSampleFormat, hostInputSampleFormat,
   2844                     numOutputChannels, outputSampleFormat, hostOutputSampleFormat,
   2845                     sampleRate, streamFlags, framesPerBuffer, stream->maxFramesPerHostBuffer,
   2846                     hostBufferSizeMode, callback, userData ) );
   2847 
   2848     /* Ok, buffer processor is initialized, now we can deduce it's latency */
   2849     if( numInputChannels > 0 )
   2850         stream->streamRepresentation.streamInfo.inputLatency = inputLatency + (PaTime)(
   2851                 PaUtil_GetBufferProcessorInputLatencyFrames( &stream->bufferProcessor ) / sampleRate);
   2852     if( numOutputChannels > 0 )
   2853         stream->streamRepresentation.streamInfo.outputLatency = outputLatency + (PaTime)(
   2854                 PaUtil_GetBufferProcessorOutputLatencyFrames( &stream->bufferProcessor ) / sampleRate);
   2855 
   2856     PA_DEBUG(( "%s: Stream: framesPerBuffer = %lu, maxFramesPerHostBuffer = %lu, latency i=%f, o=%f\n", __FUNCTION__, framesPerBuffer, stream->maxFramesPerHostBuffer, stream->streamRepresentation.streamInfo.inputLatency, stream->streamRepresentation.streamInfo.outputLatency));
   2857 
   2858     *s = (PaStream*)stream;
   2859 
   2860     return result;
   2861 
   2862 error:
   2863     if( stream )
   2864     {
   2865         PA_DEBUG(( "%s: Stream in error, terminating\n", __FUNCTION__ ));
   2866         PaAlsaStream_Terminate( stream );
   2867     }
   2868 
   2869     return result;
   2870 }
   2871 
   2872 static PaError CloseStream( PaStream* s )
   2873 {
   2874     PaError result = paNoError;
   2875     PaAlsaStream *stream = (PaAlsaStream*)s;
   2876 
   2877     PaUtil_TerminateBufferProcessor( &stream->bufferProcessor );
   2878     PaUtil_TerminateStreamRepresentation( &stream->streamRepresentation );
   2879 
   2880     PaAlsaStream_Terminate( stream );
   2881 
   2882     return result;
   2883 }
   2884 
   2885 static void SilenceBuffer( PaAlsaStream *stream )
   2886 {
   2887     const snd_pcm_channel_area_t *areas;
   2888     snd_pcm_uframes_t frames = (snd_pcm_uframes_t)alsa_snd_pcm_avail_update( stream->playback.pcm ), offset;
   2889 
   2890     alsa_snd_pcm_mmap_begin( stream->playback.pcm, &areas, &offset, &frames );
   2891     alsa_snd_pcm_areas_silence( areas, offset, stream->playback.numHostChannels, frames, stream->playback.nativeFormat );
   2892     alsa_snd_pcm_mmap_commit( stream->playback.pcm, offset, frames );
   2893 }
   2894 
   2895 /** Start/prepare pcm(s) for streaming.
   2896  *
   2897  * Depending on whether the stream is in callback or blocking mode, we will respectively start or simply
   2898  * prepare the playback pcm. If the buffer has _not_ been primed, we will in callback mode prepare and
   2899  * silence the buffer before starting playback. In blocking mode we simply prepare, as the playback will
   2900  * be started automatically as the user writes to output.
   2901  *
   2902  * The capture pcm, however, will simply be prepared and started.
   2903  */
   2904 static PaError AlsaStart( PaAlsaStream *stream, int priming )
   2905 {
   2906     PaError result = paNoError;
   2907 
   2908     if( stream->playback.pcm )
   2909     {
   2910         if( stream->callbackMode )
   2911         {
   2912             if( !priming )
   2913             {
   2914                 /* Buffer isn't primed, so prepare and silence */
   2915                 ENSURE_( alsa_snd_pcm_prepare( stream->playback.pcm ), paUnanticipatedHostError );
   2916                 if( stream->playback.canMmap )
   2917                     SilenceBuffer( stream );
   2918             }
   2919             if( stream->playback.canMmap )
   2920                 ENSURE_( alsa_snd_pcm_start( stream->playback.pcm ), paUnanticipatedHostError );
   2921         }
   2922         else
   2923             ENSURE_( alsa_snd_pcm_prepare( stream->playback.pcm ), paUnanticipatedHostError );
   2924     }
   2925     if( stream->capture.pcm && !stream->pcmsSynced )
   2926     {
   2927         ENSURE_( alsa_snd_pcm_prepare( stream->capture.pcm ), paUnanticipatedHostError );
   2928         /* For a blocking stream we want to start capture as well, since nothing will happen otherwise */
   2929         ENSURE_( alsa_snd_pcm_start( stream->capture.pcm ), paUnanticipatedHostError );
   2930     }
   2931 
   2932 end:
   2933     return result;
   2934 error:
   2935     goto end;
   2936 }
   2937 
   2938 /** Utility function for determining if pcms are in running state.
   2939  *
   2940  */
   2941 #if 0
   2942 static int IsRunning( PaAlsaStream *stream )
   2943 {
   2944     int result = 0;
   2945 
   2946     PA_ENSURE( PaUnixMutex_Lock( &stream->stateMtx ) );
   2947     if( stream->capture.pcm )
   2948     {
   2949         snd_pcm_state_t capture_state = alsa_snd_pcm_state( stream->capture.pcm );
   2950 
   2951         if( capture_state == SND_PCM_STATE_RUNNING || capture_state == SND_PCM_STATE_XRUN
   2952                 || capture_state == SND_PCM_STATE_DRAINING )
   2953         {
   2954             result = 1;
   2955             goto end;
   2956         }
   2957     }
   2958 
   2959     if( stream->playback.pcm )
   2960     {
   2961         snd_pcm_state_t playback_state = alsa_snd_pcm_state( stream->playback.pcm );
   2962 
   2963         if( playback_state == SND_PCM_STATE_RUNNING || playback_state == SND_PCM_STATE_XRUN
   2964                 || playback_state == SND_PCM_STATE_DRAINING )
   2965         {
   2966             result = 1;
   2967             goto end;
   2968         }
   2969     }
   2970 
   2971 end:
   2972     ASSERT_CALL_( PaUnixMutex_Unlock( &stream->stateMtx ), paNoError );
   2973     return result;
   2974 error:
   2975     goto error;
   2976 }
   2977 #endif
   2978 
   2979 static PaError StartStream( PaStream *s )
   2980 {
   2981     PaError result = paNoError;
   2982     PaAlsaStream* stream = (PaAlsaStream*)s;
   2983     int streamStarted = 0;  /* So we can know whether we need to take the stream down */
   2984 
   2985     /* Ready the processor */
   2986     PaUtil_ResetBufferProcessor( &stream->bufferProcessor );
   2987 
   2988     /* Set now, so we can test for activity further down */
   2989     stream->isActive = 1;
   2990 
   2991     if( stream->callbackMode )
   2992     {
   2993         PA_ENSURE( PaUnixThread_New( &stream->thread, &CallbackThreadFunc, stream, 1., stream->rtSched ) );
   2994     }
   2995     else
   2996     {
   2997         PA_ENSURE( AlsaStart( stream, 0 ) );
   2998         streamStarted = 1;
   2999     }
   3000 
   3001 end:
   3002     return result;
   3003 error:
   3004     if( streamStarted )
   3005     {
   3006         AbortStream( stream );
   3007     }
   3008     stream->isActive = 0;
   3009 
   3010     goto end;
   3011 }
   3012 
   3013 /** Stop PCM handle, either softly or abruptly.
   3014  */
   3015 static PaError AlsaStop( PaAlsaStream *stream, int abort )
   3016 {
   3017     PaError result = paNoError;
   3018     /* XXX: alsa_snd_pcm_drain tends to lock up, avoid it until we find out more */
   3019     abort = 1;
   3020     /*
   3021     if( stream->capture.pcm && !strcmp( Pa_GetDeviceInfo( stream->capture.device )->name,
   3022                 "dmix" ) )
   3023     {
   3024         abort = 1;
   3025     }
   3026     else if( stream->playback.pcm && !strcmp( Pa_GetDeviceInfo( stream->playback.device )->name,
   3027                 "dmix" ) )
   3028     {
   3029         abort = 1;
   3030     }
   3031     */
   3032 
   3033     if( abort )
   3034     {
   3035         if( stream->playback.pcm )
   3036         {
   3037             ENSURE_( alsa_snd_pcm_drop( stream->playback.pcm ), paUnanticipatedHostError );
   3038         }
   3039         if( stream->capture.pcm && !stream->pcmsSynced )
   3040         {
   3041             ENSURE_( alsa_snd_pcm_drop( stream->capture.pcm ), paUnanticipatedHostError );
   3042         }
   3043 
   3044         PA_DEBUG(( "%s: Dropped frames\n", __FUNCTION__ ));
   3045     }
   3046     else
   3047     {
   3048         if( stream->playback.pcm )
   3049         {
   3050             ENSURE_( alsa_snd_pcm_nonblock( stream->playback.pcm, 0 ), paUnanticipatedHostError );
   3051             if( alsa_snd_pcm_drain( stream->playback.pcm ) < 0 )
   3052             {
   3053                 PA_DEBUG(( "%s: Draining playback handle failed!\n", __FUNCTION__ ));
   3054             }
   3055         }
   3056         if( stream->capture.pcm && !stream->pcmsSynced )
   3057         {
   3058             /* We don't need to retrieve any remaining frames */
   3059             if( alsa_snd_pcm_drain( stream->capture.pcm ) < 0 )
   3060             {
   3061                 PA_DEBUG(( "%s: Draining capture handle failed!\n", __FUNCTION__ ));
   3062             }
   3063         }
   3064     }
   3065 
   3066 end:
   3067     return result;
   3068 error:
   3069     goto end;
   3070 }
   3071 
   3072 /** Stop or abort stream.
   3073  *
   3074  * If a stream is in callback mode we will have to inspect whether the background thread has
   3075  * finished, or we will have to take it out. In either case we join the thread before
   3076  * returning. In blocking mode, we simply tell ALSA to stop abruptly (abort) or finish
   3077  * buffers (drain)
   3078  *
   3079  * Stream will be considered inactive (!PaAlsaStream::isActive) after a call to this function
   3080  */
   3081 static PaError RealStop( PaAlsaStream *stream, int abort )
   3082 {
   3083     PaError result = paNoError;
   3084 
   3085     /* First deal with the callback thread, cancelling and/or joining
   3086      * it if necessary
   3087      */
   3088     if( stream->callbackMode )
   3089     {
   3090         PaError threadRes;
   3091         stream->callbackAbort = abort;
   3092 
   3093         if( !abort )
   3094         {
   3095             PA_DEBUG(( "Stopping callback\n" ));
   3096         }
   3097         PA_ENSURE( PaUnixThread_Terminate( &stream->thread, !abort, &threadRes ) );
   3098         if( threadRes != paNoError )
   3099         {
   3100             PA_DEBUG(( "Callback thread returned: %d\n", threadRes ));
   3101         }
   3102 #if 0
   3103         if( watchdogRes != paNoError )
   3104             PA_DEBUG(( "Watchdog thread returned: %d\n", watchdogRes ));
   3105 #endif
   3106 
   3107         stream->callback_finished = 0;
   3108     }
   3109     else
   3110     {
   3111         PA_ENSURE( AlsaStop( stream, abort ) );
   3112     }
   3113 
   3114     stream->isActive = 0;
   3115 
   3116 end:
   3117     return result;
   3118 
   3119 error:
   3120     goto end;
   3121 }
   3122 
   3123 static PaError StopStream( PaStream *s )
   3124 {
   3125     return RealStop( (PaAlsaStream *) s, 0 );
   3126 }
   3127 
   3128 static PaError AbortStream( PaStream *s )
   3129 {
   3130     return RealStop( (PaAlsaStream * ) s, 1 );
   3131 }
   3132 
   3133 /** The stream is considered stopped before StartStream, or AFTER a call to Abort/StopStream (callback
   3134  * returning !paContinue is not considered)
   3135  *
   3136  */
   3137 static PaError IsStreamStopped( PaStream *s )
   3138 {
   3139     PaAlsaStream *stream = (PaAlsaStream *)s;
   3140 
   3141     /* callback_finished indicates we need to join callback thread (ie. in Abort/StopStream) */
   3142     return !IsStreamActive( s ) && !stream->callback_finished;
   3143 }
   3144 
   3145 static PaError IsStreamActive( PaStream *s )
   3146 {
   3147     PaAlsaStream *stream = (PaAlsaStream*)s;
   3148     return stream->isActive;
   3149 }
   3150 
   3151 static PaTime GetStreamTime( PaStream *s )
   3152 {
   3153     PaAlsaStream *stream = (PaAlsaStream*)s;
   3154 
   3155     snd_timestamp_t timestamp;
   3156     snd_pcm_status_t* status;
   3157     alsa_snd_pcm_status_alloca( &status );
   3158 
   3159     /* TODO: what if we have both?  does it really matter? */
   3160 
   3161     /* TODO: if running in callback mode, this will mean
   3162      * libasound routines are being called from multiple threads.
   3163      * need to verify that libasound is thread-safe. */
   3164 
   3165     if( stream->capture.pcm )
   3166     {
   3167         alsa_snd_pcm_status( stream->capture.pcm, status );
   3168     }
   3169     else if( stream->playback.pcm )
   3170     {
   3171         alsa_snd_pcm_status( stream->playback.pcm, status );
   3172     }
   3173 
   3174     alsa_snd_pcm_status_get_tstamp( status, &timestamp );
   3175     return timestamp.tv_sec + (PaTime)timestamp.tv_usec / 1e6;
   3176 }
   3177 
   3178 static double GetStreamCpuLoad( PaStream* s )
   3179 {
   3180     PaAlsaStream *stream = (PaAlsaStream*)s;
   3181 
   3182     return PaUtil_GetCpuLoad( &stream->cpuLoadMeasurer );
   3183 }
   3184 
   3185 /* Set the stream sample rate to a nominal value requested; allow only a defined tolerance range */
   3186 static int SetApproximateSampleRate( snd_pcm_t *pcm, snd_pcm_hw_params_t *hwParams, double sampleRate )
   3187 {
   3188     PaError result = paNoError;
   3189     unsigned int reqRate, setRate, deviation;
   3190 
   3191     assert( pcm && hwParams );
   3192 
   3193     /* The Alsa sample rate is set by integer value; also the actual rate may differ */
   3194     reqRate = setRate = (unsigned int) sampleRate;
   3195 
   3196     ENSURE_( alsa_snd_pcm_hw_params_set_rate_near( pcm, hwParams, &setRate, NULL ), paUnanticipatedHostError );
   3197     /* The value actually set will be put in 'setRate' (may be way off); check the deviation as a proportion
   3198      * of the requested-rate with reference to the max-deviate-ratio (larger values allow less deviation) */
   3199     deviation = abs( setRate - reqRate );
   3200     if( deviation > 0 && deviation * RATE_MAX_DEVIATE_RATIO > reqRate )
   3201         result = paInvalidSampleRate;
   3202 
   3203 end:
   3204     return result;
   3205 
   3206 error:
   3207     /* Log */
   3208     {
   3209         unsigned int _min = 0, _max = 0;
   3210         int _dir = 0;
   3211         ENSURE_( alsa_snd_pcm_hw_params_get_rate_min( hwParams, &_min, &_dir ), paUnanticipatedHostError );
   3212         ENSURE_( alsa_snd_pcm_hw_params_get_rate_max( hwParams, &_max, &_dir ), paUnanticipatedHostError );
   3213         PA_DEBUG(( "%s: SR min = %u, max = %u, req = %u\n", __FUNCTION__, _min, _max, reqRate ));
   3214     }
   3215     goto end;
   3216 }
   3217 
   3218 /* Return exact sample rate in param sampleRate */
   3219 static int GetExactSampleRate( snd_pcm_hw_params_t *hwParams, double *sampleRate )
   3220 {
   3221     unsigned int num, den = 1;
   3222     int err;
   3223 
   3224     assert( hwParams );
   3225 
   3226     err = alsa_snd_pcm_hw_params_get_rate_numden( hwParams, &num, &den );
   3227     *sampleRate = (double) num / den;
   3228 
   3229     return err;
   3230 }
   3231 
   3232 /* Utility functions for blocking/callback interfaces */
   3233 
   3234 /* Atomic restart of stream (we don't want the intermediate state visible) */
   3235 static PaError AlsaRestart( PaAlsaStream *stream )
   3236 {
   3237     PaError result = paNoError;
   3238 
   3239     PA_ENSURE( PaUnixMutex_Lock( &stream->stateMtx ) );
   3240     PA_ENSURE( AlsaStop( stream, 0 ) );
   3241     PA_ENSURE( AlsaStart( stream, 0 ) );
   3242 
   3243     PA_DEBUG(( "%s: Restarted audio\n", __FUNCTION__ ));
   3244 
   3245 error:
   3246     PA_ENSURE( PaUnixMutex_Unlock( &stream->stateMtx ) );
   3247 
   3248     return result;
   3249 }
   3250 
   3251 /** Recover from xrun state.
   3252  *
   3253  */
   3254 static PaError PaAlsaStream_HandleXrun( PaAlsaStream *self )
   3255 {
   3256     PaError result = paNoError;
   3257     snd_pcm_status_t *st;
   3258     PaTime now = PaUtil_GetTime();
   3259     snd_timestamp_t t;
   3260     int restartAlsa = 0; /* do not restart Alsa by default */
   3261 
   3262     alsa_snd_pcm_status_alloca( &st );
   3263 
   3264     if( self->playback.pcm )
   3265     {
   3266         alsa_snd_pcm_status( self->playback.pcm, st );
   3267         if( alsa_snd_pcm_status_get_state( st ) == SND_PCM_STATE_XRUN )
   3268         {
   3269             alsa_snd_pcm_status_get_trigger_tstamp( st, &t );
   3270             self->underrun = now * 1000 - ( (PaTime)t.tv_sec * 1000 + (PaTime)t.tv_usec / 1000 );
   3271 
   3272             if( !self->playback.canMmap )
   3273             {
   3274                 if( alsa_snd_pcm_recover( self->playback.pcm, -EPIPE, 0 ) < 0 )
   3275                 {
   3276                     PA_DEBUG(( "%s: [playback] non-MMAP-PCM failed recovering from XRUN, will restart Alsa\n", __FUNCTION__ ));
   3277                     ++ restartAlsa; /* did not manage to recover */
   3278                 }
   3279             }
   3280             else
   3281                 ++ restartAlsa; /* always restart MMAPed device */
   3282         }
   3283     }
   3284     if( self->capture.pcm )
   3285     {
   3286         alsa_snd_pcm_status( self->capture.pcm, st );
   3287         if( alsa_snd_pcm_status_get_state( st ) == SND_PCM_STATE_XRUN )
   3288         {
   3289             alsa_snd_pcm_status_get_trigger_tstamp( st, &t );
   3290             self->overrun = now * 1000 - ((PaTime) t.tv_sec * 1000 + (PaTime) t.tv_usec / 1000);
   3291 
   3292             if (!self->capture.canMmap)
   3293             {
   3294                 if (alsa_snd_pcm_recover( self->capture.pcm, -EPIPE, 0 ) < 0)
   3295                 {
   3296                     PA_DEBUG(( "%s: [capture] non-MMAP-PCM failed recovering from XRUN, will restart Alsa\n", __FUNCTION__ ));
   3297                     ++ restartAlsa; /* did not manage to recover */
   3298                 }
   3299             }
   3300             else
   3301                 ++ restartAlsa; /* always restart MMAPed device */
   3302         }
   3303     }
   3304 
   3305     if( restartAlsa )
   3306     {
   3307         PA_DEBUG(( "%s: restarting Alsa to recover from XRUN\n", __FUNCTION__ ));
   3308         PA_ENSURE( AlsaRestart( self ) );
   3309     }
   3310 
   3311 end:
   3312     return result;
   3313 error:
   3314     goto end;
   3315 }
   3316 
   3317 /** Decide if we should continue polling for specified direction, eventually adjust the poll timeout.
   3318  *
   3319  */
   3320 static PaError ContinuePoll( const PaAlsaStream *stream, StreamDirection streamDir, int *pollTimeout, int *continuePoll )
   3321 {
   3322     PaError result = paNoError;
   3323     snd_pcm_sframes_t delay, margin;
   3324     int err;
   3325     const PaAlsaStreamComponent *component = NULL, *otherComponent = NULL;
   3326 
   3327     *continuePoll = 1;
   3328 
   3329     if( StreamDirection_In == streamDir )
   3330     {
   3331         component = &stream->capture;
   3332         otherComponent = &stream->playback;
   3333     }
   3334     else
   3335     {
   3336         component = &stream->playback;
   3337         otherComponent = &stream->capture;
   3338     }
   3339 
   3340     /* ALSA docs say that negative delay should indicate xrun, but in my experience alsa_snd_pcm_delay returns -EPIPE */
   3341     if( ( err = alsa_snd_pcm_delay( otherComponent->pcm, &delay ) ) < 0 )
   3342     {
   3343         if( err == -EPIPE )
   3344         {
   3345             /* Xrun */
   3346             *continuePoll = 0;
   3347             goto error;
   3348         }
   3349 
   3350         ENSURE_( err, paUnanticipatedHostError );
   3351     }
   3352 
   3353     if( StreamDirection_Out == streamDir )
   3354     {
   3355         /* Number of eligible frames before capture overrun */
   3356         delay = otherComponent->alsaBufferSize - delay;
   3357     }
   3358     margin = delay - otherComponent->framesPerPeriod / 2;
   3359 
   3360     if( margin < 0 )
   3361     {
   3362         PA_DEBUG(( "%s: Stopping poll for %s\n", __FUNCTION__, StreamDirection_In == streamDir ? "capture" : "playback" ));
   3363         *continuePoll = 0;
   3364     }
   3365     else if( margin < otherComponent->framesPerPeriod )
   3366     {
   3367         *pollTimeout = CalculatePollTimeout( stream, margin );
   3368         PA_DEBUG(( "%s: Trying to poll again for %s frames, pollTimeout: %d\n",
   3369                     __FUNCTION__, StreamDirection_In == streamDir ? "capture" : "playback", *pollTimeout ));
   3370     }
   3371 
   3372 error:
   3373     return result;
   3374 }
   3375 
   3376 /* Callback interface */
   3377 
   3378 static void OnExit( void *data )
   3379 {
   3380     PaAlsaStream *stream = (PaAlsaStream *) data;
   3381 
   3382     assert( data );
   3383 
   3384     PaUtil_ResetCpuLoadMeasurer( &stream->cpuLoadMeasurer );
   3385 
   3386     stream->callback_finished = 1;  /* Let the outside world know stream was stopped in callback */
   3387     PA_DEBUG(( "%s: Stopping ALSA handles\n", __FUNCTION__ ));
   3388     AlsaStop( stream, stream->callbackAbort );
   3389 
   3390     PA_DEBUG(( "%s: Stoppage\n", __FUNCTION__ ));
   3391 
   3392     /* Eventually notify user all buffers have played */
   3393     if( stream->streamRepresentation.streamFinishedCallback )
   3394     {
   3395         stream->streamRepresentation.streamFinishedCallback( stream->streamRepresentation.userData );
   3396     }
   3397     stream->isActive = 0;
   3398 }
   3399 
   3400 static void CalculateTimeInfo( PaAlsaStream *stream, PaStreamCallbackTimeInfo *timeInfo )
   3401 {
   3402     snd_pcm_status_t *capture_status, *playback_status;
   3403     snd_timestamp_t capture_timestamp, playback_timestamp;
   3404     PaTime capture_time = 0., playback_time = 0.;
   3405 
   3406     alsa_snd_pcm_status_alloca( &capture_status );
   3407     alsa_snd_pcm_status_alloca( &playback_status );
   3408 
   3409     if( stream->capture.pcm )
   3410     {
   3411         snd_pcm_sframes_t capture_delay;
   3412 
   3413         alsa_snd_pcm_status( stream->capture.pcm, capture_status );
   3414         alsa_snd_pcm_status_get_tstamp( capture_status, &capture_timestamp );
   3415 
   3416         capture_time = capture_timestamp.tv_sec +
   3417             ( (PaTime)capture_timestamp.tv_usec / 1000000.0 );
   3418         timeInfo->currentTime = capture_time;
   3419 
   3420         capture_delay = alsa_snd_pcm_status_get_delay( capture_status );
   3421         timeInfo->inputBufferAdcTime = timeInfo->currentTime -
   3422             (PaTime)capture_delay / stream->streamRepresentation.streamInfo.sampleRate;
   3423     }
   3424     if( stream->playback.pcm )
   3425     {
   3426         snd_pcm_sframes_t playback_delay;
   3427 
   3428         alsa_snd_pcm_status( stream->playback.pcm, playback_status );
   3429         alsa_snd_pcm_status_get_tstamp( playback_status, &playback_timestamp );
   3430 
   3431         playback_time = playback_timestamp.tv_sec +
   3432             ((PaTime)playback_timestamp.tv_usec / 1000000.0);
   3433 
   3434         if( stream->capture.pcm ) /* Full duplex */
   3435         {
   3436             /* Hmm, we have both a playback and a capture timestamp.
   3437              * Hopefully they are the same... */
   3438             if( fabs( capture_time - playback_time ) > 0.01 )
   3439                 PA_DEBUG(( "Capture time and playback time differ by %f\n", fabs( capture_time-playback_time ) ));
   3440         }
   3441         else
   3442             timeInfo->currentTime = playback_time;
   3443 
   3444         playback_delay = alsa_snd_pcm_status_get_delay( playback_status );
   3445         timeInfo->outputBufferDacTime = timeInfo->currentTime +
   3446             (PaTime)playback_delay / stream->streamRepresentation.streamInfo.sampleRate;
   3447     }
   3448 }
   3449 
   3450 /** Called after buffer processing is finished.
   3451  *
   3452  * A number of mmapped frames is committed, it is possible that an xrun has occurred in the meantime.
   3453  *
   3454  * @param numFrames The number of frames that has been processed
   3455  * @param xrun Return whether an xrun has occurred
   3456  */
   3457 static PaError PaAlsaStreamComponent_EndProcessing( PaAlsaStreamComponent *self, unsigned long numFrames, int *xrun )
   3458 {
   3459     PaError result = paNoError;
   3460     int res = 0;
   3461 
   3462     /* @concern FullDuplex It is possible that only one direction is marked ready after polling, and processed
   3463      * afterwards
   3464      */
   3465     if( !self->ready )
   3466         goto end;
   3467 
   3468     if( !self->canMmap && StreamDirection_Out == self->streamDir )
   3469     {
   3470         /* Play sound */
   3471         if( self->hostInterleaved )
   3472             res = alsa_snd_pcm_writei( self->pcm, self->nonMmapBuffer, numFrames );
   3473         else
   3474         {
   3475             void *bufs[self->numHostChannels];
   3476             int bufsize = alsa_snd_pcm_format_size( self->nativeFormat, self->framesPerPeriod + 1 );
   3477             unsigned char *buffer = self->nonMmapBuffer;
   3478             int i;
   3479             for( i = 0; i < self->numHostChannels; ++i )
   3480             {
   3481                 bufs[i] = buffer;
   3482                 buffer += bufsize;
   3483             }
   3484             res = alsa_snd_pcm_writen( self->pcm, bufs, numFrames );
   3485         }
   3486     }
   3487 
   3488     if( self->canMmap )
   3489         res = alsa_snd_pcm_mmap_commit( self->pcm, self->offset, numFrames );
   3490 
   3491     if( res == -EPIPE || res == -ESTRPIPE )
   3492     {
   3493         *xrun = 1;
   3494     }
   3495     else
   3496     {
   3497         ENSURE_( res, paUnanticipatedHostError );
   3498     }
   3499 
   3500 end:
   3501 error:
   3502     return result;
   3503 }
   3504 
   3505 /* Extract buffer from channel area */
   3506 static unsigned char *ExtractAddress( const snd_pcm_channel_area_t *area, snd_pcm_uframes_t offset )
   3507 {
   3508     return (unsigned char *) area->addr + ( area->first + offset * area->step ) / 8;
   3509 }
   3510 
   3511 /** Do necessary adaption between user and host channels.
   3512  *
   3513     @concern ChannelAdaption Adapting between user and host channels can involve silencing unused channels and
   3514     duplicating mono information if host outputs come in pairs.
   3515  */
   3516 static PaError PaAlsaStreamComponent_DoChannelAdaption( PaAlsaStreamComponent *self, PaUtilBufferProcessor *bp, int numFrames )
   3517 {
   3518     PaError result = paNoError;
   3519     unsigned char *p;
   3520     int i;
   3521     int unusedChans = self->numHostChannels - self->numUserChannels;
   3522     unsigned char *src, *dst;
   3523     int convertMono = ( self->numHostChannels % 2 ) == 0 && ( self->numUserChannels % 2 ) != 0;
   3524 
   3525     assert( StreamDirection_Out == self->streamDir );
   3526 
   3527     if( self->hostInterleaved )
   3528     {
   3529         int swidth = alsa_snd_pcm_format_size( self->nativeFormat, 1 );
   3530         unsigned char *buffer = self->canMmap ? ExtractAddress( self->channelAreas, self->offset ) : self->nonMmapBuffer;
   3531 
   3532         /* Start after the last user channel */
   3533         p = buffer + self->numUserChannels * swidth;
   3534 
   3535         if( convertMono )
   3536         {
   3537             /* Convert the last user channel into stereo pair */
   3538             src = buffer + ( self->numUserChannels - 1 ) * swidth;
   3539             for( i = 0; i < numFrames; ++i )
   3540             {
   3541                 dst = src + swidth;
   3542                 memcpy( dst, src, swidth );
   3543                 src += self->numHostChannels * swidth;
   3544             }
   3545 
   3546             /* Don't touch the channel we just wrote to */
   3547             p += swidth;
   3548             --unusedChans;
   3549         }
   3550 
   3551         if( unusedChans > 0 )
   3552         {
   3553             /* Silence unused output channels */
   3554             for( i = 0; i < numFrames; ++i )
   3555             {
   3556                 memset( p, 0, swidth * unusedChans );
   3557                 p += self->numHostChannels * swidth;
   3558             }
   3559         }
   3560     }
   3561     else
   3562     {
   3563         /* We extract the last user channel */
   3564         if( convertMono )
   3565         {
   3566             ENSURE_( alsa_snd_pcm_area_copy( self->channelAreas + self->numUserChannels, self->offset, self->channelAreas +
   3567                     ( self->numUserChannels - 1 ), self->offset, numFrames, self->nativeFormat ), paUnanticipatedHostError );
   3568             --unusedChans;
   3569         }
   3570         if( unusedChans > 0 )
   3571         {
   3572             alsa_snd_pcm_areas_silence( self->channelAreas + ( self->numHostChannels - unusedChans ), self->offset, unusedChans, numFrames,
   3573                     self->nativeFormat );
   3574         }
   3575     }
   3576 
   3577 error:
   3578     return result;
   3579 }
   3580 
   3581 static PaError PaAlsaStream_EndProcessing( PaAlsaStream *self, unsigned long numFrames, int *xrunOccurred )
   3582 {
   3583     PaError result = paNoError;
   3584     int xrun = 0;
   3585 
   3586     if( self->capture.pcm )
   3587     {
   3588         PA_ENSURE( PaAlsaStreamComponent_EndProcessing( &self->capture, numFrames, &xrun ) );
   3589     }
   3590     if( self->playback.pcm )
   3591     {
   3592         if( self->playback.numHostChannels > self->playback.numUserChannels )
   3593         {
   3594             PA_ENSURE( PaAlsaStreamComponent_DoChannelAdaption( &self->playback, &self->bufferProcessor, numFrames ) );
   3595         }
   3596         PA_ENSURE( PaAlsaStreamComponent_EndProcessing( &self->playback, numFrames, &xrun ) );
   3597     }
   3598 
   3599 error:
   3600     *xrunOccurred = xrun;
   3601     return result;
   3602 }
   3603 
   3604 /** Update the number of available frames.
   3605  *
   3606  */
   3607 static PaError PaAlsaStreamComponent_GetAvailableFrames( PaAlsaStreamComponent *self, unsigned long *numFrames, int *xrunOccurred )
   3608 {
   3609     PaError result = paNoError;
   3610     snd_pcm_sframes_t framesAvail = alsa_snd_pcm_avail_update( self->pcm );
   3611     *xrunOccurred = 0;
   3612 
   3613     if( -EPIPE == framesAvail )
   3614     {
   3615         *xrunOccurred = 1;
   3616         framesAvail = 0;
   3617     }
   3618     else
   3619     {
   3620         ENSURE_( framesAvail, paUnanticipatedHostError );
   3621     }
   3622 
   3623     *numFrames = framesAvail;
   3624 
   3625 error:
   3626     return result;
   3627 }
   3628 
   3629 /** Fill in pollfd objects.
   3630  */
   3631 static PaError PaAlsaStreamComponent_BeginPolling( PaAlsaStreamComponent* self, struct pollfd* pfds )
   3632 {
   3633     PaError result = paNoError;
   3634     int ret = alsa_snd_pcm_poll_descriptors( self->pcm, pfds, self->nfds );
   3635     (void)ret;  /* Prevent unused variable warning if asserts are turned off */
   3636     assert( ret == self->nfds );
   3637 
   3638     self->ready = 0;
   3639 
   3640     return result;
   3641 }
   3642 
   3643 /** Examine results from poll().
   3644  *
   3645  * @param pfds pollfds to inspect
   3646  * @param shouldPoll Should we continue to poll
   3647  * @param xrun Has an xrun occurred
   3648  */
   3649 static PaError PaAlsaStreamComponent_EndPolling( PaAlsaStreamComponent* self, struct pollfd* pfds, int* shouldPoll, int* xrun )
   3650 {
   3651     PaError result = paNoError;
   3652     unsigned short revents;
   3653 
   3654     ENSURE_( alsa_snd_pcm_poll_descriptors_revents( self->pcm, pfds, self->nfds, &revents ), paUnanticipatedHostError );
   3655     if( revents != 0 )
   3656     {
   3657         if( revents & POLLERR )
   3658         {
   3659             *xrun = 1;
   3660         }
   3661         else if( revents & POLLHUP )
   3662         {
   3663             *xrun = 1;
   3664             PA_DEBUG(( "%s: revents has POLLHUP, processing as XRUN\n", __FUNCTION__ ));
   3665         }
   3666         else
   3667             self->ready = 1;
   3668 
   3669         *shouldPoll = 0;
   3670     }
   3671     else /* (A zero revent occurred) */
   3672         /* Work around an issue with Alsa older than 1.0.16 using some plugins (eg default with plug + dmix) where
   3673          * POLLIN or POLLOUT are zeroed by Alsa-lib if _mmap_avail() is a few frames short of avail_min at period
   3674          * boundary, possibly due to erratic dma interrupts at period boundary?  Treat as a valid event.
   3675          */
   3676         if( self->useReventFix )
   3677         {
   3678             self->ready = 1;
   3679             *shouldPoll = 0;
   3680         }
   3681 
   3682 error:
   3683     return result;
   3684 }
   3685 
   3686 /** Return the number of available frames for this stream.
   3687  *
   3688  * @concern FullDuplex The minimum available for the two directions is calculated, it might be desirable to ignore
   3689  * one direction however (not marked ready from poll), so this is controlled by queryCapture and queryPlayback.
   3690  *
   3691  * @param queryCapture Check available for capture
   3692  * @param queryPlayback Check available for playback
   3693  * @param available The returned number of frames
   3694  * @param xrunOccurred Return whether an xrun has occurred
   3695  */
   3696 static PaError PaAlsaStream_GetAvailableFrames( PaAlsaStream *self, int queryCapture, int queryPlayback, unsigned long
   3697         *available, int *xrunOccurred )
   3698 {
   3699     PaError result = paNoError;
   3700     unsigned long captureFrames, playbackFrames;
   3701     *xrunOccurred = 0;
   3702 
   3703     assert( queryCapture || queryPlayback );
   3704 
   3705     if( queryCapture )
   3706     {
   3707         assert( self->capture.pcm );
   3708         PA_ENSURE( PaAlsaStreamComponent_GetAvailableFrames( &self->capture, &captureFrames, xrunOccurred ) );
   3709         if( *xrunOccurred )
   3710         {
   3711             goto end;
   3712         }
   3713     }
   3714     if( queryPlayback )
   3715     {
   3716         assert( self->playback.pcm );
   3717         PA_ENSURE( PaAlsaStreamComponent_GetAvailableFrames( &self->playback, &playbackFrames, xrunOccurred ) );
   3718         if( *xrunOccurred )
   3719         {
   3720             goto end;
   3721         }
   3722     }
   3723 
   3724     if( queryCapture && queryPlayback )
   3725     {
   3726         *available = PA_MIN( captureFrames, playbackFrames );
   3727         /*PA_DEBUG(("capture: %lu, playback: %lu, combined: %lu\n", captureFrames, playbackFrames, *available));*/
   3728     }
   3729     else if( queryCapture )
   3730     {
   3731         *available = captureFrames;
   3732     }
   3733     else
   3734     {
   3735         *available = playbackFrames;
   3736     }
   3737 
   3738 end:
   3739 error:
   3740     return result;
   3741 }
   3742 
   3743 /** Wait for and report available buffer space from ALSA.
   3744  *
   3745  * Unless ALSA reports a minimum of frames available for I/O, we poll the ALSA filedescriptors for more.
   3746  * Both of these operations can uncover xrun conditions.
   3747  *
   3748  * @concern Xruns Both polling and querying available frames can report an xrun condition.
   3749  *
   3750  * @param framesAvail Return the number of available frames
   3751  * @param xrunOccurred Return whether an xrun has occurred
   3752  */
   3753 static PaError PaAlsaStream_WaitForFrames( PaAlsaStream *self, unsigned long *framesAvail, int *xrunOccurred )
   3754 {
   3755     PaError result = paNoError;
   3756     int pollPlayback = self->playback.pcm != NULL, pollCapture = self->capture.pcm != NULL;
   3757     int pollTimeout = self->pollTimeout;
   3758     int xrun = 0, timeouts = 0;
   3759     int pollResults;
   3760 
   3761     assert( self );
   3762     assert( framesAvail );
   3763 
   3764     if( !self->callbackMode )
   3765     {
   3766         /* In blocking mode we will only wait if necessary */
   3767         PA_ENSURE( PaAlsaStream_GetAvailableFrames( self, self->capture.pcm != NULL, self->playback.pcm != NULL,
   3768                     framesAvail, &xrun ) );
   3769         if( xrun )
   3770         {
   3771             goto end;
   3772         }
   3773 
   3774         if( *framesAvail > 0 )
   3775         {
   3776             /* Mark pcms ready from poll */
   3777             if( self->capture.pcm )
   3778                 self->capture.ready = 1;
   3779             if( self->playback.pcm )
   3780                 self->playback.ready = 1;
   3781 
   3782             goto end;
   3783         }
   3784     }
   3785 
   3786     while( pollPlayback || pollCapture )
   3787     {
   3788         int totalFds = 0;
   3789         struct pollfd *capturePfds = NULL, *playbackPfds = NULL;
   3790 
   3791 #ifdef PTHREAD_CANCELED
   3792         pthread_testcancel();
   3793 #endif
   3794         if( pollCapture )
   3795         {
   3796             capturePfds = self->pfds;
   3797             PA_ENSURE( PaAlsaStreamComponent_BeginPolling( &self->capture, capturePfds ) );
   3798             totalFds += self->capture.nfds;
   3799         }
   3800         if( pollPlayback )
   3801         {
   3802             /* self->pfds is in effect an array of fds; if necessary, index past the capture fds */
   3803             playbackPfds = self->pfds + (pollCapture ? self->capture.nfds : 0);
   3804             PA_ENSURE( PaAlsaStreamComponent_BeginPolling( &self->playback, playbackPfds ) );
   3805             totalFds += self->playback.nfds;
   3806         }
   3807 
   3808 #ifdef PTHREAD_CANCELED
   3809         if( self->callbackMode )
   3810         {
   3811             /* To allow 'Abort' to terminate the callback thread, enable cancelability just for poll() (& disable after) */
   3812             pthread_setcancelstate( PTHREAD_CANCEL_ENABLE, NULL );
   3813         }
   3814 #endif
   3815 
   3816         pollResults = poll( self->pfds, totalFds, pollTimeout );
   3817 
   3818 #ifdef PTHREAD_CANCELED
   3819         if( self->callbackMode )
   3820         {
   3821             pthread_setcancelstate( PTHREAD_CANCEL_DISABLE, NULL );
   3822         }
   3823 #endif
   3824 
   3825         if( pollResults < 0 )
   3826         {
   3827             /*  XXX: Depend on preprocessor condition? */
   3828             if( errno == EINTR )
   3829             {
   3830                 /* gdb */
   3831                 Pa_Sleep( 1 ); /* avoid hot loop */
   3832                 continue;
   3833             }
   3834 
   3835             /* TODO: Add macro for checking system calls */
   3836             PA_ENSURE( paInternalError );
   3837         }
   3838         else if( pollResults == 0 )
   3839         {
   3840            /* Suspended, paused or failed device can provide 0 poll results. To avoid deadloop in such situation
   3841             * we simply run counter 'timeouts' which detects 0 poll result and accumulates. As soon as 2048 timouts (around 2 seconds)
   3842             * are achieved we simply fail function with paTimedOut to notify waiting methods that device is not capable
   3843             * of providing audio data anymore and needs some corresponding recovery action.
   3844             * Note that 'timeouts' is reset to 0 if poll() managed to return non 0 results.
   3845             */
   3846 
   3847             /*PA_DEBUG(( "%s: poll == 0 results, timed out, %d times left\n", __FUNCTION__, 2048 - timeouts ));*/
   3848             ++ timeouts;
   3849             if( timeouts > 1 ) /* sometimes device times out, but normally once, so we do not sleep any time */
   3850             {
   3851                 Pa_Sleep( 1 ); /* avoid hot loop */
   3852             }
   3853             /* not else ! */
   3854             if( timeouts >= 2048 ) /* audio device not working, shall return error to notify waiters */
   3855             {
   3856                 *framesAvail = 0; /* no frames available for processing */
   3857                 xrun = 1; /* try recovering device */
   3858 
   3859                 PA_DEBUG(( "%s: poll timed out\n", __FUNCTION__, timeouts ));
   3860                 goto end;/*PA_ENSURE( paTimedOut );*/
   3861             }
   3862         }
   3863         else if( pollResults > 0 )
   3864         {
   3865             /* reset timouts counter */
   3866             timeouts = 0;
   3867 
   3868             /* check the return status of our pfds */
   3869             if( pollCapture )
   3870             {
   3871                 PA_ENSURE( PaAlsaStreamComponent_EndPolling( &self->capture, capturePfds, &pollCapture, &xrun ) );
   3872             }
   3873             if( pollPlayback )
   3874             {
   3875                 PA_ENSURE( PaAlsaStreamComponent_EndPolling( &self->playback, playbackPfds, &pollPlayback, &xrun ) );
   3876             }
   3877             if( xrun )
   3878             {
   3879                 break;
   3880             }
   3881         }
   3882 
   3883         /* @concern FullDuplex If only one of two pcms is ready we may want to compromise between the two.
   3884          * If there is less than half a period's worth of samples left of frames in the other pcm's buffer we will
   3885          * stop polling.
   3886          */
   3887         if( self->capture.pcm && self->playback.pcm )
   3888         {
   3889             if( pollCapture && !pollPlayback )
   3890             {
   3891                 PA_ENSURE( ContinuePoll( self, StreamDirection_In, &pollTimeout, &pollCapture ) );
   3892             }
   3893             else if( pollPlayback && !pollCapture )
   3894             {
   3895                 PA_ENSURE( ContinuePoll( self, StreamDirection_Out, &pollTimeout, &pollPlayback ) );
   3896             }
   3897         }
   3898     }
   3899 
   3900     if( !xrun )
   3901     {
   3902         /* Get the number of available frames for the pcms that are marked ready.
   3903          * @concern FullDuplex If only one direction is marked ready (from poll), the number of frames available for
   3904          * the other direction is returned. Output is normally preferred over capture however, so capture frames may be
   3905          * discarded to avoid overrun unless paNeverDropInput is specified.
   3906          */
   3907         int captureReady = self->capture.pcm ? self->capture.ready : 0,
   3908             playbackReady = self->playback.pcm ? self->playback.ready : 0;
   3909         PA_ENSURE( PaAlsaStream_GetAvailableFrames( self, captureReady, playbackReady, framesAvail, &xrun ) );
   3910 
   3911         if( self->capture.pcm && self->playback.pcm )
   3912         {
   3913             if( !self->playback.ready && !self->neverDropInput )
   3914             {
   3915                 /* Drop input, a period's worth */
   3916                 assert( self->capture.ready );
   3917                 PaAlsaStreamComponent_EndProcessing( &self->capture, PA_MIN( self->capture.framesPerPeriod,
   3918                             *framesAvail ), &xrun );
   3919                 *framesAvail = 0;
   3920                 self->capture.ready = 0;
   3921             }
   3922         }
   3923         else if( self->capture.pcm )
   3924             assert( self->capture.ready );
   3925         else
   3926             assert( self->playback.ready );
   3927     }
   3928 
   3929 end:
   3930 error:
   3931     if( xrun )
   3932     {
   3933         /* Recover from the xrun state */
   3934         PA_ENSURE( PaAlsaStream_HandleXrun( self ) );
   3935         *framesAvail = 0;
   3936     }
   3937     else
   3938     {
   3939         if( 0 != *framesAvail )
   3940         {
   3941             /* If we're reporting frames eligible for processing, one of the handles better be ready */
   3942             PA_UNLESS( self->capture.ready || self->playback.ready, paInternalError );
   3943         }
   3944     }
   3945     *xrunOccurred = xrun;
   3946 
   3947     return result;
   3948 }
   3949 
   3950 /** Register per-channel ALSA buffer information with buffer processor.
   3951  *
   3952  * Mmapped buffer space is acquired from ALSA, and registered with the buffer processor. Differences between the
   3953  * number of host and user channels is taken into account.
   3954  *
   3955  * @param numFrames On entrance the number of requested frames, on exit the number of contiguously accessible frames.
   3956  */
   3957 static PaError PaAlsaStreamComponent_RegisterChannels( PaAlsaStreamComponent* self, PaUtilBufferProcessor* bp,
   3958         unsigned long* numFrames, int* xrun )
   3959 {
   3960     PaError result = paNoError;
   3961     const snd_pcm_channel_area_t *areas, *area;
   3962     void (*setChannel)(PaUtilBufferProcessor *, unsigned int, void *, unsigned int) =
   3963         StreamDirection_In == self->streamDir ? PaUtil_SetInputChannel : PaUtil_SetOutputChannel;
   3964     unsigned char *buffer, *p;
   3965     int i;
   3966     unsigned long framesAvail;
   3967 
   3968     /* This _must_ be called before mmap_begin */
   3969     PA_ENSURE( PaAlsaStreamComponent_GetAvailableFrames( self, &framesAvail, xrun ) );
   3970     if( *xrun )
   3971     {
   3972         *numFrames = 0;
   3973         goto end;
   3974     }
   3975 
   3976     if( self->canMmap )
   3977     {
   3978         ENSURE_( alsa_snd_pcm_mmap_begin( self->pcm, &areas, &self->offset, numFrames ), paUnanticipatedHostError );
   3979         /* @concern ChannelAdaption Buffer address is recorded so we can do some channel adaption later */
   3980         self->channelAreas = (snd_pcm_channel_area_t *)areas;
   3981     }
   3982     else
   3983     {
   3984         unsigned int bufferSize = self->numHostChannels * alsa_snd_pcm_format_size( self->nativeFormat, *numFrames );
   3985         if( bufferSize > self->nonMmapBufferSize )
   3986         {
   3987             self->nonMmapBuffer = realloc( self->nonMmapBuffer, ( self->nonMmapBufferSize = bufferSize ) );
   3988             if( !self->nonMmapBuffer )
   3989             {
   3990                 result = paInsufficientMemory;
   3991                 goto error;
   3992             }
   3993         }
   3994     }
   3995 
   3996     if( self->hostInterleaved )
   3997     {
   3998         int swidth = alsa_snd_pcm_format_size( self->nativeFormat, 1 );
   3999 
   4000         p = buffer = self->canMmap ? ExtractAddress( areas, self->offset ) : self->nonMmapBuffer;
   4001         for( i = 0; i < self->numUserChannels; ++i )
   4002         {
   4003             /* We're setting the channels up to userChannels, but the stride will be hostChannels samples */
   4004             setChannel( bp, i, p, self->numHostChannels );
   4005             p += swidth;
   4006         }
   4007     }
   4008     else
   4009     {
   4010         if( self->canMmap )
   4011         {
   4012             for( i = 0; i < self->numUserChannels; ++i )
   4013             {
   4014                 area = areas + i;
   4015                 buffer = ExtractAddress( area, self->offset );
   4016                 setChannel( bp, i, buffer, 1 );
   4017             }
   4018         }
   4019         else
   4020         {
   4021             unsigned int buf_per_ch_size = self->nonMmapBufferSize / self->numHostChannels;
   4022             buffer = self->nonMmapBuffer;
   4023             for( i = 0; i < self->numUserChannels; ++i )
   4024             {
   4025                 setChannel( bp, i, buffer, 1 );
   4026                 buffer += buf_per_ch_size;
   4027             }
   4028         }
   4029     }
   4030 
   4031     if( !self->canMmap && StreamDirection_In == self->streamDir )
   4032     {
   4033         /* Read sound */
   4034         int res;
   4035         if( self->hostInterleaved )
   4036             res = alsa_snd_pcm_readi( self->pcm, self->nonMmapBuffer, *numFrames );
   4037         else
   4038         {
   4039             void *bufs[self->numHostChannels];
   4040             unsigned int buf_per_ch_size = self->nonMmapBufferSize / self->numHostChannels;
   4041             unsigned char *buffer = self->nonMmapBuffer;
   4042             int i;
   4043             for( i = 0; i < self->numHostChannels; ++i )
   4044             {
   4045                 bufs[i] = buffer;
   4046                 buffer += buf_per_ch_size;
   4047             }
   4048             res = alsa_snd_pcm_readn( self->pcm, bufs, *numFrames );
   4049         }
   4050         if( res == -EPIPE || res == -ESTRPIPE )
   4051         {
   4052             *xrun = 1;
   4053             *numFrames = 0;
   4054         }
   4055     }
   4056 
   4057 end:
   4058 error:
   4059     return result;
   4060 }
   4061 
   4062 /** Initiate buffer processing.
   4063  *
   4064  * ALSA buffers are registered with the PA buffer processor and the buffer size (in frames) set.
   4065  *
   4066  * @concern FullDuplex If both directions are being processed, the minimum amount of frames for the two directions is
   4067  * calculated.
   4068  *
   4069  * @param numFrames On entrance the number of available frames, on exit the number of received frames
   4070  * @param xrunOccurred Return whether an xrun has occurred
   4071  */
   4072 static PaError PaAlsaStream_SetUpBuffers( PaAlsaStream* self, unsigned long* numFrames, int* xrunOccurred )
   4073 {
   4074     PaError result = paNoError;
   4075     unsigned long captureFrames = ULONG_MAX, playbackFrames = ULONG_MAX, commonFrames = 0;
   4076     int xrun = 0;
   4077 
   4078     if( *xrunOccurred )
   4079     {
   4080         *numFrames = 0;
   4081         return result;
   4082     }
   4083     /* If we got here at least one of the pcm's should be marked ready */
   4084     PA_UNLESS( self->capture.ready || self->playback.ready, paInternalError );
   4085 
   4086     /* Extract per-channel ALSA buffer pointers and register them with the buffer processor.
   4087      * It is possible that a direction is not marked ready however, because it is out of sync with the other.
   4088      */
   4089     if( self->capture.pcm && self->capture.ready )
   4090     {
   4091         captureFrames = *numFrames;
   4092         PA_ENSURE( PaAlsaStreamComponent_RegisterChannels( &self->capture, &self->bufferProcessor, &captureFrames,
   4093                     &xrun ) );
   4094     }
   4095     if( self->playback.pcm && self->playback.ready )
   4096     {
   4097         playbackFrames = *numFrames;
   4098         PA_ENSURE( PaAlsaStreamComponent_RegisterChannels( &self->playback, &self->bufferProcessor, &playbackFrames,
   4099                     &xrun ) );
   4100     }
   4101     if( xrun )
   4102     {
   4103         /* Nothing more to do */
   4104         assert( 0 == commonFrames );
   4105         goto end;
   4106     }
   4107 
   4108     commonFrames = PA_MIN( captureFrames, playbackFrames );
   4109     /* assert( commonFrames <= *numFrames ); */
   4110     if( commonFrames > *numFrames )
   4111     {
   4112         /* Hmmm ... how come there are more frames available than we requested!? Blah. */
   4113         PA_DEBUG(( "%s: Common available frames are reported to be more than number requested: %lu, %lu, callbackMode: %d\n", __FUNCTION__,
   4114                     commonFrames, *numFrames, self->callbackMode ));
   4115         if( self->capture.pcm )
   4116         {
   4117             PA_DEBUG(( "%s: captureFrames: %lu, capture.ready: %d\n", __FUNCTION__, captureFrames, self->capture.ready ));
   4118         }
   4119         if( self->playback.pcm )
   4120         {
   4121             PA_DEBUG(( "%s: playbackFrames: %lu, playback.ready: %d\n", __FUNCTION__, playbackFrames, self->playback.ready ));
   4122         }
   4123 
   4124         commonFrames = 0;
   4125         goto end;
   4126     }
   4127 
   4128     /* Inform PortAudio of the number of frames we got.
   4129      * @concern FullDuplex We might be experiencing underflow in either end; if its an input underflow, we go on
   4130      * with output. If its output underflow however, depending on the paNeverDropInput flag, we may want to simply
   4131      * discard the excess input or call the callback with paOutputOverflow flagged.
   4132      */
   4133     if( self->capture.pcm )
   4134     {
   4135         if( self->capture.ready )
   4136         {
   4137             PaUtil_SetInputFrameCount( &self->bufferProcessor, commonFrames );
   4138         }
   4139         else
   4140         {
   4141             /* We have input underflow */
   4142             PaUtil_SetNoInput( &self->bufferProcessor );
   4143         }
   4144     }
   4145     if( self->playback.pcm )
   4146     {
   4147         if( self->playback.ready )
   4148         {
   4149             PaUtil_SetOutputFrameCount( &self->bufferProcessor, commonFrames );
   4150         }
   4151         else
   4152         {
   4153             /* We have output underflow, but keeping input data (paNeverDropInput) */
   4154             assert( self->neverDropInput );
   4155             assert( self->capture.pcm != NULL );
   4156             PA_DEBUG(( "%s: Setting output buffers to NULL\n", __FUNCTION__ ));
   4157             PaUtil_SetNoOutput( &self->bufferProcessor );
   4158         }
   4159     }
   4160 
   4161 end:
   4162     *numFrames = commonFrames;
   4163 error:
   4164     if( xrun )
   4165     {
   4166         PA_ENSURE( PaAlsaStream_HandleXrun( self ) );
   4167         *numFrames = 0;
   4168     }
   4169     *xrunOccurred = xrun;
   4170 
   4171     return result;
   4172 }
   4173 
   4174 /** Callback thread's function.
   4175  *
   4176  * Roughly, the workflow can be described in the following way: The number of available frames that can be processed
   4177  * directly is obtained from ALSA, we then request as much directly accessible memory as possible within this amount
   4178  * from ALSA. The buffer memory is registered with the PA buffer processor and processing is carried out with
   4179  * PaUtil_EndBufferProcessing. Finally, the number of processed frames is reported to ALSA. The processing can
   4180  * happen in several iterations untill we have consumed the known number of available frames (or an xrun is detected).
   4181  */
   4182 static void *CallbackThreadFunc( void *userData )
   4183 {
   4184     PaError result = paNoError;
   4185     PaAlsaStream *stream = (PaAlsaStream*) userData;
   4186     PaStreamCallbackTimeInfo timeInfo = {0, 0, 0};
   4187     snd_pcm_sframes_t startThreshold = 0;
   4188     int callbackResult = paContinue;
   4189     PaStreamCallbackFlags cbFlags = 0;  /* We might want to keep state across iterations */
   4190     int streamStarted = 0;
   4191 
   4192     assert( stream );
   4193     /* Not implemented */
   4194     assert( !stream->primeBuffers );
   4195 
   4196     /* Execute OnExit when exiting */
   4197     pthread_cleanup_push( &OnExit, stream );
   4198 #ifdef PTHREAD_CANCELED
   4199     /* 'Abort' will use thread cancellation to terminate the callback thread, but the Alsa-lib functions
   4200      * are NOT cancel-safe, (and can end up in an inconsistent state).  So, disable cancelability for
   4201      * the thread here, and just re-enable it for the poll() in PaAlsaStream_WaitForFrames(). */
   4202     pthread_testcancel();
   4203     pthread_setcancelstate( PTHREAD_CANCEL_DISABLE, NULL );
   4204 #endif
   4205 
   4206     /* @concern StreamStart If the output is being primed the output pcm needs to be prepared, otherwise the
   4207      * stream is started immediately. The latter involves signaling the waiting main thread.
   4208      */
   4209     if( stream->primeBuffers )
   4210     {
   4211         snd_pcm_sframes_t avail;
   4212 
   4213         if( stream->playback.pcm )
   4214             ENSURE_( alsa_snd_pcm_prepare( stream->playback.pcm ), paUnanticipatedHostError );
   4215         if( stream->capture.pcm && !stream->pcmsSynced )
   4216             ENSURE_( alsa_snd_pcm_prepare( stream->capture.pcm ), paUnanticipatedHostError );
   4217 
   4218         /* We can't be certain that the whole ring buffer is available for priming, but there should be
   4219          * at least one period */
   4220         avail = alsa_snd_pcm_avail_update( stream->playback.pcm );
   4221         startThreshold = avail - (avail % stream->playback.framesPerPeriod);
   4222         assert( startThreshold >= stream->playback.framesPerPeriod );
   4223     }
   4224     else
   4225     {
   4226         PA_ENSURE( PaUnixThread_PrepareNotify( &stream->thread ) );
   4227         /* Buffer will be zeroed */
   4228         PA_ENSURE( AlsaStart( stream, 0 ) );
   4229         PA_ENSURE( PaUnixThread_NotifyParent( &stream->thread ) );
   4230 
   4231         streamStarted = 1;
   4232     }
   4233 
   4234     while( 1 )
   4235     {
   4236         unsigned long framesAvail, framesGot;
   4237         int xrun = 0;
   4238 
   4239 #ifdef PTHREAD_CANCELED
   4240         pthread_testcancel();
   4241 #endif
   4242 
   4243         /* @concern StreamStop if the main thread has requested a stop and the stream has not been effectively
   4244          * stopped we signal this condition by modifying callbackResult (we'll want to flush buffered output).
   4245          */
   4246         if( PaUnixThread_StopRequested( &stream->thread ) && paContinue == callbackResult )
   4247         {
   4248             PA_DEBUG(( "Setting callbackResult to paComplete\n" ));
   4249             callbackResult = paComplete;
   4250         }
   4251 
   4252         if( paContinue != callbackResult )
   4253         {
   4254             stream->callbackAbort = ( paAbort == callbackResult );
   4255             if( stream->callbackAbort ||
   4256                     /** @concern BlockAdaption: Go on if adaption buffers are empty */
   4257                     PaUtil_IsBufferProcessorOutputEmpty( &stream->bufferProcessor ) )
   4258             {
   4259                 goto end;
   4260             }
   4261 
   4262             PA_DEBUG(( "%s: Flushing buffer processor\n", __FUNCTION__ ));
   4263             /* There is still buffered output that needs to be processed */
   4264         }
   4265 
   4266         /* Wait for data to become available, this comes down to polling the ALSA file descriptors untill we have
   4267          * a number of available frames.
   4268          */
   4269         PA_ENSURE( PaAlsaStream_WaitForFrames( stream, &framesAvail, &xrun ) );
   4270         if( xrun )
   4271         {
   4272             assert( 0 == framesAvail );
   4273             continue;
   4274 
   4275             /* XXX: Report xruns to the user? A situation is conceivable where the callback is never invoked due
   4276              * to constant xruns, it might be desirable to notify the user of this.
   4277              */
   4278         }
   4279 
   4280         /* Consume buffer space. Once we have a number of frames available for consumption we must retrieve the
   4281          * mmapped buffers from ALSA, this is contiguously accessible memory however, so we may receive smaller
   4282          * portions at a time than is available as a whole. Therefore we should be prepared to process several
   4283          * chunks successively. The buffers are passed to the PA buffer processor.
   4284          */
   4285         while( framesAvail > 0 )
   4286         {
   4287             xrun = 0;
   4288 
   4289             /** @concern Xruns Under/overflows are to be reported to the callback */
   4290             if( stream->underrun > 0.0 )
   4291             {
   4292                 cbFlags |= paOutputUnderflow;
   4293                 stream->underrun = 0.0;
   4294             }
   4295             if( stream->overrun > 0.0 )
   4296             {
   4297                 cbFlags |= paInputOverflow;
   4298                 stream->overrun = 0.0;
   4299             }
   4300             if( stream->capture.pcm && stream->playback.pcm )
   4301             {
   4302                 /** @concern FullDuplex It's possible that only one direction is being processed to avoid an
   4303                  * under- or overflow, this should be reported correspondingly */
   4304                 if( !stream->capture.ready )
   4305                 {
   4306                     cbFlags |= paInputUnderflow;
   4307                     PA_DEBUG(( "%s: Input underflow\n", __FUNCTION__ ));
   4308                 }
   4309                 else if( !stream->playback.ready )
   4310                 {
   4311                     cbFlags |= paOutputOverflow;
   4312                     PA_DEBUG(( "%s: Output overflow\n", __FUNCTION__ ));
   4313                 }
   4314             }
   4315 
   4316 #if 0
   4317             CallbackUpdate( &stream->threading );
   4318 #endif
   4319 
   4320             CalculateTimeInfo( stream, &timeInfo );
   4321             PaUtil_BeginBufferProcessing( &stream->bufferProcessor, &timeInfo, cbFlags );
   4322             cbFlags = 0;
   4323 
   4324             /* CPU load measurement should include processing activity external to the stream callback */
   4325             PaUtil_BeginCpuLoadMeasurement( &stream->cpuLoadMeasurer );
   4326 
   4327             framesGot = framesAvail;
   4328             if( paUtilFixedHostBufferSize == stream->bufferProcessor.hostBufferSizeMode )
   4329             {
   4330                 /* We've committed to a fixed host buffer size, stick to that */
   4331                 framesGot = framesGot >= stream->maxFramesPerHostBuffer ? stream->maxFramesPerHostBuffer : 0;
   4332             }
   4333             else
   4334             {
   4335                 /* We've committed to an upper bound on the size of host buffers */
   4336                 assert( paUtilBoundedHostBufferSize == stream->bufferProcessor.hostBufferSizeMode );
   4337                 framesGot = PA_MIN( framesGot, stream->maxFramesPerHostBuffer );
   4338             }
   4339             PA_ENSURE( PaAlsaStream_SetUpBuffers( stream, &framesGot, &xrun ) );
   4340             /* Check the host buffer size against the buffer processor configuration */
   4341             framesAvail -= framesGot;
   4342 
   4343             if( framesGot > 0 )
   4344             {
   4345                 assert( !xrun );
   4346                 PaUtil_EndBufferProcessing( &stream->bufferProcessor, &callbackResult );
   4347                 PA_ENSURE( PaAlsaStream_EndProcessing( stream, framesGot, &xrun ) );
   4348             }
   4349             PaUtil_EndCpuLoadMeasurement( &stream->cpuLoadMeasurer, framesGot );
   4350 
   4351             if( 0 == framesGot )
   4352             {
   4353                 /* Go back to polling for more frames */
   4354                 break;
   4355             }
   4356 
   4357             if( paContinue != callbackResult )
   4358                 break;
   4359         }
   4360     }
   4361 
   4362 end:
   4363     ; /* Hack to fix "label at end of compound statement" error caused by pthread_cleanup_pop(1) macro. */
   4364     /* Match pthread_cleanup_push */
   4365     pthread_cleanup_pop( 1 );
   4366 
   4367     PA_DEBUG(( "%s: Thread %d exiting\n ", __FUNCTION__, pthread_self() ));
   4368     PaUnixThreading_EXIT( result );
   4369 
   4370 error:
   4371     PA_DEBUG(( "%s: Thread %d is canceled due to error %d\n ", __FUNCTION__, pthread_self(), result ));
   4372     goto end;
   4373 }
   4374 
   4375 /* Blocking interface */
   4376 
   4377 static PaError ReadStream( PaStream* s, void *buffer, unsigned long frames )
   4378 {
   4379     PaError result = paNoError;
   4380     PaAlsaStream *stream = (PaAlsaStream*)s;
   4381     unsigned long framesGot, framesAvail;
   4382     void *userBuffer;
   4383     snd_pcm_t *save = stream->playback.pcm;
   4384 
   4385     assert( stream );
   4386 
   4387     PA_UNLESS( stream->capture.pcm, paCanNotReadFromAnOutputOnlyStream );
   4388 
   4389     /* Disregard playback */
   4390     stream->playback.pcm = NULL;
   4391 
   4392     if( stream->overrun > 0. )
   4393     {
   4394         result = paInputOverflowed;
   4395         stream->overrun = 0.0;
   4396     }
   4397 
   4398     if( stream->capture.userInterleaved )
   4399     {
   4400         userBuffer = buffer;
   4401     }
   4402     else
   4403     {
   4404         /* Copy channels into local array */
   4405         userBuffer = stream->capture.userBuffers;
   4406         memcpy( userBuffer, buffer, sizeof (void *) * stream->capture.numUserChannels );
   4407     }
   4408 
   4409     /* Start stream if in prepared state */
   4410     if( alsa_snd_pcm_state( stream->capture.pcm ) == SND_PCM_STATE_PREPARED )
   4411     {
   4412         ENSURE_( alsa_snd_pcm_start( stream->capture.pcm ), paUnanticipatedHostError );
   4413     }
   4414 
   4415     while( frames > 0 )
   4416     {
   4417         int xrun = 0;
   4418         PA_ENSURE( PaAlsaStream_WaitForFrames( stream, &framesAvail, &xrun ) );
   4419         framesGot = PA_MIN( framesAvail, frames );
   4420 
   4421         PA_ENSURE( PaAlsaStream_SetUpBuffers( stream, &framesGot, &xrun ) );
   4422         if( framesGot > 0 )
   4423         {
   4424             framesGot = PaUtil_CopyInput( &stream->bufferProcessor, &userBuffer, framesGot );
   4425             PA_ENSURE( PaAlsaStream_EndProcessing( stream, framesGot, &xrun ) );
   4426             frames -= framesGot;
   4427         }
   4428     }
   4429 
   4430 end:
   4431     stream->playback.pcm = save;
   4432     return result;
   4433 error:
   4434     goto end;
   4435 }
   4436 
   4437 static PaError WriteStream( PaStream* s, const void *buffer, unsigned long frames )
   4438 {
   4439     PaError result = paNoError;
   4440     signed long err;
   4441     PaAlsaStream *stream = (PaAlsaStream*)s;
   4442     snd_pcm_uframes_t framesGot, framesAvail;
   4443     const void *userBuffer;
   4444     snd_pcm_t *save = stream->capture.pcm;
   4445 
   4446     assert( stream );
   4447 
   4448     PA_UNLESS( stream->playback.pcm, paCanNotWriteToAnInputOnlyStream );
   4449 
   4450     /* Disregard capture */
   4451     stream->capture.pcm = NULL;
   4452 
   4453     if( stream->underrun > 0. )
   4454     {
   4455         result = paOutputUnderflowed;
   4456         stream->underrun = 0.0;
   4457     }
   4458 
   4459     if( stream->playback.userInterleaved )
   4460         userBuffer = buffer;
   4461     else /* Copy channels into local array */
   4462     {
   4463         userBuffer = stream->playback.userBuffers;
   4464         memcpy( (void *)userBuffer, buffer, sizeof (void *) * stream->playback.numUserChannels );
   4465     }
   4466 
   4467     while( frames > 0 )
   4468     {
   4469         int xrun = 0;
   4470         snd_pcm_uframes_t hwAvail;
   4471 
   4472         PA_ENSURE( PaAlsaStream_WaitForFrames( stream, &framesAvail, &xrun ) );
   4473         framesGot = PA_MIN( framesAvail, frames );
   4474 
   4475         PA_ENSURE( PaAlsaStream_SetUpBuffers( stream, &framesGot, &xrun ) );
   4476         if( framesGot > 0 )
   4477         {
   4478             framesGot = PaUtil_CopyOutput( &stream->bufferProcessor, &userBuffer, framesGot );
   4479             PA_ENSURE( PaAlsaStream_EndProcessing( stream, framesGot, &xrun ) );
   4480             frames -= framesGot;
   4481         }
   4482 
   4483         /* Start stream after one period of samples worth */
   4484 
   4485         /* Frames residing in buffer */
   4486         PA_ENSURE( err = GetStreamWriteAvailable( stream ) );
   4487         framesAvail = err;
   4488         hwAvail = stream->playback.alsaBufferSize - framesAvail;
   4489 
   4490         if( alsa_snd_pcm_state( stream->playback.pcm ) == SND_PCM_STATE_PREPARED &&
   4491                 hwAvail >= stream->playback.framesPerPeriod )
   4492         {
   4493             ENSURE_( alsa_snd_pcm_start( stream->playback.pcm ), paUnanticipatedHostError );
   4494         }
   4495     }
   4496 
   4497 end:
   4498     stream->capture.pcm = save;
   4499     return result;
   4500 error:
   4501     goto end;
   4502 }
   4503 
   4504 /* Return frames available for reading. In the event of an overflow, the capture pcm will be restarted */
   4505 static signed long GetStreamReadAvailable( PaStream* s )
   4506 {
   4507     PaError result = paNoError;
   4508     PaAlsaStream *stream = (PaAlsaStream*)s;
   4509     unsigned long avail;
   4510     int xrun;
   4511 
   4512     PA_ENSURE( PaAlsaStreamComponent_GetAvailableFrames( &stream->capture, &avail, &xrun ) );
   4513     if( xrun )
   4514     {
   4515         PA_ENSURE( PaAlsaStream_HandleXrun( stream ) );
   4516         PA_ENSURE( PaAlsaStreamComponent_GetAvailableFrames( &stream->capture, &avail, &xrun ) );
   4517         if( xrun )
   4518             PA_ENSURE( paInputOverflowed );
   4519     }
   4520 
   4521     return (signed long)avail;
   4522 
   4523 error:
   4524     return result;
   4525 }
   4526 
   4527 static signed long GetStreamWriteAvailable( PaStream* s )
   4528 {
   4529     PaError result = paNoError;
   4530     PaAlsaStream *stream = (PaAlsaStream*)s;
   4531     unsigned long avail;
   4532     int xrun;
   4533 
   4534     PA_ENSURE( PaAlsaStreamComponent_GetAvailableFrames( &stream->playback, &avail, &xrun ) );
   4535     if( xrun )
   4536     {
   4537         snd_pcm_sframes_t savail;
   4538 
   4539         PA_ENSURE( PaAlsaStream_HandleXrun( stream ) );
   4540         savail = alsa_snd_pcm_avail_update( stream->playback.pcm );
   4541 
   4542         /* savail should not contain -EPIPE now, since PaAlsaStream_HandleXrun will only prepare the pcm */
   4543         ENSURE_( savail, paUnanticipatedHostError );
   4544 
   4545         avail = (unsigned long) savail;
   4546     }
   4547 
   4548     return (signed long)avail;
   4549 
   4550 error:
   4551     return result;
   4552 }
   4553 
   4554 /* Extensions */
   4555 
   4556 void PaAlsa_InitializeStreamInfo( PaAlsaStreamInfo *info )
   4557 {
   4558     info->size = sizeof (PaAlsaStreamInfo);
   4559     info->hostApiType = paALSA;
   4560     info->version = 1;
   4561     info->deviceString = NULL;
   4562 }
   4563 
   4564 void PaAlsa_EnableRealtimeScheduling( PaStream *s, int enable )
   4565 {
   4566     PaAlsaStream *stream = (PaAlsaStream *) s;
   4567     stream->rtSched = enable;
   4568 }
   4569 
   4570 #if 0
   4571 void PaAlsa_EnableWatchdog( PaStream *s, int enable )
   4572 {
   4573     PaAlsaStream *stream = (PaAlsaStream *) s;
   4574     stream->thread.useWatchdog = enable;
   4575 }
   4576 #endif
   4577 
   4578 static PaError GetAlsaStreamPointer( PaStream* s, PaAlsaStream** stream )
   4579 {
   4580     PaError result = paNoError;
   4581     PaUtilHostApiRepresentation* hostApi;
   4582     PaAlsaHostApiRepresentation* alsaHostApi;
   4583 
   4584     PA_ENSURE( PaUtil_ValidateStreamPointer( s ) );
   4585     PA_ENSURE( PaUtil_GetHostApiRepresentation( &hostApi, paALSA ) );
   4586     alsaHostApi = (PaAlsaHostApiRepresentation*)hostApi;
   4587 
   4588     PA_UNLESS( PA_STREAM_REP( s )->streamInterface == &alsaHostApi->callbackStreamInterface
   4589             || PA_STREAM_REP( s )->streamInterface == &alsaHostApi->blockingStreamInterface,
   4590         paIncompatibleStreamHostApi );
   4591 
   4592     *stream = (PaAlsaStream*)s;
   4593 error:
   4594     return paNoError;
   4595 }
   4596 
   4597 PaError PaAlsa_GetStreamInputCard( PaStream* s, int* card )
   4598 {
   4599     PaAlsaStream *stream;
   4600     PaError result = paNoError;
   4601     snd_pcm_info_t* pcmInfo;
   4602 
   4603     PA_ENSURE( GetAlsaStreamPointer( s, &stream ) );
   4604 
   4605     /* XXX: More descriptive error? */
   4606     PA_UNLESS( stream->capture.pcm, paDeviceUnavailable );
   4607 
   4608     alsa_snd_pcm_info_alloca( &pcmInfo );
   4609     PA_ENSURE( alsa_snd_pcm_info( stream->capture.pcm, pcmInfo ) );
   4610     *card = alsa_snd_pcm_info_get_card( pcmInfo );
   4611 
   4612 error:
   4613     return result;
   4614 }
   4615 
   4616 PaError PaAlsa_GetStreamOutputCard( PaStream* s, int* card )
   4617 {
   4618     PaAlsaStream *stream;
   4619     PaError result = paNoError;
   4620     snd_pcm_info_t* pcmInfo;
   4621 
   4622     PA_ENSURE( GetAlsaStreamPointer( s, &stream ) );
   4623 
   4624     /* XXX: More descriptive error? */
   4625     PA_UNLESS( stream->playback.pcm, paDeviceUnavailable );
   4626 
   4627     alsa_snd_pcm_info_alloca( &pcmInfo );
   4628     PA_ENSURE( alsa_snd_pcm_info( stream->playback.pcm, pcmInfo ) );
   4629     *card = alsa_snd_pcm_info_get_card( pcmInfo );
   4630 
   4631 error:
   4632     return result;
   4633 }
   4634 
   4635 PaError PaAlsa_SetRetriesBusy( int retries )
   4636 {
   4637     busyRetries_ = retries;
   4638     return paNoError;
   4639 }