|
- /*
- 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;
- }
- }
- }
|