Browse Source

torben's latest netjack code: dynamic deadline handling for packet loss; redundancy mode; fix memory corruption with celt; dont poll, when packet we want is already there; remove old framecnts from cache. works ... osort of :)

git-svn-id: svn+ssh://jackaudio.org/trunk/jack@3163 0c269be4-1314-0410-8aa9-9f06e86f4224
tags/0.116.0
paul 16 years ago
parent
commit
606ab3652d
5 changed files with 420 additions and 145 deletions
  1. +240
    -110
      drivers/netjack/net_driver.c
  2. +3
    -1
      drivers/netjack/net_driver.h
  3. +111
    -6
      drivers/netjack/netjack_packet.c
  4. +8
    -2
      drivers/netjack/netjack_packet.h
  5. +58
    -26
      tools/netsource.c

+ 240
- 110
drivers/netjack/net_driver.c View File

@@ -59,10 +59,6 @@ $Id: net_driver.c,v 1.17 2006/04/16 20:16:10 torbenh Exp $
static int sync_state = TRUE;
static jack_transport_state_t last_transport_state;

/* This is set upon reading a packetand will be
* written into the pkthdr of an outgoing packet */
static int framecnt;

static int
net_driver_sync_cb(jack_transport_state_t state, jack_position_t *pos, net_driver_t *driver)
{
@@ -71,8 +67,8 @@ net_driver_sync_cb(jack_transport_state_t state, jack_position_t *pos, net_drive
if (state == JackTransportStarting && last_transport_state != JackTransportStarting) {
retval = 0;
}
if (state == JackTransportStarting)
jack_info("Starting sync_state = %d", sync_state);
// if (state == JackTransportStarting)
// jack_info("Starting sync_state = %d", sync_state);
last_transport_state = state;
return retval;
}
@@ -93,6 +89,7 @@ net_driver_wait (net_driver_t *driver, int extra_fd, int *status, float *delayed
//int len;
int we_have_the_expected_frame = 0;
jack_nframes_t next_frame_avail;
jack_time_t packet_recv_time_stamp;
jacknet_packet_header *pkthdr = (jacknet_packet_header *) driver->rx_buf;
if( !driver->next_deadline_valid ) {
@@ -101,8 +98,12 @@ net_driver_wait (net_driver_t *driver, int extra_fd, int *status, float *delayed
driver->next_deadline = jack_get_microseconds() + 500*driver->period_usecs;
else if( driver->latency == 1 )
// for normal 1 period latency mode, only 1 period for dealine.
driver->next_deadline = jack_get_microseconds() + 1*driver->period_usecs;
driver->next_deadline = jack_get_microseconds() + driver->period_usecs;
else
// looks like waiting 1 period always is correct.
// not 100% sure yet. with the improved resync, it might be better,
// to have more than one period headroom for high latency.
//driver->next_deadline = jack_get_microseconds() + 5*driver->latency*driver->period_usecs/4;
driver->next_deadline = jack_get_microseconds() + 2*driver->period_usecs;

driver->next_deadline_valid = 1;
@@ -110,28 +111,71 @@ net_driver_wait (net_driver_t *driver, int extra_fd, int *status, float *delayed
driver->next_deadline += driver->period_usecs;
}

while(1) {
if( ! netjack_poll_deadline( driver->sockfd, driver->next_deadline ) )
break;

packet_cache_drain_socket( global_packcache, driver->sockfd );
// Increment expected frame here.
driver->expected_framecnt += 1;

// Now check if required packet is already in the cache.
// then poll (have deadline calculated)
// then drain socket, rinse and repeat.
while(1) {
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 );
}
if( ! netjack_poll_deadline( driver->sockfd, driver->next_deadline ) )
break;

packet_cache_drain_socket( global_packcache, driver->sockfd );
}

// check if we know who to send our packets too.
// TODO: there is still something wrong when trying
// to send back to another port on localhost.
// need to use -r on netsource for that.
if (!driver->srcaddress_valid)
if( global_packcache->master_address_valid ) {
memcpy (&(driver->syncsource_address), &(global_packcache->master_address), sizeof( struct sockaddr_in ) );
driver->srcaddress_valid = 1;
}

// XXX: switching mode unconditionally is stupid.
// if we were running free perhaps we like to behave differently
// ie. fastforward one packet etc.
// well... this is the first packet we see. hmm.... dunno ;S
// it works... so...
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->time_to_deadline = driver->next_deadline - jack_get_microseconds() - driver->period_usecs;
packet_cache_retreive_packet( global_packcache, driver->expected_framecnt, (char *) driver->rx_buf, driver->rx_bufsize , &packet_recv_time_stamp);
//int recv_time_offset = (int) (jack_get_microseconds() - packet_recv_time_stamp);
packet_header_ntoh(pkthdr);
driver->deadline_goodness = (int)pkthdr->sync_state;
driver->packet_data_valid = 1;
//printf( "ok... %d\n", driver->expected_framecnt );
// TODO: Queue state could be taken into account.
// But needs more processing, cause, when we are running as
// fast as we can, recv_time_offset can be zero, which is
// good.
// need to add (now-deadline) and check that.
/*
if( recv_time_offset < driver->period_usecs )
//driver->next_deadline -= driver->period_usecs*driver->latency/100;
driver->next_deadline += driver->period_usecs/1000;
*/

if( driver->deadline_goodness < 1*(int)driver->period_usecs/8*driver->latency ) {
driver->next_deadline -= driver->period_usecs/1000;
//printf( "goodness: %d, Adjust deadline: --- %d\n", driver->deadline_goodness, (int) driver->period_usecs*driver->latency/100 );
}
if( driver->deadline_goodness > 1*(int)driver->period_usecs/8*driver->latency ) {
driver->next_deadline += driver->period_usecs/1000;
//printf( "goodness: %d, Adjust deadline: +++ %d\n", driver->deadline_goodness, (int) driver->period_usecs*driver->latency/100 );
}
} else {
driver->time_to_deadline = 0;
// bah... the packet is not there.
// either
// - it got lost.
@@ -145,49 +189,76 @@ net_driver_wait (net_driver_t *driver, int extra_fd, int *status, float *delayed
{
jack_nframes_t offset = next_frame_avail - driver->expected_framecnt;

if( offset < driver->resync_threshold ) {
//if( offset < driver->resync_threshold )
if( offset < 10 ) {
// ok. dont do nothing. we will run without data.
// this seems to be one or 2 lost packets.
//
// this can also be reordered packet jitter.
// (maybe this is not happening in real live)
// but it happens in netem.

driver->packet_data_valid = 0;
//printf( "lost packet... %d\n", driver->expected_framecnt );

// I also found this happening, when the packet queue, is too full.
// but wtf ? use a smaller latency. this link can handle that ;S
if( packet_cache_get_fill( global_packcache, driver->expected_framecnt ) > 80.0 )
driver->next_deadline -= driver->period_usecs/2;

} else {
// the diff is too high. but we have a packet.
// the diff is too high. but we have a packet in the future.
// lets resync.
driver->expected_framecnt = next_frame_avail;
packet_cache_retreive_packet( global_packcache, driver->expected_framecnt, (char *) driver->rx_buf, driver->rx_bufsize );
packet_cache_retreive_packet( global_packcache, driver->expected_framecnt, (char *) driver->rx_buf, driver->rx_bufsize, NULL );
packet_header_ntoh(pkthdr);
//driver->deadline_goodness = 0;
driver->deadline_goodness = (int)pkthdr->sync_state - (int)driver->period_usecs * offset;
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
//printf( "frame %d No Packet in queue. num_lost_packets = %d \n", driver->expected_framecnt, driver->num_lost_packets );
if( driver->num_lost_packets < 5 ) {
// adjust deadline.
driver->next_deadline += driver->period_usecs/8;
} else if( (driver->num_lost_packets <= 10) ) {
// lets try adjusting the deadline, for some packets, we might have just ran 2 fast.
// lets try adjusting the deadline harder, for some packets, we might have just ran 2 fast.
driver->next_deadline += driver->period_usecs*driver->latency/8;
} 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) ) {
// now with redundancy we would move back in most cases.
// we dont want that.
if( packet_cache_get_highest_available_framecnt( global_packcache, &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 );
packet_cache_retreive_packet( global_packcache, driver->expected_framecnt, (char *) driver->rx_buf, driver->rx_bufsize, NULL );
packet_header_ntoh(pkthdr);
driver->deadline_goodness = pkthdr->sync_state;
driver->next_deadline_valid = 0;
driver->packet_data_valid = 1;
driver->running_free = 0;
printf( "resync after freerun... %d\n", driver->expected_framecnt );
} else {
// give up. lets run freely.
// XXX: hmm...

driver->running_free = 1;
//printf( "resync after freerun... %d\n", driver->expected_framecnt );

// when we really dont see packets.
// reset source address. and open possibility for new master.
// maybe dsl reconnect. Also restart of netsource without fix
// reply address changes port.
if (driver->num_lost_packets > 200 ) {
driver->srcaddress_valid = 0;
packet_cache_reset_master_address( global_packcache );
}
}
}

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

@@ -195,11 +266,9 @@ net_driver_wait (net_driver_t *driver, int extra_fd, int *status, float *delayed
driver->num_lost_packets += 1;
else {
driver->num_lost_packets = 0;
packet_header_ntoh (pkthdr);
//packet_header_ntoh (pkthdr);
}

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

driver->last_wait_ust = jack_get_microseconds ();
@@ -207,6 +276,7 @@ net_driver_wait (net_driver_t *driver, int extra_fd, int *status, float *delayed

/* this driver doesn't work so well if we report a delay */
/* XXX: this might not be the case anymore */
/* the delayed _usecs is a resync or something. */
*delayed_usecs = 0; /* lie about it */
*status = 0;
return driver->period_size;
@@ -259,7 +329,7 @@ net_driver_null_cycle (net_driver_t* driver, jack_nframes_t nframes)

tx_pkthdr->sync_state = (driver->engine->control->sync_remain <= 1);

tx_pkthdr->framecnt = framecnt;
tx_pkthdr->framecnt = driver->expected_framecnt;

// memset 0 the payload.
int payload_size = get_sample_size(driver->bitdepth) * driver->playback_channels * driver->net_period_up;
@@ -267,11 +337,15 @@ net_driver_null_cycle (net_driver_t* driver, jack_nframes_t nframes)

packet_header_hton(tx_pkthdr);
if (driver->srcaddress_valid)
if (driver->reply_port)
driver->syncsource_address.sin_port = htons(driver->reply_port);
{
int r;
if (driver->reply_port)
driver->syncsource_address.sin_port = htons(driver->reply_port);

netjack_sendto(driver->outsockfd, (char *)packet_buf, tx_size,
0, (struct sockaddr*)&driver->syncsource_address, sizeof(struct sockaddr_in), driver->mtu);
for( r=0; r<driver->redundancy; r++ )
netjack_sendto(driver->outsockfd, (char *)packet_buf, tx_size,
0, (struct sockaddr*)&(driver->syncsource_address), sizeof(struct sockaddr_in), driver->mtu);
}

return 0;
}
@@ -303,13 +377,6 @@ net_driver_read (net_driver_t* driver, jack_nframes_t nframes)

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

//packet_header_ntoh(pkthdr);
// fill framecnt from pkthdr.

//if (pkthdr->framecnt != framecnt + 1)
// jack_info("bogus framecount %d", pkthdr->framecnt);

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

@@ -383,24 +450,32 @@ net_driver_write (net_driver_t* driver, jack_nframes_t nframes)
packet_buf = alloca(packet_size);
pkthdr = (jacknet_packet_header *)packet_buf;

if( driver->running_free )
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);

pkthdr->sync_state = (driver->engine->control->sync_remain <= 1);
pkthdr->framecnt = framecnt;
pkthdr->latency = driver->time_to_deadline;
//printf( "time to deadline = %d goodness=%d\n", (int)driver->time_to_deadline, driver->deadline_goodness );
pkthdr->framecnt = driver->expected_framecnt;


render_jack_ports_to_payload(driver->bitdepth, driver->playback_ports, driver->playback_srcs, nframes, packet_bufX, driver->net_period_up);

packet_header_hton(pkthdr);
if (driver->srcaddress_valid)
{
int r;
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);
for( r=0; r<driver->redundancy; r++ )
netjack_sendto(driver->outsockfd, (char *)packet_buf, packet_size,
MSG_CONFIRM, (struct sockaddr*)&(driver->syncsource_address), sizeof(struct sockaddr_in), driver->mtu);
}

return 0;
}
@@ -556,7 +631,10 @@ net_driver_new (jack_client_t * client,
unsigned int transport_sync,
unsigned int resample_factor,
unsigned int resample_factor_up,
unsigned int bitdepth)
unsigned int bitdepth,
unsigned int use_autoconfig,
unsigned int latency,
unsigned int redundancy)
{
net_driver_t * driver;
int first_pack_len;
@@ -598,9 +676,15 @@ net_driver_new (jack_client_t * client,
driver->playback_ports = NULL;

driver->handle_transport_sync = transport_sync;
driver->mtu = 1400;
driver->latency = latency;
driver->redundancy = redundancy;


driver->client = client;
driver->engine = NULL;


if ((bitdepth != 0) && (bitdepth != 8) && (bitdepth != 16) && (bitdepth != 1000))
{
jack_info ("Invalid bitdepth: %d (8, 16 or 0 for float) !!!", bitdepth);
@@ -629,73 +713,74 @@ net_driver_new (jack_client_t * client,
}

driver->outsockfd = socket (PF_INET, SOCK_DGRAM, 0);
if (driver->sockfd == -1)
if (driver->outsockfd == -1)
{
jack_info ("socket error");
return NULL;
}
driver->srcaddress_valid = 0;

jacknet_packet_header *first_packet = alloca (sizeof (jacknet_packet_header));
socklen_t address_size = sizeof (struct sockaddr_in);
if (use_autoconfig)
{
jacknet_packet_header *first_packet = alloca (sizeof (jacknet_packet_header));
socklen_t address_size = sizeof (struct sockaddr_in);

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 !!!");
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
first_pack_len = 0;
// 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
first_pack_len = 0;

driver->srcaddress_valid = 1;
driver->srcaddress_valid = 1;

driver->mtu = 0;

if (first_pack_len == sizeof (jacknet_packet_header))
{
packet_header_ntoh (first_packet);
if (first_pack_len == sizeof (jacknet_packet_header))
{
packet_header_ntoh (first_packet);

jack_info ("AutoConfig Override !!!");
if (driver->sample_rate != first_packet->sample_rate)
{
jack_info ("AutoConfig Override: Master JACK sample rate = %d", first_packet->sample_rate);
driver->sample_rate = first_packet->sample_rate;
}
jack_info ("AutoConfig Override !!!");
if (driver->sample_rate != first_packet->sample_rate)
{
jack_info ("AutoConfig Override: Master JACK sample rate = %d", first_packet->sample_rate);
driver->sample_rate = first_packet->sample_rate;
}

if (driver->period_size != first_packet->period_size)
{
jack_info ("AutoConfig Override: Master JACK period size is %d", first_packet->period_size);
driver->period_size = first_packet->period_size;
}
if (driver->capture_channels_audio != first_packet->capture_channels_audio)
{
jack_info ("AutoConfig Override: capture_channels_audio = %d", first_packet->capture_channels_audio);
driver->capture_channels_audio = first_packet->capture_channels_audio;
}
if (driver->capture_channels_midi != first_packet->capture_channels_midi)
{
jack_info ("AutoConfig Override: capture_channels_midi = %d", first_packet->capture_channels_midi);
driver->capture_channels_midi = first_packet->capture_channels_midi;
}
if (driver->playback_channels_audio != first_packet->playback_channels_audio)
{
jack_info ("AutoConfig Override: playback_channels_audio = %d", first_packet->playback_channels_audio);
driver->playback_channels_audio = first_packet->playback_channels_audio;
}
if (driver->playback_channels_midi != first_packet->playback_channels_midi)
{
jack_info ("AutoConfig Override: playback_channels_midi = %d", first_packet->playback_channels_midi);
driver->playback_channels_midi = first_packet->playback_channels_midi;
}
driver->capture_channels = driver->capture_channels_audio + driver->capture_channels_midi;
driver->playback_channels = driver->playback_channels_audio + driver->playback_channels_midi;
if (driver->period_size != first_packet->period_size)
{
jack_info ("AutoConfig Override: Master JACK period size is %d", first_packet->period_size);
driver->period_size = first_packet->period_size;
}
if (driver->capture_channels_audio != first_packet->capture_channels_audio)
{
jack_info ("AutoConfig Override: capture_channels_audio = %d", first_packet->capture_channels_audio);
driver->capture_channels_audio = first_packet->capture_channels_audio;
}
if (driver->capture_channels_midi != first_packet->capture_channels_midi)
{
jack_info ("AutoConfig Override: capture_channels_midi = %d", first_packet->capture_channels_midi);
driver->capture_channels_midi = first_packet->capture_channels_midi;
}
if (driver->playback_channels_audio != first_packet->playback_channels_audio)
{
jack_info ("AutoConfig Override: playback_channels_audio = %d", first_packet->playback_channels_audio);
driver->playback_channels_audio = first_packet->playback_channels_audio;
}
if (driver->playback_channels_midi != first_packet->playback_channels_midi)
{
jack_info ("AutoConfig Override: playback_channels_midi = %d", first_packet->playback_channels_midi);
driver->playback_channels_midi = first_packet->playback_channels_midi;
}

driver->mtu = first_packet->mtu;
jack_info ("MTU is set to %d bytes", first_packet->mtu);
driver->latency = first_packet->latency;
driver->mtu = first_packet->mtu;
jack_info ("MTU is set to %d bytes", first_packet->mtu);
driver->latency = first_packet->latency;
}
}
driver->capture_channels = driver->capture_channels_audio + driver->capture_channels_midi;
driver->playback_channels = driver->playback_channels_audio + driver->playback_channels_midi;

// After possible Autoconfig: do all calculations...
driver->period_usecs =
@@ -720,6 +805,8 @@ net_driver_new (jack_client_t * client,
driver->expected_framecnt_valid = 0;
driver->num_lost_packets = 0;
driver->next_deadline_valid = 0;
driver->deadline_goodness = 0;
driver->time_to_deadline = 0;

// Special handling for latency=0
if( driver->latency == 0 )
@@ -748,7 +835,7 @@ driver_get_descriptor ()

desc = calloc (1, sizeof (jack_driver_desc_t));
strcpy (desc->name, "net");
desc->nparams = 12;
desc->nparams = 15;

params = calloc (desc->nparams, sizeof (jack_driver_param_desc_t));

@@ -844,8 +931,8 @@ driver_get_descriptor ()
strcpy (params[i].short_desc,
"Sample bit-depth (0 for float, 8 for 8bit and 16 for 16bit)");
strcpy (params[i].long_desc, params[i].short_desc);
i++;

i++;
strcpy (params[i].name, "transport-sync");
params[i].character = 't';
params[i].type = JackDriverParamUInt;
@@ -854,6 +941,33 @@ driver_get_descriptor ()
"Whether to slave the transport to the master transport");
strcpy (params[i].long_desc, params[i].short_desc);

i++;
strcpy (params[i].name, "autoconf");
params[i].character = 'a';
params[i].type = JackDriverParamUInt;
params[i].value.ui = 1U;
strcpy (params[i].short_desc,
"Whether to use Autoconfig, or just start.");
strcpy (params[i].long_desc, params[i].short_desc);

i++;
strcpy (params[i].name, "latency");
params[i].character = 'L';
params[i].type = JackDriverParamUInt;
params[i].value.ui = 5U;
strcpy (params[i].short_desc,
"Latency setting");
strcpy (params[i].long_desc, params[i].short_desc);

i++;
strcpy (params[i].name, "redundancy");
params[i].character = 'R';
params[i].type = JackDriverParamUInt;
params[i].value.ui = 1U;
strcpy (params[i].short_desc,
"Send packets N times");
strcpy (params[i].long_desc, params[i].short_desc);

desc->params = params;

return desc;
@@ -875,6 +989,9 @@ driver_initialize (jack_client_t *client, const JSList * params)
unsigned int resample_factor_up = 0;
unsigned int bitdepth = 0;
unsigned int handle_transport_sync = 1;
unsigned int use_autoconfig = 1;
unsigned int latency = 5;
unsigned int redundancy = 1;
const JSList * node;
const jack_driver_param_t * param;

@@ -936,6 +1053,18 @@ driver_initialize (jack_client_t *client, const JSList * params)
case 't':
handle_transport_sync = param->value.ui;
break;

case 'a':
use_autoconfig = param->value.ui;
break;

case 'L':
latency = param->value.ui;
break;

case 'R':
redundancy = param->value.ui;
break;
}
}

@@ -943,7 +1072,8 @@ driver_initialize (jack_client_t *client, const JSList * params)
capture_ports_midi, playback_ports_midi,
sample_rate, period_size,
listen_port, handle_transport_sync,
resample_factor, resample_factor_up, bitdepth);
resample_factor, resample_factor_up, bitdepth,
use_autoconfig, latency, redundancy);
}

void


+ 3
- 1
drivers/netjack/net_driver.h View File

@@ -76,6 +76,7 @@ struct _net_driver
//unsigned int tx_bufsize;
unsigned int mtu;
unsigned int latency;
unsigned int redundancy;

jack_nframes_t expected_framecnt;
int expected_framecnt_valid;
@@ -85,7 +86,8 @@ struct _net_driver
int packet_data_valid;
int resync_threshold;
int running_free;

int deadline_goodness;
jack_time_t time_to_deadline;
};

