• 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 "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 
39 struct 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 
48 int quit = 0;
49 int verbose = 0;
50 int workarounds = 0;
51 int daemonize = 0;
52 int use_syslog = 0;
53 struct loopback **loopbacks = NULL;
54 int loopbacks_count = 0;
55 char **my_argv = NULL;
56 int my_argc = 0;
57 struct loopback_thread *threads;
58 int threads_count = 0;
59 pthread_t main_job;
60 int arg_default_xrun = 0;
61 int arg_default_wake = 0;
62 
my_exit(struct loopback_thread * thread,int exitcode)63 static 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 
create_loopback_handle(struct loopback_handle ** _handle,const char * device,const char * ctldev,const char * id)76 static 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 
create_loopback(struct loopback ** _handle,struct loopback_handle * play,struct loopback_handle * capt,snd_output_t * output)116 static 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 
set_loop_time(struct loopback * loop,unsigned long loop_time)144 static 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 
setscheduler(void)150 static 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 
help(void)168 void 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 
timediff(struct timeval t1,struct timeval t2)223 static 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 
add_loop(struct loopback * loop)237 static 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 
init_mixer_control(struct loopback_control * control,char * id)248 static 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 
add_mixers(struct loopback * loop,char ** mixers,int mixers_count)268 static 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 
add_oss_mixers(struct loopback * loop,char ** mixers,int mixers_count)306 static 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 
enable_syslog(void)346 static 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 
354 static int parse_config_file(const char *file, snd_output_t *output);
355 
parse_config(int argc,char * argv[],snd_output_t * output,int cmdline)356 static 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 
parse_config_file(const char * file,snd_output_t * output)656 static 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 
thread_job1(void * _data)726 static 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 
thread_job(struct loopback_thread * thread)802 static 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 
send_to_all(int sig)812 static 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 
signal_handler(int sig ATTRIBUTE_UNUSED)824 static void signal_handler(int sig ATTRIBUTE_UNUSED)
825 {
826 	quit = 1;
827 	send_to_all(SIGUSR2);
828 }
829 
signal_handler_state(int sig)830 static 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 
signal_handler_ignore(int sig)848 static void signal_handler_ignore(int sig)
849 {
850 	signal(sig, signal_handler_ignore);
851 }
852 
main(int argc,char * argv[])853 int 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