Codebase list squeezelite / upstream/1.3.1 main.c
upstream/1.3.1

Tree @upstream/1.3.1 (Download .tar.gz)

main.c @upstream/1.3.1

c88fab0
fd65b52
c88fab0
fd65b52
c88fab0
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
fd65b52
c88fab0
 
 
5a66990
8043f32
fd65b52
 
 
5a66990
fd65b52
 
1821a99
e30e37b
 
 
 
fd65b52
c88fab0
74b08e7
 
 
 
 
 
c88fab0
5c706fa
c88fab0
0d50897
82b016d
 
 
fd65b52
5a66990
66c9585
 
5a66990
 
 
 
 
 
 
f56b8a1
 
 
fd65b52
5c706fa
fd65b52
c88fab0
74b08e7
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
f56b8a1
 
 
74b08e7
 
c88fab0
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
ec4180b
fd65b52
f38c258
 
 
fd65b52
 
c88fab0
 
 
 
0d50897
5c706fa
c88fab0
 
5a66990
fd65b52
5a66990
fd65b52
 
 
 
5a66990
 
ec4180b
 
82b016d
c88fab0
fd65b52
 
e30e37b
fd65b52
f56b8a1
 
 
fd65b52
 
 
 
 
 
 
 
 
6bb4511
 
fd65b52
 
5a66990
fd65b52
 
f56b8a1
5a66990
f56b8a1
 
 
 
5a66990
f56b8a1
fd65b52
 
 
 
 
 
c88fab0
fd65b52
c88fab0
 
 
 
 
fd65b52
ec4180b
 
 
 
5a66990
 
ec4180b
 
fd65b52
 
e30e37b
 
 
 
fd65b52
c88fab0
 
 
 
ec4180b
 
c88fab0
 
 
 
 
 
 
 
 
 
 
fd65b52
5a23374
fd65b52
 
 
5a23374
 
 
 
 
 
 
 
c88fab0
 
5c706fa
 
 
c88fab0
 
 
 
 
 
fd65b52
c88fab0
 
 
 
fd65b52
 
 
5a66990
 
 
0d50897
 
 
82b016d
 
 
 
 
 
 
 
 
c88fab0
fd65b52
c88fab0
 
5a66990
 
 
 
 
 
 
 
 
f56b8a1
 
 
 
 
fd65b52
5c706fa
 
 
fd65b52
c88fab0
 
 
 
fd65b52
c88fab0
 
 
fd65b52
 
 
 
 
 
 
 
 
5a66990
 
 
 
 
 
c88fab0
 
5c706fa
 
 
 
 
 
fd65b52
5c706fa
 
 
 
 
fd65b52
 
 
 
 
 
c0aef15
 
fd65b52
5a66990
82b016d
fd65b52
 
e30e37b
fd65b52
c0aef15
f56b8a1
 
 
 
 
 
c88fab0
 
5a66990
 
 
 
 
 
8043f32
c88fab0
 
 
 
 
fd65b52
 
 
 
c88fab0
 
/* 
 *  Squeezelite - lightweight headless squeezebox emulator
 *
 *  (c) Adrian Smith 2012, 2013, triode1@btinternet.com
 *  
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 * 
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 *
 */

#include "squeezelite.h"

#include <signal.h>

#define TITLE "Squeezelite " VERSION ", Copyright 2012, 2013 Adrian Smith."

