示例#1
0
文件: jack.c 项目: doctaweeks/rotter
/* Callback called by JACK when audio is available
   Use as little CPU time as possible, just copy accross the audio
   into the ring buffer
*/
static
int callback_jack(jack_nframes_t nframes, void *arg)
{
  jack_nframes_t frames_until_whole_second = 0;
  jack_nframes_t read_pos = 0;
  time_t this_period;
  struct timeval tv;

  // Get the current time
  if (gettimeofday(&tv, NULL)) {
    rotter_fatal("Failed to gettimeofday(): %s", strerror(errno));
    return 1;
  }

  // FIXME: this won't work if rotter is started *just* before the archive period
  if (active_ringbuffer) {
    unsigned int duration;
    int result;

    // Calculate the number of frames until we have a whole number of seconds
    // FIXME: what if the callback buffer contains over 1 second of audio?
    frames_until_whole_second = ceil(jack_get_sample_rate( client ) *
                                ((double)(1000000 - tv.tv_usec) / 1000000));

    if (frames_until_whole_second < nframes) {
      result = write_to_ringbuffer(active_ringbuffer, read_pos, frames_until_whole_second);
      if (result)
        return result;

      // Calculate the duration of the audio that we wrote
      // and add it on to the current time
      duration = ((double)frames_until_whole_second /
                 jack_get_sample_rate( client )) * 1000000;
      tv.tv_usec += (duration - 1000000);
      tv.tv_sec += 1;

      nframes -= frames_until_whole_second;
      read_pos += frames_until_whole_second;
    }
  }


  // Time to swap ring buffers, if we are now in a new archive period
  this_period = start_of_period(tv.tv_sec);
  if (active_ringbuffer == NULL || active_ringbuffer->period_start != this_period) {
    if (active_ringbuffer) {
      active_ringbuffer->close_file = 1;
    }
    if (active_ringbuffer == ringbuffers[0]) {
      active_ringbuffer = ringbuffers[1];
    } else {
      active_ringbuffer = ringbuffers[0];
    }
    active_ringbuffer->file_start = tv;
    active_ringbuffer->period_start = this_period;
  }

  // Finally, write any frames after the 1 second boundary
  return write_to_ringbuffer(active_ringbuffer, read_pos, nframes);
}
示例#2
0
/* ************************************************************************
 *  hard_xmit
 *
 *  This function runs in linux kernel context and is executed whenever
 *  there is a frame to be sent out.
 * ************************************************************************ */
static int rtnetproxy_xmit(struct sk_buff *skb, struct net_device *dev)
{
    struct net_device_stats *stats = dev->priv;

    if (write_to_ringbuffer(&ring_skb_kernel_rtnet, skb))
    {
        stats->tx_packets++;
        stats->tx_bytes+=skb->len;
    }
    else
    {
        /* No space in the ringbuffer... */
        printk("rtnetproxy_xmit - no space in queue\n");
        dev_kfree_skb(skb);  /* Free the standard skb. */
    }

    /* Signal rtnet that there are packets waiting to be processed...
     * */
    rtdm_sem_up(&rtnetproxy_sem);

    /* Delete all "used" skbs that already have been processed... */
    {
        struct sk_buff *del_skb;
        while ((del_skb = read_from_ringbuffer(&ring_skb_rtnet_kernel)) != 0)
        {
            dev_kfree_skb(del_skb);  /* Free the standard skb. */
        }
    }
    return 0;
}
示例#3
0
/* ************************************************************************
 * This function runs in kernel mode.
 * It is activated from rtnetproxy_recv whenever rtnet received a frame to
 * be processed by rtnetproxy.
 * ************************************************************************ */
static void rtnetproxy_signal_handler(rtdm_nrtsig_t nrtsig)
{
    struct rtskb *rtskb;

    while ( (rtskb = read_from_ringbuffer(&ring_rtskb_rtnet_kernel)) != 0)
    {
        rtnetproxy_kernel_recv(rtskb);
        /* Place "used" rtskb in backqueue... */
        while (0 == write_to_ringbuffer(&ring_rtskb_kernel_rtnet, rtskb)) {
            rtdm_sem_up(&rtnetproxy_sem);
        }
    }

    /* Signal rtnet that there are "used" rtskbs waiting to be processed...
     * Resume the rtnetproxy_thread to recycle "used" rtskbs
     * */
    rtdm_sem_up(&rtnetproxy_sem);
}
示例#4
0
/* ************************************************************************
 * This function runs in kernel mode.
 * It is activated from rtnetproxy_recv whenever rtnet received a frame to
 * be processed by rtnetproxy.
 * ************************************************************************ */
