Signed-off-by: falkTX <falktx@falktx.com>tags/v1.9.19
@@ -28,7 +28,7 @@ | |||||
#include "lfqueue.h" | #include "lfqueue.h" | ||||
#include "jack/control.h" | #include "jack/control.h" | ||||
static const char *clopt = "hvLSj:d:r:p:n:c:Q:I:"; | |||||
static const char *clopt = "hvLSwj:d:r:p:n:c:Q:I:"; | |||||
static void help (void) | static void help (void) | ||||
{ | { | ||||
@@ -47,6 +47,7 @@ static void help (void) | |||||
jack_info (" -Q <quality> Resampling quality, 16..96 [auto]"); | jack_info (" -Q <quality> Resampling quality, 16..96 [auto]"); | ||||
jack_info (" -I <samples> Latency adjustment [0]"); | jack_info (" -I <samples> Latency adjustment [0]"); | ||||
jack_info (" -L Force 16-bit and 2 channels [off]"); | jack_info (" -L Force 16-bit and 2 channels [off]"); | ||||
jack_info (" -w Wait until soundcard is available [off]"); | |||||
jack_info (" -v Print tracing information [off]"); | jack_info (" -v Print tracing information [off]"); | ||||
} | } | ||||
@@ -60,6 +61,7 @@ class zita_a2j | |||||
bool v_opt; | bool v_opt; | ||||
bool L_opt; | bool L_opt; | ||||
bool S_opt; | bool S_opt; | ||||
bool w_opt; | |||||
char *jname; | char *jname; | ||||
char *device; | char *device; | ||||
int fsamp; | int fsamp; | ||||
@@ -81,6 +83,7 @@ public: | |||||
v_opt = false; | v_opt = false; | ||||
L_opt = false; | L_opt = false; | ||||
S_opt = false; | S_opt = false; | ||||
w_opt = false; | |||||
jname = strdup(APPNAME); | jname = strdup(APPNAME); | ||||
device = 0; | device = 0; | ||||
fsamp = 48000; | fsamp = 48000; | ||||
@@ -92,6 +95,7 @@ public: | |||||
A = 0; | A = 0; | ||||
C = 0; | C = 0; | ||||
J = 0; | J = 0; | ||||
t = 0; | |||||
} | } | ||||
private: | private: | ||||
@@ -116,6 +120,7 @@ private: | |||||
case 'v' : v_opt = true; break; | case 'v' : v_opt = true; break; | ||||
case 'L' : L_opt = true; break; | case 'L' : L_opt = true; break; | ||||
case 'S' : S_opt = true; break; | case 'S' : S_opt = true; break; | ||||
case 'w' : w_opt = true; break; | |||||
case 'j' : jname = optarg; break; | case 'j' : jname = optarg; break; | ||||
case 'd' : device = optarg; break; | case 'd' : device = optarg; break; | ||||
case 'r' : fsamp = atoi (optarg); break; | case 'r' : fsamp = atoi (optarg); break; | ||||
@@ -227,15 +232,48 @@ private: | |||||
Alsathread *C; | Alsathread *C; | ||||
Jackclient *J; | Jackclient *J; | ||||
pthread_t t; | |||||
int topts; | |||||
static void* _retry_alsa_pcmi (void *arg) | |||||
{ | |||||
((zita_a2j*)arg)->retry_alsa_pcmi (); | |||||
return NULL; | |||||
} | |||||
void retry_alsa_pcmi () | |||||
{ | |||||
Alsa_pcmi *a; | |||||
while (! stop) | |||||
{ | |||||
sleep(1); | |||||
a = new Alsa_pcmi (0, device, 0, fsamp, bsize, nfrag, topts); | |||||
if (a->state ()) | |||||
{ | |||||
delete a; | |||||
continue; | |||||
} | |||||
A = a; | |||||
if (v_opt) A->printinfo (); | |||||
C = new Alsathread (A, Alsathread::CAPT); | |||||
usleep (100*1000); | |||||
jack_initialize_part2 (); | |||||
jack_info (APPNAME ": Device is now available and has been activated"); | |||||
break; | |||||
} | |||||
t = 0; | |||||
} | |||||
public: | public: | ||||
int | int | ||||
jack_initialize (jack_client_t* client, const char* load_init) | 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 opts; | |||||
if (parse_options (load_init)) { | if (parse_options (load_init)) { | ||||
jack_error (APPNAME ": parse options failed"); | jack_error (APPNAME ": parse options failed"); | ||||
@@ -261,22 +299,56 @@ public: | |||||
opts = 0; | opts = 0; | ||||
if (v_opt) opts |= Alsa_pcmi::DEBUG_ALL; | if (v_opt) opts |= Alsa_pcmi::DEBUG_ALL; | ||||
if (L_opt) opts |= Alsa_pcmi::FORCE_16B | Alsa_pcmi::FORCE_2CH; | 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 ()) | |||||
if (w_opt) | |||||
{ | { | ||||
jack_error (APPNAME ": Can't open ALSA capture device '%s'.", device); | |||||
delete this; | |||||
return 1; | |||||
J = new Jackclient (client, 0, Jackclient::CAPT, nchan, S_opt, this); | |||||
A = new Alsa_pcmi (0, device, 0, fsamp, bsize, nfrag, opts); | |||||
// if device is not available, spawn thread to keep trying | |||||
if (A->state ()) | |||||
{ | |||||
delete A; | |||||
A = NULL; | |||||
topts = opts; | |||||
pthread_create (&t, NULL, _retry_alsa_pcmi, this); | |||||
jack_info (APPNAME ": Could not open device, will keep trying in new thread..."); | |||||
return 0; | |||||
} | |||||
// otherwise continue as normal | |||||
if (v_opt) A->printinfo (); | |||||
C = new Alsathread (A, Alsathread::CAPT); | |||||
} | } | ||||
if (v_opt) A->printinfo (); | |||||
if (nchan > A->ncapt ()) | |||||
else | |||||
{ | { | ||||
nchan = A->ncapt (); | |||||
jack_error (APPNAME ": Warning: only %d channels are available.", nchan); | |||||
A = new Alsa_pcmi (0, device, 0, fsamp, bsize, nfrag, opts); | |||||
if (A->state ()) | |||||
{ | |||||
jack_error (APPNAME ": Can't open ALSA capture device '%s'.", device); | |||||
delete this; | |||||
return 1; | |||||
} | |||||
if (v_opt) A->printinfo (); | |||||
if (nchan > A->ncapt ()) | |||||
{ | |||||
nchan = A->ncapt (); | |||||
jack_error (APPNAME ": Warning: only %d channels are available.", nchan); | |||||
} | |||||
C = new Alsathread (A, Alsathread::CAPT); | |||||
J = new Jackclient (client, 0, Jackclient::CAPT, nchan, S_opt, this); | |||||
} | } | ||||
C = new Alsathread (A, Alsathread::CAPT); | |||||
J = new Jackclient (client, 0, Jackclient::CAPT, nchan, S_opt, this); | |||||
usleep (100000); | |||||
usleep (100*1000); | |||||
jack_initialize_part2 (); | |||||
return 0; | |||||
} | |||||
void jack_initialize_part2 () | |||||
{ | |||||
int k, k_del; | |||||
double t_alsa; | |||||
double t_jack; | |||||
double t_del; | |||||
t_alsa = (double) bsize / fsamp; | t_alsa = (double) bsize / fsamp; | ||||
if (t_alsa < 1e-3) t_alsa = 1e-3; | if (t_alsa < 1e-3) t_alsa = 1e-3; | ||||
@@ -297,12 +369,16 @@ public: | |||||
C->start (audioq, commq, alsaq, J->rprio () + 10); | C->start (audioq, commq, alsaq, J->rprio () + 10); | ||||
J->start (audioq, commq, alsaq, infoq, J->fsamp () / (double) fsamp, k_del, ltcor, rqual); | J->start (audioq, commq, alsaq, infoq, J->fsamp () / (double) fsamp, k_del, ltcor, rqual); | ||||
return 0; | |||||
} | } | ||||
void jack_finish (void* arg) | void jack_finish (void* arg) | ||||
{ | { | ||||
if (t != 0) | |||||
{ | |||||
stop = true; | |||||
pthread_join(t, NULL); | |||||
} | |||||
commq->wr_int32 (Alsathread::TERM); | commq->wr_int32 (Alsathread::TERM); | ||||
usleep (100000); | usleep (100000); | ||||
delete C; | delete C; | ||||
@@ -28,7 +28,7 @@ | |||||
#include "lfqueue.h" | #include "lfqueue.h" | ||||
#include "jack/control.h" | #include "jack/control.h" | ||||
static const char *clopt = "hvLSj:d:r:p:n:c:Q:O:"; | |||||
static const char *clopt = "hvLSwj:d:r:p:n:c:Q:O:"; | |||||
static void help (void) | static void help (void) | ||||
{ | { | ||||
@@ -47,6 +47,7 @@ static void help (void) | |||||
jack_info (" -Q <quality> Resampling quality, 16..96 [auto]"); | jack_info (" -Q <quality> Resampling quality, 16..96 [auto]"); | ||||
jack_info (" -O <samples> Latency adjustment [0]"); | jack_info (" -O <samples> Latency adjustment [0]"); | ||||
jack_info (" -L Force 16-bit and 2 channels [off]"); | jack_info (" -L Force 16-bit and 2 channels [off]"); | ||||
jack_info (" -w Wait until soundcard is available [off]"); | |||||
jack_info (" -v Print tracing information [off]"); | jack_info (" -v Print tracing information [off]"); | ||||
} | } | ||||
@@ -60,6 +61,7 @@ class zita_j2a | |||||
bool v_opt; | bool v_opt; | ||||
bool L_opt; | bool L_opt; | ||||
bool S_opt; | bool S_opt; | ||||
bool w_opt; | |||||
char *jname; | char *jname; | ||||
char *device; | char *device; | ||||
int fsamp; | int fsamp; | ||||
@@ -81,6 +83,7 @@ public: | |||||
v_opt = false; | v_opt = false; | ||||
L_opt = false; | L_opt = false; | ||||
S_opt = false; | S_opt = false; | ||||
w_opt = false; | |||||
jname = strdup(APPNAME); | jname = strdup(APPNAME); | ||||
device = 0; | device = 0; | ||||
fsamp = 48000; | fsamp = 48000; | ||||
@@ -92,6 +95,7 @@ public: | |||||
A = 0; | A = 0; | ||||
P = 0; | P = 0; | ||||
J = 0; | J = 0; | ||||
t = 0; | |||||
} | } | ||||
private: | private: | ||||
@@ -116,6 +120,7 @@ private: | |||||
case 'v' : v_opt = true; break; | case 'v' : v_opt = true; break; | ||||
case 'L' : L_opt = true; break; | case 'L' : L_opt = true; break; | ||||
case 'S' : S_opt = true; break; | case 'S' : S_opt = true; break; | ||||
case 'w' : w_opt = true; break; | |||||
case 'j' : jname = optarg; break; | case 'j' : jname = optarg; break; | ||||
case 'd' : device = optarg; break; | case 'd' : device = optarg; break; | ||||
case 'r' : fsamp = atoi (optarg); break; | case 'r' : fsamp = atoi (optarg); break; | ||||
@@ -226,15 +231,48 @@ private: | |||||
Alsa_pcmi *A; | Alsa_pcmi *A; | ||||
Alsathread *P; | Alsathread *P; | ||||
Jackclient *J; | Jackclient *J; | ||||
pthread_t t; | |||||
int topts; | |||||
static void* _retry_alsa_pcmi (void *arg) | |||||
{ | |||||
((zita_j2a*)arg)->retry_alsa_pcmi (); | |||||
return NULL; | |||||
} | |||||
void retry_alsa_pcmi () | |||||
{ | |||||
Alsa_pcmi *a; | |||||
while (! stop) | |||||
{ | |||||
sleep(1); | |||||
a = new Alsa_pcmi (device, 0, 0, fsamp, bsize, nfrag, topts); | |||||
if (a->state ()) | |||||
{ | |||||
delete a; | |||||
continue; | |||||
} | |||||
A = a; | |||||
if (v_opt) A->printinfo (); | |||||
P = new Alsathread (A, Alsathread::PLAY); | |||||
usleep (100*1000); | |||||
jack_initialize_part2 (); | |||||
jack_info (APPNAME ": Device is now available and has been activated"); | |||||
break; | |||||
} | |||||
t = 0; | |||||
} | |||||
public: | public: | ||||
int jack_initialize (jack_client_t* client, const char* load_init) | 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 opts; | |||||
if (parse_options (load_init)) { | if (parse_options (load_init)) { | ||||
delete this; | delete this; | ||||
@@ -259,22 +297,56 @@ public: | |||||
opts = 0; | opts = 0; | ||||
if (v_opt) opts |= Alsa_pcmi::DEBUG_ALL; | if (v_opt) opts |= Alsa_pcmi::DEBUG_ALL; | ||||
if (L_opt) opts |= Alsa_pcmi::FORCE_16B | Alsa_pcmi::FORCE_2CH; | 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 ()) | |||||
if (w_opt) | |||||
{ | { | ||||
jack_error (APPNAME ": Can't open ALSA playback device '%s'.", device); | |||||
delete this; | |||||
return 1; | |||||
J = new Jackclient (client, 0, Jackclient::PLAY, nchan, S_opt, this); | |||||
// if device is not available, spawn thread to keep trying | |||||
A = new Alsa_pcmi (device, 0, 0, fsamp, bsize, nfrag, opts); | |||||
if (A->state ()) | |||||
{ | |||||
delete A; | |||||
A = NULL; | |||||
topts = opts; | |||||
pthread_create (&t, NULL, _retry_alsa_pcmi, this); | |||||
jack_info (APPNAME ": Could not open device, will keep trying in new thread..."); | |||||
return 0; | |||||
} | |||||
// otherwise continue as normal | |||||
if (v_opt) A->printinfo (); | |||||
P = new Alsathread (A, Alsathread::PLAY); | |||||
} | } | ||||
if (v_opt) A->printinfo (); | |||||
if (nchan > A->nplay ()) | |||||
else | |||||
{ | { | ||||
nchan = A->nplay (); | |||||
jack_error (APPNAME ": Warning: only %d channels are available.", nchan); | |||||
A = new Alsa_pcmi (device, 0, 0, fsamp, bsize, nfrag, opts); | |||||
if (A->state ()) | |||||
{ | |||||
jack_error (APPNAME ": Can't open ALSA playback device '%s'.", device); | |||||
delete this; | |||||
return 1; | |||||
} | |||||
if (v_opt) A->printinfo (); | |||||
if (nchan > A->nplay ()) | |||||
{ | |||||
nchan = A->nplay (); | |||||
jack_error (APPNAME ": Warning: only %d channels are available.", nchan); | |||||
} | |||||
P = new Alsathread (A, Alsathread::PLAY); | |||||
J = new Jackclient (client, 0, Jackclient::PLAY, nchan, S_opt, this); | |||||
} | } | ||||
P = new Alsathread (A, Alsathread::PLAY); | |||||
J = new Jackclient (client, 0, Jackclient::PLAY, nchan, S_opt, this); | |||||
usleep (100000); | |||||
usleep (100*1000); | |||||
jack_initialize_part2 (); | |||||
return 0; | |||||
} | |||||
void jack_initialize_part2 () | |||||
{ | |||||
int k, k_del; | |||||
double t_jack; | |||||
double t_alsa; | |||||
double t_del; | |||||
t_alsa = (double) bsize / fsamp; | t_alsa = (double) bsize / fsamp; | ||||
if (t_alsa < 1e-3) t_alsa = 1e-3; | if (t_alsa < 1e-3) t_alsa = 1e-3; | ||||
@@ -295,14 +367,19 @@ public: | |||||
P->start (audioq, commq, alsaq, J->rprio () + 10); | P->start (audioq, commq, alsaq, J->rprio () + 10); | ||||
J->start (audioq, commq, alsaq, infoq, (double) fsamp / J->fsamp (), k_del, ltcor, rqual); | J->start (audioq, commq, alsaq, infoq, (double) fsamp / J->fsamp (), k_del, ltcor, rqual); | ||||
return 0; | |||||
} | } | ||||
void jack_finish (void* arg) | void jack_finish (void* arg) | ||||
{ | { | ||||
if (t != 0) | |||||
{ | |||||
stop = true; | |||||
pthread_join(t, NULL); | |||||
t = 0; | |||||
} | |||||
commq->wr_int32 (Alsathread::TERM); | commq->wr_int32 (Alsathread::TERM); | ||||
usleep (100000); | |||||
usleep (100*1000); | |||||
delete P; | delete P; | ||||
delete A; | delete A; | ||||
delete J; | delete J; | ||||