#include #include #include #include #include #include #include #include #include #define AUDIOBUFSIZE 4096 #define FRAMESPERBUFFER 1024 #define TIMEOUT 1000L /* select time out for audio device */ /* XXX probably safer to use a local buffer due to the wsjt threaded nature. */ static char rcv_buf[AUDIOBUFSIZE]; static char tx_buf[AUDIOBUFSIZE]; #define MAXDSPNAME 16 extern void decode1_(int *iarg); void oss_loop(int *iarg); /* * local state data referencing some gcom common fortran variables as well */ static 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; /* * 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, char *PttPort, char *devin_name, char *devout_name) { pthread_t thread1,thread2; int iret1,iret2; int iarg1 = 1,iarg2 = 2; int32_t rate=*nfsample; int samplesize; int format; int channels; double dnfs; int i; char *p; /* Remove space if present */ p = strchr(devin_name, ' '); if(p != NULL) *p = '\0'; p = strchr(devout_name, ' '); if(p != NULL) *p = '\0'; data.fd_in = open(devin_name, O_RDONLY, 0); if(data.fd_in < 0) { fprintf(stderr, "Cannot open %s for input.\n", devin_name); return (-1); } if (*devout_name == '\0') { close(data.fd_in); data.fd_in = open(devin_name, O_RDWR, 0); if(data.fd_in < 0) { fprintf(stderr, "Cannot open %s for input.\n", devin_name); return (-1); } data.fd_out = data.fd_in; if(ioctl(data.fd_in, SNDCTL_DSP_SETDUPLEX, 0) < 0) { fprintf(stderr, "Cannot use %s for full duplex.\n", devin_name); return(-1); } } else { data.fd_out = open(devout_name, O_WRONLY, 0); if(data.fd_out < 0) { fprintf(stderr, "Cannot open %s for output.\n", devout_name); return (-1); } } 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; channels = 2; if(ioctl (data.fd_in, SNDCTL_DSP_CHANNELS, &channels) == -1) { fprintf (stderr, "Unable to set 2 channels for input.\n"); return (-1); } if(channels != 2) { fprintf (stderr, "Unable to set 2 channels.\n"); return (-1); } format = AFMT_S16_NE; if(ioctl (data.fd_in, SNDCTL_DSP_SETFMT, &format) == -1) { fprintf (stderr, "Unable to set format for input.\n"); return (-1); } if(ioctl (data.fd_in, SNDCTL_DSP_SPEED, &rate) == -1) { fprintf (stderr, "Unable to set rate for input\n"); return (-1); } printf("Audio OSS streams running normally.\n"); printf("******************************************************************\n"); printf("Opened %s for input.\n", devin_name); if (*devout_name != '\0') printf("Opened %s for output.\n", devout_name); else printf("Opened %s for output.\n", devin_name); printf("Rate set = %d\n", rate); // printf("start_threads: creating thread for oss_loop\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); } /* * oss_loop * * inputs - int pointer NOT USED * output - none * side effects - */ void oss_loop(int *iarg) { fd_set readfds, writefds; int nfds = 0; struct timeval timeout = {0, 0}; struct timeval tv; int nread; 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; for (;;) { FD_ZERO(&readfds ); FD_ZERO(&writefds ); FD_SET(data.fd_in, &readfds); FD_SET(data.fd_out, &writefds); timeout.tv_usec = TIMEOUT; if(select(FD_SETSIZE, &readfds, &writefds, NULL, &timeout) > 0) { if(FD_ISSET(data.fd_in, &readfds)) { nread = read (data.fd_in, rcv_buf, AUDIOBUFSIZE); if(nread <= 0) { fprintf(stderr, "Read error %d\n", nread); return; } if(nread == AUDIOBUFSIZE) { /* 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 */ } } if(FD_ISSET(data.fd_in, &writefds)) { /* 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)) { nsec = (int)stime; 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 */ } } } }