#endif /* __JACK_NET_DRIVER_H__ */

+ 111
- 6
drivers/netjack/netjack_packet.c View File

@@ -131,6 +131,7 @@ packet_cache

pcache->size = num_packets;
pcache->packets = malloc (sizeof (cache_packet) * num_packets);
pcache->master_address_valid = 0;
if (pcache->packets == NULL)
{
jack_error ("could not allocate packet cache (2)\n");
@@ -198,6 +199,7 @@ cache_packet
// Get The Oldest packet and reset it.

retval = packet_cache_get_oldest_packet (pcache);
//printf( "Dropping %d from Cache :S\n", retval->framecnt );
cache_packet_reset (retval);
cache_packet_set_framecnt (retval, framecnt);

@@ -468,25 +470,62 @@ packet_cache_drain_socket( packet_cache *pcache, int sockfd )
int rcv_len;
jack_nframes_t framecnt;
cache_packet *cpack;
struct sockaddr_in sender_address;
socklen_t senderlen;

while (1)
{
rcv_len = recv (sockfd, rx_packet, pcache->mtu, MSG_DONTWAIT);
rcv_len = recvfrom (sockfd, rx_packet, pcache->mtu, MSG_DONTWAIT,
&sender_address, &senderlen);
if (rcv_len < 0)
return;

if (pcache->master_address_valid) {
// Verify its from our master.
if (memcmp (&sender_address, &(pcache->master_address), senderlen) != 0)
continue;
} else {
// Setup this one as master
//printf( "setup master...\n" );
memcpy ( &(pcache->master_address), &sender_address, senderlen );
pcache->master_address_valid = 1;
}

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);
cpack->recv_timestamp = jack_get_microseconds();
}
}

