diff --git a/client/Makefile b/client/Makefile index 841f75b6..c0bcb63d 100644 --- a/client/Makefile +++ b/client/Makefile @@ -2,10 +2,12 @@ VERSION = 0.3.90 TARGET = snapclient SHELL = /bin/bash +#CXX = /home/johannes/Develop/android-ndk-r10e-arm-21/bin/arm-linux-androideabi-g++ +#CFLAGS = -std=c++0x -Wall -Wno-unused-function -O3 -pthread -DASIO_STANDALONE -DVERSION=\"$(VERSION)\" -I.. -I../externals/asio/asio/include -I../externals/tclap/include -I../externals/ezOptionParser -I/home/johannes/Develop/build/arm/include -L/home/johannes/Develop/build/arm/lib + CXX = /usr/bin/g++ -CFLAGS = -std=c++0x -Wall -Wno-unused-function -O3 -pthread -DVERSION=\"$(VERSION)\" -I.. -I../externals/asio/asio/include -#CFLAGS = -std=c++0x -Wall -Wno-unused-function -O3 -pthread -DVERSION=\"$(VERSION)\" -I.. -static-libgcc -static-libstdc++ -LDFLAGS = -lrt -lboost_system -lboost_program_options -lasound -logg -lvorbis -lvorbisenc -lFLAC -lavahi-client -lavahi-common +CFLAGS = -std=c++0x -Wall -Wno-unused-function -O3 -pthread -DASIO_STANDALONE -DVERSION=\"$(VERSION)\" -I.. -I../externals/asio/asio/include -I../externals/tclap/include -I../externals/ezOptionParser +LDFLAGS = -lrt -lasound -logg -lvorbis -lvorbisenc -lFLAC -lavahi-client -lavahi-common OBJ = snapClient.o stream.o clientConnection.o timeProvider.o player/player.o player/alsaPlayer.o decoder/oggDecoder.o decoder/pcmDecoder.o decoder/flacDecoder.o controller.o browseAvahi.o ../message/pcmChunk.o ../common/log.o ../message/sampleFormat.o BIN = snapclient diff --git a/client/snapClient.cpp b/client/snapClient.cpp index 8d44e833..6b685495 100644 --- a/client/snapClient.cpp +++ b/client/snapClient.cpp @@ -18,18 +18,17 @@ #include #include -#include +#include -#include "common/daemon.h" -#include "common/log.h" -#include "common/signalHandler.h" #include "controller.h" #include "player/alsaPlayer.h" #include "browseAvahi.h" +#include "common/daemon.h" +#include "common/log.h" +#include "common/signalHandler.h" using namespace std; -namespace po = boost::program_options; bool g_terminated = false; @@ -58,76 +57,113 @@ PcmDevice getPcmDevice(const std::string& soundcard) } -int main (int argc, char *argv[]) +int main (int argc, char **argv) { try { - string soundcard; - string host; - // int bufferMs; - size_t port; - size_t latency; - int runAsDaemon; - bool listPcmDevices; + string soundcard("default"); + string host(""); + size_t port(1704); + size_t latency(0); + bool runAsDaemon(false); + int processPriority(-3); - po::options_description desc("Allowed options"); - desc.add_options() - ("help", "produce help message") - ("version,v", "show version number") - ("list,l", po::bool_switch(&listPcmDevices)->default_value(false), "list pcm devices") - ("host,h", po::value(&host), "server hostname or ip address") - ("port,p", po::value(&port)->default_value(1704), "server port") - ("soundcard,s", po::value(&soundcard)->default_value("default"), "index or name of the soundcard") - ("daemon,d", po::value(&runAsDaemon)->implicit_value(-3), "daemonize, optional process priority [-20..19]") - ("latency", po::value(&latency)->default_value(0), "latency of the soundcard") - ; + while (1) + { + int option_index = 0; + static struct option long_options[] = + { + {"help", no_argument, 0, '?'}, + {"version", no_argument, 0, 'v'}, + {"list", no_argument, 0, 'l'}, + {"host", required_argument, 0, 'h'}, + {"port", required_argument, 0, 'p'}, + {"soundcard", required_argument, 0, 's'}, + {"daemon", optional_argument, 0, 'd'}, + {"latency", required_argument, 0, 0 }, + {0, 0, 0, 0 } + }; + + char c = getopt_long(argc, argv, "?vlh:p:s:d::", long_options, &option_index); + if (c == -1) + break; + + switch (c) + { + case 0: + if (strcmp(long_options[option_index].name, "latency") == 0) + latency = atoi(optarg); + break; + + case 'v': + cout << "snapclient v" << VERSION << "\n" + << "Copyright (C) 2014, 2015 BadAix (snapcast@badaix.de).\n" + << "License GPLv3+: GNU GPL version 3 or later .\n" + << "This is free software: you are free to change and redistribute it.\n" + << "There is NO WARRANTY, to the extent permitted by law.\n\n" + << "Written by Johannes M. Pohl.\n\n"; + exit(EXIT_SUCCESS); + + case 'l': + { + vector pcmDevices = AlsaPlayer::pcm_list(); + for (auto dev: pcmDevices) + { + cout << dev.idx << ": " << dev.name << "\n" + << dev.description << "\n\n"; + } + exit(EXIT_SUCCESS); + } + + case 'h': + host = optarg; + break; + + case 'p': + port = atoi(optarg); + break; + + case 's': + soundcard = optarg; + break; + + case 'd': + runAsDaemon = true; + if (optarg) + processPriority = atoi(optarg); + break; + + default: //? + cout << "Allowed options:\n\n" + << " --help \t\t produce help message\n" + << " -v, --version \t\t show version number\n" + << " -l, --list \t\t list pcm devices\n" + << " -h, --host arg \t\t server hostname or ip address\n" + << " -p, --port arg (=" << port << ")\t server port\n" + << " -s, --soundcard arg(=" << soundcard << ")\t index or name of the soundcard\n" + << " -d, --daemon [arg(=" << processPriority << ")]\t daemonize, optional process priority [-20..19]\n" + << " --latency arg(=" << latency << ")\t\t latency of the soundcard [ms]\n" + << "\n"; + exit(EXIT_FAILURE); + } + } - po::variables_map vm; - po::store(po::parse_command_line(argc, argv, desc), vm); - po::notify(vm); std::clog.rdbuf(new Log("snapclient", LOG_DAEMON)); - if (vm.count("help")) - { - cout << desc << "\n"; - return 1; - } + signal(SIGHUP, signal_handler); + signal(SIGTERM, signal_handler); + signal(SIGINT, signal_handler); - if (vm.count("version")) - { - cout << "snapclient v" << VERSION << "\n" - << "Copyright (C) 2014 BadAix (snapcast@badaix.de).\n" - << "License GPLv3+: GNU GPL version 3 or later .\n" - << "This is free software: you are free to change and redistribute it.\n" - << "There is NO WARRANTY, to the extent permitted by law.\n\n" - << "Written by Johannes M. Pohl.\n"; - return 1; - } - - if (listPcmDevices) - { - vector pcmDevices = AlsaPlayer::pcm_list(); - for (auto dev: pcmDevices) - { - cout << dev.idx << ": " << dev.name << "\n" - << dev.description << "\n\n"; - } - return 1; - } - - signal(SIGHUP, signal_handler); - signal(SIGTERM, signal_handler); - signal(SIGINT, signal_handler); - - if (vm.count("daemon")) + if (runAsDaemon) { daemonize("/var/run/snapclient.pid"); - if (runAsDaemon < -20) - runAsDaemon = -20; - else if (runAsDaemon > 19) - runAsDaemon = 19; - setpriority(PRIO_PROCESS, 0, runAsDaemon); + if (processPriority < -20) + processPriority = -20; + else if (processPriority > 19) + processPriority = 19; + if (processPriority != 0) + setpriority(PRIO_PROCESS, 0, processPriority); logS(kLogNotice) << "daemon started" << std::endl; } @@ -135,10 +171,10 @@ int main (int argc, char *argv[]) if (pcmDevice.idx == -1) { cout << "soundcard \"" << soundcard << "\" not found\n"; - return 1; + exit(EXIT_FAILURE); } - if (!vm.count("host")) + if (!host.empty()) { BrowseAvahi browseAvahi; AvahiResult avahiResult; @@ -165,6 +201,7 @@ int main (int argc, char *argv[]) std::unique_ptr controller(new Controller()); if (!g_terminated) { + logO << "Latency: " << latency << "\n"; controller->start(pcmDevice, host, port, latency); while(!g_terminated) usleep(100*1000); @@ -178,7 +215,7 @@ int main (int argc, char *argv[]) logS(kLogNotice) << "daemon terminated." << endl; daemonShutdown(); - return 0; + exit(EXIT_SUCCESS); } diff --git a/common/daemon.h b/common/daemon.h index 3bac3f2c..a37195f0 100644 --- a/common/daemon.h +++ b/common/daemon.h @@ -23,6 +23,8 @@ #include #include #include +#include +#include int pidFilehandle; diff --git a/message/sampleFormat.cpp b/message/sampleFormat.cpp index 2a124919..acd90f3d 100644 --- a/message/sampleFormat.cpp +++ b/message/sampleFormat.cpp @@ -77,7 +77,7 @@ void SampleFormat::setFormat(uint32_t rate, uint16_t bits, uint16_t channels) if (bits == 24) sampleSize = 4; frameSize = channels*sampleSize; - logD << "SampleFormat: " << rate << ":" << bits << ":" << channels << "\n"; +// logD << "SampleFormat: " << rate << ":" << bits << ":" << channels << "\n"; } } diff --git a/server/Makefile b/server/Makefile index bf348aaa..9e701bcf 100644 --- a/server/Makefile +++ b/server/Makefile @@ -3,8 +3,8 @@ TARGET = snapserver SHELL = /bin/bash CXX = /usr/bin/g++ -CFLAGS = -std=c++0x -Wall -Wno-unused-function -O3 -pthread -DVERSION=\"$(VERSION)\" -I.. -I../externals/asio/asio/include -LDFLAGS = -lrt -lboost_system -lboost_program_options -lvorbis -lvorbisenc -logg -lFLAC -lavahi-client -lavahi-common +CFLAGS = -std=c++0x -Wall -Wno-unused-function -O3 -pthread -DASIO_STANDALONE -DVERSION=\"$(VERSION)\" -I.. -I../externals/asio/asio/include +LDFLAGS = -lrt -lvorbis -lvorbisenc -logg -lFLAC -lavahi-client -lavahi-common OBJ = snapServer.o config.o controlServer.o controlSession.o streamServer.o streamSession.o json/jsonrpc.o pcmreader/pcmReader.o pcmreader/pipeReader.o encoder/encoderFactory.o encoder/flacEncoder.o encoder/pcmEncoder.o encoder/oggEncoder.o publishAvahi.o ../common/log.o ../message/pcmChunk.o ../message/sampleFormat.o BIN = snapserver diff --git a/server/snapServer.cpp b/server/snapServer.cpp index e5c9aa5e..86c4826b 100644 --- a/server/snapServer.cpp +++ b/server/snapServer.cpp @@ -16,15 +16,14 @@ along with this program. If not, see . ***/ -#include +#include #include #include - #include + +#include "common/daemon.h" #include "common/timeDefs.h" #include "common/signalHandler.h" -#include "common/daemon.h" -#include "common/log.h" #include "common/snapException.h" #include "message/sampleFormat.h" #include "message/message.h" @@ -32,58 +31,106 @@ #include "streamServer.h" #include "publishAvahi.h" #include "config.h" +#include "common/log.h" bool g_terminated = false; - -namespace po = boost::program_options; +std::condition_variable terminateSignaled; using namespace std; -std::condition_variable terminateSignaled; int main(int argc, char* argv[]) { try { StreamServerSettings settings; - int runAsDaemon; + bool runAsDaemon(false); + int processPriority(-3); string sampleFormat; - po::options_description desc("Allowed options"); - desc.add_options() - ("help,h", "produce help message") - ("version,v", "show version number") - ("port,p", po::value(&settings.port)->default_value(settings.port), "server port") - ("controlPort", po::value(&settings.controlPort)->default_value(settings.controlPort), "Remote control port") - ("sampleformat,s", po::value(&sampleFormat)->default_value(settings.sampleFormat.getFormat()), "sample format") - ("codec,c", po::value(&settings.codec)->default_value(settings.codec), "transport codec [flac|ogg|pcm][:options]. Type codec:? to get codec specific options") - ("fifo,f", po::value(&settings.fifoName)->default_value(settings.fifoName), "name of the input fifo file") - ("daemon,d", po::value(&runAsDaemon)->implicit_value(-3), "daemonize, optional process priority [-20..19]") - ("buffer,b", po::value(&settings.bufferMs)->default_value(settings.bufferMs), "buffer [ms]") - ("pipeReadBuffer", po::value(&settings.pipeReadMs)->default_value(settings.pipeReadMs), "pipe read buffer [ms]") - ; - - po::variables_map vm; - po::store(po::parse_command_line(argc, argv, desc), vm); - po::notify(vm); - - if (vm.count("help")) + while (1) { - cout << desc << "\n"; - return 1; - } + int option_index = 0; + static struct option long_options[] = + { + {"help", no_argument, 0, 'h'}, + {"version", no_argument, 0, 'v'}, + {"port", required_argument, 0, 'p'}, + {"controlPort", required_argument, 0, 0 }, + {"sampleformat", required_argument, 0, 's'}, + {"codec", required_argument, 0, 'c'}, + {"fifo", required_argument, 0, 'f'}, + {"daemon", optional_argument, 0, 'd'}, + {"buffer", required_argument, 0, 'b'}, + {"pipeReadBuffer", required_argument, 0, 0 }, + {0, 0, 0, 0 } + }; - if (vm.count("version")) - { - cout << "snapserver " << VERSION << "\n" - << "Copyright (C) 2014, 2015 BadAix (snapcast@badaix.de).\n" - << "License GPLv3+: GNU GPL version 3 or later .\n" - << "This is free software: you are free to change and redistribute it.\n" - << "There is NO WARRANTY, to the extent permitted by law.\n\n" - << "Written by Johannes Pohl.\n"; - return 1; + char c = getopt_long(argc, argv, "hvp:s:c:f:d::b:", long_options, &option_index); + if (c == -1) + break; + + switch (c) + { + case 0: + if (strcmp(long_options[option_index].name, "controlPort") == 0) + settings.controlPort = atoi(optarg); + else if (strcmp(long_options[option_index].name, "pipeReadBuffer") == 0) + settings.pipeReadMs = atoi(optarg); + break; + + case 'v': + cout << "snapserver " << VERSION << "\n" + << "Copyright (C) 2014, 2015 BadAix (snapcast@badaix.de).\n" + << "License GPLv3+: GNU GPL version 3 or later .\n" + << "This is free software: you are free to change and redistribute it.\n" + << "There is NO WARRANTY, to the extent permitted by law.\n\n" + << "Written by Johannes Pohl.\n"; + exit(EXIT_SUCCESS); + + case 'p': + settings.port = atoi(optarg); + break; + + case 's': + settings.sampleFormat = string(optarg); + break; + + case 'c': + settings.codec = optarg; + break; + + case 'f': + settings.fifoName = optarg; + break; + + case 'd': + runAsDaemon = true; + if (optarg) + processPriority = atoi(optarg); + break; + + case 'b': + settings.bufferMs = atoi(optarg); + break; + + default: //? + cout << "Allowed options:\n\n" + << " -h, --help \t\t\t produce help message\n" + << " -v, --version \t\t\t show version number\n" + << " -p, --port arg (=" << settings.port << ")\t\t server port\n" + << " --controlPort arg (=" << settings.controlPort << ")\t\t Remote control port\n" + << " -s, --sampleformat arg(=" << settings.sampleFormat.getFormat() << ")\t sample format\n" + << " -c, --codec arg(=" << settings.codec << ")\t\t transport codec [flac|ogg|pcm][:options]. Type codec:? to get codec specific options\n" + << " -f, --fifo arg(=" << settings.fifoName << ")\t name of the input fifo file\n" + << " -d, --daemon [arg(=" << processPriority << ")]\t\t daemonize, optional process priority [-20..19]\n" + << " -b, --buffer arg(=" << settings.bufferMs << ")\t\t buffer [ms]\n" + << " --pipeReadBuffer arg(=" << settings.pipeReadMs << ")\t\t pipe read buffer [ms]\n" + << "\n"; + exit(EXIT_FAILURE); + } } if (settings.codec.find(":?") != string::npos) @@ -106,15 +153,16 @@ int main(int argc, char* argv[]) signal(SIGTERM, signal_handler); signal(SIGINT, signal_handler); - if (vm.count("daemon")) + if (runAsDaemon) { daemonize("/var/run/snapserver.pid"); - if (runAsDaemon < -20) - runAsDaemon = -20; - else if (runAsDaemon > 19) - runAsDaemon = 19; - setpriority(PRIO_PROCESS, 0, runAsDaemon); - logS(kLogNotice) << "daemon started." << endl; + if (processPriority < -20) + processPriority = -20; + else if (processPriority > 19) + processPriority = 19; + if (processPriority != 0) + setpriority(PRIO_PROCESS, 0, processPriority); + logS(kLogNotice) << "daemon started" << std::endl; } PublishAvahi publishAvahi("SnapCast"); @@ -125,7 +173,6 @@ int main(int argc, char* argv[]) if (settings.bufferMs < 400) settings.bufferMs = 400; - settings.sampleFormat = sampleFormat; asio::io_service io_service; std::unique_ptr streamServer(new StreamServer(&io_service, settings));