diff -r 9e2f117f24b9 NOTES --- a/NOTES Mon Oct 15 10:36:46 2007 +0200 +++ b/NOTES Fri Oct 26 02:01:39 2007 +0200 @@ -27,11 +27,14 @@ When LIBASOUND_DEBUG=1 is set, the error When LIBASOUND_DEBUG=1 is set, the errors in hw_params configuration will be dumped to stderr. Note that this will show even the non-fatal errors of plug layer (trial-and-error of parameters). -When LIBASOUND_DEBUG=2 is set, the default error message handler calls -assert() to catch with a debugger, in addition to parameter debugging. This feature is disabled when --with-debug=no is passed to configure, i.e. no strict checking is done in alsa-lib. + +In addition, when --enable-debug-assert configure option is given and +when LIBASOUND_DEBUG_ASSERT=1 is set, the default error message +handler can call assert() to catch with a debugger. This feature was +formerly activated via LIBASOUND_DEBUG=2. Blocking Open Mode diff -r 9e2f117f24b9 configure.in --- a/configure.in Mon Oct 15 10:36:46 2007 +0200 +++ b/configure.in Fri Oct 26 02:01:39 2007 +0200 @@ -167,6 +167,20 @@ else else AC_DEFINE(NDEBUG,,[No assert debug]) AC_MSG_RESULT(no) +fi + +if test "$debug" = "yes"; then + AC_MSG_CHECKING(for debug assert) + AC_ARG_ENABLE(debug-assert, + AS_HELP_STRING([--enable-debug], + [enable assert call at the default error message handler]), + debug_assert="$enableval", debug_assert="no") + if test "$debug_assert" = "yes"; then + AC_MSG_RESULT(yes) + AC_DEFINE(ALSA_DEBUG_ASSERT,,[Enable assert at error message handler]) + else + AC_MSG_RESULT(no) + fi fi dnl Temporary directory diff -r 9e2f117f24b9 include/asoundlib-head.h --- a/include/asoundlib-head.h Mon Oct 15 10:36:46 2007 +0200 +++ b/include/asoundlib-head.h Fri Oct 26 02:01:39 2007 +0200 @@ -33,7 +33,6 @@ #include #include #include -#include #include #include #include diff -r 9e2f117f24b9 include/control.h --- a/include/control.h Mon Oct 15 10:36:46 2007 +0200 +++ b/include/control.h Fri Oct 26 02:01:39 2007 +0200 @@ -279,7 +279,7 @@ size_t snd_ctl_elem_id_sizeof(void); * \brief allocate an invalid #snd_ctl_elem_id_t using standard alloca * \param ptr returned pointer */ -#define snd_ctl_elem_id_alloca(ptr) do { assert(ptr); *ptr = (snd_ctl_elem_id_t *) alloca(snd_ctl_elem_id_sizeof()); memset(*ptr, 0, snd_ctl_elem_id_sizeof()); } while (0) +#define snd_ctl_elem_id_alloca(ptr) __snd_alloca(ptr, snd_ctl_elem_id) int snd_ctl_elem_id_malloc(snd_ctl_elem_id_t **ptr); void snd_ctl_elem_id_free(snd_ctl_elem_id_t *obj); void snd_ctl_elem_id_clear(snd_ctl_elem_id_t *obj); @@ -302,7 +302,7 @@ size_t snd_ctl_card_info_sizeof(void); * \brief allocate an invalid #snd_ctl_card_info_t using standard alloca * \param ptr returned pointer */ -#define snd_ctl_card_info_alloca(ptr) do { assert(ptr); *ptr = (snd_ctl_card_info_t *) alloca(snd_ctl_card_info_sizeof()); memset(*ptr, 0, snd_ctl_card_info_sizeof()); } while (0) +#define snd_ctl_card_info_alloca(ptr) __snd_alloca(ptr, snd_ctl_card_info) int snd_ctl_card_info_malloc(snd_ctl_card_info_t **ptr); void snd_ctl_card_info_free(snd_ctl_card_info_t *obj); void snd_ctl_card_info_clear(snd_ctl_card_info_t *obj); @@ -320,7 +320,7 @@ size_t snd_ctl_event_sizeof(void); * \brief allocate an invalid #snd_ctl_event_t using standard alloca * \param ptr returned pointer */ -#define snd_ctl_event_alloca(ptr) do { assert(ptr); *ptr = (snd_ctl_event_t *) alloca(snd_ctl_event_sizeof()); memset(*ptr, 0, snd_ctl_event_sizeof()); } while (0) +#define snd_ctl_event_alloca(ptr) __snd_alloca(ptr, snd_ctl_event) int snd_ctl_event_malloc(snd_ctl_event_t **ptr); void snd_ctl_event_free(snd_ctl_event_t *obj); void snd_ctl_event_clear(snd_ctl_event_t *obj); @@ -332,7 +332,7 @@ size_t snd_ctl_elem_list_sizeof(void); * \brief allocate an invalid #snd_ctl_elem_list_t using standard alloca * \param ptr returned pointer */ -#define snd_ctl_elem_list_alloca(ptr) do { assert(ptr); *ptr = (snd_ctl_elem_list_t *) alloca(snd_ctl_elem_list_sizeof()); memset(*ptr, 0, snd_ctl_elem_list_sizeof()); } while (0) +#define snd_ctl_elem_list_alloca(ptr) __snd_alloca(ptr, snd_ctl_elem_list) int snd_ctl_elem_list_malloc(snd_ctl_elem_list_t **ptr); void snd_ctl_elem_list_free(snd_ctl_elem_list_t *obj); void snd_ctl_elem_list_clear(snd_ctl_elem_list_t *obj); @@ -353,7 +353,7 @@ size_t snd_ctl_elem_info_sizeof(void); * \brief allocate an invalid #snd_ctl_elem_info_t using standard alloca * \param ptr returned pointer */ -#define snd_ctl_elem_info_alloca(ptr) do { assert(ptr); *ptr = (snd_ctl_elem_info_t *) alloca(snd_ctl_elem_info_sizeof()); memset(*ptr, 0, snd_ctl_elem_info_sizeof()); } while (0) +#define snd_ctl_elem_info_alloca(ptr) __snd_alloca(ptr, snd_ctl_elem_info) int snd_ctl_elem_info_malloc(snd_ctl_elem_info_t **ptr); void snd_ctl_elem_info_free(snd_ctl_elem_info_t *obj); void snd_ctl_elem_info_clear(snd_ctl_elem_info_t *obj); @@ -408,7 +408,7 @@ size_t snd_ctl_elem_value_sizeof(void); * \brief allocate an invalid #snd_ctl_elem_value_t using standard alloca * \param ptr returned pointer */ -#define snd_ctl_elem_value_alloca(ptr) do { assert(ptr); *ptr = (snd_ctl_elem_value_t *) alloca(snd_ctl_elem_value_sizeof()); memset(*ptr, 0, snd_ctl_elem_value_sizeof()); } while (0) +#define snd_ctl_elem_value_alloca(ptr) __snd_alloca(ptr, snd_ctl_elem_value) int snd_ctl_elem_value_malloc(snd_ctl_elem_value_t **ptr); void snd_ctl_elem_value_free(snd_ctl_elem_value_t *obj); void snd_ctl_elem_value_clear(snd_ctl_elem_value_t *obj); @@ -441,6 +441,21 @@ const void * snd_ctl_elem_value_get_byte const void * snd_ctl_elem_value_get_bytes(const snd_ctl_elem_value_t *obj); void snd_ctl_elem_value_get_iec958(const snd_ctl_elem_value_t *obj, snd_aes_iec958_t *ptr); void snd_ctl_elem_value_set_iec958(snd_ctl_elem_value_t *obj, const snd_aes_iec958_t *ptr); + +int snd_tlv_parse_dB_info(unsigned int *tlv, unsigned int tlv_size, + unsigned int **db_tlvp); +int snd_tlv_get_dB_range(unsigned int *tlv, long rangemin, long rangemax, + long *min, long *max); +int snd_tlv_convert_to_dB(unsigned int *tlv, long rangemin, long rangemax, + long volume, long *db_gain); +int snd_tlv_convert_from_dB(unsigned int *tlv, long rangemin, long rangemax, + long db_gain, long *value, int xdir); +int snd_ctl_get_dB_range(snd_ctl_t *ctl, const snd_ctl_elem_id_t *id, + long *min, long *max); +int snd_ctl_convert_to_dB(snd_ctl_t *ctl, const snd_ctl_elem_id_t *id, + long volume, long *db_gain); +int snd_ctl_convert_from_dB(snd_ctl_t *ctl, const snd_ctl_elem_id_t *id, + long db_gain, long *value, int xdir); /** * \defgroup HControl High level Control Interface diff -r 9e2f117f24b9 include/global.h --- a/include/global.h Mon Oct 15 10:36:46 2007 +0200 +++ b/include/global.h Fri Oct 26 02:01:39 2007 +0200 @@ -102,6 +102,9 @@ int snd_dlclose(void *handle); int snd_dlclose(void *handle); +/** \brief alloca helper macro. */ +#define __snd_alloca(ptr,type) do { *ptr = (type##_t *) alloca(type##_sizeof()); memset(*ptr, 0, type##_sizeof()); } while (0) + /** * \brief Internal structure for an async notification client handler. * diff -r 9e2f117f24b9 include/hwdep.h --- a/include/hwdep.h Mon Oct 15 10:36:46 2007 +0200 +++ b/include/hwdep.h Fri Oct 26 02:01:39 2007 +0200 @@ -108,7 +108,7 @@ ssize_t snd_hwdep_read(snd_hwdep_t *hwde size_t snd_hwdep_info_sizeof(void); /** allocate #snd_hwdep_info_t container on stack */ -#define snd_hwdep_info_alloca(ptr) do { assert(ptr); *ptr = (snd_hwdep_info_t *) alloca(snd_hwdep_info_sizeof()); memset(*ptr, 0, snd_hwdep_info_sizeof()); } while (0) +#define snd_hwdep_info_alloca(ptr) __snd_alloca(ptr, snd_hwdep_info) int snd_hwdep_info_malloc(snd_hwdep_info_t **ptr); void snd_hwdep_info_free(snd_hwdep_info_t *obj); void snd_hwdep_info_copy(snd_hwdep_info_t *dst, const snd_hwdep_info_t *src); @@ -122,7 +122,7 @@ void snd_hwdep_info_set_device(snd_hwdep size_t snd_hwdep_dsp_status_sizeof(void); /** allocate #snd_hwdep_dsp_status_t container on stack */ -#define snd_hwdep_dsp_status_alloca(ptr) do { assert(ptr); *ptr = (snd_hwdep_dsp_status_t *) alloca(snd_hwdep_dsp_status_sizeof()); memset(*ptr, 0, snd_hwdep_dsp_status_sizeof()); } while (0) +#define snd_hwdep_dsp_status_alloca(ptr) __snd_alloca(ptr, snd_hwdep_dsp_status) int snd_hwdep_dsp_status_malloc(snd_hwdep_dsp_status_t **ptr); void snd_hwdep_dsp_status_free(snd_hwdep_dsp_status_t *obj); void snd_hwdep_dsp_status_copy(snd_hwdep_dsp_status_t *dst, const snd_hwdep_dsp_status_t *src); @@ -135,7 +135,7 @@ unsigned int snd_hwdep_dsp_status_get_ch size_t snd_hwdep_dsp_image_sizeof(void); /** allocate #snd_hwdep_dsp_image_t container on stack */ -#define snd_hwdep_dsp_image_alloca(ptr) do { assert(ptr); *ptr = (snd_hwdep_dsp_image_t *) alloca(snd_hwdep_dsp_image_sizeof()); memset(*ptr, 0, snd_hwdep_dsp_image_sizeof()); } while (0) +#define snd_hwdep_dsp_image_alloca(ptr) __snd_alloca(ptr, snd_hwdep_dsp_image) int snd_hwdep_dsp_image_malloc(snd_hwdep_dsp_image_t **ptr); void snd_hwdep_dsp_image_free(snd_hwdep_dsp_image_t *obj); void snd_hwdep_dsp_image_copy(snd_hwdep_dsp_image_t *dst, const snd_hwdep_dsp_image_t *src); diff -r 9e2f117f24b9 include/instr.h --- a/include/instr.h Mon Oct 15 10:36:46 2007 +0200 +++ b/include/instr.h Fri Oct 26 02:01:39 2007 +0200 @@ -44,12 +44,8 @@ typedef struct _snd_instr_header snd_ins typedef struct _snd_instr_header snd_instr_header_t; size_t snd_instr_header_sizeof(void); -#define snd_instr_header_alloca(ptr) \ -do {\ - assert(ptr);\ - *ptr = (snd_instr_header_t *)alloca(snd_instr_header_sizeof());\ - memset(*ptr, 0, snd_instr_header_sizeof());\ -} while (0) /**< allocate instrument header on stack */ +/** allocate instrument header on stack */ +#define snd_instr_header_alloca(ptr) __snd_alloca(ptr, snd_instr_header) int snd_instr_header_malloc(snd_instr_header_t **ptr, size_t len); void snd_instr_header_free(snd_instr_header_t *ptr); void snd_instr_header_copy(snd_instr_header_t *dst, const snd_instr_header_t *src); diff -r 9e2f117f24b9 include/mixer.h --- a/include/mixer.h Mon Oct 15 10:36:46 2007 +0200 +++ b/include/mixer.h Fri Oct 26 02:01:39 2007 +0200 @@ -146,7 +146,7 @@ size_t snd_mixer_class_sizeof(void); * \brief allocate an invalid #snd_mixer_class_t using standard alloca * \param ptr returned pointer */ -#define snd_mixer_class_alloca(ptr) do { assert(ptr); *ptr = (snd_mixer_class_t *) alloca(snd_mixer_class_sizeof()); memset(*ptr, 0, snd_mixer_class_sizeof()); } while (0) +#define snd_mixer_class_alloca(ptr) __snd_alloca(ptr, snd_mixer_class) int snd_mixer_class_malloc(snd_mixer_class_t **ptr); void snd_mixer_class_free(snd_mixer_class_t *obj); void snd_mixer_class_copy(snd_mixer_class_t *dst, const snd_mixer_class_t *src); @@ -294,7 +294,7 @@ size_t snd_mixer_selem_id_sizeof(void); * \brief allocate an invalid #snd_mixer_selem_id_t using standard alloca * \param ptr returned pointer */ -#define snd_mixer_selem_id_alloca(ptr) do { assert(ptr); *ptr = (snd_mixer_selem_id_t *) alloca(snd_mixer_selem_id_sizeof()); memset(*ptr, 0, snd_mixer_selem_id_sizeof()); } while (0) +#define snd_mixer_selem_id_alloca(ptr) __snd_alloca(ptr, snd_mixer_selem_id) int snd_mixer_selem_id_malloc(snd_mixer_selem_id_t **ptr); void snd_mixer_selem_id_free(snd_mixer_selem_id_t *obj); void snd_mixer_selem_id_copy(snd_mixer_selem_id_t *dst, const snd_mixer_selem_id_t *src); diff -r 9e2f117f24b9 include/pcm.h --- a/include/pcm.h Mon Oct 15 10:36:46 2007 +0200 +++ b/include/pcm.h Fri Oct 26 02:01:39 2007 +0200 @@ -470,7 +470,7 @@ size_t snd_pcm_info_sizeof(void); * \brief allocate an invalid #snd_pcm_info_t using standard alloca * \param ptr returned pointer */ -#define snd_pcm_info_alloca(ptr) do { assert(ptr); *ptr = (snd_pcm_info_t *) alloca(snd_pcm_info_sizeof()); memset(*ptr, 0, snd_pcm_info_sizeof()); } while (0) +#define snd_pcm_info_alloca(ptr) __snd_alloca(ptr, snd_pcm_info) int snd_pcm_info_malloc(snd_pcm_info_t **ptr); void snd_pcm_info_free(snd_pcm_info_t *obj); void snd_pcm_info_copy(snd_pcm_info_t *dst, const snd_pcm_info_t *src); @@ -548,7 +548,7 @@ size_t snd_pcm_hw_params_sizeof(void); * \brief allocate an invalid #snd_pcm_hw_params_t using standard alloca * \param ptr returned pointer */ -#define snd_pcm_hw_params_alloca(ptr) do { assert(ptr); *ptr = (snd_pcm_hw_params_t *) alloca(snd_pcm_hw_params_sizeof()); memset(*ptr, 0, snd_pcm_hw_params_sizeof()); } while (0) +#define snd_pcm_hw_params_alloca(ptr) __snd_alloca(ptr, snd_pcm_hw_params) int snd_pcm_hw_params_malloc(snd_pcm_hw_params_t **ptr); void snd_pcm_hw_params_free(snd_pcm_hw_params_t *obj); void snd_pcm_hw_params_copy(snd_pcm_hw_params_t *dst, const snd_pcm_hw_params_t *src); @@ -699,7 +699,7 @@ size_t snd_pcm_sw_params_sizeof(void); * \brief allocate an invalid #snd_pcm_sw_params_t using standard alloca * \param ptr returned pointer */ -#define snd_pcm_sw_params_alloca(ptr) do { assert(ptr); *ptr = (snd_pcm_sw_params_t *) alloca(snd_pcm_sw_params_sizeof()); memset(*ptr, 0, snd_pcm_sw_params_sizeof()); } while (0) +#define snd_pcm_sw_params_alloca(ptr) __snd_alloca(ptr, snd_pcm_sw_params) int snd_pcm_sw_params_malloc(snd_pcm_sw_params_t **ptr); void snd_pcm_sw_params_free(snd_pcm_sw_params_t *obj); void snd_pcm_sw_params_copy(snd_pcm_sw_params_t *dst, const snd_pcm_sw_params_t *src); @@ -747,7 +747,7 @@ size_t snd_pcm_access_mask_sizeof(void); * \brief allocate an empty #snd_pcm_access_mask_t using standard alloca * \param ptr returned pointer */ -#define snd_pcm_access_mask_alloca(ptr) do { assert(ptr); *ptr = (snd_pcm_access_mask_t *) alloca(snd_pcm_access_mask_sizeof()); memset(*ptr, 0, snd_pcm_access_mask_sizeof()); } while (0) +#define snd_pcm_access_mask_alloca(ptr) __snd_alloca(ptr, snd_pcm_access_mask) int snd_pcm_access_mask_malloc(snd_pcm_access_mask_t **ptr); void snd_pcm_access_mask_free(snd_pcm_access_mask_t *obj); void snd_pcm_access_mask_copy(snd_pcm_access_mask_t *dst, const snd_pcm_access_mask_t *src); @@ -772,7 +772,7 @@ size_t snd_pcm_format_mask_sizeof(void); * \brief allocate an empty #snd_pcm_format_mask_t using standard alloca * \param ptr returned pointer */ -#define snd_pcm_format_mask_alloca(ptr) do { assert(ptr); *ptr = (snd_pcm_format_mask_t *) alloca(snd_pcm_format_mask_sizeof()); memset(*ptr, 0, snd_pcm_format_mask_sizeof()); } while (0) +#define snd_pcm_format_mask_alloca(ptr) __snd_alloca(ptr, snd_pcm_format_mask) int snd_pcm_format_mask_malloc(snd_pcm_format_mask_t **ptr); void snd_pcm_format_mask_free(snd_pcm_format_mask_t *obj); void snd_pcm_format_mask_copy(snd_pcm_format_mask_t *dst, const snd_pcm_format_mask_t *src); @@ -797,7 +797,7 @@ size_t snd_pcm_subformat_mask_sizeof(voi * \brief allocate an empty #snd_pcm_subformat_mask_t using standard alloca * \param ptr returned pointer */ -#define snd_pcm_subformat_mask_alloca(ptr) do { assert(ptr); *ptr = (snd_pcm_subformat_mask_t *) alloca(snd_pcm_subformat_mask_sizeof()); memset(*ptr, 0, snd_pcm_subformat_mask_sizeof()); } while (0) +#define snd_pcm_subformat_mask_alloca(ptr) __snd_alloca(ptr, snd_pcm_subformat_mask) int snd_pcm_subformat_mask_malloc(snd_pcm_subformat_mask_t **ptr); void snd_pcm_subformat_mask_free(snd_pcm_subformat_mask_t *obj); void snd_pcm_subformat_mask_copy(snd_pcm_subformat_mask_t *dst, const snd_pcm_subformat_mask_t *src); @@ -822,7 +822,7 @@ size_t snd_pcm_status_sizeof(void); * \brief allocate an invalid #snd_pcm_status_t using standard alloca * \param ptr returned pointer */ -#define snd_pcm_status_alloca(ptr) do { assert(ptr); *ptr = (snd_pcm_status_t *) alloca(snd_pcm_status_sizeof()); memset(*ptr, 0, snd_pcm_status_sizeof()); } while (0) +#define snd_pcm_status_alloca(ptr) __snd_alloca(ptr, snd_pcm_status) int snd_pcm_status_malloc(snd_pcm_status_t **ptr); void snd_pcm_status_free(snd_pcm_status_t *obj); void snd_pcm_status_copy(snd_pcm_status_t *dst, const snd_pcm_status_t *src); diff -r 9e2f117f24b9 include/rawmidi.h --- a/include/rawmidi.h Mon Oct 15 10:36:46 2007 +0200 +++ b/include/rawmidi.h Fri Oct 26 02:01:39 2007 +0200 @@ -93,7 +93,7 @@ size_t snd_rawmidi_info_sizeof(void); * \brief allocate an invalid #snd_rawmidi_info_t using standard alloca * \param ptr returned pointer */ -#define snd_rawmidi_info_alloca(ptr) do { assert(ptr); *ptr = (snd_rawmidi_info_t *) alloca(snd_rawmidi_info_sizeof()); memset(*ptr, 0, snd_rawmidi_info_sizeof()); } while (0) +#define snd_rawmidi_info_alloca(ptr) __snd_alloca(ptr, snd_rawmidi_info) int snd_rawmidi_info_malloc(snd_rawmidi_info_t **ptr); void snd_rawmidi_info_free(snd_rawmidi_info_t *obj); void snd_rawmidi_info_copy(snd_rawmidi_info_t *dst, const snd_rawmidi_info_t *src); @@ -116,7 +116,7 @@ size_t snd_rawmidi_params_sizeof(void); * \brief allocate an invalid #snd_rawmidi_params_t using standard alloca * \param ptr returned pointer */ -#define snd_rawmidi_params_alloca(ptr) do { assert(ptr); *ptr = (snd_rawmidi_params_t *) alloca(snd_rawmidi_params_sizeof()); memset(*ptr, 0, snd_rawmidi_params_sizeof()); } while (0) +#define snd_rawmidi_params_alloca(ptr) __snd_alloca(ptr, snd_rawmidi_params) int snd_rawmidi_params_malloc(snd_rawmidi_params_t **ptr); void snd_rawmidi_params_free(snd_rawmidi_params_t *obj); void snd_rawmidi_params_copy(snd_rawmidi_params_t *dst, const snd_rawmidi_params_t *src); @@ -133,7 +133,7 @@ size_t snd_rawmidi_status_sizeof(void); * \brief allocate an invalid #snd_rawmidi_status_t using standard alloca * \param ptr returned pointer */ -#define snd_rawmidi_status_alloca(ptr) do { assert(ptr); *ptr = (snd_rawmidi_status_t *) alloca(snd_rawmidi_status_sizeof()); memset(*ptr, 0, snd_rawmidi_status_sizeof()); } while (0) +#define snd_rawmidi_status_alloca(ptr) __snd_alloca(ptr, snd_rawmidi_status) int snd_rawmidi_status_malloc(snd_rawmidi_status_t **ptr); void snd_rawmidi_status_free(snd_rawmidi_status_t *obj); void snd_rawmidi_status_copy(snd_rawmidi_status_t *dst, const snd_rawmidi_status_t *src); diff -r 9e2f117f24b9 include/seq.h --- a/include/seq.h Mon Oct 15 10:36:46 2007 +0200 +++ b/include/seq.h Fri Oct 26 02:01:39 2007 +0200 @@ -45,15 +45,6 @@ extern "C" { /** Sequencer handle */ typedef struct _snd_seq snd_seq_t; - -#ifndef DOC_HIDDEN -#define SND_ALLOCA(type,ptr) \ -do {\ - assert(ptr);\ - *ptr = (type##_t *)alloca(type##_sizeof());\ - memset(*ptr, 0, type##_sizeof());\ -} while (0) -#endif /** * sequencer opening stream types @@ -106,7 +97,7 @@ size_t snd_seq_system_info_sizeof(void); size_t snd_seq_system_info_sizeof(void); /** allocate a #snd_seq_system_info_t container on stack */ #define snd_seq_system_info_alloca(ptr) \ - SND_ALLOCA(snd_seq_system_info, ptr) + __snd_alloca(ptr, snd_seq_system_info) int snd_seq_system_info_malloc(snd_seq_system_info_t **ptr); void snd_seq_system_info_free(snd_seq_system_info_t *ptr); void snd_seq_system_info_copy(snd_seq_system_info_t *dst, const snd_seq_system_info_t *src); @@ -142,7 +133,7 @@ size_t snd_seq_client_info_sizeof(void); size_t snd_seq_client_info_sizeof(void); /** allocate a #snd_seq_client_info_t container on stack */ #define snd_seq_client_info_alloca(ptr) \ - SND_ALLOCA(snd_seq_client_info, ptr) + __snd_alloca(ptr, snd_seq_client_info) int snd_seq_client_info_malloc(snd_seq_client_info_t **ptr); void snd_seq_client_info_free(snd_seq_client_info_t *ptr); void snd_seq_client_info_copy(snd_seq_client_info_t *dst, const snd_seq_client_info_t *src); @@ -176,7 +167,7 @@ size_t snd_seq_client_pool_sizeof(void); size_t snd_seq_client_pool_sizeof(void); /** allocate a #snd_seq_client_pool_t container on stack */ #define snd_seq_client_pool_alloca(ptr) \ - SND_ALLOCA(snd_seq_client_pool, ptr) + __snd_alloca(ptr, snd_seq_client_pool) int snd_seq_client_pool_malloc(snd_seq_client_pool_t **ptr); void snd_seq_client_pool_free(snd_seq_client_pool_t *ptr); void snd_seq_client_pool_copy(snd_seq_client_pool_t *dst, const snd_seq_client_pool_t *src); @@ -265,7 +256,7 @@ size_t snd_seq_port_info_sizeof(void); size_t snd_seq_port_info_sizeof(void); /** allocate a #snd_seq_port_info_t container on stack */ #define snd_seq_port_info_alloca(ptr) \ - SND_ALLOCA(snd_seq_port_info, ptr) + __snd_alloca(ptr, snd_seq_port_info) int snd_seq_port_info_malloc(snd_seq_port_info_t **ptr); void snd_seq_port_info_free(snd_seq_port_info_t *ptr); void snd_seq_port_info_copy(snd_seq_port_info_t *dst, const snd_seq_port_info_t *src); @@ -323,7 +314,7 @@ size_t snd_seq_port_subscribe_sizeof(voi size_t snd_seq_port_subscribe_sizeof(void); /** allocate a #snd_seq_port_subscribe_t container on stack */ #define snd_seq_port_subscribe_alloca(ptr) \ - SND_ALLOCA(snd_seq_port_subscribe, ptr) + __snd_alloca(ptr, snd_seq_port_subscribe) int snd_seq_port_subscribe_malloc(snd_seq_port_subscribe_t **ptr); void snd_seq_port_subscribe_free(snd_seq_port_subscribe_t *ptr); void snd_seq_port_subscribe_copy(snd_seq_port_subscribe_t *dst, const snd_seq_port_subscribe_t *src); @@ -361,7 +352,7 @@ size_t snd_seq_query_subscribe_sizeof(vo size_t snd_seq_query_subscribe_sizeof(void); /** allocate a #snd_seq_query_subscribe_t container on stack */ #define snd_seq_query_subscribe_alloca(ptr) \ - SND_ALLOCA(snd_seq_query_subscribe, ptr) + __snd_alloca(ptr, snd_seq_query_subscribe) int snd_seq_query_subscribe_malloc(snd_seq_query_subscribe_t **ptr); void snd_seq_query_subscribe_free(snd_seq_query_subscribe_t *ptr); void snd_seq_query_subscribe_copy(snd_seq_query_subscribe_t *dst, const snd_seq_query_subscribe_t *src); @@ -411,7 +402,7 @@ size_t snd_seq_queue_info_sizeof(void); size_t snd_seq_queue_info_sizeof(void); /** allocate a #snd_seq_queue_info_t container on stack */ #define snd_seq_queue_info_alloca(ptr) \ - SND_ALLOCA(snd_seq_queue_info, ptr) + __snd_alloca(ptr, snd_seq_queue_info) int snd_seq_queue_info_malloc(snd_seq_queue_info_t **ptr); void snd_seq_queue_info_free(snd_seq_queue_info_t *ptr); void snd_seq_queue_info_copy(snd_seq_queue_info_t *dst, const snd_seq_queue_info_t *src); @@ -443,7 +434,7 @@ size_t snd_seq_queue_status_sizeof(void) size_t snd_seq_queue_status_sizeof(void); /** allocate a #snd_seq_queue_status_t container on stack */ #define snd_seq_queue_status_alloca(ptr) \ - SND_ALLOCA(snd_seq_queue_status, ptr) + __snd_alloca(ptr, snd_seq_queue_status) int snd_seq_queue_status_malloc(snd_seq_queue_status_t **ptr); void snd_seq_queue_status_free(snd_seq_queue_status_t *ptr); void snd_seq_queue_status_copy(snd_seq_queue_status_t *dst, const snd_seq_queue_status_t *src); @@ -461,7 +452,7 @@ size_t snd_seq_queue_tempo_sizeof(void); size_t snd_seq_queue_tempo_sizeof(void); /** allocate a #snd_seq_queue_tempo_t container on stack */ #define snd_seq_queue_tempo_alloca(ptr) \ - SND_ALLOCA(snd_seq_queue_tempo, ptr) + __snd_alloca(ptr, snd_seq_queue_tempo) int snd_seq_queue_tempo_malloc(snd_seq_queue_tempo_t **ptr); void snd_seq_queue_tempo_free(snd_seq_queue_tempo_t *ptr); void snd_seq_queue_tempo_copy(snd_seq_queue_tempo_t *dst, const snd_seq_queue_tempo_t *src); @@ -492,7 +483,7 @@ size_t snd_seq_queue_timer_sizeof(void); size_t snd_seq_queue_timer_sizeof(void); /** allocate a #snd_seq_queue_timer_t container on stack */ #define snd_seq_queue_timer_alloca(ptr) \ - SND_ALLOCA(snd_seq_queue_timer, ptr) + __snd_alloca(ptr, snd_seq_queue_timer) int snd_seq_queue_timer_malloc(snd_seq_queue_timer_t **ptr); void snd_seq_queue_timer_free(snd_seq_queue_timer_t *ptr); void snd_seq_queue_timer_copy(snd_seq_queue_timer_t *dst, const snd_seq_queue_timer_t *src); @@ -551,7 +542,7 @@ size_t snd_seq_remove_events_sizeof(void size_t snd_seq_remove_events_sizeof(void); /** allocate a #snd_seq_remove_events_t container on stack */ #define snd_seq_remove_events_alloca(ptr) \ - SND_ALLOCA(snd_seq_remove_events, ptr) + __snd_alloca(ptr, snd_seq_remove_events) int snd_seq_remove_events_malloc(snd_seq_remove_events_t **ptr); void snd_seq_remove_events_free(snd_seq_remove_events_t *ptr); void snd_seq_remove_events_copy(snd_seq_remove_events_t *dst, const snd_seq_remove_events_t *src); diff -r 9e2f117f24b9 include/timer.h --- a/include/timer.h Mon Oct 15 10:36:46 2007 +0200 +++ b/include/timer.h Fri Oct 26 02:01:39 2007 +0200 @@ -164,7 +164,7 @@ ssize_t snd_timer_read(snd_timer_t *hand size_t snd_timer_id_sizeof(void); /** allocate #snd_timer_id_t container on stack */ -#define snd_timer_id_alloca(ptr) do { assert(ptr); *ptr = (snd_timer_id_t *) alloca(snd_timer_id_sizeof()); memset(*ptr, 0, snd_timer_id_sizeof()); } while (0) +#define snd_timer_id_alloca(ptr) __snd_alloca(ptr, snd_timer_id) int snd_timer_id_malloc(snd_timer_id_t **ptr); void snd_timer_id_free(snd_timer_id_t *obj); void snd_timer_id_copy(snd_timer_id_t *dst, const snd_timer_id_t *src); @@ -182,7 +182,7 @@ int snd_timer_id_get_subdevice(snd_timer size_t snd_timer_ginfo_sizeof(void); /** allocate #snd_timer_ginfo_t container on stack */ -#define snd_timer_ginfo_alloca(ptr) do { assert(ptr); *ptr = (snd_timer_ginfo_t *) alloca(snd_timer_ginfo_sizeof()); memset(*ptr, 0, snd_timer_ginfo_sizeof()); } while (0) +#define snd_timer_ginfo_alloca(ptr) __snd_alloca(ptr, snd_timer_ginfo) int snd_timer_ginfo_malloc(snd_timer_ginfo_t **ptr); void snd_timer_ginfo_free(snd_timer_ginfo_t *obj); void snd_timer_ginfo_copy(snd_timer_ginfo_t *dst, const snd_timer_ginfo_t *src); @@ -200,7 +200,7 @@ unsigned int snd_timer_ginfo_get_clients size_t snd_timer_info_sizeof(void); /** allocate #snd_timer_info_t container on stack */ -#define snd_timer_info_alloca(ptr) do { assert(ptr); *ptr = (snd_timer_info_t *) alloca(snd_timer_info_sizeof()); memset(*ptr, 0, snd_timer_info_sizeof()); } while (0) +#define snd_timer_info_alloca(ptr) __snd_alloca(ptr, snd_timer_info) int snd_timer_info_malloc(snd_timer_info_t **ptr); void snd_timer_info_free(snd_timer_info_t *obj); void snd_timer_info_copy(snd_timer_info_t *dst, const snd_timer_info_t *src); @@ -213,7 +213,7 @@ long snd_timer_info_get_resolution(snd_t size_t snd_timer_params_sizeof(void); /** allocate #snd_timer_params_t container on stack */ -#define snd_timer_params_alloca(ptr) do { assert(ptr); *ptr = (snd_timer_params_t *) alloca(snd_timer_params_sizeof()); memset(*ptr, 0, snd_timer_params_sizeof()); } while (0) +#define snd_timer_params_alloca(ptr) __snd_alloca(ptr, snd_timer_params) int snd_timer_params_malloc(snd_timer_params_t **ptr); void snd_timer_params_free(snd_timer_params_t *obj); void snd_timer_params_copy(snd_timer_params_t *dst, const snd_timer_params_t *src); @@ -233,7 +233,7 @@ unsigned int snd_timer_params_get_filter size_t snd_timer_status_sizeof(void); /** allocate #snd_timer_status_t container on stack */ -#define snd_timer_status_alloca(ptr) do { assert(ptr); *ptr = (snd_timer_status_t *) alloca(snd_timer_status_sizeof()); memset(*ptr, 0, snd_timer_status_sizeof()); } while (0) +#define snd_timer_status_alloca(ptr) __snd_alloca(ptr, snd_timer_status) int snd_timer_status_malloc(snd_timer_status_t **ptr); void snd_timer_status_free(snd_timer_status_t *obj); void snd_timer_status_copy(snd_timer_status_t *dst, const snd_timer_status_t *src); diff -r 9e2f117f24b9 src/Versions.in --- a/src/Versions.in Mon Oct 15 10:36:46 2007 +0200 +++ b/src/Versions.in Fri Oct 26 02:01:39 2007 +0200 @@ -296,3 +296,14 @@ ALSA_1.0.14 { @SYMBOL_PREFIX@snd_device_name_free_hint; @SYMBOL_PREFIX@snd_device_name_get_hint; } ALSA_1.0.12; + +ALSA_1.0.16 { + global: + @SYMBOL_PREFIX@snd_tlv_parse_dB_info; + @SYMBOL_PREFIX@snd_tlv_get_dB_range; + @SYMBOL_PREFIX@snd_tlv_convert_to_dB; + @SYMBOL_PREFIX@snd_tlv_convert_from_dB; + @SYMBOL_PREFIX@snd_ctl_get_dB_range; + @SYMBOL_PREFIX@snd_ctl_convert_to_dB; + @SYMBOL_PREFIX@snd_ctl_convert_from_dB; +} ALSA_1.0.14; diff -r 9e2f117f24b9 src/control/Makefile.am --- a/src/control/Makefile.am Mon Oct 15 10:36:46 2007 +0200 +++ b/src/control/Makefile.am Fri Oct 26 02:01:39 2007 +0200 @@ -1,6 +1,6 @@ EXTRA_LTLIBRARIES = libcontrol.la EXTRA_LTLIBRARIES = libcontrol.la -libcontrol_la_SOURCES = cards.c namehint.c hcontrol.c \ +libcontrol_la_SOURCES = cards.c tlv.c namehint.c hcontrol.c \ control.c control_hw.c setup.c control_symbols.c if BUILD_CTL_PLUGIN_SHM libcontrol_la_SOURCES += control_shm.c diff -r 9e2f117f24b9 src/control/tlv.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/control/tlv.c Fri Oct 26 02:01:39 2007 +0200 @@ -0,0 +1,429 @@ +/** + * \file control/tlv.c + * \brief dB conversion functions from control TLV information + * \author Takashi Iwai + * \date 2007 + */ +/* + * Control Interface - dB conversion functions from control TLV information + * + * Copyright (c) 2007 Takashi Iwai + * + * + * This library is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#include +#include +#include +#include +#ifndef HAVE_SOFT_FLOAT +#include +#endif +#include "control_local.h" + +#ifndef DOC_HIDDEN +/* convert to index of integer array */ +#define int_index(size) (((size) + sizeof(int) - 1) / sizeof(int)) +/* max size of a TLV entry for dB information (including compound one) */ +#define MAX_TLV_RANGE_SIZE 256 +#endif + +/** + * \brief Parse TLV stream and retrieve dB information + * \param tlv the TLV source + * \param tlv_size the byte size of TLV source + * \param db_tlvp the pointer stored the dB TLV information + * \return the byte size of dB TLV information if found in the given + * TLV source, or a negative error code. + * + * This function parses the given TLV source and stores the TLV start + * point if the TLV information regarding dB conversion is found. + * The stored TLV pointer can be passed to the convesion functions + * #snd_tlv_convert_to_dB(), #snd_tlv_convert_from_dB() and + * #snd_tlv_get_dB_range(). + */ +int snd_tlv_parse_dB_info(unsigned int *tlv, + unsigned int tlv_size, + unsigned int **db_tlvp) +{ + unsigned int type; + unsigned int size; + int err; + + *db_tlvp = NULL; + type = tlv[0]; + size = tlv[1]; + tlv_size -= 2 * sizeof(int); + if (size > tlv_size) { + SNDERR("TLV size error"); + return -EINVAL; + } + switch (type) { + case SND_CTL_TLVT_CONTAINER: + size = int_index(size) * sizeof(int); + tlv += 2; + while (size > 0) { + unsigned int len; + err = snd_tlv_parse_dB_info(tlv, size, db_tlvp); + if (err < 0) + return err; /* error */ + if (err > 0) + return err; /* found */ + len = int_index(tlv[1]) + 2; + size -= len * sizeof(int); + tlv += len; + } + break; + case SND_CTL_TLVT_DB_SCALE: +#ifndef HAVE_SOFT_FLOAT + case SND_CTL_TLVT_DB_LINEAR: +#endif + case SND_CTL_TLVT_DB_RANGE: { + unsigned int minsize; + if (type == SND_CTL_TLVT_DB_RANGE) + minsize = 4 * sizeof(int); + else + minsize = 2 * sizeof(int); + if (size < minsize) { + SNDERR("Invalid dB_scale TLV size"); + return -EINVAL; + } + if (size > MAX_TLV_RANGE_SIZE) { + SNDERR("Too big dB_scale TLV size: %d", size); + return -EINVAL; + } + *db_tlvp = tlv; + return size + sizeof(int) * 2; + } + default: + break; + } + return -EINVAL; /* not found */ +} + +/** + * \brief Get the dB min/max values + * \param tlv the TLV source returned by #snd_tlv_parse_dB_info() + * \param rangemin the minimum value of the raw volume + * \param rangemax the maximum value of the raw volume + * \param min the pointer to store the minimum dB value (in 0.01dB unit) + * \param max the pointer to store the maximum dB value (in 0.01dB unit) + * \return 0 if successful, or a negative error code + */ +int snd_tlv_get_dB_range(unsigned int *tlv, long rangemin, long rangemax, + long *min, long *max) +{ + int err; + + switch (tlv[0]) { + case SND_CTL_TLVT_DB_RANGE: { + unsigned int pos, len; + len = int_index(tlv[1]); + if (len > MAX_TLV_RANGE_SIZE) + return -EINVAL; + pos = 2; + while (pos + 4 <= len) { + long rmin, rmax; + rangemin = (int)tlv[pos]; + rangemax = (int)tlv[pos + 1]; + err = snd_tlv_get_dB_range(tlv + pos + 2, + rangemin, rangemax, + &rmin, &rmax); + if (err < 0) + return err; + if (pos > 2) { + if (rmin < *min) + *min = rmin; + if (rmax > *max) + *max = rmax; + } else { + *min = rmin; + *max = rmax; + } + pos += int_index(tlv[pos + 3]) + 4; + } + return 0; + } + case SND_CTL_TLVT_DB_SCALE: { + int step; + *min = (int)tlv[2]; + step = (tlv[3] & 0xffff); + *max = *min + (long)(step * (rangemax - rangemin)); + return 0; + } + case SND_CTL_TLVT_DB_LINEAR: + *min = (int)tlv[2]; + *max = (int)tlv[3]; + return 0; + } + return -EINVAL; +} + +/** + * \brief Convert the given raw volume value to a dB gain + * \param tlv the TLV source returned by #snd_tlv_parse_dB_info() + * \param rangemin the minimum value of the raw volume + * \param rangemax the maximum value of the raw volume + * \param volume the raw volume value to convert + * \param db_gain the dB gain (in 0.01dB unit) + * \return 0 if successful, or a negative error code + */ +int snd_tlv_convert_to_dB(unsigned int *tlv, long rangemin, long rangemax, + long volume, long *db_gain) +{ + switch (tlv[0]) { + case SND_CTL_TLVT_DB_RANGE: { + unsigned int pos, len; + len = int_index(tlv[1]); + if (len > MAX_TLV_RANGE_SIZE) + return -EINVAL; + pos = 2; + while (pos + 4 <= len) { + rangemin = (int)tlv[pos]; + rangemax = (int)tlv[pos + 1]; + if (volume >= rangemin && volume <= rangemax) + return snd_tlv_convert_to_dB(tlv + pos + 2, + rangemin, rangemax, + volume, db_gain); + pos += int_index(tlv[pos + 3]) + 4; + } + return -EINVAL; + } + case SND_CTL_TLVT_DB_SCALE: { + int min, step, mute; + min = tlv[2]; + step = (tlv[3] & 0xffff); + mute = (tlv[3] >> 16) & 1; + if (mute && volume == rangemin) + *db_gain = SND_CTL_TLV_DB_GAIN_MUTE; + else + *db_gain = (volume - rangemin) * step + min; + return 0; + } +#ifndef HAVE_SOFT_FLOAT + case SND_CTL_TLVT_DB_LINEAR: { + int mindb = tlv[2]; + int maxdb = tlv[3]; + if (volume <= rangemin || rangemax <= rangemin) + *db_gain = mindb; + else if (volume >= rangemax) + *db_gain = maxdb; + else { + double val = (double)(volume - rangemin) / + (double)(rangemax - rangemin); + if (mindb <= SND_CTL_TLV_DB_GAIN_MUTE) + *db_gain = (long)(100.0 * 20.0 * log10(val)) + + maxdb; + else { + /* FIXME: precalculate and cache these values */ + double lmin = pow(10.0, mindb/2000.0); + double lmax = pow(10.0, maxdb/2000.0); + val = (lmax - lmin) * val + lmin; + *db_gain = (long)(100.0 * 20.0 * log10(val)); + } + } + return 0; + } +#endif + } + return -EINVAL; +} + +/** + * \brief Convert from dB gain to the corresponding raw value + * \param tlv the TLV source returned by #snd_tlv_parse_dB_info() + * \param rangemin the minimum value of the raw volume + * \param rangemax the maximum value of the raw volume + * \param db_gain the dB gain to convert (in 0.01dB unit) + * \param value the pointer to store the converted raw volume value + * \param xdir the direction for round-up. The value is round up + * when this is positive. + * \return 0 if successful, or a negative error code + */ +int snd_tlv_convert_from_dB(unsigned int *tlv, long rangemin, long rangemax, + long db_gain, long *value, int xdir) +{ + switch (tlv[0]) { + case SND_CTL_TLVT_DB_RANGE: { + unsigned int pos, len; + len = int_index(tlv[1]); + if (len > MAX_TLV_RANGE_SIZE) + return -EINVAL; + pos = 2; + while (pos + 4 <= len) { + long dbmin, dbmax; + rangemin = (int)tlv[pos]; + rangemax = (int)tlv[pos + 1]; + if (!snd_tlv_get_dB_range(tlv + pos + 2, + rangemin, rangemax, + &dbmin, &dbmax) && + db_gain >= dbmin && db_gain <= dbmax) + return snd_tlv_convert_from_dB(tlv + pos + 2, + rangemin, rangemax, + db_gain, value, xdir); + pos += int_index(tlv[pos + 3]) + 4; + } + return -EINVAL; + } + case SND_CTL_TLVT_DB_SCALE: { + int min, step, max; + min = tlv[2]; + step = (tlv[3] & 0xffff); + max = min + (int)(step * (rangemax - rangemin)); + if (db_gain <= min) + *value = rangemin; + else if (db_gain >= max) + *value = rangemax; + else { + long v = (db_gain - min) * (rangemax - rangemin); + if (xdir > 0) + v += (max - min) - 1; + v = v / (max - min) + rangemin; + *value = v; + } + return 0; + } +#ifndef HAVE_SOFT_FLOAT + case SND_CTL_TLVT_DB_LINEAR: { + int min, max; + min = tlv[2]; + max = tlv[3]; + if (db_gain <= min) + *value = rangemin; + else if (db_gain >= max) + *value = rangemax; + else { + /* FIXME: precalculate and cache vmin and vmax */ + double vmin, vmax, v; + vmin = (min <= SND_CTL_TLV_DB_GAIN_MUTE) ? 0.0 : + pow(10.0, (double)min / 2000.0); + vmax = !max ? 1.0 : pow(10.0, (double)max / 2000.0); + v = pow(10.0, (double)db_gain / 2000.0); + v = (v - vmin) * (rangemax - rangemin) / (vmax - vmin); + if (xdir > 0) + v = ceil(v); + *value = (long)v + rangemin; + } + return 0; + } +#endif + default: + break; + } + return -EINVAL; +} + +#ifndef DOC_HIDDEN +#define TEMP_TLV_SIZE 4096 +struct tlv_info { + long minval, maxval; + unsigned int *tlv; + unsigned int buf[TEMP_TLV_SIZE]; +}; +#endif + +static int get_tlv_info(snd_ctl_t *ctl, const snd_ctl_elem_id_t *id, + struct tlv_info *rec) +{ + snd_ctl_elem_info_t *info; + int err; + + snd_ctl_elem_info_alloca(&info); + snd_ctl_elem_info_set_id(info, id); + err = snd_ctl_elem_info(ctl, info); + if (err < 0) + return err; + if (!snd_ctl_elem_info_is_tlv_readable(info)) + return -EINVAL; + if (snd_ctl_elem_info_get_type(info) != SND_CTL_ELEM_TYPE_INTEGER) + return -EINVAL; + rec->minval = snd_ctl_elem_info_get_min(info); + rec->maxval = snd_ctl_elem_info_get_max(info); + err = snd_ctl_elem_tlv_read(ctl, id, rec->buf, sizeof(rec->buf)); + if (err < 0) + return err; + err = snd_tlv_parse_dB_info(rec->buf, sizeof(rec->buf), &rec->tlv); + if (err < 0) + return err; + return 0; +} + +/** + * \brief Get the dB min/max values on the given control element + * \param ctl the control handler + * \param id the element id + * \param volume the raw volume value to convert + * \param min the pointer to store the minimum dB value (in 0.01dB unit) + * \param max the pointer to store the maximum dB value (in 0.01dB unit) + * \return 0 if successful, or a negative error code + */ +int snd_ctl_get_dB_range(snd_ctl_t *ctl, const snd_ctl_elem_id_t *id, + long *min, long *max) +{ + struct tlv_info info; + int err; + + err = get_tlv_info(ctl, id, &info); + if (err < 0) + return err; + return snd_tlv_get_dB_range(info.tlv, info.minval, info.maxval, + min, max); +} + +/** + * \brief Convert the volume value to dB on the given control element + * \param ctl the control handler + * \param id the element id + * \param volume the raw volume value to convert + * \param db_gain the dB gain (in 0.01dB unit) + * \return 0 if successful, or a negative error code + */ +int snd_ctl_convert_to_dB(snd_ctl_t *ctl, const snd_ctl_elem_id_t *id, + long volume, long *db_gain) +{ + struct tlv_info info; + int err; + + err = get_tlv_info(ctl, id, &info); + if (err < 0) + return err; + return snd_tlv_convert_to_dB(info.tlv, info.minval, info.maxval, + volume, db_gain); +} + +/** + * \brief Convert from dB gain to the raw volume value on the given control element + * \param ctl the control handler + * \param id the element id + * \param db_gain the dB gain to convert (in 0.01dB unit) + * \param value the pointer to store the converted raw volume value + * \param xdir the direction for round-up. The value is round up + * when this is positive. + * \return 0 if successful, or a negative error code + */ +int snd_ctl_convert_from_dB(snd_ctl_t *ctl, const snd_ctl_elem_id_t *id, + long db_gain, long *value, int xdir) +{ + struct tlv_info info; + int err; + + err = get_tlv_info(ctl, id, &info); + if (err < 0) + return err; + return snd_tlv_convert_from_dB(info.tlv, info.minval, info.maxval, + db_gain, value, xdir); +} diff -r 9e2f117f24b9 src/error.c --- a/src/error.c Mon Oct 15 10:36:46 2007 +0200 +++ b/src/error.c Fri Oct 26 02:01:39 2007 +0200 @@ -135,8 +135,11 @@ static void snd_err_msg_default(const ch fprintf(stderr, ": %s", snd_strerror(err)); putc('\n', stderr); va_end(arg); - if (! strcmp(verbose, "assert") || atoi(verbose) > 1) +#ifdef ALSA_DEBUG_ASSERT + verbose = getenv("LIBASOUND_DEBUG_ASSERT"); + if (verbose && *verbose) assert(0); +#endif } /** diff -r 9e2f117f24b9 src/mixer/simple_none.c --- a/src/mixer/simple_none.c Mon Oct 15 10:36:46 2007 +0200 +++ b/src/mixer/simple_none.c Fri Oct 26 02:01:39 2007 +0200 @@ -35,6 +35,7 @@ #include #include #include +#include #include #include #include "mixer_simple.h" @@ -1068,150 +1069,13 @@ static int get_volume_ops(snd_mixer_elem static int init_db_range(snd_hctl_elem_t *ctl, struct selem_str *rec); -/* convert to index of integer array */ -#ifndef DOC_HIDDEN -#define int_index(size) (((size) + sizeof(int) - 1) / sizeof(int)) -#endif - -/* max size of a TLV entry for dB information (including compound one) */ -#ifndef DOC_HIDDEN -#define MAX_TLV_RANGE_SIZE 256 -#endif - -/* parse TLV stream and retrieve dB information - * return 0 if successly found and stored to rec, - * return 1 if no information is found, - * or return a negative error code - */ -static int parse_db_range(struct selem_str *rec, unsigned int *tlv, - unsigned int tlv_size) -{ - unsigned int type; - unsigned int size; - int err; - - type = tlv[0]; - size = tlv[1]; - tlv_size -= 2 * sizeof(int); - if (size > tlv_size) { - SNDERR("TLV size error"); - return -EINVAL; - } - switch (type) { - case SND_CTL_TLVT_CONTAINER: - size = int_index(size) * sizeof(int); - tlv += 2; - while (size > 0) { - unsigned int len; - err = parse_db_range(rec, tlv, size); - if (err <= 0) - return err; /* error or found dB */ - len = int_index(tlv[1]) + 2; - size -= len * sizeof(int); - tlv += len; - } - break; - case SND_CTL_TLVT_DB_SCALE: -#ifndef HAVE_SOFT_FLOAT - case SND_CTL_TLVT_DB_LINEAR: -#endif - case SND_CTL_TLVT_DB_RANGE: { - unsigned int minsize; - if (type == SND_CTL_TLVT_DB_RANGE) - minsize = 4 * sizeof(int); - else - minsize = 2 * sizeof(int); - if (size < minsize) { - SNDERR("Invalid dB_scale TLV size"); - return -EINVAL; - } - if (size > MAX_TLV_RANGE_SIZE) { - SNDERR("Too big dB_scale TLV size: %d", size); - return -EINVAL; - } - rec->db_info = malloc(size + sizeof(int) * 2); - if (! rec->db_info) - return -ENOMEM; - memcpy(rec->db_info, tlv, size + sizeof(int) * 2); - return 0; - } - default: - break; - } - return -EINVAL; /* not found */ -} - -/* convert the given raw volume value to a dB gain - */ - -static int do_convert_to_dB(unsigned int *tlv, long rangemin, long rangemax, - long volume, long *db_gain) -{ - switch (tlv[0]) { - case SND_CTL_TLVT_DB_RANGE: { - unsigned int pos, len; - len = int_index(tlv[1]); - if (len > MAX_TLV_RANGE_SIZE) - return -EINVAL; - pos = 2; - while (pos + 4 <= len) { - rangemin = (int)tlv[pos]; - rangemax = (int)tlv[pos + 1]; - if (volume >= rangemin && volume <= rangemax) - return do_convert_to_dB(tlv + pos + 2, - rangemin, rangemax, - volume, db_gain); - pos += int_index(tlv[pos + 3]) + 4; - } - return -EINVAL; - } - case SND_CTL_TLVT_DB_SCALE: { - int min, step, mute; - min = tlv[2]; - step = (tlv[3] & 0xffff); - mute = (tlv[3] >> 16) & 1; - if (mute && volume == rangemin) - *db_gain = SND_CTL_TLV_DB_GAIN_MUTE; - else - *db_gain = (volume - rangemin) * step + min; - return 0; - } -#ifndef HAVE_SOFT_FLOAT - case SND_CTL_TLVT_DB_LINEAR: { - int mindb = tlv[2]; - int maxdb = tlv[3]; - if (volume <= rangemin || rangemax <= rangemin) - *db_gain = mindb; - else if (volume >= rangemax) - *db_gain = maxdb; - else { - double val = (double)(volume - rangemin) / - (double)(rangemax - rangemin); - if (mindb <= SND_CTL_TLV_DB_GAIN_MUTE) - *db_gain = (long)(100.0 * 20.0 * log10(val)) + - maxdb; - else { - /* FIXME: precalculate and cache these values */ - double lmin = pow(10.0, mindb/2000.0); - double lmax = pow(10.0, maxdb/2000.0); - val = (lmax - lmin) * val + lmin; - *db_gain = (long)(100.0 * 20.0 * log10(val)); - } - } - return 0; - } -#endif - } - return -EINVAL; -} - static int convert_to_dB(snd_hctl_elem_t *ctl, struct selem_str *rec, long volume, long *db_gain) { if (init_db_range(ctl, rec) < 0) return -EINVAL; - return do_convert_to_dB(rec->db_info, rec->min, rec->max, - volume, db_gain); + return snd_tlv_convert_to_dB(rec->db_info, rec->min, rec->max, + volume, db_gain); } /* initialize dB range information, reading TLV via hcontrol @@ -1221,6 +1085,8 @@ static int init_db_range(snd_hctl_elem_t snd_ctl_elem_info_t *info; unsigned int *tlv = NULL; const unsigned int tlv_size = 4096; + unsigned int *dbrec; + int db_size; if (rec->db_init_error) return -EINVAL; @@ -1237,8 +1103,13 @@ static int init_db_range(snd_hctl_elem_t return -ENOMEM; if (snd_hctl_elem_tlv_read(ctl, tlv, tlv_size) < 0) goto error; - if (parse_db_range(rec, tlv, tlv_size) < 0) + db_size = snd_tlv_parse_dB_info(tlv, tlv_size, &dbrec); + if (db_size < 0) goto error; + rec->db_info = malloc(db_size); + if (!rec->db_info) + goto error; + memcpy(rec->db_info, dbrec, db_size); free(tlv); rec->db_initialized = 1; return 0; @@ -1269,59 +1140,13 @@ static selem_ctl_t *get_selem_ctl(selem_ return c; } -/* Get the dB min/max values - */ -static int do_get_dB_range(unsigned int *tlv, long rangemin, long rangemax, - long *min, long *max) -{ - switch (tlv[0]) { - case SND_CTL_TLVT_DB_RANGE: { - unsigned int pos, len; - len = int_index(tlv[1]); - if (len > MAX_TLV_RANGE_SIZE) - return -EINVAL; - pos = 2; - while (pos + 4 <= len) { - long rmin, rmax; - rangemin = (int)tlv[pos]; - rangemax = (int)tlv[pos + 1]; - do_get_dB_range(tlv + pos + 2, rangemin, rangemax, - &rmin, &rmax); - if (pos > 2) { - if (rmin < *min) - *min = rmin; - if (rmax > *max) - *max = rmax; - } else { - *min = rmin; - *max = rmax; - } - pos += int_index(tlv[pos + 3]) + 4; - } - return 0; - } - case SND_CTL_TLVT_DB_SCALE: { - int step; - *min = (int)tlv[2]; - step = (tlv[3] & 0xffff); - *max = *min + (long)(step * (rangemax - rangemin)); - return 0; - } - case SND_CTL_TLVT_DB_LINEAR: - *min = (int)tlv[2]; - *max = (int)tlv[3]; - return 0; - } - return -EINVAL; -} - static int get_dB_range(snd_hctl_elem_t *ctl, struct selem_str *rec, long *min, long *max) { if (init_db_range(ctl, rec) < 0) return -EINVAL; - return do_get_dB_range(rec->db_info, rec->min, rec->max, min, max); + return snd_tlv_get_dB_range(rec->db_info, rec->min, rec->max, min, max); } static int get_dB_range_ops(snd_mixer_elem_t *elem, int dir, @@ -1336,89 +1161,14 @@ static int get_dB_range_ops(snd_mixer_el return get_dB_range(c->elem, &s->str[dir], min, max); } -/* Convert from dB gain to the corresponding raw value. - * The value is round up when xdir > 0. - */ -static int do_convert_from_dB(unsigned int *tlv, long rangemin, long rangemax, - long db_gain, long *value, int xdir) -{ - switch (tlv[0]) { - case SND_CTL_TLVT_DB_RANGE: { - unsigned int pos, len; - len = int_index(tlv[1]); - if (len > MAX_TLV_RANGE_SIZE) - return -EINVAL; - pos = 2; - while (pos + 4 <= len) { - long dbmin, dbmax; - rangemin = (int)tlv[pos]; - rangemax = (int)tlv[pos + 1]; - if (! do_get_dB_range(tlv + pos + 2, rangemin, rangemax, - &dbmin, &dbmax) && - db_gain >= dbmin && db_gain <= dbmax) - return do_convert_from_dB(tlv + pos + 2, - rangemin, rangemax, - db_gain, value, xdir); - pos += int_index(tlv[pos + 3]) + 4; - } - return -EINVAL; - } - case SND_CTL_TLVT_DB_SCALE: { - int min, step, max; - min = tlv[2]; - step = (tlv[3] & 0xffff); - max = min + (int)(step * (rangemax - rangemin)); - if (db_gain <= min) - *value = rangemin; - else if (db_gain >= max) - *value = rangemax; - else { - long v = (db_gain - min) * (rangemax - rangemin); - if (xdir > 0) - v += (max - min) - 1; - v = v / (max - min) + rangemin; - *value = v; - } - return 0; - } -#ifndef HAVE_SOFT_FLOAT - case SND_CTL_TLVT_DB_LINEAR: { - int min, max; - min = tlv[2]; - max = tlv[3]; - if (db_gain <= min) - *value = rangemin; - else if (db_gain >= max) - *value = rangemax; - else { - /* FIXME: precalculate and cache vmin and vmax */ - double vmin, vmax, v; - vmin = (min <= SND_CTL_TLV_DB_GAIN_MUTE) ? 0.0 : - pow(10.0, (double)min / 2000.0); - vmax = !max ? 1.0 : pow(10.0, (double)max / 2000.0); - v = pow(10.0, (double)db_gain / 2000.0); - v = (v - vmin) * (rangemax - rangemin) / (vmax - vmin); - if (xdir > 0) - v = ceil(v); - *value = (long)v + rangemin; - } - return 0; - } -#endif - default: - break; - } - return -EINVAL; -} - static int convert_from_dB(snd_hctl_elem_t *ctl, struct selem_str *rec, long db_gain, long *value, int xdir) { if (init_db_range(ctl, rec) < 0) return -EINVAL; - return do_convert_from_dB(rec->db_info, rec->min, rec->max, - db_gain, value, xdir); + return snd_tlv_convert_from_dB(rec->db_info, rec->min, rec->max, + db_gain, value, xdir); } static int get_dB_ops(snd_mixer_elem_t *elem, diff -r 9e2f117f24b9 src/pcm/pcm_dmix.c --- a/src/pcm/pcm_dmix.c Mon Oct 15 10:36:46 2007 +0200 +++ b/src/pcm/pcm_dmix.c Fri Oct 26 02:01:39 2007 +0200 @@ -652,9 +652,10 @@ static int snd_pcm_dmix_close(snd_pcm_t if (dmix->client) snd_pcm_direct_client_discard(dmix); shm_sum_discard(dmix); - if (snd_pcm_direct_shm_discard(dmix)) - snd_pcm_direct_semaphore_discard(dmix); - else + if (snd_pcm_direct_shm_discard(dmix)) { + if (snd_pcm_direct_semaphore_discard(dmix)) + snd_pcm_direct_semaphore_up(dmix, DIRECT_IPC_SEM_CLIENT); + } else snd_pcm_direct_semaphore_up(dmix, DIRECT_IPC_SEM_CLIENT); free(dmix->bindings); pcm->private_data = NULL; diff -r 9e2f117f24b9 src/pcm/pcm_params.c --- a/src/pcm/pcm_params.c Mon Oct 15 10:36:46 2007 +0200 +++ b/src/pcm/pcm_params.c Fri Oct 26 02:01:39 2007 +0200 @@ -78,31 +78,14 @@ static inline int hw_is_interval(snd_pcm var <= SND_PCM_HW_PARAM_LAST_INTERVAL; } -static inline snd_mask_t *hw_param_mask(snd_pcm_hw_params_t *params, - snd_pcm_hw_param_t var) -{ - assert(hw_is_mask(var)); - return (snd_mask_t*)¶ms->masks[var - SND_PCM_HW_PARAM_FIRST_MASK]; -} +#define hw_param_mask(params,var) \ + &((params)->masks[(var) - SND_PCM_HW_PARAM_FIRST_MASK]) -static inline snd_interval_t *hw_param_interval(snd_pcm_hw_params_t *params, - snd_pcm_hw_param_t var) -{ - assert(hw_is_interval(var)); - return ¶ms->intervals[var - SND_PCM_HW_PARAM_FIRST_INTERVAL]; -} +#define hw_param_interval(params,var) \ + &((params)->intervals[(var) - SND_PCM_HW_PARAM_FIRST_INTERVAL]) -static inline const snd_mask_t *hw_param_mask_c(const snd_pcm_hw_params_t *params, - snd_pcm_hw_param_t var) -{ - return (const snd_mask_t *)hw_param_mask((snd_pcm_hw_params_t*) params, var); -} - -static inline const snd_interval_t *hw_param_interval_c(const snd_pcm_hw_params_t *params, - snd_pcm_hw_param_t var) -{ - return (const snd_interval_t *)hw_param_interval((snd_pcm_hw_params_t*) params, var); -} +#define hw_param_mask_c hw_param_mask +#define hw_param_interval_c hw_param_interval static void _snd_pcm_hw_param_any(snd_pcm_hw_params_t *params, snd_pcm_hw_param_t var) {