From 9c4c92fef6f0ef65682062870c87a29eedd79f9e Mon Sep 17 00:00:00 2001 From: dmitrykos Date: Fri, 11 Feb 2011 00:15:51 +0000 Subject: [PATCH] alsa: - implemented dynamic ALSA loading, you shall define PA_ALSA_DYNAMIC when compiling PortAudio library, by default PortAudio will use compile time linkage; - added PA_ALSA_PATHNAME define to redefine ALSA library path and filename to some other name and location, has effect only together with PA_ALSA_DYNAMIC; - added extension function (PaAlsa_SetLibraryPathName) which allows to set ALSA library path and filename during application run-time overwriting default set by PA_ALSA_PATHNAME during compilation; - added API compatibility with Android OS (although ALSA may not be available on your device and usually requires 'root' access rights to open an audio device), some missing ALSA functions are replaced with stubs (needs more input from interested parties), to compile on Android you need to add ALSA headers (get it from Android GIT source-code tree) to compiler's searchable path. --- include/pa_linux_alsa.h | 7 + src/hostapi/alsa/pa_linux_alsa.c | 1109 ++++++++++++++++++++++++------ 2 files changed, 889 insertions(+), 227 deletions(-) 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; -- 2.43.0