Browse Source

add opus support to NetJack2

tags/1.9.9.5
Robin Gareus 13 years ago
parent
commit
33bef4fcb0
9 changed files with 300 additions and 5 deletions
  1. +13
    -0
      common/JackNetAdapter.cpp
  2. +15
    -2
      common/JackNetDriver.cpp
  3. +1
    -1
      common/JackNetDriver.h
  4. +4
    -0
      common/JackNetInterface.cpp
  5. +211
    -0
      common/JackNetTool.cpp
  6. +45
    -0
      common/JackNetTool.h
  7. +1
    -0
      common/jack/net.h
  8. +2
    -2
      common/wscript
  9. +8
    -0
      wscript

+ 13
- 0
common/JackNetAdapter.cpp View File

@@ -101,6 +101,14 @@ namespace Jack
fParams.fKBps = param->value.i;
}
break;
#endif
#if HAVE_OPUS
case 'O':
if (param->value.i > 0) {
fParams.fSampleEncoder = JackOpusEncoder;
fParams.fKBps = param->value.i;
}
break;
#endif
case 'l' :
fParams.fNetworkLatency = param->value.i;
@@ -421,6 +429,11 @@ extern "C"
jack_driver_descriptor_add_parameter(desc, &filler, "celt", 'c', JackDriverParamInt, &value, NULL, "Set CELT encoding and number of kBits per channel", NULL);
#endif

#if HAVE_OPUS
value.i = -1;
jack_driver_descriptor_add_parameter(desc, &filler, "opus", 'O', JackDriverParamInt, &value, NULL, "Set Opus encoding and number of kBits per channel", NULL);
#endif

strcpy(value.str, "'hostname'");
jack_driver_descriptor_add_parameter(desc, &filler, "client-name", 'n', JackDriverParamString, &value, NULL, "Name of the jack client", NULL);



+ 15
- 2
common/JackNetDriver.cpp View File

@@ -29,7 +29,7 @@ namespace Jack
{
JackNetDriver::JackNetDriver(const char* name, const char* alias, JackLockedEngine* engine, JackSynchro* table,
const char* ip, int udp_port, int mtu, int midi_input_ports, int midi_output_ports,
char* net_name, uint transport_sync, int network_latency, int celt_encoding)
char* net_name, uint transport_sync, int network_latency, int celt_encoding, int opus_encoding)
: JackWaiterDriver(name, alias, engine, table), JackNetSlaveInterface(ip, udp_port)
{
jack_log("JackNetDriver::JackNetDriver ip %s, port %d", ip, udp_port);
@@ -45,6 +45,9 @@ namespace Jack
if (celt_encoding > 0) {
fParams.fSampleEncoder = JackCeltEncoder;
fParams.fKBps = celt_encoding;
} else if (opus_encoding > 0) {
fParams.fSampleEncoder = JackOpusEncoder;
fParams.fKBps = opus_encoding;
} else {
fParams.fSampleEncoder = JackFloatEncoder;
//fParams.fSampleEncoder = JackIntEncoder;
@@ -619,6 +622,10 @@ namespace Jack
#if HAVE_CELT
value.i = -1;
jack_driver_descriptor_add_parameter(desc, &filler, "celt", 'c', JackDriverParamInt, &value, NULL, "Set CELT encoding and number of kBits per channel", NULL);
#endif
#if HAVE_OPUS
value.i = -1;
jack_driver_descriptor_add_parameter(desc, &filler, "opus", 'O', JackDriverParamInt, &value, NULL, "Set Opus encoding and number of kBits per channel", NULL);
#endif
strcpy(value.str, "'hostname'");
jack_driver_descriptor_add_parameter(desc, &filler, "client-name", 'n', JackDriverParamString, &value, NULL, "Name of the jack client", NULL);
@@ -650,6 +657,7 @@ Deactivated for now..
int midi_input_ports = 0;
int midi_output_ports = 0;
int celt_encoding = -1;
int opus_encoding = -1;
bool monitor = false;
int network_latency = 5;
const JSList* node;
@@ -699,6 +707,11 @@ Deactivated for now..
celt_encoding = param->value.i;
break;
#endif
#if HAVE_OPUS
case 'O':
opus_encoding = param->value.i;
break;
#endif
case 'n' :
strncpy(net_name, param->value.str, JACK_CLIENT_NAME_SIZE);
break;
@@ -724,7 +737,7 @@ Deactivated for now..
new Jack::JackNetDriver("system", "net_pcm", engine, table, multicast_ip, udp_port, mtu,
midi_input_ports, midi_output_ports,
net_name, transport_sync,
network_latency, celt_encoding));
network_latency, celt_encoding, opus_encoding));
if (driver->Open(period_size, sample_rate, 1, 1, audio_capture_ports, audio_playback_ports, monitor, "from_master_", "to_master_", 0, 0) == 0) {
return driver;
} else {


+ 1
- 1
common/JackNetDriver.h View File

@@ -69,7 +69,7 @@ namespace Jack

JackNetDriver(const char* name, const char* alias, JackLockedEngine* engine, JackSynchro* table,
const char* ip, int port, int mtu, int midi_input_ports, int midi_output_ports,
char* net_name, uint transport_sync, int network_latency, int celt_encoding);
char* net_name, uint transport_sync, int network_latency, int celt_encoding, int opus_encoding);
virtual ~JackNetDriver();

