Fix thread priority and permit multiple instance of zita_a2j/j2apull/3/head
| @@ -50,7 +50,7 @@ main (int argc, char *argv[]) | |||
| /* then, get the internal client handle */ | |||
| client_name = argv[1]; | |||
| if (jack_internal_client_handle (client, client_name, &status, intclient) != 0) { | |||
| if (jack_internal_client_handle (client, client_name, &status, &intclient) != 0) { | |||
| if (status & JackFailure) { | |||
| fprintf (stderr, "client %s not found.\n", client_name); | |||
| } | |||
| @@ -25,8 +25,9 @@ | |||
| #include "alsathread.h" | |||
| Jackclient::Jackclient (jack_client_t* cl, const char*jserv, int mode, int nchan) : | |||
| Jackclient::Jackclient (jack_client_t* cl, const char*jserv, int mode, int nchan, void *arg) : | |||
| _client (cl), | |||
| _arg (arg), | |||
| _mode (mode), | |||
| _nchan (nchan), | |||
| _state (INIT), | |||
| @@ -31,7 +31,7 @@ class Jackclient | |||
| { | |||
| public: | |||
| Jackclient (jack_client_t*, const char *jserv, int mode, int nchan); | |||
| Jackclient (jack_client_t*, const char *jserv, int mode, int nchan, void *arg); | |||
| virtual ~Jackclient (void); | |||
| enum { PLAY, CAPT }; | |||
| @@ -51,6 +51,7 @@ public: | |||
| int bsize (void) const { return _bsize; } | |||
| int rprio (void) const { return _rprio; } | |||
| void register_ports (int nports); | |||
| void *getarg(void) const { return _arg; } | |||
| private: | |||
| @@ -80,6 +81,7 @@ private: | |||
| jack_client_t *_client; | |||
| jack_port_t *_ports [256]; | |||
| void *_arg; | |||
| const char *_jname; | |||
| int _mode; | |||
| int _nchan; | |||
| @@ -47,7 +47,6 @@ int Pxthread::thr_start (int policy, int priority, size_t stacksize) | |||
| min = sched_get_priority_min (policy); | |||
| max = sched_get_priority_max (policy); | |||
| priority += max; | |||
| if (priority > max) priority = max; | |||
| if (priority < min) priority = min; | |||
| parm.sched_priority = priority; | |||
| @@ -27,25 +27,7 @@ | |||
| #include "jackclient.h" | |||
| #include "lfqueue.h" | |||
| static Lfq_int32 commq (16); | |||
| static Lfq_adata alsaq (256); | |||
| static Lfq_jdata infoq (256); | |||
| static Lfq_audio *audioq = 0; | |||
| static bool stop = false; | |||
| static const char *clopt = "hvLj:d:r:p:n:c:Q:I:"; | |||
| static bool v_opt = false; | |||
| static bool L_opt = false; | |||
| static const char *jname = APPNAME; | |||
| static const char *device = 0; | |||
| static int fsamp = 0; // try to get from server if unspecified | |||
| static int bsize = 0; // try to get from server if unspecified | |||
| static int nfrag = 2; | |||
| static int nchan = 2; | |||
| static int rqual = 48; | |||
| static int ltcor = 0; | |||
| static const char *clopt = "hvLj:d:r:p:n:c:Q:I:"; | |||
| static void help (void) | |||
| { | |||
| @@ -68,57 +50,101 @@ static void help (void) | |||
| exit (1); | |||
| } | |||
| static int procoptions (int ac, const char *av []) | |||
| class zita_a2j | |||
| { | |||
| int k; | |||
| optind = 1; | |||
| opterr = 0; | |||
| while ((k = getopt (ac, (char **) av, (char *) clopt)) != -1) | |||
| Lfq_int32 *commq; | |||
| Lfq_adata *alsaq; | |||
| Lfq_jdata *infoq; | |||
| Lfq_audio *audioq; | |||
| bool stop; | |||
| bool v_opt; | |||
| bool L_opt; | |||
| char *jname; | |||
| char *device; | |||
| int fsamp; | |||
| int bsize; | |||
| int nfrag; | |||
| int nchan; | |||
| int rqual; | |||
| int ltcor; | |||
| public: | |||
| zita_a2j() | |||
| { | |||
| commq = new Lfq_int32(16); | |||
| alsaq = new Lfq_adata(256); | |||
| infoq = new Lfq_jdata(256); | |||
| audioq = 0; | |||
| stop = false; | |||
| v_opt = false; | |||
| L_opt = false; | |||
| jname = strdup(APPNAME); | |||
| device = 0; | |||
| fsamp = 0; | |||
| bsize = 0; | |||
| nfrag = 2; | |||
| nchan = 2; | |||
| rqual = 48; | |||
| ltcor = 0; | |||
| A = 0; | |||
| C = 0; | |||
| J = 0; | |||
| } | |||
| private: | |||
| int procoptions (int ac, const char *av []) | |||
| { | |||
| if (optarg && (*optarg == '-')) | |||
| int k; | |||
| optind = 1; | |||
| opterr = 0; | |||
| while ((k = getopt (ac, (char **) av, (char *) clopt)) != -1) | |||
| { | |||
| fprintf (stderr, " Missing argument for '-%c' option.\n", k); | |||
| fprintf (stderr, " Use '-h' to see all options.\n"); | |||
| exit (1); | |||
| if (optarg && (*optarg == '-')) | |||
| { | |||
| fprintf (stderr, " Missing argument for '-%c' option.\n", k); | |||
| fprintf (stderr, " Use '-h' to see all options.\n"); | |||
| exit (1); | |||
| } | |||
| switch (k) | |||
| { | |||
| case 'h' : help (); exit (0); | |||
| case 'v' : v_opt = true; break; | |||
| case 'L' : L_opt = true; break; | |||
| case 'j' : jname = optarg; break; | |||
| case 'd' : device = optarg; break; | |||
| case 'r' : fsamp = atoi (optarg); break; | |||
| case 'p' : bsize = atoi (optarg); break; | |||
| case 'n' : nfrag = atoi (optarg); break; | |||
| case 'c' : nchan = atoi (optarg); break; | |||
| case 'Q' : rqual = atoi (optarg); break; | |||
| case 'I' : ltcor = atoi (optarg); break; | |||
| case '?': | |||
| if (optopt != ':' && strchr (clopt, optopt)) | |||
| { | |||
| fprintf (stderr, " Missing argument for '-%c' option.\n", optopt); | |||
| } | |||
| else if (isprint (optopt)) | |||
| { | |||
| fprintf (stderr, " Unknown option '-%c'.\n", optopt); | |||
| } | |||
| else | |||
| { | |||
| fprintf (stderr, " Unknown option character '0x%02x'.\n", optopt & 255); | |||
| } | |||
| fprintf (stderr, " Use '-h' to see all options.\n"); | |||
| return 1; | |||
| default: | |||
| return 1; | |||
| } | |||
| } | |||
| switch (k) | |||
| { | |||
| case 'h' : help (); exit (0); | |||
| case 'v' : v_opt = true; break; | |||
| case 'L' : L_opt = true; break; | |||
| case 'j' : jname = optarg; break; | |||
| case 'd' : device = optarg; break; | |||
| case 'r' : fsamp = atoi (optarg); break; | |||
| case 'p' : bsize = atoi (optarg); break; | |||
| case 'n' : nfrag = atoi (optarg); break; | |||
| case 'c' : nchan = atoi (optarg); break; | |||
| case 'Q' : rqual = atoi (optarg); break; | |||
| case 'I' : ltcor = atoi (optarg); break; | |||
| case '?': | |||
| if (optopt != ':' && strchr (clopt, optopt)) | |||
| { | |||
| fprintf (stderr, " Missing argument for '-%c' option.\n", optopt); | |||
| } | |||
| else if (isprint (optopt)) | |||
| { | |||
| fprintf (stderr, " Unknown option '-%c'.\n", optopt); | |||
| } | |||
| else | |||
| { | |||
| fprintf (stderr, " Unknown option character '0x%02x'.\n", optopt & 255); | |||
| } | |||
| fprintf (stderr, " Use '-h' to see all options.\n"); | |||
| return 1; | |||
| default: | |||
| return 1; | |||
| } | |||
| return 0; | |||
| } | |||
| return 0; | |||
| } | |||
| static int parse_options (const char* load_init) | |||
| { | |||
| int parse_options (const char* load_init) | |||
| { | |||
| int argsz; | |||
| int argc = 0; | |||
| const char** argv; | |||
| @@ -127,8 +153,8 @@ static int parse_options (const char* load_init) | |||
| char* ptr = args; | |||
| char* savep; | |||
| if (!load_init) { | |||
| return 0; | |||
| if (!load_init) { | |||
| return 0; | |||
| } | |||
| argsz = 8; /* random guess at "maxargs" */ | |||
| @@ -137,149 +163,166 @@ static int parse_options (const char* load_init) | |||
| argv[argc++] = APPNAME; | |||
| while (1) { | |||
| if ((token = strtok_r (ptr, " ", &savep)) == NULL) { | |||
| break; | |||
| } | |||
| if (argc == argsz) { | |||
| argsz *= 2; | |||
| argv = (const char **) realloc (argv, sizeof (char *) * argsz); | |||
| } | |||
| argv[argc++] = token; | |||
| ptr = NULL; | |||
| if ((token = strtok_r (ptr, " ", &savep)) == NULL) { | |||
| break; | |||
| } | |||
| if (argc == argsz) { | |||
| argsz *= 2; | |||
| argv = (const char **) realloc (argv, sizeof (char *) * argsz); | |||
| } | |||
| argv[argc++] = token; | |||
| ptr = NULL; | |||
| } | |||
| return procoptions (argc, argv); | |||
| } | |||
| static void printinfo (void) | |||
| { | |||
| int n; | |||
| double e, r; | |||
| Jdata *J; | |||
| } | |||
| n = 0; | |||
| e = r = 0; | |||
| while (infoq.rd_avail ()) | |||
| void printinfo (void) | |||
| { | |||
| J = infoq.rd_datap (); | |||
| if (J->_state == Jackclient::TERM) | |||
| { | |||
| printf ("Fatal error condition, terminating.\n"); | |||
| stop = true; | |||
| return; | |||
| } | |||
| else if (J->_state == Jackclient::WAIT) | |||
| { | |||
| printf ("Detected excessive timing errors, waiting 15 seconds.\n"); | |||
| printf ("This may happen with current Jack1 after freewheeling.\n"); | |||
| n = 0; | |||
| } | |||
| else if (J->_state == Jackclient::SYNC0) | |||
| { | |||
| printf ("Starting synchronisation.\n"); | |||
| } | |||
| else if (v_opt) | |||
| { | |||
| n++; | |||
| e += J->_error; | |||
| r += J->_ratio; | |||
| } | |||
| infoq.rd_commit (); | |||
| } | |||
| if (n) printf ("%8.3lf %10.6lf\n", e / n, r / n); | |||
| } | |||
| int n; | |||
| double e, r; | |||
| Jdata *J; | |||
| n = 0; | |||
| e = r = 0; | |||
| while (infoq->rd_avail ()) | |||
| { | |||
| J = infoq->rd_datap (); | |||
| if (J->_state == Jackclient::TERM) | |||
| { | |||
| printf ("Fatal error condition, terminating.\n"); | |||
| stop = true; | |||
| return; | |||
| } | |||
| else if (J->_state == Jackclient::WAIT) | |||
| { | |||
| printf ("Detected excessive timing errors, waiting 15 seconds.\n"); | |||
| printf ("This may happen with current Jack1 after freewheeling.\n"); | |||
| n = 0; | |||
| } | |||
| else if (J->_state == Jackclient::SYNC0) | |||
| { | |||
| printf ("Starting synchronisation.\n"); | |||
| } | |||
| else if (v_opt) | |||
| { | |||
| n++; | |||
| e += J->_error; | |||
| r += J->_ratio; | |||
| } | |||
| infoq->rd_commit (); | |||
| } | |||
| if (n) printf ("%8.3lf %10.6lf\n", e / n, r / n); | |||
| } | |||
| static Alsa_pcmi *A = 0; | |||
| static Alsathread *C = 0; | |||
| static Jackclient *J = 0; | |||
| extern "C" { | |||
| Alsa_pcmi *A; | |||
| Alsathread *C; | |||
| Jackclient *J; | |||
| int | |||
| jack_initialize (jack_client_t* client, const char* load_init) | |||
| { | |||
| int k, k_del, opts; | |||
| double t_jack; | |||
| double t_alsa; | |||
| double t_del; | |||
| if (parse_options (load_init)) { | |||
| fprintf (stderr, "parse options failed\n"); | |||
| return 1; | |||
| } | |||
| public: | |||
| if (device == 0) help (); | |||
| if (rqual < 16) rqual = 16; | |||
| if (rqual > 96) rqual = 96; | |||
| if ((fsamp && fsamp < 8000) || (bsize && bsize < 16) || (nfrag < 2) || (nchan < 1)) | |||
| int | |||
| jack_initialize (jack_client_t* client, const char* load_init) | |||
| { | |||
| fprintf (stderr, "Illegal parameter value(s).\n"); | |||
| return 1; | |||
| } | |||
| int k, k_del, opts; | |||
| double t_jack; | |||
| double t_alsa; | |||
| double t_del; | |||
| if (parse_options (load_init)) { | |||
| fprintf (stderr, "parse options failed\n"); | |||
| return 1; | |||
| } | |||
| J = new Jackclient (client, 0, Jackclient::CAPT, 0); | |||
| usleep (100000); | |||
| if (device == 0) help (); | |||
| if (rqual < 16) rqual = 16; | |||
| if (rqual > 96) rqual = 96; | |||
| if ((fsamp && fsamp < 8000) || (bsize && bsize < 16) || (nfrag < 2) || (nchan < 1)) | |||
| { | |||
| fprintf (stderr, "Illegal parameter value(s).\n"); | |||
| return 1; | |||
| } | |||
| /* if SR and/or bufsize are unspecified, use the same values | |||
| as the JACK server. | |||
| */ | |||
| if (fsamp == 0) | |||
| { | |||
| fsamp = J->fsamp(); | |||
| } | |||
| J = new Jackclient (client, 0, Jackclient::CAPT, 0, this); | |||
| usleep (100000); | |||
| if (bsize == 0) | |||
| { | |||
| bsize = J->bsize(); | |||
| } | |||
| /* if SR and/or bufsize are unspecified, use the same values | |||
| as the JACK server. | |||
| */ | |||
| if (fsamp == 0) | |||
| { | |||
| fsamp = J->fsamp(); | |||
| } | |||
| opts = 0; | |||
| if (v_opt) opts |= Alsa_pcmi::DEBUG_ALL; | |||
| if (L_opt) opts |= Alsa_pcmi::FORCE_16B | Alsa_pcmi::FORCE_2CH; | |||
| A = new Alsa_pcmi (0, device, 0, fsamp, bsize, nfrag, opts); | |||
| if (A->state ()) | |||
| { | |||
| fprintf (stderr, "Can't open ALSA capture device '%s'.\n", device); | |||
| return 1; | |||
| if (bsize == 0) | |||
| { | |||
| bsize = J->bsize(); | |||
| } | |||
| opts = 0; | |||
| if (v_opt) opts |= Alsa_pcmi::DEBUG_ALL; | |||
| if (L_opt) opts |= Alsa_pcmi::FORCE_16B | Alsa_pcmi::FORCE_2CH; | |||
| A = new Alsa_pcmi (0, device, 0, fsamp, bsize, nfrag, opts); | |||
| if (A->state ()) | |||
| { | |||
| fprintf (stderr, "Can't open ALSA capture device '%s'.\n", device); | |||
| return 1; | |||
| } | |||
| if (v_opt) A->printinfo (); | |||
| if (nchan > A->ncapt ()) | |||
| { | |||
| nchan = A->ncapt (); | |||
| fprintf (stderr, "Warning: only %d channels are available.\n", nchan); | |||
| } | |||
| C = new Alsathread (A, Alsathread::CAPT); | |||
| J->register_ports (nchan); | |||
| t_alsa = (double) bsize / fsamp; | |||
| if (t_alsa < 1e-3) t_alsa = 1e-3; | |||
| t_jack = (double) J->bsize () / J->fsamp (); | |||
| t_del = 1.5 * t_alsa + t_jack; | |||
| k_del = (int)(t_del * fsamp); | |||
| for (k = 256; k < k_del + J->bsize (); k *= 2); | |||
| audioq = new Lfq_audio (k, nchan); | |||
| C->start (audioq, commq, alsaq, J->rprio () + 10); | |||
| J->start (audioq, commq, alsaq, infoq, J->fsamp () / (double) fsamp, k_del, ltcor, rqual); | |||
| return 0; | |||
| } | |||
| if (v_opt) A->printinfo (); | |||
| if (nchan > A->ncapt ()) | |||
| void jack_finish (void* arg) | |||
| { | |||
| nchan = A->ncapt (); | |||
| fprintf (stderr, "Warning: only %d channels are available.\n", nchan); | |||
| commq->wr_int32 (Alsathread::TERM); | |||
| usleep (100000); | |||
| delete C; | |||
| delete A; | |||
| delete J; | |||
| delete audioq; | |||
| } | |||
| C = new Alsathread (A, Alsathread::CAPT); | |||
| J->register_ports (nchan); | |||
| t_alsa = (double) bsize / fsamp; | |||
| if (t_alsa < 1e-3) t_alsa = 1e-3; | |||
| t_jack = (double) J->bsize () / J->fsamp (); | |||
| t_del = 1.5 * t_alsa + t_jack; | |||
| k_del = (int)(t_del * fsamp); | |||
| for (k = 256; k < k_del + J->bsize (); k *= 2); | |||
| audioq = new Lfq_audio (k, nchan); | |||
| C->start (audioq, &commq, &alsaq, J->rprio () + 10); | |||
| J->start (audioq, &commq, &alsaq, &infoq, J->fsamp () / (double) fsamp, k_del, ltcor, rqual); | |||
| return 0; | |||
| }; | |||
| extern "C" { | |||
| int | |||
| jack_initialize (jack_client_t* client, const char* load_init) | |||
| { | |||
| zita_a2j *c = new zita_a2j(); | |||
| c->jack_initialize(client, load_init); | |||
| } | |||
| void jack_finish (void* arg) | |||
| { | |||
| commq.wr_int32 (Alsathread::TERM); | |||
| usleep (100000); | |||
| delete C; | |||
| delete A; | |||
| delete J; | |||
| delete audioq; | |||
| Jackclient *J = (Jackclient *)arg; | |||
| zita_a2j *c = (zita_a2j *)J->getarg(); | |||
| c->jack_finish(arg); | |||
| delete c; | |||
| } | |||
| } /* extern "C" */ | |||
| @@ -27,25 +27,7 @@ | |||
| #include "jackclient.h" | |||
| #include "lfqueue.h" | |||
| static Lfq_int32 commq (16); | |||
| static Lfq_adata alsaq (256); | |||
| static Lfq_jdata infoq (256); | |||
| static Lfq_audio *audioq = 0; | |||
| static bool stop = false; | |||
| static const char *clopt = "hvLj:d:r:p:n:c:Q:O:"; | |||
| static bool v_opt = false; | |||
| static bool L_opt = false; | |||
| static const char *jname = APPNAME; | |||
| static const char *device = 0; | |||
| static int fsamp = 0; | |||
| static int bsize = 0; | |||
| static int nfrag = 2; | |||
| static int nchan = 2; | |||
| static int rqual = 48; | |||
| static int ltcor = 0; | |||
| static const char *clopt = "hvLj:d:r:p:n:c:Q:I:"; | |||
| static void help (void) | |||
| { | |||
| @@ -68,58 +50,102 @@ static void help (void) | |||
| exit (1); | |||
| } | |||
| static int procoptions (int ac, const char *av []) | |||
| class zita_j2a | |||
| { | |||
| int k; | |||
| optind = 1; | |||
| opterr = 0; | |||
| while ((k = getopt (ac, (char **) av, (char *) clopt)) != -1) | |||
| Lfq_int32 *commq; | |||
| Lfq_adata *alsaq; | |||
| Lfq_jdata *infoq; | |||
| Lfq_audio *audioq; | |||
| bool stop; | |||
| bool v_opt; | |||
| bool L_opt; | |||
| char *jname; | |||
| char *device; | |||
| int fsamp; | |||
| int bsize; | |||
| int nfrag; | |||
| int nchan; | |||
| int rqual; | |||
| int ltcor; | |||
| public: | |||
| zita_j2a() | |||
| { | |||
| commq = new Lfq_int32(16); | |||
| alsaq = new Lfq_adata(256); | |||
| infoq = new Lfq_jdata(256); | |||
| audioq = 0; | |||
| stop = false; | |||
| v_opt = false; | |||
| L_opt = false; | |||
| jname = strdup(APPNAME); | |||
| device = 0; | |||
| fsamp = 0; | |||
| bsize = 0; | |||
| nfrag = 2; | |||
| nchan = 2; | |||
| rqual = 48; | |||
| ltcor = 0; | |||
| A = 0; | |||
| P = 0; | |||
| J = 0; | |||
| } | |||
| private: | |||
| int procoptions (int ac, const char *av []) | |||
| { | |||
| if (optarg && (*optarg == '-')) | |||
| int k; | |||
| optind = 1; | |||
| opterr = 0; | |||
| while ((k = getopt (ac, (char **) av, (char *) clopt)) != -1) | |||
| { | |||
| fprintf (stderr, " Missing argument for '-%c' option.\n", k); | |||
| fprintf (stderr, " Use '-h' to see all options.\n"); | |||
| exit (1); | |||
| if (optarg && (*optarg == '-')) | |||
| { | |||
| fprintf (stderr, " Missing argument for '-%c' option.\n", k); | |||
| fprintf (stderr, " Use '-h' to see all options.\n"); | |||
| exit (1); | |||
| } | |||
| switch (k) | |||
| { | |||
| case 'h' : help (); exit (0); | |||
| case 'v' : v_opt = true; break; | |||
| case 'L' : L_opt = true; break; | |||
| case 'j' : jname = optarg; break; | |||
| case 'd' : device = optarg; break; | |||
| case 'r' : fsamp = atoi (optarg); break; | |||
| case 'p' : bsize = atoi (optarg); break; | |||
| case 'n' : nfrag = atoi (optarg); break; | |||
| case 'c' : nchan = atoi (optarg); break; | |||
| case 'Q' : rqual = atoi (optarg); break; | |||
| case 'O' : ltcor = atoi (optarg); break; | |||
| case '?': | |||
| if (optopt != ':' && strchr (clopt, optopt)) | |||
| { | |||
| fprintf (stderr, " Missing argument for '-%c' option.\n", optopt); | |||
| } | |||
| else if (isprint (optopt)) | |||
| { | |||
| fprintf (stderr, " Unknown option '-%c'.\n", optopt); | |||
| } | |||
| else | |||
| { | |||
| fprintf (stderr, " Unknown option character '0x%02x'.\n", optopt & 255); | |||
| } | |||
| fprintf (stderr, " Use '-h' to see all options.\n"); | |||
| return 1; | |||
| default: | |||
| return 1; | |||
| } | |||
| } | |||
| switch (k) | |||
| { | |||
| case 'h' : help (); exit (0); | |||
| case 'v' : v_opt = true; break; | |||
| case 'L' : L_opt = true; break; | |||
| case 'j' : jname = optarg; break; | |||
| case 'd' : device = optarg; break; | |||
| case 'r' : fsamp = atoi (optarg); break; | |||
| case 'p' : bsize = atoi (optarg); break; | |||
| case 'n' : nfrag = atoi (optarg); break; | |||
| case 'c' : nchan = atoi (optarg); break; | |||
| case 'Q' : rqual = atoi (optarg); break; | |||
| case 'O' : ltcor = atoi (optarg); break; | |||
| case '?': | |||
| if (optopt != ':' && strchr (clopt, optopt)) | |||
| { | |||
| fprintf (stderr, " Missing argument for '-%c' option.\n", optopt); | |||
| } | |||
| else if (isprint (optopt)) | |||
| { | |||
| fprintf (stderr, " Unknown option '-%c'.\n", optopt); | |||
| } | |||
| else | |||
| { | |||
| fprintf (stderr, " Unknown option character '0x%02x'.\n", optopt & 255); | |||
| } | |||
| fprintf (stderr, " Use '-h' to see all options.\n"); | |||
| return 1; | |||
| default: | |||
| return 1; | |||
| } | |||
| } | |||
| return 0; | |||
| } | |||
| return 0; | |||
| } | |||
| static int parse_options (const char* load_init) | |||
| { | |||
| int parse_options (const char* load_init) | |||
| { | |||
| int argsz; | |||
| int argc = 0; | |||
| const char** argv; | |||
| @@ -128,8 +154,8 @@ static int parse_options (const char* load_init) | |||
| char* ptr = args; | |||
| char* savep; | |||
| if (!load_init) { | |||
| return 0; | |||
| if (!load_init) { | |||
| return 0; | |||
| } | |||
| argsz = 8; /* random guess at "maxargs" */ | |||
| @@ -138,144 +164,162 @@ static int parse_options (const char* load_init) | |||
| argv[argc++] = APPNAME; | |||
| while (1) { | |||
| if ((token = strtok_r (ptr, " ", &savep)) == NULL) { | |||
| break; | |||
| } | |||
| if (argc == argsz) { | |||
| argsz *= 2; | |||
| argv = (const char **) realloc (argv, sizeof (char *) * argsz); | |||
| } | |||
| argv[argc++] = token; | |||
| ptr = NULL; | |||
| if ((token = strtok_r (ptr, " ", &savep)) == NULL) { | |||
| break; | |||
| } | |||
| if (argc == argsz) { | |||
| argsz *= 2; | |||
| argv = (const char **) realloc (argv, sizeof (char *) * argsz); | |||
| } | |||
| argv[argc++] = token; | |||
| ptr = NULL; | |||
| } | |||
| return procoptions (argc, argv); | |||
| } | |||
| static void printinfo (void) | |||
| { | |||
| int n; | |||
| double e, r; | |||
| Jdata *J; | |||
| } | |||
| n = 0; | |||
| e = r = 0; | |||
| while (infoq.rd_avail ()) | |||
| void printinfo (void) | |||
| { | |||
| J = infoq.rd_datap (); | |||
| if (J->_state == Jackclient::TERM) | |||
| { | |||
| printf ("Fatal error condition, terminating.\n"); | |||
| stop = true; | |||
| return; | |||
| } | |||
| else if (J->_state == Jackclient::WAIT) | |||
| { | |||
| printf ("Detected excessive timing errors, waiting 15 seconds.\n"); | |||
| printf ("This may happen with current Jack1 after freewheeling.\n"); | |||
| n = 0; | |||
| } | |||
| else if (J->_state == Jackclient::SYNC0) | |||
| { | |||
| printf ("Starting synchronisation.\n"); | |||
| } | |||
| else if (v_opt) | |||
| { | |||
| n++; | |||
| e += J->_error; | |||
| r += J->_ratio; | |||
| } | |||
| infoq.rd_commit (); | |||
| int n; | |||
| double e, r; | |||
| Jdata *J; | |||
| n = 0; | |||
| e = r = 0; | |||
| while (infoq->rd_avail ()) | |||
| { | |||
| J = infoq->rd_datap (); | |||
| if (J->_state == Jackclient::TERM) | |||
| { | |||
| printf ("Fatal error condition, terminating.\n"); | |||
| stop = true; | |||
| return; | |||
| } | |||
| else if (J->_state == Jackclient::WAIT) | |||
| { | |||
| printf ("Detected excessive timing errors, waiting 15 seconds.\n"); | |||
| printf ("This may happen with current Jack1 after freewheeling.\n"); | |||
| n = 0; | |||
| } | |||
| else if (J->_state == Jackclient::SYNC0) | |||
| { | |||
| printf ("Starting synchronisation.\n"); | |||
| } | |||
| else if (v_opt) | |||
| { | |||
| n++; | |||
| e += J->_error; | |||
| r += J->_ratio; | |||
| } | |||
| infoq->rd_commit (); | |||
| } | |||
| if (n) printf ("%8.3lf %10.6lf\n", e / n, r / n); | |||
| } | |||
| if (n) printf ("%8.3lf %10.6lf\n", e / n, r / n); | |||
| } | |||
| Alsa_pcmi *A = 0; | |||
| Alsathread *P = 0; | |||
| Jackclient *J = 0; | |||
| Alsa_pcmi *A; | |||
| Alsathread *P; | |||
| Jackclient *J; | |||
| public: | |||
| extern "C" { | |||
| int jack_initialize (jack_client_t* client, const char* load_init) | |||
| { | |||
| int k, k_del, opts; | |||
| double t_jack; | |||
| double t_alsa; | |||
| double t_del; | |||
| int jack_initialize (jack_client_t* client, const char* load_init) | |||
| { | |||
| int k, k_del, opts; | |||
| double t_jack; | |||
| double t_alsa; | |||
| double t_del; | |||
| if (parse_options (load_init)) { | |||
| return 1; | |||
| } | |||
| if (parse_options (load_init)) { | |||
| if (device == 0) help (); | |||
| if (rqual < 16) rqual = 16; | |||
| if (rqual > 96) rqual = 96; | |||
| if ((fsamp && fsamp < 8000) || (bsize && bsize < 16) || (nfrag < 2) || (nchan < 1)) | |||
| { | |||
| fprintf (stderr, "Illegal parameter value(s).\n"); | |||
| return 1; | |||
| } | |||
| } | |||
| if (device == 0) help (); | |||
| if (rqual < 16) rqual = 16; | |||
| if (rqual > 96) rqual = 96; | |||
| if ((fsamp && fsamp < 8000) || (bsize && bsize < 16) || (nfrag < 2) || (nchan < 1)) | |||
| { | |||
| fprintf (stderr, "Illegal parameter value(s).\n"); | |||
| return 1; | |||
| } | |||
| J = new Jackclient (client, 0, Jackclient::PLAY, 0, this); | |||
| usleep (100000); | |||
| J = new Jackclient (client, 0, Jackclient::PLAY, 0); | |||
| usleep (100000); | |||
| /* if SR and/or bufsize are unspecified, use the same values | |||
| as the JACK server. | |||
| */ | |||
| /* if SR and/or bufsize are unspecified, use the same values | |||
| as the JACK server. | |||
| */ | |||
| if (fsamp == 0) | |||
| { | |||
| fsamp = J->fsamp(); | |||
| } | |||
| if (fsamp == 0) | |||
| { | |||
| fsamp = J->fsamp(); | |||
| } | |||
| if (bsize == 0) | |||
| { | |||
| bsize = J->bsize(); | |||
| } | |||
| if (bsize == 0) | |||
| { | |||
| bsize = J->bsize(); | |||
| } | |||
| opts = 0; | |||
| if (v_opt) opts |= Alsa_pcmi::DEBUG_ALL; | |||
| if (L_opt) opts |= Alsa_pcmi::FORCE_16B | Alsa_pcmi::FORCE_2CH; | |||
| A = new Alsa_pcmi (device, 0, 0, fsamp, bsize, nfrag, opts); | |||
| if (A->state ()) | |||
| { | |||
| fprintf (stderr, "Can't open ALSA playback device '%s'.\n", device); | |||
| return 1; | |||
| opts = 0; | |||
| if (v_opt) opts |= Alsa_pcmi::DEBUG_ALL; | |||
| if (L_opt) opts |= Alsa_pcmi::FORCE_16B | Alsa_pcmi::FORCE_2CH; | |||
| A = new Alsa_pcmi (device, 0, 0, fsamp, bsize, nfrag, opts); | |||
| if (A->state ()) | |||
| { | |||
| fprintf (stderr, "Can't open ALSA playback device '%s'.\n", device); | |||
| return 1; | |||
| } | |||
| if (v_opt) A->printinfo (); | |||
| if (nchan > A->nplay ()) | |||
| { | |||
| nchan = A->nplay (); | |||
| fprintf (stderr, "Warning: only %d channels are available.\n", nchan); | |||
| } | |||
| P = new Alsathread (A, Alsathread::PLAY); | |||
| J->register_ports (nchan); | |||
| t_alsa = (double) bsize / fsamp; | |||
| if (t_alsa < 1e-3) t_alsa = 1e-3; | |||
| t_jack = (double) J->bsize () / J->fsamp (); | |||
| t_del = 1.5 * t_alsa + t_jack; | |||
| k_del = (int)(t_del * fsamp); | |||
| for (k = 256; k < k_del + J->bsize (); k *= 2); | |||
| audioq = new Lfq_audio (k, nchan); | |||
| P->start (audioq, commq, alsaq, J->rprio () + 10); | |||
| J->start (audioq, commq, alsaq, infoq, (double) fsamp / J->fsamp (), k_del, ltcor, rqual); | |||
| return 0; | |||
| } | |||
| if (v_opt) A->printinfo (); | |||
| if (nchan > A->nplay ()) | |||
| void jack_finish (void* arg) | |||
| { | |||
| nchan = A->nplay (); | |||
| fprintf (stderr, "Warning: only %d channels are available.\n", nchan); | |||
| commq->wr_int32 (Alsathread::TERM); | |||
| usleep (100000); | |||
| delete P; | |||
| delete A; | |||
| delete J; | |||
| delete audioq; | |||
| } | |||
| P = new Alsathread (A, Alsathread::PLAY); | |||
| J->register_ports (nchan); | |||
| t_alsa = (double) bsize / fsamp; | |||
| if (t_alsa < 1e-3) t_alsa = 1e-3; | |||
| t_jack = (double) J->bsize () / J->fsamp (); | |||
| t_del = 1.5 * t_alsa + t_jack; | |||
| k_del = (int)(t_del * fsamp); | |||
| for (k = 256; k < k_del + J->bsize (); k *= 2); | |||
| audioq = new Lfq_audio (k, nchan); | |||
| }; | |||
| P->start (audioq, &commq, &alsaq, J->rprio () + 10); | |||
| J->start (audioq, &commq, &alsaq, &infoq, (double) fsamp / J->fsamp (), k_del, ltcor, rqual); | |||
| extern "C" { | |||
| return 0; | |||
| int | |||
| jack_initialize (jack_client_t* client, const char* load_init) | |||
| { | |||
| zita_j2a *c = new zita_j2a(); | |||
| c->jack_initialize(client, load_init); | |||
| } | |||
| void jack_finish (void* arg) | |||
| { | |||
| commq.wr_int32 (Alsathread::TERM); | |||
| usleep (100000); | |||
| delete P; | |||
| delete A; | |||
| delete J; | |||
| delete audioq; | |||
| Jackclient *J = (Jackclient *)arg; | |||
| zita_j2a *c = (zita_j2a *)J->getarg(); | |||
| c->jack_finish(arg); | |||
| delete c; | |||
| } | |||
| } /* extern "C" */ | |||