Skip to content

Commit

Permalink
Merge pull request #16 from x42/master
Browse files Browse the repository at this point in the history
Opus Netjack integration
  • Loading branch information
sletz committed Sep 10, 2012
2 parents ee845d4 + ce83a13 commit d3d4945
Show file tree
Hide file tree
Showing 12 changed files with 429 additions and 33 deletions.
7 changes: 6 additions & 1 deletion common/JackNetAPI.cpp
Expand Up @@ -37,7 +37,7 @@ extern "C"
JackFloatEncoder = 0,
JackIntEncoder = 1,
JackCeltEncoder = 2,
JackMaxEncoder = 3
JackOpusEncoder = 3
};

typedef struct {
Expand Down Expand Up @@ -551,6 +551,11 @@ struct JackNetExtSlave : public JackNetSlaveInterface, public JackRunnableInterf
return -1;
}

if ((fParams.fSampleEncoder == JackOpusEncoder) && (fParams.fKBps == 0)) {
jack_error("Opus encoder with 0 for kps...");
return -1;
}

// Check latency
if (fParams.fNetworkLatency > NETWORK_MAX_LATENCY) {
jack_error("Error : network latency is limited to %d", NETWORK_MAX_LATENCY);
Expand Down
167 changes: 167 additions & 0 deletions common/JackNetOneDriver.cpp
Expand Up @@ -39,6 +39,11 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
#include <celt/celt.h>
#endif

#if HAVE_OPUS
#include <opus/opus.h>
#include <opus/opus_custom.h>
#endif

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

using namespace std;
Expand Down Expand Up @@ -146,6 +151,13 @@ int JackNetOneDriver::AllocPorts()
#endif
celt_mode_info(celt_mode, CELT_GET_LOOKAHEAD, &lookahead);
netj.codec_latency = 2 * lookahead;
#endif
} else if (netj.bitdepth == OPUS_MODE) {
#if HAVE_OPUS
OpusCustomMode *opus_mode = opus_custom_mode_create(netj.sample_rate, netj.period_size, NULL); // XXX free me in the end
OpusCustomDecoder *decoder = opus_custom_decoder_create( opus_mode, 1, NULL );
opus_custom_decoder_init(decoder, opus_mode, 1);
netj.capture_srcs = jack_slist_append(netj.capture_srcs, decoder);
#endif
} else {
#if HAVE_SAMPLERATE
Expand Down Expand Up @@ -191,6 +203,22 @@ int JackNetOneDriver::AllocPorts()
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
#endif
} else if (netj.bitdepth == OPUS_MODE) {
#if HAVE_OPUS
const int kbps = netj.resample_factor;
jack_error("NEW ONE OPUS ENCODER 128 <> %d!!", kbps);
int err;
OpusCustomMode *opus_mode = opus_custom_mode_create( netj.sample_rate, netj.period_size, &err ); // XXX free me in the end
if (err != OPUS_OK) { jack_error("opus mode failed"); }
OpusCustomEncoder *oe = opus_custom_encoder_create( opus_mode, 1, &err );
if (err != OPUS_OK) { jack_error("opus mode failed"); }
opus_custom_encoder_ctl(oe, OPUS_SET_BITRATE(kbps*1024)); // bits per second
opus_custom_encoder_ctl(oe, OPUS_SET_COMPLEXITY(10));
opus_custom_encoder_ctl(oe, OPUS_SET_SIGNAL(OPUS_SIGNAL_MUSIC));
opus_custom_encoder_ctl(oe, OPUS_SET_SIGNAL(OPUS_APPLICATION_RESTRICTED_LOWDELAY));
opus_custom_encoder_init(oe, opus_mode, 1);
netj.playback_srcs = jack_slist_append(netj.playback_srcs, oe);
#endif
} else {
#if HAVE_SAMPLERATE
Expand Down Expand Up @@ -450,6 +478,28 @@ JackNetOneDriver::FreePorts ()
celt_decoder_destroy(dec);
}
netj.capture_srcs = NULL;
#endif
} else if (netj.bitdepth == OPUS_MODE) {
#if HAVE_OPUS
node = netj.playback_srcs;
while (node != NULL) {
JSList *this_node = node;
OpusCustomEncoder *enc = (OpusCustomEncoder *) node->data;
node = jack_slist_remove_link(node, this_node);
jack_slist_free_1(this_node);
opus_custom_encoder_destroy(enc);
}
netj.playback_srcs = NULL;

node = netj.capture_srcs;
while (node != NULL) {
JSList *this_node = node;
OpusCustomDecoder *dec = (OpusCustomDecoder *) node->data;
node = jack_slist_remove_link(node, this_node);
jack_slist_free_1(this_node);
opus_custom_decoder_destroy(dec);
}
netj.capture_srcs = NULL;
#endif
} else {
#if HAVE_SAMPLERATE
Expand Down Expand Up @@ -724,6 +774,98 @@ JackNetOneDriver::render_jack_ports_to_payload_celt (JSList *playback_ports, JSL
}

#endif

#if HAVE_OPUS
#define CDO (sizeof(short)) ///< compressed data offset (first 2 bytes are length)
// render functions for Opus.
void
JackNetOneDriver::render_payload_to_jack_ports_opus (void *packet_payload, jack_nframes_t net_period_down, JSList *capture_ports, JSList *capture_srcs, jack_nframes_t nframes)
{
int chn = 0;
JSList *node = capture_ports;
JSList *src_node = capture_srcs;

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

while (node != NULL) {
jack_port_id_t port_index = (jack_port_id_t) (intptr_t)node->data;
JackPort *port = fGraphManager->GetPort(port_index);

jack_default_audio_sample_t* buf =
(jack_default_audio_sample_t*)fGraphManager->GetBuffer(port_index, fEngineControl->fBufferSize);

const char *portname = port->GetType();

if (strncmp(portname, JACK_DEFAULT_AUDIO_TYPE, jack_port_type_size()) == 0) {
// audio port, decode opus data.
OpusCustomDecoder *decoder = (OpusCustomDecoder*) src_node->data;
if( !packet_payload )
memset(buf, 0, nframes * sizeof(float));
else {
unsigned short len;
memcpy(&len, packet_bufX, CDO);
len = ntohs(len);
opus_custom_decode_float( decoder, packet_bufX + CDO, len, buf, nframes );
}

src_node = jack_slist_next (src_node);
} else if (strncmp(portname, JACK_DEFAULT_MIDI_TYPE, jack_port_type_size()) == 0) {
// midi port, decode midi events
// 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;
if( packet_payload )
decode_midi_buffer (buffer_uint32, buffer_size_uint32, buf);
}
packet_bufX = (packet_bufX + net_period_down);
node = jack_slist_next (node);
chn++;
}
}

void
JackNetOneDriver::render_jack_ports_to_payload_opus (JSList *playback_ports, JSList *playback_srcs, jack_nframes_t nframes, void *packet_payload, jack_nframes_t net_period_up)
{
int chn = 0;
JSList *node = playback_ports;
JSList *src_node = playback_srcs;

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

while (node != NULL) {
jack_port_id_t port_index = (jack_port_id_t) (intptr_t) node->data;
JackPort *port = fGraphManager->GetPort(port_index);

jack_default_audio_sample_t* buf =
(jack_default_audio_sample_t*)fGraphManager->GetBuffer(port_index, fEngineControl->fBufferSize);

const char *portname = port->GetType();

if (strncmp (portname, JACK_DEFAULT_AUDIO_TYPE, jack_port_type_size()) == 0) {
// audio port, encode opus data.

int encoded_bytes;
jack_default_audio_sample_t *floatbuf = (jack_default_audio_sample_t *)alloca (sizeof(jack_default_audio_sample_t) * nframes);
memcpy(floatbuf, buf, nframes * sizeof(jack_default_audio_sample_t));
OpusCustomEncoder *encoder = (OpusCustomEncoder*) src_node->data;
encoded_bytes = opus_custom_encode_float( encoder, floatbuf, nframes, packet_bufX + CDO, net_period_up - CDO );
unsigned short len = htons(encoded_bytes);
memcpy(packet_bufX, &len, CDO);
src_node = jack_slist_next( src_node );
} else if (strncmp(portname, JACK_DEFAULT_MIDI_TYPE, jack_port_type_size()) == 0) {
// encode midi events from port to packet
// convert the data buffer to a standard format (uint32_t based)
unsigned int buffer_size_uint32 = net_period_up / 2;
uint32_t * buffer_uint32 = (uint32_t*) packet_bufX;
encode_midi_buffer (buffer_uint32, buffer_size_uint32, buf);
}
packet_bufX = (packet_bufX + net_period_up);
node = jack_slist_next (node);
chn++;
}
}
#endif

/* Wrapper functions with bitdepth argument... */
void
JackNetOneDriver::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)
Expand All @@ -732,6 +874,11 @@ JackNetOneDriver::render_payload_to_jack_ports (int bitdepth, void *packet_paylo
if (bitdepth == CELT_MODE)
render_payload_to_jack_ports_celt (packet_payload, net_period_down, capture_ports, capture_srcs, nframes);
else
#endif
#if HAVE_OPUS
if (bitdepth == OPUS_MODE)
render_payload_to_jack_ports_opus (packet_payload, net_period_down, capture_ports, capture_srcs, nframes);
else
#endif
render_payload_to_jack_ports_float (packet_payload, net_period_down, capture_ports, capture_srcs, nframes, dont_htonl_floats);
}
Expand All @@ -743,6 +890,11 @@ JackNetOneDriver::render_jack_ports_to_payload (int bitdepth, JSList *playback_p
if (bitdepth == CELT_MODE)
render_jack_ports_to_payload_celt (playback_ports, playback_srcs, nframes, packet_payload, net_period_up);
else
#endif
#if HAVE_OPUS
if (bitdepth == OPUS_MODE)
render_jack_ports_to_payload_opus (playback_ports, playback_srcs, nframes, packet_payload, net_period_up);
else
#endif
render_jack_ports_to_payload_float (playback_ports, playback_srcs, nframes, packet_payload, net_period_up, dont_htonl_floats);
}
Expand Down Expand Up @@ -791,6 +943,10 @@ extern "C"
#if HAVE_CELT
value.ui = 0U;
jack_driver_descriptor_add_parameter(desc, &filler, "celt", 'c', JackDriverParamUInt, &value, NULL, "Set CELT encoding and number of kbits per channel", NULL);
#endif
#if HAVE_OPUS
value.ui = 0U;
jack_driver_descriptor_add_parameter(desc, &filler, "opus", 'P', JackDriverParamUInt, &value, NULL, "Set Opus encoding and number of kbits per channel", NULL);
#endif
value.ui = 0U;
jack_driver_descriptor_add_parameter(desc, &filler, "bit-depth", 'b', JackDriverParamUInt, &value, NULL, "Sample bit-depth (0 for float, 8 for 8bit and 16 for 16bit)", NULL);
Expand Down Expand Up @@ -904,6 +1060,17 @@ extern "C"
#endif
break;

case 'P':
#if HAVE_OPUS
bitdepth = OPUS_MODE;
resample_factor = param->value.ui;
jack_error("OPUS: %d\n", resample_factor);
#else
jack_error("not built with Opus support");
return NULL;
#endif
break;

case 't':
handle_transport_sync = param->value.ui;
break;
Expand Down
6 changes: 6 additions & 0 deletions common/JackNetOneDriver.h
Expand Up @@ -45,6 +45,12 @@ class JackNetOneDriver : public JackWaiterDriver
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
#if HAVE_OPUS
void
render_payload_to_jack_ports_opus(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_opus(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);
Expand Down

0 comments on commit d3d4945

Please sign in to comment.