static void usage(const char *argv0) {
	printf(TITLE " See -t for license terms\n"
		   "Usage: %s [options]\n"
		   "  -s <server>[:<port>]\tConnect to specified server, otherwise uses autodiscovery to find server\n"
		   "  -o <output device>\tSpecify output device, default \"default\"\n"
		   "  -l \t\t\tList output devices\n"
#if ALSA
		   "  -a <b>:<p>:<f>:<m>\tSpecify ALSA params to open output device, b = buffer time in ms or size in bytes, p = period count or size in bytes, f sample format (16|24|24_3|32), m = use mmap (0|1)\n"
#endif
#if PORTAUDIO
#if OSX
		   "  -a <l>:<r>\t\tSpecify Portaudio params to open output device, l = target latency in ms, r = allow OSX to resample (0|1)\n"
#else
		   "  -a <l>\t\tSpecify Portaudio params to open output device, l = target latency in ms\n"
#endif
#endif
		   "  -b <stream>:<output>\tSpecify internal Stream and Output buffer sizes in Kbytes\n"
		   "  -c <codec1>,<codec2>\tRestrict codecs to those specified, otherwise load all available codecs; known codecs: "
#if FFMPEG
		   "flac,pcm,mp3,ogg,aac,wma,alac (mad,mpg for specific mp3 codec)\n"
#else
		   "flac,pcm,mp3,ogg,aac (mad,mpg for specific mp3 codec)\n"
#endif
		   "  -d <log>=<level>\tSet logging level, logs: all|slimproto|stream|decode|output, level: info|debug|sdebug\n"
		   "  -f <logfile>\t\tWrite debug to logfile\n"
		   "  -m <mac addr>\t\tSet mac address, format: ab:cd:ef:12:34:56\n"
		   "  -n <name>\t\tSet the player name\n"
#if ALSA
		   "  -p <priority>\t\tSet real time priority of output thread (1-99)\n"
#endif
		   "  -r <rate>\t\tMax sample rate for output device, enables output device to be off when squeezelite is started\n"
#if RESAMPLE
		   "  -u [params]\t\tUpsample, params = <recipe>:<flags>:<attenuation>:<precision>:<passband_end>:<stopband_start>:<phase_response>,\n" 
		   "  \t\t\t recipe = (v|h|m|l|q)(|L|I|M)(|s), (|X) = async - resample to max rate for device, otherwise resample to max sync rate\n"
		   "  \t\t\t flags = num in hex,\n"
		   "  \t\t\t attenuation = attenuation in dB to apply (default is -1db if not explicitly set),\n"
		   "  \t\t\t precision = number of bits precision (NB. HQ = 20. VHQ = 28),\n"
		   "  \t\t\t passband_end = number in percent (0dB pt. bandwidth to preserve. nyquist = 100%%),\n"
		   "  \t\t\t stopband_start = number in percent (Aliasing/imaging control. > passband_end),\n"
		   "  \t\t\t phase_response = 0-100 (0 = minimum / 50 = linear / 100 = maximum)\n"
#endif
#if VISEXPORT
		   "  -v \t\t\tVisulizer support\n"
#endif
#if LINUX
		   "  -z \t\t\tDaemonize\n"
#endif
		   "  -t \t\t\tLicense terms\n"
		   "\n"
		   "Build options: "
#if LINUX
		   "LINUX"
#endif
#if WIN
		   "WIN"
#endif
#if OSX
		   "OSX"
#endif
#if ALSA
		   " ALSA"
#endif
#if PORTAUDIO
		   " PORTAUDIO"
#endif
#if EVENTFD
		   " EVENTFD"
#endif
#if SELFPIPE
		   " SELFPIPE"
#endif
#if WINEVENT
		   " WINEVENT"
#endif
#if RESAMPLE
		   " RESAMPLE"
#endif
#if FFMPEG
		   " FFMPEG"
#endif
#if VISEXPORT
		   " VISEXPORT"
#endif
		   "\n\n",
		   argv0);
}

static void license(void) {
	printf(TITLE "\n\n"
		   "This program is free software: you can redistribute it and/or modify\n"
		   "it under the terms of the GNU General Public License as published by\n"
		   "the Free Software Foundation, either version 3 of the License, or\n"
		   "(at your option) any later version.\n\n"
		   "This program is distributed in the hope that it will be useful,\n"
		   "but WITHOUT ANY WARRANTY; without even the implied warranty of\n"
		   "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n"
		   "GNU General Public License for more details.\n\n"
		   "You should have received a copy of the GNU General Public License\n"
		   "along with this program.  If not, see <http://www.gnu.org/licenses/>.\n\n"
		   );
}

static void sighandler(int signum) {
	slimproto_stop();

	// remove ourselves in case above does not work, second SIGINT will cause non gracefull shutdown
	signal(signum, SIG_DFL);
}

