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 }