At Mon, 23 May 2011 13:55:44 -0700, Stephen Warren wrote:
Jaroslav,
In recent versions of aplay, if I try to either run them in the background, or run them in the foreground, then ^Z and bg them, they hang indefinitely:
aplay foo.wav & # doesn't play anything
aplay foo.wav ... ^Z bg [1]+ Stopped aplay foo.wav bg [1]+ Stopped aplay foo.wav
At least, this is true under ChromeOS on ARM with kernel 2.6.38 and ALSA 1.0.24.2, or an Ubuntu Natty rootstock on ARM with the same ChromeOS kernel.
This was introduced by alsa-utils commit: 3bd65336222a4d00cefc4db5e74a7a96c07ab567 aplay/arecord: Added hardware pause support (press SPACE or Enter)
What happens is that the call to tcsetattr causes the process to receive signal TTOU and be stopped. Running under strace yields an infinite loop with ioctl(TCSETS) returning -ERESTARTSYS, and being retried.
I believe this is related to http://lkml.org/lkml/2008/6/2/157.
I'm not exactly sure how to solve this though. Another post in that thread implied that adding a signal handler for TTOU and then adjusting the tcsetattr settings might help, but I'm not convinced about that, since I believe the -ERESTARTSYS handling loop is inside the call to tcsetattr, and hence tcsetattr's parameters can't be changed.
Does anyone have any ideas? Thanks.
IMO, it's safer to add an option for interactive mode like below. As aplay has been used since long time ago, we shouldn't introduce any regression to this basic program.
thanks,
Takashi
--- diff --git a/aplay/aplay.1 b/aplay/aplay.1 index b6caf0b..8cd1d56 100644 --- a/aplay/aplay.1 +++ b/aplay/aplay.1 @@ -137,6 +137,10 @@ by typing aplay. Record. This is the default if the program is invoked by typing arecord. .TP +\fI-i, --interactive\fP +Allow interactive operation via stdin. +Currently only pause/resume via space key is implemented. +.TP \fI--disable-resample\fP Disable automatic rate resample. .TP diff --git a/aplay/aplay.c b/aplay/aplay.c index c09f23c..04959b8 100644 --- a/aplay/aplay.c +++ b/aplay/aplay.c @@ -103,6 +103,7 @@ static int avail_min = -1; static int start_delay = 0; static int stop_delay = 0; static int monotonic = 0; +static int interactive = 0; static int can_pause = 0; static int verbose = 0; static int vumeter = VUMETER_NONE; @@ -200,6 +201,7 @@ _("Usage: %s [OPTION]... [FILE]...\n" "-v, --verbose show PCM structure and setup (accumulative)\n" "-V, --vumeter=TYPE enable VU meter (TYPE: mono or stereo)\n" "-I, --separate-channels one file for each channel\n" +"-i, --interactive allow interactive operation from stdin\n" " --disable-resample disable automatic rate resample\n" " --disable-channels disable automatic channel conversions\n" " --disable-format disable automatic format conversions\n" @@ -404,7 +406,7 @@ enum { int main(int argc, char *argv[]) { int option_index; - static const char short_options[] = "hnlLD:qt:c:f:r:d:MNF:A:R:T:B:vV:IPC"; + static const char short_options[] = "hnlLD:qt:c:f:r:d:MNF:A:R:T:B:vV:IPCi"; static const struct option long_options[] = { {"help", 0, 0, 'h'}, {"version", 0, 0, OPT_VERSION}, @@ -442,6 +444,7 @@ int main(int argc, char *argv[]) {"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}, + {"interactive", 0, 0, 'i'}, {0, 0, 0, 0} }; char *pcm_name = "default"; @@ -608,6 +611,9 @@ int main(int argc, char *argv[]) if (file_type == FORMAT_DEFAULT) file_type = FORMAT_WAVE; break; + case 'i': + interactive = 1; + break; case OPT_DISABLE_RESAMPLE: open_mode |= SND_PCM_NO_AUTO_RESAMPLE; break; @@ -1206,6 +1212,8 @@ static void init_stdin(void) struct termios term; long flags;
+ if (!interactive) + return; tcgetattr(fileno(stdin), &term); term_c_lflag = term.c_lflag; if (fd == fileno(stdin)) @@ -1221,6 +1229,8 @@ static void done_stdin(void) { struct termios term;
+ if (!interactive) + return; if (fd == fileno(stdin) || term_c_lflag == -1) return; tcgetattr(fileno(stdin), &term); @@ -1258,6 +1268,8 @@ static void check_stdin(void) { unsigned char b;
+ if (!interactive) + return; if (fd != fileno(stdin)) { while (read(fileno(stdin), &b, 1) == 1) { if (b == ' ' || b == '\r') {