forked from pool/alsa-utils
8bb1df9742
OBS-URL: https://build.opensuse.org/package/show/multimedia:libs/alsa-utils?expand=0&rev=b4968bc00b3437042b1d724f426d3964
1431 lines
42 KiB
Diff
1431 lines
42 KiB
Diff
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=#<Hz>\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=<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 <file name>\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 <perex@perex.cz>\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;
|