#include <stdio.h>
#include "../common/jack-ringbuffer.h"
#include "../common/print.h"

/* Read data from udp port and write to ring buffer. */

void *jackudp_recv_thread(void *PTR)
{
  jackudp_t *d = (jackudp_t *) PTR;
  packet_t p;
  int last_packet = -1;
  while(1) {
    packet_recv(d->fd, &p, 0);
    if(p.index != last_packet + 1 && last_packet != -1) {
      eprintf("jack.udp recv: out of order packet arrival (%d, %d)\n", 
	      last_packet, (int)p.index);
      FAILURE;
    }
    if(p.channels != d->channels) {
      eprintf("jack.udp recv: channel mismatch packet arrival (%d != %d)\n", 
	      p.channels, d->channels);
      FAILURE;
    }
    int bytes_available = (int) jack_ringbuffer_write_space(d->rb);
    if(PAYLOAD_BYTES > bytes_available) {
      eprintf("jack.udp recv: buffer overflow (%d > %d)\n", 
	      (int) PAYLOAD_BYTES, bytes_available);
    } else {
      jack_ringbuffer_write_exactly(d->rb,
				    (char *) p.data, 
				    (size_t) PAYLOAD_BYTES);
    }
  }  
  return NULL;
}

/* Write data from ring buffer to JACK output ports. */

int jackudp_recv (jack_nframes_t nframes, void *PTR)
{
  jackudp_t *d = (jackudp_t *) PTR;
  if(nframes >= d->buffer_size) {
    eprintf("jack.udp recv: JACK buffer size exceeds limit\n");
    return -1;
  }

  int i, j;
  float *out[MAX_CHANNELS];
  for(i = 0; i < d->channels; i++) {
    out[i] = (float *) jack_port_get_buffer(d->j_port[i], nframes);
  }

  int nsamples = nframes * d->channels;
  int nbytes = nsamples * sizeof(f32);
  int bytes_available = (int) jack_ringbuffer_read_space(d->rb);
  if(nbytes > bytes_available) {
    eprintf("jack.udp recv: buffer underflow (%d > %d)\n", 
	    nbytes, bytes_available);
    for(i = 0; i < nframes; i++) {
      for(j = 0; j < d->channels; j++) {
	out[j][i] = (float) 0.0;
      }
    }
  } else {
    jack_ringbuffer_read_exactly(d->rb, (char *)d->j_buffer, nbytes);
    for(i = 0; i < nframes; i++) {
      for(j = 0; j < d->channels; j++) {
	out[j][i] = (float) d->j_buffer[(i * d->channels) + j];
      }
    }
  }
  return 0;
}
