diff --git a/sdrbase/audio/audionetsink.cpp b/sdrbase/audio/audionetsink.cpp index 6bc9ff201..275539c81 100644 --- a/sdrbase/audio/audionetsink.cpp +++ b/sdrbase/audio/audionetsink.cpp @@ -269,6 +269,19 @@ void AudioNetSink::write(qint16 isample) } } break; + case CodecOpus: + { + if (m_codecInputIndex == m_codecInputSize) + { + int nbBytes = m_opus.encode(m_codecInputSize, m_opusIn, (uint8_t *) m_data); + nbBytes = nbBytes > m_udpBlockSize ? m_udpBlockSize : nbBytes; + m_udpSocket->writeDatagram((const char*) m_data, (qint64 ) nbBytes, m_address, m_port); + m_codecInputIndex = 0; + } + + m_opusIn[m_codecInputIndex++] = sample; + } + break; case CodecL16: default: { @@ -314,6 +327,25 @@ void AudioNetSink::write(qint16 isample) m_bufferIndex += 1; } break; + case CodecOpus: + { + if (m_codecInputIndex == m_codecInputSize) + { + int nbBytes = m_opus.encode(m_codecInputSize, m_opusIn, (uint8_t *) m_data); + if (nbBytes != AudioOpus::m_bitrate/400) { // 8 bits for 1/50s (20ms) + qWarning("AudioNetSink::write: CodecOpus mono: unexpected output frame size: %d bytes", nbBytes); + } + m_bufferIndex = 0; + m_codecInputIndex = 0; + } + + if (m_codecInputIndex % m_codecRatio == 0) { + m_rtpBufferAudio->write((uint8_t *) &m_data[m_bufferIndex++]); + } + + m_opusIn[m_codecInputIndex++] = sample; + } + break; case CodecL16: default: m_rtpBufferAudio->write((uint8_t *) &sample); @@ -359,6 +391,21 @@ void AudioNetSink::write(qint16 ilSample, qint16 irSample) case CodecPCMU: case CodecG722: break; // mono modes - do nothing + case CodecOpus: + { + if (m_codecInputIndex == m_codecInputSize) + { + int nbBytes = m_opus.encode(m_codecInputSize, m_opusIn, (uint8_t *) m_data); + nbBytes = nbBytes > m_udpBlockSize ? m_udpBlockSize : nbBytes; + m_udpSocket->writeDatagram((const char*) m_data, (qint64 ) nbBytes, m_address, m_port); + m_codecInputIndex = 0; + } + + m_opusIn[2*m_codecInputIndex] = lSample; + m_opusIn[2*m_codecInputIndex+1] = rSample; + m_codecInputIndex++; + } + break; case CodecL8: { qint8 *p = (qint8*) &m_data[m_bufferIndex]; @@ -390,6 +437,27 @@ void AudioNetSink::write(qint16 ilSample, qint16 irSample) case CodecPCMU: case CodecG722: break; // mono modes - do nothing + case CodecOpus: + { + if (m_codecInputIndex == m_codecInputSize) + { + int nbBytes = m_opus.encode(m_codecInputSize, m_opusIn, (uint8_t *) m_data); + if (nbBytes != AudioOpus::m_bitrate/400) { // 8 bits for 1/50s (20ms) + qWarning("AudioNetSink::write: CodecOpus stereo: unexpected output frame size: %d bytes", nbBytes); + } + m_bufferIndex = 0; + m_codecInputIndex = 0; + } + + if (m_codecInputIndex % m_codecRatio == 0) { + m_rtpBufferAudio->write((uint8_t *) &m_data[m_bufferIndex++]); + } + + m_opusIn[2*m_codecInputIndex] = lSample; + m_opusIn[2*m_codecInputIndex+1] = rSample; + m_codecInputIndex++; + } + break; case CodecL8: { qint8 pl = lSample / 256; diff --git a/sdrbase/util/rtpsink.cpp b/sdrbase/util/rtpsink.cpp index ed4ce92f7..3ebe842a5 100644 --- a/sdrbase/util/rtpsink.cpp +++ b/sdrbase/util/rtpsink.cpp @@ -112,9 +112,9 @@ void RTPSink::setPayloadInformation(PayloadType payloadType, int sampleRate) break; case PayloadOpus: m_sampleBytes = 1; - m_rtpSession.SetDefaultPayloadType(101); - m_packetSamples = 960; // Fixed 20ms @ 48 kHz as per https://tools.ietf.org/html/rfc7587 - timestampinc = 960; // and per single channel + m_rtpSession.SetDefaultPayloadType(96); + m_packetSamples = 160; // Payload size is 160 bytes + timestampinc = 960; // But increment is 960 break; case PayloadL16Mono: default: @@ -336,6 +336,9 @@ unsigned int RTPSink::elemLength(PayloadType payloadType) { case PayloadPCMA8: case PayloadPCMU8: + case PayloadG722: + case PayloadOpus: + case PayloadL8: return sizeof(int8_t); break; case PayloadL16Stereo: