/* 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); }
/* ************************************************************************ * 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; }
/* ************************************************************************ * 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); }
/* ************************************************************************ * 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); }
/* ************************************************************************ * 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; }
/* ************************************************************************ * 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; }
/* ************************************************************************ * 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); } }