static void rtnetproxy_rtai_srq(void)
{
    struct rtskb *rtskb;

    while ( (rtskb = read_from_ringbuffer(&ring_rtskb_rtnet_kernel)) != 0)
    {
        rtnetproxy_kernel_recv(rtskb);
        /* Place "used" rtskb in backqueue... */
        while (0 == write_to_ringbuffer(&ring_rtskb_kernel_rtnet, rtskb)) {
            rt_task_resume(&rtnetproxy_thread);
        }
    }

    /* Signal rtnet that there are "used" rtskbs waiting to be processed...
     * Resume the rtnetproxy_thread to recycle "used" rtskbs
     * */
    rt_task_resume(&rtnetproxy_thread);
}
示例#5
0
/* ************************************************************************
 * This function runs in rtai context.
 *
 * It is called from inside rtnet whenever a packet has been received that
 * has to be processed by rtnetproxy.
 * ************************************************************************ */
static int rtnetproxy_recv(struct rtskb *rtskb)
{

    /* Place the rtskb in the ringbuffer: */
    if (write_to_ringbuffer(&ring_rtskb_rtnet_kernel, rtskb))
    {
        /* Switch over to kernel context: */
        rt_pend_linux_srq(rtnetproxy_srq);
    }
    else
    {
        /* No space in ringbuffer => Free rtskb here... */
        rt_printk("rtnetproxy_recv: No space in queue\n");
        kfree_rtskb(rtskb);
    }

    return 0;
}
示例#6
0
/* ************************************************************************
 * This function runs in rtai context.
 *
 * It is called from inside rtnet whenever a packet has been received that
 * has to be processed by rtnetproxy.
 * ************************************************************************ */
static int rtnetproxy_recv(struct rtskb *rtskb)
{
    /* Acquire rtskb (JK) */
    if (rtskb_acquire(rtskb, &rtskb_pool) != 0) {
        rtdm_printk("rtnetproxy_recv: No free rtskb in pool\n");
        kfree_rtskb(rtskb);
    }
    /* Place the rtskb in the ringbuffer: */
    else if (write_to_ringbuffer(&ring_rtskb_rtnet_kernel, rtskb))
    {
        /* Switch over to kernel context: */
        rtdm_nrtsig_pend(&rtnetproxy_signal);
    }
    else
    {
        /* No space in ringbuffer => Free rtskb here... */
        rtdm_printk("rtnetproxy_recv: No space in queue\n");
        kfree_rtskb(rtskb);
    }

    return 0;
}
示例#7
0
/* ************************************************************************
 * This is a RTAI thread. It will be activated (resumed) by the
 * functions "rtnetproxy_xmit" or "rtnetproxy_kernel_recv" (in linux context)
 * whenever new frames have to be sent out or if the
 * "used" rtskb ringbuffer is full.
 * ************************************************************************ */
static void rtnetproxy_transmit_thread(void *arg)
{
    struct sk_buff *skb;
    struct rtskb *del;
    while (1)
    {
	/* Free all "used" rtskbs in ringbuffer */
	while ((del=read_from_ringbuffer(&ring_rtskb_kernel_rtnet)) != 0)	{
	    kfree_rtskb(del);
	}

        /* Send out all frames in the ringbuffer that have not been sent yet */
        while ((skb = read_from_ringbuffer(&ring_skb_kernel_rtnet)) != 0)
        {
            send_data_out(skb);
            /* Place the "used" skb in the ringbuffer back to kernel */
            write_to_ringbuffer(&ring_skb_rtnet_kernel, skb);
        }
        /* Will be activated with next frame to send... */
        rtdm_sem_down(&rtnetproxy_sem);
    }
}