commit e541f8f411995b2aff33a5c599620f5a60fd730a
parent 3bf725a355e638cf0351887a603b85b9fc81daa8
Author: Jacob R. Edwards <jacobouno@protonmail.com>
Date: Thu, 15 Jul 2021 15:35:02 -0700
Separate player code into another program
This simplifies sigap and the player code. It also allows sigap to
manage any program (see the new -e option) aswell as users to have
just a simple audio player.
Additionally a README and license headers in source files were
added.
Diffstat:
A | README | | | 8 | ++++++++ |
A | ap.1 | | | 27 | +++++++++++++++++++++++++++ |
A | ap.c | | | 44 | ++++++++++++++++++++++++++++++++++++++++++++ |
M | apfd.c | | | 16 | ++++++++++++++++ |
M | die.c | | | 16 | ++++++++++++++++ |
D | main.c | | | 119 | ------------------------------------------------------------------------------- |
M | mkfile | | | 34 | ++++++++++++++++++++++------------ |
D | sigap | | | 0 | |
M | sigap.1 | | | 15 | ++++++++++++--- |
A | sigap.c | | | 135 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
10 files changed, 280 insertions(+), 134 deletions(-)
diff --git a/README b/README
@@ -0,0 +1,8 @@
+I made this because I wanted a truly simple (in both usage and
+implementation) way to play a variety of audio formats. While
+sndfile-play(1) would work well enough, it doesn't report errors
+in the way of it's exit status.
+
+The very simple ap(1) plays from the standard input or the given
+file. To facilitate a file queue and basic controls with signals
+sigap(1) is provided.
diff --git a/ap.1 b/ap.1
@@ -0,0 +1,27 @@
+.\" Copyright 2021 Jacob R. Edwards
+.Dd April 8, 2021
+.Dt AP 1
+.Os
+.Sh NAME
+.Nm ap
+.Nd simple audio player
+.Sh SYNOPSIS
+.Nm
+.Op Ar file
+.Sh DESCRIPTION
+The
+.Nm
+utility plays audio data from the standard input or, if given, from
+.Ar file .
+.Sh EXIT STATUS
+.Ex -std
+.Sh EXAMPLES
+Play the audio in
+.Pa file.ogg
+.Pp
+.Dl $ ap file.ogg
+.Sh SEE ALSO
+.Xr sigap 1 ,
+.Xr sndfile-play 1
+.Sh AUTHORS
+.An Jacob R. Edwards
diff --git a/ap.c b/ap.c
@@ -0,0 +1,44 @@
+/* Copyright 2021 Jacob R. Edwards
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <ao/ao.h>
+
+#include <fcntl.h>
+#include <stdio.h>
+
+#include "apfd.h"
+#include "die.h"
+
+int
+main(int argc, char *argv[])
+{
+ char *status;
+
+ if (argc > 2) {
+ fprintf(stderr, "usage: %s [file]\n", *argv);
+ return 1;
+ }
+
+ ao_initialize();
+ status = apfd(open(argv[1] ? argv[1] : "/dev/stdin", O_RDONLY));
+ ao_shutdown();
+
+ if (status) {
+ fprintf(stderr, "%s.\n", status);
+ return 1;
+ }
+ return 0;
+}
diff --git a/apfd.c b/apfd.c
@@ -1,3 +1,19 @@
+/* Copyright 2021 Jacob R. Edwards
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
#include <ao/ao.h>
#include <sndfile.h>
diff --git a/die.c b/die.c
@@ -1,3 +1,19 @@
+/* Copyright 2021 Jacob R. Edwards
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
#include <stdio.h>
#include <stdlib.h>
diff --git a/main.c b/main.c
@@ -1,119 +0,0 @@
-#include <ao/ao.h>
-
-#include <sys/wait.h>
-
-#include <fcntl.h>
-#include <signal.h>
-#include <stdio.h>
-#include <unistd.h>
-
-#include "apfd.h"
-#include "die.h"
-
-enum state {
- OFF,
- STOPPED,
- RUNNING,
-};
-
-static struct player {
- char *path;
- int state;
- int status;
- pid_t pid;
-} player;
-
-static int persist;
-
-void
-signals(void (*func)(int))
-{
- signal(SIGCHLD, func);
- signal(SIGINFO, func);
- signal(SIGINT, func);
-}
-
-void
-handle(int sig)
-{
- int status;
-
- switch (sig) {
- case SIGINFO:
- puts(player.path);
- break;
- case SIGINT:
- if (player.state != OFF && kill(player.pid, SIGTERM))
- perror("kill");
- break;
- case SIGCHLD:
- while ((waitpid(player.pid, &status, 0)) != -1) {
- if (WIFEXITED(status)) {
- player.state = OFF;
- player.status = WEXITSTATUS(status);
- } else if (WIFSIGNALED(status)) {
- player.state = OFF;
- } else if (WIFSTOPPED(status)) {
- player.state = STOPPED;
- } else if (WIFCONTINUED(status)) {
- player.state = RUNNING;
- }
- }
- break;
- }
-}
-
-int
-play(char *path)
-{
- char *status;
-
- player.state = RUNNING;
- player.path = path;
- player.pid = fork();
- if (player.pid != 0) {
- if (player.pid == -1)
- player.state = OFF;
- return player.pid == -1;
- }
-
- signals(SIG_DFL);
- if ((status = apfd(open(path, O_RDONLY)))) {
- fprintf(stderr, "%s: %s.\n", path, status);
- _exit(1);
- }
- _exit(0);
-}
-
-int
-main(int argc, char *argv[])
-{
- int c;
- int i;
-
- while ((c = getopt(argc, argv, "p")) != -1) {
- switch (c) {
- case 'p':
- persist = 1;
- break;
- default:
- fprintf(stderr, "usage: %s [-p] [file ...]\n", *argv);
- return 1;
- }
- }
- argc -= optind;
- argv += optind;
-
- ao_initialize();
- signals(handle);
-
- for (i = 0; i < argc && (persist || player.status == 0); ++i) {
- if (play(argv[i]))
- die(argv[i]);
- while (player.state != OFF)
- pause();
- }
-
- ao_shutdown();
- return player.status;
-}
diff --git a/mkfile b/mkfile
@@ -6,25 +6,35 @@ ldlibs = -lc -lsndfile -lao
prefix = /usr/local
manprefix = $prefix/man
-name = sigap
-src = apfd.c main.c die.c
-obj = ${src:%.c=%.o}
+names = sigap ap
+src = apfd.c die.c
+libobj = ${src:%.c=%.o}
+obj = ${names:%=%.o} $libobj
-all:V: $name
+all:V: $names
%.o: %.c
$cc $cppflags $cflags -c -o $stem.o $stem.c
-$name: $obj
- $cc $ldflags -o $target $prereq $ldlibs
+$names: $obj
+ for name in $target
+ do
+ $cc $ldflags -o $name $name.o $libobj $ldlibs
+ done
clean:V:
- rm -f $name $obj
+ rm -f $names $obj
-install:V: $name
- cp -f $name $prefix/bin
- cp -f $name.1 $manprefix/man1
+install:V: $names
+ for name in $names
+ do
+ cp -f $name $prefix/bin
+ cp -f $name.1 $manprefix/man1
+ done
uninstall:V:
- rm -f $prefix/bin/$name
- rm -f $manprefix/man1/$name.1
+ for name in $names
+ do
+ rm -f $prefix/bin/$name
+ rm -f $manprefix/man1/$name.1
+ done
diff --git a/sigap b/sigap
Binary files differ.
diff --git a/sigap.1 b/sigap.1
@@ -8,17 +8,25 @@
.Sh SYNOPSIS
.Nm
.Op Fl p
+.Op Fl e Ar player
.Ar file ...
.Sh DESCRIPTION
The
.Nm
-audio player plays the given files while waiting for signals to
-control it. The
+utility plays the given files while waiting for signals to control
+it. The
.Dv SIGINT
-signal skips current file, SIGINFO displays current filename.
+signal skips current file and
+.Dv SIGINFO
+displays current filename.
.Pp
The options are as follows:
.Bl -tag -width indent
+.It Fl e
+Use
+.Ar player
+instead of the default
+.Pa ap .
.It Fl p
Ignore player errors.
.El
@@ -31,6 +39,7 @@ directory:
.Pp
.Dl $ bigap music/*
.Sh SEE ALSO
+.Xr ap 1 ,
.Xr sndfile-play 1
.Sh AUTHORS
.An Jacob R. Edwards
diff --git a/sigap.c b/sigap.c
@@ -0,0 +1,135 @@
+/* Copyright 2021 Jacob R. Edwards
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <sys/wait.h>
+
+#include <fcntl.h>
+#include <signal.h>
+#include <stdio.h>
+#include <unistd.h>
+
+#include "apfd.h"
+#include "die.h"
+
+enum state {
+ OFF,
+ STOPPED,
+ RUNNING,
+};
+
+static struct player {
+ char *path;
+ int state;
+ int status;
+ pid_t pid;
+} player;
+
+static char *ap[] = { "ap", NULL };
+static int persist;
+
+void
+handle(int sig)
+{
+ int status;
+
+ switch (sig) {
+ case SIGINFO:
+ puts(player.path);
+ break;
+ case SIGINT:
+ if (player.state != OFF && kill(player.pid, SIGTERM))
+ perror("kill");
+ break;
+ case SIGCHLD:
+ while ((waitpid(player.pid, &status, 0)) != -1) {
+ if (WIFEXITED(status)) {
+ player.state = OFF;
+ player.status = WEXITSTATUS(status);
+ } else if (WIFSIGNALED(status)) {
+ player.state = OFF;
+ } else if (WIFSTOPPED(status)) {
+ player.state = STOPPED;
+ } else if (WIFCONTINUED(status)) {
+ player.state = RUNNING;
+ }
+ }
+ break;
+ }
+}
+
+int
+play(char *path)
+{
+ char *status;
+
+ player.state = RUNNING;
+ player.path = path;
+ player.pid = fork();
+ if (player.pid != 0) {
+ if (player.pid == -1)
+ player.state = OFF;
+ return player.pid == -1;
+ }
+
+ if (dup2(open(path, O_RDONLY), 0) == -1)
+ die(path);
+ execvp(*ap, ap);
+ perror(*ap);
+ _exit(1);
+}
+
+int
+main(int argc, char *argv[])
+{
+ int c;
+ int i;
+
+#ifdef __OpenBSD__
+ if (pledge("stdio rpath proc exec", NULL) == -1)
+ die("pledge");
+#endif
+
+ while ((c = getopt(argc, argv, "e:p")) != -1) {
+ switch (c) {
+ case 'e':
+ *ap = optarg;
+ break;
+ case 'p':
+ persist = 1;
+ break;
+ default:
+ fprintf(stderr, "usage: %s [-p] [-e player] [file ...]\n",
+ *argv);
+ return 1;
+ }
+ }
+ argc -= optind;
+ argv += optind;
+
+ signal(SIGCHLD, handle);
+ signal(SIGINFO, handle);
+ signal(SIGINT, handle);
+
+ for (i = 0; i < argc && (persist || player.status == 0); ++i) {
+ if (play(argv[i]))
+ die(argv[i]);
+ puts(player.path);
+ while (player.state != OFF)
+ pause();
+ }
+
+ return player.status;
+}