/*
 *  PCM-Capture nach TCP / 16bit signed auf Ice1712 Pro mit ALSA/Linux/x86
 *  Aufruf [Programm] [Portnummer]
 *
 *  (Compilieren fuer Mono oder Stereo und auf eine feste Samplingrate zw.
 *   8000 und 48000Hz, hat bisher keine eigene Erkennung fuer WAV-Header!)
 *  Benoetigte Libraries: asound pthread
 *
 *  Frei kopierbarer  haesslicher  "proof of concept"  Code  ohne jegliche
 *  Garantien, nicht mal die, die oben versprochene Funktion zu erfuellen.
 *
 *  Beteiligt: Eric Auer, Attilio Erriquez, Dan Hollis, Christian Dressler
 *
 *  Achtung: Der ALSA Treiber fuer diese Karte erlaubt nur,  ALLE  Kanaele
 *  gleichzeitig zu oeffnen, daher funktioniert dafuer auch keine OSS-Emu.
 *  Fuer Ausgabe sind das exakt 10, fuer Eingabe exakt 12 Monokanaele.
 *
 *  30.05.2000 - 01.06.2000
 */

#include "rec-sock-alsa.h" 

/* ***************************************************************** */

void help(void) 
{ 
  printf("Usage: Give me a port and I will write,\n"
         "signed %dbit "
         "mono"
         " PCM %dHz data to it.\n",
         snd_inBITS,snd_HZ); 
  _exit(1); return; 
};

/* ***************************************************************** */

signed int mybuf[RBUF*nCHN]; // nCHN wg nCHN voices
int want_data; // for locking

/* ***************************************************************** */

int send_buffer(int sockfd, int channel)
// verbindet beide Welten!
// Aktion: fetch channel from buffer (locking), send it, recv ack (ign. ack)
{
  int cnt,cnt2,left;
  fmtSOCK mywrbuf[RBUF+1];
  char combuf[200];

  LOCK;
  want_data++;
  UNLOCK;
  
  while (in_buffer<=0) { /* usleep(1); */ };

  LOCK;
  if ((left=in_buffer)<=0) return 1; // Pech gehabt?
  left /= sizeof(mybuf[0]) * nCHN;
  if (left>=RBUF) return 2; // dont overflow yourself

  for (cnt=0,cnt2=channel; cnt<left; cnt++)
      { 
        mywrbuf[cnt] = mybuf[cnt2] >> snd_SHL; 
        cnt2+=nCHN;
      };
  if (want_data>0) want_data--;
  UNLOCK;

  fprintf(stderr,"send_buffer: %d Samples\n",left);
  if (left<=0) return 3; // should never happen
  
  if (send(sockfd,mywrbuf,left * sizeof(mywrbuf[0]),0) == -1)
     { perror("send"); return 4; };

  if (recv(sockfd,combuf,sizeof(combuf),0) == -1)
     { perror("recv"); return 5; };
  /* Ack. from client is ignored here, there only has to be some message */
              
  return 0;
};

/* ***************************************************************** */

int read_sound(snd_pcm_t * handle)
{
int left, cnt;

if ((cnt = snd_pcm_capture_go(handle))) 
   { fprintf(stderr,"Error with snd_pcm_capture_go: %s\n",
             snd_strerror(cnt)); return 1; 
   };
want_data=0;
usleep(1000);

while (run_server>0)
  { 
    LOCK;
    in_buffer = 0;
    left = in_buffer = snd_pcm_read(handle,mybuf, sizeof(mybuf));
    UNLOCK;
    left = (left>0) ? left / (nCHN * sizeof(mybuf[0])) : left;
    if (left<=0)
       { fprintf(stderr,"Error with snd_pcm_read: %s\n", snd_strerror(left));
         left = snd_pcm_capture_go(handle);
         fprintf(stderr,"Tried to restart capture: %s\n", snd_strerror(left));
         left = 0;
         fprintf(stderr,"Trying to continue\n");
       };
    if ((left<0) && (left!= -EAGAIN)) 
       { fprintf(stderr,"Error with snd_pcm_read: %s\n", snd_strerror(left));
         LOCK;
         run_server = -1;
         in_buffer = 0;
         UNLOCK;
         return 1;
       };
    if (left>0)
    { // wait a bit if someone wants to copy the buffer
      // but only if there is something in it.
      usleep(1000);
      while (want_data) usleep(1000);
    };
#ifdef DEBUG
    if (left>0) { fprintf(stderr,"%d samples fetched\n",left); };
#endif
  };

LOCK;
run_server = -1;
in_buffer = 0;
UNLOCK;
return 0;
};

/* ***************************************************************** */

int main(int argc, char ** argv)
{
snd_pcm_t * soundhandle=NULL;
int sockfd;
long int port;

run_server = 1;
in_buffer = 0;

if ((argc!=2) || (!argv)) help(); if (!argv[1]) help();

port = strtol(argv[1],NULL,10);
if ((port < 1024) || (port > 65519)) help();

fprintf(stderr,"Opening sound for capture\n");
if (open_sound(&soundhandle)) return 1;

fprintf(stderr,"Starting to listen to port %d\n",(int)port);
if ((sockfd = open_socket((int)port)) < 0) return 1;

if (read_sound(soundhandle))
   { fprintf(stderr, "Error reading from PCM\n"); };
   // kehrt nur bei Fehler zurueck oder bei "CLOSE" Kommando

fprintf(stderr,"Closing server sockets\n");
if (close_socket(sockfd)) return 1;

fprintf(stderr,"Closing sound\n");
if (close_sound(soundhandle)) return 1;

return 0;
};
