Browse Source

Pure Add netone driver

tags/v1.9.4
Torben Hohn 16 years ago
parent
commit
38f5f4f7f2
6 changed files with 3732 additions and 0 deletions
  1. +1117
    -0
      common/JackNetOneDriver.cpp
  2. +95
    -0
      common/JackNetOneDriver.h
  3. +687
    -0
      common/netjack.c
  4. +144
    -0
      common/netjack.h
  5. +1527
    -0
      common/netjack_packet.c
  6. +162
    -0
      common/netjack_packet.h

+ 1117
- 0
common/JackNetOneDriver.cpp
File diff suppressed because it is too large
View File


+ 95
- 0
common/JackNetOneDriver.h View File

@@ -0,0 +1,95 @@
/*
Copyright (C) 2001 Paul Davis
Copyright (C) 2008 Romain Moret at Grame

This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.

*/

#ifndef __JackNetDriver__
#define __JackNetDriver__

#include "JackAudioDriver.h"
#include "netjack.h"

namespace Jack
{
/**
\Brief This class describes the Net Backend
*/

class JackNetOneDriver : public JackAudioDriver
{
private:
netjack_driver_state_t netj;

void
render_payload_to_jack_ports_float ( void *packet_payload, jack_nframes_t net_period_down, JSList *capture_ports, JSList *capture_srcs, jack_nframes_t nframes, int dont_htonl_floats);
void
render_jack_ports_to_payload_float (JSList *playback_ports, JSList *playback_srcs, jack_nframes_t nframes, void *packet_payload, jack_nframes_t net_period_up, int dont_htonl_floats );
#ifdef HAVE_CELT
void
render_payload_to_jack_ports_celt (void *packet_payload, jack_nframes_t net_period_down, JSList *capture_ports, JSList *capture_srcs, jack_nframes_t nframes);
void
render_jack_ports_to_payload_celt (JSList *playback_ports, JSList *playback_srcs, jack_nframes_t nframes, void *packet_payload, jack_nframes_t net_period_up);
#endif
void
render_payload_to_jack_ports (int bitdepth, void *packet_payload, jack_nframes_t net_period_down, JSList *capture_ports, JSList *capture_srcs, jack_nframes_t nframes, int dont_htonl_floats);
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, int dont_htonl_floats);

public:
JackNetOneDriver ( const char* name, const char* alias, JackLockedEngine* engine, JackSynchro* table,
int port, int mtu, int capture_ports, int playback_ports, int midi_input_ports, int midi_output_ports,
int sample_rate, int period_size, int resample_factor,
char* net_name, uint transport_sync, int bitdepth, int use_autoconfig,
int latency, int redundancy, int dont_htonl_floats, int always_deadline );
~JackNetOneDriver();

int Open ( jack_nframes_t frames_per_cycle, jack_nframes_t rate, bool capturing, bool playing,
int inchannels, int outchannels, bool monitor, const char* capture_driver_name,
const char* playback_driver_name, jack_nframes_t capture_latency, jack_nframes_t playback_latency );

int Close();
int Attach();
int Detach();

int Read();
int Write();

bool Initialize();
int AllocPorts();
void FreePorts();

// BufferSize can't be changed
bool IsFixedBufferSize()
{
return true;
}

int SetBufferSize ( jack_nframes_t buffer_size )
{
return -1;
}

int SetSampleRate ( jack_nframes_t sample_rate )
{
return -1;
}

};
}

#endif

+ 687
- 0
common/netjack.c View File

@@ -0,0 +1,687 @@

/* -*- mode: c; c-file-style: "linux"; -*- */
/*
NetJack Abstraction.

Copyright (C) 2008 Pieter Palmers <pieterpalmers@users.sourceforge.net>
Copyright (C) 2006 Torben Hohn <torbenh@gmx.de>
Copyright (C) 2003 Robert Ham <rah@bash.sh>
Copyright (C) 2001 Paul Davis

This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.

$Id: net_driver.c,v 1.17 2006/04/16 20:16:10 torbenh Exp $
*/

#define HAVE_CELT 1


#include <math.h>
#include <stdio.h>
#include <memory.h>
#include <unistd.h>
#include <stdlib.h>
#include <errno.h>
#include <stdarg.h>

