From 202d67f1416b820ceee1912badef6055a42aa475 Mon Sep 17 00:00:00 2001 From: f4exb Date: Sun, 17 Feb 2019 03:40:11 +0100 Subject: [PATCH] Copy to UDP/RTP: implemented G722 --- sdrbase/audio/audionetsink.cpp | 86 +++++++++++++++++++++++----------- sdrbase/audio/audionetsink.h | 9 +++- sdrbase/audio/audiooutput.h | 3 +- sdrbase/util/rtpsink.cpp | 14 ++++-- sdrbase/util/rtpsink.h | 3 +- sdrgui/gui/audiodialog.cpp | 80 ++++++++++++++++++++++--------- sdrgui/gui/audiodialog.ui | 5 ++ 7 files changed, 142 insertions(+), 58 deletions(-) diff --git a/sdrbase/audio/audionetsink.cpp b/sdrbase/audio/audionetsink.cpp index d0dbb372c..7de15b3ee 100644 --- a/sdrbase/audio/audionetsink.cpp +++ b/sdrbase/audio/audionetsink.cpp @@ -15,6 +15,8 @@ // along with this program. If not, see . // /////////////////////////////////////////////////////////////////////////////////// +#include + #include "audionetsink.h" #include "util/rtpsink.h" @@ -33,7 +35,7 @@ AudioNetSink::AudioNetSink(QObject *parent) : m_bufferIndex(0), m_port(9998) { - memset(m_data, 0, 65536); + std::fill(m_data, m_data+m_dataBlockSize, 0); m_udpSocket = new QUdpSocket(parent); } @@ -47,7 +49,7 @@ AudioNetSink::AudioNetSink(QObject *parent, int sampleRate, bool stereo) : m_bufferIndex(0), m_port(9998) { - memset(m_data, 0, 65536); + std::fill(m_data, m_data+m_dataBlockSize, 0); m_udpSocket = new QUdpSocket(parent); m_rtpBufferAudio = new RTPSink(m_udpSocket, sampleRate, stereo); } @@ -130,6 +132,9 @@ void AudioNetSink::setParameters(Codec codec, bool stereo, int sampleRate) case CodecL8: m_rtpBufferAudio->setPayloadInformation(RTPSink::PayloadL8, sampleRate); break; + case CodecG722: + m_rtpBufferAudio->setPayloadInformation(RTPSink::PayloadG722, sampleRate/2); + break; case CodecL16: // actually no codec default: m_rtpBufferAudio->setPayloadInformation(stereo ? RTPSink::PayloadL16Stereo : RTPSink::PayloadL16Mono, sampleRate); @@ -173,35 +178,44 @@ void AudioNetSink::write(qint16 isample) m_udpSocket->writeDatagram((const char*)m_data, (qint64 ) m_udpBlockSize, m_address, m_port); m_bufferIndex = 0; } - else + + switch(m_codec) { - switch(m_codec) - { - case CodecPCMA: - case CodecPCMU: - { - qint8 *p = (qint8*) &m_data[m_bufferIndex]; - *p = m_audioCompressor.compress8(sample); - m_bufferIndex += sizeof(qint8); - } - break; - case CodecL8: - { - qint8 *p = (qint8*) &m_data[m_bufferIndex]; - *p = sample / 256; - m_bufferIndex += sizeof(qint8); - } - break; - case CodecL16: - default: - { - qint16 *p = (qint16*) &m_data[m_bufferIndex]; - *p = sample; - m_bufferIndex += sizeof(qint16); - } - break; + case CodecPCMA: + case CodecPCMU: + { + qint8 *p = (qint8*) &m_data[m_bufferIndex]; + *p = m_audioCompressor.compress8(sample); + m_bufferIndex += sizeof(qint8); + } + break; + case CodecL8: + { + qint8 *p = (qint8*) &m_data[m_bufferIndex]; + *p = sample / 256; + m_bufferIndex += sizeof(qint8); + } + break; + case CodecG722: + { + qint16 *p = (qint16*) &m_data[m_udpBlockSize + 2*m_bufferIndex]; + *p = sample; + m_bufferIndex += 1; + + if (m_bufferIndex == m_udpBlockSize) { + m_g722.encode((uint8_t *) m_data, (const int16_t*) &m_data[3*m_udpBlockSize], m_udpBlockSize); } } + break; + case CodecL16: + default: + { + qint16 *p = (qint16*) &m_data[m_bufferIndex]; + *p = sample; + m_bufferIndex += sizeof(qint16); + } + break; + } } else if (m_type == SinkRTP) { @@ -220,6 +234,22 @@ void AudioNetSink::write(qint16 isample) m_rtpBufferAudio->write((uint8_t *) &p); } break; + case CodecG722: + { + if (m_bufferIndex >= m_g722BlockSize) + { + static const int sz = m_g722BlockSize / sizeof(int16_t); + uint8_t g722_data[sz]; + m_g722.encode(g722_data, (const int16_t*) m_data, sz); + m_rtpBufferAudio->write(g722_data, sz); + m_bufferIndex = 0; + } + + qint16 *p = (qint16*) &m_data[m_bufferIndex]; + *p = sample; + m_bufferIndex += sizeof(qint16); + } + break; case CodecL16: default: m_rtpBufferAudio->write((uint8_t *) &sample); diff --git a/sdrbase/audio/audionetsink.h b/sdrbase/audio/audionetsink.h index 02db8e709..b60ebdaf4 100644 --- a/sdrbase/audio/audionetsink.h +++ b/sdrbase/audio/audionetsink.h @@ -21,6 +21,7 @@ #include "dsp/dsptypes.h" #include "audiofilter.h" #include "audiocompressor.h" +#include "audiog722.h" #include "export.h" #include @@ -44,7 +45,8 @@ public: CodecL16, //!< Linear 16 bit samples (no formatting) CodecL8, //!< Linear 8 bit samples CodecPCMA, //!< PCM A-law 8 bit samples - CodecPCMU //!< PCM Mu-law 8 bit samples + CodecPCMU, //!< PCM Mu-law 8 bit samples + CodecG722 //!< G722 compressed 8 bit samples 16kS/s in 8kS/s out } Codec; AudioNetSink(QObject *parent); //!< without RTP @@ -66,6 +68,8 @@ public: void moveToThread(QThread *thread); static const int m_udpBlockSize; + static const int m_dataBlockSize = 65536; + static const int m_g722BlockSize = 1024; // size in bytes protected: SinkType m_type; @@ -73,11 +77,12 @@ protected: QUdpSocket *m_udpSocket; RTPSink *m_rtpBufferAudio; AudioCompressor m_audioCompressor; + AudioG722 m_g722; AudioFilter m_audioFilter; int m_sampleRate; uint32_t m_decimation; uint32_t m_decimationCount; - char m_data[65536]; + char m_data[m_dataBlockSize]; unsigned int m_bufferIndex; QHostAddress m_address; unsigned int m_port; diff --git a/sdrbase/audio/audiooutput.h b/sdrbase/audio/audiooutput.h index 5c389c731..e5fea5926 100644 --- a/sdrbase/audio/audiooutput.h +++ b/sdrbase/audio/audiooutput.h @@ -46,7 +46,8 @@ public: UDPCodecL16, //!< Linear 16 bit (no codec) UDPCodecL8, //!< Linear 8 bit UDPCodecALaw, //!< PCM A-law 8 bit - UDPCodecULaw //!< PCM Mu-law 8 bit + UDPCodecULaw, //!< PCM Mu-law 8 bit + UDPCodecG722 //!< G722 compression }; AudioOutput(); diff --git a/sdrbase/util/rtpsink.cpp b/sdrbase/util/rtpsink.cpp index 999b16679..9e92793c7 100644 --- a/sdrbase/util/rtpsink.cpp +++ b/sdrbase/util/rtpsink.cpp @@ -104,6 +104,12 @@ void RTPSink::setPayloadInformation(PayloadType payloadType, int sampleRate) m_packetSamples = m_sampleRate / 50; // 20ms packet samples timestampinc = m_sampleRate / 100; // 2 channels break; + case PayloadG722: + m_sampleBytes = 1; + m_rtpSession.SetDefaultPayloadType(9); + m_packetSamples = m_sampleRate / 50; // 20ms packet samples + timestampinc = m_sampleRate / 50; // 1 channel + break; case PayloadL16Mono: default: m_sampleBytes = 2; @@ -226,10 +232,10 @@ void RTPSink::write(const uint8_t *sampleByte) qCritical("RTPSink::write: cannot write packet: %s", qrtplib::RTPGetErrorString(status).c_str()); } - writeNetBuf(&m_byteBuffer[0], - sampleByte, - elemLength(m_payloadType), - m_sampleBytes, + writeNetBuf(&m_byteBuffer[0], + sampleByte, + elemLength(m_payloadType), + m_sampleBytes, m_endianReverse); m_sampleBufferIndex = 1; } diff --git a/sdrbase/util/rtpsink.h b/sdrbase/util/rtpsink.h index ea69b4549..8f6a421ac 100644 --- a/sdrbase/util/rtpsink.h +++ b/sdrbase/util/rtpsink.h @@ -44,7 +44,8 @@ public: PayloadL16Stereo, PayloadL8, PayloadPCMA8, - PayloadPCMU8 + PayloadPCMU8, + PayloadG722 } PayloadType; RTPSink(QUdpSocket *udpSocket, int sampleRate, bool stereo); diff --git a/sdrgui/gui/audiodialog.cpp b/sdrgui/gui/audiodialog.cpp index 2b59d3af0..167184f84 100644 --- a/sdrgui/gui/audiodialog.cpp +++ b/sdrgui/gui/audiodialog.cpp @@ -1,10 +1,29 @@ -#include "audiodialog.h" +/////////////////////////////////////////////////////////////////////////////////// +// Copyright (C) 2015-2019 F4EXB // +// written by Edouard Griffiths // +// // +// 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 as version 3 of the License, or // +// // +// 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 V3 for more details. // +// // +// You should have received a copy of the GNU General Public License // +// along with this program. If not, see . // +/////////////////////////////////////////////////////////////////////////////////// -#include