From 16e5b4ae0665153fd652bf316c91d37f6d446da0 Mon Sep 17 00:00:00 2001 From: "F. Duncanh" Date: Sat, 22 Apr 2023 20:02:50 -0400 Subject: [PATCH] add ability to use a configuration file uxplayrc --- uxplay.cpp | 91 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 91 insertions(+) diff --git a/uxplay.cpp b/uxplay.cpp index 0d8dc3b..5efa4a1 100644 --- a/uxplay.cpp +++ b/uxplay.cpp @@ -28,6 +28,9 @@ #include #include #include +#include +#include +#include #ifdef _WIN32 /*modifications for Windows compilation */ #include @@ -39,6 +42,8 @@ #include #include #include +#include +#include # ifdef __linux__ # include # else @@ -269,6 +274,37 @@ static int parse_hw_addr (std::string str, std::vector &hw_addr) { return 0; } +static std::string find_uxplay_config_file() { + std::string no_config_file = ""; + const char *homedir = NULL; + const char *uxplayrc = NULL; + std::string config0, config1, config2; + struct stat sb; + uxplayrc = getenv("UXPLAYRC"); /* first look for $UXPLAYRC */ + if (uxplayrc) { + config0 = uxplayrc; + if (stat(config0.c_str(), &sb) == 0) return config0; + } + homedir = getenv("XDG_CONFIG_HOMEDIR"); + if (homedir == NULL) { + homedir = getenv("HOME"); + } +#ifndef _WIN32 + if (homedir == NULL){ + homedir = getpwuid(getuid())->pw_dir; + } +#endif + if (homedir) { + config1 = homedir; + config1.append("/.uxplayrc"); + if (stat(config1.c_str(), &sb) == 0) return config1; /* look for ~/.uxplayrc */ + config2 = homedir; + config2.append("/.config/uxplayrc"); /* look for ~/.config/uxplayrc */ + if (stat(config2.c_str(), &sb) == 0) return config2; + } + return no_config_file; +} + static std::string find_mac () { /* finds the MAC address of a network interface * * in a Windows, Linux, *BSD or macOS system. */ @@ -363,13 +399,16 @@ static std::string random_mac () { static void print_info (char *name) { printf("UxPlay %s: An open-source AirPlay mirroring server based on RPiPlay\n", VERSION); + printf("=========== Website: https://github.com/FDH2/UxPlay =============\n"); printf("Usage: %s [-n name] [-s wxh] [-p [n]]\n", name); printf("Options:\n"); printf("-n name Specify the network name of the AirPlay server\n"); printf("-nh Do not add \"@hostname\" at the end of the AirPlay server name\n"); printf("-vsync [x]Mirror mode: sync audio to video (default: stream w/o sync)\n"); printf(" x is optional audio delay in millisecs, can be neg., decimal\n"); + printf("-vsync no Switch off vsync audio/(server)video timestamp synchronization \n"); printf("-async [x]Audio-Only mode: sync audio to client video (default: no sync)\n"); + printf("-async no Switch off async audio/(client)video timestamp synchronization\n"); printf("-s wxh[@r]Set display resolution [refresh_rate] default 1920x1080[@60]\n"); printf("-o Set display \"overscanned\" mode on (not usually needed)\n"); printf("-fs Full-screen (only works with X11, Wayland and VAAPI)\n"); @@ -566,6 +605,11 @@ static void parse_arguments (int argc, char *argv[]) { } else if (arg == "-async") { audio_sync = true; if (i < argc - 1) { + if (strlen(argv[i+1]) == 2 && strncmp(argv[i+1], "no", 2) == 0) { + audio_sync = false; + i++; + continue; + } char *end; int n = (int) (strtof(argv[i + 1], &end) * 1000); if (*end == '\0') { @@ -581,6 +625,11 @@ static void parse_arguments (int argc, char *argv[]) { } else if (arg == "-vsync") { video_sync = true; if (i < argc - 1) { + if (strlen(argv[i+1]) == 2 && strncmp(argv[i+1], "no", 2) == 0) { + video_sync = false; + i++; + continue; + } char *end; int n = (int) (strtof(argv[i + 1], &end) * 1000); if (*end == '\0') { @@ -1252,9 +1301,47 @@ static void stop_raop_server () { return; } +static void read_config_file(const char * filename, const char * uxplay_name) { + std::string config_file = filename; + std::string option_char = "-"; + std::vector options; + options.push_back(uxplay_name); + std::ifstream file(config_file); + if (file.is_open()) { + fprintf(stdout,"UxPlay: reading configuration from %s\n", config_file.c_str()); + std::string line; + while (std::getline(file, line)) { + if (line[0] == '#') continue; + std::stringstream ss(line); + std::istream_iterator begin(ss); + std::istream_iterator end; + std::vector tokens(begin,end); + if (tokens.size() > 0) { + options.push_back(option_char + tokens[0]); + for (int i = 1; i < tokens.size(); i++) { + options.push_back(tokens[i].c_str()); + } + } + } + file.close(); + } else { + fprintf(stderr,"UxPlay: failed to open configuration file at %s\n", config_file.c_str()); + } + if (options.size() > 1) { + int argc = options.size(); + char **argv = (char **) malloc(sizeof(char*) * argc); + for (int i = 0; i < argc; i++) { + argv[i] = (char *) options[i].c_str(); + } + parse_arguments (argc, argv); + free (argv); + } +} + int main (int argc, char *argv[]) { std::vector server_hw_addr; std::string mac_address; + std::string config_file = ""; #ifdef SUPPRESS_AVAHI_COMPAT_WARNING // suppress avahi_compat nag message. avahi emits a "nag" warning (once) @@ -1263,6 +1350,10 @@ int main (int argc, char *argv[]) { if (!getenv("AVAHI_COMPAT_NOWARN")) putenv(avahi_compat_nowarn); #endif + config_file = find_uxplay_config_file(); + if (config_file.length()) { + read_config_file(config_file.c_str(), argv[0]); + } parse_arguments (argc, argv); #ifdef _WIN32 /* use utf-8 terminal output; don't buffer stdout in WIN32 when debug_log = false */