int Close();


+ 4
- 0
common/JackNetInterface.cpp View File

@@ -243,6 +243,10 @@ namespace Jack
case JackCeltEncoder:
return new NetCeltAudioBuffer(&fParams, nports, buffer, fParams.fKBps);
#endif
#if HAVE_OPUS
case JackOpusEncoder:
return new NetOpusAudioBuffer(&fParams, nports, buffer, fParams.fKBps);
#endif
}
return NULL;
}


+ 211
- 0
common/JackNetTool.cpp View File

@@ -709,6 +709,210 @@ namespace Jack

#endif

#if HAVE_OPUS

NetOpusAudioBuffer::NetOpusAudioBuffer(session_params_t* params, uint32_t nports, char* net_buffer, int kbps)
:NetAudioBuffer(params, nports, net_buffer)
{
fOpusMode = new OpusCustomMode *[fNPorts];
fOpusEncoder = new OpusCustomEncoder *[fNPorts];
fOpusDecoder = new OpusCustomDecoder *[fNPorts];

memset(fOpusMode, 0, fNPorts * sizeof(OpusCustomMode*));
memset(fOpusEncoder, 0, fNPorts * sizeof(OpusCustomEncoder*));
memset(fOpusDecoder, 0, fNPorts * sizeof(OpusCustomDecoder*));

int error = OPUS_OK;

for (int i = 0; i < fNPorts; i++) {
/* Allocate en/decoders */
fOpusMode[i] = opus_custom_mode_create(
params->fSampleRate, params->fPeriodSize, &error);
if (error != OPUS_OK) {
goto error;
}

fOpusEncoder[i] = opus_custom_encoder_create(fOpusMode[i], 1,&error);
if (error != OPUS_OK) {
goto error;
}

fOpusDecoder[i] = opus_custom_decoder_create(fOpusMode[i], 1, &error);
if (error != OPUS_OK) {
goto error;
}

opus_custom_encoder_ctl(fOpusEncoder[i], OPUS_SET_BITRATE(kbps*1024)); // bits per second
opus_custom_encoder_ctl(fOpusEncoder[i], OPUS_SET_COMPLEXITY(10));
opus_custom_encoder_ctl(fOpusEncoder[i], OPUS_SET_SIGNAL(OPUS_SIGNAL_MUSIC));
opus_custom_encoder_ctl(fOpusEncoder[i], OPUS_SET_SIGNAL(OPUS_APPLICATION_RESTRICTED_LOWDELAY));

/* initilize decoders */
error = opus_custom_encoder_init(fOpusEncoder[i], fOpusMode[i], 1);
error = opus_custom_decoder_init(fOpusDecoder[i], fOpusMode[i], 1);
}

{
fPeriodSize = params->fPeriodSize;
fCompressedSizeByte = (kbps * params->fPeriodSize * 1024) / (params->fSampleRate * 8);
jack_log("NetOpusAudioBuffer fCompressedSizeByte %d", fCompressedSizeByte);

fCompressedBuffer = new unsigned char* [fNPorts];
for (int port_index = 0; port_index < fNPorts; port_index++) {
fCompressedBuffer[port_index] = new unsigned char[fCompressedSizeByte];
memset(fCompressedBuffer[port_index], 0, fCompressedSizeByte * sizeof(char));
}

int res1 = (fNPorts * fCompressedSizeByte) % PACKET_AVAILABLE_SIZE(params);
int res2 = (fNPorts * fCompressedSizeByte) / PACKET_AVAILABLE_SIZE(params);

fNumPackets = (res1) ? (res2 + 1) : res2;

jack_log("NetOpusAudioBuffer res1 = %d res2 = %d", res1, res2);

fSubPeriodBytesSize = fCompressedSizeByte / fNumPackets;
fLastSubPeriodBytesSize = fSubPeriodBytesSize + fCompressedSizeByte % fNumPackets;

jack_log("NetOpusAudioBuffer fNumPackets = %d fSubPeriodBytesSize = %d, fLastSubPeriodBytesSize = %d", fNumPackets, fSubPeriodBytesSize, fLastSubPeriodBytesSize);

fCycleDuration = float(fSubPeriodBytesSize / sizeof(sample_t)) / float(params->fSampleRate);
fCycleBytesSize = params->fMtu * fNumPackets;

fLastSubCycle = -1;
return;
}

error:

FreeOpus();
throw std::bad_alloc();
}