int main(int argc, char **argv) {
	char *server = NULL;
	char *output_device = "default";
	char *codecs = NULL;
	char *name = NULL;
	char *logfile = NULL;
	u8_t mac[6];
	unsigned stream_buf_size = STREAMBUF_SIZE;
	unsigned output_buf_size = 0; // set later
	unsigned max_rate = 0;
	char *upsample = NULL;
#if LINUX
	bool daemonize = false;
#endif
#if ALSA
	unsigned alsa_buffer = ALSA_BUFFER_TIME;
	unsigned alsa_period = ALSA_PERIOD_COUNT;
	char *alsa_sample_fmt = NULL;
	bool alsa_mmap = true;
	unsigned rt_priority = OUTPUT_RT_PRIORITY;
#endif
#if PORTAUDIO
	unsigned pa_latency = 0;
	int pa_osx_playnice = -1;
#endif
#if VISEXPORT
	bool visexport = false;
#endif
	
	log_level log_output = lWARN;
	log_level log_stream = lWARN;
	log_level log_decode = lWARN;
	log_level log_slimproto = lWARN;

	char *optarg = NULL;
	int optind = 1;

	get_mac(mac);

	while (optind < argc && strlen(argv[optind]) >= 2 && argv[optind][0] == '-') {
		char *opt = argv[optind] + 1;
		if (strstr("oabcdfmnprs", opt) && optind < argc - 1) {
			optarg = argv[optind + 1];
			optind += 2;
		} else if (strstr("ltz"
#if RESAMPLE
						  "u"
#endif
#if VISEXPORT
						  "v"
#endif
						  , opt)) {
			optarg = NULL;
			optind += 1;
		} else {
			usage(argv[0]);
            exit(0);
		}

		switch (opt[0]) {
        case 'o':
            output_device = optarg;
            break;
		case 'a': 
			{
#if ALSA				
				char *t = next_param(optarg, ':');
				char *c = next_param(NULL, ':');
				char *s = next_param(NULL, ':');
				char *m = next_param(NULL, ':');
				if (t) alsa_buffer = atoi(t);
				if (c) alsa_period = atoi(c);
				if (s) alsa_sample_fmt = s;
				if (m) alsa_mmap = atoi(m);
#endif
#if PORTAUDIO
				char *l = next_param(optarg, ':');
				char *p = next_param(NULL, ':');
				if (l) pa_latency = (unsigned)atoi(l);
				if (p) pa_osx_playnice = atoi(p);
#endif
			}
			break;
		case 'b': 
			{
				char *s = next_param(optarg, ':');
				char *o = next_param(NULL, ':');
				if (s) stream_buf_size = atoi(s) * 1024;
				if (o) output_buf_size = atoi(o) * 1024;
			}
			break;
		case 'c':
			codecs = optarg;
			break;
        case 'd':
			{
				char *l = strtok(optarg, "=");
				char *v = strtok(NULL, "=");
				log_level new = lWARN;
				if (l && v) {
					if (!strcmp(v, "info"))   new = lINFO;
					if (!strcmp(v, "debug"))  new = lDEBUG;
					if (!strcmp(v, "sdebug")) new = lSDEBUG;
					if (!strcmp(l, "all") || !strcmp(l, "slimproto")) log_slimproto = new;
					if (!strcmp(l, "all") || !strcmp(l, "stream"))    log_stream = new;
					if (!strcmp(l, "all") || !strcmp(l, "decode"))    log_decode = new;
					if (!strcmp(l, "all") || !strcmp(l, "output"))    log_output = new;
				} else {
					usage(argv[0]);
					exit(0);
				}
			}
            break;
		case 'f':
			logfile = optarg;
			break;
		case 'm':
			{
				int byte = 0;
				char *tmp;
				char *t = strtok(optarg, ":");
				while (t && byte < 6) {
					mac[byte++] = (u8_t)strtoul(t, &tmp, 16);
					t = strtok(NULL, ":");
				}
			}
			break;
		case 'r':
			max_rate = atoi(optarg);
			break;
		case 's':
			server = optarg;
			break;
		case 'n':
			name = optarg;
			break;
#if ALSA
		case 'p':
			rt_priority = atoi(optarg);
			if (rt_priority > 99 || rt_priority < 1) {
				usage(argv[0]);
				exit(0);
			}
			break;
#endif
		case 'l':
			list_devices();
			exit(0);
			break;
#if RESAMPLE
		case 'u':
			if (optind < argc && argv[optind] && argv[optind][0] != '-') {
				upsample = argv[optind++];
			} else {
				upsample = "";
			}
			break;
#endif
#if VISEXPORT
		case 'v':
			visexport = true;
			break;
#endif
#if LINUX
		case 'z':
			daemonize = true;
			break;
#endif
		case 't':
			license();
			exit(0);
        default:
			break;
        }
    }

	signal(SIGINT, sighandler);
	signal(SIGTERM, sighandler);
#if defined(SIGQUIT)
	signal(SIGQUIT, sighandler);
#endif
#if defined(SIGHUP)
	signal(SIGHUP, sighandler);
#endif

	// set the output buffer size if not specified on the command line to take account of upsampling
	if (!output_buf_size) {
		output_buf_size = OUTPUTBUF_SIZE;
		if (upsample) {
			output_buf_size *= max_rate ? max_rate / 44100 : 8;
		}
	}

	if (logfile) {
		if (!freopen(logfile, "a", stdout) || !freopen(logfile, "a", stderr)) {
			fprintf(stderr, "error opening logfile %s: %s\n", logfile, strerror(errno));
		}
	}

#if LINUX
	if (daemonize) {
		if (daemon(0, logfile ? 1 : 0)) {
			fprintf(stderr, "error daemonizing: %s\n", strerror(errno));
		}
	}
#endif

#if WIN
	winsock_init();
#endif

	stream_init(log_stream, stream_buf_size);

#if ALSA
	output_init(log_output, output_device, output_buf_size, alsa_buffer, alsa_period, alsa_sample_fmt, alsa_mmap, 
				max_rate, rt_priority);
#endif
#if PORTAUDIO
	output_init(log_output, output_device, output_buf_size, pa_latency, pa_osx_playnice, max_rate);
#endif

#if VISEXPORT
	if (visexport) {
		output_vis_init(mac);
	}
#endif

	decode_init(log_decode, codecs);

#if RESAMPLE
	if (upsample) {
		process_init(upsample);
	}
#endif

	slimproto(log_slimproto, server, mac, name);
	
	decode_close();
	stream_close();
	output_close();

#if WIN
	winsock_close();
#endif

	exit(0);
}