From 010f6b7ec6d1be23c432bbdeecc3df369fcb5866 Mon Sep 17 00:00:00 2001 From: f4exb Date: Sun, 17 Feb 2019 06:15:12 +0100 Subject: [PATCH] Copy audio to UDP/RTP: G722 fixes --- sdrbase/audio/audionetsink.cpp | 37 ++++++++++++++------- sdrbase/audio/audionetsink.h | 4 +-- sdrgui/audio.md | 5 +-- sdrgui/gui/audiodialog.cpp | 61 ++++++++++++++++++++++++---------- sdrgui/gui/audiodialog.h | 1 + 5 files changed, 74 insertions(+), 34 deletions(-) diff --git a/sdrbase/audio/audionetsink.cpp b/sdrbase/audio/audionetsink.cpp index 7de15b3ee..1eb8e47a1 100644 --- a/sdrbase/audio/audionetsink.cpp +++ b/sdrbase/audio/audionetsink.cpp @@ -173,10 +173,21 @@ void AudioNetSink::write(qint16 isample) if (m_type == SinkUDP) { - if (m_bufferIndex >= m_udpBlockSize) + if (m_codec == CodecG722) { - m_udpSocket->writeDatagram((const char*)m_data, (qint64 ) m_udpBlockSize, m_address, m_port); - m_bufferIndex = 0; + if (m_bufferIndex >= 2*m_udpBlockSize) + { + m_udpSocket->writeDatagram((const char*) m_data, (qint64 ) m_udpBlockSize, m_address, m_port); + m_bufferIndex = 0; + } + } + else + { + if (m_bufferIndex >= m_udpBlockSize) + { + m_udpSocket->writeDatagram((const char*) m_data, (qint64 ) m_udpBlockSize, m_address, m_port); + m_bufferIndex = 0; + } } switch(m_codec) @@ -202,8 +213,8 @@ void AudioNetSink::write(qint16 isample) *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); + if (m_bufferIndex == 2*m_udpBlockSize) { + m_g722.encode((uint8_t *) m_data, (const int16_t*) &m_data[m_udpBlockSize], 2*m_udpBlockSize); } } break; @@ -236,18 +247,20 @@ void AudioNetSink::write(qint16 isample) break; case CodecG722: { - if (m_bufferIndex >= m_g722BlockSize) + + if (m_bufferIndex >= 2*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_g722.encode((uint8_t *) m_data, (const int16_t*) &m_data[m_g722BlockSize], 2*m_g722BlockSize); m_bufferIndex = 0; } - qint16 *p = (qint16*) &m_data[m_bufferIndex]; + if (m_bufferIndex%2 == 0) { + m_rtpBufferAudio->write((uint8_t *) &m_data[m_bufferIndex/2]); + } + + qint16 *p = (qint16*) &m_data[m_g722BlockSize + 2*m_bufferIndex]; *p = sample; - m_bufferIndex += sizeof(qint16); + m_bufferIndex += 1; } break; case CodecL16: diff --git a/sdrbase/audio/audionetsink.h b/sdrbase/audio/audionetsink.h index b60ebdaf4..55589c7ac 100644 --- a/sdrbase/audio/audionetsink.h +++ b/sdrbase/audio/audionetsink.h @@ -68,8 +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 + static const int m_dataBlockSize = 16384*5; // room for G722 conversion (largest to date) + static const int m_g722BlockSize = 16384; // number of resulting G722 bytes protected: SinkType m_type; diff --git a/sdrgui/audio.md b/sdrgui/audio.md index 843a60b56..1b85bc31f 100644 --- a/sdrgui/audio.md +++ b/sdrgui/audio.md @@ -64,8 +64,9 @@ This is the codec applied before sending the stream via UDP. The following are a - `L16`: Linear 16 bit signed integers (native) - `L8`: Linear 8 bit signed integers - - `PCMA`: A-law compressed 8 bit PCM - - `PCMU`: Mu-law compressed 8 bit PCM + - `PCMA`: A-law compressed 8 bit PCM (requires 8000 Hz sample rate mono) + - `PCMU`: Mu-law compressed 8 bit PCM (requires 8000 Hz sample rate mono) + - `G722`: G722 64 kbit/s (requires 16000 Hz sample rate mono)

