From c1fb4bb46cb60b903ff554af100006c037a4cbb6 Mon Sep 17 00:00:00 2001 From: f4exb Date: Mon, 18 Feb 2019 02:30:43 +0100 Subject: [PATCH] Copy audio to UDP/RTP: Opus environment setting --- debian/control | 4 ++-- sdrbase/audio/audionetsink.cpp | 4 ++++ sdrbase/audio/audionetsink.h | 4 +++- sdrbase/audio/audiooutput.h | 3 ++- sdrbase/util/rtpsink.cpp | 6 ++++++ sdrbase/util/rtpsink.h | 3 ++- sdrgui/audio.md | 20 +++++++++++++++----- sdrgui/gui/audiodialog.cpp | 3 +++ sdrgui/gui/audiodialog.ui | 5 +++++ swagger/sdrangel/examples/rx_test.py | 2 +- 10 files changed, 43 insertions(+), 11 deletions(-) diff --git a/debian/control b/debian/control index eebac6bb5..4600f3974 100644 --- a/debian/control +++ b/debian/control @@ -10,13 +10,13 @@ Homepage: https://github.com/f4exb/sdrangel Package: sdrangel Architecture: any -Depends: libc6, libasound2, libfftw3-single3, libgcc1, libgl1-mesa-glx, libqt5core5a, libqt5gui5, libqt5multimedia5, libqt5network5, libqt5opengl5, libqt5widgets5, libqt5multimedia5-plugins, libstdc++6, libusb-1.0-0, libopencv-dev, pulseaudio, libxml2, ffmpeg, libavcodec-dev, libavformat-dev, ${shlibs:Depends}, ${misc:Depends} +Depends: libc6, libasound2, libfftw3-single3, libgcc1, libgl1-mesa-glx, libqt5core5a, libqt5gui5, libqt5multimedia5, libqt5network5, libqt5opengl5, libqt5widgets5, libqt5multimedia5-plugins, libstdc++6, libusb-1.0-0, libopencv-dev, pulseaudio, libxml2, ffmpeg, libavcodec-dev, libavformat-dev, libopus-dev, ${shlibs:Depends}, ${misc:Depends} Description: SDR/Analyzer/Generator front-end for various hardware SDR/Analyzer/Generator front-end for Airspy, BladeRF, HackRF, RTL-SDR, FunCube, LimeSDR, PlutoSDR. Also File source and sink for I/Q samples, network I/Q sources with remote instance. Based on Qt5 framework and OpenGL for the spectrum and scope rendering. Builds on Linux, Windows and Mac O/S - Reception modes supported: + Reception modes supported: Analog: AM, ATV, NFM, WFM, SSB, broadcast FM Digital: D-Star, Yaesu SF, DMR, dPMR, LoRa Analyzer: Generic channel diff --git a/sdrbase/audio/audionetsink.cpp b/sdrbase/audio/audionetsink.cpp index 974c23f37..8410faa07 100644 --- a/sdrbase/audio/audionetsink.cpp +++ b/sdrbase/audio/audionetsink.cpp @@ -136,6 +136,9 @@ void AudioNetSink::setParameters(Codec codec, bool stereo, int sampleRate) case CodecG722: m_rtpBufferAudio->setPayloadInformation(RTPSink::PayloadG722, sampleRate/2); break; + case CodecOpus: + m_rtpBufferAudio->setPayloadInformation(RTPSink::PayloadOpus, sampleRate); + break; case CodecL16: // actually no codec default: m_rtpBufferAudio->setPayloadInformation(stereo ? RTPSink::PayloadL16Stereo : RTPSink::PayloadL16Mono, sampleRate); @@ -165,6 +168,7 @@ void AudioNetSink::setDecimationFilters() case CodecG722: m_audioFilter.setDecimFilters(m_sampleRate, decimatedSampleRate, 7000.0, 50.0); break; + case CodecOpus: case CodecL8: case CodecL16: default: diff --git a/sdrbase/audio/audionetsink.h b/sdrbase/audio/audionetsink.h index 52410f547..97b283b4d 100644 --- a/sdrbase/audio/audionetsink.h +++ b/sdrbase/audio/audionetsink.h @@ -46,7 +46,8 @@ public: CodecL8, //!< Linear 8 bit samples CodecPCMA, //!< PCM A-law 8 bit samples CodecPCMU, //!< PCM Mu-law 8 bit samples - CodecG722 //!< G722 compressed 8 bit samples 16kS/s in 8kS/s out + CodecG722, //!< G722 compressed 8 bit samples 16kS/s in 8kS/s out + CodecOpus //!< Opus compressed 8 bit samples at 64kbits/s (8kS/s out). Various input sample rates } Codec; AudioNetSink(QObject *parent); //!< without RTP @@ -70,6 +71,7 @@ public: static const int m_udpBlockSize; 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) + static const int m_opusBlockSize = 960*4; // provision for 20ms of 2 int16 channels at 48 kS/s protected: void setDecimationFilters(); diff --git a/sdrbase/audio/audiooutput.h b/sdrbase/audio/audiooutput.h index e5fea5926..cdc579287 100644 --- a/sdrbase/audio/audiooutput.h +++ b/sdrbase/audio/audiooutput.h @@ -47,7 +47,8 @@ public: UDPCodecL8, //!< Linear 8 bit UDPCodecALaw, //!< PCM A-law 8 bit UDPCodecULaw, //!< PCM Mu-law 8 bit - UDPCodecG722 //!< G722 compression + UDPCodecG722, //!< G722 compression + UDPCodecOpus //!< Opus compression }; AudioOutput(); diff --git a/sdrbase/util/rtpsink.cpp b/sdrbase/util/rtpsink.cpp index 9e92793c7..0073d7ae7 100644 --- a/sdrbase/util/rtpsink.cpp +++ b/sdrbase/util/rtpsink.cpp @@ -110,6 +110,12 @@ void RTPSink::setPayloadInformation(PayloadType payloadType, int sampleRate) m_packetSamples = m_sampleRate / 50; // 20ms packet samples timestampinc = m_sampleRate / 50; // 1 channel break; + case PayloadOpus: + m_sampleBytes = 1; + m_rtpSession.SetDefaultPayloadType(101); + m_packetSamples = 160; // Fixed 20ms @ 64 kbits/s packet samples + timestampinc = 160; // 1 channel + break; case PayloadL16Mono: default: m_sampleBytes = 2; diff --git a/sdrbase/util/rtpsink.h b/sdrbase/util/rtpsink.h index 8f6a421ac..f7323868f 100644 --- a/sdrbase/util/rtpsink.h +++ b/sdrbase/util/rtpsink.h @@ -45,7 +45,8 @@ public: PayloadL8, PayloadPCMA8, PayloadPCMU8, - PayloadG722 + PayloadG722, + PayloadOpus } PayloadType; RTPSink(QUdpSocket *udpSocket, int sampleRate, bool stereo); diff --git a/sdrgui/audio.md b/sdrgui/audio.md index cf3a0ccd9..e93371980 100644 --- a/sdrgui/audio.md +++ b/sdrgui/audio.md @@ -67,10 +67,11 @@ This is the codec applied before sending the stream via UDP. The following are a - `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) - + - `OPUS` : Opus 64 kbit/s +

