| @@ -0,0 +1,268 @@ | |||
| /* | |||
| Copyright (C) 2008-2011 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. | |||
| */ | |||
| #include "JackNetCelt.h" | |||
| #include "JackError.h" | |||
| namespace Jack | |||
| { | |||
| #define KPS 32 | |||
| #define KPS_DIV 8 | |||
| NetCeltAudioBuffer::NetCeltAudioBuffer(session_params_t* params, uint32_t nports, char* net_buffer, int kbps) | |||
| :NetAudioBuffer(params, nports, net_buffer) | |||
| { | |||
| fCeltMode = new CELTMode*[fNPorts]; | |||
| fCeltEncoder = new CELTEncoder*[fNPorts]; | |||
| fCeltDecoder = new CELTDecoder*[fNPorts]; | |||
| memset(fCeltMode, 0, fNPorts * sizeof(CELTMode*)); | |||
| memset(fCeltEncoder, 0, fNPorts * sizeof(CELTEncoder*)); | |||
| memset(fCeltDecoder, 0, fNPorts * sizeof(CELTDecoder*)); | |||
| int error = CELT_OK; | |||
| for (int i = 0; i < fNPorts; i++) { | |||
| fCeltMode[i] = celt_mode_create(params->fSampleRate, params->fPeriodSize, &error); | |||
| if (error != CELT_OK) { | |||
| jack_log("NetCeltAudioBuffer celt_mode_create err = %d", error); | |||
| goto error; | |||
| } | |||
| #if HAVE_CELT_API_0_11 | |||
| fCeltEncoder[i] = celt_encoder_create_custom(fCeltMode[i], 1, &error); | |||
| if (error != CELT_OK) { | |||
| jack_log("NetCeltAudioBuffer celt_encoder_create_custom err = %d", error); | |||
| goto error; | |||
| } | |||
| celt_encoder_ctl(fCeltEncoder[i], CELT_SET_COMPLEXITY(1)); | |||
| fCeltDecoder[i] = celt_decoder_create_custom(fCeltMode[i], 1, &error); | |||
| if (error != CELT_OK) { | |||
| jack_log("NetCeltAudioBuffer celt_decoder_create_custom err = %d", error); | |||
| goto error; | |||
| } | |||
| celt_decoder_ctl(fCeltDecoder[i], CELT_SET_COMPLEXITY(1)); | |||
| #elif HAVE_CELT_API_0_7 || HAVE_CELT_API_0_8 | |||
| fCeltEncoder[i] = celt_encoder_create(fCeltMode[i], 1, &error); | |||
| if (error != CELT_OK) { | |||
| jack_log("NetCeltAudioBuffer celt_mode_create err = %d", error); | |||
| goto error; | |||
| } | |||
| celt_encoder_ctl(fCeltEncoder[i], CELT_SET_COMPLEXITY(1)); | |||
| fCeltDecoder[i] = celt_decoder_create(fCeltMode[i], 1, &error); | |||
| if (error != CELT_OK) { | |||
| jack_log("NetCeltAudioBuffer celt_decoder_create err = %d", error); | |||
| goto error; | |||
| } | |||
| celt_decoder_ctl(fCeltDecoder[i], CELT_SET_COMPLEXITY(1)); | |||
| #else | |||
| fCeltEncoder[i] = celt_encoder_create(fCeltMode[i]); | |||
| if (error != CELT_OK) { | |||
| jack_log("NetCeltAudioBuffer celt_encoder_create err = %d", error); | |||
| goto error; | |||
| } | |||
| celt_encoder_ctl(fCeltEncoder[i], CELT_SET_COMPLEXITY(1)); | |||
| fCeltDecoder[i] = celt_decoder_create(fCeltMode[i]); | |||
| if (error != CELT_OK) { | |||
| jack_log("NetCeltAudioBuffer celt_decoder_create err = %d", error); | |||
| goto error; | |||
| } | |||
| celt_decoder_ctl(fCeltDecoder[i], CELT_SET_COMPLEXITY(1)); | |||
| #endif | |||
| } | |||
| { | |||
| fPeriodSize = params->fPeriodSize; | |||
| fCompressedSizeByte = (kbps * params->fPeriodSize * 1024) / (params->fSampleRate * 8); | |||
| jack_log("NetCeltAudioBuffer 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("NetCeltAudioBuffer res1 = %d res2 = %d", res1, res2); | |||
| fSubPeriodBytesSize = fCompressedSizeByte / fNumPackets; | |||
| fLastSubPeriodBytesSize = fSubPeriodBytesSize + fCompressedSizeByte % fNumPackets; | |||
| jack_log("NetCeltAudioBuffer 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: | |||
| FreeCelt(); | |||
| throw std::bad_alloc(); | |||
| } | |||
| NetCeltAudioBuffer::~NetCeltAudioBuffer() | |||
| { | |||
| FreeCelt(); | |||
| for (int port_index = 0; port_index < fNPorts; port_index++) { | |||
| delete [] fCompressedBuffer[port_index]; | |||
| } | |||
| delete [] fCompressedBuffer; | |||
| } | |||
| void NetCeltAudioBuffer::FreeCelt() | |||
| { | |||
| for (int i = 0; i < fNPorts; i++) { | |||
| if (fCeltEncoder[i]) { | |||
| celt_encoder_destroy(fCeltEncoder[i]); | |||
| } | |||
| if (fCeltDecoder[i]) { | |||
| celt_decoder_destroy(fCeltDecoder[i]); | |||
| } | |||
| if (fCeltMode[i]) { | |||
| celt_mode_destroy(fCeltMode[i]); | |||
| } | |||
| } | |||
| delete [] fCeltMode; | |||
| delete [] fCeltEncoder; | |||
| delete [] fCeltDecoder; | |||
| } | |||
| size_t NetCeltAudioBuffer::GetCycleSize() | |||
| { | |||
| return fCycleBytesSize; | |||
| } | |||
| float NetCeltAudioBuffer::GetCycleDuration() | |||
| { | |||
| return fCycleDuration; | |||
| } | |||
| int NetCeltAudioBuffer::GetNumPackets(int active_ports) | |||
| { | |||
| return fNumPackets; | |||
| } | |||
| int NetCeltAudioBuffer::RenderFromJackPorts(int nframes) | |||
| { | |||
| 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)); | |||
| } | |||
| #if HAVE_CELT_API_0_8 || HAVE_CELT_API_0_11 | |||
| //int res = celt_encode_float(fCeltEncoder[port_index], buffer, fPeriodSize, fCompressedBuffer[port_index], fCompressedSizeByte); | |||
| int res = celt_encode_float(fCeltEncoder[port_index], buffer, nframes, fCompressedBuffer[port_index], fCompressedSizeByte); | |||
| #else | |||
| int res = celt_encode_float(fCeltEncoder[port_index], buffer, NULL, fCompressedBuffer[port_index], fCompressedSizeByte); | |||
| #endif | |||
| if (res != fCompressedSizeByte) { | |||
| jack_error("celt_encode_float error fCompressedSizeByte = %d res = %d", fCompressedSizeByte, res); | |||
| } | |||
| } | |||
| // All ports active | |||
| return fNPorts; | |||
| } | |||
| void NetCeltAudioBuffer::RenderToJackPorts(int nframes) | |||
| { | |||
| for (int port_index = 0; port_index < fNPorts; port_index++) { | |||
| if (fPortBuffer[port_index]) { | |||
| #if HAVE_CELT_API_0_8 || HAVE_CELT_API_0_11 | |||
| //int res = celt_decode_float(fCeltDecoder[port_index], fCompressedBuffer[port_index], fCompressedSizeByte, fPortBuffer[port_index], fPeriodSize); | |||
| int res = celt_decode_float(fCeltDecoder[port_index], fCompressedBuffer[port_index], fCompressedSizeByte, fPortBuffer[port_index], nframes); | |||
| #else | |||
| int res = celt_decode_float(fCeltDecoder[port_index], fCompressedBuffer[port_index], fCompressedSizeByte, fPortBuffer[port_index]); | |||
| #endif | |||
| if (res != CELT_OK) { | |||
| jack_error("celt_decode_float error fCompressedSizeByte = %d res = %d", fCompressedSizeByte, res); | |||
| } | |||
| } | |||
| } | |||
| NextCycle(); | |||
| } | |||
| //network<->buffer | |||
| int NetCeltAudioBuffer::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) { | |||
| int sub_period_bytes_size; | |||
| // Last packet of the cycle | |||
| if (sub_cycle == fNumPackets - 1) { | |||
| sub_period_bytes_size = fLastSubPeriodBytesSize; | |||
| } else { | |||
| sub_period_bytes_size = fSubPeriodBytesSize; | |||
| } | |||
| for (int port_index = 0; port_index < fNPorts; port_index++) { | |||
| memcpy(fCompressedBuffer[port_index] + sub_cycle * fSubPeriodBytesSize, fNetBuffer + port_index * sub_period_bytes_size, sub_period_bytes_size); | |||
| } | |||
| } | |||
| return CheckPacket(cycle, sub_cycle); | |||
| } | |||
| int NetCeltAudioBuffer::RenderToNetwork(int sub_cycle, uint32_t port_num) | |||
| { | |||
| int sub_period_bytes_size; | |||
| // Last packet of the cycle | |||
| if (sub_cycle == fNumPackets - 1) { | |||
| sub_period_bytes_size = fLastSubPeriodBytesSize; | |||
| } else { | |||
| sub_period_bytes_size = fSubPeriodBytesSize; | |||
| } | |||
| for (int port_index = 0; port_index < fNPorts; port_index++) { | |||
| memcpy(fNetBuffer + port_index * sub_period_bytes_size, fCompressedBuffer[port_index] + sub_cycle * fSubPeriodBytesSize, sub_period_bytes_size); | |||
| } | |||
| return fNPorts * sub_period_bytes_size; | |||
| } | |||
| } | |||
| @@ -0,0 +1,66 @@ | |||
| /* | |||
| Copyright (C) 2008-2011 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 __JackNetCelt__ | |||
| #define __JackNetCelt__ | |||
| #include "JackNetTool.h" | |||
| #include <celt/celt.h> | |||
| namespace Jack | |||
| { | |||
| class SERVER_EXPORT NetCeltAudioBuffer : public NetAudioBuffer | |||
| { | |||
| private: | |||
| CELTMode** fCeltMode; | |||
| CELTEncoder** fCeltEncoder; | |||
| CELTDecoder** fCeltDecoder; | |||
| int fCompressedSizeByte; | |||
| unsigned char** fCompressedBuffer; | |||
| size_t fLastSubPeriodBytesSize; | |||
| void FreeCelt(); | |||
| public: | |||
| NetCeltAudioBuffer(session_params_t* params, uint32_t nports, char* net_buffer, int kbps); | |||
| virtual ~NetCeltAudioBuffer(); | |||
| // 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(int nframes); | |||
| void RenderToJackPorts(int nframes); | |||
| //network<->buffer | |||
| int RenderFromNetwork(int cycle, int sub_cycle, uint32_t port_num); | |||
| int RenderToNetwork(int sub_cycle, uint32_t port_num); | |||
| }; | |||
| } | |||
| #endif | |||
| @@ -20,6 +20,14 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | |||
| #include "JackException.h" | |||
| #include "JackError.h" | |||
| #if HAVE_CELT | |||
| #include "JackNetCelt.h" | |||
| #endif | |||
| #if HAVE_OPUS | |||
| #include "JackNetOpus.h" | |||
| #endif | |||
| #include <assert.h> | |||
| using namespace std; | |||
| @@ -40,8 +40,8 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | |||
| #endif | |||
| #if HAVE_OPUS | |||
| #include <opus/opus.h> | |||
| #include <opus/opus_custom.h> | |||
| #include <opus.h> | |||
| #include <opus_custom.h> | |||
| #endif | |||
| #define MIN(x,y) ((x)<(y) ? (x) : (y)) | |||
| @@ -0,0 +1,243 @@ | |||
| /* | |||
| Copyright (C) 2008-2011 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. | |||
| */ | |||
| #include "JackNetOpus.h" | |||
| #include "JackError.h" | |||
| namespace Jack | |||
| { | |||
| #define CDO (sizeof(short)) ///< compressed data offset (first 2 bytes are length) | |||
| 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]; | |||
| fCompressedSizesByte = new unsigned short[fNPorts]; | |||
| memset(fOpusMode, 0, fNPorts * sizeof(OpusCustomMode*)); | |||
| memset(fOpusEncoder, 0, fNPorts * sizeof(OpusCustomEncoder*)); | |||
| memset(fOpusDecoder, 0, fNPorts * sizeof(OpusCustomDecoder*)); | |||
| memset(fCompressedSizesByte, 0, fNPorts * sizeof(short)); | |||
| 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) { | |||
| jack_log("NetOpusAudioBuffer opus_custom_mode_create err = %d", error); | |||
| goto error; | |||
| } | |||
| fOpusEncoder[i] = opus_custom_encoder_create(fOpusMode[i], 1, &error); | |||
| if (error != OPUS_OK) { | |||
| jack_log("NetOpusAudioBuffer opus_custom_encoder_create err = %d", error); | |||
| goto error; | |||
| } | |||
| fOpusDecoder[i] = opus_custom_decoder_create(fOpusMode[i], 1, &error); | |||
| if (error != OPUS_OK) { | |||
| jack_log("NetOpusAudioBuffer opus_custom_decoder_create err = %d", error); | |||
| 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)); | |||
| } | |||
| { | |||
| fCompressedMaxSizeByte = (kbps * params->fPeriodSize * 1024) / (params->fSampleRate * 8); | |||
| fPeriodSize = params->fPeriodSize; | |||
| jack_log("NetOpusAudioBuffer fCompressedMaxSizeByte %d", fCompressedMaxSizeByte); | |||
| fCompressedBuffer = new unsigned char* [fNPorts]; | |||
| for (int port_index = 0; port_index < fNPorts; port_index++) { | |||
| fCompressedBuffer[port_index] = new unsigned char[fCompressedMaxSizeByte]; | |||
| memset(fCompressedBuffer[port_index], 0, fCompressedMaxSizeByte * sizeof(char)); | |||
| } | |||
| int res1 = (fNPorts * fCompressedMaxSizeByte + CDO) % PACKET_AVAILABLE_SIZE(params); | |||
| int res2 = (fNPorts * fCompressedMaxSizeByte + CDO) / PACKET_AVAILABLE_SIZE(params); | |||
| fNumPackets = (res1) ? (res2 + 1) : res2; | |||
| jack_log("NetOpusAudioBuffer res1 = %d res2 = %d", res1, res2); | |||
| fSubPeriodBytesSize = (fCompressedMaxSizeByte + CDO) / fNumPackets; | |||
| fLastSubPeriodBytesSize = fSubPeriodBytesSize + (fCompressedMaxSizeByte + CDO) % fNumPackets; | |||
| if (fNumPackets == 1) { | |||
| fSubPeriodBytesSize = fLastSubPeriodBytesSize; | |||
| } | |||
| 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; | |||
| delete [] fCompressedSizesByte; | |||
| } | |||
| 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(int nframes) | |||
| { | |||
| 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, ((nframes == -1) ? fPeriodSize : nframes), fCompressedBuffer[port_index], fCompressedMaxSizeByte); | |||
| if (res < 0 || res >= 65535) { | |||
| jack_error("opus_custom_encode_float error res = %d", res); | |||
| fCompressedSizesByte[port_index] = 0; | |||
| } else { | |||
| fCompressedSizesByte[port_index] = res; | |||
| } | |||
| } | |||
| // All ports active | |||
| return fNPorts; | |||
| } | |||
| void NetOpusAudioBuffer::RenderToJackPorts(int nframes) | |||
| { | |||
| 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], fCompressedSizesByte[port_index], fPortBuffer[port_index], ((nframes == -1) ? fPeriodSize : nframes)); | |||
| if (res < 0 || res != ((nframes == -1) ? fPeriodSize : nframes)) { | |||
| jack_error("opus_custom_decode_float error fCompressedSizeByte = %d res = %d", fCompressedSizesByte[port_index], 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) { | |||
| if (sub_cycle == 0) { | |||
| for (int port_index = 0; port_index < fNPorts; port_index++) { | |||
| size_t len = *((size_t*)(fNetBuffer + port_index * fSubPeriodBytesSize)); | |||
| fCompressedSizesByte[port_index] = ntohs(len); | |||
| memcpy(fCompressedBuffer[port_index] + sub_cycle * fSubPeriodBytesSize, fNetBuffer + CDO + port_index * fSubPeriodBytesSize, fSubPeriodBytesSize - CDO); | |||
| } | |||
| } else if (sub_cycle == fNumPackets - 1) { | |||
| for (int port_index = 0; port_index < fNPorts; port_index++) { | |||
| memcpy(fCompressedBuffer[port_index] + sub_cycle * fSubPeriodBytesSize - CDO, fNetBuffer + port_index * fLastSubPeriodBytesSize, fLastSubPeriodBytesSize); | |||
| } | |||
| } else { | |||
| for (int port_index = 0; port_index < fNPorts; port_index++) { | |||
| memcpy(fCompressedBuffer[port_index] + sub_cycle * fSubPeriodBytesSize - CDO, fNetBuffer + port_index * fSubPeriodBytesSize, fSubPeriodBytesSize); | |||
| } | |||
| } | |||
| } | |||
| return CheckPacket(cycle, sub_cycle); | |||
| } | |||
| int NetOpusAudioBuffer::RenderToNetwork(int sub_cycle, uint32_t port_num) | |||
| { | |||
| if (sub_cycle == 0) { | |||
| for (int port_index = 0; port_index < fNPorts; port_index++) { | |||
| unsigned short len = htons(fCompressedSizesByte[port_index]); | |||
| memcpy(fNetBuffer + port_index * fSubPeriodBytesSize, &len, CDO); | |||
| memcpy(fNetBuffer + port_index * fSubPeriodBytesSize + CDO, fCompressedBuffer[port_index], fSubPeriodBytesSize - CDO); | |||
| } | |||
| return fNPorts * fSubPeriodBytesSize; | |||
| } else 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 - CDO, 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 - CDO, fSubPeriodBytesSize); | |||
| } | |||
| return fNPorts * fSubPeriodBytesSize; | |||
| } | |||
| } | |||
| } | |||
| @@ -0,0 +1,68 @@ | |||
| /* | |||
| Copyright (C) 2008-2011 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 __JackNetOpus__ | |||
| #define __JackNetOpus__ | |||
| #include "JackNetTool.h" | |||
| #include <opus.h> | |||
| #include <opus_custom.h> | |||
| namespace Jack | |||
| { | |||
| class SERVER_EXPORT NetOpusAudioBuffer : public NetAudioBuffer | |||
| { | |||
| private: | |||
| OpusCustomMode** fOpusMode; | |||
| OpusCustomEncoder** fOpusEncoder; | |||
| OpusCustomDecoder** fOpusDecoder; | |||
| int fCompressedMaxSizeByte; | |||
| unsigned short* fCompressedSizesByte; | |||
| 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(int nframes); | |||
| void RenderToJackPorts(int nframes); | |||
| //network<->buffer | |||
| int RenderFromNetwork(int cycle, int sub_cycle, uint32_t port_num); | |||
| int RenderToNetwork(int sub_cycle, uint32_t port_num); | |||
| }; | |||
| } | |||
| #endif | |||
| @@ -473,478 +473,7 @@ namespace Jack | |||
| } | |||
| #endif | |||
| // Celt audio buffer ********************************************************************************* | |||
| #if HAVE_CELT | |||
| #define KPS 32 | |||
| #define KPS_DIV 8 | |||
| NetCeltAudioBuffer::NetCeltAudioBuffer(session_params_t* params, uint32_t nports, char* net_buffer, int kbps) | |||
| :NetAudioBuffer(params, nports, net_buffer) | |||
| { | |||
| fCeltMode = new CELTMode*[fNPorts]; | |||
| fCeltEncoder = new CELTEncoder*[fNPorts]; | |||
| fCeltDecoder = new CELTDecoder*[fNPorts]; | |||
| memset(fCeltMode, 0, fNPorts * sizeof(CELTMode*)); | |||
| memset(fCeltEncoder, 0, fNPorts * sizeof(CELTEncoder*)); | |||
| memset(fCeltDecoder, 0, fNPorts * sizeof(CELTDecoder*)); | |||
| int error = CELT_OK; | |||
| for (int i = 0; i < fNPorts; i++) { | |||
| fCeltMode[i] = celt_mode_create(params->fSampleRate, params->fPeriodSize, &error); | |||
| if (error != CELT_OK) { | |||
| jack_log("NetCeltAudioBuffer celt_mode_create err = %d", error); | |||
| goto error; | |||
| } | |||
| #if HAVE_CELT_API_0_11 | |||
| fCeltEncoder[i] = celt_encoder_create_custom(fCeltMode[i], 1, &error); | |||
| if (error != CELT_OK) { | |||
| jack_log("NetCeltAudioBuffer celt_encoder_create_custom err = %d", error); | |||
| goto error; | |||
| } | |||
| celt_encoder_ctl(fCeltEncoder[i], CELT_SET_COMPLEXITY(1)); | |||
| fCeltDecoder[i] = celt_decoder_create_custom(fCeltMode[i], 1, &error); | |||
| if (error != CELT_OK) { | |||
| jack_log("NetCeltAudioBuffer celt_decoder_create_custom err = %d", error); | |||
| goto error; | |||
| } | |||
| celt_decoder_ctl(fCeltDecoder[i], CELT_SET_COMPLEXITY(1)); | |||
| #elif HAVE_CELT_API_0_7 || HAVE_CELT_API_0_8 | |||
| fCeltEncoder[i] = celt_encoder_create(fCeltMode[i], 1, &error); | |||
| if (error != CELT_OK) { | |||
| jack_log("NetCeltAudioBuffer celt_mode_create err = %d", error); | |||
| goto error; | |||
| } | |||
| celt_encoder_ctl(fCeltEncoder[i], CELT_SET_COMPLEXITY(1)); | |||
| fCeltDecoder[i] = celt_decoder_create(fCeltMode[i], 1, &error); | |||
| if (error != CELT_OK) { | |||
| jack_log("NetCeltAudioBuffer celt_decoder_create err = %d", error); | |||
| goto error; | |||
| } | |||
| celt_decoder_ctl(fCeltDecoder[i], CELT_SET_COMPLEXITY(1)); | |||
| #else | |||
| fCeltEncoder[i] = celt_encoder_create(fCeltMode[i]); | |||
| if (error != CELT_OK) { | |||
| jack_log("NetCeltAudioBuffer celt_encoder_create err = %d", error); | |||
| goto error; | |||
| } | |||
| celt_encoder_ctl(fCeltEncoder[i], CELT_SET_COMPLEXITY(1)); | |||
| fCeltDecoder[i] = celt_decoder_create(fCeltMode[i]); | |||
| if (error != CELT_OK) { | |||
| jack_log("NetCeltAudioBuffer celt_decoder_create err = %d", error); | |||
| goto error; | |||
| } | |||
| celt_decoder_ctl(fCeltDecoder[i], CELT_SET_COMPLEXITY(1)); | |||
| #endif | |||
| } | |||
| { | |||
| fPeriodSize = params->fPeriodSize; | |||
| fCompressedSizeByte = (kbps * params->fPeriodSize * 1024) / (params->fSampleRate * 8); | |||
| jack_log("NetCeltAudioBuffer 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("NetCeltAudioBuffer res1 = %d res2 = %d", res1, res2); | |||
| fSubPeriodBytesSize = fCompressedSizeByte / fNumPackets; | |||
| fLastSubPeriodBytesSize = fSubPeriodBytesSize + fCompressedSizeByte % fNumPackets; | |||
| jack_log("NetCeltAudioBuffer 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: | |||
| FreeCelt(); | |||
| throw std::bad_alloc(); | |||
| } | |||
| NetCeltAudioBuffer::~NetCeltAudioBuffer() | |||
| { | |||
| FreeCelt(); | |||
| for (int port_index = 0; port_index < fNPorts; port_index++) { | |||
| delete [] fCompressedBuffer[port_index]; | |||
| } | |||
| delete [] fCompressedBuffer; | |||
| } | |||
| void NetCeltAudioBuffer::FreeCelt() | |||
| { | |||
| for (int i = 0; i < fNPorts; i++) { | |||
| if (fCeltEncoder[i]) { | |||
| celt_encoder_destroy(fCeltEncoder[i]); | |||
| } | |||
| if (fCeltDecoder[i]) { | |||
| celt_decoder_destroy(fCeltDecoder[i]); | |||
| } | |||
| if (fCeltMode[i]) { | |||
| celt_mode_destroy(fCeltMode[i]); | |||
| } | |||
| } | |||
| delete [] fCeltMode; | |||
| delete [] fCeltEncoder; | |||
| delete [] fCeltDecoder; | |||
| } | |||
| size_t NetCeltAudioBuffer::GetCycleSize() | |||
| { | |||
| return fCycleBytesSize; | |||
| } | |||
| float NetCeltAudioBuffer::GetCycleDuration() | |||
| { | |||
| return fCycleDuration; | |||
| } | |||
| int NetCeltAudioBuffer::GetNumPackets(int active_ports) | |||
| { | |||
| return fNumPackets; | |||
| } | |||
| int NetCeltAudioBuffer::RenderFromJackPorts(int nframes) | |||
| { | |||
| 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)); | |||
| } | |||
| #if HAVE_CELT_API_0_8 || HAVE_CELT_API_0_11 | |||
| //int res = celt_encode_float(fCeltEncoder[port_index], buffer, fPeriodSize, fCompressedBuffer[port_index], fCompressedSizeByte); | |||
| int res = celt_encode_float(fCeltEncoder[port_index], buffer, nframes, fCompressedBuffer[port_index], fCompressedSizeByte); | |||
| #else | |||
| int res = celt_encode_float(fCeltEncoder[port_index], buffer, NULL, fCompressedBuffer[port_index], fCompressedSizeByte); | |||
| #endif | |||
| if (res != fCompressedSizeByte) { | |||
| jack_error("celt_encode_float error fCompressedSizeByte = %d res = %d", fCompressedSizeByte, res); | |||
| } | |||
| } | |||
| // All ports active | |||
| return fNPorts; | |||
| } | |||
| void NetCeltAudioBuffer::RenderToJackPorts(int nframes) | |||
| { | |||
| for (int port_index = 0; port_index < fNPorts; port_index++) { | |||
| if (fPortBuffer[port_index]) { | |||
| #if HAVE_CELT_API_0_8 || HAVE_CELT_API_0_11 | |||
| //int res = celt_decode_float(fCeltDecoder[port_index], fCompressedBuffer[port_index], fCompressedSizeByte, fPortBuffer[port_index], fPeriodSize); | |||
| int res = celt_decode_float(fCeltDecoder[port_index], fCompressedBuffer[port_index], fCompressedSizeByte, fPortBuffer[port_index], nframes); | |||
| #else | |||
| int res = celt_decode_float(fCeltDecoder[port_index], fCompressedBuffer[port_index], fCompressedSizeByte, fPortBuffer[port_index]); | |||
| #endif | |||
| if (res != CELT_OK) { | |||
| jack_error("celt_decode_float error fCompressedSizeByte = %d res = %d", fCompressedSizeByte, res); | |||
| } | |||
| } | |||
| } | |||
| NextCycle(); | |||
| } | |||
| //network<->buffer | |||
| int NetCeltAudioBuffer::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) { | |||
| int sub_period_bytes_size; | |||
| // Last packet of the cycle | |||
| if (sub_cycle == fNumPackets - 1) { | |||
| sub_period_bytes_size = fLastSubPeriodBytesSize; | |||
| } else { | |||
| sub_period_bytes_size = fSubPeriodBytesSize; | |||
| } | |||
| for (int port_index = 0; port_index < fNPorts; port_index++) { | |||
| memcpy(fCompressedBuffer[port_index] + sub_cycle * fSubPeriodBytesSize, fNetBuffer + port_index * sub_period_bytes_size, sub_period_bytes_size); | |||
| } | |||
| } | |||
| return CheckPacket(cycle, sub_cycle); | |||
| } | |||
| int NetCeltAudioBuffer::RenderToNetwork(int sub_cycle, uint32_t port_num) | |||
| { | |||
| int sub_period_bytes_size; | |||
| // Last packet of the cycle | |||
| if (sub_cycle == fNumPackets - 1) { | |||
| sub_period_bytes_size = fLastSubPeriodBytesSize; | |||
| } else { | |||
| sub_period_bytes_size = fSubPeriodBytesSize; | |||
| } | |||
| for (int port_index = 0; port_index < fNPorts; port_index++) { | |||
| memcpy(fNetBuffer + port_index * sub_period_bytes_size, fCompressedBuffer[port_index] + sub_cycle * fSubPeriodBytesSize, sub_period_bytes_size); | |||
| } | |||
| return fNPorts * sub_period_bytes_size; | |||
| } | |||
| #endif | |||
| #if HAVE_OPUS | |||
| #define CDO (sizeof(short)) ///< compressed data offset (first 2 bytes are length) | |||
| 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]; | |||
| fCompressedSizesByte = new unsigned short[fNPorts]; | |||
| memset(fOpusMode, 0, fNPorts * sizeof(OpusCustomMode*)); | |||
| memset(fOpusEncoder, 0, fNPorts * sizeof(OpusCustomEncoder*)); | |||
| memset(fOpusDecoder, 0, fNPorts * sizeof(OpusCustomDecoder*)); | |||
| memset(fCompressedSizesByte, 0, fNPorts * sizeof(short)); | |||
| 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) { | |||
| jack_log("NetOpusAudioBuffer opus_custom_mode_create err = %d", error); | |||
| goto error; | |||
| } | |||
| fOpusEncoder[i] = opus_custom_encoder_create(fOpusMode[i], 1, &error); | |||
| if (error != OPUS_OK) { | |||
| jack_log("NetOpusAudioBuffer opus_custom_encoder_create err = %d", error); | |||
| goto error; | |||
| } | |||
| fOpusDecoder[i] = opus_custom_decoder_create(fOpusMode[i], 1, &error); | |||
| if (error != OPUS_OK) { | |||
| jack_log("NetOpusAudioBuffer opus_custom_decoder_create err = %d", error); | |||
| 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)); | |||
| } | |||
| { | |||
| fCompressedMaxSizeByte = (kbps * params->fPeriodSize * 1024) / (params->fSampleRate * 8); | |||
| fPeriodSize = params->fPeriodSize; | |||
| jack_log("NetOpusAudioBuffer fCompressedMaxSizeByte %d", fCompressedMaxSizeByte); | |||
| fCompressedBuffer = new unsigned char* [fNPorts]; | |||
| for (int port_index = 0; port_index < fNPorts; port_index++) { | |||
| fCompressedBuffer[port_index] = new unsigned char[fCompressedMaxSizeByte]; | |||
| memset(fCompressedBuffer[port_index], 0, fCompressedMaxSizeByte * sizeof(char)); | |||
| } | |||
| int res1 = (fNPorts * fCompressedMaxSizeByte + CDO) % PACKET_AVAILABLE_SIZE(params); | |||
| int res2 = (fNPorts * fCompressedMaxSizeByte + CDO) / PACKET_AVAILABLE_SIZE(params); | |||
| fNumPackets = (res1) ? (res2 + 1) : res2; | |||
| jack_log("NetOpusAudioBuffer res1 = %d res2 = %d", res1, res2); | |||
| fSubPeriodBytesSize = (fCompressedMaxSizeByte + CDO) / fNumPackets; | |||
| fLastSubPeriodBytesSize = fSubPeriodBytesSize + (fCompressedMaxSizeByte + CDO) % fNumPackets; | |||
| if (fNumPackets == 1) { | |||
| fSubPeriodBytesSize = fLastSubPeriodBytesSize; | |||
| } | |||
| 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; | |||
| delete [] fCompressedSizesByte; | |||
| } | |||
| 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(int nframes) | |||
| { | |||
| 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, ((nframes == -1) ? fPeriodSize : nframes), fCompressedBuffer[port_index], fCompressedMaxSizeByte); | |||
| if (res < 0 || res >= 65535) { | |||
| jack_error("opus_custom_encode_float error res = %d", res); | |||
| fCompressedSizesByte[port_index] = 0; | |||
| } else { | |||
| fCompressedSizesByte[port_index] = res; | |||
| } | |||
| } | |||
| // All ports active | |||
| return fNPorts; | |||
| } | |||
| void NetOpusAudioBuffer::RenderToJackPorts(int nframes) | |||
| { | |||
| 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], fCompressedSizesByte[port_index], fPortBuffer[port_index], ((nframes == -1) ? fPeriodSize : nframes)); | |||
| if (res < 0 || res != ((nframes == -1) ? fPeriodSize : nframes)) { | |||
| jack_error("opus_custom_decode_float error fCompressedSizeByte = %d res = %d", fCompressedSizesByte[port_index], 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) { | |||
| if (sub_cycle == 0) { | |||
| for (int port_index = 0; port_index < fNPorts; port_index++) { | |||
| size_t len = *((size_t*)(fNetBuffer + port_index * fSubPeriodBytesSize)); | |||
| fCompressedSizesByte[port_index] = ntohs(len); | |||
| memcpy(fCompressedBuffer[port_index] + sub_cycle * fSubPeriodBytesSize, fNetBuffer + CDO + port_index * fSubPeriodBytesSize, fSubPeriodBytesSize - CDO); | |||
| } | |||
| } else if (sub_cycle == fNumPackets - 1) { | |||
| for (int port_index = 0; port_index < fNPorts; port_index++) { | |||
| memcpy(fCompressedBuffer[port_index] + sub_cycle * fSubPeriodBytesSize - CDO, fNetBuffer + port_index * fLastSubPeriodBytesSize, fLastSubPeriodBytesSize); | |||
| } | |||
| } else { | |||
| for (int port_index = 0; port_index < fNPorts; port_index++) { | |||
| memcpy(fCompressedBuffer[port_index] + sub_cycle * fSubPeriodBytesSize - CDO, fNetBuffer + port_index * fSubPeriodBytesSize, fSubPeriodBytesSize); | |||
| } | |||
| } | |||
| } | |||
| return CheckPacket(cycle, sub_cycle); | |||
| } | |||
| int NetOpusAudioBuffer::RenderToNetwork(int sub_cycle, uint32_t port_num) | |||
| { | |||
| if (sub_cycle == 0) { | |||
| for (int port_index = 0; port_index < fNPorts; port_index++) { | |||
| unsigned short len = htons(fCompressedSizesByte[port_index]); | |||
| memcpy(fNetBuffer + port_index * fSubPeriodBytesSize, &len, CDO); | |||
| memcpy(fNetBuffer + port_index * fSubPeriodBytesSize + CDO, fCompressedBuffer[port_index], fSubPeriodBytesSize - CDO); | |||
| } | |||
| return fNPorts * fSubPeriodBytesSize; | |||
| } else 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 - CDO, 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 - CDO, fSubPeriodBytesSize); | |||
| } | |||
| return fNPorts * fSubPeriodBytesSize; | |||
| } | |||
| } | |||
| #endif | |||
| NetIntAudioBuffer::NetIntAudioBuffer(session_params_t* params, uint32_t nports, char* net_buffer) | |||
| : NetAudioBuffer(params, nports, net_buffer) | |||
| @@ -17,6 +17,9 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | |||
| */ | |||
| #ifndef __JackNetTool__ | |||
| #define __JackNetTool__ | |||
| #include "JackMidiPort.h" | |||
| #include "JackTools.h" | |||
| #include "types.h" | |||
| @@ -366,92 +369,6 @@ namespace Jack | |||
| }; | |||
| #if HAVE_CELT | |||
| #include <celt/celt.h> | |||
| class SERVER_EXPORT NetCeltAudioBuffer : public NetAudioBuffer | |||
| { | |||
| private: | |||
| CELTMode** fCeltMode; | |||
| CELTEncoder** fCeltEncoder; | |||
| CELTDecoder** fCeltDecoder; | |||
| int fCompressedSizeByte; | |||
| unsigned char** fCompressedBuffer; | |||
| size_t fLastSubPeriodBytesSize; | |||
| void FreeCelt(); | |||
| public: | |||
| NetCeltAudioBuffer(session_params_t* params, uint32_t nports, char* net_buffer, int kbps); | |||
| virtual ~NetCeltAudioBuffer(); | |||
| // 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(int nframes); | |||
| void RenderToJackPorts(int nframes); | |||
| //network<->buffer | |||
| int RenderFromNetwork(int cycle, int sub_cycle, uint32_t port_num); | |||
| 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 fCompressedMaxSizeByte; | |||
| unsigned short* fCompressedSizesByte; | |||
| 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(int nframes); | |||
| void RenderToJackPorts(int nframes); | |||
| //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 | |||
| { | |||
| private: | |||
| @@ -509,3 +426,5 @@ namespace Jack | |||
| SERVER_EXPORT const char* GetTransportState(int transport_state); | |||
| SERVER_EXPORT void NetTransportDataDisplay(net_transport_data_t* data); | |||
| } | |||
| #endif | |||
| @@ -33,8 +33,8 @@ | |||
| #endif | |||
| #if HAVE_OPUS | |||
| #include <opus/opus.h> | |||
| #include <opus/opus_custom.h> | |||
| #include <opus.h> | |||
| #include <opus_custom.h> | |||
| #endif | |||
| #ifdef __cplusplus | |||
| @@ -73,8 +73,8 @@ | |||
| #endif | |||
| #if HAVE_OPUS | |||
| #include <opus/opus.h> | |||
| #include <opus/opus_custom.h> | |||
| #include <opus.h> | |||
| #include <opus_custom.h> | |||
| #endif | |||
| #include "netjack_packet.h" | |||
| @@ -244,6 +244,11 @@ def build(bld): | |||
| 'JackMidiWriteQueue.cpp' | |||
| ] | |||
| if bld.env['CELT']: | |||
| serverlib.source += ['JackNetCelt.cpp'] | |||
| if bld.env['OPUS']: | |||
| serverlib.source += ['JackNetOpus.cpp'] | |||
| if bld.env['IS_LINUX']: | |||
| serverlib.source += [ | |||
| '../posix/JackSocketServerChannel.cpp', | |||
| @@ -317,6 +322,11 @@ def build(bld): | |||
| 'JackGlobals.cpp', | |||
| 'ringbuffer.c'] | |||
| if bld.env['CELT']: | |||
| netlib.source += ['JackNetCelt.cpp'] | |||
| if bld.env['OPUS']: | |||
| netlib.source += ['JackNetOpus.cpp'] | |||
| if bld.env['IS_LINUX']: | |||
| netlib.source += ['../posix/JackNetUnixSocket.cpp','../posix/JackPosixThread.cpp', '../posix/JackPosixMutex.cpp', '../linux/JackLinuxTime.c'] | |||
| netlib.env.append_value("CPPFLAGS", "-fvisibility=hidden") | |||
| @@ -63,8 +63,8 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | |||
| #endif | |||
| #if HAVE_OPUS | |||
| #include <opus/opus.h> | |||
| #include <opus/opus_custom.h> | |||
| #include <opus.h> | |||
| #include <opus_custom.h> | |||
| #endif | |||
| #include <math.h> | |||
| @@ -89,6 +89,6 @@ def build(bld): | |||
| create_jack_driver_obj(bld, 'netone', [ '../common/JackNetOneDriver.cpp', | |||
| '../common/netjack.c', | |||
| '../common/netjack_packet.c' ], ["SAMPLERATE", "CELT"]) | |||
| '../common/netjack_packet.c' ], ["SAMPLERATE", "CELT", "OPUS"]) | |||
| create_jack_driver_obj(bld, 'proxy', '../common/JackProxyDriver.cpp') | |||
| @@ -187,10 +187,23 @@ class AutoOption: | |||
| """ | |||
| all_found = True | |||
| # Use-variables that should be used when checking libraries, headers and | |||
| # programs. The list will be populated when looking for packages. | |||
| use = [] | |||
| # check for packages | |||
| for package,uselib_store,atleast_version in self.packages: | |||
| try: | |||
| conf.check_cfg(package=package, uselib_store=uselib_store, atleast_version=atleast_version, args='--cflags --libs') | |||
| use.append(uselib_store) | |||
| except conf.errors.ConfigurationError: | |||
| all_found = False | |||
| self.packages_not_found.append([package,atleast_version]) | |||
| # check for libraries | |||
| for lib,uselib_store in self.libs: | |||
| try: | |||
| conf.check_cc(lib=lib, uselib_store=uselib_store) | |||
| conf.check_cc(lib=lib, uselib_store=uselib_store, use=use) | |||
| except conf.errors.ConfigurationError: | |||
| all_found = False | |||
| self.libs_not_found.append(lib) | |||
| @@ -198,23 +211,15 @@ class AutoOption: | |||
| # check for headers | |||
| for header in self.headers: | |||
| try: | |||
| conf.check_cc(header_name=header) | |||
| conf.check_cc(header_name=header, use=use) | |||
| except conf.errors.ConfigurationError: | |||
| all_found = False | |||
| self.headers_not_found.append(header) | |||
| # check for packages | |||
| for package,uselib_store,atleast_version in self.packages: | |||
| try: | |||
| conf.check_cfg(package=package, uselib_store=uselib_store, atleast_version=atleast_version, args='--cflags --libs') | |||
| except conf.errors.ConfigurationError: | |||
| all_found = False | |||
| self.packages_not_found.append([package,atleast_version]) | |||
| # check for programs | |||
| for program,var in self.programs: | |||
| try: | |||
| conf.find_program(program, var=var) | |||
| conf.find_program(program, var=var, use=use) | |||
| except conf.errors.ConfigurationError: | |||
| all_found = False | |||
| self.programs_not_found.append(program) | |||
| @@ -428,8 +433,8 @@ def options(opt): | |||
| celt = add_auto_option(opt, 'celt', help='Build with CELT') | |||
| celt.set_check_hook(check_for_celt, check_for_celt_error) | |||
| opus = add_auto_option(opt, 'opus', help='Build Opus netjack2') | |||
| opus.add_header('opus/opus_custom.h') | |||
| opus.add_package('opus', atleast_version='0.9.0') | |||
| opus.add_header('opus_custom.h') | |||
| samplerate = add_auto_option(opt, 'samplerate', help='Build with libsamplerate') | |||
| samplerate.add_package('samplerate') | |||
| sndfile = add_auto_option(opt, 'sndfile', help='Build with libsndfile') | |||