From 5d38699f39db298e8d324d4fb96c4ba09c5a9155 Mon Sep 17 00:00:00 2001 From: joq Date: Mon, 3 Jan 2005 00:15:31 +0000 Subject: [PATCH] [0.99.44] ALSA driver bug fixes: + format search problem introduced yesterday + bug:00031 "crash when using more than 32 channels" git-svn-id: svn+ssh://jackaudio.org/trunk/jack@864 0c269be4-1314-0410-8aa9-9f06e86f4224 --- configure.ac | 2 +- drivers/alsa/alsa_driver.c | 26 +++++---- drivers/alsa/alsa_driver.h | 67 +++++++++++++--------- jack/Makefile.am | 1 + jack/bitset.h | 112 +++++++++++++++++++++++++++++++++++++ 5 files changed, 170 insertions(+), 38 deletions(-) create mode 100644 jack/bitset.h diff --git a/configure.ac b/configure.ac index 1b5fd82..f6cad53 100644 --- a/configure.ac +++ b/configure.ac @@ -15,7 +15,7 @@ dnl changes are made dnl --- JACK_MAJOR_VERSION=0 JACK_MINOR_VERSION=99 -JACK_MICRO_VERSION=43 +JACK_MICRO_VERSION=44 dnl --- dnl HOWTO: updating the jack protocol version diff --git a/drivers/alsa/alsa_driver.c b/drivers/alsa/alsa_driver.c index 4b6e7d2..367e77c 100644 --- a/drivers/alsa/alsa_driver.c +++ b/drivers/alsa/alsa_driver.c @@ -58,6 +58,9 @@ extern void show_work_times (); static void alsa_driver_release_channel_dependent_memory (alsa_driver_t *driver) { + bitset_destroy (&driver->channels_done); + bitset_destroy (&driver->channels_not_done); + if (driver->playback_addr) { free (driver->playback_addr); driver->playback_addr = 0; @@ -340,7 +343,8 @@ alsa_driver_configure_stream (alsa_driver_t *driver, char *device_name, snd_pcm_hw_params_t *hw_params, snd_pcm_sw_params_t *sw_params, unsigned int *nperiodsp, - unsigned long *nchns,unsigned long sample_width) + unsigned long *nchns, + unsigned long sample_width) { int err, format; unsigned int frame_rate; @@ -387,9 +391,9 @@ alsa_driver_configure_stream (alsa_driver_t *driver, char *device_name, if ((err = snd_pcm_hw_params_set_format ( handle, hw_params, formats[format].format)) < 0) { int failed_format = format; - if (sample_width == (4 - ? format++ < NOFORMATS - 1 - : format-- > 0)) { + if ((sample_width == 4 + ? format++ < NOFORMATS - 1 + : format-- > 0)) { jack_error ("Couldn't open %s for %s samples" " trying %s instead", device_name, formats[failed_format].Name, @@ -806,12 +810,10 @@ alsa_driver_set_parameters (alsa_driver_t *driver, channels require action on every cycle. any bits that are not set after the engine's process() call indicate channels that potentially need to be silenced. - - XXX this is limited to channels. Use a bitset - type instead. */ - driver->channel_done_bits = 0; + bitset_create (&driver->channels_done, driver->max_nchannels); + bitset_create (&driver->channels_not_done, driver->max_nchannels); if (driver->playback_handle) { driver->playback_addr = (char **) @@ -827,7 +829,7 @@ alsa_driver_set_parameters (alsa_driver_t *driver, } for (chn = 0; chn < driver->playback_nchannels; chn++) { - driver->channel_done_bits |= (1<channels_done, chn); } driver->dither_state = (dither_state_t *) @@ -1148,7 +1150,7 @@ alsa_driver_silence_untouched_channels (alsa_driver_t *driver, driver->frames_per_cycle * driver->playback_nperiods; for (chn = 0; chn < driver->playback_nchannels; chn++) { - if ((driver->channels_not_done & (1<channels_not_done, chn)) { if (driver->silent[chn] < buffer_frames) { alsa_driver_silence_on_channel_no_mark ( driver, chn, nframes); @@ -1414,7 +1416,7 @@ alsa_driver_wait (alsa_driver_t *driver, int extra_fd, int *status, float /* mark all channels not done for now. read/write will change this */ - driver->channels_not_done = driver->channel_done_bits; + bitset_copy (driver->channels_not_done, driver->channels_done); /* constrain the available count to the nearest (round down) number of periods. @@ -1622,7 +1624,7 @@ alsa_driver_write (alsa_driver_t* driver, jack_nframes_t nframes) buf + nwritten, contiguous); } - if (driver->channels_not_done) { + if (!bitset_empty (driver->channels_not_done)) { alsa_driver_silence_untouched_channels (driver, contiguous); } diff --git a/drivers/alsa/alsa_driver.h b/drivers/alsa/alsa_driver.h index 493394d..70b5f12 100644 --- a/drivers/alsa/alsa_driver.h +++ b/drivers/alsa/alsa_driver.h @@ -22,6 +22,7 @@ #define __jack_alsa_driver_h__ #include +#include #if __BYTE_ORDER == __LITTLE_ENDIAN #define SND_PCM_FORMAT_S24_3 SND_PCM_FORMAT_S24_3LE @@ -82,8 +83,8 @@ typedef struct _alsa_driver { char *alsa_name_playback; char *alsa_name_capture; char *alsa_driver; - unsigned long channels_not_done; - unsigned long channel_done_bits; + bitset_t channels_not_done; + bitset_t channels_done; snd_pcm_format_t playback_sample_format; snd_pcm_format_t capture_sample_format; float max_sample_val; @@ -139,12 +140,15 @@ typedef struct _alsa_driver { } alsa_driver_t; -static __inline__ void alsa_driver_mark_channel_done (alsa_driver_t *driver, channel_t chn) { - driver->channels_not_done &= ~(1<channels_not_done, chn); driver->silent[chn] = 0; } -static __inline__ void alsa_driver_silence_on_channel (alsa_driver_t *driver, channel_t chn, jack_nframes_t nframes) { +static inline void +alsa_driver_silence_on_channel (alsa_driver_t *driver, channel_t chn, + jack_nframes_t nframes) { if (driver->playback_interleaved) { memset_interleave (driver->playback_addr[chn], @@ -152,12 +156,15 @@ static __inline__ void alsa_driver_silence_on_channel (alsa_driver_t *driver, ch driver->interleave_unit, driver->playback_interleave_skip); } else { - memset (driver->playback_addr[chn], 0, nframes * driver->playback_sample_bytes); + memset (driver->playback_addr[chn], 0, + nframes * driver->playback_sample_bytes); } alsa_driver_mark_channel_done (driver,chn); } -static __inline__ void alsa_driver_silence_on_channel_no_mark (alsa_driver_t *driver, channel_t chn, jack_nframes_t nframes) { +static inline void +alsa_driver_silence_on_channel_no_mark (alsa_driver_t *driver, channel_t chn, + jack_nframes_t nframes) { if (driver->playback_interleaved) { memset_interleave (driver->playback_addr[chn], @@ -165,13 +172,16 @@ static __inline__ void alsa_driver_silence_on_channel_no_mark (alsa_driver_t *dr driver->interleave_unit, driver->playback_interleave_skip); } else { - memset (driver->playback_addr[chn], 0, nframes * driver->playback_sample_bytes); + memset (driver->playback_addr[chn], 0, + nframes * driver->playback_sample_bytes); } } -static __inline__ void alsa_driver_read_from_channel (alsa_driver_t *driver, - channel_t channel, jack_default_audio_sample_t *buf, - jack_nframes_t nsamples) +static inline void +alsa_driver_read_from_channel (alsa_driver_t *driver, + channel_t channel, + jack_default_audio_sample_t *buf, + jack_nframes_t nsamples) { driver->read_via_copy (buf, driver->capture_addr[channel], @@ -179,10 +189,11 @@ static __inline__ void alsa_driver_read_from_channel (alsa_driver_t *driver, driver->capture_interleave_skip); } -static __inline__ void alsa_driver_write_to_channel (alsa_driver_t *driver, - channel_t channel, - jack_default_audio_sample_t *buf, - jack_nframes_t nsamples) +static inline void +alsa_driver_write_to_channel (alsa_driver_t *driver, + channel_t channel, + jack_default_audio_sample_t *buf, + jack_nframes_t nsamples) { driver->write_via_copy (driver->playback_addr[channel], buf, @@ -192,10 +203,11 @@ static __inline__ void alsa_driver_write_to_channel (alsa_driver_t *driver, alsa_driver_mark_channel_done (driver, channel); } -static __inline__ void alsa_driver_copy_channel (alsa_driver_t *driver, - channel_t input_channel, - channel_t output_channel, - jack_nframes_t nsamples) { +static inline void +alsa_driver_copy_channel (alsa_driver_t *driver, + channel_t input_channel, + channel_t output_channel, + jack_nframes_t nsamples) { driver->channel_copy (driver->playback_addr[output_channel], driver->capture_addr[input_channel], @@ -205,11 +217,16 @@ static __inline__ void alsa_driver_copy_channel (alsa_driver_t *driver, alsa_driver_mark_channel_done (driver, output_channel); } -void alsa_driver_silence_untouched_channels (alsa_driver_t *driver, jack_nframes_t nframes); -void alsa_driver_set_clock_sync_status (alsa_driver_t *driver, channel_t chn, ClockSyncStatus status); -int alsa_driver_listen_for_clock_sync_status (alsa_driver_t *, ClockSyncListenerFunction, void *arg); -int alsa_driver_stop_listen_for_clock_sync_status (alsa_driver_t *, unsigned int); -void alsa_driver_clock_sync_notify (alsa_driver_t *, channel_t chn, ClockSyncStatus); - +void alsa_driver_silence_untouched_channels (alsa_driver_t *driver, + jack_nframes_t nframes); +void alsa_driver_set_clock_sync_status (alsa_driver_t *driver, channel_t chn, + ClockSyncStatus status); +int alsa_driver_listen_for_clock_sync_status (alsa_driver_t *, + ClockSyncListenerFunction, + void *arg); +int alsa_driver_stop_listen_for_clock_sync_status (alsa_driver_t *, + unsigned int); +void alsa_driver_clock_sync_notify (alsa_driver_t *, channel_t chn, + ClockSyncStatus); #endif /* __jack_alsa_driver_h__ */ diff --git a/jack/Makefile.am b/jack/Makefile.am index 587c051..48d9cd9 100644 --- a/jack/Makefile.am +++ b/jack/Makefile.am @@ -14,6 +14,7 @@ libjackinclude_HEADERS = \ noinst_HEADERS = \ atomicity.h \ + bitset.h \ driver.h \ driver_interface.h \ driver_parse.h \ diff --git a/jack/bitset.h b/jack/bitset.h new file mode 100644 index 0000000..8e78a26 --- /dev/null +++ b/jack/bitset.h @@ -0,0 +1,112 @@ +/* + * bitset.h -- some simple bit vector set operations. + * + * This is useful for sets of small non-negative integers. There are + * some obvious set operations that are not implemented because I + * don't need them right now. + * + * These functions represent sets as arrays of unsigned 32-bit + * integers allocated on the heap. The first entry contains the set + * cardinality (number of elements allowed), followed by one or more + * words containing bit vectors. + * + * $Id$ + */ + +/* + * Copyright (C) 2005 Jack O'Quin + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 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 + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#ifndef __bitset_h__ +#define __bitset_h__ + +#include /* POSIX standard fixed-size types */ +#include /* `#define NDEBUG' to disable */ + +/* On some 64-bit machines, this implementation may be slightly + * inefficient, depending on how compilers allocate space for + * uint32_t. For the set sizes I currently need, this is acceptable. + * It should not be hard to pack the bits better, if that becomes + * worthwhile. + */ +typedef uint32_t _bitset_word_t; +typedef _bitset_word_t *bitset_t; + +#define WORD_SIZE(cardinality) (1+((cardinality)+31)/32) +#define BYTE_SIZE(cardinality) (WORD_SIZE(cardinality)*sizeof(_bitset_word_t)) +#define WORD_INDEX(element) (1+(element)/32) +#define BIT_INDEX(element) ((element)&037) + +static inline void +bitset_add(bitset_t set, unsigned int element) +{ + assert(element < set[0]); + set[WORD_INDEX(element)] |= (1 << BIT_INDEX(element)); +} + +static inline void +bitset_copy(bitset_t to_set, bitset_t from_set) +{ + assert(to_set[0] == from_set[0]); + memcpy(to_set, from_set, BYTE_SIZE(to_set[0])); +} + +static inline void +bitset_create(bitset_t *set, unsigned int cardinality) +{ + *set = (bitset_t) calloc(WORD_SIZE(cardinality), + sizeof(_bitset_word_t)); + assert(*set); + *set[0] = cardinality; +} + +static inline void +bitset_destroy(bitset_t *set) +{ + if (*set) { + free(*set); + *set = (bitset_t) 0; + } +} + +static inline int +bitset_empty(bitset_t set) +{ + int i; + _bitset_word_t result = 0; + int nwords = WORD_SIZE(set[0]); + for (i = 1; i < nwords; i++) { + result |= set[i]; + } + return (result == 0); +} + +static inline int +bitset_contains(bitset_t set, unsigned int element) +{ + assert(element < set[0]); + return (0 != (set[WORD_INDEX(element)] & (1<