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