sigap

Simplest audio player possible bundled signal based queue manager
Log | Files | Refs | README | LICENSE

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:
AREADME | 8++++++++
Aap.1 | 27+++++++++++++++++++++++++++
Aap.c | 44++++++++++++++++++++++++++++++++++++++++++++
Mapfd.c | 16++++++++++++++++
Mdie.c | 16++++++++++++++++
Dmain.c | 119-------------------------------------------------------------------------------
Mmkfile | 34++++++++++++++++++++++------------
Dsigap | 0
Msigap.1 | 15++++++++++++---
Asigap.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; +}