void
packet_cache_reset_master_address( packet_cache *pcache )
{
pcache->master_address_valid = 0;
}

void
packet_cache_clear_old_packets (packet_cache *pcache, jack_nframes_t framecnt )
{
int i;

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

int
packet_cache_retreive_packet( packet_cache *pcache, jack_nframes_t framecnt, char *packet_buf, int pkt_size )
packet_cache_retreive_packet( packet_cache *pcache, jack_nframes_t framecnt, char *packet_buf, int pkt_size, jack_time_t *timestamp )
{
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]);
@@ -494,18 +533,43 @@ packet_cache_retreive_packet( packet_cache *pcache, jack_nframes_t framecnt, cha
}
}

if( cpack == NULL )
if( cpack == NULL ) {
//printf( "retreive packet: %d....not found\n", framecnt );
return -1;
}

if( !cache_packet_is_complete( cpack ) )
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);
if( timestamp )
*timestamp = cpack->recv_timestamp;

cache_packet_reset (cpack);
packet_cache_clear_old_packets( pcache, framecnt );
return pkt_size;
}

float
packet_cache_get_fill( packet_cache *pcache, jack_nframes_t expected_framecnt )
{
int num_packets_before_us = 0;
int i;

for (i = 0; i < pcache->size; i++)
{
cache_packet *cpack = &(pcache->packets[i]);
if (cpack->valid && cache_packet_is_complete( cpack ))
if( cpack->framecnt >= expected_framecnt )
num_packets_before_us += 1;
}

return 100.0 * (float)num_packets_before_us / (float)( pcache->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 )
@@ -540,6 +604,37 @@ packet_cache_get_next_available_framecnt( packet_cache *pcache, jack_nframes_t e
return retval;
}

int
packet_cache_get_highest_available_framecnt( packet_cache *pcache, jack_nframes_t *framecnt )
{
int i;
jack_nframes_t best_value = 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 < best_value) {
continue;
}

best_value = cpack->framecnt;
retval = 1;

}
if( retval && framecnt )
*framecnt = best_value;

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 )
@@ -636,12 +731,18 @@ 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) {
int err;
pkthdr = (jacknet_packet_header *) packet_buf;
pkthdr->fragment_nr = htonl (0);
sendto(sockfd, packet_buf, pkt_size, flags, addr, addr_size);
err = sendto(sockfd, packet_buf, pkt_size, flags, addr, addr_size);
if( err<0 ) {
printf( "error in send\n" );
perror( "send" );
}
}
else
{
int err;
// Copy the packet header to the tx pack first.
memcpy(tx_packet, packet_buf, sizeof (jacknet_packet_header));

@@ -663,6 +764,10 @@ netjack_sendto (int sockfd, char *packet_buf, int pkt_size, int flags, struct so

// sendto(last_pack_size);
sendto(sockfd, tx_packet, last_payload_size + sizeof(jacknet_packet_header), flags, addr, addr_size);
if( err<0 ) {
printf( "error in send\n" );
perror( "send" );
}
}
}