#include <jack/types.h>
#include "jack/jslist.h"

#include <sys/types.h>

#ifdef WIN32
#include <winsock.h>
#include <malloc.h>
#else
#include <sys/socket.h>
#include <netinet/in.h>
#endif

#include "netjack.h"

//#include "config.h"
#if HAVE_SAMPLERATE
#include <samplerate.h>
#endif

#if HAVE_CELT
#include <celt/celt.h>
#endif

#include "netjack.h"
#include "netjack_packet.h"

// JACK2
#include "jack/control.h"

#define MIN(x,y) ((x)<(y) ? (x) : (y))

static int sync_state = 1;
static jack_transport_state_t last_transport_state;

static int
net_driver_sync_cb(jack_transport_state_t state, jack_position_t *pos, void *data)
{
int retval = sync_state;

if (state == JackTransportStarting && last_transport_state != JackTransportStarting) {
retval = 0;
}
// if (state == JackTransportStarting)
// jack_info("Starting sync_state = %d", sync_state);
last_transport_state = state;
return retval;
}

void netjack_wait( netjack_driver_state_t *netj )
{
int we_have_the_expected_frame = 0;
jack_nframes_t next_frame_avail;
jack_time_t packet_recv_time_stamp;
jacknet_packet_header *pkthdr;

if( !netj->next_deadline_valid ) {
if( netj->latency == 0 )
// for full sync mode... always wait for packet.
netj->next_deadline = jack_get_time() + 50*netj->period_usecs;
else if( netj->latency == 1 )
// for normal 1 period latency mode, only 1 period for dealine.
netj->next_deadline = jack_get_time() + 110 * netj->period_usecs /100;
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.
//netj->next_deadline = jack_get_time() + 5*netj->latency*netj->period_usecs/4;
netj->next_deadline = jack_get_time() + netj->period_usecs + 10*netj->latency*netj->period_usecs/100;

netj->next_deadline_valid = 1;
} else {
netj->next_deadline += netj->period_usecs;
}

// Increment expected frame here.

netj->expected_framecnt += 1;

//jack_log( "expect %d", netj->expected_framecnt );
// 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, netj->expected_framecnt, &next_frame_avail) ) {
if( next_frame_avail == netj->expected_framecnt ) {
we_have_the_expected_frame = 1;
if( !netj->always_deadline )
break;
}
}
if( ! netjack_poll_deadline( netj->sockfd, netj->next_deadline ) ) {
break;
}

packet_cache_drain_socket( global_packcache, netj->sockfd );
}

// check if we know who to send our packets too.
if (!netj->srcaddress_valid)
if( global_packcache->master_address_valid ) {
memcpy (&(netj->syncsource_address), &(global_packcache->master_address), sizeof( struct sockaddr_in ) );
netj->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...
netj->running_free = 0;

if( !we_have_the_expected_frame )
jack_log( "xrun... %d", netj->expected_framecnt );

if( we_have_the_expected_frame ) {
netj->time_to_deadline = netj->next_deadline - jack_get_time() - netj->period_usecs;
packet_cache_retreive_packet_pointer( global_packcache, netj->expected_framecnt, (char **) &(netj->rx_buf), netj->rx_bufsize , &packet_recv_time_stamp);
pkthdr = (jacknet_packet_header *) netj->rx_buf;
packet_header_ntoh(pkthdr);
netj->deadline_goodness = (int)pkthdr->sync_state;
netj->packet_data_valid = 1;

// 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 < netj->period_usecs )
//netj->next_deadline -= netj->period_usecs*netj->latency/100;
netj->next_deadline += netj->period_usecs/1000;
*/

if( netj->deadline_goodness < (netj->period_usecs/4+10*(int)netj->period_usecs*netj->latency/100) ) {
netj->next_deadline += netj->period_usecs/100;
//jack_log( "goodness: %d, Adjust deadline: --- %d\n", netj->deadline_goodness, (int) netj->period_usecs*netj->latency/100 );
}
if( netj->deadline_goodness > (netj->period_usecs/4+10*(int)netj->period_usecs*netj->latency/100) ) {
netj->next_deadline -= netj->period_usecs/100;
//jack_log( "goodness: %d, Adjust deadline: +++ %d\n", netj->deadline_goodness, (int) netj->period_usecs*netj->latency/100 );
}
} else {
netj->time_to_deadline = 0;
// 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, netj->expected_framecnt, &next_frame_avail) )
{
jack_nframes_t offset = next_frame_avail - netj->expected_framecnt;

//XXX: hmm... i need to remember why resync_threshold wasnt right.
//if( offset < netj->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.

netj->packet_data_valid = 0;

// 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, netj->expected_framecnt ) > 80.0 )
netj->next_deadline -= netj->period_usecs/2;


} else {
// the diff is too high. but we have a packet in the future.
// lets resync.
netj->expected_framecnt = next_frame_avail;
packet_cache_retreive_packet_pointer( global_packcache, netj->expected_framecnt, (char **) &(netj->rx_buf), netj->rx_bufsize, NULL );
pkthdr = (jacknet_packet_header *) netj->rx_buf;
packet_header_ntoh(pkthdr);
//netj->deadline_goodness = 0;
netj->deadline_goodness = (int)pkthdr->sync_state - (int)netj->period_usecs * offset;
netj->next_deadline_valid = 0;
netj->packet_data_valid = 1;
}

} else {
// no packets in buffer.
netj->packet_data_valid = 0;

//printf( "frame %d No Packet in queue. num_lost_packets = %d \n", netj->expected_framecnt, netj->num_lost_packets );
if( netj->num_lost_packets < 5 ) {
// ok. No Packet in queue. The packet was either lost,
// or we are running too fast.
//
// Adjusting the deadline unconditionally resulted in
// too many xruns on master.
// But we need to adjust for the case we are running too fast.
// So lets check if the last packet is there now.
//
// It would not be in the queue anymore, if it had been
// retrieved. This might break for redundancy, but
// i will make the packet cache drop redundant packets,
// that have already been retreived.
//
if( packet_cache_get_highest_available_framecnt( global_packcache, &next_frame_avail) ) {
if( next_frame_avail == (netj->expected_framecnt - 1) ) {
// Ok. the last packet is there now.
// and it had not been retrieved.
//
// TODO: We are still dropping 2 packets.
// perhaps we can adjust the deadline
// when (num_packets lost == 0)

// This might still be too much.
netj->next_deadline += netj->period_usecs;
}
}
} else if( (netj->num_lost_packets <= 100) ) {
// lets try adjusting the deadline harder, for some packets, we might have just ran 2 fast.
netj->next_deadline += netj->period_usecs*netj->latency/8;
} else {

// But now we can check for any new frame available.
//
if( packet_cache_get_highest_available_framecnt( global_packcache, &next_frame_avail) ) {
netj->expected_framecnt = next_frame_avail;
packet_cache_retreive_packet_pointer( global_packcache, netj->expected_framecnt, (char **) &(netj->rx_buf), netj->rx_bufsize, NULL );
pkthdr = (jacknet_packet_header *) netj->rx_buf;
packet_header_ntoh(pkthdr);
netj->deadline_goodness = pkthdr->sync_state;
netj->next_deadline_valid = 0;
netj->packet_data_valid = 1;
netj->running_free = 0;
jack_info( "resync after freerun... %d\n", netj->expected_framecnt );
} else {
// give up. lets run freely.
// XXX: hmm...

netj->running_free = 1;

// 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 (netj->num_lost_packets > 200 ) {
netj->srcaddress_valid = 0;
packet_cache_reset_master_address( global_packcache );
}
}
}
}
}

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

