From d98c4cd3ac89c0b2df4392443d800622d6801eb9 Mon Sep 17 00:00:00 2001 From: f4exb Date: Sun, 17 Feb 2019 13:32:17 +0100 Subject: [PATCH] Copy audio to UDP/RTP: adapt decimation filter to codec also --- sdrbase/audio/audiofilter.cpp | 11 +++++------ sdrbase/audio/audiofilter.h | 2 +- sdrbase/audio/audiog722.cpp | 5 ++++- sdrbase/audio/audionetsink.cpp | 28 +++++++++++++++++++++++++--- sdrbase/audio/audionetsink.h | 6 ++++-- sdrgui/audio.md | 26 +++++++++++++++++++------- 6 files changed, 58 insertions(+), 20 deletions(-) diff --git a/sdrbase/audio/audiofilter.cpp b/sdrbase/audio/audiofilter.cpp index 5cf963c96..980df959a 100644 --- a/sdrbase/audio/audiofilter.cpp +++ b/sdrbase/audio/audiofilter.cpp @@ -37,14 +37,13 @@ AudioFilter::~AudioFilter() {} -void AudioFilter::setDecimFilters(int sr, uint32_t decim) +void AudioFilter::setDecimFilters(int srHigh, int srLow, float fcHigh, float fcLow) { - int downSR = sr / (decim == 0 ? 1 : decim); - double fcH = (0.45 * downSR) / (sr <= 0 ? 1 : sr); // high cut frequency normalized to SR - double fcL = 300.0 / downSR; // low cut frequency normalized to downsampled SR + double fcNormHigh = fcHigh / srHigh; + double fcNormLow = fcLow / srLow; - calculate2(false, fcH, m_lpva, m_lpvb); - calculate2(true, fcL, m_hpva, m_hpvb); + calculate2(false, fcNormHigh, m_lpva, m_lpvb); + calculate2(true, fcNormLow, m_hpva, m_hpvb); m_filterLP.setCoeffs(m_lpva, m_lpvb); m_filterHP.setCoeffs(m_hpva, m_hpvb); diff --git a/sdrbase/audio/audiofilter.h b/sdrbase/audio/audiofilter.h index de2dbddf6..935351b31 100644 --- a/sdrbase/audio/audiofilter.h +++ b/sdrbase/audio/audiofilter.h @@ -47,7 +47,7 @@ public: void useHP(bool useHP) { m_useHP = useHP; } bool usesHP() const { return m_useHP; } - void setDecimFilters(int sr, uint32_t decim); + void setDecimFilters(int srHigh, int srLow, float fcHigh, float fcLow); float run(const float& sample); float runHP(const float& sample); float runLP(const float& sample); diff --git a/sdrbase/audio/audiog722.cpp b/sdrbase/audio/audiog722.cpp index ad3fa74c0..addbb9a5b 100644 --- a/sdrbase/audio/audiog722.cpp +++ b/sdrbase/audio/audiog722.cpp @@ -93,6 +93,9 @@ void AudioG722::g722_encode_state::init(int rate, int options) out_buffer = 0; out_bits = 0; + char *pBand = (char *) band; + std::fill(pBand, pBand + sizeof(band), 0); + if (rate == 48000) { bits_per_sample = 6; } else if (rate == 56000) { @@ -263,8 +266,8 @@ int AudioG722::encode(uint8_t g722_data[], const int16_t amp[], int len) { if (state.itu_test_mode) { - xlow = xhigh = amp[j++] >> 1; + xlow = xhigh; } else { diff --git a/sdrbase/audio/audionetsink.cpp b/sdrbase/audio/audionetsink.cpp index 1eb8e47a1..974c23f37 100644 --- a/sdrbase/audio/audionetsink.cpp +++ b/sdrbase/audio/audionetsink.cpp @@ -115,7 +115,8 @@ void AudioNetSink::setParameters(Codec codec, bool stereo, int sampleRate) m_codec = codec; m_sampleRate = sampleRate; - m_audioFilter.setDecimFilters(m_sampleRate, m_decimation); + + setDecimationFilters(); if (m_rtpBufferAudio) { @@ -147,17 +148,38 @@ void AudioNetSink::setDecimation(uint32_t decimation) { m_decimation = decimation < 1 ? 1 : decimation > 6 ? 6 : decimation; qDebug() << "AudioNetSink::setDecimation: " << m_decimation << " from: " << decimation; - m_audioFilter.setDecimFilters(m_sampleRate, m_decimation); + setDecimationFilters(); m_decimationCount = 0; } +void AudioNetSink::setDecimationFilters() +{ + int decimatedSampleRate = m_sampleRate / m_decimation; + + switch (m_codec) + { + case CodecPCMA: + case CodecPCMU: + m_audioFilter.setDecimFilters(m_sampleRate, decimatedSampleRate, 3300.0, 300.0); + break; + case CodecG722: + m_audioFilter.setDecimFilters(m_sampleRate, decimatedSampleRate, 7000.0, 50.0); + break; + case CodecL8: + case CodecL16: + default: + m_audioFilter.setDecimFilters(m_sampleRate, decimatedSampleRate, 0.45*decimatedSampleRate, 50.0); + break; + } +} + void AudioNetSink::write(qint16 isample) { qint16& sample = isample; if (m_decimation > 1) { - float lpSample = m_audioFilter.runLP(sample / 32768.0f); + float lpSample = m_audioFilter.run(sample / 32768.0f); if (m_decimationCount >= m_decimation - 1) { diff --git a/sdrbase/audio/audionetsink.h b/sdrbase/audio/audionetsink.h index 55589c7ac..52410f547 100644 --- a/sdrbase/audio/audionetsink.h +++ b/sdrbase/audio/audionetsink.h @@ -68,10 +68,12 @@ public: void moveToThread(QThread *thread); static const int m_udpBlockSize; - 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 + static const int m_dataBlockSize = 65536; // room for G722 conversion (64000 = 12800*5 largest to date) + static const int m_g722BlockSize = 12800; // number of resulting G722 bytes (80*20ms frames) protected: + void setDecimationFilters(); + SinkType m_type; Codec m_codec; QUdpSocket *m_udpSocket; diff --git a/sdrgui/audio.md b/sdrgui/audio.md index 1b85bc31f..cf3a0ccd9 100644 --- a/sdrgui/audio.md +++ b/sdrgui/audio.md @@ -1,8 +1,8 @@

Audio management

Audio devices can be controlled with two dialogs: - - The Audio preferences dialog: set audio device parameters. The dialog shows one tab for output and another tab for input devices - - The Audio selection dialog: each channel plugin having audio output or input can show this dialog to select which device to use to direct output or input streams. This dialog opens by right clicking on a button that depends on the plugin (see plugin documentation). + - The Audio preferences dialog: set audio device parameters. The dialog shows one tab for output and another tab for input devices. Detailed in sections 1 and 2. + - The Audio selection dialog: each channel plugin having audio output or input can show this dialog to select which device to use to direct output or input streams. This dialog opens by right clicking on a button that depends on the plugin (see plugin documentation). Detailed in section 3.

1. Audio output preferences

@@ -64,8 +64,8 @@ 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 (requires 8000 Hz sample rate mono) - - `PCMU`: Mu-law compressed 8 bit PCM (requires 8000 Hz sample rate mono) + - `PCMA`: A-law 8 bit PCM (requires 8000 Hz sample rate mono) + - `PCMU`: Mu-law 8 bit PCM (requires 8000 Hz sample rate mono) - `G722`: G722 64 kbit/s (requires 16000 Hz sample rate mono)

1.10 SDP string

@@ -92,10 +92,14 @@ Check this box to activate the RTP protocol over UDP. RTP parameters are as foll - codec `L16`, `L8`: 96 - codec `PCMA`: 8 - codec `PCMU`: 0 - - Sample rate: the sample rate of the corresponding audio device + - codec `G722`: 9 + - Sample rate: the resulting stream sample rate after decimation and possible compression: + - codec `PCMA`, `PCMU`: must be 8000 S/s + - codec `G722`: must be 8000 S/s (16000 S/s input before compression) - Sample format: - codec `L16`: 16 bit integer signed (S16LE) - codec `L8`, `PCMA`, `PCMU`: 8 bit integer signed (S8) + - codec `G722`: 8 bit unsigned integer. Note that this is the stream compressed to 64 kbits/s. - Channels: 1 for mono (Left, Right and Mixed copy channels mode); 2 for stereo (Stereo copy channels mode) - Address and port: destination address and port (local on the client machine) @@ -107,7 +111,7 @@ m=audio 9998 RTP/AVP 96 a=rtpmap:96 L16/48000/1 ``` -For PCMA at 8k sample rate which is a popular format the contents of the file would be as follows: +For PCMA or PCMU (here PCMA): ``` c=IN IP4 192.168.0.34 @@ -115,9 +119,17 @@ m=audio 9998 RTP/AVP 8 a=rtpmap:8 PCMA/8000/1 ``` +For G722: + +``` +c=IN IP4 192.168.0.34 +m=audio 9998 RTP/AVP 9 +a=rtpmap:9 G722/8000/1 +``` + ☞ Note that on Android clients VLC has trouble working with the RTP stream (choppy audio, hanging unexpectedly...) therefore [MX player](https://play.google.com/store/apps/details?id=com.mxtech.videoplayer.ad&hl=en) is recommended. -☞ With PCMA and PCMU codecs it is possible to listen to the RTP stream directly in the browser using a [Janus WebRTC server](https://janus.conf.meetecho.com/). Please refer to the Wiki for more instructions. +☞ With PCMA and PCMU and more recently G722 codecs it is possible to listen to the RTP stream directly in the browser using a [Janus WebRTC server](https://janus.conf.meetecho.com/). Please refer to the Wiki page "Networking audio" for detailed instructions.

1.15 Cleanup registrations not in the list