NetOpusAudioBuffer::~NetOpusAudioBuffer()
{
FreeOpus();

for (int port_index = 0; port_index < fNPorts; port_index++) {
delete [] fCompressedBuffer[port_index];
}

delete [] fCompressedBuffer;
}

void NetOpusAudioBuffer::FreeOpus()
{
for (int i = 0; i < fNPorts; i++) {
if (fOpusEncoder[i]) {
opus_custom_encoder_destroy(fOpusEncoder[i]);
fOpusEncoder[i]=0;
}
if (fOpusDecoder[i]) {
opus_custom_decoder_destroy(fOpusDecoder[i]);
fOpusDecoder[i]=0;
}
if (fOpusMode[i]) {
opus_custom_mode_destroy(fOpusMode[i]);
fOpusMode[i]=0;
}
}

delete [] fOpusEncoder;
delete [] fOpusDecoder;
delete [] fOpusMode;
}

size_t NetOpusAudioBuffer::GetCycleSize()
{
return fCycleBytesSize;
}

float NetOpusAudioBuffer::GetCycleDuration()
{
return fCycleDuration;
}

int NetOpusAudioBuffer::GetNumPackets(int active_ports)
{
return fNumPackets;
}

int NetOpusAudioBuffer::RenderFromJackPorts()
{
float buffer[BUFFER_SIZE_MAX];

for (int port_index = 0; port_index < fNPorts; port_index++) {
if (fPortBuffer[port_index]) {
memcpy(buffer, fPortBuffer[port_index], fPeriodSize * sizeof(sample_t));
} else {
memset(buffer, 0, fPeriodSize * sizeof(sample_t));
}
int res = opus_custom_encode_float(fOpusEncoder[port_index], buffer, fPeriodSize, fCompressedBuffer[port_index], fCompressedSizeByte);
if (res != fCompressedSizeByte) {
jack_error("opus_encode_float error fCompressedSizeByte = %d res = %d", fCompressedSizeByte, res);
}
}

// All ports active
return fNPorts;
}