1.10 SDP string

-This is the SDP string representatiopn of the stream sent via UDP (RTP). In SDP files it is used on the `a=rtpmap`line (See 1.14). It can be used to check the effect of settings 1.5, 1.8 and 1.9. +This is the SDP string representatiopn of the stream sent via UDP (RTP). In SDP files it is used on the `a=rtpmap`line (See 1.14). It can be used to check the effect of settings 1.5, 1.8 and 1.9.

1.11 UDP address

@@ -88,18 +89,19 @@ Use this button to activate or de-activate the copy of the audio stream to UDP s Check this box to activate the RTP protocol over UDP. RTP parameters are as follows: - - Payload type: + - Payload type: - codec `L16`, `L8`: 96 + - codec `OPUS`: 101 - codec `PCMA`: 8 - codec `PCMU`: 0 - 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) + - 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. + - codec `G722`, `OPUS`: 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) @@ -127,6 +129,14 @@ m=audio 9998 RTP/AVP 9 a=rtpmap:9 G722/8000/1 ``` +For Opus mono: + +``` +c=IN IP4 192.168.0.34 +m=audio 9998 RTP/AVP 101 +a=rtpmap:101 opus/48000/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 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. diff --git a/sdrgui/gui/audiodialog.cpp b/sdrgui/gui/audiodialog.cpp index 06763a90c..d1ebac714 100644 --- a/sdrgui/gui/audiodialog.cpp +++ b/sdrgui/gui/audiodialog.cpp @@ -315,6 +315,9 @@ void AudioDialogX::updateOutputSDPString() case AudioOutput::UDPCodecL8: format = "L8"; break; + case AudioOutput::UDPCodecOpus: + format = "opus"; + break; case AudioOutput::UDPCodecL16: default: format = "L16"; diff --git a/sdrgui/gui/audiodialog.ui b/sdrgui/gui/audiodialog.ui index e422da931..b48550b03 100644 --- a/sdrgui/gui/audiodialog.ui +++ b/sdrgui/gui/audiodialog.ui @@ -260,6 +260,11 @@ G722 + + + Opus + + diff --git a/swagger/sdrangel/examples/rx_test.py b/swagger/sdrangel/examples/rx_test.py index b3dad9f4c..aa6026dd1 100755 --- a/swagger/sdrangel/examples/rx_test.py +++ b/swagger/sdrangel/examples/rx_test.py @@ -46,7 +46,7 @@ def getInputOptions(): parser.add_option("--audio-address", dest="audio_address", help="Audio: UDP destination address", metavar="IP_ADDRESS", type="string") parser.add_option("--audio-port", dest="audio_port", help="Audio: UDP destination port", metavar="IP_PORT", type="int") parser.add_option("--audio-channels", dest="audio_channels", help="Audio: UDP mode (0: L only 1: R only 2: L+R mono 3: LR stereo)", metavar="ENUM_INT", type="int") - parser.add_option("--audio-codec", dest="audio_codec", help="Audio: codec to use for UDP (0: L16, 1: L8, 2: PCMA, 3: PCMU, 4: G722)", metavar="ENUM_INT", type="int") + parser.add_option("--audio-codec", dest="audio_codec", help="Audio: codec to use for UDP (0: L16, 1: L8, 2: PCMA, 3: PCMU, 4: G722, 5: Opus)", metavar="ENUM_INT", type="int") parser.add_option("--audio-decim", dest="audio_decim", help="Audio. decimation to apply for UDP (1 to 6)", metavar="INT", type="int") parser.add_option("--baud-rate", dest="baud_rate", help="DSD: baud rate in Baud", metavar="BAUD", type="int", default=4800) parser.add_option("--fm-dev", dest="fm_deviation", help="DSD: expected FM deviation", metavar="FREQ", type="int", default=5400)