Add -w option to display variables periodically
authorratchov <ratchov@openbsd.org>
Sun, 8 Jan 2023 06:58:07 +0000 (06:58 +0000)
committerratchov <ratchov@openbsd.org>
Sun, 8 Jan 2023 06:58:07 +0000 (06:58 +0000)
The purpose of -w is to monitor underruns without triggering long
kernel code-paths (ex. fork and exec of new audioctl process) that may
cause additional underruns than the ones being monitored.

ok chehola, edd

usr.bin/audioctl/audioctl.8
usr.bin/audioctl/audioctl.c

index 2559240..4d75a40 100644 (file)
@@ -1,4 +1,4 @@
-.\" $OpenBSD: audioctl.8,v 1.4 2020/04/23 00:16:59 schwarze Exp $
+.\" $OpenBSD: audioctl.8,v 1.5 2023/01/08 06:58:07 ratchov Exp $
 .\" $NetBSD: audioctl.1,v 1.7 1998/04/27 16:55:23 augustss Exp $
 .\" Copyright (c) 1997 The NetBSD Foundation, Inc.
 .\" All rights reserved.
@@ -26,7 +26,7 @@
 .\" ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 .\" POSSIBILITY OF SUCH DAMAGE.
 .\"
-.Dd $Mdocdate: April 23 2020 $
+.Dd $Mdocdate: January 8 2023 $
 .Dt AUDIOCTL 8
 .Os
 .Sh NAME
 .Sh SYNOPSIS
 .Nm audioctl
 .Op Fl f Ar file
+.Op Fl w Ar wait
 .Nm audioctl
 .Op Fl n
 .Op Fl f Ar file
+.Op Fl w Ar wait
 .Ar name ...
 .Nm audioctl
 .Op Fl nq
@@ -59,6 +61,12 @@ The default is
 Suppress printing of the variable name.
 .It Fl q
 Suppress all output when setting a variable.
+.It Fl w Ar wait
+Pause
+.Ar wait
+seconds between each display.
+.Nm
+will display variables forever.
 .It Ar name Ns = Ns Ar value
 Attempt to set the specified variable
 .Ar name
@@ -130,10 +138,10 @@ audio control devices
 audio devices
 .El
 .Sh EXAMPLES
-Display the number of bytes of silence inserted during play buffer
-underruns since device started:
+Once per-second, display the number of bytes of silence inserted due to buffer
+underruns (since the device started playback):
 .Bd -literal -offset indent
-# audioctl play.errors
+# audioctl -w 1 play.errors
 .Ed
 .Pp
 Use signed 24-bit samples and 44100Hz sample rate:
index fde1690..e9bf643 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: audioctl.c,v 1.44 2022/12/26 19:16:00 jmc Exp $       */
+/*     $OpenBSD: audioctl.c,v 1.45 2023/01/08 06:58:07 ratchov Exp $   */
 /*
  * Copyright (c) 2016 Alexandre Ratchov <alex@caoua.org>
  *
@@ -43,6 +43,7 @@ struct field {
 #define STR    2
 #define ENC    3
        int type;
+       int show;
        int set;
 } fields[] = {
        {"name",                &rname.name,            NULL,           STR},
@@ -63,11 +64,11 @@ struct field {
 };
 
 const char usagestr[] =
-       "usage: audioctl [-f file]\n"
-       "       audioctl [-n] [-f file] name ...\n"
+       "usage: audioctl [-f file] [-w wait_sec]\n"
+       "       audioctl [-n] [-f file] [-w wait_sec] name ...\n"
        "       audioctl [-nq] [-f file] name=value ...\n";
 
-int fd, show_names = 1, quiet = 0;
+int fd, show_names = 1, quiet = 0, wait_sec = 0;
 
 /*
  * parse encoding string (examples: s8, u8, s16, s16le, s24be ...)
@@ -198,20 +199,9 @@ audio_main(int argc, char **argv)
        char *lhs, *rhs;
        int set = 0;
 
-       if (ioctl(fd, AUDIO_GETSTATUS, &rstatus) == -1)
-               err(1, "AUDIO_GETSTATUS");
-       if (ioctl(fd, AUDIO_GETDEV, &rname) == -1)
-               err(1, "AUDIO_GETDEV");
-       if (ioctl(fd, AUDIO_GETPAR, &rpar) == -1)
-               err(1, "AUDIO_GETPAR");
-       if (ioctl(fd, AUDIO_GETPOS, &rpos) == -1)
-               err(1, "AUDIO_GETPOS");
        if (argc == 0) {
-               for (f = fields; f->name != NULL; f++) {
-                       printf("%s=", f->name);
-                       print_field(f, f->raddr);
-                       printf("\n");
-               }
+               for (f = fields; f->name != NULL; f++)
+                       f->show = 1;
        }
        AUDIO_INITPAR(&wpar);
        for (; argc > 0; argc--, argv++) {
@@ -231,15 +221,41 @@ audio_main(int argc, char **argv)
                        parse_field(f, f->waddr, rhs);
                        f->set = 1;
                        set = 1;
-               } else {
+               } else
+                       f->show = 1;
+       }
+
+       if (set && wait_sec)
+               errx(1, "Can't set variables wait_secically");
+
+       while (1) {
+               if (ioctl(fd, AUDIO_GETSTATUS, &rstatus) == -1)
+                       err(1, "AUDIO_GETSTATUS");
+               if (ioctl(fd, AUDIO_GETDEV, &rname) == -1)
+                       err(1, "AUDIO_GETDEV");
+               if (ioctl(fd, AUDIO_GETPAR, &rpar) == -1)
+                       err(1, "AUDIO_GETPAR");
+               if (ioctl(fd, AUDIO_GETPOS, &rpos) == -1)
+                       err(1, "AUDIO_GETPOS");
+               for (f = fields; f->name != NULL; f++) {
+                       if (!f->show)
+                               continue;
                        if (show_names)
                                printf("%s=", f->name);
                        print_field(f, f->raddr);
                        printf("\n");
                }
+
+               if (wait_sec == 0)
+                       break;
+
+               /* ioctls are fast, we neglect drift from real-time clock */
+               sleep(wait_sec);
        }
+
        if (!set)
                return;
+
        if (ioctl(fd, AUDIO_SETPAR, &wpar) == -1)
                err(1, "AUDIO_SETPAR");
        if (ioctl(fd, AUDIO_GETPAR, &wpar) == -1)
@@ -261,9 +277,10 @@ int
 main(int argc, char **argv)
 {
        char *path = "/dev/audioctl0";
+       const char *errstr;
        int c;
 
-       while ((c = getopt(argc, argv, "anf:q")) != -1) {
+       while ((c = getopt(argc, argv, "anf:qw:")) != -1) {
                switch (c) {
                case 'a':       /* ignored, compat */
                        break;
@@ -276,6 +293,11 @@ main(int argc, char **argv)
                case 'q':
                        quiet = 1;
                        break;
+               case 'w':
+                       wait_sec = strtonum(optarg, 1, INT_MAX, &errstr);
+                       if (errstr != NULL)
+                               errx(1, "wait is %s: %s", errstr, optarg);
+                       break;
                default:
                        fputs(usagestr, stderr);
                        return 1;