@@ -1201,7 +1306,7 @@ render_jack_ports_to_payload_celt (JSList *playback_ports, JSList *playback_srcs
CELTEncoder *encoder = src_node->data;
encoded_bytes = celt_encode_float( encoder, floatbuf, NULL, packet_bufX, net_period_up );
if( encoded_bytes != net_period_up )
printf( "bah... they are not the same\n" );
printf( "something in celt changed. netjack needs to be changed to handle this.\n" );
src_node = jack_slist_next( src_node );
}
else if (strncmp(portname, JACK_DEFAULT_MIDI_TYPE, jack_port_type_size()) == 0)


+ 8
- 2
drivers/netjack/netjack_packet.h View File

@@ -56,8 +56,8 @@ struct _jacknet_packet_header
// Packet loss Detection, and latency reduction
jack_nframes_t framecnt;
jack_nframes_t latency;
jack_nframes_t reply_port;

jack_nframes_t reply_port;
jack_nframes_t mtu;
jack_nframes_t fragment_nr;
};
@@ -79,6 +79,7 @@ struct _cache_packet
int num_fragments;
int packet_size;
int mtu;
jack_time_t recv_timestamp;
jack_nframes_t framecnt;
char * fragment_array;
char * packet_buf;
@@ -91,6 +92,8 @@ struct _packet_cache
int size;
cache_packet *packets;
int mtu;
struct sockaddr_in master_address;
int master_address_valid;
};

