Signed-off-by: falkTX <falktx@falktx.com>tags/v1.9.19
@@ -28,7 +28,7 @@ | |||
#include "lfqueue.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) | |||
{ | |||
@@ -47,6 +47,7 @@ static void help (void) | |||
jack_info (" -Q <quality> Resampling quality, 16..96 [auto]"); | |||
jack_info (" -I <samples> Latency adjustment [0]"); | |||
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]"); | |||
} | |||
@@ -60,6 +61,7 @@ class zita_a2j | |||
bool v_opt; | |||
bool L_opt; | |||
bool S_opt; | |||
bool w_opt; | |||
char *jname; | |||
char *device; | |||
int fsamp; | |||
@@ -81,6 +83,7 @@ public: | |||
v_opt = false; | |||
L_opt = false; | |||
S_opt = false; | |||
w_opt = false; | |||
jname = strdup(APPNAME); | |||
device = 0; | |||
fsamp = 48000; | |||
@@ -92,6 +95,7 @@ public: | |||
A = 0; | |||
C = 0; | |||
J = 0; | |||
t = 0; | |||
} | |||
private: | |||
@@ -116,6 +120,7 @@ private: | |||
case 'v' : v_opt = true; break; | |||
case 'L' : L_opt = true; break; | |||
case 'S' : S_opt = true; break; | |||
case 'w' : w_opt = true; break; | |||
case 'j' : jname = optarg; break; | |||
case 'd' : device = optarg; break; | |||
case 'r' : fsamp = atoi (optarg); break; | |||
@@ -227,15 +232,48 @@ private: | |||
Alsathread *C; | |||
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: | |||
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)) { | |||
jack_error (APPNAME ": parse options failed"); | |||
@@ -261,22 +299,56 @@ public: | |||
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 ()) | |||
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; | |||
if (t_alsa < 1e-3) t_alsa = 1e-3; | |||
@@ -297,12 +369,16 @@ public: | |||
C->start (audioq, commq, alsaq, J->rprio () + 10); | |||
J->start (audioq, commq, alsaq, infoq, J->fsamp () / (double) fsamp, k_del, ltcor, rqual); | |||
return 0; | |||
} | |||
void jack_finish (void* arg) | |||
{ | |||
if (t != 0) | |||
{ | |||
stop = true; | |||
pthread_join(t, NULL); | |||
} | |||
commq->wr_int32 (Alsathread::TERM); | |||
usleep (100000); | |||
delete C; | |||
@@ -28,7 +28,7 @@ | |||
#include "lfqueue.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) | |||
{ | |||
@@ -47,6 +47,7 @@ static void help (void) | |||
jack_info (" -Q <quality> Resampling quality, 16..96 [auto]"); | |||
jack_info (" -O <samples> Latency adjustment [0]"); | |||
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]"); | |||
} | |||
@@ -60,6 +61,7 @@ class zita_j2a | |||
bool v_opt; | |||
bool L_opt; | |||
bool S_opt; | |||
bool w_opt; | |||
char *jname; | |||
char *device; | |||
int fsamp; | |||
@@ -81,6 +83,7 @@ public: | |||
v_opt = false; | |||
L_opt = false; | |||
S_opt = false; | |||
w_opt = false; | |||
jname = strdup(APPNAME); | |||
device = 0; | |||
fsamp = 48000; | |||
@@ -92,6 +95,7 @@ public: | |||
A = 0; | |||
P = 0; | |||
J = 0; | |||
t = 0; | |||
} | |||
private: | |||
@@ -116,6 +120,7 @@ private: | |||
case 'v' : v_opt = true; break; | |||
case 'L' : L_opt = true; break; | |||
case 'S' : S_opt = true; break; | |||
case 'w' : w_opt = true; break; | |||
case 'j' : jname = optarg; break; | |||
case 'd' : device = optarg; break; | |||
case 'r' : fsamp = atoi (optarg); break; | |||
@@ -226,15 +231,48 @@ private: | |||
Alsa_pcmi *A; | |||
Alsathread *P; | |||
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: | |||
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)) { | |||
delete this; | |||
@@ -259,22 +297,56 @@ public: | |||
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 ()) | |||
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; | |||
if (t_alsa < 1e-3) t_alsa = 1e-3; | |||
@@ -295,14 +367,19 @@ public: | |||
P->start (audioq, commq, alsaq, J->rprio () + 10); | |||
J->start (audioq, commq, alsaq, infoq, (double) fsamp / J->fsamp (), k_del, ltcor, rqual); | |||
return 0; | |||
} | |||
void jack_finish (void* arg) | |||
{ | |||
if (t != 0) | |||
{ | |||
stop = true; | |||
pthread_join(t, NULL); | |||
t = 0; | |||
} | |||
commq->wr_int32 (Alsathread::TERM); | |||
usleep (100000); | |||
usleep (100*1000); | |||
delete P; | |||
delete A; | |||
delete J; | |||