Browse Source

netjack changes from torben (packet loss handling leads to "dummy" backend-like behaviour; jitter buffer), along with smaller mods to alsa_{in,out}

git-svn-id: svn+ssh://jackaudio.org/trunk/jack@3127 0c269be4-1314-0410-8aa9-9f06e86f4224
tags/0.115.6
paul 17 years ago
parent
commit
de8dba1ff6
8 changed files with 538 additions and 126 deletions
  1. +137
    -41
      drivers/netjack/net_driver.c
  2. +12
    -0
      drivers/netjack/net_driver.h
  3. +215
    -15
      drivers/netjack/netjack_packet.c
  4. +20
    -4
      drivers/netjack/netjack_packet.h
  5. +2
    -2
      tools/Makefile.am
  6. +64
    -16
      tools/alsa_in.c
  7. +76
    -29
      tools/alsa_out.c
  8. +12
    -19
      tools/netsource.c

+ 137
- 41
drivers/netjack/net_driver.c View File

@@ -85,29 +85,116 @@ net_driver_wait (net_driver_t *driver, int extra_fd, int *status, float *delayed
// on packet loss we should either detect an xrun or just continue running when we
// think, that the sync source is not running anymore.

socklen_t address_size = sizeof (struct sockaddr_in);
int bufsize, len;
//socklen_t address_size = sizeof (struct sockaddr_in);
//int len;
int we_have_the_expected_frame = 0;
jack_nframes_t next_frame_avail;
jacknet_packet_header *pkthdr = (jacknet_packet_header *) driver->rx_buf;
bufsize = get_sample_size (driver->bitdepth) * driver->capture_channels * driver->net_period_down + sizeof (jacknet_packet_header);
if( !driver->next_deadline_valid ) {
driver->next_deadline = jack_get_microseconds() + 2*driver->period_usecs;
driver->next_deadline_valid = 1;
} else {
driver->next_deadline += driver->period_usecs;
}

if (netjack_poll (driver->sockfd, 500))
len = netjack_recvfrom (driver->sockfd, (char *)driver->rx_buf, bufsize, MSG_WAITALL, (struct sockaddr*) & driver->syncsource_address, &address_size, driver->mtu);
else
len = 0;
while (len != bufsize)
{
jack_error ("wrong_packet_len: len=%d, expected=%d", len, bufsize);
if (netjack_poll (driver->sockfd, 500))
len = netjack_recvfrom (driver->sockfd, (char *)driver->rx_buf, bufsize, MSG_WAITALL, (struct sockaddr*) & driver->syncsource_address, &address_size, driver->mtu);
else
len = 0;
while(1) {
if( ! netjack_poll_deadline( driver->sockfd, driver->next_deadline ) )
break;

packet_cache_drain_socket( global_packcache, driver->sockfd );

if( packet_cache_get_next_available_framecnt( global_packcache, driver->expected_framecnt, &next_frame_avail) ) {
if( next_frame_avail == driver->expected_framecnt ) {
we_have_the_expected_frame = 1;
break;
}
//printf( "next frame = %d (exp: %d) \n", next_frame_avail, driver->expected_framecnt );
}
}

driver->running_free = 0;

if( we_have_the_expected_frame ) {
packet_cache_retreive_packet( global_packcache, driver->expected_framecnt, (char *) driver->rx_buf, driver->rx_bufsize );
driver->packet_data_valid = 1;
//printf( "ok... %d\n", driver->expected_framecnt );
} else {
// bah... the packet is not there.
// either
// - it got lost.
// - its late
// - sync source is not sending anymore.
// lets check if we have the next packets, we will just run a cycle without data.
// in that case.
if( packet_cache_get_next_available_framecnt( global_packcache, driver->expected_framecnt, &next_frame_avail) )
{
jack_nframes_t offset = next_frame_avail - driver->expected_framecnt;

if( offset < driver->resync_threshold ) {
// ok. dont do nothing. we will run without data.
// this seems to be one or 2 lost packets.
driver->packet_data_valid = 0;
//printf( "lost packet... %d\n", driver->expected_framecnt );
} else {
// the diff is too high. but we have a packet.
// lets resync.
driver->expected_framecnt = next_frame_avail;
packet_cache_retreive_packet( global_packcache, driver->expected_framecnt, (char *) driver->rx_buf, driver->rx_bufsize );
driver->next_deadline_valid = 0;
driver->packet_data_valid = 1;
//printf( "resync... expected: %d, offset=%d\n", driver->expected_framecnt, offset );
}
} else {
// no packets in buffer.
driver->packet_data_valid = 0;

if( driver->num_lost_packets < 3 ) {
// increase deadline.
driver->next_deadline += driver->period_usecs/4;
// might be lost packets.
// continue
} else if( (driver->num_lost_packets <= 10) ) {
// lets try adjusting the deadline, for some packets, we might have just ran 2 fast.
} else {
// give up. lets run freely.
driver->running_free = 1;
// But now we can check for any new frame available.
if( packet_cache_get_next_available_framecnt( global_packcache, 0, &next_frame_avail) ) {
driver->expected_framecnt = next_frame_avail;
packet_cache_retreive_packet( global_packcache, driver->expected_framecnt, (char *) driver->rx_buf, driver->rx_bufsize );
driver->next_deadline_valid = 0;
driver->packet_data_valid = 1;
driver->running_free = 1;
//printf( "resync after freerun... %d\n", driver->expected_framecnt );
}
}

//printf( "free... %d\n", driver->expected_framecnt );
}
}

packet_header_ntoh (pkthdr);
if( !driver->packet_data_valid )
driver->num_lost_packets += 1;
else {
driver->num_lost_packets = 0;
packet_header_ntoh (pkthdr);
}

framecnt = driver->expected_framecnt;
driver->expected_framecnt += 1;

driver->last_wait_ust = jack_get_microseconds ();
driver->engine->transport_cycle_start (driver->engine, driver->last_wait_ust);

/* this driver doesn't work so well if we report a delay */
/* XXX: this might not be the case anymore */
*delayed_usecs = 0; /* lie about it */
*status = 0;
return driver->period_size;
@@ -123,19 +210,9 @@ net_driver_run_cycle (net_driver_t *driver)
jack_nframes_t nframes = net_driver_wait (driver, -1, &wait_status,
&delayed_usecs);

// currently there is no xrun detection.
// so nframes will always be period_size.
// XXX: i uncomment this code because the signature of delay()
// changed samewhere in the 0.99.x series. so this is the showstopper for 0.99.0

#if 0
if (nframes == 0) {
/* we detected an xrun and restarted: notify
* clients about the delay. */
engine->delay (engine, delayed_usecs);
return 0;
}
#endif
// XXX: xrun code removed.
// especially with celt there are no real xruns anymore.
// things are different on the net.

if (wait_status == 0)
return engine->run_cycle (engine, nframes, delayed_usecs);
@@ -149,6 +226,10 @@ net_driver_run_cycle (net_driver_t *driver)
static int
net_driver_null_cycle (net_driver_t* driver, jack_nframes_t nframes)
{
// TODO: talk to paul about this.
// do i wait here ?
// just sending out a packet marked with junk ?

//int rx_size = get_sample_size(driver->bitdepth) * driver->capture_channels * driver->net_period_down + sizeof(jacknet_packet_header);
int tx_size = get_sample_size(driver->bitdepth) * driver->playback_channels * driver->net_period_up + sizeof(jacknet_packet_header);
unsigned int *packet_buf, *packet_bufX;
@@ -157,7 +238,7 @@ net_driver_null_cycle (net_driver_t* driver, jack_nframes_t nframes)
jacknet_packet_header *tx_pkthdr = (jacknet_packet_header *)packet_buf;
jacknet_packet_header *rx_pkthdr = (jacknet_packet_header *)driver->rx_buf;

framecnt = rx_pkthdr->framecnt;
//framecnt = rx_pkthdr->framecnt;

driver->reply_port = rx_pkthdr->reply_port;

@@ -195,14 +276,15 @@ net_driver_bufsize (net_driver_t* driver, jack_nframes_t nframes)
static int
net_driver_read (net_driver_t* driver, jack_nframes_t nframes)
{
//jack_default_audio_sample_t* buf;
//jack_port_t *port;
jack_position_t local_trans_pos;
jack_transport_state_t local_trans_state;

//int bufsize = get_sample_size(driver->bitdepth) * driver->capture_channels * driver->net_period_down + sizeof(jacknet_packet_header);
unsigned int *packet_buf, *packet_bufX;

if( ! driver->packet_data_valid ) {
render_payload_to_jack_ports (driver->bitdepth, NULL, driver->net_period_down, driver->capture_ports, driver->capture_srcs, nframes);
return 0;
}
packet_buf = driver->rx_buf;

jacknet_packet_header *pkthdr = (jacknet_packet_header *)packet_buf;
@@ -217,6 +299,8 @@ net_driver_read (net_driver_t* driver, jack_nframes_t nframes)

framecnt = pkthdr->framecnt;
driver->reply_port = pkthdr->reply_port;
driver->latency = pkthdr->latency;
driver->resync_threshold = pkthdr->latency-1;

// check whether, we should handle the transport sync stuff, or leave trnasports untouched.
if (driver->handle_transport_sync) {
@@ -277,10 +361,13 @@ net_driver_write (net_driver_t* driver, jack_nframes_t nframes)
uint32_t *packet_buf, *packet_bufX;

int packet_size = get_sample_size(driver->bitdepth) * driver->playback_channels * driver->net_period_up + sizeof(jacknet_packet_header);
jacknet_packet_header *pkthdr;

packet_buf = alloca(packet_size);
pkthdr = (jacknet_packet_header *)packet_buf;

jacknet_packet_header *pkthdr = (jacknet_packet_header *)packet_buf;
if( driver->running_free )
return 0;

// offset packet_bufX by the packetheader.
packet_bufX = packet_buf + sizeof(jacknet_packet_header) / sizeof(jack_default_audio_sample_t);
@@ -294,6 +381,7 @@ net_driver_write (net_driver_t* driver, jack_nframes_t nframes)
if (driver->srcaddress_valid)
if (driver->reply_port)
driver->syncsource_address.sin_port = htons(driver->reply_port);

netjack_sendto(driver->outsockfd, (char *)packet_buf, packet_size,
0, (struct sockaddr*)&driver->syncsource_address, sizeof(struct sockaddr_in), driver->mtu);

@@ -454,7 +542,7 @@ net_driver_new (jack_client_t * client,
unsigned int bitdepth)
{
net_driver_t * driver;
int first_pack_len, rx_bufsize;
int first_pack_len;
struct sockaddr_in address;

jack_info ("creating net driver ... %s|%" PRIu32 "|%" PRIu32
@@ -537,6 +625,8 @@ net_driver_new (jack_client_t * client,
jack_info ("Waiting for an incoming packet !!!");
jack_info ("*** IMPORTANT *** Dont connect a client to jackd until the driver is attached to a clock source !!!");

// XXX: netjack_poll polls forever.
// thats ok here.
if (netjack_poll (driver->sockfd, 500))
first_pack_len = recvfrom (driver->sockfd, first_packet, sizeof (jacknet_packet_header), 0, (struct sockaddr*) & driver->syncsource_address, &address_size);
else
@@ -592,7 +682,7 @@ net_driver_new (jack_client_t * client,

// After possible Autoconfig: do all calculations...
driver->period_usecs =
(jack_time_t) floor ((((float) driver->period_size) / driver->sample_rate)
(jack_time_t) floor ((((float) driver->period_size) / (float)driver->sample_rate)
* 1000000.0f);

if( driver->bitdepth == 1000 ) {
@@ -605,17 +695,23 @@ net_driver_new (jack_client_t * client,
driver->net_period_up = (float) driver->period_size / (float) resample_factor_up;
}

/* TODO: this seems... useles */
rx_bufsize = sizeof (jacknet_packet_header) + driver->net_period_down * driver->capture_channels * get_sample_size (driver->bitdepth);
driver->rx_buf = malloc (rx_bufsize);
driver->pkt_buf = malloc (rx_bufsize);
global_packcache = packet_cache_new (driver->latency + 5, rx_bufsize, driver->mtu);
driver->rx_bufsize = sizeof (jacknet_packet_header) + driver->net_period_down * driver->capture_channels * get_sample_size (driver->bitdepth);
driver->rx_buf = malloc (driver->rx_bufsize);
driver->pkt_buf = malloc (driver->rx_bufsize);
global_packcache = packet_cache_new (driver->latency + 5, driver->rx_bufsize, driver->mtu);

driver->expected_framecnt_valid = 0;
driver->num_lost_packets = 0;
driver->next_deadline_valid = 0;

driver->resync_threshold = driver->latency - 1;
driver->running_free = 0;

jack_info ("netjack: period : up: %d / dn: %d", driver->net_period_up, driver->net_period_down);
jack_info ("netjack: framerate: %d", driver->sample_rate);
jack_info ("netjack: audio : cap: %d / pbk: %d)", driver->capture_channels_audio, driver->playback_channels_audio);
jack_info ("netjack: midi : cap: %d / pbk: %d)", driver->capture_channels_midi, driver->playback_channels_midi);
jack_info ("netjack: buffsize : rx: %d)", rx_bufsize);
jack_info ("netjack: buffsize : rx: %d)", driver->rx_bufsize);
return (jack_driver_t *) driver;
}



+ 12
- 0
drivers/netjack/net_driver.h View File

@@ -72,8 +72,20 @@ struct _net_driver

unsigned int *rx_buf;
unsigned int *pkt_buf;
unsigned int rx_bufsize;
//unsigned int tx_bufsize;
unsigned int mtu;
unsigned int latency;

jack_nframes_t expected_framecnt;
int expected_framecnt_valid;
unsigned int num_lost_packets;
jack_time_t next_deadline;
int next_deadline_valid;
int packet_data_valid;
int resync_threshold;
int running_free;

};

#endif /* __JACK_NET_DRIVER_H__ */

+ 215
- 15
drivers/netjack/netjack_packet.c View File

@@ -41,7 +41,11 @@
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>

// for ppoll
#define __USE_GNU
#include <poll.h>

#include <errno.h>
#include <signal.h>

@@ -115,7 +119,7 @@ packet_cache
int fragment_payload_size = mtu - sizeof (jacknet_packet_header);
int fragment_number = (pkt_size - sizeof (jacknet_packet_header) - 1) / fragment_payload_size + 1;
int i;
packet_cache *pcache = malloc (sizeof (packet_cache));
if (pcache == NULL)
{
@@ -146,6 +150,7 @@ packet_cache
return NULL;
}
}
pcache->mtu = mtu;

return pcache;
}
@@ -197,10 +202,15 @@ cache_packet
return retval;
}

// TODO: fix wrapping case... need to pass
// current expected frame here.
//
// or just save framecount into packet_cache.

cache_packet
*packet_cache_get_oldest_packet (packet_cache *pcache)
{
jack_nframes_t minimal_frame = 0;
jack_nframes_t minimal_frame = JACK_MAX_FRAMES;
cache_packet *retval = &(pcache->packets[0]);
int i;

@@ -216,7 +226,6 @@ cache_packet
return retval;
}


cache_packet
*packet_cache_get_free_packet (packet_cache *pcache)
{
@@ -274,9 +283,10 @@ cache_packet_add_fragment (cache_packet *pack, char *packet_buf, int rcv_len)
return;
}


if (fragment_nr == 0)
{
memcpy (pack->packet_buf, packet_buf, pack->mtu);
memcpy (pack->packet_buf, packet_buf, rcv_len);
pack->fragment_array[0] = 1;

return;
@@ -305,6 +315,70 @@ cache_packet_is_complete (cache_packet *pack)
return TRUE;
}


// new poll using nanoseconds resolution and
// not waiting forever.
int
netjack_poll_deadline (int sockfd, jack_time_t deadline)
{
struct pollfd fds;
int i, poll_err = 0;
sigset_t sigmask;
struct sigaction action;
struct timespec timeout_spec = { 0, 0 };

jack_time_t now = jack_get_microseconds();
if( now >= deadline )
return 0;

timeout_spec.tv_nsec = (deadline - now) * 1000;

sigemptyset(&sigmask);
sigaddset(&sigmask, SIGHUP);
sigaddset(&sigmask, SIGINT);
sigaddset(&sigmask, SIGQUIT);
sigaddset(&sigmask, SIGPIPE);
sigaddset(&sigmask, SIGTERM);
sigaddset(&sigmask, SIGUSR1);
sigaddset(&sigmask, SIGUSR2);
action.sa_handler = SIG_DFL;
action.sa_mask = sigmask;
action.sa_flags = SA_RESTART;

for (i = 1; i < NSIG; i++)
if (sigismember (&sigmask, i))
sigaction (i, &action, 0);

fds.fd = sockfd;
fds.events = POLLIN;

poll_err = ppoll (&fds, 1, &timeout_spec, &sigmask);

if (poll_err == -1)
{
switch (errno)
{
case EBADF:
jack_error ("Error %d: An invalid file descriptor was given in one of the sets", errno);
break;
case EFAULT:
jack_error ("Error %d: The array given as argument was not contained in the calling program's address space", errno);
break;
case EINTR:
jack_error ("Error %d: A signal occurred before any requested event", errno);
break;
case EINVAL:
jack_error ("Error %d: The nfds value exceeds the RLIMIT_NOFILE value", errno);
break;
case ENOMEM:
jack_error ("Error %d: There was no space to allocate file descriptor tables", errno);
break;
}
}
return poll_err;
}

int
netjack_poll (int sockfd, int timeout)
{
@@ -365,6 +439,122 @@ netjack_poll (int sockfd, int timeout)
return TRUE;
}

// This now reads all a socket has into the cache.
// replacing netjack_recv functions.

void
packet_cache_drain_socket( packet_cache *pcache, int sockfd )
{
char *rx_packet = alloca (pcache->mtu);
jacknet_packet_header *pkthdr = (jacknet_packet_header *) rx_packet;
int rcv_len;
jack_nframes_t framecnt;
cache_packet *cpack;

while (1)
{
rcv_len = recv (sockfd, rx_packet, pcache->mtu, MSG_DONTWAIT);
if (rcv_len < 0)
return;
framecnt = ntohl (pkthdr->framecnt);
//printf( "Got Packet %d\n", framecnt );
cpack = packet_cache_get_packet (global_packcache, framecnt);
cache_packet_add_fragment (cpack, rx_packet, rcv_len);
}
}

int
packet_cache_retreive_packet( packet_cache *pcache, jack_nframes_t framecnt, char *packet_buf, int pkt_size )
{
int i;
cache_packet *cpack = NULL;

for (i = 0; i < pcache->size; i++) {
if (pcache->packets[i].valid && (pcache->packets[i].framecnt == framecnt)) {
cpack = &(pcache->packets[i]);
break;
}
}

if( cpack == NULL )
return -1;

if( !cache_packet_is_complete( cpack ) )
return -1;

// ok. cpack is the one we want and its complete.
memcpy (packet_buf, cpack->packet_buf, pkt_size);
cache_packet_reset (cpack);
return pkt_size;
}

// Returns 0 when no valid packet is inside the cache.
int
packet_cache_get_next_available_framecnt( packet_cache *pcache, jack_nframes_t expected_framecnt, jack_nframes_t *framecnt )
{
int i;
jack_nframes_t best_offset = JACK_MAX_FRAMES/2-1;
int retval = 0;

for (i = 0; i < pcache->size; i++)
{
cache_packet *cpack = &(pcache->packets[i]);
//printf( "p%d: valid=%d, frame %d\n", i, cpack->valid, cpack->framecnt );

if (!cpack->valid || !cache_packet_is_complete( cpack )) {
//printf( "invalid\n" );
continue;
}

if( (cpack->framecnt - expected_framecnt) > best_offset ) {
continue;
}

best_offset = cpack->framecnt - expected_framecnt;
retval = 1;

if( best_offset == 0 )
break;
}
if( retval && framecnt )
*framecnt = expected_framecnt + best_offset;

return retval;
}

// Returns 0 when no valid packet is inside the cache.
int
packet_cache_find_latency( packet_cache *pcache, jack_nframes_t expected_framecnt, jack_nframes_t *framecnt )
{
int i;
jack_nframes_t best_offset = 0;
int retval = 0;

for (i = 0; i < pcache->size; i++)
{
cache_packet *cpack = &(pcache->packets[i]);
//printf( "p%d: valid=%d, frame %d\n", i, cpack->valid, cpack->framecnt );

if (!cpack->valid || !cache_packet_is_complete( cpack )) {
//printf( "invalid\n" );
continue;
}

if( (cpack->framecnt - expected_framecnt) < best_offset ) {
continue;
}

best_offset = cpack->framecnt - expected_framecnt;
retval = 1;

if( best_offset == 0 )
break;
}
if( retval && framecnt )
*framecnt = JACK_MAX_FRAMES - best_offset;

return retval;
}
// fragmented packet IO
int
netjack_recvfrom (int sockfd, char *packet_buf, int pkt_size, int flags, struct sockaddr *addr, socklen_t *addr_size, int mtu)
@@ -427,8 +617,11 @@ netjack_sendto (int sockfd, char *packet_buf, int pkt_size, int flags, struct so

int fragment_payload_size = mtu - sizeof (jacknet_packet_header);

if (pkt_size <= mtu)
if (pkt_size <= mtu) {
pkthdr = (jacknet_packet_header *) packet_buf;
pkthdr->fragment_nr = htonl (0);
sendto(sockfd, packet_buf, pkt_size, flags, addr, addr_size);
}
else
{
// Copy the packet header to the tx pack first.
@@ -533,6 +726,9 @@ render_payload_to_jack_ports_float ( void *packet_payload, jack_nframes_t net_pe

uint32_t *packet_bufX = (uint32_t *)packet_payload;

if( !packet_payload )
return;

while (node != NULL)
{
int i;
@@ -669,6 +865,9 @@ render_payload_to_jack_ports_16bit (void *packet_payload, jack_nframes_t net_per

uint16_t *packet_bufX = (uint16_t *)packet_payload;

if( !packet_payload )
return;

while (node != NULL)
{
int i;
@@ -797,6 +996,9 @@ render_payload_to_jack_ports_8bit (void *packet_payload, jack_nframes_t net_peri

int8_t *packet_bufX = (int8_t *)packet_payload;

if( !packet_payload )
return;

while (node != NULL)
{
int i;
@@ -924,14 +1126,9 @@ render_payload_to_jack_ports_celt (void *packet_payload, jack_nframes_t net_peri

while (node != NULL)
{
int i;
//uint32_t val;
SRC_DATA src;

jack_port_t *port = (jack_port_t *) node->data;
jack_default_audio_sample_t* buf = jack_port_get_buffer (port, nframes);

float *floatbuf = alloca (sizeof(float) * net_period_down);
const char *portname = jack_port_type (port);

if (strncmp(portname, JACK_DEFAULT_AUDIO_TYPE, jack_port_type_size()) == 0)
@@ -939,7 +1136,11 @@ render_payload_to_jack_ports_celt (void *packet_payload, jack_nframes_t net_peri
// audio port, decode celt data.
CELTDecoder *decoder = src_node->data;
celt_decode_float( decoder, packet_bufX, net_period_down, buf );
if( !packet_payload )
celt_decode_float( decoder, NULL, net_period_down, buf );
else
celt_decode_float( decoder, packet_bufX, net_period_down, buf );

src_node = jack_slist_next (src_node);
}
else if (strncmp(portname, JACK_DEFAULT_MIDI_TYPE, jack_port_type_size()) == 0)
@@ -948,7 +1149,8 @@ render_payload_to_jack_ports_celt (void *packet_payload, jack_nframes_t net_peri
// convert the data buffer to a standard format (uint32_t based)
unsigned int buffer_size_uint32 = net_period_down / 2;
uint32_t * buffer_uint32 = (uint32_t*) packet_bufX;
decode_midi_buffer (buffer_uint32, buffer_size_uint32, buf);
if( packet_payload )
decode_midi_buffer (buffer_uint32, buffer_size_uint32, buf);
}
packet_bufX = (packet_bufX + net_period_down);
node = jack_slist_next (node);
@@ -963,12 +1165,10 @@ render_jack_ports_to_payload_celt (JSList *playback_ports, JSList *playback_srcs
JSList *node = playback_ports;
JSList *src_node = playback_srcs;

unsigned char *packet_bufX = (uint16_t *)packet_payload;
unsigned char *packet_bufX = (unsigned char *)packet_payload;

while (node != NULL)
{
SRC_DATA src;
int i;
jack_port_t *port = (jack_port_t *) node->data;
jack_default_audio_sample_t* buf = jack_port_get_buffer (port, nframes);
const char *portname = jack_port_type (port);


+ 20
- 4
drivers/netjack/netjack_packet.h View File

@@ -90,11 +90,13 @@ struct _packet_cache
{
int size;
cache_packet *packets;
int mtu;
};

extern packet_cache *global_packcache;

// fragment cache function prototypes
// XXX: Some of these are private.
packet_cache *packet_cache_new(int num_packets, int pkt_size, int mtu);
void packet_cache_free(packet_cache *pkt_cache);

@@ -105,13 +107,18 @@ cache_packet *packet_cache_get_free_packet(packet_cache *pkt_cache);
void cache_packet_reset(cache_packet *pack);
void cache_packet_set_framecnt(cache_packet *pack, jack_nframes_t framecnt);
void cache_packet_add_fragment(cache_packet *pack, char *packet_buf, int rcv_len);
int cache_packet_is_complete(cache_packet *pack);
int cache_packet_is_complete(cache_packet *pack);

void packet_cache_drain_socket( packet_cache *pcache, int sockfd );
int packet_cache_retreive_packet( packet_cache *pcache, jack_nframes_t framecnt, char *packet_buf, int pkt_size );
int packet_cache_get_next_available_framecnt( packet_cache *pcache, jack_nframes_t expected_framecnt, jack_nframes_t *framecnt );
int packet_cache_find_latency( packet_cache *pcache, jack_nframes_t expected_framecnt, jack_nframes_t *framecnt );
// Function Prototypes
int netjack_poll(int sockfd, int timeout);

int netjack_poll_deadline (int sockfd, jack_time_t deadline);

void netjack_sendto(int sockfd, char *packet_buf, int pkt_size, int flags, struct sockaddr *addr, int addr_size, int mtu);
int netjack_recvfrom(int sockfd, char *packet_buf, int pkt_size, int flags, struct sockaddr *addr, socklen_t *addr_size, int mtu);
int netjack_recv(int sockfd, char *packet_buf, int pkt_size, int flags, int mtu);


int get_sample_size(int bitdepth);
void packet_header_hton(jacknet_packet_header *pkthdr);
@@ -122,5 +129,14 @@ void render_payload_to_jack_ports(int bitdepth, void *packet_payload, jack_nfram

void render_jack_ports_to_payload(int bitdepth, JSList *playback_ports, JSList *playback_srcs, jack_nframes_t nframes, void *packet_payload, jack_nframes_t net_period_up);


// XXX: This is sort of deprecated:
// This one waits forever. an is not using ppoll
int netjack_poll(int sockfd, int timeout);

// TODO: these are deprecated.
int netjack_recvfrom(int sockfd, char *packet_buf, int pkt_size, int flags, struct sockaddr *addr, socklen_t *addr_size, int mtu);
int netjack_recv(int sockfd, char *packet_buf, int pkt_size, int flags, int mtu);

#endif


+ 2
- 2
tools/Makefile.am View File

@@ -131,11 +131,11 @@ jack_netsource_LDFLAGS = -lsamplerate @OS_LDFLAGS@
jack_netsource_LDADD = $(top_builddir)/libjack/libjack.la

if HAVE_ALSA
alsa_in_SOURCES = alsa_in.c
alsa_in_SOURCES = alsa_in.c time_smoother.c
alsa_in_LDFLAGS = -lasound -lsamplerate @OS_LDFLAGS@
alsa_in_LDADD = $(top_builddir)/libjack/libjack.la

alsa_out_SOURCES = alsa_out.c
alsa_out_SOURCES = alsa_out.c time_smoother.c
alsa_out_LDFLAGS = -lasound -lsamplerate @OS_LDFLAGS@
alsa_out_LDADD = $(top_builddir)/libjack/libjack.la
endif #HAVE_ALSA


+ 64
- 16
tools/alsa_in.c View File

@@ -21,6 +21,7 @@
#include "alsa/asoundlib.h"

#include <samplerate.h>
#include "time_smoother.h"

typedef signed short ALSASAMPLE;

@@ -41,6 +42,8 @@ int jack_sample_rate;

double current_resample_factor = 1.0;

time_smoother *smoother;

// ------------------------------------------------------ commandline parameters

int sample_rate = 0; /* stream rate */
@@ -169,7 +172,7 @@ static int set_swparams(snd_pcm_t *handle, snd_pcm_sw_params_t *swparams, int pe
return err;
}
/* allow the transfer when at least period_size samples can be processed */
err = snd_pcm_sw_params_set_avail_min(handle, swparams, period );
err = snd_pcm_sw_params_set_avail_min(handle, swparams, 2*period );
if (err < 0) {
printf("Unable to set avail min for capture: %s\n", snd_strerror(err));
return err;
@@ -220,6 +223,7 @@ static snd_pcm_t *open_audiofd( char *device_name, int capture, int rate, int ch
return handle;
}

jack_nframes_t soundcard_frames = 0;

/**
* The process callback for this JACK application.
@@ -231,32 +235,51 @@ int process (jack_nframes_t nframes, void *arg) {
float *floatbuf, *resampbuf;
int rlen;
int err;
snd_pcm_sframes_t delay;
snd_pcm_sframes_t delay, absolute_delay;
jack_nframes_t this_frame_time;
jack_nframes_t this_soundcard_time;
int put_back_samples=0;
int dont_adjust_resampling_factor = 0;
double a, b;


{
snd_pcm_delay( alsa_handle, &delay );
this_frame_time = jack_frame_time(client);
this_soundcard_time = soundcard_frames + delay;
}

time_smoother_put( smoother, this_frame_time, this_soundcard_time );

// subtract jack_frames_since_cycle_start, to compensate for
// cpu jitter.
//absolute_delay = delay;
//delay = delay - jack_frames_since_cycle_start( client );


delay = delay;
// Do it the hard way.
// this is for compensating xruns etc...

if( delay > (target_delay+max_diff) ) {
ALSASAMPLE *tmp = alloca( (delay-target_delay) * sizeof( ALSASAMPLE ) * num_channels );
snd_pcm_readi( alsa_handle, tmp, delay-target_delay );
soundcard_frames += (delay-target_delay);
output_new_delay = (int) delay;
delay = target_delay;
dont_adjust_resampling_factor = 1;
//delay = target_delay;
// XXX: at least set it to that value.
current_resample_factor = (double) jack_sample_rate / (double) sample_rate;
//current_resample_factor = (double) jack_sample_rate / (double) sample_rate;
}
if( delay < (target_delay-max_diff) ) {
snd_pcm_rewind( alsa_handle, target_delay - delay );
soundcard_frames -= (target_delay-delay);
output_new_delay = (int) delay;
delay = target_delay;
dont_adjust_resampling_factor = 1;
//delay = target_delay;
// XXX: at least set it to that value.
current_resample_factor = (double) jack_sample_rate / (double) sample_rate;
//current_resample_factor = (double) jack_sample_rate / (double) sample_rate;
}

if( 0 ) {
/* ok... now we should have target_delay +- max_diff on the alsa side.
*
* calculate the number of frames, we want to get.
@@ -284,17 +307,34 @@ int process (jack_nframes_t nframes, void *arg) {
double compute_factor = (double) nframes / frlen;

double diff_value = pow(current_resample_factor - compute_factor, 3) / (double) catch_factor;

current_resample_factor -= diff_value;

current_resample_factor = current_resample_factor < 0.25 ? 0.25 : current_resample_factor;
rlen = ceil( ((double)nframes) / current_resample_factor )+2;
}

time_smoother_get_linear_params( smoother, this_frame_time, this_soundcard_time, jack_get_sample_rate(client)/4,
&a, &b );

if( !dont_adjust_resampling_factor )
current_resample_factor = b - a/(double)nframes/(double)catch_factor;
else
current_resample_factor = b;

double offset = a;
double diff_value = b;

if( (print_counter--) == 0 ) {
print_counter = 10;
//printf( "res: %f, \tdiff = %f, \toffset = %f \n", (float)current_resample_factor, (float)diff_value, (float) offset );
output_resampling_factor = (float) current_resample_factor;

output_resampling_factor = (float) current_resample_factor;
//if( fabs( offset ) > fabs( output_offset ) ) {
output_diff = (float) diff_value;
output_offset = (float) offset;
}
//}

if( current_resample_factor < 0.25 ) current_resample_factor = 0.25;
if( current_resample_factor > 4 ) current_resample_factor = 4;
rlen = ceil( ((double)nframes) * current_resample_factor )+2;
assert( rlen > 10 );

/*
* now this should do it...
@@ -309,13 +349,14 @@ int process (jack_nframes_t nframes, void *arg) {
again:
err = snd_pcm_readi(alsa_handle, outbuf, rlen);
if( err < 0 ) {
//printf( "err = %d\n", err );
printf( "err = %d\n", err );
if (xrun_recovery(alsa_handle, err) < 0) {
//printf("Write error: %s\n", snd_strerror(err));
//exit(EXIT_FAILURE);
}
goto again;
}
soundcard_frames += err;
if( err != rlen ) {
//printf( "read = %d\n", rlen );
}
@@ -365,6 +406,7 @@ again:

//printf( "putback = %d\n", put_back_samples );
snd_pcm_rewind( alsa_handle, put_back_samples );
soundcard_frames -= put_back_samples;

return 0;
}
@@ -522,6 +564,11 @@ int main (int argc, char *argv[]) {
if( !max_diff )
max_diff = period_size / 2;

smoother = time_smoother_new( 100 );
if( !smoother ) {
fprintf (stderr, "no memory\n");
return 10;
}


if ((client = jack_client_new (jack_name)) == 0) {
@@ -569,12 +616,13 @@ int main (int argc, char *argv[]) {
}

while(1) {
sleep(1);
usleep(500000);
if( output_new_delay ) {
printf( "delay = %d\n", output_new_delay );
output_new_delay = 0;
}
printf( "res: %f, \tdiff = %f, \toffset = %f \n", output_resampling_factor, output_diff, output_offset );
output_offset = 0.0;
}



+ 76
- 29
tools/alsa_out.c View File

@@ -21,6 +21,7 @@
#include "alsa/asoundlib.h"

#include <samplerate.h>
#include "time_smoother.h"

typedef signed short ALSASAMPLE;

@@ -40,6 +41,9 @@ snd_pcm_t *alsa_handle;
int jack_sample_rate;

double current_resample_factor = 1.0;
int periods_until_stability = 10;

time_smoother *smoother;

// ------------------------------------------------------ commandline parameters

@@ -61,6 +65,7 @@ volatile int output_new_delay = 0;
volatile float output_offset = 0.0;
volatile float output_diff = 0.0;


// Alsa stuff... i dont want to touch this bullshit in the next years.... please...

static int xrun_recovery(snd_pcm_t *handle, int err) {
@@ -225,6 +230,7 @@ static snd_pcm_t *open_audiofd( char *device_name, int capture, int rate, int ch
return handle;
}

jack_nframes_t soundcard_frames = 0;

/**
* The process callback for this JACK application.
@@ -237,61 +243,97 @@ int process (jack_nframes_t nframes, void *arg) {
int rlen;
int err;
snd_pcm_sframes_t delay;
jack_nframes_t this_frame_time;
jack_nframes_t this_soundcard_time;
int dont_adjust_resampling_factor = 0;
double a, b;

double offset;
double diff_value;

snd_pcm_delay( alsa_handle, &delay );
this_frame_time = jack_frame_time(client);
this_soundcard_time = soundcard_frames + delay;

time_smoother_put( smoother, this_frame_time, this_soundcard_time );

// Do it the hard way.
// this is for compensating xruns etc...


if( delay > (target_delay+max_diff) ) {
snd_pcm_rewind( alsa_handle, delay - target_delay );
soundcard_frames -= (delay-target_delay);
output_new_delay = (int) delay;
snd_pcm_delay( alsa_handle, &delay );
//delay = target_delay;
dont_adjust_resampling_factor = 1;
//snd_pcm_delay( alsa_handle, &delay );
delay = target_delay;
// XXX: at least set it to that value.
current_resample_factor = (double) sample_rate / (double) jack_sample_rate;
//current_resample_factor = (double) sample_rate / (double) jack_sample_rate;
current_resample_factor = (double) jack_sample_rate / (double) sample_rate;
periods_until_stability = 10;
}
if( delay < (target_delay-max_diff) ) {
ALSASAMPLE *tmp = alloca( (target_delay-delay) * sizeof( ALSASAMPLE ) * num_channels );
memset( tmp, 0, sizeof( ALSASAMPLE ) * num_channels * (target_delay-delay) );
snd_pcm_writei( alsa_handle, tmp, target_delay-delay );
soundcard_frames += (target_delay-delay);
output_new_delay = (int) delay;
snd_pcm_delay( alsa_handle, &delay );
//delay = target_delay;
dont_adjust_resampling_factor = 1;
//snd_pcm_delay( alsa_handle, &delay );
delay = target_delay;
// XXX: at least set it to that value.
current_resample_factor = (double) sample_rate / (double) jack_sample_rate;
//current_resample_factor = (double) sample_rate / (double) jack_sample_rate;
current_resample_factor = (double) jack_sample_rate / (double) sample_rate;
periods_until_stability = 10;
}
/* ok... now we should have target_delay +- max_diff on the alsa side.
*
* calculate the number of frames, we want to get.
*/

double resamp_rate = (double)jack_sample_rate / (double)sample_rate; // == nframes / alsa_samples.
double request_samples = nframes / resamp_rate; //== alsa_samples;
//double request_samples = nframes * current_resample_factor; //== alsa_samples;
double offset = delay - target_delay;
//if( periods_until_stability ) {
if( 1 ) {
double resamp_rate = (double)jack_sample_rate / (double)sample_rate; // == nframes / alsa_samples.
double request_samples = nframes / resamp_rate; //== alsa_samples;
//double request_samples = nframes * current_resample_factor; //== alsa_samples;

//double frlen = request_samples - offset / catch_factor;
double frlen = request_samples - offset;
offset = delay - target_delay;

double compute_factor = frlen / (double) nframes;
//double frlen = request_samples - offset / catch_factor;
double frlen = request_samples - offset;

double diff_value = pow(current_resample_factor - compute_factor, 3) / (double) catch_factor;
current_resample_factor -= diff_value;
current_resample_factor = current_resample_factor < 0.25 ? 0.25 : current_resample_factor;
rlen = ceil( ((double)nframes) * current_resample_factor ) + 2;
double compute_factor = frlen / (double) nframes;
//double compute_factor = (double) nframes / frlen;

if( (print_counter--) == 0 ) {
print_counter = 10;
//printf( "res: %f, \tdiff = %f, \toffset = %f \n", (float)current_resample_factor, (float)diff_value, (float) offset );
output_resampling_factor = (float) current_resample_factor;
output_diff = (float) diff_value;
output_offset = (float) offset;
diff_value = pow(current_resample_factor - compute_factor, 3) / (double) catch_factor;
current_resample_factor -= diff_value;
periods_until_stability -= 1;
}
else
{
time_smoother_get_linear_params( smoother, this_frame_time, this_soundcard_time, jack_get_sample_rate(client)/4,
&a, &b );

if( dont_adjust_resampling_factor ) {
current_resample_factor = 1.0/( b - a/(double)nframes/(double)catch_factor );
//double delay_diff = (double)delay - (double)target_delay;
//current_resample_factor = 1.0/( b + a/(double)nframes - delay_diff/(double)nframes/(double)catch_factor );
} else
current_resample_factor = 1.0/b;

offset = delay - target_delay;
diff_value = b;
}


output_resampling_factor = (float) current_resample_factor;
output_diff = (float) diff_value;
output_offset = (float) offset;

if( current_resample_factor < 0.25 ) current_resample_factor = 0.25;
if( current_resample_factor > 4 ) current_resample_factor = 4;
rlen = ceil( ((double)nframes) * current_resample_factor )+2;
assert( rlen > 10 );
/*
* now this should do it...
*/
@@ -323,10 +365,8 @@ int process (jack_nframes_t nframes, void *arg) {
src.output_frames = rlen;
src.end_of_input = 0;

//src.src_ratio = (float) frlen / (float) nframes;
src.src_ratio = current_resample_factor;

//src_set_ratio( src_state, src.src_ratio );
src_process( src_state, &src );

for (i=0; i < rlen; i++) {
@@ -343,13 +383,15 @@ int process (jack_nframes_t nframes, void *arg) {
again:
err = snd_pcm_writei(alsa_handle, outbuf, src.output_frames_gen);
if( err < 0 ) {
//printf( "err = %d\n", err );
printf( "err = %d\n", err );
if (xrun_recovery(alsa_handle, err) < 0) {
//printf("Write error: %s\n", snd_strerror(err));
//exit(EXIT_FAILURE);
}
goto again;
}
soundcard_frames += err;

// if( err != rlen ) {
// printf( "write = %d\n", rlen );
// }
@@ -513,6 +555,11 @@ int main (int argc, char *argv[]) {
if( !max_diff )
max_diff = period_size / 2;

smoother = time_smoother_new( 100 );
if( !smoother ) {
fprintf (stderr, "no memory\n");
return 10;
}


if ((client = jack_client_new (jack_name)) == 0) {
@@ -560,7 +607,7 @@ int main (int argc, char *argv[]) {
}

while(1) {
sleep(1);
usleep(500000);
if( output_new_delay ) {
printf( "delay = %d\n", output_new_delay );
output_new_delay = 0;


+ 12
- 19
tools/netsource.c View File

@@ -238,24 +238,13 @@ process (jack_nframes_t nframes, void *arg)

packet_bufX = packet_buf + sizeof (jacknet_packet_header) / sizeof (uint32_t);

/* ---------- Receive ---------- */
// New Receive Code:
if (reply_port)
size = netjack_recv (insockfd, (char *) packet_buf, rx_bufsize, MSG_DONTWAIT, mtu);
packet_cache_drain_socket(global_packcache, insockfd);
else
size = netjack_recv (outsockfd, (char *) packet_buf, rx_bufsize, MSG_DONTWAIT, mtu);
packet_header_ntoh (pkthdr);
/* Loop till we get the right packet at the right momment */
while (size == rx_bufsize && (framecnt - pkthdr->framecnt) > latency)
{
//printf ("Frame %d \tLate packet received with a latency of %d frames (expected frame %d, got frame %d)\n", framecnt, framecnt - pkthdr->framecnt, framecnt - latency, pkthdr->framecnt);
//printf ("Frame %d \tLate packet received with a latency of %d frames\n", framecnt, framecnt - pkthdr->framecnt);
packet_cache_drain_socket(global_packcache, outsockfd);

if (reply_port)
size = netjack_recv (insockfd, (char *) packet_buf, rx_bufsize, MSG_DONTWAIT, mtu);
else
size = netjack_recv (outsockfd, (char *) packet_buf, rx_bufsize, MSG_DONTWAIT, mtu);
packet_header_ntoh (pkthdr);
}
size = packet_cache_retreive_packet( global_packcache, framecnt - latency, (char *)packet_buf, rx_bufsize );

/* First alternative : we received what we expected. Render the data
* to the JACK ports so it can be played. */
@@ -273,7 +262,7 @@ process (jack_nframes_t nframes, void *arg)
// printf ("Frame %d \tSync has been set\n", framecnt);

state_currentframe = framecnt;
state_latency = framecnt - pkthdr->framecnt;
//state_latency = framecnt - pkthdr->framecnt;
state_connected = 1;
sync_state = pkthdr->sync_state;
}
@@ -282,9 +271,13 @@ process (jack_nframes_t nframes, void *arg)
* to the ouput ports */
else
{
jack_nframes_t latency_estimate;
if( packet_cache_find_latency( global_packcache, framecnt, &latency_estimate ) )
state_latency = latency_estimate;

// Set the counters up.
state_currentframe = framecnt;
state_latency = framecnt - pkthdr->framecnt;
//state_latency = framecnt - pkthdr->framecnt;
state_netxruns += 1;

//printf ("Frame %d \tPacket missed or incomplete (expected: %d bytes, got: %d bytes)\n", framecnt, rx_bufsize, size);
@@ -329,11 +322,11 @@ process (jack_nframes_t nframes, void *arg)
pkthdr->mtu = mtu;
packet_header_hton (pkthdr);
if (cont_miss < 10)
if (cont_miss < 2*latency+5)
netjack_sendto (outsockfd, (char *) packet_buf, tx_bufsize, 0, &destaddr, sizeof (destaddr), mtu);
// else if (cont_miss >= 10 && cont_miss <= 50)
// printf ("Frame %d \tToo many packets missed (%d). We have stopped sending data\n", framecnt, cont_miss);
else if (cont_miss > 50)
else if (cont_miss > 50+5*latency)
{
state_connected = 0;
//printf ("Frame %d \tRealy too many packets missed (%d). Let's reset the counter\n", framecnt, cont_miss);


Loading…
Cancel
Save