extern packet_cache *global_packcache;
@@ -110,8 +113,11 @@ void cache_packet_add_fragment(cache_packet *pack, char *packet_buf, int rcv_len
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 );
void packet_cache_reset_master_address( packet_cache *pcache );
float packet_cache_get_fill( packet_cache *pcache, jack_nframes_t expected_framecnt );
int packet_cache_retreive_packet( packet_cache *pcache, jack_nframes_t framecnt, char *packet_buf, int pkt_size, jack_time_t *timestamp );
int packet_cache_get_next_available_framecnt( packet_cache *pcache, jack_nframes_t expected_framecnt, jack_nframes_t *framecnt );
int packet_cache_get_highest_available_framecnt( packet_cache *pcache, jack_nframes_t *framecnt );
int packet_cache_find_latency( packet_cache *pcache, jack_nframes_t expected_framecnt, jack_nframes_t *framecnt );
// Function Prototypes



+ 58
- 26
tools/netsource.c View File

@@ -55,6 +55,8 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
#include <celt/celt.h>
#endif

#include <math.h>

JSList *capture_ports = NULL;
JSList *capture_srcs = NULL;
int capture_channels = 0;
@@ -71,12 +73,14 @@ jack_nframes_t factor = 1;
int bitdepth = 0;
int mtu = 1400;
int reply_port = 0;
int redundancy = 1;
jack_client_t *client;

