ncmixer

ncurses audio mixer for DJ'ing
git clone git://git.2f30.org/ncmixer
Log | Files | Refs | README | LICENSE

mixerd.c (19883B)


      1 #include <sys/types.h>
      2 #include <sys/socket.h>
      3 #include <sys/stat.h>
      4 #include <sys/un.h>
      5 
      6 #include <err.h>
      7 #include <errno.h>
      8 #include <math.h>
      9 #include <poll.h>
     10 #include <signal.h>
     11 #include <sndio.h>
     12 #include <stdarg.h>
     13 #include <stdio.h>
     14 #include <stdlib.h>
     15 #include <string.h>
     16 #include <syslog.h>
     17 #include <time.h>
     18 #include <unistd.h>
     19 
     20 #include <lame/lame.h>
     21 #include <shout/shout.h>
     22 
     23 #include "arg.h"
     24 #include "proto.h"
     25 #include "util.h"
     26 
     27 #define LEN(x) (sizeof (x) / sizeof *(x))
     28 #undef MIN
     29 #define MIN(x, y) ((x) < (y) ? (x) : (y))
     30 #undef MAX
     31 #define MAX(x, y) ((x) > (y) ? (x) : (y))
     32 #define SA struct sockaddr
     33 #define CTL_SOCK_PATH "/tmp/mixerctl"
     34 #define CH0_SOCK_PATH "/tmp/mixer0"
     35 #define CH1_SOCK_PATH "/tmp/mixer1"
     36 /* to use the snd/0 and snd/1 handles: sndiod -f rsnd/0 -f rsnd/1 */
     37 #define MASTER_DEV "sndio://snd/0"
     38 #define MONITOR_DEV "sndio://snd/1"
     39 #define NOUTPUTS 2
     40 #define BITS 16
     41 #define BPS (BITS / 8)
     42 #define BITRATE 320 /* for lame */
     43 #define RATE 44100
     44 #define CHANS 2
     45 #define NSAMPLES 128
     46 #define BUFFER_TIME_MS 100
     47 #define TIMEO_MS 40
     48 #define FADE_LOW 0.25f
     49 #define FADE_DUR_MS 1500
     50 
     51 char *argv0;
     52 int debug;
     53 
     54 /* mixer state */
     55 float xf_pos = 0.0f; /* values in [-1.0, 1.0] */
     56 float fade = 1.0f; /* values in [FADE_LOW, 1.0] */
     57 float fadeold;
     58 struct timespec airtp; /* when air direction changed */
     59 int onair = 0;
     60 
     61 /* forward decls */
     62 struct input;
     63 struct output;
     64 
     65 int mix_master(struct output *, struct input *, struct input *);
     66 int mix_monitor(struct output *, struct input *, struct input *);
     67 
     68 struct input {
     69 	int listenfd;
     70 	int clifd;
     71 	short buf[NSAMPLES];
     72 	short attenuated_buf[NSAMPLES];
     73 	int nsamples;
     74 	int mon_on;	/* whether input should be directed to monitor */
     75 	float level;	/* channel level in the interval [0.0, 1.0] */
     76 } inputs[] = {
     77 	{ .listenfd = -1, .clifd = -1, .level = 1.0f },
     78 	{ .listenfd = -1, .clifd = -1, .level = 1.0f }
     79 };
     80 
     81 struct output {
     82 	short buf[NSAMPLES];
     83 	int nsamples;
     84 	void *enc;	/* lame handle, only useful for the shout output */
     85 	void *hdl;	/* shout/sndio handle */
     86 	void *arg;	/* shout/sndio args, see {shout,sndio}_arg below */
     87 	int (*open)(struct output *);
     88 	int (*play)(struct output *);
     89 	void (*close)(struct output *);
     90 	int (*mix)(struct output *, struct input *, struct input *);
     91 } outputs[NOUTPUTS];
     92 
     93 struct sio_arg {
     94 	char *devname;
     95 } sio_arg[NOUTPUTS];
     96 
     97 struct shout_arg {
     98 	char *user;
     99 	char *pw;
    100 	char *host;
    101 	char *port;
    102 	char *mount;
    103 } shout_arg[NOUTPUTS];
    104 
    105 int (*mixers[NOUTPUTS])(struct output *, struct input *, struct input *) = {
    106 	mix_master,
    107 	mix_monitor
    108 };
    109 
    110 void
    111 log_msg(int prio, const char *msg, ...)
    112 {
    113 	va_list ap;
    114 
    115 	if (debug) {
    116 		va_start(ap, msg);
    117 		vfprintf(stderr, msg, ap);
    118 		fprintf(stderr, "\n");
    119 		va_end(ap);
    120 	} else {
    121 		va_start(ap, msg);
    122 		vsyslog(LOG_DAEMON | prio, msg, ap);
    123 		va_end(ap);
    124 	}
    125 }
    126 
    127 void
    128 log_err(const char *msg, ...)
    129 {
    130 	va_list ap;
    131 
    132 	if (debug) {
    133 		va_start(ap, msg);
    134 		fprintf(stderr, "rebound: ");
    135 		vfprintf(stderr, msg, ap);
    136 		fprintf(stderr, "\n");
    137 		va_end(ap);
    138 	} else {
    139 		va_start(ap, msg);
    140 		vsyslog(LOG_DAEMON | LOG_ERR, msg, ap);
    141 		va_end(ap);
    142 	}
    143 	exit(1);
    144 }
    145 
    146 /* initialize lame to be used with libshout */
    147 int
    148 encoder_open(struct output *out)
    149 {
    150 	if ((out->enc = lame_init()) == NULL) {
    151 		log_msg(LOG_WARNING, "failed to initialize lame");
    152 		return -1;
    153 	}
    154 
    155 	if (lame_set_brate(out->enc, BITRATE) == -1) {
    156 		log_msg(LOG_WARNING, "failed to set lame bitrate");
    157 		goto err0;
    158 	}
    159 
    160 	if (lame_set_num_channels(out->enc, CHANS) == -1) {
    161 		log_msg(LOG_WARNING, "failed to set lame channels");
    162 		goto err0;
    163 	}
    164 
    165 	if (lame_set_in_samplerate(out->enc, RATE) == -1) {
    166 		log_msg(LOG_WARNING, "failed to set lame input sample rate");
    167 		goto err0;
    168 	}
    169 
    170 	if (lame_set_out_samplerate(out->enc, RATE) == -1) {
    171 		log_msg(LOG_WARNING, "failed to set lame output sample rate");
    172 		goto err0;
    173 	}
    174 
    175 	if (lame_init_params(out->enc) == -1) {
    176 		log_msg(LOG_WARNING, "failed to set lame params");
    177 		goto err0;
    178 	}
    179 
    180 	return 0;
    181 err0:
    182 	lame_close(out->enc);
    183 	out->enc = NULL;
    184 	return -1;
    185 }
    186 
    187 void
    188 encoder_close(struct output *out)
    189 {
    190 	if (out->enc != NULL) {
    191 		lame_close(out->enc);
    192 		out->enc = NULL;
    193 	}
    194 }
    195 
    196 int
    197 shout_audio_open(struct output *out)
    198 {
    199 	struct shout_arg *shout_arg = out->arg;
    200 	shout_t *hdl;
    201 	char tmp[32];
    202 
    203 	if (encoder_open(out) == -1)
    204 		return -1;
    205 
    206 	shout_init();
    207 
    208 	if ((hdl = shout_new()) == NULL)
    209 		goto err0;
    210 
    211 	strlcpy(tmp, shout_arg->user, sizeof(tmp));
    212 	if (shout_arg->user[0] == '\0')
    213 		strlcpy(tmp, "source", sizeof(tmp));
    214 	if (shout_set_user(hdl, tmp) != SHOUTERR_SUCCESS) {
    215 		log_msg(LOG_WARNING, "failed to set user: %s",
    216 		        shout_get_error(hdl));
    217 		goto err1;
    218 	}
    219 
    220 	if (shout_set_password(hdl, shout_arg->pw) != SHOUTERR_SUCCESS) {
    221 		log_msg(LOG_WARNING, "failed to set password: %s",
    222 		        shout_get_error(hdl));
    223 		goto err1;
    224 	}
    225 
    226 	if (shout_set_host(hdl, shout_arg->host) != SHOUTERR_SUCCESS) {
    227 		log_msg(LOG_WARNING, "failed to set host: %s",
    228 		        shout_get_error(hdl));
    229 		goto err1;
    230 	}
    231 
    232 	if (shout_set_port(hdl, atoi(shout_arg->port)) != SHOUTERR_SUCCESS) {
    233 		log_msg(LOG_WARNING, "failed to set port: %s",
    234 		        shout_get_error(hdl));
    235 		goto err1;
    236 	}
    237 
    238 	strlcpy(tmp, shout_arg->mount, sizeof(tmp));
    239 	if (shout_arg->mount[0] != '/') {
    240 		strlcpy(tmp, "/", sizeof(tmp));
    241 		strlcat(tmp, shout_arg->mount, sizeof(tmp));
    242 	}
    243 	if (shout_set_mount(hdl, tmp) != SHOUTERR_SUCCESS) {
    244 		log_msg(LOG_WARNING, "failed to set mountpoint: %s",
    245 		        shout_get_error(hdl));
    246 		goto err1;
    247 	}
    248 
    249 	if (shout_set_protocol(hdl, SHOUT_PROTOCOL_HTTP) != SHOUTERR_SUCCESS) {
    250 		log_msg(LOG_WARNING, "failed to set protocol: %s",
    251 		        shout_get_error(hdl));
    252 		goto err1;
    253 	}
    254 
    255 	/* XXX: should be configurable */
    256 	if (shout_set_format(hdl, SHOUT_FORMAT_MP3) != SHOUTERR_SUCCESS) {
    257 		log_msg(LOG_WARNING, "failed to set format: %s",
    258 		        shout_get_error(hdl));
    259 		goto err1;
    260 	}
    261 
    262 	snprintf(tmp, sizeof(tmp), "%d", BITRATE);
    263 	if (shout_set_audio_info(hdl, SHOUT_AI_BITRATE, tmp) != SHOUTERR_SUCCESS) {
    264 		log_msg(LOG_WARNING, "failed to set bitrate: %s",
    265 		        shout_get_error(hdl));
    266 		goto err1;
    267 	}
    268 
    269 	snprintf(tmp, sizeof(tmp), "%d", RATE);
    270 	if (shout_set_audio_info(hdl, SHOUT_AI_SAMPLERATE, tmp) != SHOUTERR_SUCCESS) {
    271 		log_msg(LOG_WARNING, "failed to set sample rate: %s",
    272 		        shout_get_error(hdl));
    273 		goto err1;
    274 	}
    275 
    276 	snprintf(tmp, sizeof(tmp), "%d", CHANS);
    277 	if (shout_set_audio_info(hdl, SHOUT_AI_CHANNELS, tmp) != SHOUTERR_SUCCESS) {
    278 		log_msg(LOG_WARNING, "failed to set channels: %s",
    279 		        shout_get_error(hdl));
    280 		goto err1;
    281 	}
    282 
    283 	if (shout_open(hdl) != SHOUTERR_SUCCESS) {
    284 		log_msg(LOG_WARNING, "failed to connect: %s",
    285 		        shout_get_error(hdl));
    286 		goto err1;
    287 	}
    288 
    289 	out->hdl = hdl;
    290 	return 0;
    291 err1:
    292 	shout_free(hdl);
    293 	out->hdl = NULL;
    294 err0:
    295 	encoder_close(out);
    296 	return -1;
    297 }
    298 
    299 int
    300 shout_audio_play(struct output *out)
    301 {
    302 	unsigned char mp3buf[2 * out->nsamples + 7200]; /* worst-case scenario */
    303 	int n;
    304 
    305 	n = lame_encode_buffer_interleaved(out->enc, out->buf,
    306 	                                   out->nsamples / CHANS,
    307 	                                   mp3buf, sizeof(mp3buf));
    308 	if (shout_send(out->hdl, mp3buf, n) != SHOUTERR_SUCCESS) {
    309 		log_msg(LOG_WARNING, "failed to send data: %s",
    310 		        shout_get_error(out->hdl));
    311 		return -1;
    312 	}
    313 	shout_sync(out->hdl);
    314 	return out->nsamples * BPS;
    315 }
    316 
    317 void
    318 shout_audio_close(struct output *out)
    319 {
    320 	if (out->hdl != NULL) {
    321 		shout_close(out->hdl);
    322 		shout_free(out->hdl);
    323 		shout_shutdown();
    324 		out->hdl = NULL;
    325 	}
    326 
    327 	encoder_close(out);
    328 }
    329 
    330 int
    331 sio_audio_open(struct output *out)
    332 {
    333 	struct sio_arg *sio_arg = out->arg;
    334 	char *devname = sio_arg->devname;
    335 	struct sio_hdl *hdl;
    336 	struct sio_par par;
    337 
    338 	hdl = sio_open(devname, SIO_PLAY, 0);
    339 	if (hdl == NULL)
    340 		return -1;
    341 
    342 	sio_initpar(&par);
    343 	par.bits = BITS;
    344 	par.rate = RATE;
    345 	par.pchan = CHANS;
    346 	par.sig = 1;
    347 	par.le = SIO_LE_NATIVE;
    348 	par.appbufsz = RATE * BUFFER_TIME_MS / 1000;
    349 
    350 	if (sio_setpar(hdl, &par) == 0) {
    351 		log_msg(LOG_WARNING, "%s: failed to set params", devname);
    352 		goto err0;
    353 	}
    354 
    355 	if (sio_getpar(hdl, &par) == 0) {
    356 		log_msg(LOG_WARNING, "%s: failed to get params", devname);
    357 		goto err0;
    358 	}
    359 
    360 	if (par.pchan != CHANS) {
    361 		log_msg(LOG_WARNING, "%s: failed to set number of channels",
    362 		        devname);
    363 		goto err0;
    364 	}
    365 
    366 	if (par.sig  != 1 ||
    367 	    par.bits != BITS ||
    368 	    par.le   != SIO_LE_NATIVE) {
    369 		log_msg(LOG_WARNING, "%s: failed to set format", devname);
    370 		goto err0;
    371 	}
    372 
    373 	/* allow 0.5% tolerance for actual sample rate */
    374 	if (par.rate < RATE * 995 / 1000 ||
    375 	    par.rate > RATE * 1005 / 1000) {
    376 		log_msg(LOG_WARNING, "%s: failed to set rate", devname);
    377 		goto err0;
    378 	}
    379 
    380 	if (sio_start(hdl) == 0) {
    381 		log_msg(LOG_WARNING, "%s: failed to start audio device",
    382 		        devname);
    383 		goto err0;
    384 	}
    385 
    386 	out->hdl = hdl;
    387 	return 0;
    388 err0:
    389 	sio_close(hdl);
    390 	out->hdl = NULL;
    391 	return -1;
    392 }
    393 
    394 int
    395 sio_audio_play(struct output *out)
    396 {
    397 	int n;
    398 
    399 	n = sio_write(out->hdl, out->buf, out->nsamples * BPS);
    400 	if (n == 0 && sio_eof(out->hdl) != 0)
    401 		return -1;
    402 	return n;
    403 }
    404 
    405 void
    406 sio_audio_close(struct output *out)
    407 {
    408 	if (out->hdl != NULL) {
    409 		sio_close(out->hdl);
    410 		out->hdl = NULL;
    411 	}
    412 }
    413 
    414 int
    415 consume(struct input *in)
    416 {
    417 	int n;
    418 
    419 	do {
    420 		n = read(in->clifd, in->buf, sizeof(in->buf));
    421 	} while (n == -1 && errno == EINTR);
    422 	if (n == 0 || n == -1)
    423 		return -1;
    424 	in->nsamples = n / BPS;
    425 	return in->nsamples;
    426 }
    427 
    428 void
    429 level(struct input *in)
    430 {
    431 	short *ch0 = (short *)in->buf;
    432 	int i;
    433 
    434 	for (i = 0; i < in->nsamples; i++) {
    435 		*ch0 *= in->level;
    436 		ch0++;
    437 	}
    438 }
    439 
    440 void
    441 attenuate(struct input *in, float factor)
    442 {
    443 	short *ch0 = (short *)in->buf;
    444 	short *out = (short *)in->attenuated_buf;
    445 	int i;
    446 
    447 	for (i = 0; i < in->nsamples; i++) {
    448 		*out = *ch0 * factor;
    449 		ch0++, out++;
    450 	}
    451 }
    452 
    453 void
    454 applyfade(struct input *in)
    455 {
    456 	struct timespec tp;
    457 	float complete;
    458 	int durationms;
    459 	int deltams;
    460 	short *buf;
    461 	int i;
    462 
    463 	if ((onair && fade > FADE_LOW) || (!onair && fade < 1.0f)) {
    464 		clock_gettime(CLOCK_MONOTONIC, &tp);
    465 		deltams = (tp.tv_sec * 1000 + tp.tv_nsec / 1000000)
    466 		    - (airtp.tv_sec * 1000 + airtp.tv_nsec / 1000000);
    467 		/* fade should complete faster if it was interrupted */
    468 		if (onair)
    469 			durationms = (fadeold - FADE_LOW) * FADE_DUR_MS;
    470 		else
    471 			durationms = (1.0f - fadeold) * FADE_DUR_MS;
    472 		durationms /= 1.0f - FADE_LOW;
    473 		complete = (float)deltams / durationms;
    474 		fade = fadeold;
    475 		if (onair) {
    476 			fade -= (1.0f - FADE_LOW) * complete;
    477 			fade = MAX(fade, FADE_LOW);
    478 		} else {
    479 			fade += (1.0f - FADE_LOW) * complete;
    480 			fade = MIN(fade, 1.0f);
    481 		}
    482 	}
    483 
    484 	buf = (short *)in->attenuated_buf;
    485 	for (i = 0; i < in->nsamples; i++) {
    486 		*buf *= fade;
    487 		buf++;
    488 	}
    489 }
    490 
    491 int
    492 mix_master(struct output *out, struct input *in0, struct input *in1)
    493 {
    494 	short *ch0 = (short *)in0->attenuated_buf;
    495 	short *ch1 = (short *)in1->attenuated_buf;
    496 	short *buf = (short *)out->buf;
    497 	int i;
    498 
    499 	out->nsamples = MAX(in0->nsamples, in1->nsamples);
    500 	for (i = 0; i < out->nsamples; i++) {
    501 		*buf = *ch0 * 0.5 + *ch1 * 0.5;
    502 		ch0++, ch1++, buf++;
    503 	}
    504 	return out->nsamples;
    505 }
    506 
    507 int
    508 mix_monitor(struct output *out, struct input *in0, struct input *in1)
    509 {
    510 	short *ch0 = (short *)in0->buf;
    511 	short *ch1 = (short *)in1->buf;
    512 	short *buf = (short *)out->buf;
    513 	int i;
    514 
    515 	out->nsamples = MAX(in0->nsamples, in1->nsamples);
    516 	for (i = 0; i < out->nsamples; i++) {
    517 		*ch0 *= in0->mon_on;
    518 		*ch1 *= in1->mon_on;
    519 		*buf = *ch0 * 0.5 + *ch1 * 0.5;
    520 		ch0++, ch1++, buf++;
    521 	}
    522 	return out->nsamples;
    523 }
    524 
    525 int
    526 server_listen(char *name, int ctl)
    527 {
    528 	struct sockaddr_un sun;
    529 	socklen_t len;
    530 	int fd, type, oldumask;
    531 
    532 	if (ctl)
    533 		type = SOCK_SEQPACKET;
    534 	else
    535 		type = SOCK_STREAM;
    536 
    537 	fd = socket(AF_UNIX, type, 0);
    538 	if (fd == -1)
    539 		log_err("socket failed");
    540 	unlink(name);
    541 	memset(&sun, 0, sizeof(sun));
    542 	sun.sun_family = AF_UNIX;
    543 	snprintf(sun.sun_path, sizeof(sun.sun_path), "%s", name);
    544 	len = sizeof(sun);
    545 	oldumask = umask(0111);
    546 	if (bind(fd, (SA *)&sun, len) == -1)
    547 		log_err("bind failed");
    548 	umask(oldumask);
    549 	if (listen(fd, 5) == -1)
    550 		log_err("listen failed");
    551 	return fd;
    552 }
    553 
    554 int
    555 msg_handler(int fd)
    556 {
    557 	struct msg msg;
    558 	int n, tx_reply = 0;
    559 
    560 	do {
    561 		n = read(fd, &msg, sizeof(msg));
    562 	} while (n == -1 && errno == EINTR);
    563 	if (n == 0 || n == -1)
    564 		return -1;
    565 
    566 	switch (msg.type) {
    567 	case SET_XF:
    568 		if (msg.m_xf_pos < -1.0f ||
    569 		    msg.m_xf_pos > 1.0f) {
    570 			log_msg(LOG_WARNING, "xf pos out of bounds: %f",
    571 			        msg.m_xf_pos);
    572 			return 0;
    573 		}
    574 		xf_pos = msg.m_xf_pos;
    575 		break;
    576 	case GET_XF:
    577 		msg.m_xf_pos = xf_pos;
    578 		tx_reply = 1;
    579 		break;
    580 	case SET_MON:
    581 		if (msg.m_mon_index != 0 &&
    582 		    msg.m_mon_index != 1) {
    583 			log_msg(LOG_WARNING, "invalid monitor index: %d",
    584 			        msg.m_mon_index);
    585 			return 0;
    586 		}
    587 		inputs[msg.m_mon_index].mon_on = !inputs[msg.m_mon_index].mon_on;
    588 		break;
    589 	case GET_MON:
    590 		if (msg.m_mon_index != 0 &&
    591 		    msg.m_mon_index != 1) {
    592 			log_msg(LOG_WARNING, "invalid monitor index: %d",
    593 			        msg.m_mon_index);
    594 			return 0;
    595 		}
    596 		msg.m_mon_on = inputs[msg.m_mon_index].mon_on;
    597 		tx_reply = 1;
    598 		break;
    599 	case SET_VOL:
    600 		if (msg.m_vol_chan != 0 &&
    601 		    msg.m_vol_chan != 1) {
    602 			log_msg(LOG_WARNING, "invalid input channel: %d",
    603 			        msg.m_vol_chan);
    604 			return 0;
    605 		}
    606 		if (msg.m_vol_level < 0.0f ||
    607 		    msg.m_vol_level > 1.0f) {
    608 			log_msg(LOG_WARNING, "invalid input channel volume: %f",
    609 			        msg.m_vol_level);
    610 			return 0;
    611 		}
    612 		inputs[msg.m_vol_chan].level = msg.m_vol_level;
    613 		break;
    614 	case GET_VOL:
    615 		if (msg.m_vol_chan != 0 &&
    616 		    msg.m_vol_chan != 1) {
    617 			log_msg(LOG_WARNING, "invalid input channel: %d",
    618 			        msg.m_vol_chan);
    619 			return 0;
    620 		}
    621 		msg.m_vol_level = inputs[msg.m_vol_chan].level;
    622 		tx_reply = 1;
    623 		break;
    624 	case GET_IN:
    625 		if (msg.m_input_index != 0 &&
    626 		    msg.m_input_index != 1) {
    627 			log_msg(LOG_WARNING, "invalid input index: %d",
    628 			        msg.m_input_index);
    629 			return 0;
    630 		}
    631 		msg.m_input_on = inputs[msg.m_input_index].clifd != -1;
    632 		tx_reply = 1;
    633 		break;
    634 	case GET_OUT:
    635 		if (msg.m_output_index != 0 &&
    636 		    msg.m_output_index != 1) {
    637 			log_msg(LOG_WARNING, "invalid output index: %d",
    638 			        msg.m_output_index);
    639 			return 0;
    640 		}
    641 		msg.m_output_on = outputs[msg.m_output_index].hdl != NULL;
    642 		tx_reply = 1;
    643 		break;
    644 	case SET_AIR:
    645 		if (msg.m_air_on != onair) {
    646 			clock_gettime(CLOCK_MONOTONIC, &airtp);
    647 			fadeold = fade;
    648 		}
    649 		onair = msg.m_air_on;
    650 		break;
    651 	case GET_AIR:
    652 		msg.m_air_on = onair;
    653 		tx_reply = 1;
    654 		break;
    655 	default:
    656 		log_msg(LOG_WARNING, "unknown message type: %d", msg.type);
    657 		break;
    658 	}
    659 
    660 	/* for GET_* requests, send a reply */
    661 	if (tx_reply) {
    662 		do {
    663 			n = write(fd, &msg, sizeof(msg));
    664 		} while (n == -1 && errno == EINTR);
    665 		if (n == -1)
    666 			return -1;
    667 	}
    668 	return 0;
    669 }
    670 
    671 /* do not re-order */
    672 #define CTL_LISTEN 0
    673 #define IN0_LISTEN 1
    674 #define IN1_LISTEN 2
    675 #define CTL_CLIENT 3
    676 #define IN0_CLIENT 4
    677 #define IN1_CLIENT 5
    678 #define NR_SOCKETS 6
    679 void
    680 loop(void)
    681 {
    682 	struct sockaddr_un sun;
    683 	socklen_t len;
    684 	struct pollfd pfd[NR_SOCKETS];
    685 	struct input *in;
    686 	struct output *out;
    687 	int i, ret, clifd, nready;
    688 
    689 	for (i = 0; i < LEN(pfd); i++) {
    690 		pfd[i].fd = -1;
    691 		pfd[i].events = 0;
    692 	}
    693 
    694 	inputs[0].listenfd = server_listen(CH0_SOCK_PATH, 0);
    695 	inputs[1].listenfd = server_listen(CH1_SOCK_PATH, 0);
    696 
    697 	pfd[CTL_LISTEN].fd = server_listen(CTL_SOCK_PATH, 1);
    698 	pfd[CTL_LISTEN].events = POLLIN;
    699 	pfd[IN0_LISTEN].fd = inputs[0].listenfd;
    700 	pfd[IN0_LISTEN].events = POLLIN;
    701 	pfd[IN1_LISTEN].fd = inputs[1].listenfd;
    702 	pfd[IN1_LISTEN].events = POLLIN;
    703 
    704 	for (;;) {
    705 		nready = poll(pfd, LEN(pfd), TIMEO_MS);
    706 		if (nready == -1) {
    707 			if (errno != EINTR)
    708 				log_err("poll failed");
    709 			continue;
    710 		}
    711 
    712 		for (i = 0; i < LEN(pfd); i++)
    713 			if (pfd[i].revents & POLLERR)
    714 				log_err("bad fd");
    715 
    716 		/* handle client request */
    717 		if (pfd[CTL_CLIENT].revents & (POLLIN | POLLHUP)) {
    718 			if (msg_handler(pfd[CTL_CLIENT].fd) == -1) {
    719 				close(pfd[CTL_CLIENT].fd);
    720 				pfd[CTL_CLIENT].fd = -1;
    721 				pfd[CTL_CLIENT].events = 0;
    722 			}
    723 		}
    724 
    725 		/* accept control socket connection */
    726 		if (pfd[CTL_LISTEN].revents & POLLIN) {
    727 			len = sizeof(sun);
    728 			do {
    729 				clifd = accept(pfd[CTL_LISTEN].fd,
    730 				               (SA *)&sun, &len);
    731 			} while (clifd == -1 && errno == EINTR);
    732 			if (clifd == -1)
    733 				log_err("accept failed");
    734 			/* control socket already connected, reject this one */
    735 			if (pfd[CTL_CLIENT].fd != -1) {
    736 				close(clifd);
    737 			} else {
    738 				pfd[CTL_CLIENT].fd = clifd;
    739 				pfd[CTL_CLIENT].events = POLLIN;
    740 			}
    741 		}
    742 
    743 		/* accept input channel connections */
    744 		for (i = 0; i < LEN(inputs); i++) {
    745 			in = &inputs[i];
    746 			if (pfd[IN0_LISTEN + i].revents & POLLIN) {
    747 				len = sizeof(sun);
    748 				do {
    749 					clifd = accept(in->listenfd,
    750 					               (SA *)&sun, &len);
    751 				} while (clifd == -1 && errno == EINTR);
    752 				if (clifd == -1)
    753 					log_err("accept failed");
    754 				/* input already connnected, reject this one */
    755 				if (in->clifd != -1) {
    756 					close(clifd);
    757 					continue;
    758 				}
    759 				in->clifd = clifd;
    760 				pfd[IN0_CLIENT + i].fd = clifd;
    761 				pfd[IN0_CLIENT + i].events = POLLIN;
    762 			}
    763 		}
    764 
    765 		/* reinit input channel buffers to avoid mixing stale data */
    766 		for (i = 0; i < LEN(inputs); i++) {
    767 			in = &inputs[i];
    768 			memset(in->buf, 0, sizeof(in->buf));
    769 			memset(in->attenuated_buf, 0,
    770 			       sizeof(in->attenuated_buf));
    771 			in->nsamples = 0;
    772 		}
    773 
    774 		/* consume pcm data on input channels */
    775 		for (i = 0; i < LEN(inputs); i++) {
    776 			in = &inputs[i];
    777 			if (pfd[IN0_CLIENT + i].revents & (POLLIN | POLLHUP)) {
    778 				if (consume(in) == -1) {
    779 					close(in->clifd);
    780 					in->clifd = -1;
    781 					pfd[IN0_CLIENT + i].fd = -1;
    782 					pfd[IN0_CLIENT + i].events = 0;
    783 				} else {
    784 					level(in);
    785 				}
    786 			}
    787 		}
    788 
    789 		/* attenuate inputs based on cross-fader position */
    790 		if (xf_pos <= 0) {
    791 			attenuate(&inputs[0], 1.0f);
    792 			attenuate(&inputs[1], 1.0f - fabsf(xf_pos));
    793 		} else {
    794 			attenuate(&inputs[0], 1.0f - fabsf(xf_pos));
    795 			attenuate(&inputs[1], 1.0f);
    796 		}
    797 
    798 		/* apply fade effect for on-air toggle */
    799 		applyfade(&inputs[0]);
    800 		applyfade(&inputs[1]);
    801 
    802 		/* play dat shit! */
    803 		for (i = 0; i < LEN(outputs); i++) {
    804 			out = &outputs[i];
    805 			/* open output device on demand */
    806 			if (out->hdl == NULL && out->open(out) == -1)
    807 				continue;
    808 			out->mix(out, &inputs[0], &inputs[1]);
    809 			ret = out->play(out);
    810 			if (ret == -1)
    811 				out->close(out);
    812 		}
    813 	}
    814 }
    815 
    816 void
    817 map_sndio_output(int idx, char *uri)
    818 {
    819 	struct output *out = &outputs[idx];
    820 	struct sio_arg *arg = &sio_arg[idx];
    821 
    822 	arg->devname = uri;
    823 	out->arg = arg;
    824 	out->open = sio_audio_open;
    825 	out->play = sio_audio_play;
    826 	out->close = sio_audio_close;
    827 	out->mix = mixers[idx];
    828 }
    829 
    830 void
    831 map_shout_output(int idx, char *uri)
    832 {
    833 	struct output *out = &outputs[idx];
    834 	struct shout_arg *arg = &shout_arg[idx];
    835 	char *p;
    836 
    837 	/* dumb URI parser, all fields are mandatory */
    838 #define EXTRACT_FIELD(field, sep) do { \
    839 	if ((p = strchr(uri, sep)) == NULL) \
    840 		errx(1, "URI is malformed"); \
    841 	*p++ = '\0'; \
    842 	arg->field = uri; \
    843 	uri = p; \
    844 } while (0)
    845 
    846 	EXTRACT_FIELD(user, ':');
    847 	EXTRACT_FIELD(pw, '@');
    848 	EXTRACT_FIELD(host, ':');
    849 	EXTRACT_FIELD(port, '/');
    850 	EXTRACT_FIELD(mount, '\0');
    851 
    852 	out->arg = arg;
    853 	out->open = shout_audio_open;
    854 	out->play = shout_audio_play;
    855 	out->close = shout_audio_close;
    856 	out->mix = mixers[idx];
    857 }
    858 
    859 void
    860 map_output(int idx, char *uri)
    861 {
    862 	int i;
    863 	struct {
    864 		char *scheme;
    865 		void (*fn)(int, char *);
    866 	} uris[] = {
    867 		{ .scheme = "sndio://", map_sndio_output },
    868 		{ .scheme = "shout://", map_shout_output }
    869 	};
    870 
    871 	for (i = 0; i < LEN(uris); i++) {
    872 		char *scheme = uris[i].scheme;
    873 		if (strncmp(uri, scheme, strlen(scheme)) == 0) {
    874 			uris[i].fn(idx, uri + strlen(scheme));
    875 			break;
    876 		}
    877 	}
    878 	if (i == LEN(uris))
    879 		errx(1, "invalid output");
    880 }
    881 
    882 void
    883 map_outputs(int argc, char *argv[])
    884 {
    885 	map_output(0, argc > 0 ? argv[0] : MASTER_DEV);
    886 	map_output(1, argc > 1 ? argv[1] : MONITOR_DEV);
    887 }
    888 
    889 void
    890 usage(void)
    891 {
    892 	fprintf(stderr, "usage: mixerd [-d] [master-output] [monitor-output]\n");
    893 	exit(1);
    894 }
    895 
    896 int
    897 main(int argc, char *argv[])
    898 {
    899 	ARGBEGIN {
    900 	case 'd':
    901 		debug = 1;
    902 		break;
    903 	default:
    904 		usage();
    905 	} ARGEND
    906 
    907 	map_outputs(argc, argv);
    908 	if (!debug && daemon(0, 0) == -1)
    909 		err(1, "daemon");
    910 	signal(SIGPIPE, SIG_IGN);
    911 	loop();
    912 	return 0;
    913 }