Makefile: doc: convert the AsciiDoc files (manpage & README)
[ng-jackspa.git] / jackspa-cli.c
blob01cb32ba8de5ae78a371c4837d8dcc36348ae2c2
1 /* jackspa-cli.c - simple CLI LADSPA host for the Jack Audio Connection Kit
2 * Copyright © 2013 Géraud Meyer <graud@gmx.com>
4 * This file is part of ng-jackspa.
6 * ng-jackspa is free software; you can redistribute it and/or modify it under
7 * the terms of the GNU General Public License version 2 as published by the
8 * Free Software Foundation.
10 * This program is distributed in the hope that it will be useful, but WITHOUT
11 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
12 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
13 * more details.
15 * You should have received a copy of the GNU General Public License along
16 * with ng-jackspa. If not, see <http://www.gnu.org/licenses/>.
19 #include <stdlib.h>
20 #include <stdio.h>
21 #include <unistd.h>
22 #include <signal.h>
23 #include <fcntl.h>
24 #include "jackspa.h"
25 #include "control.h"
27 #define PROGRAM_NAME "jackspa-cli"
28 #include "interface.c"
30 #define NOTIF_BACKGROUND "continuing to run in the background"
32 volatile sig_atomic_t stop_signaled = 0;
34 static void stop_handler(int s)
36 stop_signaled = 1;
39 static int tty = -1; /* controlling terminal or -1 */
41 static void background_handler(int s)
43 int i;
45 /* setup a child that will stop us then wake us up */
46 i = fork();
47 if (i < 0) {
48 /* error, use the default handler */
49 signal(SIGTSTP, SIG_DFL);
50 kill(0, SIGTSTP);
52 else if (i == 0) {
53 if (tty >= 0 && verbose)
54 write( STDOUT_FILENO, PROGRAM_NAME ": " NOTIF_BACKGROUND "\n",
55 sizeof(PROGRAM_NAME)-1 + 2 + sizeof(NOTIF_BACKGROUND)-1 + 1 );
56 /* make sure the parent is not in the foreground (or has no ctty) */
57 for (i = 1; tcgetpgrp(tty) == getpgid(getppid()); i <<= 1) {
58 kill(getppid(), SIGSTOP); /* let the shell regain control of the tty */
59 usleep(i), kill(getppid(), SIGCONT);
61 _exit(0);
65 volatile sig_atomic_t print_signaled = 0;
67 static void printcontrols_handler(int s)
69 print_signaled = 1;
72 void printcontrols_async(unsigned long c, controls_t controls)
74 if (!print_signaled) return;
76 for (; c; c--, controls++)
77 printf("%e\t# %s\n", *(*controls)->val, (*controls)->name);
78 print_signaled = 0;
81 int main(int argc, char *argv[])
83 int rc = 0;
85 tty = open("/dev/tty", O_NOCTTY);
87 /* Signals */
88 struct sigaction act;
89 act.sa_flags = 0;
90 rc = !sigemptyset(&act.sa_mask);
91 if (rc) {
92 /* SIGINT handler to exit gracefully */
93 act.sa_handler = stop_handler;
94 rc = !sigaction(SIGINT, &act, NULL) && rc;
95 /* SIGTTIN handler to avoid being stopped */
96 act.sa_handler = SIG_IGN;
97 rc = !sigaction(SIGTTIN, &act, NULL) && rc;
98 /* SIGTSTP handler to go into the background */
99 act.sa_handler = background_handler;
100 rc = !sigaction(SIGTSTP, &act, NULL) && rc;
101 /* SIGCHLD handler to avoid a child to become defunct */
102 act.sa_handler = SIG_IGN;
103 rc = !sigaction(SIGCHLD, &act, NULL) && rc;
104 /* SIGUSR1 to print the active values */
105 act.sa_handler = printcontrols_handler;
106 rc = !sigaction(SIGUSR1, &act, NULL) && rc;
108 if (!rc)
109 fputs(PROGRAM_NAME ": error while setting up the signal handlers\n", stderr);
111 /* Command line options */
112 GOptionContext *context = interface_context();
113 GError *error = NULL;
114 if (!g_option_context_parse(context, &argc, &argv, &error))
115 return (fprintf(stderr, "option parsing failed: %s\n", error->message), -1);
117 /* Initialize jackspa */
118 state_t state;
119 if (!jackspa_init(&state, argc, argv))
120 return 1;
122 /* Initialize the controls with the requested values */
123 unsigned long c;
124 controls_t controls;
125 if (control_buildall(&c, &controls, &state))
126 return 2;
128 /* Wait */
129 if (!isatty(fileno(stdin)))
130 while (!stop_signaled) {
131 printcontrols_async(c, controls);
132 sleep(-1);
134 else
135 while (!stop_signaled && !feof(stdin)) {
136 printcontrols_async(c, controls);
137 if (getpgrp() == tcgetpgrp(STDIN_FILENO))
138 /* we are in the foreground process group */
139 getchar();
140 else usleep(100000);
143 control_cleanupall(c, &controls);
144 jackspa_fini(&state);
146 return 0;