2 * A simple PCM loopback utility with adaptive sample rate support
4 * Author: Jaroslav Kysela <perex@perex.cz>
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.
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.
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
29 #include <alsa/asoundlib.h>
37 struct loopback_thread {
41 struct loopback **loopbacks;
51 struct loopback **loopbacks = NULL;
52 int loopbacks_count = 0;
53 char **my_argv = NULL;
55 struct loopback_thread *threads;
56 int threads_count = 0;
58 int arg_default_xrun = 0;
59 int arg_default_wake = 0;
61 static void my_exit(struct loopback_thread *thread, int exitcode)
65 for (i = 0; i < thread->loopbacks_count; i++)
66 pcmjob_done(thread->loopbacks[i]);
67 if (thread->threaded) {
68 thread->exitcode = exitcode;
74 static int create_loopback_handle(struct loopback_handle **_handle,
80 struct loopback_handle *handle;
82 handle = calloc(1, sizeof(*handle));
87 handle->device = strdup(device);
88 if (handle->device == NULL)
91 handle->ctldev = strdup(ctldev);
92 if (handle->ctldev == NULL)
95 handle->ctldev = NULL;
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;
109 static int create_loopback(struct loopback **_handle,
110 struct loopback_handle *play,
111 struct loopback_handle *capt,
112 snd_output_t *output)
114 struct loopback *handle;
116 handle = calloc(1, sizeof(*handle));
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;
137 static void set_loop_time(struct loopback *loop, unsigned long loop_time)
139 loop->loop_time = loop_time;
140 loop->loop_limit = loop->capt->rate * loop_time;
143 static void setscheduler(void)
145 struct sched_param sched_param;
147 if (sched_getparam(0, &sched_param) < 0) {
148 logit(LOG_WARNING, "Scheduler getparam failed.\n");
151 sched_param.sched_priority = sched_get_priority_max(SCHED_RR);
152 if (!sched_setscheduler(0, SCHED_RR, &sched_param)) {
154 logit(LOG_WARNING, "Scheduler set to Round Robin with priority %i\n", sched_param.sched_priority);
158 logit(LOG_INFO, "!!!Scheduler set to Round Robin with priority %i FAILED!\n", sched_param.sched_priority);
165 "Usage: alsaloop [OPTION]...\n\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"
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"
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"
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);
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"
215 static long timediff(struct timeval t1, struct timeval t2)
219 t1.tv_sec -= t2.tv_sec;
220 l = (signed long) t1.tv_usec - (signed long) t2.tv_usec;
226 return (t1.tv_sec * 1000000) + l;
229 static void add_loop(struct loopback *loop)
231 loopbacks = realloc(loopbacks, (loopbacks_count + 1) *
232 sizeof(struct loopback *));
233 if (loopbacks == NULL) {
234 logit(LOG_CRIT, "No enough memory\n");
237 loopbacks[loopbacks_count++] = loop;
240 static int init_mixer_control(struct loopback_control *control,
245 err = snd_ctl_elem_id_malloc(&control->id);
248 err = snd_ctl_elem_info_malloc(&control->info);
251 err = snd_ctl_elem_value_malloc(&control->value);
254 err = control_parse_id(id, control->id);
260 static int add_mixers(struct loopback *loop,
264 struct loopback_mixer *mixer, *last = NULL;
268 while (mixers_count > 0) {
269 mixer = calloc(1, sizeof(*mixer));
275 loop->controls = mixer;
277 str1 = strchr(*mixers, '@');
280 err = init_mixer_control(&mixer->src, *mixers);
282 logit(LOG_CRIT, "Wrong mixer control ID syntax '%s'\n", *mixers);
285 err = init_mixer_control(&mixer->dst, str1 ? str1 + 1 : *mixers);
287 logit(LOG_CRIT, "Wrong mixer control ID syntax '%s'\n", str1 ? str1 + 1 : *mixers);
298 static int add_oss_mixers(struct loopback *loop,
302 struct loopback_ossmixer *mixer, *last = NULL;
305 while (mixers_count > 0) {
306 mixer = calloc(1, sizeof(*mixer));
312 loop->oss_controls = mixer;
314 str1 = strchr(*mixers, ',');
317 str2 = strchr(str1 ? str1 + 1 : *mixers, '@');
320 mixer->alsa_id = strdup(*mixers);
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");
338 static void enable_syslog(void)
342 openlog("alsaloop", LOG_NDELAY|LOG_PID, LOG_DAEMON);
346 static int parse_config_file(const char *file, snd_output_t *output);
348 static int parse_config(int argc, char *argv[], snd_output_t *output,
351 struct option long_option[] =
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'},
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;
399 int arg_resample = 0;
400 #ifdef USE_SAMPLERATE
401 int arg_samplerate = SRC_SINC_FASTEST + 1;
403 int arg_sync = SYNC_TYPE_AUTO;
404 int arg_slave = SLAVE_TYPE_AUTO;
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;
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)
426 arg_config = strdup(optarg);
433 arg_pdevice = strdup(optarg);
436 arg_cdevice = strdup(optarg);
439 arg_pctl = strdup(optarg);
442 arg_cctl = strdup(optarg);
446 arg_latency_req = err >= 4 ? err : 4;
450 arg_latency_reqtime = err >= 500 ? err : 500;
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;
461 arg_channels = err >= 1 && err < 1024 ? err : 1;
465 arg_rate = err >= 4000 && err < 200000 ? err : 44100;
469 arg_buffer_size = err >= 32 && err < 200000 ? err : 0;
473 arg_period_size = err >= 32 && err < 200000 ? err : 0;
477 arg_loop_time = err >= 1 && err <= 100000 ? err : 30;
488 #ifdef USE_SAMPLERATE
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;
501 arg_samplerate = atoi(optarg);
502 if (arg_samplerate < 0 || arg_samplerate > SRC_LINEAR)
503 arg_sync = SRC_SINC_FASTEST;
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;
521 arg_sync = atoi(optarg);
522 if (arg_sync < 0 || arg_sync > SYNC_TYPE_LAST)
523 arg_sync = SYNC_TYPE_AUTO;
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;
533 arg_slave = atoi(optarg);
534 if (arg_slave < 0 || arg_slave > SLAVE_TYPE_LAST)
535 arg_slave = SLAVE_TYPE_AUTO;
538 arg_thread = atoi(optarg);
540 arg_thread = 10000000 + loopbacks_count;
543 if (arg_mixers_count >= MAX_MIXERS) {
544 logit(LOG_CRIT, "Maximum redirected mixer controls reached (max %i)\n", (int)MAX_MIXERS);
547 arg_mixers[arg_mixers_count++] = optarg;
550 if (arg_ossmixers_count >= MAX_MIXERS) {
551 logit(LOG_CRIT, "Maximum redirected mixer controls reached (max %i)\n", (int)MAX_MIXERS);
554 arg_ossmixers[arg_ossmixers_count++] = optarg;
560 if (strcasecmp(optarg, "serialopen") == 0)
561 workarounds |= WORKAROUND_SERIALOPEN;
566 arg_default_xrun = 1;
569 arg_wake = atoi(optarg);
571 arg_default_wake = arg_wake;
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");
588 logit(LOG_CRIT, "Unable to create playback handle.\n");
591 err = create_loopback_handle(&capt, arg_cdevice, arg_cctl, "capture");
593 logit(LOG_CRIT, "Unable to create capture handle.\n");
596 err = create_loopback(&loop, play, capt, output);
598 logit(LOG_CRIT, "Unable to create loopback handle.\n");
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);
617 logit(LOG_CRIT, "Unable to add mixer controls.\n");
620 err = add_oss_mixers(loop, arg_ossmixers, arg_ossmixers_count);
622 logit(LOG_CRIT, "Unable to add ossmixer controls.\n");
625 #ifdef USE_SAMPLERATE
626 loop->src_enable = arg_samplerate > 0;
627 if (loop->src_enable)
628 loop->src_converter_type = arg_samplerate - 1;
630 set_loop_time(loop, arg_loop_time);
635 return parse_config_file(arg_config, output);
638 static int parse_config_file(const char *file, snd_output_t *output)
641 char line[2048], word[2048];
643 int argc, c, err = 0;
646 fp = fopen(file, "r");
648 logit(LOG_CRIT, "Unable to open file '%s': %s\n", file, strerror(errno));
652 if (fgets(line, sizeof(line)-1, fp) == NULL)
654 line[sizeof(line)-1] = '\0';
655 my_argv = realloc(my_argv, my_argc + MAX_ARGS * sizeof(char *));
658 argv = my_argv + my_argc;
660 argv[argc++] = strdup("<prog>");
665 while (*str && (*str == ' ' || *str < ' '))
669 if (*str == '\'' || *str == '\"') {
671 while (*str && *str != c)
676 while (*str && *str != ' ' && *str != '\t')
680 if (*(ptr-1) == '\n')
683 if (argc >= MAX_ARGS) {
684 logit(LOG_CRIT, "Too many arguments.");
687 argv[argc++] = strdup(word);
691 /* erase runtime variables for getopt */
696 err = parse_config(argc, argv, output, 0);
708 static void thread_job1(void *_data)
710 struct loopback_thread *thread = _data;
711 snd_output_t *output = thread->output;
712 struct pollfd *pfds = NULL;
714 int i, j, err, wake = 1000000;
718 for (i = 0; i < thread->loopbacks_count; i++) {
719 err = pcmjob_init(thread->loopbacks[i]);
721 logit(LOG_CRIT, "Loopback initialization failure.\n");
722 my_exit(thread, EXIT_FAILURE);
725 for (i = 0; i < thread->loopbacks_count; i++) {
726 err = pcmjob_start(thread->loopbacks[i]);
728 logit(LOG_CRIT, "Loopback start failure.\n");
729 my_exit(thread, EXIT_FAILURE);
731 pfds_count += thread->loopbacks[i]->pollfd_count;
732 j = thread->loopbacks[i]->wake;
733 if (j > 0 && j < wake)
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);
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]);
748 logit(LOG_CRIT, "Poll FD initialization failed.\n");
749 my_exit(thread, EXIT_FAILURE);
754 gettimeofday(&tv1, NULL);
755 err = poll(pfds, j, wake);
759 gettimeofday(&tv2, NULL);
760 snd_output_printf(output, "pool took %lius\n", timediff(tv2, tv1));
763 if (err == -EINTR || err == -ERESTART)
765 logit(LOG_CRIT, "Poll failed: %s\n", strerror(-err));
766 my_exit(thread, EXIT_FAILURE);
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]);
773 logit(LOG_CRIT, "pcmjob failed.\n");
777 j += loop->active_pollfd_count;
781 my_exit(thread, EXIT_SUCCESS);
784 static void thread_job(struct loopback_thread *thread)
786 if (!thread->threaded) {
790 pthread_create(&thread->thread, NULL, (void *) &thread_job1,
794 static void send_to_all(int sig)
796 struct loopback_thread *thread;
799 for (i = 0; i < threads_count; i++) {
800 thread = &threads[i];
801 if (thread->threaded)
802 pthread_kill(thread->thread, sig);
806 static void signal_handler(int sig)
809 send_to_all(SIGUSR2);
812 static void signal_handler_state(int sig)
814 pthread_t self = pthread_self();
815 struct loopback_thread *thread;
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]);
827 signal(sig, signal_handler_state);
830 static void signal_handler_ignore(int sig)
832 signal(sig, signal_handler_ignore);
835 int main(int argc, char *argv[])
837 snd_output_t *output;
840 err = snd_output_stdio_attach(&output, stdout, 0);
842 logit(LOG_CRIT, "Output failed: %s\n", snd_strerror(err));
845 err = parse_config(argc, argv, output, 1);
847 logit(LOG_CRIT, "Unable to parse arguments or configuration...\n");
851 free(my_argv[--my_argc]);
854 if (loopbacks_count <= 0) {
855 logit(LOG_CRIT, "No loopback defined...\n");
860 if (daemon(0, 0) < 0) {
861 logit(LOG_CRIT, "daemon() failed: %s\n", strerror(errno));
866 logit(LOG_CRIT, "fork() failed: %s\n", strerror(errno));
875 /* we must sort thread IDs */
879 for (i = 0; i < loopbacks_count; i++) {
880 if (loopbacks[i]->thread < k &&
881 loopbacks[i]->thread > j)
882 k = loopbacks[i]->thread;
885 for (i = 0; i < loopbacks_count; i++) {
886 if (loopbacks[i]->thread == k)
887 loopbacks[i]->thread = j;
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;
896 threads = calloc(1, sizeof(struct loopback_thread) * j);
897 if (threads == NULL) {
898 logit(LOG_CRIT, "No enough memory\n");
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)
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];
915 main_job = pthread_self();
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);
923 for (k = 0; k < threads_count; k++)
924 thread_job(&threads[k]);
927 for (k = 0; k < threads_count; k++)
928 pthread_join(threads[k].thread, NULL);