From 464498eb53129ec43f8b78325eada59c4d7c8f33 Mon Sep 17 00:00:00 2001 From: Diane Bruce Date: Mon, 17 Apr 2006 20:43:21 +0000 Subject: [PATCH] - More refinements on configure for jack - first (non working) cut at jack support (start_jack.c) git-svn-id: svn+ssh://svn.code.sf.net/p/wsjt/wsjt/trunk@175 ab8295b8-cf94-4d9e-aec4-7959e3be5d79 --- configure | 13 +- configure.ac | 9 +- start_jack.c | 397 +++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 411 insertions(+), 8 deletions(-) create mode 100644 start_jack.c diff --git a/configure b/configure index ad579685c..41ece91b1 100755 --- a/configure +++ b/configure @@ -2,7 +2,7 @@ # Guess values for system-dependent variables and create Makefiles. # Generated by GNU Autoconf 2.53 for wsjt 5.9.2. # -# $Id: configure.ac 161 2006-04-13 04:50:00Z va3db $ +# $Id: configure.ac 173 2006-04-17 06:26:09Z va3db $ # # Copyright 1992, 1993, 1994, 1995, 1996, 1998, 1999, 2000, 2001, 2002 # Free Software Foundation, Inc. @@ -929,7 +929,7 @@ Free Software Foundation, Inc. This configure script is free software; the Free Software Foundation gives unlimited permission to copy, distribute and modify it. -$Id: configure.ac 161 2006-04-13 04:50:00Z va3db $ +$Id: configure.ac 173 2006-04-17 06:26:09Z va3db $ _ACEOF exit 0 fi @@ -6076,11 +6076,14 @@ _ACEOF fi -if test "$alsa" != yes -a "$oss" != yes -a "$portaudio" != yes; then +if test "$alsa" != yes -a "$oss" != yes -a \ + "$portaudio" != yes -a "$jack" != yes; then if test $HAS_PORTAUDIO_H -eq 1; then portaudio=yes; elif test $HAS_ASOUNDLIB_H -eq 1; then alsa=yes; + elif test $HAS_SOUNDCARD_H -eq 1; then + oss=yes; fi fi @@ -6122,9 +6125,9 @@ cat >>confdefs.h <<\_ACEOF #define USE_JACK 1 _ACEOF - AUDIO="a2d.f90 jtaudio.c start_jack.c" + AUDIO="start_jack.c" - LDFLAGS="${LDFLAGS} -ljack -lsamplerate" + LDFLAGS="${LDFLAGS} -ljack" fi diff --git a/configure.ac b/configure.ac index b024d1822..5d8653968 100644 --- a/configure.ac +++ b/configure.ac @@ -306,11 +306,14 @@ if test "$parallel" = yes; then AC_DEFINE(USE_PARALLEL, 1, [Define if you want Serial port used.]) fi -if test "$alsa" != yes -a "$oss" != yes -a "$portaudio" != yes; then +if test "$alsa" != yes -a "$oss" != yes -a \ + "$portaudio" != yes -a "$jack" != yes; then if test $HAS_PORTAUDIO_H -eq 1; then [portaudio=yes]; elif test $HAS_ASOUNDLIB_H -eq 1; then [alsa=yes]; + elif test $HAS_SOUNDCARD_H -eq 1; then + [oss=yes]; fi fi @@ -333,8 +336,8 @@ fi if test "$jack" = yes; then AC_DEFINE(USE_JACK, 1, [Define if you want JACK used.]) - AC_SUBST(AUDIO, "a2d.f90 jtaudio.c start_jack.c") - LDFLAGS="${LDFLAGS} -ljack -lsamplerate" + AC_SUBST(AUDIO, "start_jack.c") + LDFLAGS="${LDFLAGS} -ljack" fi dnl set conf flags diff --git a/start_jack.c b/start_jack.c new file mode 100644 index 000000000..763707384 --- /dev/null +++ b/start_jack.c @@ -0,0 +1,397 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define AUDIOBUFSIZE 4096 +#define FRAMESPERBUFFER 1024 + +char rcv_buf[AUDIOBUFSIZE]; /* XXX grab one from upper app later --db */ +char tx_buf[AUDIOBUFSIZE]; /* XXX grab one from upper app later --db */ + +/* + * Lots of pieces stolen directly from jack simple_client.c + */ +jack_port_t *input_port; +jack_port_t *output_port; +jack_client_t *client; +void jack_read(void); +void jack_write(void); + +/* a simple state machine for this client */ +volatile enum { + Init, + Run, + Exit +} client_state = Init; + +extern void decode1_(int *iarg); + +/* + * local state data referencing some gcom common fortran variables as well + */ +struct audio_data { + int fd_in; /* Audio fd in; used only locally in this function */ + int fd_out; /* Audio fd out; used only locally in this function */ + double *Tsec; /* Present time SoundIn,SoundOut */ + double *tbuf; /* Tsec at time of input callback SoundIn */ + int *iwrite; /* Write pointer to Rx ring buffer SoundIn */ + int *ibuf; /* Most recent input buffer# SoundIn */ + int *TxOK; /* OK to transmit? SoundIn */ + int *ndebug; /* Write debugging info? GUI */ + int *ndsec; /* Dsec in units of 0.1 s GUI */ + int *Transmitting; /* Actually transmitting? SoundOut */ + int *nwave; /* Number of samples in iwave SoundIn */ + int *nmode; /* Which WSJT mode? GUI */ + int *trperiod; /* Tx or Rx period in seconds GUI */ + int nbuflen; + int nfs; + int16_t *y1; /* Ring buffer for audio channel 0 SoundIn */ + int16_t *y2; /* Ring buffer for audio channel 1 SoundIn */ + short *iwave; +}data; + +/** + * The process callback for this JACK application is called in a + * special realtime thread once for each audio cycle. + * + * This client follows a simple rule: when the JACK transport is + * running, copy the input port to the output. When it stops, exit. + */ +int +process (jack_nframes_t nframes, void *arg) +{ + jack_default_audio_sample_t *in, *out; + jack_transport_state_t ts = jack_transport_query(client, NULL); + int i; + + if (ts == JackTransportRolling) { + + if (client_state == Init) + client_state = Run; + printf("ZZZ nframes = %d\n", nframes); + in = jack_port_get_buffer (input_port, nframes); + /* First hack */ + memcpy (rcv_buf, in, AUDIOBUFSIZE); + jack_read(); + +#if 0 + out = jack_port_get_buffer (output_port, nframes); + memcpy (out, in, + sizeof (jack_default_audio_sample_t) * nframes); +#endif + + } else if (ts == JackTransportStopped) { + + if (client_state == Run) + client_state = Exit; + } + + return 0; +} + +/** + * JACK calls this shutdown_callback if the server ever shuts down or + * decides to disconnect the client. + */ +void +jack_shutdown (void *arg) +{ + return; +} + +/* + * start_threads() + * inputs - ndevin device number for input + * - ndevout device number for output + * - y1 short int array for channel 0 + * - y2 short int array for channel 1 + * - nmax + * - iwrite + * - iwave + * - nwave + * - rate + * - NSPB + * - TRPeriod + * - TxOK + * - ndebug debug output or not? + * - Transmitting + * - Tsec + * - ngo + * - nmode + * - tbuf + * - ibuf + * - ndsec + * output - ? + * side effects - Called from audio_init.f90 to start audio decode and + * OSS thread. + */ + +int +start_threads_(int *ndevin, int *ndevout, short y1[], short y2[], + int *nbuflen, int *iwrite, short iwave[], + int *nwave, int *nfsample, int *nsamperbuf, + int *TRPeriod, int *TxOK, int *ndebug, + int *Transmitting, double *Tsec, int *ngo, int *nmode, + double tbuf[], int *ibuf, int *ndsec) +{ + pthread_t thread1,thread2; + int iret1,iret2; + int iarg1 = 1,iarg2 = 2; + int32_t rate=*nfsample; + double dnfs; + const char **ports; + const char *client_name; + jack_options_t options = JackNullOption; + jack_status_t status; + + data.Tsec = Tsec; + data.tbuf = tbuf; + data.iwrite = iwrite; + data.ibuf = ibuf; + data.TxOK = TxOK; + data.ndebug = ndebug; + data.ndsec = ndsec; + data.Transmitting = Transmitting; + data.y1 = y1; + data.y2 = y2; + data.nbuflen = *nbuflen; + data.nmode = nmode; + data.nwave = nwave; + data.iwave = iwave; + data.nfs = *nfsample; + data.trperiod = TRPeriod; + + dnfs=(double)*nfsample; + + /* open a client connection to the JACK server */ + + client = jack_client_open ("wsjt", options, &status, NULL); + if (client == NULL) { + fprintf (stderr, "jack_client_open() failed, " + "status = 0x%2.0x\n", status); + if (status & JackServerFailed) { + fprintf (stderr, "Unable to connect to JACK server\n"); + } + return(-1); + } + if (status & JackServerStarted) { + fprintf (stderr, "JACK server started\n"); + } + if (status & JackNameNotUnique) { + client_name = jack_get_client_name(client); + fprintf (stderr, "unique name `%s' assigned\n", client_name); + } + + /* tell the JACK server to call `process()' whenever + * there is work to be done. + */ + + jack_set_process_callback (client, process, 0); + + /* tell the JACK server to call `jack_shutdown()' if + * it ever shuts down, either entirely, or if it + * just decides to stop calling us. + */ + + jack_on_shutdown (client, jack_shutdown, 0); + + /* display the current sample rate. + */ + + printf ("engine sample rate: %" PRIu32 "\n", + jack_get_sample_rate (client)); + + /* create two ports */ + + input_port = jack_port_register (client, "input", + JACK_DEFAULT_AUDIO_TYPE, + JackPortIsInput, 0); + output_port = jack_port_register (client, "output", + JACK_DEFAULT_AUDIO_TYPE, + JackPortIsOutput, 0); + + if ((input_port == NULL) || (output_port == NULL)) { + fprintf(stderr, "no more JACK ports available\n"); + /* ZZZ close jack above */ + return(-1); + } + + /* Tell the JACK server that we are ready to roll. Our + * process() callback will start running now. + */ + + if (jack_activate (client)) { + fprintf (stderr, "cannot activate client"); + /* ZZZ close jack above */ + return(-1); + } + + /* Connect the ports. You can't do this before the client is + * activated, because we can't make connections to clients + * that aren't running. Note the confusing (but necessary) + * orientation of the driver backend ports: playback ports are + * "input" to the backend, and capture ports are "output" from + * it. + */ + + ports = jack_get_ports (client, NULL, NULL, + JackPortIsPhysical|JackPortIsOutput); + if (ports == NULL) { + fprintf(stderr, "no physical capture ports\n"); + /* ZZZ close jack above */ + return(-1); + } + + if (jack_connect (client, ports[0], jack_port_name (input_port))) { + fprintf (stderr, "cannot connect input ports\n"); + } + + free (ports); + + ports = jack_get_ports (client, NULL, NULL, + JackPortIsPhysical|JackPortIsInput); + if (ports == NULL) { + fprintf(stderr, "no physical playback ports\n"); + /* ZZZ close jack above */ + return(-1); + } + + if (jack_connect (client, jack_port_name (output_port), ports[0])) { + fprintf (stderr, "cannot connect output ports\n"); + } + + free (ports); + + + printf("Audio jack streams running normally.\n"); + printf("******************************************************************\n"); + + printf("start_threads: creating thread for decode1\n"); + // iret1 = pthread_create(&thread1, NULL, + // (void *(*)(void *))oss_loop, &iarg1); + // printf("start_threads: creating thread for decode1_\n"); + iret2 = pthread_create(&thread2, NULL, + (void *(*)(void *))decode1_,&iarg2); +/* keep running until the transport stops */ + + while (client_state != Exit) { + sleep (1); + } + + jack_client_close (client); + + return(0); +} + +/* + * oss_loop + * + * inputs - int pointer NOT USED + * output - none + * side effects - + */ + +void +jack_read(void) +{ + struct timeval tv; + unsigned int i; + static int n=0; + static int n2=0; + static int ia=0; + static int ib=0; + static int ic=0; + static int16_t *in; + static int16_t *wptr; + static int TxOKz=0; + static int ncall=0; + static int nsec=0; + static double stime; + + /* Get System time */ + gettimeofday(&tv, NULL); + stime = (double) tv.tv_sec + ((double)tv.tv_usec / 1000000.0) + + *(data.ndsec) * 0.1; + *(data.Tsec) = stime; + + ncall++; + + /* increment buffer pointers only if data available */ + ia=*(data.iwrite); + ib=*(data.ibuf); + data.tbuf[ib-1] = stime; /* convert to c index to store */ + ib++; + if(ib>FRAMESPERBUFFER) + ib=1; + *(data.ibuf) = ib; + in = (int16_t *)rcv_buf; /* XXX */ + for(i=0; i= data.nbuflen) + ia=0; //Wrap buffer pointer if necessary + *(data.iwrite) = ia; /* Save buffer pointer */ + fivehz_(); /* Call fortran routine */ +} + +void +jack_write(void) +{ + int i; + static int n=0; + static int ic=0; + struct timeval tv; + static int n2=0; + static int16_t *wptr; + static int TxOKz=0; + static int nsec=0; + static double stime; + + /* Get System time */ + gettimeofday(&tv, NULL); + stime = (double) tv.tv_sec + ((double)tv.tv_usec / 1000000.0) + + *(data.ndsec) * 0.1; + *(data.Tsec) = stime; + + if(*(data.TxOK) && (!TxOKz)) { + n=nsec/(*(data.trperiod)); + ic = (int)(stime - *(data.trperiod)*n) * data.nfs; + ic = ic % *(data.nwave); + } + + TxOKz = *(data.TxOK); + *(data.Transmitting) = *(data.TxOK); + wptr = (int16_t *)tx_buf; /* XXX */ + if(*(data.TxOK)) { + for(i=0 ; i= *(data.nwave)) { + ic = ic % *(data.nwave); /* Wrap buffer pointer if necessary */ + if(*(data.nmode) == 2) + *(data.TxOK) = 0; + } + } + } else { + memset(tx_buf, 0, AUDIOBUFSIZE); + } + + if (write(data.fd_out, tx_buf, AUDIOBUFSIZE) < 0) { + fprintf(stderr, "Can't write to soundcard.\n"); + return; + } + fivehztx_(); /* Call fortran routine */ +}