add ability to use a configuration file uxplayrc

This commit is contained in:
F. Duncanh
2023-04-22 20:02:50 -04:00
parent 96333754be
commit 16e5b4ae06

View File

@@ -28,6 +28,9 @@
#include <string>
#include <vector>
#include <fstream>
#include <sstream>
#include <iterator>
#include <sys/stat.h>
#ifdef _WIN32 /*modifications for Windows compilation */
#include <glib.h>
@@ -39,6 +42,8 @@
#include <sys/utsname.h>
#include <sys/socket.h>
#include <ifaddrs.h>
#include <sys/types.h>
#include <pwd.h>
# ifdef __linux__
# include <netpacket/packet.h>
# else
@@ -269,6 +274,37 @@ static int parse_hw_addr (std::string str, std::vector<char> &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<std::string> 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<std::string> begin(ss);
std::istream_iterator<std::string> end;
std::vector<std::string> 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<char> 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 */