1/* 2 * A simple PCM loopback utility with adaptive sample rate support 3 * 4 * Author: Jaroslav Kysela <perex@perex.cz> 5 * 6 * 7 * This program is free software; you can redistribute it and/or modify 8 * it under the terms of the GNU General Public License as published by 9 * the Free Software Foundation; either version 2 of the License, or 10 * (at your option) any later version. 11 * 12 * This program is distributed in the hope that it will be useful, 13 * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 * GNU General Public License for more details. 16 * 17 * You should have received a copy of the GNU General Public License 18 * along with this program; if not, write to the Free Software 19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 20 * 21 */ 22 23#include "aconfig.h" 24#include <stdio.h> 25#include <stdlib.h> 26#include <string.h> 27#include <sched.h> 28#include <errno.h> 29#include <getopt.h> 30#include <alsa/asoundlib.h> 31#include <sys/time.h> 32#include <math.h> 33#include <pthread.h> 34#include <syslog.h> 35#include <signal.h> 36#include "alsaloop.h" 37#include "os_compat.h" 38 39struct loopback_thread { 40 int threaded; 41 pthread_t thread; 42 int exitcode; 43 struct loopback **loopbacks; 44 int loopbacks_count; 45 snd_output_t *output; 46}; 47 48int quit = 0; 49int verbose = 0; 50int workarounds = 0; 51int daemonize = 0; 52int use_syslog = 0; 53struct loopback **loopbacks = NULL; 54int loopbacks_count = 0; 55char **my_argv = NULL; 56int my_argc = 0; 57struct loopback_thread *threads; 58int threads_count = 0; 59pthread_t main_job; 60int arg_default_xrun = 0; 61int arg_default_wake = 0; 62 63static void my_exit(struct loopback_thread *thread, int exitcode) 64{ 65 int i; 66 67 for (i = 0; i < thread->loopbacks_count; i++) 68 pcmjob_done(thread->loopbacks[i]); 69 if (thread->threaded) { 70 thread->exitcode = exitcode; 71 pthread_exit(0); 72 } 73 exit(exitcode); 74} 75 76static int create_loopback_handle(struct loopback_handle **_handle, 77 const char *device, 78 const char *ctldev, 79 const char *id) 80{ 81 char idbuf[1024]; 82 struct loopback_handle *handle; 83 84 handle = calloc(1, sizeof(*handle)); 85 if (handle == NULL) 86 return -ENOMEM; 87 if (device == NULL) 88 device = "hw:0,0"; 89 handle->device = strdup(device); 90 if (handle->device == NULL) { 91 free(handle); 92 return -ENOMEM; 93 } 94 if (ctldev) { 95 handle->ctldev = strdup(ctldev); 96 if (handle->ctldev == NULL) { 97 free(handle->device); 98 free(handle); 99 return -ENOMEM; 100 } 101 } else { 102 handle->ctldev = NULL; 103 } 104 snprintf(idbuf, sizeof(idbuf)-1, "%s %s", id, device); 105 idbuf[sizeof(idbuf)-1] = '\0'; 106 handle->id = strdup(idbuf); 107 handle->access = SND_PCM_ACCESS_RW_INTERLEAVED; 108 handle->format = SND_PCM_FORMAT_S16_LE; 109 handle->rate = handle->rate_req = 48000; 110 handle->channels = 2; 111 handle->resample = 0; 112 *_handle = handle; 113 return 0; 114} 115 116static int create_loopback(struct loopback **_handle, 117 struct loopback_handle *play, 118 struct loopback_handle *capt, 119 snd_output_t *output) 120{ 121 struct loopback *handle; 122 123 handle = calloc(1, sizeof(*handle)); 124 if (handle == NULL) 125 return -ENOMEM; 126 handle->play = play; 127 handle->capt = capt; 128 play->loopback = handle; 129 capt->loopback = handle; 130 handle->latency_req = 0; 131 handle->latency_reqtime = 10000; 132 handle->loop_time = ~0UL; 133 handle->loop_limit = ~0ULL; 134 handle->output = output; 135 handle->state = output; 136#ifdef USE_SAMPLERATE 137 handle->src_enable = 1; 138 handle->src_converter_type = SRC_SINC_BEST_QUALITY; 139#endif 140 *_handle = handle; 141 return 0; 142} 143 144static void set_loop_time(struct loopback *loop, unsigned long loop_time) 145{ 146 loop->loop_time = loop_time; 147 loop->loop_limit = loop->capt->rate * loop_time; 148} 149 150static void setscheduler(void) 151{ 152 struct sched_param sched_param; 153 154 if (sched_getparam(0, &sched_param) < 0) { 155 logit(LOG_WARNING, "Scheduler getparam failed.\n"); 156 return; 157 } 158 sched_param.sched_priority = sched_get_priority_max(SCHED_RR); 159 if (!sched_setscheduler(0, SCHED_RR, &sched_param)) { 160 if (verbose) 161 logit(LOG_WARNING, "Scheduler set to Round Robin with priority %i\n", sched_param.sched_priority); 162 return; 163 } 164 if (verbose) 165 logit(LOG_INFO, "!!!Scheduler set to Round Robin with priority %i FAILED!\n", sched_param.sched_priority); 166} 167 168void help(void) 169{ 170 int k; 171 printf( 172"Usage: alsaloop [OPTION]...\n\n" 173"-h,--help help\n" 174"-g,--config configuration file (one line = one job specified)\n" 175"-d,--daemonize daemonize the main process and use syslog for errors\n" 176"-P,--pdevice playback device\n" 177"-C,--cdevice capture device\n" 178"-X,--pctl playback ctl device\n" 179"-Y,--cctl capture ctl device\n" 180"-x,--prateshift playback 'PCM Rate Shift 100000' ascii ctl name\n" 181"-l,--latency requested latency in frames\n" 182"-t,--tlatency requested latency in usec (1/1000000sec)\n" 183"-f,--format sample format\n" 184"-c,--channels channels\n" 185"-r,--rate rate\n" 186"-n,--resample resample in alsa-lib\n" 187"-A,--samplerate use converter (0=sincbest,1=sincmedium,2=sincfastest,\n" 188" 3=zerohold,4=linear)\n" 189"-B,--buffer buffer size in frames\n" 190"-E,--period period size in frames\n" 191"-s,--seconds duration of loop in seconds\n" 192"-b,--nblock non-block mode (very early process wakeup)\n" 193"-S,--sync sync mode(0=none,1=simple,2=captshift,3=playshift,4=samplerate,\n" 194" 5=auto)\n" 195"-a,--slave stream parameters slave mode (0=auto, 1=on, 2=off)\n" 196"-T,--thread thread number (-1 = create unique)\n" 197"-m,--mixer redirect mixer, argument is:\n" 198" SRC_SLAVE_ID(PLAYBACK)[@DST_SLAVE_ID(CAPTURE)]\n" 199"-O,--ossmixer rescan and redirect oss mixer, argument is:\n" 200" ALSA_ID@OSS_ID (for example: \"Master@VOLUME\")\n" 201"-e,--effect apply an effect (bandpass filter sweep)\n" 202"-v,--verbose verbose mode (more -v means more verbose)\n" 203"-w,--workaround use workaround (serialopen)\n" 204"-U,--xrun xrun profiling\n" 205"-W,--wake process wake timeout in ms\n" 206"-z,--syslog use syslog for errors\n" 207); 208 printf("\nRecognized sample formats are:"); 209 for (k = 0; k < SND_PCM_FORMAT_LAST; ++k) { 210 const char *s = snd_pcm_format_name(k); 211 if (s) 212 printf(" %s", s); 213 } 214 printf("\n\n"); 215 printf( 216"Tip #1 (usable 500ms latency, good CPU usage, superb xrun prevention):\n" 217" alsaloop -t 500000\n" 218"Tip #2 (superb 1ms latency, but heavy CPU usage):\n" 219" alsaloop -t 1000\n" 220); 221} 222 223static long timediff(struct timeval t1, struct timeval t2) 224{ 225 signed long l; 226 227 t1.tv_sec -= t2.tv_sec; 228 l = (signed long) t1.tv_usec - (signed long) t2.tv_usec; 229 if (l < 0) { 230 t1.tv_sec--; 231 l = 1000000 + l; 232 l %= 1000000; 233 } 234 return (t1.tv_sec * 1000000) + l; 235} 236 237static void add_loop(struct loopback *loop) 238{ 239 loopbacks = realloc(loopbacks, (loopbacks_count + 1) * 240 sizeof(struct loopback *)); 241 if (loopbacks == NULL) { 242 logit(LOG_CRIT, "No enough memory\n"); 243 exit(EXIT_FAILURE); 244 } 245 loopbacks[loopbacks_count++] = loop; 246} 247 248static int init_mixer_control(struct loopback_control *control, 249 char *id) 250{ 251 int err; 252 253 err = snd_ctl_elem_id_malloc(&control->id); 254 if (err < 0) 255 return err; 256 err = snd_ctl_elem_info_malloc(&control->info); 257 if (err < 0) 258 return err; 259 err = snd_ctl_elem_value_malloc(&control->value); 260 if (err < 0) 261 return err; 262 err = control_parse_id(id, control->id); 263 if (err < 0) 264 return err; 265 return 0; 266} 267 268static int add_mixers(struct loopback *loop, 269 char **mixers, 270 int mixers_count) 271{ 272 struct loopback_mixer *mixer, *last = NULL; 273 char *str1; 274 int err; 275 276 while (mixers_count > 0) { 277 mixer = calloc(1, sizeof(*mixer)); 278 if (mixer == NULL) 279 return -ENOMEM; 280 if (last) 281 last->next = mixer; 282 else 283 loop->controls = mixer; 284 last = mixer; 285 str1 = strchr(*mixers, '@'); 286 if (str1) 287 *str1 = '\0'; 288 err = init_mixer_control(&mixer->src, *mixers); 289 if (err < 0) { 290 logit(LOG_CRIT, "Wrong mixer control ID syntax '%s'\n", *mixers); 291 return -EINVAL; 292 } 293 err = init_mixer_control(&mixer->dst, str1 ? str1 + 1 : *mixers); 294 if (err < 0) { 295 logit(LOG_CRIT, "Wrong mixer control ID syntax '%s'\n", str1 ? str1 + 1 : *mixers); 296 return -EINVAL; 297 } 298 if (str1) 299 *str1 = '@'; 300 mixers++; 301 mixers_count--; 302 } 303 return 0; 304} 305 306static int add_oss_mixers(struct loopback *loop, 307 char **mixers, 308 int mixers_count) 309{ 310 struct loopback_ossmixer *mixer, *last = NULL; 311 char *str1, *str2; 312 313 while (mixers_count > 0) { 314 mixer = calloc(1, sizeof(*mixer)); 315 if (mixer == NULL) 316 return -ENOMEM; 317 if (last) 318 last->next = mixer; 319 else 320 loop->oss_controls = mixer; 321 last = mixer; 322 str1 = strchr(*mixers, ','); 323 if (str1) 324 *str1 = '\0'; 325 str2 = strchr(str1 ? str1 + 1 : *mixers, '@'); 326 if (str2) 327 *str2 = '\0'; 328 mixer->alsa_id = strdup(*mixers); 329 if (str1) 330 mixer->alsa_index = atoi(str1); 331 mixer->oss_id = strdup(str2 ? str2 + 1 : *mixers); 332 if (mixer->alsa_id == NULL || mixer->oss_id == NULL) { 333 logit(LOG_CRIT, "Not enough memory"); 334 return -ENOMEM; 335 } 336 if (str1) 337 *str1 = ','; 338 if (str2) 339 *str2 = ','; 340 mixers++; 341 mixers_count--; 342 } 343 return 0; 344} 345 346static void enable_syslog(void) 347{ 348 if (!use_syslog) { 349 use_syslog = 1; 350 openlog("alsaloop", LOG_NDELAY|LOG_PID, LOG_DAEMON); 351 } 352} 353 354static int parse_config_file(const char *file, snd_output_t *output); 355 356static int parse_config(int argc, char *argv[], snd_output_t *output, 357 int cmdline) 358{ 359 struct option long_option[] = 360 { 361 {"help", 0, NULL, 'h'}, 362 {"config", 1, NULL, 'g'}, 363 {"daemonize", 0, NULL, 'd'}, 364 {"pdevice", 1, NULL, 'P'}, 365 {"cdevice", 1, NULL, 'C'}, 366 {"pctl", 1, NULL, 'X'}, 367 {"cctl", 1, NULL, 'Y'}, 368 {"prateshift", 1, NULL, 'x'}, 369 {"latency", 1, NULL, 'l'}, 370 {"tlatency", 1, NULL, 't'}, 371 {"format", 1, NULL, 'f'}, 372 {"channels", 1, NULL, 'c'}, 373 {"rate", 1, NULL, 'r'}, 374 {"buffer", 1, NULL, 'B'}, 375 {"period", 1, NULL, 'E'}, 376 {"seconds", 1, NULL, 's'}, 377 {"nblock", 0, NULL, 'b'}, 378 {"effect", 0, NULL, 'e'}, 379 {"verbose", 0, NULL, 'v'}, 380 {"resample", 0, NULL, 'n'}, 381 {"samplerate", 1, NULL, 'A'}, 382 {"sync", 1, NULL, 'S'}, 383 {"slave", 1, NULL, 'a'}, 384 {"thread", 1, NULL, 'T'}, 385 {"mixer", 1, NULL, 'm'}, 386 {"ossmixer", 1, NULL, 'O'}, 387 {"workaround", 1, NULL, 'w'}, 388 {"xrun", 0, NULL, 'U'}, 389 {"syslog", 0, NULL, 'z'}, 390 {NULL, 0, NULL, 0}, 391 }; 392 int err, morehelp; 393 char *arg_config = NULL; 394 char *arg_pdevice = NULL; 395 char *arg_cdevice = NULL; 396 char *arg_pctl = NULL; 397 char *arg_cctl = NULL; 398 char *arg_prateshift = NULL; 399 unsigned int arg_latency_req = 0; 400 unsigned int arg_latency_reqtime = 10000; 401 snd_pcm_format_t arg_format = SND_PCM_FORMAT_S16_LE; 402 unsigned int arg_channels = 2; 403 unsigned int arg_rate = 48000; 404 snd_pcm_uframes_t arg_buffer_size = 0; 405 snd_pcm_uframes_t arg_period_size = 0; 406 unsigned long arg_loop_time = ~0UL; 407 int arg_nblock = 0; 408 // int arg_effect = 0; 409 int arg_resample = 0; 410#ifdef USE_SAMPLERATE 411 int arg_samplerate = SRC_SINC_FASTEST + 1; 412#endif 413 int arg_sync = SYNC_TYPE_AUTO; 414 int arg_slave = SLAVE_TYPE_AUTO; 415 int arg_thread = 0; 416 struct loopback *loop = NULL; 417 char *arg_mixers[MAX_MIXERS]; 418 int arg_mixers_count = 0; 419 char *arg_ossmixers[MAX_MIXERS]; 420 int arg_ossmixers_count = 0; 421 int arg_xrun = arg_default_xrun; 422 int arg_wake = arg_default_wake; 423 424 morehelp = 0; 425 while (1) { 426 int c; 427 if ((c = getopt_long(argc, argv, 428 "hdg:P:C:X:Y:x:l:t:F:f:c:r:s:benvA:S:a:m:T:O:w:UW:z", 429 long_option, NULL)) < 0) 430 break; 431 switch (c) { 432 case 'h': 433 morehelp++; 434 break; 435 case 'g': 436 arg_config = strdup(optarg); 437 break; 438 case 'd': 439 daemonize = 1; 440 enable_syslog(); 441 break; 442 case 'P': 443 arg_pdevice = strdup(optarg); 444 break; 445 case 'C': 446 arg_cdevice = strdup(optarg); 447 break; 448 case 'X': 449 arg_pctl = strdup(optarg); 450 break; 451 case 'Y': 452 arg_cctl = strdup(optarg); 453 break; 454 case 'x': 455 arg_prateshift = strdup(optarg); 456 break; 457 case 'l': 458 err = atoi(optarg); 459 arg_latency_req = err >= 4 ? err : 4; 460 break; 461 case 't': 462 err = atoi(optarg); 463 arg_latency_reqtime = err >= 500 ? err : 500; 464 break; 465 case 'f': 466 arg_format = snd_pcm_format_value(optarg); 467 if (arg_format == SND_PCM_FORMAT_UNKNOWN) { 468 logit(LOG_WARNING, "Unknown format, setting to default S16_LE\n"); 469 arg_format = SND_PCM_FORMAT_S16_LE; 470 } 471 break; 472 case 'c': 473 err = atoi(optarg); 474 arg_channels = err >= 1 && err < 1024 ? err : 1; 475 break; 476 case 'r': 477 err = atoi(optarg); 478 arg_rate = err >= 4000 && err < 200000 ? err : 44100; 479 break; 480 case 'B': 481 err = atoi(optarg); 482 arg_buffer_size = err >= 32 && err < 200000 ? err : 0; 483 break; 484 case 'E': 485 err = atoi(optarg); 486 arg_period_size = err >= 32 && err < 200000 ? err : 0; 487 break; 488 case 's': 489 err = atoi(optarg); 490 arg_loop_time = err >= 1 && err <= 100000 ? err : 30; 491 break; 492 case 'b': 493 arg_nblock = 1; 494 break; 495 case 'e': 496 // arg_effect = 1; 497 break; 498 case 'n': 499 arg_resample = 1; 500 break; 501#ifdef USE_SAMPLERATE 502 case 'A': 503 if (strcasecmp(optarg, "sincbest") == 0) 504 arg_samplerate = SRC_SINC_BEST_QUALITY; 505 else if (strcasecmp(optarg, "sincmedium") == 0) 506 arg_samplerate = SRC_SINC_MEDIUM_QUALITY; 507 else if (strcasecmp(optarg, "sincfastest") == 0) 508 arg_samplerate = SRC_SINC_FASTEST; 509 else if (strcasecmp(optarg, "zerohold") == 0) 510 arg_samplerate = SRC_ZERO_ORDER_HOLD; 511 else if (strcasecmp(optarg, "linear") == 0) 512 arg_samplerate = SRC_LINEAR; 513 else 514 arg_samplerate = atoi(optarg); 515 if (arg_samplerate < 0 || arg_samplerate > SRC_LINEAR) 516 arg_sync = SRC_SINC_FASTEST; 517 arg_samplerate += 1; 518 break; 519#endif 520 case 'S': 521 if (strcasecmp(optarg, "samplerate") == 0) 522 arg_sync = SYNC_TYPE_SAMPLERATE; 523 else if (optarg[0] == 'n') 524 arg_sync = SYNC_TYPE_NONE; 525 else if (optarg[0] == 's') 526 arg_sync = SYNC_TYPE_SIMPLE; 527 else if (optarg[0] == 'c') 528 arg_sync = SYNC_TYPE_CAPTRATESHIFT; 529 else if (optarg[0] == 'p') 530 arg_sync = SYNC_TYPE_PLAYRATESHIFT; 531 else if (optarg[0] == 'r') 532 arg_sync = SYNC_TYPE_SAMPLERATE; 533 else if (optarg[0] == 'a') 534 arg_sync = SYNC_TYPE_AUTO; 535 else 536 arg_sync = atoi(optarg); 537 if (arg_sync < 0 || arg_sync > SYNC_TYPE_LAST) 538 arg_sync = SYNC_TYPE_AUTO; 539 break; 540 case 'a': 541 if (optarg[0] == 'a') 542 arg_slave = SLAVE_TYPE_AUTO; 543 else if (strcasecmp(optarg, "on") == 0) 544 arg_slave = SLAVE_TYPE_ON; 545 else if (strcasecmp(optarg, "off") == 0) 546 arg_slave = SLAVE_TYPE_OFF; 547 else 548 arg_slave = atoi(optarg); 549 if (arg_slave < 0 || arg_slave > SLAVE_TYPE_LAST) 550 arg_slave = SLAVE_TYPE_AUTO; 551 break; 552 case 'T': 553 arg_thread = atoi(optarg); 554 if (arg_thread < 0) 555 arg_thread = 10000000 + loopbacks_count; 556 break; 557 case 'm': 558 if (arg_mixers_count >= MAX_MIXERS) { 559 logit(LOG_CRIT, "Maximum redirected mixer controls reached (max %i)\n", (int)MAX_MIXERS); 560 exit(EXIT_FAILURE); 561 } 562 arg_mixers[arg_mixers_count++] = optarg; 563 break; 564 case 'O': 565 if (arg_ossmixers_count >= MAX_MIXERS) { 566 logit(LOG_CRIT, "Maximum redirected mixer controls reached (max %i)\n", (int)MAX_MIXERS); 567 exit(EXIT_FAILURE); 568 } 569 arg_ossmixers[arg_ossmixers_count++] = optarg; 570 break; 571 case 'v': 572 verbose++; 573 break; 574 case 'w': 575 if (strcasecmp(optarg, "serialopen") == 0) 576 workarounds |= WORKAROUND_SERIALOPEN; 577 break; 578 case 'U': 579 arg_xrun = 1; 580 if (cmdline) 581 arg_default_xrun = 1; 582 break; 583 case 'W': 584 arg_wake = atoi(optarg); 585 if (cmdline) 586 arg_default_wake = arg_wake; 587 break; 588 case 'z': 589 enable_syslog(); 590 break; 591 } 592 } 593 594 if (morehelp) { 595 help(); 596 exit(EXIT_SUCCESS); 597 } 598 if (arg_config == NULL) { 599 struct loopback_handle *play; 600 struct loopback_handle *capt; 601 err = create_loopback_handle(&play, arg_pdevice, arg_pctl, "playback"); 602 if (err < 0) { 603 logit(LOG_CRIT, "Unable to create playback handle.\n"); 604 exit(EXIT_FAILURE); 605 } 606 err = create_loopback_handle(&capt, arg_cdevice, arg_cctl, "capture"); 607 if (err < 0) { 608 logit(LOG_CRIT, "Unable to create capture handle.\n"); 609 exit(EXIT_FAILURE); 610 } 611 err = create_loopback(&loop, play, capt, output); 612 if (err < 0) { 613 logit(LOG_CRIT, "Unable to create loopback handle.\n"); 614 exit(EXIT_FAILURE); 615 } 616 play->format = capt->format = arg_format; 617 play->rate = play->rate_req = capt->rate = capt->rate_req = arg_rate; 618 play->channels = capt->channels = arg_channels; 619 play->buffer_size_req = capt->buffer_size_req = arg_buffer_size; 620 play->period_size_req = capt->period_size_req = arg_period_size; 621 play->resample = capt->resample = arg_resample; 622 play->nblock = capt->nblock = arg_nblock ? 1 : 0; 623 loop->latency_req = arg_latency_req; 624 loop->latency_reqtime = arg_latency_reqtime; 625 loop->sync = arg_sync; 626 loop->slave = arg_slave; 627 loop->thread = arg_thread; 628 loop->xrun = arg_xrun; 629 loop->wake = arg_wake; 630 err = add_mixers(loop, arg_mixers, arg_mixers_count); 631 if (err < 0) { 632 logit(LOG_CRIT, "Unable to add mixer controls.\n"); 633 exit(EXIT_FAILURE); 634 } 635 err = add_oss_mixers(loop, arg_ossmixers, arg_ossmixers_count); 636 if (err < 0) { 637 logit(LOG_CRIT, "Unable to add ossmixer controls.\n"); 638 exit(EXIT_FAILURE); 639 } 640 if (arg_prateshift) 641 play->prateshift_name = arg_prateshift; 642 643#ifdef USE_SAMPLERATE 644 loop->src_enable = arg_samplerate > 0; 645 if (loop->src_enable) 646 loop->src_converter_type = arg_samplerate - 1; 647#endif 648 set_loop_time(loop, arg_loop_time); 649 add_loop(loop); 650 return 0; 651 } 652 653 return parse_config_file(arg_config, output); 654} 655 656static int parse_config_file(const char *file, snd_output_t *output) 657{ 658 FILE *fp; 659 char line[2048], word[2048]; 660 char *str, *ptr; 661 int argc, c, err = 0; 662 char **argv; 663 664 fp = fopen(file, "r"); 665 if (fp == NULL) { 666 logit(LOG_CRIT, "Unable to open file '%s': %s\n", file, strerror(errno)); 667 return -EIO; 668 } 669 while (!feof(fp)) { 670 if (fgets(line, sizeof(line)-1, fp) == NULL) 671 break; 672 line[sizeof(line)-1] = '\0'; 673 my_argv = realloc(my_argv, my_argc + MAX_ARGS * sizeof(char *)); 674 if (my_argv == NULL) 675 return -ENOMEM; 676 argv = my_argv + my_argc; 677 argc = 0; 678 argv[argc++] = strdup("<prog>"); 679 my_argc++; 680 str = line; 681 while (*str) { 682 ptr = word; 683 while (*str && (*str == ' ' || *str < ' ')) 684 str++; 685 if (*str == '#') 686 goto __next; 687 if (*str == '\'' || *str == '\"') { 688 c = *str++; 689 while (*str && *str != c) 690 *ptr++ = *str++; 691 if (*str == c) 692 str++; 693 } else { 694 while (*str && *str != ' ' && *str != '\t') 695 *ptr++ = *str++; 696 } 697 if (ptr != word) { 698 if (*(ptr-1) == '\n') 699 ptr--; 700 *ptr = '\0'; 701 if (argc >= MAX_ARGS) { 702 logit(LOG_CRIT, "Too many arguments."); 703 goto __error; 704 } 705 argv[argc++] = strdup(word); 706 my_argc++; 707 } 708 } 709 /* erase runtime variables for getopt */ 710 optarg = NULL; 711 optind = opterr = 1; 712 optopt = '?'; 713 714 err = parse_config(argc, argv, output, 0); 715 __next: 716 if (err < 0) 717 break; 718 err = 0; 719 } 720 __error: 721 fclose(fp); 722 723 return err; 724} 725 726static void thread_job1(void *_data) 727{ 728 struct loopback_thread *thread = _data; 729 snd_output_t *output = thread->output; 730 struct pollfd *pfds = NULL; 731 int pfds_count = 0; 732 int i, j, err, wake = 1000000; 733 734 setscheduler(); 735 736 for (i = 0; i < thread->loopbacks_count; i++) { 737 err = pcmjob_init(thread->loopbacks[i]); 738 if (err < 0) { 739 logit(LOG_CRIT, "Loopback initialization failure.\n"); 740 my_exit(thread, EXIT_FAILURE); 741 } 742 } 743 for (i = 0; i < thread->loopbacks_count; i++) { 744 err = pcmjob_start(thread->loopbacks[i]); 745 if (err < 0) { 746 logit(LOG_CRIT, "Loopback start failure.\n"); 747 my_exit(thread, EXIT_FAILURE); 748 } 749 pfds_count += thread->loopbacks[i]->pollfd_count; 750 j = thread->loopbacks[i]->wake; 751 if (j > 0 && j < wake) 752 wake = j; 753 } 754 if (wake >= 1000000) 755 wake = -1; 756 pfds = calloc(pfds_count, sizeof(struct pollfd)); 757 if (pfds == NULL || pfds_count <= 0) { 758 logit(LOG_CRIT, "Poll FDs allocation failed.\n"); 759 my_exit(thread, EXIT_FAILURE); 760 } 761 while (!quit) { 762 struct timeval tv1, tv2; 763 for (i = j = 0; i < thread->loopbacks_count; i++) { 764 err = pcmjob_pollfds_init(thread->loopbacks[i], &pfds[j]); 765 if (err < 0) { 766 logit(LOG_CRIT, "Poll FD initialization failed.\n"); 767 my_exit(thread, EXIT_FAILURE); 768 } 769 j += err; 770 } 771 if (verbose > 10) 772 gettimeofday(&tv1, NULL); 773 err = poll(pfds, j, wake); 774 if (err < 0) 775 err = -errno; 776 if (verbose > 10) { 777 gettimeofday(&tv2, NULL); 778 snd_output_printf(output, "pool took %lius\n", timediff(tv2, tv1)); 779 } 780 if (err < 0) { 781 if (err == -EINTR || err == -ERESTART) 782 continue; 783 logit(LOG_CRIT, "Poll failed: %s\n", strerror(-err)); 784 my_exit(thread, EXIT_FAILURE); 785 } 786 for (i = j = 0; i < thread->loopbacks_count; i++) { 787 struct loopback *loop = thread->loopbacks[i]; 788 if (j < loop->active_pollfd_count) { 789 err = pcmjob_pollfds_handle(loop, &pfds[j]); 790 if (err < 0) { 791 logit(LOG_CRIT, "pcmjob failed.\n"); 792 exit(EXIT_FAILURE); 793 } 794 } 795 j += loop->active_pollfd_count; 796 } 797 } 798 799 my_exit(thread, EXIT_SUCCESS); 800} 801 802static void thread_job(struct loopback_thread *thread) 803{ 804 if (!thread->threaded) { 805 thread_job1(thread); 806 return; 807 } 808 pthread_create(&thread->thread, NULL, (void *) &thread_job1, 809 (void *) thread); 810} 811 812static void send_to_all(int sig) 813{ 814 struct loopback_thread *thread; 815 int i; 816 817 for (i = 0; i < threads_count; i++) { 818 thread = &threads[i]; 819 if (thread->threaded) 820 pthread_kill(thread->thread, sig); 821 } 822} 823 824static void signal_handler(int sig ATTRIBUTE_UNUSED) 825{ 826 quit = 1; 827 send_to_all(SIGUSR2); 828} 829 830static void signal_handler_state(int sig) 831{ 832 pthread_t self = pthread_self(); 833 struct loopback_thread *thread; 834 int i, j; 835 836 if (pthread_equal(main_job, self)) 837 send_to_all(SIGUSR1); 838 for (i = 0; i < threads_count; i++) { 839 thread = &threads[i]; 840 if (thread->thread == self) { 841 for (j = 0; j < thread->loopbacks_count; j++) 842 pcmjob_state(thread->loopbacks[j]); 843 } 844 } 845 signal(sig, signal_handler_state); 846} 847 848static void signal_handler_ignore(int sig) 849{ 850 signal(sig, signal_handler_ignore); 851} 852 853int main(int argc, char *argv[]) 854{ 855 snd_output_t *output; 856 int i, j, k, l, err; 857 858 err = snd_output_stdio_attach(&output, stdout, 0); 859 if (err < 0) { 860 logit(LOG_CRIT, "Output failed: %s\n", snd_strerror(err)); 861 exit(EXIT_FAILURE); 862 } 863 err = parse_config(argc, argv, output, 1); 864 if (err < 0) { 865 logit(LOG_CRIT, "Unable to parse arguments or configuration...\n"); 866 exit(EXIT_FAILURE); 867 } 868 while (my_argc > 0) 869 free(my_argv[--my_argc]); 870 free(my_argv); 871 872 if (loopbacks_count <= 0) { 873 logit(LOG_CRIT, "No loopback defined...\n"); 874 exit(EXIT_FAILURE); 875 } 876 877 if (daemonize) { 878 if (daemon(0, 0) < 0) { 879 logit(LOG_CRIT, "daemon() failed: %s\n", strerror(errno)); 880 exit(EXIT_FAILURE); 881 } 882 i = fork(); 883 if (i < 0) { 884 logit(LOG_CRIT, "fork() failed: %s\n", strerror(errno)); 885 exit(EXIT_FAILURE); 886 } 887 if (i > 0) { 888 /* wait(&i); */ 889 exit(EXIT_SUCCESS); 890 } 891 } 892 893 /* we must sort thread IDs */ 894 j = -1; 895 do { 896 k = 0x7fffffff; 897 for (i = 0; i < loopbacks_count; i++) { 898 if (loopbacks[i]->thread < k && 899 loopbacks[i]->thread > j) 900 k = loopbacks[i]->thread; 901 } 902 j++; 903 for (i = 0; i < loopbacks_count; i++) { 904 if (loopbacks[i]->thread == k) 905 loopbacks[i]->thread = j; 906 } 907 } while (k != 0x7fffffff); 908 /* fix maximum thread id */ 909 for (i = 0, j = -1; i < loopbacks_count; i++) { 910 if (loopbacks[i]->thread > j) 911 j = loopbacks[i]->thread; 912 } 913 j += 1; 914 threads = calloc(1, sizeof(struct loopback_thread) * j); 915 if (threads == NULL) { 916 logit(LOG_CRIT, "No enough memory\n"); 917 exit(EXIT_FAILURE); 918 } 919 /* sort all threads */ 920 for (k = 0; k < j; k++) { 921 for (i = l = 0; i < loopbacks_count; i++) 922 if (loopbacks[i]->thread == k) 923 l++; 924 threads[k].loopbacks = malloc(l * sizeof(struct loopback *)); 925 threads[k].loopbacks_count = l; 926 threads[k].output = output; 927 threads[k].threaded = j > 1; 928 for (i = l = 0; i < loopbacks_count; i++) 929 if (loopbacks[i]->thread == k) 930 threads[k].loopbacks[l++] = loopbacks[i]; 931 } 932 threads_count = j; 933 main_job = pthread_self(); 934 935 signal(SIGINT, signal_handler); 936 signal(SIGTERM, signal_handler); 937 signal(SIGABRT, signal_handler); 938 signal(SIGUSR1, signal_handler_state); 939 signal(SIGUSR2, signal_handler_ignore); 940 941 for (k = 0; k < threads_count; k++) 942 thread_job(&threads[k]); 943 944 if (j > 1) { 945 for (k = 0; k < threads_count; k++) 946 pthread_join(threads[k].thread, NULL); 947 } 948 949 if (use_syslog) 950 closelog(); 951 exit(EXIT_SUCCESS); 952} 953