diff --git a/include/pa_linux_alsa.h b/include/pa_linux_alsa.h index 9e17439..7ac6736 100644 --- a/include/pa_linux_alsa.h +++ b/include/pa_linux_alsa.h @@ -93,6 +93,13 @@ PaError PaAlsa_SetNumPeriods( int numPeriods ); */ PaError PaAlsa_SetRetriesBusy( int retries ); +/** Set the path and name of ALSA library file if PortAudio is configured to load it dynamically (see + * PA_ALSA_DYNAMIC). This setting will overwrite the default name set by PA_ALSA_PATHNAME define. + * @param pathName Full path with filename. Only filename can be used, but dlopen() will lookup default + * searchable directories (/usr/lib;/usr/local/lib) then. + */ +void PaAlsa_SetLibraryPathName( const char *pathName ); + #ifdef __cplusplus } #endif diff --git a/src/hostapi/alsa/pa_linux_alsa.c b/src/hostapi/alsa/pa_linux_alsa.c index 6aeac0e..8482bc8 100644 --- a/src/hostapi/alsa/pa_linux_alsa.c +++ b/src/hostapi/alsa/pa_linux_alsa.c @@ -62,6 +62,9 @@ #include #include #include /* For sig_atomic_t */ +#ifdef PA_ALSA_DYNAMIC + #include /* For dlXXX functions */ +#endif #include "portaudio.h" #include "pa_util.h" @@ -76,29 +79,498 @@ #include "pa_linux_alsa.h" +/* Defines Alsa function types and pointers to these functions. */ +#define _PA_DEFINE_FUNC(x) typedef typeof(x) x##_ft; static x##_ft *alsa_##x = 0 + +/* Alloca helper. */ +#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) + +_PA_DEFINE_FUNC(snd_pcm_open); +_PA_DEFINE_FUNC(snd_pcm_close); +_PA_DEFINE_FUNC(snd_pcm_nonblock); +_PA_DEFINE_FUNC(snd_pcm_frames_to_bytes); +_PA_DEFINE_FUNC(snd_pcm_prepare); +_PA_DEFINE_FUNC(snd_pcm_start); +_PA_DEFINE_FUNC(snd_pcm_resume); +_PA_DEFINE_FUNC(snd_pcm_wait); +_PA_DEFINE_FUNC(snd_pcm_state); +_PA_DEFINE_FUNC(snd_pcm_avail_update); +_PA_DEFINE_FUNC(snd_pcm_areas_silence); +_PA_DEFINE_FUNC(snd_pcm_mmap_begin); +_PA_DEFINE_FUNC(snd_pcm_mmap_commit); +_PA_DEFINE_FUNC(snd_pcm_readi); +_PA_DEFINE_FUNC(snd_pcm_readn); +_PA_DEFINE_FUNC(snd_pcm_writei); +_PA_DEFINE_FUNC(snd_pcm_writen); +_PA_DEFINE_FUNC(snd_pcm_drain); +_PA_DEFINE_FUNC(snd_pcm_recover); +_PA_DEFINE_FUNC(snd_pcm_drop); +_PA_DEFINE_FUNC(snd_pcm_area_copy); +_PA_DEFINE_FUNC(snd_pcm_poll_descriptors); +_PA_DEFINE_FUNC(snd_pcm_poll_descriptors_count); +_PA_DEFINE_FUNC(snd_pcm_poll_descriptors_revents); +_PA_DEFINE_FUNC(snd_pcm_format_size); +_PA_DEFINE_FUNC(snd_pcm_link); +_PA_DEFINE_FUNC(snd_pcm_delay); + +_PA_DEFINE_FUNC(snd_pcm_hw_params_sizeof); +_PA_DEFINE_FUNC(snd_pcm_hw_params_malloc); +_PA_DEFINE_FUNC(snd_pcm_hw_params_free); +_PA_DEFINE_FUNC(snd_pcm_hw_params_any); +_PA_DEFINE_FUNC(snd_pcm_hw_params_set_access); +_PA_DEFINE_FUNC(snd_pcm_hw_params_set_format); +_PA_DEFINE_FUNC(snd_pcm_hw_params_set_channels); +//_PA_DEFINE_FUNC(snd_pcm_hw_params_set_periods_near); +_PA_DEFINE_FUNC(snd_pcm_hw_params_set_rate_near); //!!! +_PA_DEFINE_FUNC(snd_pcm_hw_params_set_rate); +_PA_DEFINE_FUNC(snd_pcm_hw_params_set_rate_resample); +//_PA_DEFINE_FUNC(snd_pcm_hw_params_set_buffer_time_near); +_PA_DEFINE_FUNC(snd_pcm_hw_params_set_buffer_size); +_PA_DEFINE_FUNC(snd_pcm_hw_params_set_buffer_size_near); //!!! +_PA_DEFINE_FUNC(snd_pcm_hw_params_set_buffer_size_min); +//_PA_DEFINE_FUNC(snd_pcm_hw_params_set_period_time_near); +_PA_DEFINE_FUNC(snd_pcm_hw_params_set_period_size_near); +_PA_DEFINE_FUNC(snd_pcm_hw_params_set_periods_integer); +_PA_DEFINE_FUNC(snd_pcm_hw_params_set_periods_min); + +_PA_DEFINE_FUNC(snd_pcm_hw_params_get_buffer_size); +//_PA_DEFINE_FUNC(snd_pcm_hw_params_get_period_size); +//_PA_DEFINE_FUNC(snd_pcm_hw_params_get_access); +//_PA_DEFINE_FUNC(snd_pcm_hw_params_get_periods); +//_PA_DEFINE_FUNC(snd_pcm_hw_params_get_rate); +_PA_DEFINE_FUNC(snd_pcm_hw_params_get_channels_min); +_PA_DEFINE_FUNC(snd_pcm_hw_params_get_channels_max); + +_PA_DEFINE_FUNC(snd_pcm_hw_params_test_period_size); +_PA_DEFINE_FUNC(snd_pcm_hw_params_test_format); +_PA_DEFINE_FUNC(snd_pcm_hw_params_test_access); +_PA_DEFINE_FUNC(snd_pcm_hw_params_dump); +_PA_DEFINE_FUNC(snd_pcm_hw_params); + +_PA_DEFINE_FUNC(snd_pcm_hw_params_get_periods_min); +_PA_DEFINE_FUNC(snd_pcm_hw_params_get_periods_max); +_PA_DEFINE_FUNC(snd_pcm_hw_params_set_period_size); +_PA_DEFINE_FUNC(snd_pcm_hw_params_get_period_size_min); +_PA_DEFINE_FUNC(snd_pcm_hw_params_get_period_size_max); +_PA_DEFINE_FUNC(snd_pcm_hw_params_get_buffer_size_max); +_PA_DEFINE_FUNC(snd_pcm_hw_params_get_rate_min); +_PA_DEFINE_FUNC(snd_pcm_hw_params_get_rate_max); +_PA_DEFINE_FUNC(snd_pcm_hw_params_get_rate_numden); +#define alsa_snd_pcm_hw_params_alloca(ptr) __alsa_snd_alloca(ptr, snd_pcm_hw_params) + +_PA_DEFINE_FUNC(snd_pcm_sw_params_sizeof); +_PA_DEFINE_FUNC(snd_pcm_sw_params_malloc); +_PA_DEFINE_FUNC(snd_pcm_sw_params_current); +_PA_DEFINE_FUNC(snd_pcm_sw_params_set_avail_min); +_PA_DEFINE_FUNC(snd_pcm_sw_params); +_PA_DEFINE_FUNC(snd_pcm_sw_params_free); +_PA_DEFINE_FUNC(snd_pcm_sw_params_set_start_threshold); +_PA_DEFINE_FUNC(snd_pcm_sw_params_set_stop_threshold); +_PA_DEFINE_FUNC(snd_pcm_sw_params_get_boundary); +_PA_DEFINE_FUNC(snd_pcm_sw_params_set_silence_threshold); +_PA_DEFINE_FUNC(snd_pcm_sw_params_set_silence_size); +_PA_DEFINE_FUNC(snd_pcm_sw_params_set_xfer_align); +_PA_DEFINE_FUNC(snd_pcm_sw_params_set_tstamp_mode); +#define alsa_snd_pcm_sw_params_alloca(ptr) __alsa_snd_alloca(ptr, snd_pcm_sw_params) + +_PA_DEFINE_FUNC(snd_pcm_info); +_PA_DEFINE_FUNC(snd_pcm_info_sizeof); +_PA_DEFINE_FUNC(snd_pcm_info_malloc); +_PA_DEFINE_FUNC(snd_pcm_info_free); +_PA_DEFINE_FUNC(snd_pcm_info_set_device); +_PA_DEFINE_FUNC(snd_pcm_info_set_subdevice); +_PA_DEFINE_FUNC(snd_pcm_info_set_stream); +_PA_DEFINE_FUNC(snd_pcm_info_get_name); +_PA_DEFINE_FUNC(snd_pcm_info_get_card); +#define alsa_snd_pcm_info_alloca(ptr) __alsa_snd_alloca(ptr, snd_pcm_info) + +_PA_DEFINE_FUNC(snd_ctl_pcm_next_device); +_PA_DEFINE_FUNC(snd_ctl_pcm_info); +_PA_DEFINE_FUNC(snd_ctl_open); +_PA_DEFINE_FUNC(snd_ctl_close); +_PA_DEFINE_FUNC(snd_ctl_card_info_malloc); +_PA_DEFINE_FUNC(snd_ctl_card_info_free); +_PA_DEFINE_FUNC(snd_ctl_card_info); +_PA_DEFINE_FUNC(snd_ctl_card_info_sizeof); +_PA_DEFINE_FUNC(snd_ctl_card_info_get_name); +#define alsa_snd_ctl_card_info_alloca(ptr) __alsa_snd_alloca(ptr, snd_ctl_card_info) + +_PA_DEFINE_FUNC(snd_config); +_PA_DEFINE_FUNC(snd_config_update); +_PA_DEFINE_FUNC(snd_config_search); +_PA_DEFINE_FUNC(snd_config_iterator_entry); +_PA_DEFINE_FUNC(snd_config_iterator_first); +_PA_DEFINE_FUNC(snd_config_iterator_end); +_PA_DEFINE_FUNC(snd_config_iterator_next); +_PA_DEFINE_FUNC(snd_config_get_string); +_PA_DEFINE_FUNC(snd_config_get_id); +_PA_DEFINE_FUNC(snd_config_update_free_global); + +_PA_DEFINE_FUNC(snd_pcm_status); +_PA_DEFINE_FUNC(snd_pcm_status_sizeof); +_PA_DEFINE_FUNC(snd_pcm_status_get_tstamp); +_PA_DEFINE_FUNC(snd_pcm_status_get_state); +_PA_DEFINE_FUNC(snd_pcm_status_get_trigger_tstamp); +_PA_DEFINE_FUNC(snd_pcm_status_get_delay); +#define alsa_snd_pcm_status_alloca(ptr) __alsa_snd_alloca(ptr, snd_pcm_status) + +_PA_DEFINE_FUNC(snd_card_next); +_PA_DEFINE_FUNC(snd_strerror); +_PA_DEFINE_FUNC(snd_output_stdio_attach); + +#define alsa_snd_config_for_each(pos, next, node)\ + for (pos = alsa_snd_config_iterator_first(node),\ + next = alsa_snd_config_iterator_next(pos);\ + pos != alsa_snd_config_iterator_end(node); pos = next, next = alsa_snd_config_iterator_next(pos)) + +#undef _PA_DEFINE_FUNC + +/* Redefine 'PA_ALSA_PATHNAME' to a different Alsa library name if desired. */ +#ifndef PA_ALSA_PATHNAME + #define PA_ALSA_PATHNAME "libasound.so" +#endif +static const char *g_AlsaLibName = PA_ALSA_PATHNAME; + +/* Handle to dynamically loaded library. */ +static void *g_AlsaLib = NULL; + +#ifdef PA_ALSA_DYNAMIC + +#define _PA_LOCAL_IMPL(x) __pa_local_##x + +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) +{ + int ret; + + if ((ret = alsa_snd_pcm_hw_params_set_rate(pcm, params, (*val), (*dir))) < 0) + return ret; + + return 0; +} + +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) +{ + int ret; + + if ((ret = alsa_snd_pcm_hw_params_set_buffer_size(pcm, params, (*val))) < 0) + return ret; + + return 0; +} + +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) +{ + int ret; + + if ((ret = alsa_snd_pcm_hw_params_set_period_size(pcm, params, (*val), (*dir))) < 0) + return ret; + + return 0; +} + +int _PA_LOCAL_IMPL(snd_pcm_hw_params_get_channels_min) (const snd_pcm_hw_params_t *params, unsigned int *val) +{ + (*val) = 1; + return 0; +} + +int _PA_LOCAL_IMPL(snd_pcm_hw_params_get_channels_max) (const snd_pcm_hw_params_t *params, unsigned int *val) +{ + (*val) = 2; + return 0; +} + +int _PA_LOCAL_IMPL(snd_pcm_hw_params_get_periods_min) (const snd_pcm_hw_params_t *params, unsigned int *val, int *dir) +{ + (*val) = 2; + return 0; +} + +int _PA_LOCAL_IMPL(snd_pcm_hw_params_get_periods_max) (const snd_pcm_hw_params_t *params, unsigned int *val, int *dir) +{ + (*val) = 8; + return 0; +} + +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) +{ + (*frames) = 64; + return 0; +} + +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) +{ + (*frames) = 512; + return 0; +} + +int _PA_LOCAL_IMPL(snd_pcm_hw_params_get_buffer_size_max) (const snd_pcm_hw_params_t *params, snd_pcm_uframes_t *val) +{ + int ret; + int dir = 0; + snd_pcm_uframes_t pmax = 0; + unsigned int pcnt = 0; + + if ((ret = _PA_LOCAL_IMPL(snd_pcm_hw_params_get_period_size_max)(params, &pmax, &dir)) < 0) + return ret; + if ((ret = _PA_LOCAL_IMPL(snd_pcm_hw_params_get_periods_max)(params, &pcnt, &dir)) < 0) + return ret; + + (*val) = pmax * pcnt; + return 0; +} + +int _PA_LOCAL_IMPL(snd_pcm_hw_params_get_rate_min) (const snd_pcm_hw_params_t *params, unsigned int *val, int *dir) +{ + (*val) = 44100; + return 0; +} + +int _PA_LOCAL_IMPL(snd_pcm_hw_params_get_rate_max) (const snd_pcm_hw_params_t *params, unsigned int *val, int *dir) +{ + (*val) = 44100; + return 0; +} + +#endif // PA_ALSA_DYNAMIC + +/* Trying to load Alsa library dynamically if 'PA_ALSA_DYNAMIC' is defined, othervise + will link during compilation. +*/ +static int PaAlsa_LoadLibrary() +{ +#ifdef PA_ALSA_DYNAMIC + + PA_DEBUG(( "%s: loading ALSA library file - %s\n", __FUNCTION__, g_AlsaLibName )); + + dlerror(); + g_AlsaLib = dlopen(g_AlsaLibName, (RTLD_NOW|RTLD_GLOBAL)); + if (g_AlsaLib == NULL) + { + PA_DEBUG(( "%s: failed dlopen() ALSA library file - %s, error: %s\n", __FUNCTION__, g_AlsaLibName, dlerror() )); + return 0; + } + + PA_DEBUG(( "%s: loading ALSA API\n", __FUNCTION__ )); + + #define _PA_LOAD_FUNC(x) do { \ + alsa_##x = dlsym(g_AlsaLib, #x); \ + if (alsa_##x == NULL) { \ + PA_DEBUG(( "%s: symbol [%s] not found in - %s, error: %s\n", __FUNCTION__, #x, g_AlsaLibName, dlerror() )); }\ + } while(0) + +#else + + #define _PA_LOAD_FUNC(x) alsa_##x = &x + +#endif + +_PA_LOAD_FUNC(snd_pcm_open); +_PA_LOAD_FUNC(snd_pcm_close); +_PA_LOAD_FUNC(snd_pcm_nonblock); +_PA_LOAD_FUNC(snd_pcm_frames_to_bytes); +_PA_LOAD_FUNC(snd_pcm_prepare); +_PA_LOAD_FUNC(snd_pcm_start); +_PA_LOAD_FUNC(snd_pcm_resume); +_PA_LOAD_FUNC(snd_pcm_wait); +_PA_LOAD_FUNC(snd_pcm_state); +_PA_LOAD_FUNC(snd_pcm_avail_update); +_PA_LOAD_FUNC(snd_pcm_areas_silence); +_PA_LOAD_FUNC(snd_pcm_mmap_begin); +_PA_LOAD_FUNC(snd_pcm_mmap_commit); +_PA_LOAD_FUNC(snd_pcm_readi); +_PA_LOAD_FUNC(snd_pcm_readn); +_PA_LOAD_FUNC(snd_pcm_writei); +_PA_LOAD_FUNC(snd_pcm_writen); +_PA_LOAD_FUNC(snd_pcm_drain); +_PA_LOAD_FUNC(snd_pcm_recover); +_PA_LOAD_FUNC(snd_pcm_drop); +_PA_LOAD_FUNC(snd_pcm_area_copy); +_PA_LOAD_FUNC(snd_pcm_poll_descriptors); +_PA_LOAD_FUNC(snd_pcm_poll_descriptors_count); +_PA_LOAD_FUNC(snd_pcm_poll_descriptors_revents); +_PA_LOAD_FUNC(snd_pcm_format_size); +_PA_LOAD_FUNC(snd_pcm_link); +_PA_LOAD_FUNC(snd_pcm_delay); + +_PA_LOAD_FUNC(snd_pcm_hw_params_sizeof); +_PA_LOAD_FUNC(snd_pcm_hw_params_malloc); +_PA_LOAD_FUNC(snd_pcm_hw_params_free); +_PA_LOAD_FUNC(snd_pcm_hw_params_any); +_PA_LOAD_FUNC(snd_pcm_hw_params_set_access); +_PA_LOAD_FUNC(snd_pcm_hw_params_set_format); +_PA_LOAD_FUNC(snd_pcm_hw_params_set_channels); +//_PA_LOAD_FUNC(snd_pcm_hw_params_set_periods_near); +_PA_LOAD_FUNC(snd_pcm_hw_params_set_rate_near); +_PA_LOAD_FUNC(snd_pcm_hw_params_set_rate); +_PA_LOAD_FUNC(snd_pcm_hw_params_set_rate_resample); +//_PA_LOAD_FUNC(snd_pcm_hw_params_set_buffer_time_near); +_PA_LOAD_FUNC(snd_pcm_hw_params_set_buffer_size); +_PA_LOAD_FUNC(snd_pcm_hw_params_set_buffer_size_near); +_PA_LOAD_FUNC(snd_pcm_hw_params_set_buffer_size_min); +//_PA_LOAD_FUNC(snd_pcm_hw_params_set_period_time_near); +_PA_LOAD_FUNC(snd_pcm_hw_params_set_period_size_near); +_PA_LOAD_FUNC(snd_pcm_hw_params_set_periods_integer); +_PA_LOAD_FUNC(snd_pcm_hw_params_set_periods_min); + +_PA_LOAD_FUNC(snd_pcm_hw_params_get_buffer_size); +//_PA_LOAD_FUNC(snd_pcm_hw_params_get_period_size); +//_PA_LOAD_FUNC(snd_pcm_hw_params_get_access); +//_PA_LOAD_FUNC(snd_pcm_hw_params_get_periods); +//_PA_LOAD_FUNC(snd_pcm_hw_params_get_rate); +_PA_LOAD_FUNC(snd_pcm_hw_params_get_channels_min); +_PA_LOAD_FUNC(snd_pcm_hw_params_get_channels_max); + +_PA_LOAD_FUNC(snd_pcm_hw_params_test_period_size); +_PA_LOAD_FUNC(snd_pcm_hw_params_test_format); +_PA_LOAD_FUNC(snd_pcm_hw_params_test_access); +_PA_LOAD_FUNC(snd_pcm_hw_params_dump); +_PA_LOAD_FUNC(snd_pcm_hw_params); + +_PA_LOAD_FUNC(snd_pcm_hw_params_get_periods_min); +_PA_LOAD_FUNC(snd_pcm_hw_params_get_periods_max); +_PA_LOAD_FUNC(snd_pcm_hw_params_set_period_size); +_PA_LOAD_FUNC(snd_pcm_hw_params_get_period_size_min); +_PA_LOAD_FUNC(snd_pcm_hw_params_get_period_size_max); +_PA_LOAD_FUNC(snd_pcm_hw_params_get_buffer_size_max); +_PA_LOAD_FUNC(snd_pcm_hw_params_get_rate_min); +_PA_LOAD_FUNC(snd_pcm_hw_params_get_rate_max); +_PA_LOAD_FUNC(snd_pcm_hw_params_get_rate_numden); + +_PA_LOAD_FUNC(snd_pcm_sw_params_sizeof); +_PA_LOAD_FUNC(snd_pcm_sw_params_malloc); +_PA_LOAD_FUNC(snd_pcm_sw_params_current); +_PA_LOAD_FUNC(snd_pcm_sw_params_set_avail_min); +_PA_LOAD_FUNC(snd_pcm_sw_params); +_PA_LOAD_FUNC(snd_pcm_sw_params_free); +_PA_LOAD_FUNC(snd_pcm_sw_params_set_start_threshold); +_PA_LOAD_FUNC(snd_pcm_sw_params_set_stop_threshold); +_PA_LOAD_FUNC(snd_pcm_sw_params_get_boundary); +_PA_LOAD_FUNC(snd_pcm_sw_params_set_silence_threshold); +_PA_LOAD_FUNC(snd_pcm_sw_params_set_silence_size); +_PA_LOAD_FUNC(snd_pcm_sw_params_set_xfer_align); +_PA_LOAD_FUNC(snd_pcm_sw_params_set_tstamp_mode); + +_PA_LOAD_FUNC(snd_pcm_info); +_PA_LOAD_FUNC(snd_pcm_info_sizeof); +_PA_LOAD_FUNC(snd_pcm_info_malloc); +_PA_LOAD_FUNC(snd_pcm_info_free); +_PA_LOAD_FUNC(snd_pcm_info_set_device); +_PA_LOAD_FUNC(snd_pcm_info_set_subdevice); +_PA_LOAD_FUNC(snd_pcm_info_set_stream); +_PA_LOAD_FUNC(snd_pcm_info_get_name); +_PA_LOAD_FUNC(snd_pcm_info_get_card); + +_PA_LOAD_FUNC(snd_ctl_pcm_next_device); +_PA_LOAD_FUNC(snd_ctl_pcm_info); +_PA_LOAD_FUNC(snd_ctl_open); +_PA_LOAD_FUNC(snd_ctl_close); +_PA_LOAD_FUNC(snd_ctl_card_info_malloc); +_PA_LOAD_FUNC(snd_ctl_card_info_free); +_PA_LOAD_FUNC(snd_ctl_card_info); +_PA_LOAD_FUNC(snd_ctl_card_info_sizeof); +_PA_LOAD_FUNC(snd_ctl_card_info_get_name); + +_PA_LOAD_FUNC(snd_config); +_PA_LOAD_FUNC(snd_config_update); +_PA_LOAD_FUNC(snd_config_search); +_PA_LOAD_FUNC(snd_config_iterator_entry); +_PA_LOAD_FUNC(snd_config_iterator_first); +_PA_LOAD_FUNC(snd_config_iterator_end); +_PA_LOAD_FUNC(snd_config_iterator_next); +_PA_LOAD_FUNC(snd_config_get_string); +_PA_LOAD_FUNC(snd_config_get_id); +_PA_LOAD_FUNC(snd_config_update_free_global); + +_PA_LOAD_FUNC(snd_pcm_status); +_PA_LOAD_FUNC(snd_pcm_status_sizeof); +_PA_LOAD_FUNC(snd_pcm_status_get_tstamp); +_PA_LOAD_FUNC(snd_pcm_status_get_state); +_PA_LOAD_FUNC(snd_pcm_status_get_trigger_tstamp); +_PA_LOAD_FUNC(snd_pcm_status_get_delay); + +_PA_LOAD_FUNC(snd_card_next); +_PA_LOAD_FUNC(snd_strerror); +_PA_LOAD_FUNC(snd_output_stdio_attach); +#undef _PA_LOAD_FUNC + +#ifdef PA_ALSA_DYNAMIC + PA_DEBUG(( "%s: loaded ALSA API - ok\n", __FUNCTION__ )); + +#define _PA_VALIDATE_LOAD_REPLACEMENT(x)\ + do {\ + if (alsa_##x == NULL)\ + {\ + alsa_##x = &_PA_LOCAL_IMPL(x);\ + PA_DEBUG(( "%s: replacing [%s] with local implementation\n", __FUNCTION__, #x ));\ + }\ + } while (0) + + _PA_VALIDATE_LOAD_REPLACEMENT(snd_pcm_hw_params_set_rate_near); + _PA_VALIDATE_LOAD_REPLACEMENT(snd_pcm_hw_params_set_buffer_size_near); + _PA_VALIDATE_LOAD_REPLACEMENT(snd_pcm_hw_params_set_period_size_near); + _PA_VALIDATE_LOAD_REPLACEMENT(snd_pcm_hw_params_get_channels_min); + _PA_VALIDATE_LOAD_REPLACEMENT(snd_pcm_hw_params_get_channels_max); + _PA_VALIDATE_LOAD_REPLACEMENT(snd_pcm_hw_params_get_periods_min); + _PA_VALIDATE_LOAD_REPLACEMENT(snd_pcm_hw_params_get_periods_max); + _PA_VALIDATE_LOAD_REPLACEMENT(snd_pcm_hw_params_get_period_size_min); + _PA_VALIDATE_LOAD_REPLACEMENT(snd_pcm_hw_params_get_period_size_max); + _PA_VALIDATE_LOAD_REPLACEMENT(snd_pcm_hw_params_get_buffer_size_max); + _PA_VALIDATE_LOAD_REPLACEMENT(snd_pcm_hw_params_get_rate_min); + _PA_VALIDATE_LOAD_REPLACEMENT(snd_pcm_hw_params_get_rate_max); + +#undef _PA_LOCAL_IMPL +#undef _PA_VALIDATE_LOAD_REPLACEMENT + +#endif // PA_ALSA_DYNAMIC + + return 1; +} + +void PaAlsa_SetLibraryPathName( const char *pathName ) +{ +#ifdef PA_ALSA_DYNAMIC + g_AlsaLibName = pathName; +#else + (void)pathName; +#endif +} + +/* Close handle to Alsa library. */ +static void PaAlsa_CloseLibrary() +{ +#ifdef PA_ALSA_DYNAMIC + dlclose(g_AlsaLib); + g_AlsaLib = NULL; +#endif +} + /* Check return value of ALSA function, and map it to PaError */ #define ENSURE_(expr, code) \ do { \ - if( UNLIKELY( (aErr_ = (expr)) < 0 ) ) \ + int __pa_unsure_error_id;\ + if( UNLIKELY( (__pa_unsure_error_id = (expr)) < 0 ) ) \ { \ /* PaUtil_SetLastHostErrorInfo should only be used in the main thread */ \ if( (code) == paUnanticipatedHostError && pthread_equal( pthread_self(), paUnixMainThread) ) \ { \ - PaUtil_SetLastHostErrorInfo( paALSA, aErr_, snd_strerror( aErr_ ) ); \ + PaUtil_SetLastHostErrorInfo( paALSA, __pa_unsure_error_id, alsa_snd_strerror( __pa_unsure_error_id ) ); \ } \ PaUtil_DebugPrint( "Expression '" #expr "' failed in '" __FILE__ "', line: " STRINGIZE( __LINE__ ) "\n" ); \ if( (code) == paUnanticipatedHostError ) \ - PA_DEBUG(( "Host error description: %s\n", snd_strerror( aErr_ ) )); \ + PA_DEBUG(( "Host error description: %s\n", alsa_snd_strerror( __pa_unsure_error_id ) )); \ result = (code); \ goto error; \ } \ - } while( 0 ); + } while (0) #define ASSERT_CALL_(expr, success) \ - aErr_ = (expr); \ - assert( success == aErr_ ); + do {\ + int __pa_assert_error_id;\ + __pa_assert_error_id = (expr);\ + assert( success == __pa_assert_error_id );\ + } while (0) -static int aErr_; /* Used with ENSURE_ */ static int numPeriods_ = 4; static int busyRetries_ = 100; @@ -239,7 +711,7 @@ static const PaAlsaDeviceInfo *GetDeviceInfo( const PaUtilHostApiRepresentation return (const PaAlsaDeviceInfo *)hostApi->deviceInfos[device]; } -/** Uncommented because AlsaErrorHandler is unused for anything good yet. If AlsaErrorHandler is +/** Uncommented because AlsaErrorHandler is unused for anything good yet. If AlsaErrorHandler is to be used, do not forget to register this callback in PaAlsa_Initialize, and unregister in Terminate. */ /*static void AlsaErrorHandler(const char *file, int line, const char *function, int err, const char *fmt, ...) @@ -251,6 +723,10 @@ PaError PaAlsa_Initialize( PaUtilHostApiRepresentation **hostApi, PaHostApiIndex PaError result = paNoError; PaAlsaHostApiRepresentation *alsaHostApi = NULL; + /* Try loading Alsa library. */ + if (!PaAlsa_LoadLibrary()) + return paHostApiNotFound; + PA_UNLESS( alsaHostApi = (PaAlsaHostApiRepresentation*) PaUtil_AllocateMemory( sizeof(PaAlsaHostApiRepresentation) ), paInsufficientMemory ); PA_UNLESS( alsaHostApi->allocations = PaUtil_CreateAllocationGroup(), paInsufficientMemory ); @@ -265,7 +741,7 @@ PaError PaAlsa_Initialize( PaUtilHostApiRepresentation **hostApi, PaHostApiIndex (*hostApi)->OpenStream = OpenStream; (*hostApi)->IsFormatSupported = IsFormatSupported; - /** If AlsaErrorHandler is to be used, do not forget to unregister callback pointer in + /** If AlsaErrorHandler is to be used, do not forget to unregister callback pointer in Terminate function. */ /*ENSURE_( snd_lib_error_set_handler(AlsaErrorHandler), paUnanticipatedHostError );*/ @@ -314,7 +790,7 @@ static void Terminate( struct PaUtilHostApiRepresentation *hostApi ) PaAlsaHostApiRepresentation *alsaHostApi = (PaAlsaHostApiRepresentation*)hostApi; assert( hostApi ); - + /** See AlsaErrorHandler and PaAlsa_Initialize for details. */ /*snd_lib_error_set_handler(NULL);*/ @@ -326,7 +802,10 @@ static void Terminate( struct PaUtilHostApiRepresentation *hostApi ) } PaUtil_FreeMemory( alsaHostApi ); - snd_config_update_free_global(); + alsa_snd_config_update_free_global(); + + /* Close Alsa library. */ + PaAlsa_CloseLibrary(); } /** Determine max channels and default latencies. @@ -349,6 +828,8 @@ static PaError GropeDevice( snd_pcm_t* pcm, int isPlug, StreamDirection mode, in assert( pcm ); + PA_DEBUG(( "%s: collecting info ..\n", __FUNCTION__ )); + if( StreamDirection_In == mode ) { minChannels = &devInfo->minInputChannels; @@ -364,10 +845,10 @@ static PaError GropeDevice( snd_pcm_t* pcm, int isPlug, StreamDirection mode, in defaultHighLatency = &devInfo->baseDeviceInfo.defaultHighOutputLatency; } - ENSURE_( snd_pcm_nonblock( pcm, 0 ), paUnanticipatedHostError ); + ENSURE_( alsa_snd_pcm_nonblock( pcm, 0 ), paUnanticipatedHostError ); - snd_pcm_hw_params_alloca( &hwParams ); - snd_pcm_hw_params_any( pcm, hwParams ); + alsa_snd_pcm_hw_params_alloca( &hwParams ); + alsa_snd_pcm_hw_params_any( pcm, hwParams ); if( defaultSr >= 0 ) { @@ -383,7 +864,7 @@ static PaError GropeDevice( snd_pcm_t* pcm, int isPlug, StreamDirection mode, in if( defaultSr < 0. ) /* Default sample rate not set */ { unsigned int sampleRate = 44100; /* Will contain approximate rate returned by alsa-lib */ - if( snd_pcm_hw_params_set_rate_near( pcm, hwParams, &sampleRate, NULL ) < 0) + if( alsa_snd_pcm_hw_params_set_rate_near( pcm, hwParams, &sampleRate, NULL ) < 0) { result = paUnanticipatedHostError; goto error; @@ -391,8 +872,8 @@ static PaError GropeDevice( snd_pcm_t* pcm, int isPlug, StreamDirection mode, in ENSURE_( GetExactSampleRate( hwParams, &defaultSr ), paUnanticipatedHostError ); } - ENSURE_( snd_pcm_hw_params_get_channels_min( hwParams, &minChans ), paUnanticipatedHostError ); - ENSURE_( snd_pcm_hw_params_get_channels_max( hwParams, &maxChans ), paUnanticipatedHostError ); + ENSURE_( alsa_snd_pcm_hw_params_get_channels_min( hwParams, &minChans ), paUnanticipatedHostError ); + ENSURE_( alsa_snd_pcm_hw_params_get_channels_max( hwParams, &maxChans ), paUnanticipatedHostError ); assert( maxChans <= INT_MAX ); assert( maxChans > 0 ); /* Weird linking issue could cause wrong version of ALSA symbols to be called, resulting in zeroed values */ @@ -423,11 +904,11 @@ static PaError GropeDevice( snd_pcm_t* pcm, int isPlug, StreamDirection mode, in * select the nearest setting that will work at stream * config time. */ - ENSURE_( snd_pcm_hw_params_set_buffer_size_near( pcm, hwParams, &lowLatency ), paUnanticipatedHostError ); + ENSURE_( alsa_snd_pcm_hw_params_set_buffer_size_near( pcm, hwParams, &lowLatency ), paUnanticipatedHostError ); /* Have to reset hwParams, to set new buffer size */ - ENSURE_( snd_pcm_hw_params_any( pcm, hwParams ), paUnanticipatedHostError ); - ENSURE_( snd_pcm_hw_params_set_buffer_size_near( pcm, hwParams, &highLatency ), paUnanticipatedHostError ); + ENSURE_( alsa_snd_pcm_hw_params_any( pcm, hwParams ), paUnanticipatedHostError ); + ENSURE_( alsa_snd_pcm_hw_params_set_buffer_size_near( pcm, hwParams, &highLatency ), paUnanticipatedHostError ); *minChannels = (int)minChans; *maxChannels = (int)maxChans; @@ -436,7 +917,7 @@ static PaError GropeDevice( snd_pcm_t* pcm, int isPlug, StreamDirection mode, in *defaultHighLatency = (double) highLatency / *defaultSampleRate; end: - snd_pcm_close( pcm ); + alsa_snd_pcm_close( pcm ); return result; error: @@ -487,6 +968,23 @@ HwDevInfo predefinedNames[] = { { "surround50", NULL, 0, 1, 0 }, { "surround51", NULL, 0, 1, 0 }, { "surround71", NULL, 0, 1, 0 }, + + { "AndroidPlayback_Earpiece_normal", NULL, 0, 1, 0 }, + { "AndroidPlayback_Speaker_normal", NULL, 0, 1, 0 }, + { "AndroidPlayback_Bluetooth_normal", NULL, 0, 1, 0 }, + { "AndroidPlayback_Headset_normal", NULL, 0, 1, 0 }, + { "AndroidPlayback_Speaker_Headset_normal", NULL, 0, 1, 0 }, + { "AndroidPlayback_Bluetooth-A2DP_normal", NULL, 0, 1, 0 }, + { "AndroidPlayback_ExtraDockSpeaker_normal", NULL, 0, 1, 0 }, + { "AndroidPlayback_TvOut_normal", NULL, 0, 1, 0 }, + + { "AndroidRecord_Microphone", NULL, 0, 0, 1 }, + { "AndroidRecord_Earpiece_normal", NULL, 0, 0, 1 }, + { "AndroidRecord_Speaker_normal", NULL, 0, 0, 1 }, + { "AndroidRecord_Headset_normal", NULL, 0, 0, 1 }, + { "AndroidRecord_Bluetooth_normal", NULL, 0, 0, 1 }, + { "AndroidRecord_Speaker_Headset_normal", NULL, 0, 0, 1 }, + { NULL, NULL, 0, 1, 0 } }; @@ -543,7 +1041,7 @@ static int IgnorePlugin( const char *pluginId ) /** Open PCM device. * - * Wrapper around snd_pcm_open which may repeatedly retry opening a device if it is busy, for + * Wrapper around alsa_snd_pcm_open which may repeatedly retry opening a device if it is busy, for * a certain time. This is because dmix may temporarily hold on to a device after it (dmix) * has been opened and closed. * @param mode: Open mode (e.g., SND_PCM_BLOCKING). @@ -552,11 +1050,11 @@ static int IgnorePlugin( const char *pluginId ) static int OpenPcm( snd_pcm_t **pcmp, const char *name, snd_pcm_stream_t stream, int mode, int waitOnBusy ) { int tries = 0, maxTries = waitOnBusy ? busyRetries_ : 0; - int ret = snd_pcm_open( pcmp, name, stream, mode ); + int ret = alsa_snd_pcm_open( pcmp, name, stream, mode ); for( tries = 0; tries < maxTries && -EBUSY == ret; ++tries ) { Pa_Sleep( 10 ); - ret = snd_pcm_open( pcmp, name, stream, mode ); + ret = alsa_snd_pcm_open( pcmp, name, stream, mode ); if( -EBUSY != ret ) { PA_DEBUG(( "%s: Successfully opened initially busy device after %d tries\n", @@ -565,8 +1063,12 @@ static int OpenPcm( snd_pcm_t **pcmp, const char *name, snd_pcm_stream_t stream, } if( -EBUSY == ret ) { - PA_DEBUG(( "%s: Failed to open busy device '%s'\n", - __FUNCTION__, name )); + PA_DEBUG(( "%s: Failed to open busy device '%s'\n", __FUNCTION__, name )); + } + else + { + if (ret < 0) + PA_DEBUG(( "%s: Opened device '%s' ptr[%p] - result: [%d:%s]\n", __FUNCTION__, name, *pcmp, ret, alsa_snd_strerror(ret) )); } return ret; @@ -577,9 +1079,11 @@ static PaError FillInDevInfo( PaAlsaHostApiRepresentation *alsaApi, HwDevInfo* d { PaError result = 0; PaDeviceInfo *baseDeviceInfo = &devInfo->baseDeviceInfo; - snd_pcm_t *pcm; + snd_pcm_t *pcm = NULL; PaUtilHostApiRepresentation *baseApi = &alsaApi->baseHostApiRep; + PA_DEBUG(( "%s: filling device info for: %s\n", __FUNCTION__, deviceName->name )); + /* Zero fields */ InitializeDeviceInfo( baseDeviceInfo ); @@ -640,6 +1144,10 @@ static PaError FillInDevInfo( PaAlsaHostApiRepresentation *alsaApi, HwDevInfo* d baseApi->deviceInfos[*devIdx] = (PaDeviceInfo *) devInfo; (*devIdx) += 1; } + else + { + PA_DEBUG(( "%s: skipped device: %s, all channels - 0\n", __FUNCTION__, deviceName->name )); + } end: return result; @@ -673,16 +1181,16 @@ static PaError BuildDeviceList( PaAlsaHostApiRepresentation *alsaApi ) /* Gather info about hw devices - * snd_card_next() modifies the integer passed to it to be: + * alsa_snd_card_next() modifies the integer passed to it to be: * the index of the first card if the parameter is -1 * the index of the next card if the parameter is the index of a card * -1 if there are no more cards * * The function itself returns 0 if it succeeded. */ cardIdx = -1; - snd_ctl_card_info_alloca( &cardInfo ); - snd_pcm_info_alloca( &pcmInfo ); - while( snd_card_next( &cardIdx ) == 0 && cardIdx >= 0 ) + alsa_snd_ctl_card_info_alloca( &cardInfo ); + alsa_snd_pcm_info_alloca( &pcmInfo ); + while( alsa_snd_card_next( &cardIdx ) == 0 && cardIdx >= 0 ) { char *cardName; int devIdx = -1; @@ -692,17 +1200,17 @@ static PaError BuildDeviceList( PaAlsaHostApiRepresentation *alsaApi ) snprintf( alsaCardName, sizeof (alsaCardName), "hw:%d", cardIdx ); /* Acquire name of card */ - if( snd_ctl_open( &ctl, alsaCardName, 0 ) < 0 ) + if( alsa_snd_ctl_open( &ctl, alsaCardName, 0 ) < 0 ) { /* Unable to open card :( */ PA_DEBUG(( "%s: Unable to open device %s\n", __FUNCTION__, alsaCardName )); continue; } - snd_ctl_card_info( ctl, cardInfo ); + alsa_snd_ctl_card_info( ctl, cardInfo ); - PA_ENSURE( PaAlsa_StrDup( alsaApi, &cardName, snd_ctl_card_info_get_name( cardInfo )) ); + PA_ENSURE( PaAlsa_StrDup( alsaApi, &cardName, alsa_snd_ctl_card_info_get_name( cardInfo )) ); - while( snd_ctl_pcm_next_device( ctl, &devIdx ) == 0 && devIdx >= 0 ) + while( alsa_snd_ctl_pcm_next_device( ctl, &devIdx ) == 0 && devIdx >= 0 ) { char *alsaDeviceName, *deviceName; size_t len; @@ -710,16 +1218,16 @@ static PaError BuildDeviceList( PaAlsaHostApiRepresentation *alsaApi ) snprintf( buf, sizeof (buf), "hw:%d,%d", cardIdx, devIdx ); /* Obtain info about this particular device */ - snd_pcm_info_set_device( pcmInfo, devIdx ); - snd_pcm_info_set_subdevice( pcmInfo, 0 ); - snd_pcm_info_set_stream( pcmInfo, SND_PCM_STREAM_CAPTURE ); - if( snd_ctl_pcm_info( ctl, pcmInfo ) >= 0 ) + alsa_snd_pcm_info_set_device( pcmInfo, devIdx ); + alsa_snd_pcm_info_set_subdevice( pcmInfo, 0 ); + alsa_snd_pcm_info_set_stream( pcmInfo, SND_PCM_STREAM_CAPTURE ); + if( alsa_snd_ctl_pcm_info( ctl, pcmInfo ) >= 0 ) { hasCapture = 1; } - snd_pcm_info_set_stream( pcmInfo, SND_PCM_STREAM_PLAYBACK ); - if( snd_ctl_pcm_info( ctl, pcmInfo ) >= 0 ) + alsa_snd_pcm_info_set_stream( pcmInfo, SND_PCM_STREAM_PLAYBACK ); + if( alsa_snd_ctl_pcm_info( ctl, pcmInfo ) >= 0 ) { hasPlayback = 1; } @@ -731,11 +1239,11 @@ static PaError BuildDeviceList( PaAlsaHostApiRepresentation *alsaApi ) } /* The length of the string written by snprintf plus terminating 0 */ - len = snprintf( NULL, 0, "%s: %s (%s)", cardName, snd_pcm_info_get_name( pcmInfo ), buf ) + 1; + len = snprintf( NULL, 0, "%s: %s (%s)", cardName, alsa_snd_pcm_info_get_name( pcmInfo ), buf ) + 1; PA_UNLESS( deviceName = (char *)PaUtil_GroupAllocateMemory( alsaApi->allocations, len ), paInsufficientMemory ); snprintf( deviceName, len, "%s: %s (%s)", cardName, - snd_pcm_info_get_name( pcmInfo ), buf ); + alsa_snd_pcm_info_get_name( pcmInfo ), buf ); ++numDeviceNames; if( !hwDevInfos || numDeviceNames > maxDeviceNames ) @@ -753,32 +1261,32 @@ static PaError BuildDeviceList( PaAlsaHostApiRepresentation *alsaApi ) hwDevInfos[ numDeviceNames - 1 ].hasPlayback = hasPlayback; hwDevInfos[ numDeviceNames - 1 ].hasCapture = hasCapture; } - snd_ctl_close( ctl ); + alsa_snd_ctl_close( ctl ); } /* Iterate over plugin devices */ - if( NULL == snd_config ) + if( NULL == (*alsa_snd_config) ) { - /* snd_config_update is called implicitly by some functions, if this hasn't happened snd_config will be NULL (bleh) */ - ENSURE_( snd_config_update(), paUnanticipatedHostError ); + /* alsa_snd_config_update is called implicitly by some functions, if this hasn't happened snd_config will be NULL (bleh) */ + ENSURE_( alsa_snd_config_update(), paUnanticipatedHostError ); PA_DEBUG(( "Updating snd_config\n" )); } - assert( snd_config ); - if( (res = snd_config_search( snd_config, "pcm", &topNode )) >= 0 ) + assert( *alsa_snd_config ); + if( (res = alsa_snd_config_search( *alsa_snd_config, "pcm", &topNode )) >= 0 ) { snd_config_iterator_t i, next; - snd_config_for_each( i, next, topNode ) + alsa_snd_config_for_each( i, next, topNode ) { const char *tpStr = "unknown", *idStr = NULL; int err = 0; char *alsaDeviceName, *deviceName; const HwDevInfo *predefined = NULL; - snd_config_t *n = snd_config_iterator_entry( i ), * tp = NULL;; + snd_config_t *n = alsa_snd_config_iterator_entry( i ), * tp = NULL;; - if( (err = snd_config_search( n, "type", &tp )) < 0 ) + if( (err = alsa_snd_config_search( n, "type", &tp )) < 0 ) { if( -ENOENT != err ) { @@ -787,15 +1295,15 @@ static PaError BuildDeviceList( PaAlsaHostApiRepresentation *alsaApi ) } else { - ENSURE_( snd_config_get_string( tp, &tpStr ), paUnanticipatedHostError ); + ENSURE_( alsa_snd_config_get_string( tp, &tpStr ), paUnanticipatedHostError ); } - ENSURE_( snd_config_get_id( n, &idStr ), paUnanticipatedHostError ); + ENSURE_( alsa_snd_config_get_id( n, &idStr ), paUnanticipatedHostError ); if( IgnorePlugin( idStr ) ) { - PA_DEBUG(( "%s: Ignoring ALSA plugin device %s of type %s\n", __FUNCTION__, idStr, tpStr )); + PA_DEBUG(( "%s: Ignoring ALSA plugin device [%s] of type [%s]\n", __FUNCTION__, idStr, tpStr )); continue; } - PA_DEBUG(( "%s: Found plugin %s of type %s\n", __FUNCTION__, idStr, tpStr )); + PA_DEBUG(( "%s: Found plugin [%s] of type [%s]\n", __FUNCTION__, idStr, tpStr )); PA_UNLESS( alsaDeviceName = (char*)PaUtil_GroupAllocateMemory( alsaApi->allocations, strlen(idStr) + 6 ), paInsufficientMemory ); @@ -831,7 +1339,7 @@ static PaError BuildDeviceList( PaAlsaHostApiRepresentation *alsaApi ) } } else - PA_DEBUG(( "%s: Iterating over ALSA plugins failed: %s\n", __FUNCTION__, snd_strerror( res ) )); + PA_DEBUG(( "%s: Iterating over ALSA plugins failed: %s\n", __FUNCTION__, alsa_snd_strerror( res ) )); /* allocate deviceInfo memory based on the number of devices */ PA_UNLESS( baseApi->deviceInfos = (PaDeviceInfo**)PaUtil_GroupAllocateMemory( @@ -849,7 +1357,7 @@ static PaError BuildDeviceList( PaAlsaHostApiRepresentation *alsaApi ) * (dmix) is closed. The 'default' plugin may also point to the dmix plugin, so the same goes * for this. */ - + PA_DEBUG(( "%s: filling device info for %d devices\n", __FUNCTION__, numDeviceNames )); for( i = 0, devIdx = 0; i < numDeviceNames; ++i ) { PaAlsaDeviceInfo* devInfo = &deviceInfoArray[i]; @@ -933,36 +1441,158 @@ static PaSampleFormat GetAvailableFormats( snd_pcm_t *pcm ) { PaSampleFormat available = 0; snd_pcm_hw_params_t *hwParams; - snd_pcm_hw_params_alloca( &hwParams ); + alsa_snd_pcm_hw_params_alloca( &hwParams ); - snd_pcm_hw_params_any( pcm, hwParams ); + alsa_snd_pcm_hw_params_any( pcm, hwParams ); - if( snd_pcm_hw_params_test_format( pcm, hwParams, SND_PCM_FORMAT_FLOAT ) >= 0) + if( alsa_snd_pcm_hw_params_test_format( pcm, hwParams, SND_PCM_FORMAT_FLOAT ) >= 0) available |= paFloat32; - if( snd_pcm_hw_params_test_format( pcm, hwParams, SND_PCM_FORMAT_S32 ) >= 0) + if( alsa_snd_pcm_hw_params_test_format( pcm, hwParams, SND_PCM_FORMAT_S32 ) >= 0) available |= paInt32; #ifdef PA_LITTLE_ENDIAN - if( snd_pcm_hw_params_test_format( pcm, hwParams, SND_PCM_FORMAT_S24_3LE ) >= 0) + if( alsa_snd_pcm_hw_params_test_format( pcm, hwParams, SND_PCM_FORMAT_S24_3LE ) >= 0) available |= paInt24; #elif defined PA_BIG_ENDIAN - if( snd_pcm_hw_params_test_format( pcm, hwParams, SND_PCM_FORMAT_S24_3BE ) >= 0) + if( alsa_snd_pcm_hw_params_test_format( pcm, hwParams, SND_PCM_FORMAT_S24_3BE ) >= 0) available |= paInt24; #endif - if( snd_pcm_hw_params_test_format( pcm, hwParams, SND_PCM_FORMAT_S16 ) >= 0) + if( alsa_snd_pcm_hw_params_test_format( pcm, hwParams, SND_PCM_FORMAT_S16 ) >= 0) available |= paInt16; - if( snd_pcm_hw_params_test_format( pcm, hwParams, SND_PCM_FORMAT_U8 ) >= 0) + if( alsa_snd_pcm_hw_params_test_format( pcm, hwParams, SND_PCM_FORMAT_U8 ) >= 0) available |= paUInt8; - if( snd_pcm_hw_params_test_format( pcm, hwParams, SND_PCM_FORMAT_S8 ) >= 0) + if( alsa_snd_pcm_hw_params_test_format( pcm, hwParams, SND_PCM_FORMAT_S8 ) >= 0) available |= paInt8; return available; } +/* Output to console all formats supported by device */ +static void LogAllAvailableFormats( snd_pcm_t *pcm ) +{ + PaSampleFormat available = 0; + snd_pcm_hw_params_t *hwParams; + alsa_snd_pcm_hw_params_alloca( &hwParams ); + + alsa_snd_pcm_hw_params_any( pcm, hwParams ); + + PA_DEBUG(( " --- Supported Formats ---\n" )); + + if( alsa_snd_pcm_hw_params_test_format( pcm, hwParams, SND_PCM_FORMAT_S8 ) >= 0) + PA_DEBUG(( "SND_PCM_FORMAT_S8\n" )); + if( alsa_snd_pcm_hw_params_test_format( pcm, hwParams, SND_PCM_FORMAT_U8 ) >= 0) + PA_DEBUG(( "SND_PCM_FORMAT_U8\n" )); + + if( alsa_snd_pcm_hw_params_test_format( pcm, hwParams, SND_PCM_FORMAT_S16_LE ) >= 0) + PA_DEBUG(( "SND_PCM_FORMAT_S16_LE\n" )); + if( alsa_snd_pcm_hw_params_test_format( pcm, hwParams, SND_PCM_FORMAT_S16_BE ) >= 0) + PA_DEBUG(( "SND_PCM_FORMAT_S16_BE\n" )); + + if( alsa_snd_pcm_hw_params_test_format( pcm, hwParams, SND_PCM_FORMAT_U16_LE ) >= 0) + PA_DEBUG(( "SND_PCM_FORMAT_U16_LE\n" )); + if( alsa_snd_pcm_hw_params_test_format( pcm, hwParams, SND_PCM_FORMAT_U16_BE ) >= 0) + PA_DEBUG(( "SND_PCM_FORMAT_U16_BE\n" )); + + if( alsa_snd_pcm_hw_params_test_format( pcm, hwParams, SND_PCM_FORMAT_S24_LE ) >= 0) + PA_DEBUG(( "SND_PCM_FORMAT_S24_LE\n" )); + if( alsa_snd_pcm_hw_params_test_format( pcm, hwParams, SND_PCM_FORMAT_S24_BE ) >= 0) + PA_DEBUG(( "SND_PCM_FORMAT_S24_BE\n" )); + + if( alsa_snd_pcm_hw_params_test_format( pcm, hwParams, SND_PCM_FORMAT_U24_LE ) >= 0) + PA_DEBUG(( "SND_PCM_FORMAT_U24_LE\n" )); + if( alsa_snd_pcm_hw_params_test_format( pcm, hwParams, SND_PCM_FORMAT_U24_BE ) >= 0) + PA_DEBUG(( "SND_PCM_FORMAT_U24_BE\n" )); + + if( alsa_snd_pcm_hw_params_test_format( pcm, hwParams, SND_PCM_FORMAT_FLOAT_LE ) >= 0) + PA_DEBUG(( "SND_PCM_FORMAT_FLOAT_LE\n" )); + if( alsa_snd_pcm_hw_params_test_format( pcm, hwParams, SND_PCM_FORMAT_FLOAT_BE ) >= 0) + PA_DEBUG(( "SND_PCM_FORMAT_FLOAT_BE\n" )); + + if( alsa_snd_pcm_hw_params_test_format( pcm, hwParams, SND_PCM_FORMAT_FLOAT64_LE ) >= 0) + PA_DEBUG(( "SND_PCM_FORMAT_FLOAT64_LE\n" )); + if( alsa_snd_pcm_hw_params_test_format( pcm, hwParams, SND_PCM_FORMAT_FLOAT64_BE ) >= 0) + PA_DEBUG(( "SND_PCM_FORMAT_FLOAT64_BE\n" )); + + if( alsa_snd_pcm_hw_params_test_format( pcm, hwParams, SND_PCM_FORMAT_IEC958_SUBFRAME_LE ) >= 0) + PA_DEBUG(( "SND_PCM_FORMAT_IEC958_SUBFRAME_LE\n" )); + if( alsa_snd_pcm_hw_params_test_format( pcm, hwParams, SND_PCM_FORMAT_IEC958_SUBFRAME_BE ) >= 0) + PA_DEBUG(( "SND_PCM_FORMAT_IEC958_SUBFRAME_BE\n" )); + + if( alsa_snd_pcm_hw_params_test_format( pcm, hwParams, SND_PCM_FORMAT_MU_LAW ) >= 0) + PA_DEBUG(( "SND_PCM_FORMAT_MU_LAW\n" )); + if( alsa_snd_pcm_hw_params_test_format( pcm, hwParams, SND_PCM_FORMAT_A_LAW ) >= 0) + PA_DEBUG(( "SND_PCM_FORMAT_A_LAW\n" )); + + if( alsa_snd_pcm_hw_params_test_format( pcm, hwParams, SND_PCM_FORMAT_IMA_ADPCM ) >= 0) + PA_DEBUG(( "SND_PCM_FORMAT_IMA_ADPCM\n" )); + if( alsa_snd_pcm_hw_params_test_format( pcm, hwParams, SND_PCM_FORMAT_MPEG ) >= 0) + PA_DEBUG(( "SND_PCM_FORMAT_MPEG\n" )); + + if( alsa_snd_pcm_hw_params_test_format( pcm, hwParams, SND_PCM_FORMAT_GSM ) >= 0) + PA_DEBUG(( "SND_PCM_FORMAT_GSM\n" )); + if( alsa_snd_pcm_hw_params_test_format( pcm, hwParams, SND_PCM_FORMAT_SPECIAL ) >= 0) + PA_DEBUG(( "SND_PCM_FORMAT_SPECIAL\n" )); + + if( alsa_snd_pcm_hw_params_test_format( pcm, hwParams, SND_PCM_FORMAT_S24_3LE ) >= 0) + PA_DEBUG(( "SND_PCM_FORMAT_S24_3LE\n" )); + if( alsa_snd_pcm_hw_params_test_format( pcm, hwParams, SND_PCM_FORMAT_S24_3BE ) >= 0) + PA_DEBUG(( "SND_PCM_FORMAT_S24_3BE\n" )); + + if( alsa_snd_pcm_hw_params_test_format( pcm, hwParams, SND_PCM_FORMAT_U24_3LE ) >= 0) + PA_DEBUG(( "SND_PCM_FORMAT_U24_3LE\n" )); + if( alsa_snd_pcm_hw_params_test_format( pcm, hwParams, SND_PCM_FORMAT_U24_3BE ) >= 0) + PA_DEBUG(( "SND_PCM_FORMAT_U24_3BE\n" )); + + if( alsa_snd_pcm_hw_params_test_format( pcm, hwParams, SND_PCM_FORMAT_S20_3LE ) >= 0) + PA_DEBUG(( "SND_PCM_FORMAT_S20_3LE\n" )); + if( alsa_snd_pcm_hw_params_test_format( pcm, hwParams, SND_PCM_FORMAT_S20_3BE ) >= 0) + PA_DEBUG(( "SND_PCM_FORMAT_S20_3BE\n" )); + + if( alsa_snd_pcm_hw_params_test_format( pcm, hwParams, SND_PCM_FORMAT_U20_3LE ) >= 0) + PA_DEBUG(( "SND_PCM_FORMAT_U20_3LE\n" )); + if( alsa_snd_pcm_hw_params_test_format( pcm, hwParams, SND_PCM_FORMAT_U20_3BE ) >= 0) + PA_DEBUG(( "SND_PCM_FORMAT_U20_3BE\n" )); + + if( alsa_snd_pcm_hw_params_test_format( pcm, hwParams, SND_PCM_FORMAT_S18_3LE ) >= 0) + PA_DEBUG(( "SND_PCM_FORMAT_S18_3LE\n" )); + if( alsa_snd_pcm_hw_params_test_format( pcm, hwParams, SND_PCM_FORMAT_S18_3BE ) >= 0) + PA_DEBUG(( "SND_PCM_FORMAT_S18_3BE\n" )); + + if( alsa_snd_pcm_hw_params_test_format( pcm, hwParams, SND_PCM_FORMAT_U18_3LE ) >= 0) + PA_DEBUG(( "SND_PCM_FORMAT_U18_3LE\n" )); + if( alsa_snd_pcm_hw_params_test_format( pcm, hwParams, SND_PCM_FORMAT_U18_3BE ) >= 0) + PA_DEBUG(( "SND_PCM_FORMAT_U18_3BE\n" )); + + if( alsa_snd_pcm_hw_params_test_format( pcm, hwParams, SND_PCM_FORMAT_S16 ) >= 0) + PA_DEBUG(( "SND_PCM_FORMAT_S16\n" )); + if( alsa_snd_pcm_hw_params_test_format( pcm, hwParams, SND_PCM_FORMAT_U16 ) >= 0) + PA_DEBUG(( "SND_PCM_FORMAT_U16\n" )); + + if( alsa_snd_pcm_hw_params_test_format( pcm, hwParams, SND_PCM_FORMAT_S24 ) >= 0) + PA_DEBUG(( "SND_PCM_FORMAT_S24\n" )); + if( alsa_snd_pcm_hw_params_test_format( pcm, hwParams, SND_PCM_FORMAT_U24 ) >= 0) + PA_DEBUG(( "SND_PCM_FORMAT_U24\n" )); + + if( alsa_snd_pcm_hw_params_test_format( pcm, hwParams, SND_PCM_FORMAT_S32 ) >= 0) + PA_DEBUG(( "SND_PCM_FORMAT_S32\n" )); + if( alsa_snd_pcm_hw_params_test_format( pcm, hwParams, SND_PCM_FORMAT_U32 ) >= 0) + PA_DEBUG(( "SND_PCM_FORMAT_U32\n" )); + + if( alsa_snd_pcm_hw_params_test_format( pcm, hwParams, SND_PCM_FORMAT_FLOAT ) >= 0) + PA_DEBUG(( "SND_PCM_FORMAT_FLOAT\n" )); + if( alsa_snd_pcm_hw_params_test_format( pcm, hwParams, SND_PCM_FORMAT_FLOAT64 ) >= 0) + PA_DEBUG(( "SND_PCM_FORMAT_FLOAT64\n" )); + + if( alsa_snd_pcm_hw_params_test_format( pcm, hwParams, SND_PCM_FORMAT_IEC958_SUBFRAME ) >= 0) + PA_DEBUG(( "SND_PCM_FORMAT_IEC958_SUBFRAME\n" )); + + PA_DEBUG(( " -------------------------\n" )); +} + static snd_pcm_format_t Pa2AlsaFormat( PaSampleFormat paFormat ) { switch( paFormat ) @@ -1034,7 +1664,7 @@ static PaError AlsaOpen( const PaUtilHostApiRepresentation *hostApi, const PaStr *pcm = NULL; ENSURE_( ret, -EBUSY == ret ? paDeviceUnavailable : paBadIODeviceCombination ); } - ENSURE_( snd_pcm_nonblock( *pcm, 0 ), paUnanticipatedHostError ); + ENSURE_( alsa_snd_pcm_nonblock( *pcm, 0 ), paUnanticipatedHostError ); end: return result; @@ -1053,7 +1683,7 @@ static PaError TestParameters( const PaUtilHostApiRepresentation *hostApi, const unsigned int numHostChannels; PaSampleFormat hostFormat; snd_pcm_hw_params_t *hwParams; - snd_pcm_hw_params_alloca( &hwParams ); + alsa_snd_pcm_hw_params_alloca( &hwParams ); if( !parameters->hostApiSpecificStreamInfo ) { @@ -1066,7 +1696,7 @@ static PaError TestParameters( const PaUtilHostApiRepresentation *hostApi, const PA_ENSURE( AlsaOpen( hostApi, parameters, streamDir, &pcm ) ); - snd_pcm_hw_params_any( pcm, hwParams ); + alsa_snd_pcm_hw_params_any( pcm, hwParams ); if( SetApproximateSampleRate( pcm, hwParams, sampleRate ) < 0 ) { @@ -1074,7 +1704,7 @@ static PaError TestParameters( const PaUtilHostApiRepresentation *hostApi, const goto error; } - if( snd_pcm_hw_params_set_channels( pcm, hwParams, numHostChannels ) < 0 ) + if( alsa_snd_pcm_hw_params_set_channels( pcm, hwParams, numHostChannels ) < 0 ) { result = paInvalidChannelCount; goto error; @@ -1083,12 +1713,14 @@ static PaError TestParameters( const PaUtilHostApiRepresentation *hostApi, const /* See if we can find a best possible match */ availableFormats = GetAvailableFormats( pcm ); PA_ENSURE( hostFormat = PaUtil_SelectClosestAvailableFormat( availableFormats, parameters->sampleFormat ) ); - ENSURE_( snd_pcm_hw_params_set_format( pcm, hwParams, Pa2AlsaFormat( hostFormat ) ), paUnanticipatedHostError ); + + /* Some specific hardware (reported: Audio8 DJ) can fail with assertion during this step. */ + ENSURE_( alsa_snd_pcm_hw_params_set_format( pcm, hwParams, Pa2AlsaFormat( hostFormat ) ), paUnanticipatedHostError ); { /* It happens that this call fails because the device is busy */ int ret = 0; - if( (ret = snd_pcm_hw_params( pcm, hwParams )) < 0) + if( (ret = alsa_snd_pcm_hw_params( pcm, hwParams )) < 0) { if( -EINVAL == ret ) { @@ -1113,7 +1745,7 @@ static PaError TestParameters( const PaUtilHostApiRepresentation *hostApi, const end: if( pcm ) { - snd_pcm_close( pcm ); + alsa_snd_pcm_close( pcm ); } return result; @@ -1169,7 +1801,7 @@ static PaError PaAlsaStreamComponent_Initialize( PaAlsaStreamComponent *self, Pa const PaStreamParameters *params, StreamDirection streamDir, int callbackMode ) { PaError result = paNoError; - PaSampleFormat userSampleFormat = params->sampleFormat, hostSampleFormat; + PaSampleFormat userSampleFormat = params->sampleFormat, hostSampleFormat = paNoError; assert( params->channelCount > 0 ); /* Make sure things have an initial value */ @@ -1190,8 +1822,9 @@ static PaError PaAlsaStreamComponent_Initialize( PaAlsaStreamComponent *self, Pa self->device = params->device; PA_ENSURE( AlsaOpen( &alsaApi->baseHostApiRep, params, streamDir, &self->pcm ) ); - self->nfds = snd_pcm_poll_descriptors_count( self->pcm ); - hostSampleFormat = PaUtil_SelectClosestAvailableFormat( GetAvailableFormats( self->pcm ), userSampleFormat ); + self->nfds = alsa_snd_pcm_poll_descriptors_count( self->pcm ); + + PA_ENSURE( hostSampleFormat = PaUtil_SelectClosestAvailableFormat( GetAvailableFormats( self->pcm ), userSampleFormat ) ); self->hostSampleFormat = hostSampleFormat; self->nativeFormat = Pa2AlsaFormat( hostSampleFormat ); @@ -1210,12 +1843,20 @@ static PaError PaAlsaStreamComponent_Initialize( PaAlsaStreamComponent *self, Pa } error: + + /* Log all available formats. */ + if ( hostSampleFormat == paSampleFormatNotSupported ) + { + LogAllAvailableFormats( self->pcm ); + PA_DEBUG(( "%s: Please provide the log output to PortAudio developers, your hardware does not have any sample format implemented yet.\n", __FUNCTION__ )); + } + return result; } static void PaAlsaStreamComponent_Terminate( PaAlsaStreamComponent *self ) { - snd_pcm_close( self->pcm ); + alsa_snd_pcm_close( self->pcm ); if( self->userBuffers ) PaUtil_FreeMemory( self->userBuffers ); } @@ -1252,12 +1893,12 @@ static PaError PaAlsaStreamComponent_InitialConfigure( PaAlsaStreamComponent *se /* ... fill up the configuration space with all possibile * combinations of parameters this device will accept */ - ENSURE_( snd_pcm_hw_params_any( pcm, hwParams ), paUnanticipatedHostError ); + ENSURE_( alsa_snd_pcm_hw_params_any( pcm, hwParams ), paUnanticipatedHostError ); - ENSURE_( snd_pcm_hw_params_set_periods_integer( pcm, hwParams ), paUnanticipatedHostError ); + ENSURE_( alsa_snd_pcm_hw_params_set_periods_integer( pcm, hwParams ), paUnanticipatedHostError ); /* I think there should be at least 2 periods (even though ALSA doesn't appear to enforce this) */ dir = 0; - ENSURE_( snd_pcm_hw_params_set_periods_min( pcm, hwParams, &minPeriods, &dir ), paUnanticipatedHostError ); + ENSURE_( alsa_snd_pcm_hw_params_set_periods_min( pcm, hwParams, &minPeriods, &dir ), paUnanticipatedHostError ); if( self->userInterleaved ) { @@ -1265,11 +1906,11 @@ static PaError PaAlsaStreamComponent_InitialConfigure( PaAlsaStreamComponent *se alternateAccessMode = SND_PCM_ACCESS_MMAP_NONINTERLEAVED; /* test if MMAP supported */ - self->canMmap = snd_pcm_hw_params_test_access( pcm, hwParams, accessMode ) >= 0 || - snd_pcm_hw_params_test_access( pcm, hwParams, alternateAccessMode ) >= 0; + self->canMmap = alsa_snd_pcm_hw_params_test_access( pcm, hwParams, accessMode ) >= 0 || + alsa_snd_pcm_hw_params_test_access( pcm, hwParams, alternateAccessMode ) >= 0; - PA_DEBUG(("%s: device MMAP SND_PCM_ACCESS_MMAP_INTERLEAVED: %s\n", __FUNCTION__, (snd_pcm_hw_params_test_access( pcm, hwParams, accessMode ) >= 0 ? "YES" : "NO"))); - PA_DEBUG(("%s: device MMAP SND_PCM_ACCESS_MMAP_NONINTERLEAVED: %s\n", __FUNCTION__, (snd_pcm_hw_params_test_access( pcm, hwParams, alternateAccessMode ) >= 0 ? "YES" : "NO"))); + 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"))); + 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"))); if (!self->canMmap) { @@ -1283,11 +1924,11 @@ static PaError PaAlsaStreamComponent_InitialConfigure( PaAlsaStreamComponent *se alternateAccessMode = SND_PCM_ACCESS_MMAP_INTERLEAVED; /* test if MMAP supported */ - self->canMmap = snd_pcm_hw_params_test_access( pcm, hwParams, accessMode ) >= 0 || - snd_pcm_hw_params_test_access( pcm, hwParams, alternateAccessMode ) >= 0; + self->canMmap = alsa_snd_pcm_hw_params_test_access( pcm, hwParams, accessMode ) >= 0 || + alsa_snd_pcm_hw_params_test_access( pcm, hwParams, alternateAccessMode ) >= 0; - PA_DEBUG(("%s: device MMAP SND_PCM_ACCESS_MMAP_NONINTERLEAVED: %s\n", __FUNCTION__, (snd_pcm_hw_params_test_access( pcm, hwParams, accessMode ) >= 0 ? "YES" : "NO"))); - PA_DEBUG(("%s: device MMAP SND_PCM_ACCESS_MMAP_INTERLEAVED: %s\n", __FUNCTION__, (snd_pcm_hw_params_test_access( pcm, hwParams, alternateAccessMode ) >= 0 ? "YES" : "NO"))); + 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"))); + 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"))); if (!self->canMmap) { @@ -1299,20 +1940,21 @@ static PaError PaAlsaStreamComponent_InitialConfigure( PaAlsaStreamComponent *se PA_DEBUG(("%s: device can MMAP: %s\n", __FUNCTION__, (self->canMmap ? "YES" : "NO"))); /* If requested access mode fails, try alternate mode */ - if( snd_pcm_hw_params_set_access( pcm, hwParams, accessMode ) < 0 ) + if( alsa_snd_pcm_hw_params_set_access( pcm, hwParams, accessMode ) < 0 ) { int err = 0; - if( (err = snd_pcm_hw_params_set_access( pcm, hwParams, alternateAccessMode )) < 0) + if( (err = alsa_snd_pcm_hw_params_set_access( pcm, hwParams, alternateAccessMode )) < 0) { result = paUnanticipatedHostError; - PaUtil_SetLastHostErrorInfo( paALSA, err, snd_strerror( err ) ); + PaUtil_SetLastHostErrorInfo( paALSA, err, alsa_snd_strerror( err ) ); goto error; } /* Flip mode */ self->hostInterleaved = !self->userInterleaved; } - ENSURE_( snd_pcm_hw_params_set_format( pcm, hwParams, self->nativeFormat ), paUnanticipatedHostError ); + /* Some specific hardware (reported: Audio8 DJ) can fail with assertion during this step. */ + ENSURE_( alsa_snd_pcm_hw_params_set_format( pcm, hwParams, self->nativeFormat ), paUnanticipatedHostError ); ENSURE_( SetApproximateSampleRate( pcm, hwParams, sr ), paInvalidSampleRate ); ENSURE_( GetExactSampleRate( hwParams, &sr ), paUnanticipatedHostError ); @@ -1323,7 +1965,7 @@ static PaError PaAlsaStreamComponent_InitialConfigure( PaAlsaStreamComponent *se PA_ENSURE( paInvalidSampleRate ); } - ENSURE_( snd_pcm_hw_params_set_channels( pcm, hwParams, self->numHostChannels ), paInvalidChannelCount ); + ENSURE_( alsa_snd_pcm_hw_params_set_channels( pcm, hwParams, self->numHostChannels ), paInvalidChannelCount ); *sampleRate = sr; @@ -1348,49 +1990,57 @@ static PaError PaAlsaStreamComponent_FinishConfigure( PaAlsaStreamComponent *sel snd_pcm_uframes_t bufSz = 0; *latency = -1.; - snd_pcm_sw_params_alloca( &swParams ); + alsa_snd_pcm_sw_params_alloca( &swParams ); bufSz = params->suggestedLatency * sampleRate; - ENSURE_( snd_pcm_hw_params_set_buffer_size_near( self->pcm, hwParams, &bufSz ), paUnanticipatedHostError ); + ENSURE_( alsa_snd_pcm_hw_params_set_buffer_size_near( self->pcm, hwParams, &bufSz ), paUnanticipatedHostError ); /* Set the parameters! */ { - int r = snd_pcm_hw_params( self->pcm, hwParams ); + int r = alsa_snd_pcm_hw_params( self->pcm, hwParams ); #ifdef PA_ENABLE_DEBUG_OUTPUT if( r < 0 ) { snd_output_t *output = NULL; - snd_output_stdio_attach( &output, stderr, 0 ); - snd_pcm_hw_params_dump( hwParams, output ); + alsa_snd_output_stdio_attach( &output, stderr, 0 ); + alsa_snd_pcm_hw_params_dump( hwParams, output ); } #endif ENSURE_(r, paUnanticipatedHostError ); } - ENSURE_( snd_pcm_hw_params_get_buffer_size( hwParams, &self->bufferSize ), paUnanticipatedHostError ); + if (alsa_snd_pcm_hw_params_get_buffer_size != NULL) + { + ENSURE_( alsa_snd_pcm_hw_params_get_buffer_size( hwParams, &self->bufferSize ), paUnanticipatedHostError ); + } + else + { + self->bufferSize = bufSz; + } + /* Latency in seconds */ *latency = self->bufferSize / sampleRate; /* Now software parameters... */ - ENSURE_( snd_pcm_sw_params_current( self->pcm, swParams ), paUnanticipatedHostError ); + ENSURE_( alsa_snd_pcm_sw_params_current( self->pcm, swParams ), paUnanticipatedHostError ); - ENSURE_( snd_pcm_sw_params_set_start_threshold( self->pcm, swParams, self->framesPerBuffer ), paUnanticipatedHostError ); - ENSURE_( snd_pcm_sw_params_set_stop_threshold( self->pcm, swParams, self->bufferSize ), paUnanticipatedHostError ); + ENSURE_( alsa_snd_pcm_sw_params_set_start_threshold( self->pcm, swParams, self->framesPerBuffer ), paUnanticipatedHostError ); + ENSURE_( alsa_snd_pcm_sw_params_set_stop_threshold( self->pcm, swParams, self->bufferSize ), paUnanticipatedHostError ); /* Silence buffer in the case of underrun */ if( !primeBuffers ) /* XXX: Make sense? */ { snd_pcm_uframes_t boundary; - ENSURE_( snd_pcm_sw_params_get_boundary( swParams, &boundary ), paUnanticipatedHostError ); - ENSURE_( snd_pcm_sw_params_set_silence_threshold( self->pcm, swParams, 0 ), paUnanticipatedHostError ); - ENSURE_( snd_pcm_sw_params_set_silence_size( self->pcm, swParams, boundary ), paUnanticipatedHostError ); + ENSURE_( alsa_snd_pcm_sw_params_get_boundary( swParams, &boundary ), paUnanticipatedHostError ); + ENSURE_( alsa_snd_pcm_sw_params_set_silence_threshold( self->pcm, swParams, 0 ), paUnanticipatedHostError ); + ENSURE_( alsa_snd_pcm_sw_params_set_silence_size( self->pcm, swParams, boundary ), paUnanticipatedHostError ); } - ENSURE_( snd_pcm_sw_params_set_avail_min( self->pcm, swParams, self->framesPerBuffer ), paUnanticipatedHostError ); - ENSURE_( snd_pcm_sw_params_set_xfer_align( self->pcm, swParams, 1 ), paUnanticipatedHostError ); - ENSURE_( snd_pcm_sw_params_set_tstamp_mode( self->pcm, swParams, SND_PCM_TSTAMP_ENABLE ), paUnanticipatedHostError ); + ENSURE_( alsa_snd_pcm_sw_params_set_avail_min( self->pcm, swParams, self->framesPerBuffer ), paUnanticipatedHostError ); + ENSURE_( alsa_snd_pcm_sw_params_set_xfer_align( self->pcm, swParams, 1 ), paUnanticipatedHostError ); + ENSURE_( alsa_snd_pcm_sw_params_set_tstamp_mode( self->pcm, swParams, SND_PCM_TSTAMP_ENABLE ), paUnanticipatedHostError ); /* Set the parameters! */ - ENSURE_( snd_pcm_sw_params( self->pcm, swParams ), paUnanticipatedHostError ); + ENSURE_( alsa_snd_pcm_sw_params( self->pcm, swParams ), paUnanticipatedHostError ); error: return result; @@ -1590,8 +2240,8 @@ static PaError PaAlsaStreamComponent_DetermineFramesPerBuffer( PaAlsaStreamCompo /* It may be that the device only supports 2 periods for instance */ dir = 0; - ENSURE_( snd_pcm_hw_params_get_periods_min( hwParams, &minPeriods, &dir ), paUnanticipatedHostError ) - ENSURE_( snd_pcm_hw_params_get_periods_max( hwParams, &maxPeriods, &dir ), paUnanticipatedHostError ); + ENSURE_( alsa_snd_pcm_hw_params_get_periods_min( hwParams, &minPeriods, &dir ), paUnanticipatedHostError ); + ENSURE_( alsa_snd_pcm_hw_params_get_periods_max( hwParams, &maxPeriods, &dir ), paUnanticipatedHostError ); assert( maxPeriods > 1 ); /* Clamp to min/max */ @@ -1614,24 +2264,24 @@ static PaError PaAlsaStreamComponent_DetermineFramesPerBuffer( PaAlsaStreamCompo if( framesPerHostBuffer < framesPerUserBuffer ) { assert( framesPerUserBuffer % framesPerHostBuffer == 0 ); - if( snd_pcm_hw_params_test_period_size( self->pcm, hwParams, framesPerHostBuffer, 0 ) < 0 ) + if( alsa_snd_pcm_hw_params_test_period_size( self->pcm, hwParams, framesPerHostBuffer, 0 ) < 0 ) { - if( snd_pcm_hw_params_test_period_size( self->pcm, hwParams, framesPerHostBuffer * 2, 0 ) == 0 ) + if( alsa_snd_pcm_hw_params_test_period_size( self->pcm, hwParams, framesPerHostBuffer * 2, 0 ) == 0 ) framesPerHostBuffer *= 2; - else - if( snd_pcm_hw_params_test_period_size( self->pcm, hwParams, framesPerHostBuffer / 2, 0 ) == 0 ) + else + if( alsa_snd_pcm_hw_params_test_period_size( self->pcm, hwParams, framesPerHostBuffer / 2, 0 ) == 0 ) framesPerHostBuffer /= 2; } } else { assert( framesPerHostBuffer % framesPerUserBuffer == 0 ); - if( snd_pcm_hw_params_test_period_size( self->pcm, hwParams, framesPerHostBuffer, 0 ) < 0 ) + if( alsa_snd_pcm_hw_params_test_period_size( self->pcm, hwParams, framesPerHostBuffer, 0 ) < 0 ) { - if( snd_pcm_hw_params_test_period_size( self->pcm, hwParams, framesPerHostBuffer + framesPerUserBuffer, 0 ) == 0 ) + if( alsa_snd_pcm_hw_params_test_period_size( self->pcm, hwParams, framesPerHostBuffer + framesPerUserBuffer, 0 ) == 0 ) framesPerHostBuffer += framesPerUserBuffer; - else - if( snd_pcm_hw_params_test_period_size( self->pcm, hwParams, framesPerHostBuffer - framesPerUserBuffer, 0 ) == 0 ) + else + if( alsa_snd_pcm_hw_params_test_period_size( self->pcm, hwParams, framesPerHostBuffer - framesPerUserBuffer, 0 ) == 0 ) framesPerHostBuffer -= framesPerUserBuffer; } } @@ -1672,22 +2322,22 @@ static PaError PaAlsaStreamComponent_DetermineFramesPerBuffer( PaAlsaStreamCompo if( framesPerHostBuffer < framesPerUserBuffer ) { assert( framesPerUserBuffer % framesPerHostBuffer == 0 ); - if( snd_pcm_hw_params_test_period_size( self->pcm, hwParams, framesPerHostBuffer, 0 ) < 0 ) + if( alsa_snd_pcm_hw_params_test_period_size( self->pcm, hwParams, framesPerHostBuffer, 0 ) < 0 ) { - if( snd_pcm_hw_params_test_period_size( self->pcm, hwParams, framesPerHostBuffer * 2, 0 ) == 0 ) + if( alsa_snd_pcm_hw_params_test_period_size( self->pcm, hwParams, framesPerHostBuffer * 2, 0 ) == 0 ) framesPerHostBuffer *= 2; - else if( snd_pcm_hw_params_test_period_size( self->pcm, hwParams, framesPerHostBuffer / 2, 0 ) == 0 ) + else if( alsa_snd_pcm_hw_params_test_period_size( self->pcm, hwParams, framesPerHostBuffer / 2, 0 ) == 0 ) framesPerHostBuffer /= 2; } } else { assert( framesPerHostBuffer % framesPerUserBuffer == 0 ); - if( snd_pcm_hw_params_test_period_size( self->pcm, hwParams, framesPerHostBuffer, 0 ) < 0 ) + if( alsa_snd_pcm_hw_params_test_period_size( self->pcm, hwParams, framesPerHostBuffer, 0 ) < 0 ) { - if( snd_pcm_hw_params_test_period_size( self->pcm, hwParams, framesPerHostBuffer + framesPerUserBuffer, 0 ) == 0 ) + if( alsa_snd_pcm_hw_params_test_period_size( self->pcm, hwParams, framesPerHostBuffer + framesPerUserBuffer, 0 ) == 0 ) framesPerHostBuffer += framesPerUserBuffer; - else if( snd_pcm_hw_params_test_period_size( self->pcm, hwParams, framesPerHostBuffer - framesPerUserBuffer, 0 ) == 0 ) + else if( alsa_snd_pcm_hw_params_test_period_size( self->pcm, hwParams, framesPerHostBuffer - framesPerUserBuffer, 0 ) == 0 ) framesPerHostBuffer -= framesPerUserBuffer; } } @@ -1707,8 +2357,8 @@ static PaError PaAlsaStreamComponent_DetermineFramesPerBuffer( PaAlsaStreamCompo { /* Get min/max period sizes and adjust our chosen */ snd_pcm_uframes_t min = 0, max = 0, minmax_diff; - ENSURE_( snd_pcm_hw_params_get_period_size_min( hwParams, &min, NULL ), paUnanticipatedHostError ); - ENSURE_( snd_pcm_hw_params_get_period_size_max( hwParams, &max, NULL ), paUnanticipatedHostError ); + ENSURE_( alsa_snd_pcm_hw_params_get_period_size_min( hwParams, &min, NULL ), paUnanticipatedHostError ); + ENSURE_( alsa_snd_pcm_hw_params_get_period_size_max( hwParams, &max, NULL ), paUnanticipatedHostError ); minmax_diff = max - min; if( framesPerHostBuffer < min ) @@ -1716,7 +2366,7 @@ static PaError PaAlsaStreamComponent_DetermineFramesPerBuffer( PaAlsaStreamCompo PA_DEBUG(( "%s: The determined period size (%lu) is less than minimum (%lu)\n", __FUNCTION__, framesPerHostBuffer, min )); framesPerHostBuffer = ((minmax_diff == 2) ? min + 1 : min); } - else + else if( framesPerHostBuffer > max ) { PA_DEBUG(( "%s: The determined period size (%lu) is greater than maximum (%lu)\n", __FUNCTION__, framesPerHostBuffer, max )); @@ -1730,7 +2380,7 @@ static PaError PaAlsaStreamComponent_DetermineFramesPerBuffer( PaAlsaStreamCompo /* Try setting period size */ dir = 0; - ENSURE_( snd_pcm_hw_params_set_period_size_near( self->pcm, hwParams, &framesPerHostBuffer, &dir ), paUnanticipatedHostError ); + ENSURE_( alsa_snd_pcm_hw_params_set_period_size_near( self->pcm, hwParams, &framesPerHostBuffer, &dir ), paUnanticipatedHostError ); if( dir != 0 ) { PA_DEBUG(( "%s: The configured period size is non-integer.\n", __FUNCTION__, dir )); @@ -1798,13 +2448,13 @@ static PaError PaAlsaStream_DetermineFramesPerBuffer( PaAlsaStream* self, double minCapture, minPlayback, maxCapture, maxPlayback; dir = 0; - ENSURE_( snd_pcm_hw_params_get_period_size_min( hwParamsCapture, &minCapture, &dir ), paUnanticipatedHostError ); + ENSURE_( alsa_snd_pcm_hw_params_get_period_size_min( hwParamsCapture, &minCapture, &dir ), paUnanticipatedHostError ); dir = 0; - ENSURE_( snd_pcm_hw_params_get_period_size_min( hwParamsPlayback, &minPlayback, &dir ), paUnanticipatedHostError ); + ENSURE_( alsa_snd_pcm_hw_params_get_period_size_min( hwParamsPlayback, &minPlayback, &dir ), paUnanticipatedHostError ); dir = 0; - ENSURE_( snd_pcm_hw_params_get_period_size_max( hwParamsCapture, &maxCapture, &dir ), paUnanticipatedHostError ); + ENSURE_( alsa_snd_pcm_hw_params_get_period_size_max( hwParamsCapture, &maxCapture, &dir ), paUnanticipatedHostError ); dir = 0; - ENSURE_( snd_pcm_hw_params_get_period_size_max( hwParamsPlayback, &maxPlayback, &dir ), paUnanticipatedHostError ); + ENSURE_( alsa_snd_pcm_hw_params_get_period_size_max( hwParamsPlayback, &maxPlayback, &dir ), paUnanticipatedHostError ); minPeriodSize = PA_MAX( minPlayback, minCapture ); maxPeriodSize = PA_MIN( maxPlayback, maxCapture ); PA_UNLESS( minPeriodSize <= maxPeriodSize, paBadIODeviceCombination ); @@ -1815,8 +2465,8 @@ static PaError PaAlsaStream_DetermineFramesPerBuffer( PaAlsaStream* self, double { snd_pcm_uframes_t maxBufferSize; snd_pcm_uframes_t maxBufferSizeCapture, maxBufferSizePlayback; - ENSURE_( snd_pcm_hw_params_get_buffer_size_max( hwParamsCapture, &maxBufferSizeCapture ), paUnanticipatedHostError ); - ENSURE_( snd_pcm_hw_params_get_buffer_size_max( hwParamsPlayback, &maxBufferSizePlayback ), paUnanticipatedHostError ); + ENSURE_( alsa_snd_pcm_hw_params_get_buffer_size_max( hwParamsCapture, &maxBufferSizeCapture ), paUnanticipatedHostError ); + ENSURE_( alsa_snd_pcm_hw_params_get_buffer_size_max( hwParamsPlayback, &maxBufferSizePlayback ), paUnanticipatedHostError ); maxBufferSize = PA_MIN( maxBufferSizeCapture, maxBufferSizePlayback ); desiredBufSz = PA_MIN( desiredBufSz, maxBufferSize ); @@ -1830,8 +2480,8 @@ static PaError PaAlsaStream_DetermineFramesPerBuffer( PaAlsaStream* self, double while( periodSize <= maxPeriodSize ) { - if( snd_pcm_hw_params_test_period_size( self->playback.pcm, hwParamsPlayback, periodSize, 0 ) >= 0 && - snd_pcm_hw_params_test_period_size( self->capture.pcm, hwParamsCapture, periodSize, 0 ) >= 0 ) + if( alsa_snd_pcm_hw_params_test_period_size( self->playback.pcm, hwParamsPlayback, periodSize, 0 ) >= 0 && + alsa_snd_pcm_hw_params_test_period_size( self->capture.pcm, hwParamsCapture, periodSize, 0 ) >= 0 ) { /* OK! */ break; @@ -1851,8 +2501,8 @@ static PaError PaAlsaStream_DetermineFramesPerBuffer( PaAlsaStream* self, double while( optimalPeriodSize >= periodSize ) { - if( snd_pcm_hw_params_test_period_size( self->capture.pcm, hwParamsCapture, optimalPeriodSize, 0 ) - >= 0 && snd_pcm_hw_params_test_period_size( self->playback.pcm, hwParamsPlayback, + if( alsa_snd_pcm_hw_params_test_period_size( self->capture.pcm, hwParamsCapture, optimalPeriodSize, 0 ) + >= 0 && alsa_snd_pcm_hw_params_test_period_size( self->playback.pcm, hwParamsPlayback, optimalPeriodSize, 0 ) >= 0 ) { break; @@ -1866,9 +2516,9 @@ static PaError PaAlsaStream_DetermineFramesPerBuffer( PaAlsaStream* self, double if( periodSize <= maxPeriodSize ) { /* Looks good, the periodSize _should_ be acceptable by both devices */ - ENSURE_( snd_pcm_hw_params_set_period_size( self->capture.pcm, hwParamsCapture, periodSize, 0 ), + ENSURE_( alsa_snd_pcm_hw_params_set_period_size( self->capture.pcm, hwParamsCapture, periodSize, 0 ), paUnanticipatedHostError ); - ENSURE_( snd_pcm_hw_params_set_period_size( self->playback.pcm, hwParamsPlayback, periodSize, 0 ), + ENSURE_( alsa_snd_pcm_hw_params_set_period_size( self->playback.pcm, hwParamsPlayback, periodSize, 0 ), paUnanticipatedHostError ); self->capture.framesPerBuffer = self->playback.framesPerBuffer = periodSize; framesPerHostBuffer = periodSize; @@ -1881,11 +2531,11 @@ static PaError PaAlsaStream_DetermineFramesPerBuffer( PaAlsaStream* self, double self->capture.framesPerBuffer = optimalPeriodSize; dir = 0; - ENSURE_( snd_pcm_hw_params_set_period_size_near( self->capture.pcm, hwParamsCapture, &self->capture.framesPerBuffer, &dir ), + ENSURE_( alsa_snd_pcm_hw_params_set_period_size_near( self->capture.pcm, hwParamsCapture, &self->capture.framesPerBuffer, &dir ), paUnanticipatedHostError ); self->playback.framesPerBuffer = optimalPeriodSize; dir = 0; - ENSURE_( snd_pcm_hw_params_set_period_size_near( self->playback.pcm, hwParamsPlayback, &self->playback.framesPerBuffer, &dir ), + ENSURE_( alsa_snd_pcm_hw_params_set_period_size_near( self->playback.pcm, hwParamsPlayback, &self->playback.framesPerBuffer, &dir ), paUnanticipatedHostError ); framesPerHostBuffer = PA_MAX( self->capture.framesPerBuffer, self->playback.framesPerBuffer ); *hostBufferSizeMode = paUtilBoundedHostBufferSize; @@ -1903,7 +2553,7 @@ static PaError PaAlsaStream_DetermineFramesPerBuffer( PaAlsaStream* self, double snd_pcm_hw_params_t* firstHwParams = hwParamsCapture, * secondHwParams = hwParamsPlayback; dir = 0; - ENSURE_( snd_pcm_hw_params_get_periods_max( hwParamsPlayback, &maxPeriods, &dir ), paUnanticipatedHostError ); + ENSURE_( alsa_snd_pcm_hw_params_get_periods_max( hwParamsPlayback, &maxPeriods, &dir ), paUnanticipatedHostError ); if( maxPeriods < numPeriods ) { /* The playback component is trickier to get right, try that first */ @@ -1919,7 +2569,7 @@ static PaError PaAlsaStream_DetermineFramesPerBuffer( PaAlsaStream* self, double second->framesPerBuffer = first->framesPerBuffer; dir = 0; - ENSURE_( snd_pcm_hw_params_set_period_size_near( second->pcm, secondHwParams, &second->framesPerBuffer, &dir ), + ENSURE_( alsa_snd_pcm_hw_params_set_period_size_near( second->pcm, secondHwParams, &second->framesPerBuffer, &dir ), paUnanticipatedHostError ); if( self->capture.framesPerBuffer == self->playback.framesPerBuffer ) { @@ -1976,8 +2626,8 @@ static PaError PaAlsaStream_Configure( PaAlsaStream *self, const PaStreamParamet double realSr = sampleRate; snd_pcm_hw_params_t* hwParamsCapture, * hwParamsPlayback; - snd_pcm_hw_params_alloca( &hwParamsCapture ); - snd_pcm_hw_params_alloca( &hwParamsPlayback ); + alsa_snd_pcm_hw_params_alloca( &hwParamsCapture ); + alsa_snd_pcm_hw_params_alloca( &hwParamsPlayback ); if( self->capture.pcm ) PA_ENSURE( PaAlsaStreamComponent_InitialConfigure( &self->capture, inParams, self->primeBuffers, hwParamsCapture, @@ -2013,11 +2663,11 @@ static PaError PaAlsaStream_Configure( PaAlsaStream *self, const PaStreamParamet */ if( self->callbackMode && self->capture.pcm && self->playback.pcm ) { - int err = snd_pcm_link( self->capture.pcm, self->playback.pcm ); + int err = alsa_snd_pcm_link( self->capture.pcm, self->playback.pcm ); if( err == 0 ) self->pcmsSynced = 1; else - PA_DEBUG(( "%s: Unable to sync pcms: %s\n", __FUNCTION__, snd_strerror( err ) )); + PA_DEBUG(( "%s: Unable to sync pcms: %s\n", __FUNCTION__, alsa_snd_strerror( err ) )); } { @@ -2155,11 +2805,11 @@ static PaError CloseStream( PaStream* s ) static void SilenceBuffer( PaAlsaStream *stream ) { const snd_pcm_channel_area_t *areas; - snd_pcm_uframes_t frames = (snd_pcm_uframes_t)snd_pcm_avail_update( stream->playback.pcm ), offset; + snd_pcm_uframes_t frames = (snd_pcm_uframes_t)alsa_snd_pcm_avail_update( stream->playback.pcm ), offset; - snd_pcm_mmap_begin( stream->playback.pcm, &areas, &offset, &frames ); - snd_pcm_areas_silence( areas, offset, stream->playback.numHostChannels, frames, stream->playback.nativeFormat ); - snd_pcm_mmap_commit( stream->playback.pcm, offset, frames ); + alsa_snd_pcm_mmap_begin( stream->playback.pcm, &areas, &offset, &frames ); + alsa_snd_pcm_areas_silence( areas, offset, stream->playback.numHostChannels, frames, stream->playback.nativeFormat ); + alsa_snd_pcm_mmap_commit( stream->playback.pcm, offset, frames ); } /** Start/prepare pcm(s) for streaming. @@ -2182,21 +2832,21 @@ static PaError AlsaStart( PaAlsaStream *stream, int priming ) if( !priming ) { /* Buffer isn't primed, so prepare and silence */ - ENSURE_( snd_pcm_prepare( stream->playback.pcm ), paUnanticipatedHostError ); + ENSURE_( alsa_snd_pcm_prepare( stream->playback.pcm ), paUnanticipatedHostError ); if( stream->playback.canMmap ) SilenceBuffer( stream ); } if( stream->playback.canMmap ) - ENSURE_( snd_pcm_start( stream->playback.pcm ), paUnanticipatedHostError ); + ENSURE_( alsa_snd_pcm_start( stream->playback.pcm ), paUnanticipatedHostError ); } else - ENSURE_( snd_pcm_prepare( stream->playback.pcm ), paUnanticipatedHostError ); + ENSURE_( alsa_snd_pcm_prepare( stream->playback.pcm ), paUnanticipatedHostError ); } if( stream->capture.pcm && !stream->pcmsSynced ) { - ENSURE_( snd_pcm_prepare( stream->capture.pcm ), paUnanticipatedHostError ); + ENSURE_( alsa_snd_pcm_prepare( stream->capture.pcm ), paUnanticipatedHostError ); /* For a blocking stream we want to start capture as well, since nothing will happen otherwise */ - ENSURE_( snd_pcm_start( stream->capture.pcm ), paUnanticipatedHostError ); + ENSURE_( alsa_snd_pcm_start( stream->capture.pcm ), paUnanticipatedHostError ); } end: @@ -2216,7 +2866,7 @@ static int IsRunning( PaAlsaStream *stream ) PA_ENSURE( PaUnixMutex_Lock( &stream->stateMtx ) ); if( stream->capture.pcm ) { - snd_pcm_state_t capture_state = snd_pcm_state( stream->capture.pcm ); + snd_pcm_state_t capture_state = alsa_snd_pcm_state( stream->capture.pcm ); if( capture_state == SND_PCM_STATE_RUNNING || capture_state == SND_PCM_STATE_XRUN || capture_state == SND_PCM_STATE_DRAINING ) @@ -2228,7 +2878,7 @@ static int IsRunning( PaAlsaStream *stream ) if( stream->playback.pcm ) { - snd_pcm_state_t playback_state = snd_pcm_state( stream->playback.pcm ); + snd_pcm_state_t playback_state = alsa_snd_pcm_state( stream->playback.pcm ); if( playback_state == SND_PCM_STATE_RUNNING || playback_state == SND_PCM_STATE_XRUN || playback_state == SND_PCM_STATE_DRAINING ) @@ -2285,7 +2935,7 @@ error: static PaError AlsaStop( PaAlsaStream *stream, int abort ) { PaError result = paNoError; - /* XXX: snd_pcm_drain tends to lock up, avoid it until we find out more */ + /* XXX: alsa_snd_pcm_drain tends to lock up, avoid it until we find out more */ abort = 1; /* if( stream->capture.pcm && !strcmp( Pa_GetDeviceInfo( stream->capture.device )->name, @@ -2304,11 +2954,11 @@ static PaError AlsaStop( PaAlsaStream *stream, int abort ) { if( stream->playback.pcm ) { - ENSURE_( snd_pcm_drop( stream->playback.pcm ), paUnanticipatedHostError ); + ENSURE_( alsa_snd_pcm_drop( stream->playback.pcm ), paUnanticipatedHostError ); } if( stream->capture.pcm && !stream->pcmsSynced ) { - ENSURE_( snd_pcm_drop( stream->capture.pcm ), paUnanticipatedHostError ); + ENSURE_( alsa_snd_pcm_drop( stream->capture.pcm ), paUnanticipatedHostError ); } PA_DEBUG(( "%s: Dropped frames\n", __FUNCTION__ )); @@ -2317,8 +2967,8 @@ static PaError AlsaStop( PaAlsaStream *stream, int abort ) { if( stream->playback.pcm ) { - ENSURE_( snd_pcm_nonblock( stream->playback.pcm, 0 ), paUnanticipatedHostError ); - if( snd_pcm_drain( stream->playback.pcm ) < 0 ) + ENSURE_( alsa_snd_pcm_nonblock( stream->playback.pcm, 0 ), paUnanticipatedHostError ); + if( alsa_snd_pcm_drain( stream->playback.pcm ) < 0 ) { PA_DEBUG(( "%s: Draining playback handle failed!\n", __FUNCTION__ )); } @@ -2326,7 +2976,7 @@ static PaError AlsaStop( PaAlsaStream *stream, int abort ) if( stream->capture.pcm && !stream->pcmsSynced ) { /* We don't need to retrieve any remaining frames */ - if( snd_pcm_drain( stream->capture.pcm ) < 0 ) + if( alsa_snd_pcm_drain( stream->capture.pcm ) < 0 ) { PA_DEBUG(( "%s: Draining capture handle failed!\n", __FUNCTION__ )); } @@ -2424,7 +3074,7 @@ static PaTime GetStreamTime( PaStream *s ) snd_timestamp_t timestamp; snd_pcm_status_t* status; - snd_pcm_status_alloca( &status ); + alsa_snd_pcm_status_alloca( &status ); /* TODO: what if we have both? does it really matter? */ @@ -2434,14 +3084,14 @@ static PaTime GetStreamTime( PaStream *s ) if( stream->capture.pcm ) { - snd_pcm_status( stream->capture.pcm, status ); + alsa_snd_pcm_status( stream->capture.pcm, status ); } else if( stream->playback.pcm ) { - snd_pcm_status( stream->playback.pcm, status ); + alsa_snd_pcm_status( stream->playback.pcm, status ); } - snd_pcm_status_get_tstamp( status, ×tamp ); + alsa_snd_pcm_status_get_tstamp( status, ×tamp ); return timestamp.tv_sec + (PaTime)timestamp.tv_usec / 1e6; } @@ -2472,9 +3122,9 @@ static int SetApproximateSampleRate( snd_pcm_t *pcm, snd_pcm_hw_params_t *hwPara dir = 1; } - if( snd_pcm_hw_params_set_rate( pcm, hwParams, approx, dir ) < 0) + if( alsa_snd_pcm_hw_params_set_rate( pcm, hwParams, approx, dir ) < 0) result = paInvalidSampleRate; - + end: return result; @@ -2484,8 +3134,8 @@ error: /* Log */ { unsigned int _min = 0, _max = 0; int _dir = 0; - ENSURE_( snd_pcm_hw_params_get_rate_min( hwParams, &_min, &_dir ), paUnanticipatedHostError ); - ENSURE_( snd_pcm_hw_params_get_rate_max( hwParams, &_max, &_dir ), paUnanticipatedHostError ); + ENSURE_( alsa_snd_pcm_hw_params_get_rate_min( hwParams, &_min, &_dir ), paUnanticipatedHostError ); + ENSURE_( alsa_snd_pcm_hw_params_get_rate_max( hwParams, &_max, &_dir ), paUnanticipatedHostError ); PA_DEBUG(( "%s: SR min = %d, max = %d, req = %lu\n", __FUNCTION__, _min, _max, approx )); } @@ -2500,7 +3150,7 @@ static int GetExactSampleRate( snd_pcm_hw_params_t *hwParams, double *sampleRate assert( hwParams ); - err = snd_pcm_hw_params_get_rate_numden( hwParams, &num, &den ); + err = alsa_snd_pcm_hw_params_get_rate_numden( hwParams, &num, &den ); *sampleRate = (double) num / den; return err; @@ -2536,19 +3186,19 @@ static PaError PaAlsaStream_HandleXrun( PaAlsaStream *self ) snd_timestamp_t t; int restartAlsa = 0; /* do not restart Alsa by default */ - snd_pcm_status_alloca( &st ); + alsa_snd_pcm_status_alloca( &st ); if( self->playback.pcm ) { - snd_pcm_status( self->playback.pcm, st ); - if( snd_pcm_status_get_state( st ) == SND_PCM_STATE_XRUN ) + alsa_snd_pcm_status( self->playback.pcm, st ); + if( alsa_snd_pcm_status_get_state( st ) == SND_PCM_STATE_XRUN ) { - snd_pcm_status_get_trigger_tstamp( st, &t ); + alsa_snd_pcm_status_get_trigger_tstamp( st, &t ); self->underrun = now * 1000 - ((PaTime) t.tv_sec * 1000 + (PaTime) t.tv_usec / 1000); if (!self->playback.canMmap) { - if (snd_pcm_recover( self->playback.pcm, -EPIPE, 0 ) < 0) + if (alsa_snd_pcm_recover( self->playback.pcm, -EPIPE, 0 ) < 0) { PA_DEBUG(( "%s: [playback] non-MMAP-PCM failed recovering from XRUN, will restart Alsa\n", __FUNCTION__ )); ++ restartAlsa; /* did not manage to recover */ @@ -2560,15 +3210,15 @@ static PaError PaAlsaStream_HandleXrun( PaAlsaStream *self ) } if( self->capture.pcm ) { - snd_pcm_status( self->capture.pcm, st ); - if( snd_pcm_status_get_state( st ) == SND_PCM_STATE_XRUN ) + alsa_snd_pcm_status( self->capture.pcm, st ); + if( alsa_snd_pcm_status_get_state( st ) == SND_PCM_STATE_XRUN ) { - snd_pcm_status_get_trigger_tstamp( st, &t ); + alsa_snd_pcm_status_get_trigger_tstamp( st, &t ); self->overrun = now * 1000 - ((PaTime) t.tv_sec * 1000 + (PaTime) t.tv_usec / 1000); if (!self->capture.canMmap) { - if (snd_pcm_recover( self->capture.pcm, -EPIPE, 0 ) < 0) + if (alsa_snd_pcm_recover( self->capture.pcm, -EPIPE, 0 ) < 0) { PA_DEBUG(( "%s: [capture] non-MMAP-PCM failed recovering from XRUN, will restart Alsa\n", __FUNCTION__ )); ++ restartAlsa; /* did not manage to recover */ @@ -2614,8 +3264,8 @@ static PaError ContinuePoll( const PaAlsaStream *stream, StreamDirection streamD otherComponent = &stream->capture; } - /* ALSA docs say that negative delay should indicate xrun, but in my experience snd_pcm_delay returns -EPIPE */ - if( (err = snd_pcm_delay( otherComponent->pcm, &delay )) < 0 ) + /* ALSA docs say that negative delay should indicate xrun, but in my experience alsa_snd_pcm_delay returns -EPIPE */ + if( (err = alsa_snd_pcm_delay( otherComponent->pcm, &delay )) < 0 ) { if( err == -EPIPE ) { @@ -2680,21 +3330,21 @@ static void CalculateTimeInfo( PaAlsaStream *stream, PaStreamCallbackTimeInfo *t snd_timestamp_t capture_timestamp, playback_timestamp; PaTime capture_time = 0., playback_time = 0.; - snd_pcm_status_alloca( &capture_status ); - snd_pcm_status_alloca( &playback_status ); + alsa_snd_pcm_status_alloca( &capture_status ); + alsa_snd_pcm_status_alloca( &playback_status ); if( stream->capture.pcm ) { snd_pcm_sframes_t capture_delay; - snd_pcm_status( stream->capture.pcm, capture_status ); - snd_pcm_status_get_tstamp( capture_status, &capture_timestamp ); + alsa_snd_pcm_status( stream->capture.pcm, capture_status ); + alsa_snd_pcm_status_get_tstamp( capture_status, &capture_timestamp ); capture_time = capture_timestamp.tv_sec + ((PaTime)capture_timestamp.tv_usec / 1000000.0); timeInfo->currentTime = capture_time; - capture_delay = snd_pcm_status_get_delay( capture_status ); + capture_delay = alsa_snd_pcm_status_get_delay( capture_status ); timeInfo->inputBufferAdcTime = timeInfo->currentTime - (PaTime)capture_delay / stream->streamRepresentation.streamInfo.sampleRate; } @@ -2702,8 +3352,8 @@ static void CalculateTimeInfo( PaAlsaStream *stream, PaStreamCallbackTimeInfo *t { snd_pcm_sframes_t playback_delay; - snd_pcm_status( stream->playback.pcm, playback_status ); - snd_pcm_status_get_tstamp( playback_status, &playback_timestamp ); + alsa_snd_pcm_status( stream->playback.pcm, playback_status ); + alsa_snd_pcm_status_get_tstamp( playback_status, &playback_timestamp ); playback_time = playback_timestamp.tv_sec + ((PaTime)playback_timestamp.tv_usec / 1000000.0); @@ -2718,7 +3368,7 @@ static void CalculateTimeInfo( PaAlsaStream *stream, PaStreamCallbackTimeInfo *t else timeInfo->currentTime = playback_time; - playback_delay = snd_pcm_status_get_delay( playback_status ); + playback_delay = alsa_snd_pcm_status_get_delay( playback_status ); timeInfo->outputBufferDacTime = timeInfo->currentTime + (PaTime)playback_delay / stream->streamRepresentation.streamInfo.sampleRate; } @@ -2746,11 +3396,11 @@ static PaError PaAlsaStreamComponent_EndProcessing( PaAlsaStreamComponent *self, { /* Play sound */ if( self->hostInterleaved ) - res = snd_pcm_writei( self->pcm, self->nonMmapBuffer, numFrames ); + res = alsa_snd_pcm_writei( self->pcm, self->nonMmapBuffer, numFrames ); else { void *bufs[self->numHostChannels]; - int bufsize = snd_pcm_format_size( self->nativeFormat, self->framesPerBuffer + 1 ); + int bufsize = alsa_snd_pcm_format_size( self->nativeFormat, self->framesPerBuffer + 1 ); unsigned char *buffer = self->nonMmapBuffer; int i; for( i = 0; i < self->numHostChannels; ++i ) @@ -2758,12 +3408,12 @@ static PaError PaAlsaStreamComponent_EndProcessing( PaAlsaStreamComponent *self, bufs[i] = buffer; buffer += bufsize; } - res = snd_pcm_writen( self->pcm, bufs, numFrames ); + res = alsa_snd_pcm_writen( self->pcm, bufs, numFrames ); } } if( self->canMmap ) - res = snd_pcm_mmap_commit( self->pcm, self->offset, numFrames ); + res = alsa_snd_pcm_mmap_commit( self->pcm, self->offset, numFrames ); else { /* using realloc for optimisation @@ -2810,7 +3460,7 @@ static PaError PaAlsaStreamComponent_DoChannelAdaption( PaAlsaStreamComponent *s if( self->hostInterleaved ) { - int swidth = snd_pcm_format_size( self->nativeFormat, 1 ); + int swidth = alsa_snd_pcm_format_size( self->nativeFormat, 1 ); unsigned char *buffer = self->canMmap ? ExtractAddress( self->channelAreas, self->offset ) : self->nonMmapBuffer; /* Start after the last user channel */ @@ -2847,13 +3497,13 @@ static PaError PaAlsaStreamComponent_DoChannelAdaption( PaAlsaStreamComponent *s /* We extract the last user channel */ if( convertMono ) { - ENSURE_( snd_pcm_area_copy( self->channelAreas + self->numUserChannels, self->offset, self->channelAreas + + ENSURE_( alsa_snd_pcm_area_copy( self->channelAreas + self->numUserChannels, self->offset, self->channelAreas + (self->numUserChannels - 1), self->offset, numFrames, self->nativeFormat ), paUnanticipatedHostError ); --unusedChans; } if( unusedChans > 0 ) { - snd_pcm_areas_silence( self->channelAreas + (self->numHostChannels - unusedChans), self->offset, unusedChans, numFrames, + alsa_snd_pcm_areas_silence( self->channelAreas + (self->numHostChannels - unusedChans), self->offset, unusedChans, numFrames, self->nativeFormat ); } } @@ -2891,7 +3541,7 @@ error: static PaError PaAlsaStreamComponent_GetAvailableFrames( PaAlsaStreamComponent *self, unsigned long *numFrames, int *xrunOccurred ) { PaError result = paNoError; - snd_pcm_sframes_t framesAvail = snd_pcm_avail_update( self->pcm ); + snd_pcm_sframes_t framesAvail = alsa_snd_pcm_avail_update( self->pcm ); *xrunOccurred = 0; if( -EPIPE == framesAvail ) @@ -2915,7 +3565,7 @@ error: static PaError PaAlsaStreamComponent_BeginPolling( PaAlsaStreamComponent* self, struct pollfd* pfds ) { PaError result = paNoError; - int ret = snd_pcm_poll_descriptors( self->pcm, pfds, self->nfds ); + int ret = alsa_snd_pcm_poll_descriptors( self->pcm, pfds, self->nfds ); (void)ret; /* Prevent unused variable warning if asserts are turned off */ assert( ret == self->nfds ); @@ -2935,7 +3585,7 @@ static PaError PaAlsaStreamComponent_EndPolling( PaAlsaStreamComponent* self, st PaError result = paNoError; unsigned short revents; - ENSURE_( snd_pcm_poll_descriptors_revents( self->pcm, pfds, self->nfds, &revents ), paUnanticipatedHostError ); + ENSURE_( alsa_snd_pcm_poll_descriptors_revents( self->pcm, pfds, self->nfds, &revents ), paUnanticipatedHostError ); if( revents != 0 ) { if( revents & POLLERR ) @@ -3063,8 +3713,9 @@ static PaError PaAlsaStream_WaitForFrames( PaAlsaStream *self, unsigned long *fr int totalFds = 0; struct pollfd *capturePfds = NULL, *playbackPfds = NULL; +#ifdef PTHREAD_CANCELED pthread_testcancel(); - +#endif if( pollCapture ) { capturePfds = self->pfds; @@ -3237,13 +3888,13 @@ static PaError PaAlsaStreamComponent_RegisterChannels( PaAlsaStreamComponent* se if( self->canMmap ) { - ENSURE_( snd_pcm_mmap_begin( self->pcm, &areas, &self->offset, numFrames ), paUnanticipatedHostError ); + ENSURE_( alsa_snd_pcm_mmap_begin( self->pcm, &areas, &self->offset, numFrames ), paUnanticipatedHostError ); /* @concern ChannelAdaption Buffer address is recorded so we can do some channel adaption later */ self->channelAreas = (snd_pcm_channel_area_t *)areas; } else { - unsigned int bufferSize = self->numHostChannels * snd_pcm_format_size( self->nativeFormat, *numFrames ); + unsigned int bufferSize = self->numHostChannels * alsa_snd_pcm_format_size( self->nativeFormat, *numFrames ); if (bufferSize > self->nonMmapBufferSize) { self->nonMmapBuffer = realloc(self->nonMmapBuffer, (self->nonMmapBufferSize = bufferSize)); @@ -3257,7 +3908,7 @@ static PaError PaAlsaStreamComponent_RegisterChannels( PaAlsaStreamComponent* se if( self->hostInterleaved ) { - int swidth = snd_pcm_format_size( self->nativeFormat, 1 ); + int swidth = alsa_snd_pcm_format_size( self->nativeFormat, 1 ); p = buffer = self->canMmap ? ExtractAddress( areas, self->offset ) : self->nonMmapBuffer; for( i = 0; i < self->numUserChannels; ++i ) @@ -3295,7 +3946,7 @@ static PaError PaAlsaStreamComponent_RegisterChannels( PaAlsaStreamComponent* se /* Read sound */ int res; if( self->hostInterleaved ) - res = snd_pcm_readi( self->pcm, self->nonMmapBuffer, *numFrames ); + res = alsa_snd_pcm_readi( self->pcm, self->nonMmapBuffer, *numFrames ); else { void *bufs[self->numHostChannels]; @@ -3307,7 +3958,7 @@ static PaError PaAlsaStreamComponent_RegisterChannels( PaAlsaStreamComponent* se bufs[i] = buffer; buffer += buf_per_ch_size; } - res = snd_pcm_readn( self->pcm, bufs, *numFrames ); + res = alsa_snd_pcm_readn( self->pcm, bufs, *numFrames ); } if( res == -EPIPE || res == -ESTRPIPE ) { @@ -3467,13 +4118,13 @@ static void *CallbackThreadFunc( void *userData ) snd_pcm_sframes_t avail; if( stream->playback.pcm ) - ENSURE_( snd_pcm_prepare( stream->playback.pcm ), paUnanticipatedHostError ); + ENSURE_( alsa_snd_pcm_prepare( stream->playback.pcm ), paUnanticipatedHostError ); if( stream->capture.pcm && !stream->pcmsSynced ) - ENSURE_( snd_pcm_prepare( stream->capture.pcm ), paUnanticipatedHostError ); + ENSURE_( alsa_snd_pcm_prepare( stream->capture.pcm ), paUnanticipatedHostError ); /* We can't be certain that the whole ring buffer is available for priming, but there should be * at least one period */ - avail = snd_pcm_avail_update( stream->playback.pcm ); + avail = alsa_snd_pcm_avail_update( stream->playback.pcm ); startThreshold = avail - (avail % stream->playback.framesPerBuffer); assert( startThreshold >= stream->playback.framesPerBuffer ); } @@ -3492,7 +4143,9 @@ static void *CallbackThreadFunc( void *userData ) unsigned long framesAvail, framesGot; int xrun = 0; - pthread_testcancel(); +#ifdef PTHREAD_CANCELED + pthread_testcancel(); +#endif /* @concern StreamStop if the main thread has requested a stop and the stream has not been effectively * stopped we signal this condition by modifying callbackResult (we'll want to flush buffered output). @@ -3540,7 +4193,9 @@ static void *CallbackThreadFunc( void *userData ) { xrun = 0; - pthread_testcancel(); +#ifdef PTHREAD_CANCELED + pthread_testcancel(); +#endif /** @concern Xruns Under/overflows are to be reported to the callback */ if( stream->underrun > 0.0 ) @@ -3662,9 +4317,9 @@ static PaError ReadStream( PaStream* s, void *buffer, unsigned long frames ) } /* Start stream if in prepared state */ - if( snd_pcm_state( stream->capture.pcm ) == SND_PCM_STATE_PREPARED ) + if( alsa_snd_pcm_state( stream->capture.pcm ) == SND_PCM_STATE_PREPARED ) { - ENSURE_( snd_pcm_start( stream->capture.pcm ), paUnanticipatedHostError ); + ENSURE_( alsa_snd_pcm_start( stream->capture.pcm ), paUnanticipatedHostError ); } while( frames > 0 ) @@ -3742,10 +4397,10 @@ static PaError WriteStream( PaStream* s, const void *buffer, unsigned long frame framesAvail = err; hwAvail = stream->playback.bufferSize - framesAvail; - if( snd_pcm_state( stream->playback.pcm ) == SND_PCM_STATE_PREPARED && + if( alsa_snd_pcm_state( stream->playback.pcm ) == SND_PCM_STATE_PREPARED && hwAvail >= stream->playback.framesPerBuffer ) { - ENSURE_( snd_pcm_start( stream->playback.pcm ), paUnanticipatedHostError ); + ENSURE_( alsa_snd_pcm_start( stream->playback.pcm ), paUnanticipatedHostError ); } } @@ -3792,7 +4447,7 @@ static signed long GetStreamWriteAvailable( PaStream* s ) snd_pcm_sframes_t savail; PA_ENSURE( PaAlsaStream_HandleXrun( stream ) ); - savail = snd_pcm_avail_update( stream->playback.pcm ); + savail = alsa_snd_pcm_avail_update( stream->playback.pcm ); /* savail should not contain -EPIPE now, since PaAlsaStream_HandleXrun will only prepare the pcm */ ENSURE_( savail, paUnanticipatedHostError ); @@ -3859,9 +4514,9 @@ PaError PaAlsa_GetStreamInputCard(PaStream* s, int* card) { /* XXX: More descriptive error? */ PA_UNLESS( stream->capture.pcm, paDeviceUnavailable ); - snd_pcm_info_alloca( &pcmInfo ); - PA_ENSURE( snd_pcm_info( stream->capture.pcm, pcmInfo ) ); - *card = snd_pcm_info_get_card( pcmInfo ); + alsa_snd_pcm_info_alloca( &pcmInfo ); + PA_ENSURE( alsa_snd_pcm_info( stream->capture.pcm, pcmInfo ) ); + *card = alsa_snd_pcm_info_get_card( pcmInfo ); error: return result; @@ -3877,9 +4532,9 @@ PaError PaAlsa_GetStreamOutputCard(PaStream* s, int* card) { /* XXX: More descriptive error? */ PA_UNLESS( stream->playback.pcm, paDeviceUnavailable ); - snd_pcm_info_alloca( &pcmInfo ); - PA_ENSURE( snd_pcm_info( stream->playback.pcm, pcmInfo ) ); - *card = snd_pcm_info_get_card( pcmInfo ); + alsa_snd_pcm_info_alloca( &pcmInfo ); + PA_ENSURE( alsa_snd_pcm_info( stream->playback.pcm, pcmInfo ) ); + *card = alsa_snd_pcm_info_get_card( pcmInfo ); error: return result;