int main(int argc, char *argv[]) { struct option long_option[] = { {"help", 0, NULL, 'h'}, {"pdevice", 1, NULL, 'P'}, {"cdevice", 1, NULL, 'C'}, {"min", 1, NULL, 'm'}, {"max", 1, NULL, 'M'}, {"frames", 1, NULL, 'F'}, {"format", 1, NULL, 'f'}, {"channels", 1, NULL, 'c'}, {"rate", 1, NULL, 'r'}, {"seconds", 1, NULL, 's'}, {"block", 0, NULL, 'b'}, {"time", 1, NULL, 't'}, {"poll", 0, NULL, 'p'}, {"effect", 0, NULL, 'e'}, {NULL, 0, NULL, 0}, }; snd_pcm_t *phandle, *chandle; char *buffer; int err, latency, morehelp; int ok; snd_timestamp_t p_tstamp, c_tstamp; ssize_t r; size_t frames_in, frames_out, in_max; int effect = 0; morehelp = 0; while (1) { int c; if ((c = getopt_long(argc, argv, "hP:C:m:M:F:f:c:r:s:bt:pe", long_option, NULL)) < 0) break; switch (c) { case 'h': morehelp++; break; case 'P': pdevice = strdup(optarg); break; case 'C': cdevice = strdup(optarg); break; case 'm': err = atoi(optarg) / 2; latency_min = err >= 4 ? err : 4; if (latency_max < latency_min) latency_max = latency_min; break; case 'M': err = atoi(optarg) / 2; latency_max = latency_min > err ? latency_min : err; break; case 'f': format = snd_pcm_format_value(optarg); if (format == SND_PCM_FORMAT_UNKNOWN) { printf("Unknown format, setting to default S16_LE\n"); format = SND_PCM_FORMAT_S16_LE; } break; case 'c': err = atoi(optarg); channels = err >= 1 && err < 1024 ? err : 1; break; case 'r': err = atoi(optarg); rate = err >= 4000 && err < 200000 ? err : 44100; break; case 's': err = atoi(optarg); loop_sec = err >= 1 && err <= 100000 ? err : 30; break; case 'b': block = 1; break; case 't': tick_time = atoi(optarg); tick_time = tick_time < 0 ? 0 : tick_time; break; case 'p': use_poll = 1; break; case 'e': effect = 1; break; } } if (morehelp) { help(); return 0; } err = snd_output_stdio_attach(&output, stdout, 0); if (err < 0) { printf("Output failed: %s\n", snd_strerror(err)); return 0; } loop_limit = loop_sec * rate; latency = latency_min - 4; buffer = malloc((latency_max * snd_pcm_format_width(format) / 8) * 2); setscheduler(); printf("Playback device is %s\n", pdevice); printf("Capture device is %s\n", cdevice); printf("Parameters are %iHz, %s, %i channels, %s mode\n", rate, snd_pcm_format_name(format), channels, block ? "blocking" : "non-blocking"); printf("Wanted tick time: %ius, poll mode: %s\n", tick_time, use_poll ? "yes" : "no"); printf("Loop limit is %li frames, minimum latency = %i, maximum latency = %i\n", loop_limit, latency_min * 2, latency_max * 2); if ((err = snd_pcm_open(&phandle, pdevice, SND_PCM_STREAM_PLAYBACK, block ? 0 : SND_PCM_NONBLOCK)) < 0) { printf("Playback open error: %s\n", snd_strerror(err)); return 0; } if ((err = snd_pcm_open(&chandle, cdevice, SND_PCM_STREAM_CAPTURE, block ? 0 : SND_PCM_NONBLOCK)) < 0) { printf("Record open error: %s\n", snd_strerror(err)); return 0; } /* initialize the filter sweep variables */ if (effect) { fs = (float) rate; BW = FILTER_BANDWIDTH; lfo = 0; dlfo = 2.*M_PI*FILTERSWEEP_LFO_FREQ/fs; x[0] = (float*) malloc(channels*sizeof(float)); x[1] = (float*) malloc(channels*sizeof(float)); x[2] = (float*) malloc(channels*sizeof(float)); y[0] = (float*) malloc(channels*sizeof(float)); y[1] = (float*) malloc(channels*sizeof(float)); y[2] = (float*) malloc(channels*sizeof(float)); } while (1) { frames_in = frames_out = 0; if (setparams(phandle, chandle, &latency) < 0) break; showlatency(latency); if (tick_time_ok) printf("Using tick time %ius\n", tick_time_ok); if ((err = snd_pcm_link(chandle, phandle)) < 0) { printf("Streams link error: %s\n", snd_strerror(err)); exit(0); } if (snd_pcm_format_set_silence(format, buffer, latency*channels) < 0) { fprintf(stderr, "silence error\n"); break; } if (writebuf(phandle, buffer, latency, &frames_out) < 0) { fprintf(stderr, "write error\n"); break; } if (writebuf(phandle, buffer, latency, &frames_out) < 0) { fprintf(stderr, "write error\n"); break; } if ((err = snd_pcm_start(chandle)) < 0) { printf("Go error: %s\n", snd_strerror(err)); exit(0); } gettimestamp(phandle, &p_tstamp); gettimestamp(chandle, &c_tstamp); #if 0 printf("Playback:\n"); showstat(phandle, frames_out); printf("Capture:\n"); showstat(chandle, frames_in); #endif ok = 1; in_max = 0; while (ok && frames_in < loop_limit) { if (use_poll) { /* use poll to wait for next event */ snd_pcm_wait(chandle, 1000); } if ((r = readbuf(chandle, buffer, latency, &frames_in, &in_max)) < 0) ok = 0; else { if (effect) applyeffect(buffer,r); if (writebuf(phandle, buffer, r, &frames_out) < 0) ok = 0; } } if (ok) printf("Success\n"); else printf("Failure\n"); printf("Playback:\n"); showstat(phandle, frames_out); printf("Capture:\n"); showstat(chandle, frames_in); showinmax(in_max); if (p_tstamp.tv_sec == p_tstamp.tv_sec && p_tstamp.tv_usec == c_tstamp.tv_usec) printf("Hardware sync\n"); snd_pcm_drop(chandle); snd_pcm_nonblock(phandle, 0); snd_pcm_drain(phandle); snd_pcm_nonblock(phandle, !block ? 1 : 0); if (ok) { #if 1 printf("Playback time = %li.%i, Record time = %li.%i, diff = %li\n", p_tstamp.tv_sec, (int)p_tstamp.tv_usec, c_tstamp.tv_sec, (int)c_tstamp.tv_usec, timediff(p_tstamp, c_tstamp)); #endif break; } snd_pcm_unlink(chandle); snd_pcm_hw_free(phandle); snd_pcm_hw_free(chandle); } snd_pcm_close(phandle); snd_pcm_close(chandle); return 0; }
int main(int argc, char **argv) { bool_t nodaemon = false; #ifdef POSIX_PRIORITY_SCHEDULING bool_t realtime = false; #endif bool_t testconfig = false; char *conffile = NULL, *pidfile = NULL; int c; struct utsname utsbuf; /* Arguments */ #ifdef POSIX_PRIORITY_SCHEDULING while ((c = getopt(argc, argv, "drp:c:a:A:b:B:ht")) != EOF) { #else while ((c = getopt(argc, argv, "dp:c:a:A:b:B:ht")) != EOF) { #endif switch(c) { case 'c': conffile = optarg; break; case 'p': pidfile = optarg; break; case 'a': bindaddr = optarg; break; case 'A': bindaddr6 = optarg; break; case 'b': bindport = atoi(optarg); break; case 'B': bindport6 = atoi(optarg); break; case 'd': nodaemon = true; break; case 'h': printhelp(); break; case 't': testconfig = true; break; #ifdef POSIX_PRIORITY_SCHEDULING case 'r': realtime = true; break; #endif default: fprintf(stderr, "Unrecognized option\n"); printhelp(); break; } } if (testconfig) { if (!Conf_ok(conffile)) exit(1); else exit(0); } /* Initialize the config subsystem early; * switch_user() will need to read some config variables as well as logging. */ Conf_init(conffile); /* Logging to terminal if not daemonizing, otherwise to syslog or log file. */ if (!nodaemon) { daemonize(); Log_init(false); if (pidfile != NULL) lockfile(pidfile); switch_user(); /* Reopen log file. If user switch results in access denied, we catch * it early. */ Log_reset(); } else Log_init(true); signal(SIGCHLD, SIG_IGN); /* ignore child */ signal(SIGTSTP, SIG_IGN); /* ignore tty signals */ signal(SIGTTOU, SIG_IGN); signal(SIGTTIN, SIG_IGN); signal(SIGPIPE, SIG_IGN); signal(SIGHUP, signal_handler); /* catch hangup signal */ signal(SIGTERM, signal_handler); /* catch kill signal */ /* Build system string */ if (uname(&utsbuf) == 0) { snprintf(system_string, 64, "%s %s", utsbuf.sysname, utsbuf.machine); snprintf(version_string, 64, "%s", utsbuf.release); } else { snprintf(system_string, 64, "unknown unknown"); snprintf(version_string, 64, "unknown"); } /* Initializing */ SSLi_init(); Chan_init(); Client_init(); Ban_init(); #ifdef USE_SHAREDMEMORY_API Sharedmemory_init( bindport, bindport6 ); #endif #ifdef POSIX_PRIORITY_SCHEDULING if (realtime) setscheduler(); #endif Server_run(); #ifdef USE_SHAREDMEMORY_API Sharedmemory_deinit(); #endif Ban_deinit(); SSLi_deinit(); Chan_free(); Log_free(); Conf_deinit(); if (pidfile != NULL) unlink(pidfile); return 0; }
static void thread_job1(void *_data) { struct loopback_thread *thread = _data; snd_output_t *output = thread->output; struct pollfd *pfds = NULL; int pfds_count = 0; int i, j, err, wake = 1000000; setscheduler(); for (i = 0; i < thread->loopbacks_count; i++) { err = pcmjob_init(thread->loopbacks[i]); if (err < 0) { logit(LOG_CRIT, "Loopback initialization failure.\n"); my_exit(thread, EXIT_FAILURE); } } for (i = 0; i < thread->loopbacks_count; i++) { err = pcmjob_start(thread->loopbacks[i]); if (err < 0) { logit(LOG_CRIT, "Loopback start failure.\n"); my_exit(thread, EXIT_FAILURE); } pfds_count += thread->loopbacks[i]->pollfd_count; j = thread->loopbacks[i]->wake; if (j > 0 && j < wake) wake = j; } if (wake >= 1000000) wake = -1; pfds = calloc(pfds_count, sizeof(struct pollfd)); if (pfds == NULL || pfds_count <= 0) { logit(LOG_CRIT, "Poll FDs allocation failed.\n"); my_exit(thread, EXIT_FAILURE); } while (!quit) { struct timeval tv1, tv2; for (i = j = 0; i < thread->loopbacks_count; i++) { err = pcmjob_pollfds_init(thread->loopbacks[i], &pfds[j]); if (err < 0) { logit(LOG_CRIT, "Poll FD initialization failed.\n"); my_exit(thread, EXIT_FAILURE); } j += err; } if (verbose > 10) gettimeofday(&tv1, NULL); usleep(1000); err = poll(pfds, j, wake); if (err < 0) err = -errno; if (verbose > 10) { gettimeofday(&tv2, NULL); snd_output_printf(output, "pool took %lius\n", timediff(tv2, tv1)); } if (err < 0) { if (err == -EINTR || err == -ERESTART) continue; logit(LOG_CRIT, "Poll failed: %s\n", strerror(-err)); my_exit(thread, EXIT_FAILURE); } for (i = j = 0; i < thread->loopbacks_count; i++) { struct loopback *loop = thread->loopbacks[i]; if (j < loop->active_pollfd_count) { err = pcmjob_pollfds_handle(loop, &pfds[j]); if (err < 0) { logit(LOG_CRIT, "pcmjob failed.\n"); return EXIT_FAILURE; } } j += loop->active_pollfd_count; } } my_exit(thread, EXIT_SUCCESS); }