void NetOpusAudioBuffer::RenderToJackPorts()
{
for (int port_index = 0; port_index < fNPorts; port_index++) {
if (fPortBuffer[port_index]) {
int res = opus_custom_decode_float(fOpusDecoder[port_index], fCompressedBuffer[port_index], fCompressedSizeByte, fPortBuffer[port_index], fPeriodSize);
if (res != OPUS_OK) {
jack_error("opus_decode_float error fCompressedSizeByte = %d res = %d", fCompressedSizeByte, res);
}
}
}

NextCycle();
}

//network<->buffer
int NetOpusAudioBuffer::RenderFromNetwork(int cycle, int sub_cycle, uint32_t port_num)
{
// Cleanup all JACK ports at the beginning of the cycle
if (sub_cycle == 0) {
Cleanup();
}

if (port_num > 0) {
// Last packet of the cycle
if (sub_cycle == fNumPackets - 1) {
for (int port_index = 0; port_index < fNPorts; port_index++) {
memcpy(fCompressedBuffer[port_index] + sub_cycle * fSubPeriodBytesSize, fNetBuffer + port_index * fLastSubPeriodBytesSize, fLastSubPeriodBytesSize);
}
} else {
for (int port_index = 0; port_index < fNPorts; port_index++) {
memcpy(fCompressedBuffer[port_index] + sub_cycle * fSubPeriodBytesSize, fNetBuffer + port_index * fSubPeriodBytesSize, fSubPeriodBytesSize);
}
}
}

return CheckPacket(cycle, sub_cycle);
}

int NetOpusAudioBuffer::RenderToNetwork(int sub_cycle, uint32_t port_num)
{
// Last packet of the cycle
if (sub_cycle == fNumPackets - 1) {
for (int port_index = 0; port_index < fNPorts; port_index++) {
memcpy(fNetBuffer + port_index * fLastSubPeriodBytesSize, fCompressedBuffer[port_index] + sub_cycle * fSubPeriodBytesSize, fLastSubPeriodBytesSize);
}
return fNPorts * fLastSubPeriodBytesSize;
} else {
for (int port_index = 0; port_index < fNPorts; port_index++) {
memcpy(fNetBuffer + port_index * fSubPeriodBytesSize, fCompressedBuffer[port_index] + sub_cycle * fSubPeriodBytesSize, fSubPeriodBytesSize);
}
return fNPorts * fSubPeriodBytesSize;
}
}

#endif


NetIntAudioBuffer::NetIntAudioBuffer(session_params_t* params, uint32_t nports, char* net_buffer)
: NetAudioBuffer(params, nports, net_buffer)
{
@@ -891,6 +1095,9 @@ namespace Jack
case JackCeltEncoder:
strcpy(encoder, "CELT");
break;
case JackOpusEncoder:
strcpy(encoder, "OPUS");
break;
}

jack_info("**************** Network parameters ****************");
@@ -917,6 +1124,10 @@ namespace Jack
jack_info("SampleEncoder : %s", "CELT");
jack_info("kBits : %d", params->fKBps);
break;
case (JackOpusEncoder):
jack_info("SampleEncoder : %s", "OPUS");
jack_info("kBits : %d", params->fKBps);
break;
};
jack_info("Slave mode : %s", (params->fSlaveSyncMode) ? "sync" : "async");
jack_info("****************************************************");


+ 45
- 0
common/JackNetTool.h View File

@@ -62,6 +62,7 @@ namespace Jack
JackFloatEncoder = 0,
JackIntEncoder = 1,
JackCeltEncoder = 2,
JackOpusEncoder = 3,
};

//session params ******************************************************************************
@@ -403,6 +404,50 @@ namespace Jack
int RenderToNetwork(int sub_cycle, uint32_t port_num);
};

