#include #include #include #include #include #include #include #include #include #include #include "trivmix.h" #define PIDFILE "pid" #define INPUTFILE "input" #define OUTPUTFILE "output" #define NAMEFILE "name" #define GAINFILE "gain" #define DIRMODE S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH #define FILEMODE S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH #define INOTIFYBUFLEN 1024 * (sizeof(struct inotify_event) + 16) #define NOTIFYMASK IN_MODIFY | IN_CREATE | IN_DELETE | IN_ONESHOT mixState state = { .input = NULL, .output = NULL, .name = NULL, .dBGain = -90 }; char *workdir; char *inotifyBuffer; bool changedDir = false; void initState() { const char *defaultName = "mixer"; state.input = malloc(sizeof(char)); *(state.input) = '\0'; state.output = malloc(sizeof(char)); *(state.output) = '\0'; state.name = malloc(sizeof(char) * (1 + strlen(defaultName))); strcpy(state.name, defaultName); } void signalHandler(int signal) { fprintf(stderr, "Received signal: %d\n", signal); cleanExit(1); } void setupSignalHandler() { signal(SIGABRT, signalHandler); signal(SIGFPE, SIG_IGN); signal(SIGILL, SIG_IGN); signal(SIGINT, signalHandler); signal(SIGTERM, signalHandler); signal(SIGSEGV, signalHandler); } void parseArgs(int argc, char *argv[]) { char opt; while ((opt = getopt(argc, argv, "g:n:i:o:")) != -1) { switch (opt) { case 'g': sscanf(optarg, "%f", &(state.dBGain)); break; case 'n': state.name = realloc(state.name, sizeof(char) * (1 + strlen(optarg))); strcpy(state.name, optarg); break; case 'i': state.input = realloc(state.input, sizeof(char) * (1 + strlen(optarg))); strcpy(state.input, optarg); break; case 'o': state.output = realloc(state.output, sizeof(char) * (1 + strlen(optarg))); strcpy(state.output, optarg); break; } } if (optind > argc - 1) { fprintf(stderr, "Usage: %s [-g {gain}] [-n {name}] [-i {input}] [-o {output}] {working directory}\n", argv[0]); cleanExit(2); } workdir = argv[optind++]; } void setWorkdir() { if (!(mkdir(workdir, DIRMODE) == 0 || errno == EEXIST) || chdir(workdir) == -1) errMsg(1, &errno, "Failed to change to workdir", workdir); changedDir = true; } void writePid() { FILE *pidFile; openSyncFile(&pidFile, PIDFILE, "wx", false); if (fprintf(pidFile, "%d\n", getpid()) <= 1) errMsg(1, &errno, "Failed to write to pidfile", PIDFILE); fclose(pidFile); } void syncState() { readState(); writeState(); } void readState() { FILE *pidFile; FILE *inputFile; FILE *outputFile; FILE *nameFile; FILE *gainFile; int newInt; char newString[64]; float newFloat; int ret; if (openSyncFile(&pidFile, PIDFILE, "r", true) == -1) { ret = fscanf(pidFile, "%d", &newInt); fclose(pidFile); if (ret == 0 || ret == EOF || newInt != getpid()) cleanExit(0); } else cleanExit(0); if (openSyncFile(&inputFile, INPUTFILE, "r", true) == -1) { ret = fscanf(inputFile, "%63s", newString); fclose(inputFile); if (ret != 0 && ret != EOF) { // TODO Try to set new jack input here state.input = realloc(state.input, sizeof(char) * (1 + strlen(newString))); strcpy(state.input, newString); } } if (openSyncFile(&outputFile, OUTPUTFILE, "r", true) == -1) { ret = fscanf(outputFile, "%63s", newString); fclose(outputFile); if (ret != 0 && ret != EOF) { // TODO Try to set new jack output here state.output = realloc(state.output, sizeof(char) * (1 + strlen(newString))); strcpy(state.output, newString); } } if (openSyncFile(&gainFile, GAINFILE, "r", true) == -1) { ret = fscanf(gainFile, "%f", &newFloat); fclose(gainFile); if (ret != 0 && ret != EOF) { if (newFloat < -90) newFloat = -90; state.dBGain = newFloat; } } } void writeState() { FILE *pidFile; FILE *inputFile; FILE *outputFile; FILE *nameFile; FILE *gainFile; int ret; openSyncFile(&pidFile, PIDFILE, "w", false); ret = fprintf(pidFile, "%d\n", getpid()); if (ret < 1) errMsg(1, &errno, "Failed to write pidfile", PIDFILE); fclose(pidFile); openSyncFile(&inputFile, INPUTFILE, "w", false); ret = fprintf(inputFile, "%s\n", state.input); if (ret < 1) errMsg(1, &errno, "Failed to write file", INPUTFILE); fclose(inputFile); openSyncFile(&outputFile, OUTPUTFILE, "w", false); ret = fprintf(outputFile, "%s\n", state.output); if (ret < 1) errMsg(1, &errno, "Failed to write file", OUTPUTFILE); fclose(outputFile); openSyncFile(&nameFile, NAMEFILE, "w", false); ret = fprintf(nameFile, "%s\n", state.name); if (ret < 1) errMsg(1, &errno, "Failed to write file", NAMEFILE); fclose(nameFile); openSyncFile(&gainFile, GAINFILE, "w", false); ret = fprintf(gainFile, "%.2f\n", state.dBGain); if (ret < 1) errMsg(1, &errno, "Failed to write file", GAINFILE); fclose(gainFile); } int openSyncFile(FILE **file, char *fileName, char *fileMode, bool errOK) { int ret = -1; if ((*file = fopen(fileName, fileMode)) == NULL) { if (errOK == false) errMsg(1, &errno, "Failed to open file", fileName); else { ret = errno; } } return ret; } int main(int argc, char *argv[]) { int inotifyFD; initState(); inotifyBuffer = malloc(INOTIFYBUFLEN); setupSignalHandler(); parseArgs(argc, argv); setWorkdir(); writePid(); writeState(); inotifyFD = inotify_init(); if (inotifyFD < 0) errMsg(1, NULL, "Failed to setup inotify", NULL); do { syncState(); printf("State:\n input = %s\n output = %s\n name = %s\n gain = %.2fdB\n", state.input, state.output, state.name, state.dBGain); inotify_add_watch(inotifyFD, ".", NOTIFYMASK); } while (read(inotifyFD, inotifyBuffer, INOTIFYBUFLEN) >= 0); exit(0); } void cleanExit(int r) { if (changedDir == true) { if (unlink(PIDFILE) != 0 && errno != ENOENT) errMsg(-1, &errno, "Failed to delete pidfile", PIDFILE); } free(state.input); free(state.output); free(state.name); free(inotifyBuffer); exit(r); } void errMsg(int r, int *errno, char *head, char *detail) { int err; bool error = false; if (errno != NULL) { error = true; err = *errno; } fprintf(stderr, "%s\n", head); if (detail != NULL) fprintf(stderr, " %s\n", detail); if (error == true) fprintf(stderr, " (%d) %s\n", err, strerror(err)); if (r >= 0) cleanExit(r); }