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