• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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