#endif

#if HAVE_OPUS

#include <opus/opus.h>
#include <opus/opus_custom.h>

class SERVER_EXPORT NetOpusAudioBuffer : public NetAudioBuffer
{
private:

OpusCustomMode** fOpusMode;
OpusCustomEncoder** fOpusEncoder;
OpusCustomDecoder** fOpusDecoder;

int fCompressedSizeByte;
int fNumPackets;

size_t fLastSubPeriodBytesSize;

unsigned char** fCompressedBuffer;
void FreeOpus();

public:

NetOpusAudioBuffer(session_params_t* params, uint32_t nports, char* net_buffer, int kbps);
virtual ~NetOpusAudioBuffer();

// needed size in bytes for an entire cycle
size_t GetCycleSize();

// cycle duration in sec
float GetCycleDuration();
int GetNumPackets(int active_ports);

//jack<->buffer
int RenderFromJackPorts();
void RenderToJackPorts();

//network<->buffer
int RenderFromNetwork(int cycle, int sub_cycle, uint32_t port_num);
int RenderToNetwork(int sub_cycle, uint32_t port_num);
};

#endif

class SERVER_EXPORT NetIntAudioBuffer : public NetAudioBuffer


+ 1
- 0
common/jack/net.h View File

@@ -40,6 +40,7 @@ enum JackNetEncoder {
JackFloatEncoder = 0, // samples are transmitted as float
JackIntEncoder = 1, // samples are transmitted as 16 bits integer
JackCeltEncoder = 2, // samples are transmitted using CELT codec (http://www.celt-codec.org/)
JackOpusEncoder = 2, // samples are transmitted using OPUS codec (http://www.opus-codec.org/)
};

typedef struct {


+ 2
- 2
common/wscript View File

@@ -68,7 +68,7 @@ def build(bld):
]

includes = ['.', './jack', '..']
uselib = ["PTHREAD", "CELT"]
uselib = ["PTHREAD", "CELT", "OPUS"]

if bld.env['IS_LINUX']:
common_libsources += [
@@ -193,7 +193,7 @@ def build(bld):
netlib.includes = includes
netlib.name = 'netlib'
netlib.target = 'jacknet'
netlib.use = ['SAMPLERATE', 'CELT', 'PTHREAD' , 'RT']
netlib.use = ['SAMPLERATE', 'CELT', 'OPUS', 'PTHREAD' , 'RT']
netlib.install_path = '${LIBDIR}'
netlib.source = [
'JackNetAPI.cpp',


+ 8
- 0
wscript View File

@@ -173,6 +173,13 @@ def configure(conf):
conf.define('HAVE_CELT_API_0_7', 0)
conf.define('HAVE_CELT_API_0_5', 0)

conf.env['WITH_OPUS'] = False
if conf.check_cfg(package='opus', atleast_version='0.9.0' , args='--cflags --libs', mandatory=False):
if conf.check_cc(header_name='opus/opus_custom.h', mandatory=False):
conf.define('HAVE_OPUS', 1)
conf.env['WITH_OPUS'] = True


conf.env['LIB_PTHREAD'] = ['pthread']
conf.env['LIB_DL'] = ['dl']
conf.env['LIB_RT'] = ['rt']
@@ -264,6 +271,7 @@ def configure(conf):
display_msg('C++ compiler flags', repr(conf.env['CXXFLAGS']))
display_msg('Linker flags', repr(conf.env['LINKFLAGS']))
display_feature('Build doxygen documentation', conf.env['BUILD_DOXYGEN_DOCS'])
display_feature('Build Opus netjack2', conf.env['WITH_OPUS'])
display_feature('Build with engine profiling', conf.env['BUILD_WITH_PROFILE'])
display_feature('Build with 32/64 bits mixed mode', conf.env['BUILD_WITH_32_64'])



Loading…
Cancel
Save