int state_connected = 0;
int state_latency = 0;
int state_netxruns = 0;
int state_currentframe = 0;
int state_recv_packet_queue_time = 0;


int outsockfd;
@@ -203,6 +207,7 @@ sync_cb (jack_transport_state_t state, jack_position_t *pos, void *arg)
return retval;
}

int deadline_goodness=0;
/**
* The process callback for this JACK application.
* It is called by JACK at the appropriate times.
@@ -211,14 +216,7 @@ int
process (jack_nframes_t nframes, void *arg)
{
jack_nframes_t net_period;

if( bitdepth == 1000 )
net_period = factor;
else
net_period = (float) nframes / (float) factor;

int rx_bufsize = get_sample_size (bitdepth) * capture_channels * net_period + sizeof (jacknet_packet_header);
int tx_bufsize = get_sample_size (bitdepth) * playback_channels * net_period + sizeof (jacknet_packet_header);
int rx_bufsize, tx_bufsize;

jack_default_audio_sample_t *buf;
jack_port_t *port;
@@ -231,6 +229,16 @@ process (jack_nframes_t nframes, void *arg)
jack_position_t local_trans_pos;

uint32_t *packet_buf, *packet_bufX;
jack_time_t packet_recv_timestamp;

if( bitdepth == 1000 )
net_period = factor;
else
net_period = (float) nframes / (float) factor;

rx_bufsize = get_sample_size (bitdepth) * capture_channels * net_period + sizeof (jacknet_packet_header);
tx_bufsize = get_sample_size (bitdepth) * playback_channels * net_period + sizeof (jacknet_packet_header);


/* Allocate a buffer where both In and Out Buffer will fit */
packet_buf = alloca ((rx_bufsize > tx_bufsize) ? rx_bufsize : tx_bufsize);
@@ -265,13 +273,19 @@ process (jack_nframes_t nframes, void *arg)
pkthdr->capture_channels_midi = playback_channels_midi;
pkthdr->playback_channels_midi = capture_channels_midi;
pkthdr->mtu = mtu;
pkthdr->sync_state = (jack_nframes_t)deadline_goodness;
//printf("goodness=%d\n", deadline_goodness );
packet_header_hton (pkthdr);
if (cont_miss < 2*latency+5)
netjack_sendto (outsockfd, (char *) packet_buf, tx_bufsize, 0, &destaddr, sizeof (destaddr), mtu);
if (cont_miss < 3*latency+5) {
int r;
for( r=0; r<redundancy; r++ )
netjack_sendto (outsockfd, (char *) packet_buf, tx_bufsize, 0, &destaddr, sizeof (destaddr), mtu);
}
else if (cont_miss > 50+5*latency)
{
state_connected = 0;
packet_cache_reset_master_address( global_packcache );
//printf ("Frame %d \tRealy too many packets missed (%d). Let's reset the counter\n", framecnt, cont_miss);
cont_miss = 5;
}
@@ -299,7 +313,7 @@ process (jack_nframes_t nframes, void *arg)