1.10 SDP string

diff --git a/sdrgui/gui/audiodialog.cpp b/sdrgui/gui/audiodialog.cpp index 167184f84..d4b3713f5 100644 --- a/sdrgui/gui/audiodialog.cpp +++ b/sdrgui/gui/audiodialog.cpp @@ -234,28 +234,37 @@ void AudioDialogX::on_outputSampleRate_valueChanged(int value) { m_outputDeviceInfo.sampleRate = value; updateOutputSDPString(); + check(); } void AudioDialogX::on_decimationFactor_currentIndexChanged(int index) { m_outputDeviceInfo.udpDecimationFactor = index + 1; updateOutputSDPString(); + check(); } void AudioDialogX::on_outputUDPChannelCodec_currentIndexChanged(int index) { m_outputDeviceInfo.udpChannelCodec = (AudioOutput::UDPChannelCodec) index; updateOutputSDPString(); + check(); } void AudioDialogX::on_outputUDPChannelMode_currentIndexChanged(int index) { m_outputDeviceInfo.udpChannelMode = (AudioOutput::UDPChannelMode) index; updateOutputSDPString(); + check(); } void AudioDialogX::updateOutputDisplay() { + ui->outputSampleRate->blockSignals(true); + ui->outputUDPChannelMode->blockSignals(true); + ui->outputUDPChannelCodec->blockSignals(true); + ui->decimationFactor->blockSignals(true); + ui->outputSampleRate->setValue(m_outputDeviceInfo.sampleRate); ui->outputUDPAddress->setText(m_outputDeviceInfo.udpAddress); ui->outputUDPPort->setText(tr("%1").arg(m_outputDeviceInfo.udpPort)); @@ -264,7 +273,13 @@ void AudioDialogX::updateOutputDisplay() ui->outputUDPChannelMode->setCurrentIndex((int) m_outputDeviceInfo.udpChannelMode); ui->outputUDPChannelCodec->setCurrentIndex((int) m_outputDeviceInfo.udpChannelCodec); ui->decimationFactor->setCurrentIndex(m_outputDeviceInfo.udpDecimationFactor == 0 ? 0 : m_outputDeviceInfo.udpDecimationFactor - 1); + updateOutputSDPString(); + + ui->outputSampleRate->blockSignals(false); + ui->outputUDPChannelMode->blockSignals(false); + ui->outputUDPChannelCodec->blockSignals(false); + ui->decimationFactor->blockSignals(false); } void AudioDialogX::updateOutputDeviceInfo() @@ -285,40 +300,50 @@ void AudioDialogX::updateOutputSDPString() int nChannels = m_outputDeviceInfo.udpChannelMode == AudioOutput::UDPChannelStereo ? 2 : 1; uint32_t decimationFactor = m_outputDeviceInfo.udpDecimationFactor == 0 ? 1 : m_outputDeviceInfo.udpDecimationFactor; + switch (m_outputDeviceInfo.udpChannelCodec) + { + case AudioOutput::UDPCodecALaw: + format = "PCMA"; + break; + case AudioOutput::UDPCodecULaw: + format = "PCMU"; + break; + case AudioOutput::UDPCodecG722: + format = "G722"; + break; + case AudioOutput::UDPCodecL8: + format = "L8"; + break; + case AudioOutput::UDPCodecL16: + default: + format = "L16"; + break; + } + + ui->outputSDPText->setText(tr("%1/%2/%3").arg(format).arg(m_outputDeviceInfo.sampleRate/decimationFactor).arg(nChannels)); +} + +void AudioDialogX::check() +{ + 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)); } diff --git a/sdrgui/gui/audiodialog.h b/sdrgui/gui/audiodialog.h index 9305a582e..4c237fbce 100644 --- a/sdrgui/gui/audiodialog.h +++ b/sdrgui/gui/audiodialog.h @@ -39,6 +39,7 @@ private: private slots: void accept(); void reject(); + void check(); void on_audioInTree_currentItemChanged(QTreeWidgetItem* currentItem, QTreeWidgetItem* previousItem); void on_audioOutTree_currentItemChanged(QTreeWidgetItem* currentItem, QTreeWidgetItem* previousItem); void on_inputVolume_valueChanged(int value);