Copy to UDP/RTP: implemented G722

pull/295/head
f4exb 2019-02-17 03:40:11 +01:00
rodzic 752e71c402
commit 202d67f141
7 zmienionych plików z 142 dodań i 58 usunięć

Wyświetl plik

@ -15,6 +15,8 @@
// along with this program. If not, see <http://www.gnu.org/licenses/>. //
///////////////////////////////////////////////////////////////////////////////////
#include <algorithm>
#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);

Wyświetl plik

@ -21,6 +21,7 @@
#include "dsp/dsptypes.h"
#include "audiofilter.h"
#include "audiocompressor.h"
#include "audiog722.h"
#include "export.h"
#include <QObject>
@ -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;

Wyświetl plik

@ -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();

Wyświetl plik

@ -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;
}

Wyświetl plik

@ -44,7 +44,8 @@ public:
PayloadL16Stereo,
PayloadL8,
PayloadPCMA8,
PayloadPCMU8
PayloadPCMU8,
PayloadG722
} PayloadType;
RTPSink(QUdpSocket *udpSocket, int sampleRate, bool stereo);

Wyświetl plik

@ -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 <http://www.gnu.org/licenses/>. //
///////////////////////////////////////////////////////////////////////////////////
#include <audio/audiodevicemanager.h>
#include <QTreeWidgetItem>
#include "ui_audiodialog.h"
#include <math.h>
#include <QTreeWidgetItem>
#include <QMessageBox>
#include "audio/audiodevicemanager.h"
#include "audiodialog.h"
#include "ui_audiodialog.h"
AudioDialogX::AudioDialogX(AudioDeviceManager* audioDeviceManager, QWidget* parent) :
QDialog(parent),
ui(new Ui::AudioDialog),
@ -263,26 +282,43 @@ void AudioDialogX::updateOutputDeviceInfo()
void AudioDialogX::updateOutputSDPString()
{
QString format;
switch(m_outputDeviceInfo.udpChannelCodec)
{
case AudioOutput::UDPCodecALaw:
format = "PCMA";
break;
case AudioOutput::UDPCodecULaw:
format = "PCMU";
break;
case AudioOutput::UDPCodecL8:
format = "L8";
break;
case AudioOutput::UDPCodecL16:
default:
format = "L16";
break;
}
int nChannels = m_outputDeviceInfo.udpChannelMode == AudioOutput::UDPChannelStereo ? 2 : 1;
uint32_t decimationFactor = m_outputDeviceInfo.udpDecimationFactor == 0 ? 1 : m_outputDeviceInfo.udpDecimationFactor;
if (m_outputDeviceInfo.udpChannelCodec == AudioOutput::UDPCodecALaw)
{
format = "PCMA";
if ((nChannels != 1) || (m_outputDeviceInfo.sampleRate/decimationFactor != 8000)) {
QMessageBox::information(this, tr("Message"), tr("PCMA must be 8000 Hz single channel"));
}
}
else if (m_outputDeviceInfo.udpChannelCodec == AudioOutput::UDPCodecULaw)
{
format = "PCMU";
if ((nChannels != 1) || (m_outputDeviceInfo.sampleRate/decimationFactor != 8000)) {
QMessageBox::information(this, tr("Message"), tr("PCMU must be 8000 Hz single channel"));
}
}
else if (m_outputDeviceInfo.udpChannelCodec == AudioOutput::UDPCodecG722)
{
format = "G722";
if ((nChannels != 1) || (m_outputDeviceInfo.sampleRate/decimationFactor != 16000)) {
QMessageBox::information(this, tr("Message"), tr("G722 must be 16000 Hz single channel"));
}
}
else if (m_outputDeviceInfo.udpChannelCodec == AudioOutput::UDPCodecL8)
{
format = "L8";
}
else if (m_outputDeviceInfo.udpChannelCodec == AudioOutput::UDPCodecL16)
{
format = "L16";
}
else
{
QMessageBox::information(this, tr("Message"), tr("Unknown codec"));
format = "UNK";
}
ui->outputSDPText->setText(tr("%1/%2/%3").arg(format).arg(m_outputDeviceInfo.sampleRate/decimationFactor).arg(nChannels));
}

Wyświetl plik

@ -255,6 +255,11 @@
<string>PCMU</string>
</property>
</item>
<item>
<property name="text">
<string>G722</string>
</property>
</item>
</widget>
</item>
<item>