packet_cache_drain_socket(global_packcache, input_fd);

if (packet_cache_get_next_available_framecnt( global_packcache, framecnt, NULL ))
if (packet_cache_get_next_available_framecnt( global_packcache, framecnt - latency, NULL ))
break;
}
} else {
@@ -308,12 +322,18 @@ process (jack_nframes_t nframes, void *arg)
packet_cache_drain_socket(global_packcache, input_fd);
}

size = packet_cache_retreive_packet( global_packcache, framecnt - latency, (char *)packet_buf, rx_bufsize );

size = packet_cache_retreive_packet( global_packcache, framecnt - latency, (char *)packet_buf, rx_bufsize, &packet_recv_timestamp );
/* First alternative : we received what we expected. Render the data
* to the JACK ports so it can be played. */
if (size == rx_bufsize)
{
// calculate how much time there would have been, if this packet was sent at the deadline.

int recv_time_offset = (int) (jack_get_microseconds() - packet_recv_timestamp);
packet_header_ntoh (pkthdr);
deadline_goodness = recv_time_offset - (int)pkthdr->latency;
//printf( "deadline goodness = %d ---> off: %d\n", deadline_goodness, recv_time_offset );

if (cont_miss)
{
//printf("Frame %d \tRecovered from dropouts\n", framecnt);
@@ -322,6 +342,7 @@ process (jack_nframes_t nframes, void *arg)
render_payload_to_jack_ports (bitdepth, packet_bufX, net_period, capture_ports, capture_srcs, nframes);

state_currentframe = framecnt;
state_recv_packet_queue_time = recv_time_offset;
state_connected = 1;
sync_state = pkthdr->sync_state;
}
@@ -332,7 +353,7 @@ process (jack_nframes_t nframes, void *arg)
{
jack_nframes_t latency_estimate;
if( packet_cache_find_latency( global_packcache, framecnt, &latency_estimate ) )
if( (state_latency == 0) || (latency_estimate < state_latency) )
//if( (state_latency == 0) || (latency_estimate < state_latency) )
state_latency = latency_estimate;

// Set the counters up.
@@ -411,6 +432,7 @@ fprintf (stderr, "usage: jack_netsource -h <host peer> [options]\n"
" -b <bitdepth> - Set transport to use 16bit or 8bit\n"
" -m <mtu> - Assume this mtu for the link\n"
" -c <bytes> - Use Celt and encode <bytes> per channel and packet.\n"
" -R <N> - Send out packets N times.\n"
"\n");
}

@@ -426,7 +448,7 @@ main (int argc, char *argv[])
/* Torben's famous state variables, aka "the reporting API" ! */
/* heh ? these are only the copies of them ;) */
int statecopy_connected, statecopy_latency, statecopy_netxruns;
jack_nframes_t net_period;
/* Argument parsing stuff */
extern char *optarg;
extern int optind, optopt;
@@ -438,28 +460,28 @@ main (int argc, char *argv[])
return 1;
}
client_name = (char *) malloc (sizeof (char) * 9);
peer_ip = (char *) malloc (sizeof (char) * 9);
client_name = (char *) malloc (sizeof (char) * 10);
peer_ip = (char *) malloc (sizeof (char) * 10);
sprintf(client_name, "netsource");
sprintf(peer_ip, "localhost");

