diff --git a/alsa-utils-git-fixes.diff b/alsa-utils-git-fixes.diff new file mode 100644 index 0000000..53ad2ba --- /dev/null +++ b/alsa-utils-git-fixes.diff @@ -0,0 +1,1430 @@ +diff --git a/alsactl/alsactl.c b/alsactl/alsactl.c +index 02e082f..3b5dfda 100644 +--- a/alsactl/alsactl.c ++++ b/alsactl/alsactl.c +@@ -189,5 +189,5 @@ int main(int argc, char *argv[]) + } + + snd_config_update_free_global(); +- return res < 0 ? res : 0; ++ return res < 0 ? -res : 0; + } +diff --git a/alsactl/alsactl.h b/alsactl/alsactl.h +index 89ad295..be90efb 100644 +--- a/alsactl/alsactl.h ++++ b/alsactl/alsactl.h +@@ -34,16 +34,16 @@ extern char *statefile; + + #if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 95) + #define cerror(cond, ...) do {\ +- if (cond) { \ +- fprintf(stderr, "%s: %s:%d: ", command, __FUNCTION__, __LINE__); \ ++ if (cond || debugflag) { \ ++ fprintf(stderr, "%s%s: %s:%d: ", debugflag ? "WARNING: " : "", command, __FUNCTION__, __LINE__); \ + fprintf(stderr, __VA_ARGS__); \ + putc('\n', stderr); \ + } \ + } while (0) + #else + #define cerror(cond, args...) do {\ +- if (cond) { \ +- fprintf(stderr, "%s: %s:%d: ", command, __FUNCTION__, __LINE__); \ ++ if (cond || debugflag) { \ ++ fprintf(stderr, "%s%s: %s:%d: ", debugflag ? "WARNING: " : "", command, __FUNCTION__, __LINE__); \ + fprintf(stderr, ##args); \ + putc('\n', stderr); \ + } \ +@@ -78,7 +78,7 @@ int generate_names(const char *cfgfile); + int file_map(const char *filename, char **buf, size_t *bufsize); + void file_unmap(void *buf, size_t bufsize); + size_t line_width(const char *buf, size_t bufsize, size_t pos); +-void initfailed(int cardnumber, const char *reason); ++void initfailed(int cardnumber, const char *reason, int exitcode); + + static inline int hextodigit(int c) + { +diff --git a/alsactl/state.c b/alsactl/state.c +index 635a999..e70c6f9 100644 +--- a/alsactl/state.c ++++ b/alsactl/state.c +@@ -1117,7 +1117,6 @@ static int restore_config_value2(snd_ctl_t *handle, snd_ctl_elem_info_t *info, + } + snd_ctl_elem_value_set_byte(ctl, idx, val); + return 1; +- break; + default: + break; + } +@@ -1404,6 +1403,7 @@ static int set_controls(int card, snd_config_t *top, int doit) + snd_ctl_card_info_alloca(&info); + + sprintf(name, "hw:%d", card); ++ dbg("device='%s', doit=%i", name, doit); + err = snd_ctl_open(&handle, name, 0); + if (err < 0) { + error("snd_ctl_open error: %s", snd_strerror(err)); +@@ -1415,6 +1415,7 @@ static int set_controls(int card, snd_config_t *top, int doit) + goto _close; + } + id = snd_ctl_card_info_get_id(info); ++ dbg("card-info-id: '%s'", id); + err = snd_config_searchv(top, &control, "state", id, "control", 0); + if (err < 0) { + if (force_restore) { +@@ -1440,24 +1441,25 @@ static int set_controls(int card, snd_config_t *top, int doit) + goto _close; + } + ++ dbg("maxnumid=%i", maxnumid); + /* check if we have additional controls in driver */ + /* in this case we should go through init procedure */ + if (!doit && maxnumid >= 0) { +- snd_ctl_elem_id_t *id; + snd_ctl_elem_info_t *info; +- snd_ctl_elem_id_alloca(&id); + snd_ctl_elem_info_alloca(&info); + snd_ctl_elem_info_set_numid(info, maxnumid+1); + if (snd_ctl_elem_info(handle, info) == 0) { + /* not very informative */ + /* but value is used for check only */ + err = -EAGAIN; ++ dbg("more controls than maxnumid?"); + goto _close; + } + } + + _close: + snd_ctl_close(handle); ++ dbg("result code: %i", err); + return err; + } + +@@ -1582,9 +1584,9 @@ int load_state(const char *file, const char *initfile, const char *cardname, + err = init(initfile, cardname1); + if (err < 0) { + finalerr = err; +- initfailed(card, "init"); ++ initfailed(card, "init", err); + } +- initfailed(card, "restore"); ++ initfailed(card, "restore", -ENOENT); + } + if (first) + finalerr = 0; /* no cards, no error code */ +@@ -1617,14 +1619,14 @@ int load_state(const char *file, const char *initfile, const char *cardname, + sprintf(cardname1, "%i", card); + err = init(initfile, cardname1); + if (err < 0) { +- initfailed(card, "init"); ++ initfailed(card, "init", err); + finalerr = err; + } + } + if ((err = set_controls(card, config, 1))) { + if (!force_restore) + finalerr = err; +- initfailed(card, "restore"); ++ initfailed(card, "restore", err); + } + } + } else { +@@ -1639,12 +1641,12 @@ int load_state(const char *file, const char *initfile, const char *cardname, + if (do_init && set_controls(cardno, config, 0)) { + err = init(initfile, cardname); + if (err < 0) { +- initfailed(cardno, "init"); +- return err; ++ initfailed(cardno, "init", err); ++ finalerr = err; + } + } + if ((err = set_controls(cardno, config, 1))) { +- initfailed(cardno, "restore"); ++ initfailed(cardno, "restore", err); + if (!force_restore) + return err; + } +diff --git a/alsactl/utils.c b/alsactl/utils.c +index ab4dbd4..a27eb6e 100644 +--- a/alsactl/utils.c ++++ b/alsactl/utils.c +@@ -79,19 +79,23 @@ size_t line_width(const char *buf, size_t bufsize, size_t pos) + return count - pos; + } + +-void initfailed(int cardnumber, const char *reason) ++void initfailed(int cardnumber, const char *reason, int exitcode) + { + int fp; + char *str; ++ char sexitcode[16]; + + if (statefile == NULL) + return; + if (snd_card_get_name(cardnumber, &str) < 0) + return; ++ sprintf(sexitcode, "%i", exitcode); + fp = open(statefile, O_WRONLY|O_CREAT|O_APPEND, 0644); + write(fp, str, strlen(str)); + write(fp, ":", 1); + write(fp, reason, strlen(reason)); ++ write(fp, ":", 1); ++ write(fp, sexitcode, strlen(sexitcode)); + write(fp, "\n", 1); + close(fp); + free(str); +diff --git a/alsamixer/mixer_display.c b/alsamixer/mixer_display.c +index 9eadcc9..20d6d6a 100644 +--- a/alsamixer/mixer_display.c ++++ b/alsamixer/mixer_display.c +@@ -390,6 +390,15 @@ static void display_string_centered_in_control(int y, int col, const char *s, in + display_string_in_field(y, x, s, width, ALIGN_CENTER); + } + ++static long clamp(long value, long min, long max) ++{ ++ if (value < min) ++ return min; ++ if (value > max) ++ return max; ++ return value; ++} ++ + static void display_control(unsigned int control_index) + { + struct control *control; +@@ -462,6 +471,10 @@ static void display_control(unsigned int control_index) + err = snd_mixer_selem_get_capture_volume_range(control->elem, &min, &max); + if (err < 0) + return; ++ if (min >= max) ++ max = min + 1; ++ volumes[0] = clamp(volumes[0], min, max); ++ volumes[1] = clamp(volumes[1], min, max); + + if (control->flags & IS_ACTIVE) + wattrset(mixer_widget.window, 0); +diff --git a/amidi/amidi.c b/amidi/amidi.c +index 2e970ae..cedf18c 100644 +--- a/amidi/amidi.c ++++ b/amidi/amidi.c +@@ -95,122 +95,63 @@ static void *my_malloc(size_t size) + return p; + } + +-static int is_input(snd_ctl_t *ctl, int card, int device, int sub) +-{ +- snd_rawmidi_info_t *info; +- int err; +- +- snd_rawmidi_info_alloca(&info); +- snd_rawmidi_info_set_device(info, device); +- snd_rawmidi_info_set_subdevice(info, sub); +- snd_rawmidi_info_set_stream(info, SND_RAWMIDI_STREAM_INPUT); +- +- if ((err = snd_ctl_rawmidi_info(ctl, info)) < 0 && err != -ENXIO) +- return err; +- else if (err == 0) +- return 1; +- +- return 0; +-} +- +-static int is_output(snd_ctl_t *ctl, int card, int device, int sub) +-{ +- snd_rawmidi_info_t *info; +- int err; +- +- snd_rawmidi_info_alloca(&info); +- snd_rawmidi_info_set_device(info, device); +- snd_rawmidi_info_set_subdevice(info, sub); +- snd_rawmidi_info_set_stream(info, SND_RAWMIDI_STREAM_OUTPUT); +- +- if ((err = snd_ctl_rawmidi_info(ctl, info)) < 0 && err != -ENXIO) +- return err; +- else if (err == 0) +- return 1; +- +- return 0; +-} +- + static void list_device(snd_ctl_t *ctl, int card, int device) + { + snd_rawmidi_info_t *info; + const char *name; + const char *sub_name; + int subs, subs_in, subs_out; +- int sub, in, out; ++ int sub; + int err; + + snd_rawmidi_info_alloca(&info); + snd_rawmidi_info_set_device(info, device); + + snd_rawmidi_info_set_stream(info, SND_RAWMIDI_STREAM_INPUT); +- snd_ctl_rawmidi_info(ctl, info); +- subs_in = snd_rawmidi_info_get_subdevices_count(info); ++ err = snd_ctl_rawmidi_info(ctl, info); ++ if (err >= 0) ++ subs_in = snd_rawmidi_info_get_subdevices_count(info); ++ else ++ subs_in = 0; ++ + snd_rawmidi_info_set_stream(info, SND_RAWMIDI_STREAM_OUTPUT); +- snd_ctl_rawmidi_info(ctl, info); +- subs_out = snd_rawmidi_info_get_subdevices_count(info); +- subs = subs_in > subs_out ? subs_in : subs_out; ++ err = snd_ctl_rawmidi_info(ctl, info); ++ if (err >= 0) ++ subs_out = snd_rawmidi_info_get_subdevices_count(info); ++ else ++ subs_out = 0; + +- sub = 0; +- in = out = 0; +- if ((err = is_output(ctl, card, device, sub)) < 0) { +- error("cannot get rawmidi information %d:%d: %s", +- card, device, snd_strerror(err)); ++ subs = subs_in > subs_out ? subs_in : subs_out; ++ if (!subs) + return; +- } else if (err) +- out = 1; + +- if (err == 0) { +- if ((err = is_input(ctl, card, device, sub)) < 0) { +- error("cannot get rawmidi information %d:%d: %s", +- card, device, snd_strerror(err)); ++ for (sub = 0; sub < subs; ++sub) { ++ snd_rawmidi_info_set_stream(info, sub < subs_in ? ++ SND_RAWMIDI_STREAM_INPUT : ++ SND_RAWMIDI_STREAM_OUTPUT); ++ snd_rawmidi_info_set_subdevice(info, sub); ++ err = snd_ctl_rawmidi_info(ctl, info); ++ if (err < 0) { ++ error("cannot get rawmidi information %d:%d:%d: %s\n", ++ card, device, sub, snd_strerror(err)); + return; + } +- } else if (err) +- in = 1; +- +- if (err == 0) +- return; +- +- name = snd_rawmidi_info_get_name(info); +- sub_name = snd_rawmidi_info_get_subdevice_name(info); +- if (sub_name[0] == '\0') { +- if (subs == 1) { +- printf("%c%c hw:%d,%d %s\n", +- in ? 'I' : ' ', out ? 'O' : ' ', ++ name = snd_rawmidi_info_get_name(info); ++ sub_name = snd_rawmidi_info_get_subdevice_name(info); ++ if (sub == 0 && sub_name[0] == '\0') { ++ printf("%c%c hw:%d,%d %s", ++ sub < subs_in ? 'I' : ' ', ++ sub < subs_out ? 'O' : ' ', + card, device, name); +- } else +- printf("%c%c hw:%d,%d %s (%d subdevices)\n", +- in ? 'I' : ' ', out ? 'O' : ' ', +- card, device, name, subs); +- } else { +- sub = 0; +- for (;;) { ++ if (subs > 1) ++ printf(" (%d subdevices)", subs); ++ putchar('\n'); ++ break; ++ } else { + printf("%c%c hw:%d,%d,%d %s\n", +- in ? 'I' : ' ', out ? 'O' : ' ', ++ sub < subs_in ? 'I' : ' ', ++ sub < subs_out ? 'O' : ' ', + card, device, sub, sub_name); +- if (++sub >= subs) +- break; +- +- in = is_input(ctl, card, device, sub); +- out = is_output(ctl, card, device, sub); +- snd_rawmidi_info_set_subdevice(info, sub); +- if (out) { +- snd_rawmidi_info_set_stream(info, SND_RAWMIDI_STREAM_OUTPUT); +- if ((err = snd_ctl_rawmidi_info(ctl, info)) < 0) { +- error("cannot get rawmidi information %d:%d:%d: %s", +- card, device, sub, snd_strerror(err)); +- break; +- } +- } else { +- snd_rawmidi_info_set_stream(info, SND_RAWMIDI_STREAM_INPUT); +- if ((err = snd_ctl_rawmidi_info(ctl, info)) < 0) { +- error("cannot get rawmidi information %d:%d:%d: %s", +- card, device, sub, snd_strerror(err)); +- break; +- } +- } +- sub_name = snd_rawmidi_info_get_subdevice_name(info); + } + } + } +diff --git a/amixer/amixer.c b/amixer/amixer.c +index 9620721..c9ea572 100644 +--- a/amixer/amixer.c ++++ b/amixer/amixer.c +@@ -534,6 +534,26 @@ static void decode_tlv(unsigned int spaces, unsigned int *tlv, unsigned int tlv_ + } + break; + #endif ++#ifdef SND_CTL_TLVT_DB_MINMAX ++ case SND_CTL_TLVT_DB_MINMAX: ++ case SND_CTL_TLVT_DB_MINMAX_MUTE: ++ if (type == SND_CTL_TLVT_DB_MINMAX_MUTE) ++ printf("dBminmaxmute-"); ++ else ++ printf("dBminmax-"); ++ if (size != 2 * sizeof(unsigned int)) { ++ while (size > 0) { ++ printf("0x%08x,", tlv[idx++]); ++ size -= sizeof(unsigned int); ++ } ++ } else { ++ printf("min="); ++ print_dB(tlv[2]); ++ printf(",max="); ++ print_dB(tlv[3]); ++ } ++ break; ++#endif + default: + printf("unk-%i-", type); + while (size > 0) { +@@ -602,6 +622,8 @@ static int show_control(const char *space, snd_hctl_elem_t *elem, + break; + } + if (level & LEVEL_BASIC) { ++ if (!snd_ctl_elem_info_is_readable(info)) ++ goto __skip_read; + if ((err = snd_hctl_elem_read(elem, control)) < 0) { + error("Control %s element read error: %s\n", card, snd_strerror(err)); + return err; +@@ -638,6 +660,7 @@ static int show_control(const char *space, snd_hctl_elem_t *elem, + } + } + printf("\n"); ++ __skip_read: + if (!snd_ctl_elem_info_is_tlv_readable(info)) + goto __skip_tlv; + tlv = malloc(4096); +diff --git a/aplay/aplay.1 b/aplay/aplay.1 +index 7759347..b6caf0b 100644 +--- a/aplay/aplay.1 ++++ b/aplay/aplay.1 +@@ -1,4 +1,4 @@ +-.TH APLAY 1 "2 August 2001" ++.TH APLAY 1 "1 January 2010" + .SH NAME + arecord, aplay \- command-line sound recorder and player for ALSA + soundcard driver +@@ -46,6 +46,7 @@ If this parameter is omitted the WAVE format is used. + \fI\-c, \-\-channels=#\fP + The number of channels. + The default is one channel. ++Valid values are 1 through 32. + .TP + \fI\-f \-\-format=FORMAT\fP + Sample format +@@ -53,19 +54,23 @@ Sample format + Recognized sample formats are: S8 U8 S16_LE S16_BE U16_LE U16_BE S24_LE + S24_BE U24_LE U24_BE S32_LE S32_BE U32_LE U32_BE FLOAT_LE FLOAT_BE + FLOAT64_LE FLOAT64_BE IEC958_SUBFRAME_LE IEC958_SUBFRAME_BE MU_LAW +-A_LAW IMA_ADPCM MPEG GSM ++A_LAW IMA_ADPCM MPEG GSM SPECIAL S24_3LE S24_3BE U24_3LE U24_3BE S20_3LE ++S20_3BE U20_3LE U20_3BE S18_3LE S18_3BE U18_3LE + .br + Some of these may not be available on selected hardware + .br +-There are also two format shortcuts available: ++The available format shortcuts are: + .nf +-\-f cd (16 bit little endian, 44100, stereo [\-f S16_LE \-c2 \-r44100] ++\-f cd (16 bit little endian, 44100, stereo) [\-f S16_LE \-c2 \-r44100] ++\-f cdr (16 bit big endian, 44100, stereo) [\-f S16_BE \-c2 \-f44100] + \-f dat (16 bit little endian, 48000, stereo) [\-f S16_LE \-c2 \-r48000] + .fi + If no format is given U8 is used. + .TP + \fI\-r, \-\-rate=#\fP + Sampling rate in Hertz. The default rate is 8000 Hertz. ++If the value specified is less than 300, it is taken as the rate in kilohertz. ++Valid values are 2000 through 192000 Hertz. + .TP + \fI\-d, \-\-duration=#\fP + Interrupt after # seconds. +@@ -120,10 +125,69 @@ The stereo VU-meter is available only for 2-channel stereo samples + with interleaved format. + .TP + \fI\-I, \-\-separate\-channels\fP +-One file for each channel ++One file for each channel. This option disables max\-file\-time ++and use\-strftime, and ignores SIGUSR1. The stereo VU meter is ++not available with separate channels. ++.TP ++\fI\-P\fP ++Playback. This is the default if the program is invoked ++by typing aplay. ++.TP ++\fI\-C\fP ++Record. This is the default if the program is invoked ++by typing arecord. ++.TP ++\fI\-\-disable\-resample\fP ++Disable automatic rate resample. ++.TP ++\fI\-\-disable\-channels\fP ++Disable automatic channel conversions. ++.TP ++\fI\-\-disable\-format\fP ++Disable automatic format conversions. ++.TP ++\fI\-\-disable\-softvol\fP ++Disable software volume control (softvol). ++.TP ++\fI\-\-test\-position\fP ++Test ring buffer position. ++.TP ++\fI\-\-test\-coef=\fP ++Test coefficient for ring buffer position; default is 8. ++Expression for validation is: coef * (buffer_size / 2). ++Minimum value is 1. ++.TP ++\fI\-\-test\-nowait\fP ++Do not wait for the ring buffer--eats the whole CPU. ++.TP ++\fI\-\-max\-file\-time\fP ++While recording, when the output file has been accumulating ++sound for this long, ++close it and open a new output file. Default is the maximum ++size supported by the file format: 2 GiB for WAV files. ++This option has no effect if \-\-separate\-channels is ++specified. ++.TP ++\fI\-\-process\-id\-file \fP ++aplay writes its process ID here, so other programs can ++send signals to it. ++.TP ++\fI\-\-use\-strftime\fP ++When recording, interpret %-codes in the file name parameter using ++the strftime facility whenever the output file is opened. The ++important strftime codes are: %Y is the year, %m month, %d day of ++the month, %H hour, %M minute and %S second. In addition, %v is ++the file number, starting at 1. When this option is specified, ++intermediate directories for the output file are created automatically. ++This option has no effect if \-\-separate\-channels is specified. + +-.SS +-Example: ++.SH SIGNALS ++When recording, SIGINT, SIGTERM and SIGABRT will close the output ++file and exit. SIGUSR1 will close the output file, open a new one, ++and continue recording. However, SIGUSR1 does not work with ++\-\-separate\-channels. ++ ++.SH EXAMPLES + + .TP + \fBaplay \-c 1 \-t raw \-r 22050 \-f mu_law foobar\fR +@@ -144,6 +208,19 @@ pcm.copy { + } + .fi + ++.TP ++\fBarecord \-t wav \-max-file_time 30 mon.wav\fP ++Record from the default audio source in monaural, 8,000 samples ++per second, 8 bits per sample. Start a new file every ++30 seconds. File names are mon-nn.wav, where nn increases ++from 01. The file after mon-99.wav is mon-100.wav. ++ ++.TP ++\fBarecord \-f cd \-t wav \-max-file-time 3600 --use-strftime %Y/%m/%d/listen-%H-%M-%v.wav\fP ++Record in stereo from the default audio source. Create a new file ++every hour. The files are placed in directories based on their start dates ++and have names which include their start times and file numbers. ++ + .SH SEE ALSO + \fB + alsamixer(1), +diff --git a/aplay/aplay.c b/aplay/aplay.c +index 22a5fe0..e1d8e6a 100644 +--- a/aplay/aplay.c ++++ b/aplay/aplay.c +@@ -111,11 +111,19 @@ static int test_position = 0; + static int test_coef = 8; + static int test_nowait = 0; + static snd_output_t *log; ++static long long max_file_size = 0; ++static int max_file_time = 0; ++static int use_strftime = 0; ++volatile static int recycle_capture_file = 0; + + static int fd = -1; + static off64_t pbrec_count = LLONG_MAX, fdcount; + static int vocmajor, vocminor; + ++static char *pidfile_name = NULL; ++FILE *pidf = NULL; ++static int pidfile_written = 0; ++ + /* needed prototypes */ + + static void playback(char *filename); +@@ -194,7 +202,11 @@ _("Usage: %s [OPTION]... [FILE]...\n" + " --test-position test ring buffer position\n" + " --test-coef=# test coeficient for ring buffer position (default 8)\n" + " expression for validation is: coef * (buffer_size / 2)\n" +-" --test-nowait do not wait for ring buffer - eats whole CPU\n") ++" --test-nowait do not wait for ring buffer - eats whole CPU\n" ++" --max-file-time=# start another output file when the old file has recorded\n" ++" for this many seconds\n" ++" --process-id-file write the process ID here\n" ++" --use-strftime apply the strftime facility to the output file name\n") + , command); + printf(_("Recognized sample formats are:")); + for (k = 0; k < SND_PCM_FORMAT_LAST; ++k) { +@@ -324,6 +336,18 @@ static void version(void) + printf("%s: version " SND_UTIL_VERSION_STR " by Jaroslav Kysela \n", command); + } + ++/* ++ * Subroutine to clean up before exit. ++ */ ++static void prg_exit(int code) ++{ ++ if (handle) ++ snd_pcm_close(handle); ++ if (pidfile_written) ++ remove (pidfile_name); ++ exit(code); ++} ++ + static void signal_handler(int sig) + { + if (verbose==2) +@@ -345,7 +369,14 @@ static void signal_handler(int sig) + snd_pcm_close(handle); + handle = NULL; + } +- exit(EXIT_FAILURE); ++ prg_exit(EXIT_FAILURE); ++} ++ ++/* call on SIGUSR1 signal. */ ++static void signal_handler_recycle (int sig) ++{ ++ /* flag the capture loop to start a new output file */ ++ recycle_capture_file = 1; + } + + enum { +@@ -358,7 +389,10 @@ enum { + OPT_DISABLE_SOFTVOL, + OPT_TEST_POSITION, + OPT_TEST_COEF, +- OPT_TEST_NOWAIT ++ OPT_TEST_NOWAIT, ++ OPT_MAX_FILE_TIME, ++ OPT_PROCESS_ID_FILE, ++ OPT_USE_STRFTIME + }; + + int main(int argc, char *argv[]) +@@ -399,6 +433,9 @@ int main(int argc, char *argv[]) + {"test-position", 0, 0, OPT_TEST_POSITION}, + {"test-coef", 1, 0, OPT_TEST_COEF}, + {"test-nowait", 0, 0, OPT_TEST_NOWAIT}, ++ {"max-file-time", 1, 0, OPT_MAX_FILE_TIME}, ++ {"process-id-file", 1, 0, OPT_PROCESS_ID_FILE}, ++ {"use-strftime", 0, 0, OPT_USE_STRFTIME}, + {0, 0, 0, 0} + }; + char *pcm_name = "default"; +@@ -493,7 +530,7 @@ int main(int argc, char *argv[]) + rhwparams.format = snd_pcm_format_value(optarg); + if (rhwparams.format == SND_PCM_FORMAT_UNKNOWN) { + error(_("wrong extended format '%s'"), optarg); +- exit(EXIT_FAILURE); ++ prg_exit(EXIT_FAILURE); + } + } + break; +@@ -588,6 +625,15 @@ int main(int argc, char *argv[]) + case OPT_TEST_NOWAIT: + test_nowait = 1; + break; ++ case OPT_MAX_FILE_TIME: ++ max_file_time = strtol(optarg, NULL, 0); ++ break; ++ case OPT_PROCESS_ID_FILE: ++ pidfile_name = optarg; ++ break; ++ case OPT_USE_STRFTIME: ++ use_strftime = 1; ++ break; + default: + fprintf(stderr, _("Try `%s --help' for more information.\n"), command); + return 1; +@@ -643,10 +689,24 @@ int main(int argc, char *argv[]) + readn_func = snd_pcm_readn; + } + ++ if (pidfile_name) { ++ errno = 0; ++ pidf = fopen (pidfile_name, "w"); ++ if (pidf) { ++ (void)fprintf (pidf, "%d\n", getpid()); ++ fclose(pidf); ++ pidfile_written = 1; ++ } else { ++ error(_("Cannot create process ID file %s: %s"), ++ pidfile_name, strerror (errno)); ++ return 1; ++ } ++ } + + signal(SIGINT, signal_handler); + signal(SIGTERM, signal_handler); + signal(SIGABRT, signal_handler); ++ signal(SIGUSR1, signal_handler_recycle); + if (interleaved) { + if (optind > argc - 1) { + if (stream == SND_PCM_STREAM_PLAYBACK) +@@ -670,10 +730,13 @@ int main(int argc, char *argv[]) + if (verbose==2) + putchar('\n'); + snd_pcm_close(handle); ++ handle = NULL; + free(audiobuf); + __end: + snd_output_close(log); + snd_config_update_free_global(); ++ prg_exit(EXIT_SUCCESS); ++ /* avoid warning */ + return EXIT_SUCCESS; + } + +@@ -725,7 +788,7 @@ static size_t test_wavefile_read(int fd, u_char *buffer, size_t *size, size_t re + return *size; + if ((size_t)safe_read(fd, buffer + *size, reqsize - *size) != reqsize - *size) { + error(_("read error (called from line %i)"), line); +- exit(EXIT_FAILURE); ++ prg_exit(EXIT_FAILURE); + } + return *size = reqsize; + } +@@ -735,7 +798,7 @@ static size_t test_wavefile_read(int fd, u_char *buffer, size_t *size, size_t re + blimit = len; \ + if ((buffer = realloc(buffer, blimit)) == NULL) { \ + error(_("not enough memory")); \ +- exit(EXIT_FAILURE); \ ++ prg_exit(EXIT_FAILURE); \ + } \ + } + +@@ -784,7 +847,7 @@ static ssize_t test_wavefile(int fd, u_char *_buffer, size_t size) + if (len < sizeof(WaveFmtBody)) { + error(_("unknown length of 'fmt ' chunk (read %u, should be %u at least)"), + len, (u_int)sizeof(WaveFmtBody)); +- exit(EXIT_FAILURE); ++ prg_exit(EXIT_FAILURE); + } + check_wavefile_space(buffer, len, blimit); + test_wavefile_read(fd, buffer, &size, len, __LINE__); +@@ -794,22 +857,22 @@ static ssize_t test_wavefile(int fd, u_char *_buffer, size_t size) + if (len < sizeof(WaveFmtExtensibleBody)) { + error(_("unknown length of extensible 'fmt ' chunk (read %u, should be %u at least)"), + len, (u_int)sizeof(WaveFmtExtensibleBody)); +- exit(EXIT_FAILURE); ++ prg_exit(EXIT_FAILURE); + } + if (memcmp(fe->guid_tag, WAV_GUID_TAG, 14) != 0) { + error(_("wrong format tag in extensible 'fmt ' chunk")); +- exit(EXIT_FAILURE); ++ prg_exit(EXIT_FAILURE); + } + f->format = fe->guid_format; + } + if (LE_SHORT(f->format) != WAV_FMT_PCM && + LE_SHORT(f->format) != WAV_FMT_IEEE_FLOAT) { + error(_("can't play WAVE-file format 0x%04x which is not PCM or FLOAT encoded"), LE_SHORT(f->format)); +- exit(EXIT_FAILURE); ++ prg_exit(EXIT_FAILURE); + } + if (LE_SHORT(f->channels) < 1) { + error(_("can't play WAVE-files with %d tracks"), LE_SHORT(f->channels)); +- exit(EXIT_FAILURE); ++ prg_exit(EXIT_FAILURE); + } + hwparams.channels = LE_SHORT(f->channels); + switch (LE_SHORT(f->bit_p_spl)) { +@@ -842,7 +905,7 @@ static ssize_t test_wavefile(int fd, u_char *_buffer, size_t size) + default: + error(_(" can't play WAVE-files with sample %d bits in %d bytes wide (%d channels)"), + LE_SHORT(f->bit_p_spl), LE_SHORT(f->byte_p_spl), hwparams.channels); +- exit(EXIT_FAILURE); ++ prg_exit(EXIT_FAILURE); + } + break; + case 32: +@@ -854,7 +917,7 @@ static ssize_t test_wavefile(int fd, u_char *_buffer, size_t size) + default: + error(_(" can't play WAVE-files with sample %d bits wide"), + LE_SHORT(f->bit_p_spl)); +- exit(EXIT_FAILURE); ++ prg_exit(EXIT_FAILURE); + } + hwparams.rate = LE_INT(f->sample_fq); + +@@ -936,7 +999,7 @@ static int test_au(int fd, void *buffer) + return -1; + if ((size_t)safe_read(fd, buffer + sizeof(AuHeader), BE_INT(ap->hdr_size) - sizeof(AuHeader)) != BE_INT(ap->hdr_size) - sizeof(AuHeader)) { + error(_("read error")); +- exit(EXIT_FAILURE); ++ prg_exit(EXIT_FAILURE); + } + return 0; + } +@@ -966,7 +1029,7 @@ static void set_params(void) + err = snd_pcm_hw_params_any(handle, params); + if (err < 0) { + error(_("Broken configuration for this PCM: no configurations available")); +- exit(EXIT_FAILURE); ++ prg_exit(EXIT_FAILURE); + } + if (mmap_flag) { + snd_pcm_access_mask_t *mask = alloca(snd_pcm_access_mask_sizeof()); +@@ -983,18 +1046,18 @@ static void set_params(void) + SND_PCM_ACCESS_RW_NONINTERLEAVED); + if (err < 0) { + error(_("Access type not available")); +- exit(EXIT_FAILURE); ++ prg_exit(EXIT_FAILURE); + } + err = snd_pcm_hw_params_set_format(handle, params, hwparams.format); + if (err < 0) { + error(_("Sample format non available")); + show_available_sample_formats(params); +- exit(EXIT_FAILURE); ++ prg_exit(EXIT_FAILURE); + } + err = snd_pcm_hw_params_set_channels(handle, params, hwparams.channels); + if (err < 0) { + error(_("Channels count non available")); +- exit(EXIT_FAILURE); ++ prg_exit(EXIT_FAILURE); + } + + #if 0 +@@ -1052,14 +1115,14 @@ static void set_params(void) + if (err < 0) { + error(_("Unable to install hw params:")); + snd_pcm_hw_params_dump(params, log); +- exit(EXIT_FAILURE); ++ prg_exit(EXIT_FAILURE); + } + snd_pcm_hw_params_get_period_size(params, &chunk_size, 0); + snd_pcm_hw_params_get_buffer_size(params, &buffer_size); + if (chunk_size == buffer_size) { + error(_("Can't use period equal to buffer size (%lu == %lu)"), + chunk_size, buffer_size); +- exit(EXIT_FAILURE); ++ prg_exit(EXIT_FAILURE); + } + snd_pcm_sw_params_current(handle, swparams); + if (avail_min < 0) +@@ -1090,7 +1153,7 @@ static void set_params(void) + if (snd_pcm_sw_params(handle, swparams) < 0) { + error(_("unable to install sw params:")); + snd_pcm_sw_params_dump(swparams, log); +- exit(EXIT_FAILURE); ++ prg_exit(EXIT_FAILURE); + } + + if (verbose) +@@ -1102,7 +1165,7 @@ static void set_params(void) + audiobuf = realloc(audiobuf, chunk_bytes); + if (audiobuf == NULL) { + error(_("not enough memory")); +- exit(EXIT_FAILURE); ++ prg_exit(EXIT_FAILURE); + } + // fprintf(stderr, "real chunk_size = %i, frags = %i, total = %i\n", chunk_size, setup.buf.block.frags, setup.buf.block.frags * chunk_size); + +@@ -1120,7 +1183,7 @@ static void set_params(void) + err = snd_pcm_mmap_begin(handle, &areas, &offset, &size); + if (err < 0) { + error("snd_pcm_mmap_begin problem: %s", snd_strerror(err)); +- exit(EXIT_FAILURE); ++ prg_exit(EXIT_FAILURE); + } + for (i = 0; i < hwparams.channels; i++) + fprintf(stderr, "mmap_area[%i] = %p,%u,%u (%u)\n", i, areas[i].addr, areas[i].first, areas[i].step, snd_pcm_format_physical_width(hwparams.format)); +@@ -1164,7 +1227,7 @@ static void xrun(void) + snd_pcm_status_alloca(&status); + if ((res = snd_pcm_status(handle, status))<0) { + error(_("status error: %s"), snd_strerror(res)); +- exit(EXIT_FAILURE); ++ prg_exit(EXIT_FAILURE); + } + if (snd_pcm_status_get_state(status) == SND_PCM_STATE_XRUN) { + if (monotonic) { +@@ -1194,7 +1257,7 @@ static void xrun(void) + } + if ((res = snd_pcm_prepare(handle))<0) { + error(_("xrun: prepare error: %s"), snd_strerror(res)); +- exit(EXIT_FAILURE); ++ prg_exit(EXIT_FAILURE); + } + return; /* ok, data should be accepted again */ + } if (snd_pcm_status_get_state(status) == SND_PCM_STATE_DRAINING) { +@@ -1206,7 +1269,7 @@ static void xrun(void) + fprintf(stderr, _("capture stream format change? attempting recover...\n")); + if ((res = snd_pcm_prepare(handle))<0) { + error(_("xrun(DRAINING): prepare error: %s"), snd_strerror(res)); +- exit(EXIT_FAILURE); ++ prg_exit(EXIT_FAILURE); + } + return; + } +@@ -1216,7 +1279,7 @@ static void xrun(void) + snd_pcm_status_dump(status, log); + } + error(_("read/write error, state = %s"), snd_pcm_state_name(snd_pcm_status_get_state(status))); +- exit(EXIT_FAILURE); ++ prg_exit(EXIT_FAILURE); + } + + /* I/O suspend handler */ +@@ -1233,7 +1296,7 @@ static void suspend(void) + fprintf(stderr, _("Failed. Restarting stream. ")); fflush(stderr); + if ((res = snd_pcm_prepare(handle)) < 0) { + error(_("suspend: prepare error: %s"), snd_strerror(res)); +- exit(EXIT_FAILURE); ++ prg_exit(EXIT_FAILURE); + } + } + if (!quiet_mode) +@@ -1538,7 +1601,7 @@ static ssize_t pcm_write(u_char *data, size_t count) + suspend(); + } else if (r < 0) { + error(_("write error: %s"), snd_strerror(r)); +- exit(EXIT_FAILURE); ++ prg_exit(EXIT_FAILURE); + } + if (r > 0) { + if (vumeter) +@@ -1584,7 +1647,7 @@ static ssize_t pcm_writev(u_char **data, unsigned int channels, size_t count) + suspend(); + } else if (r < 0) { + error(_("writev error: %s"), snd_strerror(r)); +- exit(EXIT_FAILURE); ++ prg_exit(EXIT_FAILURE); + } + if (r > 0) { + if (vumeter) { +@@ -1627,7 +1690,7 @@ static ssize_t pcm_read(u_char *data, size_t rcount) + suspend(); + } else if (r < 0) { + error(_("read error: %s"), snd_strerror(r)); +- exit(EXIT_FAILURE); ++ prg_exit(EXIT_FAILURE); + } + if (r > 0) { + if (vumeter) +@@ -1670,7 +1733,7 @@ static ssize_t pcm_readv(u_char **data, unsigned int channels, size_t rcount) + suspend(); + } else if (r < 0) { + error(_("readv error: %s"), snd_strerror(r)); +- exit(EXIT_FAILURE); ++ prg_exit(EXIT_FAILURE); + } + if (r > 0) { + if (vumeter) { +@@ -1727,7 +1790,7 @@ static void voc_write_silence(unsigned x) + l = chunk_size; + if (voc_pcm_write(buf, l) != (ssize_t)l) { + error(_("write error")); +- exit(EXIT_FAILURE); ++ prg_exit(EXIT_FAILURE); + } + x -= l; + } +@@ -1769,7 +1832,7 @@ static void voc_play(int fd, int ofs, char *name) + buffer_pos = 0; + if (data == NULL) { + error(_("malloc error")); +- exit(EXIT_FAILURE); ++ prg_exit(EXIT_FAILURE); + } + if (!quiet_mode) { + fprintf(stderr, _("Playing Creative Labs Channel file '%s'...\n"), name); +@@ -1778,14 +1841,14 @@ static void voc_play(int fd, int ofs, char *name) + while (ofs > (ssize_t)chunk_bytes) { + if ((size_t)safe_read(fd, buf, chunk_bytes) != chunk_bytes) { + error(_("read error")); +- exit(EXIT_FAILURE); ++ prg_exit(EXIT_FAILURE); + } + ofs -= chunk_bytes; + } + if (ofs) { + if (safe_read(fd, buf, ofs) != ofs) { + error(_("read error")); +- exit(EXIT_FAILURE); ++ prg_exit(EXIT_FAILURE); + } + } + hwparams.format = DEFAULT_FORMAT; +@@ -1809,7 +1872,7 @@ static void voc_play(int fd, int ofs, char *name) + nextblock = buf[0] = 0; + if (l == -1) { + perror(name); +- exit(EXIT_FAILURE); ++ prg_exit(EXIT_FAILURE); + } + } + } +@@ -1953,12 +2016,12 @@ static void voc_play(int fd, int ofs, char *name) + if (output && !quiet_mode) { + if (write(2, data, l) != l) { /* to stderr */ + error(_("write error")); +- exit(EXIT_FAILURE); ++ prg_exit(EXIT_FAILURE); + } + } else { + if (voc_pcm_write(data, l) != l) { + error(_("write error")); +- exit(EXIT_FAILURE); ++ prg_exit(EXIT_FAILURE); + } + } + COUNT(l); +@@ -2005,7 +2068,7 @@ static void begin_voc(int fd, size_t cnt) + + if (write(fd, &vh, sizeof(VocHeader)) != sizeof(VocHeader)) { + error(_("write error")); +- exit(EXIT_FAILURE); ++ prg_exit(EXIT_FAILURE); + } + if (hwparams.channels > 1) { + /* write an extended block */ +@@ -2014,14 +2077,14 @@ static void begin_voc(int fd, size_t cnt) + bt.datalen_m = bt.datalen_h = 0; + if (write(fd, &bt, sizeof(VocBlockType)) != sizeof(VocBlockType)) { + error(_("write error")); +- exit(EXIT_FAILURE); ++ prg_exit(EXIT_FAILURE); + } + eb.tc = LE_SHORT(65536 - 256000000L / (hwparams.rate << 1)); + eb.pack = 0; + eb.mode = 1; + if (write(fd, &eb, sizeof(VocExtBlock)) != sizeof(VocExtBlock)) { + error(_("write error")); +- exit(EXIT_FAILURE); ++ prg_exit(EXIT_FAILURE); + } + } + bt.type = 1; +@@ -2031,13 +2094,13 @@ static void begin_voc(int fd, size_t cnt) + bt.datalen_h = (u_char) ((cnt & 0xFF0000) >> 16); + if (write(fd, &bt, sizeof(VocBlockType)) != sizeof(VocBlockType)) { + error(_("write error")); +- exit(EXIT_FAILURE); ++ prg_exit(EXIT_FAILURE); + } + vd.tc = (u_char) (256 - (1000000 / hwparams.rate)); + vd.pack = 0; + if (write(fd, &vd, sizeof(VocVoiceData)) != sizeof(VocVoiceData)) { + error(_("write error")); +- exit(EXIT_FAILURE); ++ prg_exit(EXIT_FAILURE); + } + } + +@@ -2073,7 +2136,7 @@ static void begin_wave(int fd, size_t cnt) + break; + default: + error(_("Wave doesn't support %s format..."), snd_pcm_format_name(hwparams.format)); +- exit(EXIT_FAILURE); ++ prg_exit(EXIT_FAILURE); + } + h.magic = WAV_RIFF; + tmp = cnt + sizeof(WaveHeader) + sizeof(WaveChunkHeader) + sizeof(WaveFmtBody) + sizeof(WaveChunkHeader) - 8; +@@ -2109,7 +2172,7 @@ static void begin_wave(int fd, size_t cnt) + write(fd, &f, sizeof(WaveFmtBody)) != sizeof(WaveFmtBody) || + write(fd, &cd, sizeof(WaveChunkHeader)) != sizeof(WaveChunkHeader)) { + error(_("write error")); +- exit(EXIT_FAILURE); ++ prg_exit(EXIT_FAILURE); + } + } + +@@ -2133,13 +2196,13 @@ static void begin_au(int fd, size_t cnt) + break; + default: + error(_("Sparc Audio doesn't support %s format..."), snd_pcm_format_name(hwparams.format)); +- exit(EXIT_FAILURE); ++ prg_exit(EXIT_FAILURE); + } + ah.sample_rate = BE_INT(hwparams.rate); + ah.channels = BE_INT(hwparams.channels); + if (write(fd, &ah, sizeof(AuHeader)) != sizeof(AuHeader)) { + error(_("write error")); +- exit(EXIT_FAILURE); ++ prg_exit(EXIT_FAILURE); + } + } + +@@ -2153,7 +2216,7 @@ static void end_voc(int fd) + + if (write(fd, &dummy, 1) != 1) { + error(_("write error")); +- exit(EXIT_FAILURE); ++ prg_exit(EXIT_FAILURE); + } + length_seek = sizeof(VocHeader); + if (hwparams.channels > 1) +@@ -2261,7 +2324,7 @@ static void playback_go(int fd, size_t loaded, off64_t count, int rtype, char *n + r = safe_read(fd, audiobuf + l, c); + if (r < 0) { + perror(name); +- exit(EXIT_FAILURE); ++ prg_exit(EXIT_FAILURE); + } + fdcount += r; + if (r == 0) +@@ -2300,14 +2363,14 @@ static void playback(char *name) + } else { + if ((fd = open64(name, O_RDONLY, 0)) == -1) { + perror(name); +- exit(EXIT_FAILURE); ++ prg_exit(EXIT_FAILURE); + } + } + /* read the file header */ + dta = sizeof(AuHeader); + if ((size_t)safe_read(fd, audiobuf, dta) != dta) { + error(_("read error")); +- exit(EXIT_FAILURE); ++ prg_exit(EXIT_FAILURE); + } + if (test_au(fd, audiobuf) >= 0) { + rhwparams.format = hwparams.format; +@@ -2319,7 +2382,7 @@ static void playback(char *name) + if ((size_t)safe_read(fd, audiobuf + sizeof(AuHeader), + dta - sizeof(AuHeader)) != dta - sizeof(AuHeader)) { + error(_("read error")); +- exit(EXIT_FAILURE); ++ prg_exit(EXIT_FAILURE);; + } + if ((ofs = test_vocfile(audiobuf)) >= 0) { + pbrec_count = calc_count(); +@@ -2341,13 +2404,98 @@ static void playback(char *name) + close(fd); + } + ++/** ++ * mystrftime ++ * ++ * Variant of strftime(3) that supports additional format ++ * specifiers in the format string. ++ * ++ * Parameters: ++ * ++ * s - destination string ++ * max - max number of bytes to write ++ * userformat - format string ++ * tm - time information ++ * filenumber - the number of the file, starting at 1 ++ * ++ * Returns: number of bytes written to the string s ++ */ ++size_t mystrftime(char *s, size_t max, const char *userformat, ++ const struct tm *tm, const int filenumber) ++{ ++ char formatstring[PATH_MAX] = ""; ++ char tempstring[PATH_MAX] = ""; ++ char *format, *tempstr; ++ const char *pos_userformat; ++ ++ format = formatstring; ++ ++ /* if mystrftime is called with userformat = NULL we return a zero length string */ ++ if (userformat == NULL) { ++ *s = '\0'; ++ return 0; ++ } ++ ++ for (pos_userformat = userformat; *pos_userformat; ++pos_userformat) { ++ if (*pos_userformat == '%') { ++ tempstr = tempstring; ++ tempstr[0] = '\0'; ++ switch (*++pos_userformat) { ++ ++ case '\0': // end of string ++ --pos_userformat; ++ break; ++ ++ case 'v': // file number ++ sprintf(tempstr, "%02d", filenumber); ++ break; ++ ++ default: // All other codes will be handled by strftime ++ *format++ = '%'; ++ *format++ = *pos_userformat; ++ continue; ++ } ++ ++ /* If a format specifier was found and used, copy the result. */ ++ if (tempstr[0]) { ++ while ((*format = *tempstr++) != '\0') ++ ++format; ++ continue; ++ } ++ } ++ ++ /* For any other character than % we simply copy the character */ ++ *format++ = *pos_userformat; ++ } ++ ++ *format = '\0'; ++ format = formatstring; ++ return strftime(s, max, format, tm); ++} ++ + static int new_capture_file(char *name, char *namebuf, size_t namelen, + int filecount) + { +- /* get a copy of the original filename */ + char *s; + char buf[PATH_MAX+1]; ++ time_t t; ++ struct tm *tmp; ++ ++ if (use_strftime) { ++ t = time(NULL); ++ tmp = localtime(&t); ++ if (tmp == NULL) { ++ perror("localtime"); ++ prg_exit(EXIT_FAILURE); ++ } ++ if (mystrftime(namebuf, namelen, name, tmp, filecount+1) == 0) { ++ fprintf(stderr, "mystrftime returned 0"); ++ prg_exit(EXIT_FAILURE); ++ } ++ return filecount; ++ } + ++ /* get a copy of the original filename */ + strncpy(buf, name, sizeof(buf)); + + /* separate extension from filename */ +@@ -2379,6 +2527,58 @@ static int new_capture_file(char *name, char *namebuf, size_t namelen, + return filecount; + } + ++/** ++ * create_path ++ * ++ * This function creates a file path, like mkdir -p. ++ * ++ * Parameters: ++ * ++ * path - the path to create ++ * ++ * Returns: 0 on success, -1 on failure ++ * On failure, a message has been printed to stderr. ++ */ ++int create_path(const char *path) ++{ ++ char *start; ++ mode_t mode = S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH; ++ ++ if (path[0] == '/') ++ start = strchr(path + 1, '/'); ++ else ++ start = strchr(path, '/'); ++ ++ while (start) { ++ char *buffer = strdup(path); ++ buffer[start-path] = 0x00; ++ ++ if (mkdir(buffer, mode) == -1 && errno != EEXIST) { ++ fprintf(stderr, "Problem creating directory %s", buffer); ++ perror(" "); ++ free(buffer); ++ return -1; ++ } ++ free(buffer); ++ start = strchr(start + 1, '/'); ++ } ++ return 0; ++} ++ ++static int safe_open(const char *name) ++{ ++ int fd; ++ ++ fd = open64(name, O_WRONLY | O_CREAT, 0644); ++ if (fd == -1) { ++ if (errno != ENOENT || !use_strftime) ++ return -1; ++ if (create_path(name) == 0) ++ fd = open64(name, O_WRONLY | O_CREAT, 0644); ++ } ++ return fd; ++} ++ + static void capture(char *orig_name) + { + int tostdout=0; /* boolean which describes output stream */ +@@ -2391,6 +2591,10 @@ static void capture(char *orig_name) + count = calc_count(); + if (count == 0) + count = LLONG_MAX; ++ /* compute the number of bytes per file */ ++ max_file_size = max_file_time * ++ snd_pcm_format_size(hwparams.format, ++ hwparams.rate * hwparams.channels); + /* WAVE-file should be even (I'm not sure), but wasting one byte + isn't a problem (this can only be in 8 bit mono) */ + if (count < LLONG_MAX) +@@ -2417,7 +2621,7 @@ static void capture(char *orig_name) + /* open a file to write */ + if(!tostdout) { + /* upon the second file we start the numbering scheme */ +- if (filecount) { ++ if (filecount || use_strftime) { + filecount = new_capture_file(orig_name, namebuf, + sizeof(namebuf), + filecount); +@@ -2426,9 +2630,10 @@ static void capture(char *orig_name) + + /* open a new file */ + remove(name); +- if ((fd = open64(name, O_WRONLY | O_CREAT, 0644)) == -1) { ++ fd = safe_open(name); ++ if (fd < 0) { + perror(name); +- exit(EXIT_FAILURE); ++ prg_exit(EXIT_FAILURE); + } + filecount++; + } +@@ -2436,6 +2641,8 @@ static void capture(char *orig_name) + rest = count; + if (rest > fmt_rec_table[file_type].max_filesize) + rest = fmt_rec_table[file_type].max_filesize; ++ if (max_file_size && (rest > max_file_size)) ++ rest = max_file_size; + + /* setup sample header */ + if (fmt_rec_table[file_type].start) +@@ -2443,7 +2650,7 @@ static void capture(char *orig_name) + + /* capture */ + fdcount = 0; +- while (rest > 0) { ++ while (rest > 0 && recycle_capture_file == 0) { + size_t c = (rest <= (off64_t)chunk_bytes) ? + (size_t)rest : chunk_bytes; + size_t f = c * 8 / bits_per_frame; +@@ -2451,13 +2658,19 @@ static void capture(char *orig_name) + break; + if (write(fd, audiobuf, c) != c) { + perror(name); +- exit(EXIT_FAILURE); ++ prg_exit(EXIT_FAILURE); + } + count -= c; + rest -= c; + fdcount += c; + } + ++ /* re-enable SIGUSR1 signal */ ++ if (recycle_capture_file) { ++ recycle_capture_file = 0; ++ signal(SIGUSR1, signal_handler_recycle); ++ } ++ + /* finish sample container */ + if (fmt_rec_table[file_type].end && !tostdout) { + fmt_rec_table[file_type].end(fd); +@@ -2498,12 +2711,12 @@ static void playbackv_go(int* fds, unsigned int channels, size_t loaded, off64_t + r = safe_read(fds[0], bufs[0], expected); + if (r < 0) { + perror(names[channel]); +- exit(EXIT_FAILURE); ++ prg_exit(EXIT_FAILURE); + } + for (channel = 1; channel < channels; ++channel) { + if (safe_read(fds[channel], bufs[channel], r) != r) { + perror(names[channel]); +- exit(EXIT_FAILURE); ++ prg_exit(EXIT_FAILURE); + } + } + if (r == 0) +@@ -2550,7 +2763,7 @@ static void capturev_go(int* fds, unsigned int channels, off64_t count, int rtyp + for (channel = 0; channel < channels; ++channel) { + if ((size_t)write(fds[channel], bufs[channel], rv) != rv) { + perror(names[channel]); +- exit(EXIT_FAILURE); ++ prg_exit(EXIT_FAILURE); + } + } + r = r * bits_per_frame / 8; +@@ -2583,7 +2796,7 @@ static void playbackv(char **names, unsigned int count) + alloced = 1; + } else if (count != channels) { + error(_("You need to specify %d files"), channels); +- exit(EXIT_FAILURE); ++ prg_exit(EXIT_FAILURE); + } + + for (channel = 0; channel < channels; ++channel) { +@@ -2609,7 +2822,7 @@ static void playbackv(char **names, unsigned int count) + if (alloced) + free(names); + if (ret) +- exit(ret); ++ prg_exit(ret); + } + + static void capturev(char **names, unsigned int count) +@@ -2636,7 +2849,7 @@ static void capturev(char **names, unsigned int count) + alloced = 1; + } else if (count != channels) { + error(_("You need to specify %d files"), channels); +- exit(EXIT_FAILURE); ++ prg_exit(EXIT_FAILURE); + } + + for (channel = 0; channel < channels; ++channel) { +@@ -2662,5 +2875,5 @@ static void capturev(char **names, unsigned int count) + if (alloced) + free(names); + if (ret) +- exit(ret); ++ prg_exit(ret); + } +diff --git a/speaker-test/speaker-test.c b/speaker-test/speaker-test.c +index 053ed3b..d8d68e2 100644 +--- a/speaker-test/speaker-test.c ++++ b/speaker-test/speaker-test.c +@@ -689,6 +689,7 @@ static int write_loop(snd_pcm_t *handle, int channel, int periods, uint8_t *fram + double phase = 0; + int err, n; + ++ fflush(stdout); + if (test_type == TEST_WAV) { + int bufsize = snd_pcm_frames_to_bytes(handle, period_size); + n = 0; diff --git a/alsa-utils.changes b/alsa-utils.changes index 127ef76..40c062c 100644 --- a/alsa-utils.changes +++ b/alsa-utils.changes @@ -1,3 +1,22 @@ +------------------------------------------------------------------- +Mon Mar 8 14:35:52 CET 2010 - tiwai@suse.de + +- Backport upstream fixes: + * aplay: Dump PCM state on xrun when verbose mode is active + * aplay - add option --process-id-file + * aplay -- add features for audio surveilance + * aplay -- update the man file + * amidi: fix port listing + * speaker-test: add fflush(stdout) to write_loop + * amixer: fix display of unreadable control elements + * amixer: add support for TLV dB minmax types + * alsactl: Fix return code + * alsamixer: fix division by zero + * alsamixer: handle out-of-range volume values + * alsactl: improve -d to get warnings and store exitcode to runstate file + * alsactl: add more debug prints to state.c + * alsactl: update debug prints in state.c + ------------------------------------------------------------------- Fri Dec 18 17:37:24 CET 2009 - tiwai@suse.de diff --git a/alsa-utils.spec b/alsa-utils.spec index 9b9b307..87a34da 100644 --- a/alsa-utils.spec +++ b/alsa-utils.spec @@ -1,7 +1,7 @@ # # spec file for package alsa-utils (Version 1.0.21) # -# Copyright (c) 2009 SUSE LINUX Products GmbH, Nuernberg, Germany. +# Copyright (c) 2010 SUSE LINUX Products GmbH, Nuernberg, Germany. # # All modifications and additions to the file contributed by third parties # remain the property of their copyright owners, unless otherwise agreed @@ -28,9 +28,9 @@ Requires: dialog pciutils AutoReqProv: on Summary: Advanced Linux Sound Architecture Utilities Version: 1.0.21 -Release: 3 +Release: 4 Source: ftp://ftp.alsa-project.org/pub/util/alsa-utils-%{package_version}.tar.bz2 -# Patch: alsa-utils-git-fixes.diff +Patch: alsa-utils-git-fixes.diff Patch1: alsa-utils-gettext-version-removal.diff # Patch2: alsa-utils-po-pre-patch.diff Url: http://www.alsa-project.org/ @@ -54,7 +54,7 @@ sed -i -e's/EXTRA_DIST= config.rpath /EXTRA_DIST=/' Makefile.am # fix po changes in tarball first # %patch2 -p1 # rm -f po/Makefile* po/*.gmo po/*.pot po/*.header po/stamp-* -# %patch -p1 +%patch -p1 %if %suse_version < 1020 %patch1 -p1 %endif