/***** jack.udp.c - (c) rohan drape, 2003-2005 *****/

#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <string.h>
#include <pthread.h>

#include "common/byte-order.h"
#include "common/failure.h"
#include "common/file.h"
#include "common/jack-client.h"
#include "common/jack-port.h"
#include "common/jack-ringbuffer.h"
#include "common/memory.h"
#include "common/network.h"

#define MAX_CHANNELS 32

typedef struct 
{
  int buffer_size;
  f32 *j_buffer;
  int fd;
  struct sockaddr_in address;
  int channels;
  jack_port_t *j_port[MAX_CHANNELS];
  jack_ringbuffer_t *rb;
  pthread_t c_thread;
  int pipe[2];
  char *name;
} jackudp_t;

static void jackudp_init(jackudp_t *d)
{
  d->buffer_size = 4096;
  d->channels = 2;
  d->name = NULL;
}

#include "shared/packet.c"
#include "shared/send.c"
#include "shared/recv.c"

void jackudp_usage (void)
{
  eprintf("Usage: jack.udp [ options ] mode\n");
  eprintf("   -b  Set the ring buffer size in frames (default=4096).\n");
  eprintf("   -c  Set the client name (default=\"jack.udp-PID\").\n");
  eprintf("   -p  Set the port number (default=57160).\n");
  eprintf("   -n  Set the number of channels (default=2).\n");
  eprintf("   -r  Set the remote addrress to send to (default=\"127.0.0.1\").\n");
  FAILURE;
}

int main (int argc, char **argv)
{
  jackudp_t d;
  int c;
  int port_n = 57160;
  char *hostname =  NULL;
  jackudp_init(&d);
  while((c = getopt(argc, argv, "b:hn:p:r:c:")) != -1) {
    switch(c) {
    case 'b':
      d.buffer_size = atoi(optarg);
      break;
    case 'c':
      d.name = optarg;
      break;
    case 'h':
      jackudp_usage ();
      break;
    case 'n':
      d.channels = atoi (optarg);
      break;
    case 'p':
      port_n = atoi (optarg);
      break;
    case 'r':
      hostname = optarg;
      break;
    default:
      eprintf ("jack.udp: Illegal option %c.\n", c);
      jackudp_usage ();
      break;
    }
  }
  if (optind != argc - 1) {
    jackudp_usage ();
  }
  if(d.channels < 1 || d.channels > MAX_CHANNELS) {
    eprintf("jack.udp: illegal number of channels: %d\n", d.channels);
    FAILURE;
  }
  int recv_mode = (strcmp(argv[optind], "recv") == 0);
  d.fd = socket_udp(0);
  if(recv_mode) {
    bind_inet(d.fd, NULL, port_n);
  } else {
    init_sockaddr_in(&(d.address), 
		     hostname ? hostname : "127.0.0.1", 
		     port_n);
  }  
  d.buffer_size *= d.channels * sizeof(f32);
  d.j_buffer = xmalloc(d.buffer_size);
  d.rb = jack_ringbuffer_create(d.buffer_size);
  xpipe(d.pipe);
  jack_client_t *client = NULL;
  if(d.name) {
    client = jack_client_new(d.name );
  } else {
    client = jack_client_unique("jack.udp");
  }
  jack_set_error_function(jack_client_minimal_error_handler);
  jack_on_shutdown(client, jack_client_minimal_shutdown_handler, 0);
  jack_set_process_callback(client, 
			    recv_mode ? jackudp_recv : jackudp_send, 
			    &d);
  jack_port_make_standard(client, d.j_port, d.channels, recv_mode);
  jack_client_activate(client);
  pthread_create(&(d.c_thread), 
		 NULL, 
		 recv_mode ? jackudp_recv_thread : jackudp_send_thread, 
		 &d);
  pthread_join(d.c_thread, NULL);
  close(d.fd);
  jack_ringbuffer_free(d.rb);
  jack_client_close(client);
  close(d.pipe[0]);
  close(d.pipe[1]);
  free(d.j_buffer);
  return EXIT_SUCCESS;
}