while ((c = getopt (argc, argv, ":n:s:h:p:C:P:i:o:l:r:f:b:m:c:")) != -1)
while ((c = getopt (argc, argv, ":R:n:s:h:p:C:P:i:o:l:r:f:b:m:c:")) != -1)
{
switch (c)
{
case 'n':
free(client_name);
client_name = (char *) malloc (sizeof (char) * strlen (optarg));
client_name = (char *) malloc (sizeof (char) * strlen (optarg)+1);
strcpy (client_name, optarg);
break;
case 's':
server_name = (char *) malloc (sizeof (char) * strlen (optarg));
server_name = (char *) malloc (sizeof (char) * strlen (optarg)+1);
strcpy (server_name, optarg);
options |= JackServerName;
break;
case 'h':
free(peer_ip);
peer_ip = (char *) malloc (sizeof (char) * strlen (optarg));
peer_ip = (char *) malloc (sizeof (char) * strlen (optarg)+1);
strcpy (peer_ip, optarg);
break;
case 'p':
@@ -501,6 +523,9 @@ main (int argc, char *argv[])
case 'm':
mtu = atoi (optarg);
break;
case 'R':
redundancy = atoi (optarg);
break;
case ':':
fprintf (stderr, "Option -%c requires an operand\n", optopt);
errflg++;
@@ -544,9 +569,13 @@ main (int argc, char *argv[])

alloc_ports (capture_channels_audio, playback_channels_audio, capture_channels_midi, playback_channels_midi);

jack_nframes_t net_period = (float) jack_get_buffer_size (client) / (float) factor;
if( bitdepth == 1000 )
net_period = factor;
else
net_period = ceilf((float) jack_get_buffer_size (client) / (float) factor);

int rx_bufsize = get_sample_size (bitdepth) * capture_channels * net_period + sizeof (jacknet_packet_header);
global_packcache = packet_cache_new (latency + 5, rx_bufsize, mtu);
global_packcache = packet_cache_new (latency + 50, rx_bufsize, mtu);

/* tell the JACK server that we are ready to roll */
if (jack_activate (client))
@@ -578,11 +607,14 @@ main (int argc, char *argv[])
fflush(stdout);
}

if (statecopy_connected)
{
if (statecopy_connected)
{
if (statecopy_netxruns != state_netxruns) {
statecopy_netxruns = state_netxruns;
printf ("at frame %06d -> total netxruns %d\n", state_currentframe, statecopy_netxruns);
printf ("at frame %06d -> total netxruns %d (%d%%) queue time= %d\n", state_currentframe,
statecopy_netxruns,
100*statecopy_netxruns/state_currentframe,
state_recv_packet_queue_time);
fflush(stdout);
}
}


Loading…
Cancel
Save