void netjack_send_silence( netjack_driver_state_t *netj, int syncstate )
{
int tx_size = get_sample_size(netj->bitdepth) * netj->playback_channels * netj->net_period_up + sizeof(jacknet_packet_header);
unsigned int *packet_buf, *packet_bufX;

packet_buf = alloca( tx_size);
jacknet_packet_header *tx_pkthdr = (jacknet_packet_header *)packet_buf;
jacknet_packet_header *rx_pkthdr = (jacknet_packet_header *)netj->rx_buf;

//framecnt = rx_pkthdr->framecnt;

netj->reply_port = rx_pkthdr->reply_port;

// offset packet_bufX by the packetheader.
packet_bufX = packet_buf + sizeof(jacknet_packet_header) / sizeof(jack_default_audio_sample_t);

tx_pkthdr->sync_state = syncstate;
tx_pkthdr->framecnt = netj->expected_framecnt;

// memset 0 the payload.
int payload_size = get_sample_size(netj->bitdepth) * netj->playback_channels * netj->net_period_up;
memset(packet_bufX, 0, payload_size);

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

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


void netjack_attach( netjack_driver_state_t *netj )
{
//puts ("net_driver_attach");
jack_port_t * port;
char buf[32];
unsigned int chn;
int port_flags;


if (netj->handle_transport_sync)
jack_set_sync_callback(netj->client, (JackSyncCallback) net_driver_sync_cb, NULL);

port_flags = JackPortIsOutput | JackPortIsPhysical | JackPortIsTerminal;

for (chn = 0; chn < netj->capture_channels_audio; chn++) {
snprintf (buf, sizeof(buf) - 1, "capture_%u", chn + 1);

port = jack_port_register (netj->client, buf,
JACK_DEFAULT_AUDIO_TYPE,
port_flags, 0);
if (!port) {
jack_error ("NET: cannot register port for %s", buf);
break;
}

netj->capture_ports =
jack_slist_append (netj->capture_ports, port);

if( netj->bitdepth == 1000 ) {
#if HAVE_CELT
celt_int32_t lookahead;
// XXX: memory leak
CELTMode *celt_mode = celt_mode_create( netj->sample_rate, 1, netj->period_size, NULL );
celt_mode_info( celt_mode, CELT_GET_LOOKAHEAD, &lookahead );
netj->codec_latency = 2*lookahead;

netj->capture_srcs = jack_slist_append(netj->capture_srcs, celt_decoder_create( celt_mode ) );
#endif
} else {
#if HAVE_SAMPLERATE
netj->capture_srcs = jack_slist_append(netj->capture_srcs, src_new(SRC_LINEAR, 1, NULL));
#endif
}
}
for (chn = netj->capture_channels_audio; chn < netj->capture_channels; chn++) {
snprintf (buf, sizeof(buf) - 1, "capture_%u", chn + 1);

port = jack_port_register (netj->client, buf,
JACK_DEFAULT_MIDI_TYPE,
port_flags, 0);
if (!port) {
jack_error ("NET: cannot register port for %s", buf);
break;
}

netj->capture_ports =
jack_slist_append (netj->capture_ports, port);
}

port_flags = JackPortIsInput | JackPortIsPhysical | JackPortIsTerminal;

for (chn = 0; chn < netj->playback_channels_audio; chn++) {
snprintf (buf, sizeof(buf) - 1, "playback_%u", chn + 1);

port = jack_port_register (netj->client, buf,
JACK_DEFAULT_AUDIO_TYPE,
port_flags, 0);

if (!port) {
jack_error ("NET: cannot register port for %s", buf);
break;
}

netj->playback_ports =
jack_slist_append (netj->playback_ports, port);
if( netj->bitdepth == 1000 ) {
#if HAVE_CELT
// XXX: memory leak
CELTMode *celt_mode = celt_mode_create( netj->sample_rate, 1, netj->period_size, NULL );
netj->playback_srcs = jack_slist_append(netj->playback_srcs, celt_encoder_create( celt_mode ) );
#endif
} else {
#if HAVE_SAMPLERATE
netj->playback_srcs = jack_slist_append(netj->playback_srcs, src_new(SRC_LINEAR, 1, NULL));
#endif
}
}
for (chn = netj->playback_channels_audio; chn < netj->playback_channels; chn++) {
snprintf (buf, sizeof(buf) - 1, "playback_%u", chn + 1);

port = jack_port_register (netj->client, buf,
JACK_DEFAULT_MIDI_TYPE,
port_flags, 0);

if (!port) {
jack_error ("NET: cannot register port for %s", buf);
break;
}

netj->playback_ports =
jack_slist_append (netj->playback_ports, port);
}

jack_activate (netj->client);
}


void netjack_detach( netjack_driver_state_t *netj )
{
JSList * node;


for (node = netj->capture_ports; node; node = jack_slist_next (node))
jack_port_unregister (netj->client,
((jack_port_t *) node->data));

jack_slist_free (netj->capture_ports);
netj->capture_ports = NULL;

for (node = netj->playback_ports; node; node = jack_slist_next (node))
jack_port_unregister (netj->client,
((jack_port_t *) node->data));

jack_slist_free (netj->playback_ports);
netj->playback_ports = NULL;
}


netjack_driver_state_t *netjack_init (netjack_driver_state_t *netj,
jack_client_t * client,
const char *name,
unsigned int capture_ports,
unsigned int playback_ports,
unsigned int capture_ports_midi,
unsigned int playback_ports_midi,
jack_nframes_t sample_rate,
jack_nframes_t period_size,
unsigned int listen_port,
unsigned int transport_sync,
unsigned int resample_factor,
unsigned int resample_factor_up,
unsigned int bitdepth,
unsigned int use_autoconfig,
unsigned int latency,
unsigned int redundancy,
int dont_htonl_floats,
int always_deadline)
{

// Fill in netj values.
// might be subject to autoconfig...
// so dont calculate anything with them...


netj->sample_rate = sample_rate;
netj->period_size = period_size;
netj->dont_htonl_floats = dont_htonl_floats;

netj->listen_port = listen_port;

netj->capture_channels = capture_ports + capture_ports_midi;
netj->capture_channels_audio = capture_ports;
netj->capture_channels_midi = capture_ports_midi;
netj->capture_ports = NULL;
netj->playback_channels = playback_ports + playback_ports_midi;
netj->playback_channels_audio = playback_ports;
netj->playback_channels_midi = playback_ports_midi;
netj->playback_ports = NULL;
netj->codec_latency = 0;

netj->handle_transport_sync = transport_sync;
netj->mtu = 1400;
netj->latency = latency;
netj->redundancy = redundancy;
netj->use_autoconfig = use_autoconfig;
netj->always_deadline = always_deadline;


netj->client = client;


if ((bitdepth != 0) && (bitdepth != 8) && (bitdepth != 16) && (bitdepth != 1000))
{
jack_info ("Invalid bitdepth: %d (8, 16 or 0 for float) !!!", bitdepth);
return NULL;
}
netj->bitdepth = bitdepth;


if (resample_factor_up == 0)
resample_factor_up = resample_factor;

netj->resample_factor = resample_factor;
netj->resample_factor_up = resample_factor_up;


return netj;
}

void netjack_release( netjack_driver_state_t *netj )
{
close( netj->sockfd );
close( netj->outsockfd );

packet_cache_free( global_packcache );
global_packcache = NULL;
}

int
netjack_startup( netjack_driver_state_t *netj )
{
int first_pack_len;
struct sockaddr_in address;
// Now open the socket, and wait for the first packet to arrive...
netj->sockfd = socket (AF_INET, SOCK_DGRAM, 0);
#ifdef WIN32
if (netj->sockfd == INVALID_SOCKET)
#else
if (netj->sockfd == -1)
#endif
{
jack_info ("socket error");
return -1;
}
address.sin_family = AF_INET;
address.sin_port = htons(netj->listen_port);
address.sin_addr.s_addr = htonl(INADDR_ANY);
if (bind (netj->sockfd, (struct sockaddr *) &address, sizeof (address)) < 0)
{
jack_info("bind error");
return -1;
}

netj->outsockfd = socket (AF_INET, SOCK_DGRAM, 0);
#ifdef WIN32
if (netj->outsockfd == INVALID_SOCKET)
#else
if (netj->outsockfd == -1)
#endif
{
jack_info ("socket error");
return -1;
}
netj->srcaddress_valid = 0;
if (netj->use_autoconfig)
{
jacknet_packet_header *first_packet = alloca (sizeof (jacknet_packet_header));
#ifdef WIN32
int address_size = sizeof( struct sockaddr_in );
#else
socklen_t address_size = sizeof (struct sockaddr_in);
#endif
//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 !!!");

while(1) {
first_pack_len = recvfrom (netj->sockfd, (char *)first_packet, sizeof (jacknet_packet_header), 0, (struct sockaddr*) & netj->syncsource_address, &address_size);
#ifdef WIN32
if( first_pack_len == -1 ) {
first_pack_len = sizeof(jacknet_packet_header);
break;
}
#else
if (first_pack_len == sizeof (jacknet_packet_header))
break;
#endif
}
netj->srcaddress_valid = 1;

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

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

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

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

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

if( netj->bitdepth == 1000 ) {
// celt mode.
// TODO: this is a hack. But i dont want to change the packet header.
netj->net_period_down = netj->resample_factor;
netj->net_period_up = netj->resample_factor_up;
} else {
netj->net_period_down = (float) netj->period_size / (float) netj->resample_factor;
netj->net_period_up = (float) netj->period_size / (float) netj->resample_factor_up;
}

netj->rx_bufsize = sizeof (jacknet_packet_header) + netj->net_period_down * netj->capture_channels * get_sample_size (netj->bitdepth);
netj->pkt_buf = malloc (netj->rx_bufsize);
global_packcache = packet_cache_new (netj->latency + 50, netj->rx_bufsize, netj->mtu);

netj->expected_framecnt_valid = 0;
netj->num_lost_packets = 0;
netj->next_deadline_valid = 0;
netj->deadline_goodness = 0;
netj->time_to_deadline = 0;

// Special handling for latency=0
if( netj->latency == 0 )
netj->resync_threshold = 0;
else
netj->resync_threshold = MIN( 15, netj->latency-1 );

netj->running_free = 0;

return 0;
}

+ 144
- 0
common/netjack.h View File

@@ -0,0 +1,144 @@

/*
Copyright (C) 2003 Robert Ham <rah@bash.sh>
Copyright (C) 2005 Torben Hohn <torbenh@gmx.de>

This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/

#ifndef __NETJACK_H__
#define __NETJACK_H__

#include <unistd.h>

#include <jack/types.h>
//#include <jack/driver.h>
#include <jack/jack.h>
#include <jack/transport.h>

#include "jack/jslist.h"

//#include <netinet/in.h>

#ifdef __cplusplus
extern "C"
{
#endif

typedef struct _netjack_driver_state netjack_driver_state_t;

struct _netjack_driver_state {
jack_nframes_t net_period_up;
jack_nframes_t net_period_down;

jack_nframes_t sample_rate;
jack_nframes_t bitdepth;
jack_nframes_t period_size;
jack_time_t period_usecs;
int dont_htonl_floats;
int always_deadline;

jack_nframes_t codec_latency;

unsigned int listen_port;

unsigned int capture_channels;
unsigned int playback_channels;
unsigned int capture_channels_audio;
unsigned int playback_channels_audio;
unsigned int capture_channels_midi;
unsigned int playback_channels_midi;

JSList *capture_ports;
JSList *playback_ports;
JSList *playback_srcs;
JSList *capture_srcs;

jack_client_t *client;

#ifdef WIN32
SOCKET sockfd;
SOCKET outsockfd;
#else
int sockfd;
int outsockfd;
#endif

struct sockaddr_in syncsource_address;

int reply_port;
int srcaddress_valid;

int sync_state;
unsigned int handle_transport_sync;

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

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;
int deadline_goodness;
jack_time_t time_to_deadline;
unsigned int use_autoconfig;
unsigned int resample_factor;
unsigned int resample_factor_up;
};

void netjack_wait( netjack_driver_state_t *netj );
void netjack_send_silence( netjack_driver_state_t *netj, int syncstate );
void netjack_read( netjack_driver_state_t *netj, jack_nframes_t nframes ) ;
void netjack_write( netjack_driver_state_t *netj, jack_nframes_t nframes, int syncstate );
void netjack_attach( netjack_driver_state_t *netj );
void netjack_detach( netjack_driver_state_t *netj );

netjack_driver_state_t *netjack_init (netjack_driver_state_t *netj,
jack_client_t * client,
const char *name,
unsigned int capture_ports,
unsigned int playback_ports,
unsigned int capture_ports_midi,
unsigned int playback_ports_midi,
jack_nframes_t sample_rate,
jack_nframes_t period_size,
unsigned int listen_port,
unsigned int transport_sync,
unsigned int resample_factor,
unsigned int resample_factor_up,
unsigned int bitdepth,
unsigned int use_autoconfig,
unsigned int latency,
unsigned int redundancy,
int dont_htonl_floats,
int always_deadline);

void netjack_release( netjack_driver_state_t *netj );
int netjack_startup( netjack_driver_state_t *netj );

#ifdef __cplusplus
}
#endif

#endif

+ 1527
- 0
common/netjack_packet.c
File diff suppressed because it is too large
View File


+ 162
- 0
common/netjack_packet.h View File

@@ -0,0 +1,162 @@

/*
* NetJack - Packet Handling functions
*
* used by the driver and the jacknet_client
*
* Copyright (C) 2006 Torben Hohn <torbenh@gmx.de>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Id: net_driver.c,v 1.16 2006/03/20 19:41:37 torbenh Exp $
*
*/

#ifndef __JACK_NET_PACKET_H__
#define __JACK_NET_PACKET_H__

#ifdef __cplusplus
extern "C"
{
#endif

#include <jack/jack.h>
#include <jack/types.h>
//#include <jack/engine.h>
#include <jack/jslist.h>

#include <jack/midiport.h>

//#include <netinet/in.h>
// The Packet Header.

typedef struct _jacknet_packet_header jacknet_packet_header;

struct _jacknet_packet_header
{
// General AutoConf Data
jack_nframes_t capture_channels_audio;
jack_nframes_t playback_channels_audio;
jack_nframes_t capture_channels_midi;
jack_nframes_t playback_channels_midi;
jack_nframes_t period_size;
jack_nframes_t sample_rate;

// Transport Sync
jack_nframes_t sync_state;
jack_nframes_t transport_frame;
jack_nframes_t transport_state;

// Packet loss Detection, and latency reduction
jack_nframes_t framecnt;
jack_nframes_t latency;

jack_nframes_t reply_port;
jack_nframes_t mtu;
jack_nframes_t fragment_nr;
};

typedef union _int_float int_float_t;

union _int_float
{
uint32_t i;
float f;
};

// fragment reorder cache.
typedef struct _cache_packet cache_packet;

struct _cache_packet
{
int valid;
int num_fragments;
int packet_size;
int mtu;
jack_time_t recv_timestamp;
jack_nframes_t framecnt;
char * fragment_array;
char * packet_buf;
};

typedef struct _packet_cache packet_cache;

struct _packet_cache
{
int size;
cache_packet *packets;
int mtu;
struct sockaddr_in master_address;
int master_address_valid;
jack_nframes_t last_framecnt_retreived;
int last_framecnt_retreived_valid;
};

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);

cache_packet *packet_cache_get_packet(packet_cache *pkt_cache, jack_nframes_t framecnt);
cache_packet *packet_cache_get_oldest_packet(packet_cache *pkt_cache);
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);

void packet_cache_drain_socket( packet_cache *pcache, int sockfd );
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_pointer( packet_cache *pcache, jack_nframes_t framecnt, char **packet_buf, int pkt_size, jack_time_t *timestamp );
int packet_cache_release_packet( packet_cache *pcache, jack_nframes_t framecnt );
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

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 get_sample_size(int bitdepth);
void packet_header_hton(jacknet_packet_header *pkthdr);

void packet_header_ntoh(jacknet_packet_header *pkthdr);

void render_payload_to_jack_ports(int bitdepth, void *packet_payload, jack_nframes_t net_period_down, JSList *capture_ports, JSList *capture_srcs, jack_nframes_t nframes, int dont_htonl_floats );

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, int dont_htonl_floats );


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

void decode_midi_buffer (uint32_t *buffer_uint32, unsigned int buffer_size_uint32, jack_default_audio_sample_t* buf);
void encode_midi_buffer (uint32_t *buffer_uint32, unsigned int buffer_size_uint32, jack_default_audio_sample_t* buf);
#ifdef __cplusplus
}
#endif
#endif


Loading…
Cancel
Save