diff --git a/sdrbase/audio/audiocompressor.cpp b/sdrbase/audio/audiocompressor.cpp index fd25257f7..aced6a949 100644 --- a/sdrbase/audio/audiocompressor.cpp +++ b/sdrbase/audio/audiocompressor.cpp @@ -17,6 +17,11 @@ #include "audiocompressor.h" +const uint16_t AudioCompressor::ALAW_MAX = 0xFFF; +const uint16_t AudioCompressor::MULAW_MAX = 0x1FFF; +const uint16_t AudioCompressor::MULAW_BIAS = 33; + + AudioCompressor::AudioCompressor() { fillLUT2(); @@ -79,9 +84,117 @@ void AudioCompressor::fillLUT2() } } +void AudioCompressor::fillALaw() +{ + for (int i=0; i<8*4096; i++) { + m_lut[i] = ALaw_Encode(i/2 + 16384); + } +} + +void AudioCompressor::fillULaw() +{ + for (int i=0; i<8*4096; i++) { + m_lut[i] = MuLaw_Encode(i/2 + 16384); + } +} + int16_t AudioCompressor::compress(int16_t sample) { int16_t sign = sample < 0 ? -1 : 1; int16_t abs = sample < 0 ? -sample : sample; return sign * m_lut[abs]; } + +int8_t AudioCompressor::compress8(int16_t sample) +{ + return ALaw_Encode(sample); + //return m_lut[sample/2 + 16384]; +} + +/* http://dystopiancode.blogspot.com/2012/02/pcm-law-and-u-law-companding-algorithms.html + * + * First, the number is verified is its negative. If the number is negative he will be made + * positive and the sign variable (by default 0) will contain the value 0x80 + * (so when it's OR-ed to the coded result it will determine it's sign). + * + * Since the A-Law algorithm considers numbers in the range 0x000 - 0xFFF + * (without considering the sign bit), if a number is bigger than 0xFFF, it will automatically + * made equal to 0xFFF in order to avoid further problems. + * + * The first step in determining the coded value is finding the position of the first bit + * who has a 1 value (excluding the sign bit). The search is started from position 11 + * and is continued until a bit with the value 1 is find or until a position smaller than 5 is met. + * + * If the position is smaller than 5 (there was no 1 bit found on the positions 11-5), + * the least significant byte of the coded number is made equal the the bits 5,4,3,2 + * of the original number. Otherwise the least significant bit of the coded number is equal + * to the first four bits who come after the first 1 bit encountered. + * + * In the end, the most significant byte of the coded number is computed according to the position + * of the first 1 bit (if not such this was found, then the position is considered). + * + * Also, before returning the result, the even bits of the result will be complemented + * (by XOR-ing with 0x55). + */ +int8_t AudioCompressor::ALaw_Encode(int16_t number) +{ + uint16_t mask = 0x800; + uint8_t sign = 0; + uint8_t position = 11; + uint8_t lsb = 0; + + if (number < 0) + { + number = -number; + sign = 0x80; + } + + if (number > ALAW_MAX) { + number = ALAW_MAX; + } + + for (; ((number & mask) != mask && position >= 5); mask >>= 1, position--) { + } + + lsb = (number >> ((position == 4) ? (1) : (position - 4))) & 0x0f; + + return (sign | ((position - 4) << 4) | lsb) ^ 0x55; +} + +/* http://dystopiancode.blogspot.com/2012/02/pcm-law-and-u-law-companding-algorithms.html + * + * The µ-Law compression algorithm is very similar to the A-Law compression algorithm. + * The main difference is that the µ-Law uses 13 bits instead of 12 bits, so the position + * variable will be initialized with 12 instead of 11. In order to make sure that there will be + * no number without a 1 bit in the first 12-5 positions, a bias value is added to the number + * (in this case 33). So, since there is no special case (numbers who do not have a 1 bit in + * the first 12-5 positions), this makes the algorithm less complex by eliminating some condtions. + * + * Also in the end all bits are complemented, not just the even ones. + */ +int8_t AudioCompressor::MuLaw_Encode(int16_t number) +{ + uint16_t mask = 0x1000; + uint8_t sign = 0; + uint8_t position = 12; + uint8_t lsb = 0; + + if (number < 0) + { + number = -number; + sign = 0x80; + } + + number += MULAW_BIAS; + + if (number > MULAW_MAX) { + number = MULAW_MAX; + } + + for (; ((number & mask) != mask && position >= 5); mask >>= 1, position--) { + } + + lsb = (number >> (position - 4)) & 0x0f; + + return (~(sign | ((position - 5) << 4) | lsb)); +} diff --git a/sdrbase/audio/audiocompressor.h b/sdrbase/audio/audiocompressor.h index 7f7ba0edd..5ad144ad5 100644 --- a/sdrbase/audio/audiocompressor.h +++ b/sdrbase/audio/audiocompressor.h @@ -28,10 +28,20 @@ public: ~AudioCompressor(); void fillLUT(); //!< 4 bands void fillLUT2(); //!< 8 bands (default) + void fillALaw(); //!< A-law compression to 8 bits + void fillULaw(); //!< u-law compression to 8 bits int16_t compress(int16_t sample); + int8_t compress8(int16_t sample); private: + int8_t ALaw_Encode(int16_t number); + int8_t MuLaw_Encode(int16_t number); + int16_t m_lut[32768]; + static const uint16_t ALAW_MAX; + static const uint16_t MULAW_MAX; + static const uint16_t MULAW_BIAS; + }; diff --git a/sdrbase/audio/audiodevicemanager.cpp b/sdrbase/audio/audiodevicemanager.cpp index 1b6d90c8d..40a599fa7 100644 --- a/sdrbase/audio/audiodevicemanager.cpp +++ b/sdrbase/audio/audiodevicemanager.cpp @@ -42,15 +42,30 @@ QDataStream& operator>>(QDataStream& ds, AudioDeviceManager::InputDeviceInfo& in QDataStream& operator<<(QDataStream& ds, const AudioDeviceManager::OutputDeviceInfo& info) { - ds << info.sampleRate << info.udpAddress << info.udpPort << info.copyToUDP << info.udpUseRTP << (int) info.udpChannelMode; + ds << info.sampleRate + << info.udpAddress + << info.udpPort + << info.copyToUDP + << info.udpUseRTP + << (int) info.udpChannelMode + << (int) info.udpChannelCodec; return ds; } QDataStream& operator>>(QDataStream& ds, AudioDeviceManager::OutputDeviceInfo& info) { int intChannelMode; - ds >> info.sampleRate >> info.udpAddress >> info.udpPort >> info.copyToUDP >> info.udpUseRTP >> intChannelMode; + int intChannelCodec; + + ds >> info.sampleRate + >> info.udpAddress + >> info.udpPort + >> info.copyToUDP + >> info.udpUseRTP + >> intChannelMode + >> intChannelCodec; info.udpChannelMode = (AudioOutput::UDPChannelMode) intChannelMode; + info.udpChannelCodec = (AudioOutput::UDPChannelCodec) intChannelCodec; return ds; } @@ -346,6 +361,7 @@ void AudioDeviceManager::startAudioOutput(int outputDeviceIndex) bool copyAudioToUDP; bool udpUseRTP; AudioOutput::UDPChannelMode udpChannelMode; + AudioOutput::UDPChannelCodec udpChannelCodec; QString deviceName; if (getOutputDeviceName(outputDeviceIndex, deviceName)) @@ -358,6 +374,7 @@ void AudioDeviceManager::startAudioOutput(int outputDeviceIndex) copyAudioToUDP = false; udpUseRTP = false; udpChannelMode = AudioOutput::UDPChannelLeft; + udpChannelCodec = AudioOutput::UDPCodecL16; } else { @@ -367,6 +384,7 @@ void AudioDeviceManager::startAudioOutput(int outputDeviceIndex) copyAudioToUDP = m_audioOutputInfos[deviceName].copyToUDP; udpUseRTP = m_audioOutputInfos[deviceName].udpUseRTP; udpChannelMode = m_audioOutputInfos[deviceName].udpChannelMode; + udpChannelCodec = m_audioOutputInfos[deviceName].udpChannelCodec; } m_audioOutputs[outputDeviceIndex]->start(outputDeviceIndex, sampleRate); @@ -376,6 +394,7 @@ void AudioDeviceManager::startAudioOutput(int outputDeviceIndex) m_audioOutputInfos[deviceName].copyToUDP = copyAudioToUDP; m_audioOutputInfos[deviceName].udpUseRTP = udpUseRTP; m_audioOutputInfos[deviceName].udpChannelMode = udpChannelMode; + m_audioOutputInfos[deviceName].udpChannelCodec = udpChannelCodec; } else { @@ -588,7 +607,7 @@ void AudioDeviceManager::setOutputDeviceInfo(int outputDeviceIndex, const Output audioOutput->setUdpDestination(deviceInfo.udpAddress, deviceInfo.udpPort); audioOutput->setUdpUseRTP(deviceInfo.udpUseRTP); audioOutput->setUdpChannelMode(deviceInfo.udpChannelMode); - audioOutput->setUdpChannelFormat(deviceInfo.udpChannelMode == AudioOutput::UDPChannelStereo, deviceInfo.sampleRate); + audioOutput->setUdpChannelFormat(deviceInfo.udpChannelCodec, deviceInfo.udpChannelMode == AudioOutput::UDPChannelStereo, deviceInfo.sampleRate); qDebug("AudioDeviceManager::setOutputDeviceInfo: index: %d device: %s updated", outputDeviceIndex, qPrintable(deviceName)); @@ -756,6 +775,7 @@ void AudioDeviceManager::debugAudioOutputInfos() const << " udpPort: " << it.value().udpPort << " copyToUDP: " << it.value().copyToUDP << " udpUseRTP: " << it.value().udpUseRTP - << " udpChannelMode: " << (int) it.value().udpChannelMode; + << " udpChannelMode: " << (int) it.value().udpChannelMode + << " udpChannelCodec: " << (int) it.value().udpChannelCodec; } } diff --git a/sdrbase/audio/audiodevicemanager.h b/sdrbase/audio/audiodevicemanager.h index 4ee715bc6..c1240d208 100644 --- a/sdrbase/audio/audiodevicemanager.h +++ b/sdrbase/audio/audiodevicemanager.h @@ -75,6 +75,7 @@ public: bool copyToUDP; bool udpUseRTP; AudioOutput::UDPChannelMode udpChannelMode; + AudioOutput::UDPChannelCodec udpChannelCodec; friend QDataStream& operator<<(QDataStream& ds, const OutputDeviceInfo& info); friend QDataStream& operator>>(QDataStream& ds, OutputDeviceInfo& info); }; diff --git a/sdrbase/audio/audionetsink.cpp b/sdrbase/audio/audionetsink.cpp index 4da761a5e..f11415d00 100644 --- a/sdrbase/audio/audionetsink.cpp +++ b/sdrbase/audio/audionetsink.cpp @@ -18,12 +18,14 @@ #include "audionetsink.h" #include "util/rtpsink.h" +#include #include const int AudioNetSink::m_udpBlockSize = 512; AudioNetSink::AudioNetSink(QObject *parent) : m_type(SinkUDP), + m_codec(CodecL16), m_rtpBufferAudio(0), m_bufferIndex(0), m_port(9998) @@ -34,6 +36,7 @@ AudioNetSink::AudioNetSink(QObject *parent) : AudioNetSink::AudioNetSink(QObject *parent, int sampleRate, bool stereo) : m_type(SinkUDP), + m_codec(CodecL16), m_rtpBufferAudio(0), m_bufferIndex(0), m_port(9998) @@ -95,10 +98,32 @@ void AudioNetSink::deleteDestination(const QString& address, uint16_t port) } } -void AudioNetSink::setParameters(bool stereo, int sampleRate) +void AudioNetSink::setParameters(Codec codec, bool stereo, int sampleRate) { - if (m_rtpBufferAudio) { - m_rtpBufferAudio->setPayloadInformation(stereo ? RTPSink::PayloadL16Stereo : RTPSink::PayloadL16Mono, sampleRate); + qDebug() << "AudioNetSink::setParameters:" + << " codec: " << codec + << " stereo: " << stereo + << " sampleRate: " << sampleRate; + + m_codec = codec; + + if (m_rtpBufferAudio) + { + switch (m_codec) + { + case CodecPCMA: + m_audioCompressor.fillALaw(); + m_rtpBufferAudio->setPayloadInformation(RTPSink::PayloadPCMA8, sampleRate); + break; + case CodecPCMU: + m_audioCompressor.fillULaw(); + m_rtpBufferAudio->setPayloadInformation(RTPSink::PayloadPCMU8, sampleRate); + break; + case CodecL16: // actually no codec + default: + m_rtpBufferAudio->setPayloadInformation(stereo ? RTPSink::PayloadL16Stereo : RTPSink::PayloadL16Mono, sampleRate); + break; + } } } @@ -113,14 +138,43 @@ void AudioNetSink::write(qint16 sample) } else { - qint16 *p = (qint16*) &m_data[m_bufferIndex]; - *p = sample; - m_bufferIndex += sizeof(qint16); + 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 CodecL16: + default: + { + qint16 *p = (qint16*) &m_data[m_bufferIndex]; + *p = sample; + m_bufferIndex += sizeof(qint16); + } + break; + } } } else if (m_type == SinkRTP) { - m_rtpBufferAudio->write((uint8_t *) &sample); + switch(m_codec) + { + case CodecPCMA: + case CodecPCMU: + { + qint8 p = m_audioCompressor.compress8(sample); + m_rtpBufferAudio->write((uint8_t *) &p); + } + break; + case CodecL16: + default: + m_rtpBufferAudio->write((uint8_t *) &sample); + break; + } } } @@ -149,35 +203,35 @@ void AudioNetSink::write(qint16 lSample, qint16 rSample) } } -void AudioNetSink::write(AudioSample* samples, uint32_t numSamples) -{ - if (m_type == SinkUDP) - { - int samplesIndex = 0; - - if (m_bufferIndex + numSamples*sizeof(AudioSample) >= m_udpBlockSize) // fill remainder of buffer and send it - { - memcpy(&m_data[m_bufferIndex], &samples[samplesIndex], m_udpBlockSize - m_bufferIndex); // fill remainder of buffer - m_udpSocket->writeDatagram((const char*)m_data, (qint64 ) m_udpBlockSize, m_address, m_port); - m_bufferIndex = 0; - samplesIndex += (m_udpBlockSize - m_bufferIndex) / sizeof(AudioSample); - numSamples -= (m_udpBlockSize - m_bufferIndex) / sizeof(AudioSample); - } - - while (numSamples > m_udpBlockSize/sizeof(AudioSample)) // send directly from input without buffering - { - m_udpSocket->writeDatagram((const char*)&samples[samplesIndex], (qint64 ) m_udpBlockSize, m_address, m_port); - samplesIndex += m_udpBlockSize/sizeof(AudioSample); - numSamples -= m_udpBlockSize/sizeof(AudioSample); - } - - memcpy(&m_data[m_bufferIndex], &samples[samplesIndex], numSamples*sizeof(AudioSample)); - } - else if (m_type == SinkRTP) - { - m_rtpBufferAudio->write((uint8_t *) samples, numSamples*2); // 2 x 16 bit sample - } -} +//void AudioNetSink::write(AudioSample* samples, uint32_t numSamples) +//{ +// if (m_type == SinkUDP) +// { +// int samplesIndex = 0; +// +// if (m_bufferIndex + numSamples*sizeof(AudioSample) >= m_udpBlockSize) // fill remainder of buffer and send it +// { +// memcpy(&m_data[m_bufferIndex], &samples[samplesIndex], m_udpBlockSize - m_bufferIndex); // fill remainder of buffer +// m_udpSocket->writeDatagram((const char*)m_data, (qint64 ) m_udpBlockSize, m_address, m_port); +// m_bufferIndex = 0; +// samplesIndex += (m_udpBlockSize - m_bufferIndex) / sizeof(AudioSample); +// numSamples -= (m_udpBlockSize - m_bufferIndex) / sizeof(AudioSample); +// } +// +// while (numSamples > m_udpBlockSize/sizeof(AudioSample)) // send directly from input without buffering +// { +// m_udpSocket->writeDatagram((const char*)&samples[samplesIndex], (qint64 ) m_udpBlockSize, m_address, m_port); +// samplesIndex += m_udpBlockSize/sizeof(AudioSample); +// numSamples -= m_udpBlockSize/sizeof(AudioSample); +// } +// +// memcpy(&m_data[m_bufferIndex], &samples[samplesIndex], numSamples*sizeof(AudioSample)); +// } +// else if (m_type == SinkRTP) +// { +// m_rtpBufferAudio->write((uint8_t *) samples, numSamples*2); // 2 x 16 bit sample +// } +//} void AudioNetSink::moveToThread(QThread *thread) { diff --git a/sdrbase/audio/audionetsink.h b/sdrbase/audio/audionetsink.h index 38c237e15..284a5ee7a 100644 --- a/sdrbase/audio/audionetsink.h +++ b/sdrbase/audio/audionetsink.h @@ -19,6 +19,7 @@ #define SDRBASE_AUDIO_AUDIONETSINK_H_ #include "dsp/dsptypes.h" +#include "audiocompressor.h" #include "export.h" #include @@ -37,6 +38,13 @@ public: SinkRTP } SinkType; + typedef enum + { + CodecL16, + CodecPCMA, + CodecPCMU + } Codec; + AudioNetSink(QObject *parent); //!< without RTP AudioNetSink(QObject *parent, int sampleRate, bool stereo); //!< with RTP ~AudioNetSink(); @@ -44,11 +52,11 @@ public: void setDestination(const QString& address, uint16_t port); void addDestination(const QString& address, uint16_t port); void deleteDestination(const QString& address, uint16_t port); - void setParameters(bool stereo, int sampleRate); + void setParameters(Codec codec, bool stereo, int sampleRate); void write(qint16 sample); void write(qint16 lSample, qint16 rSample); - void write(AudioSample* samples, uint32_t numSamples); + //void write(AudioSample* samples, uint32_t numSamples); bool isRTPCapable() const; bool selectType(SinkType type); @@ -59,8 +67,10 @@ public: protected: SinkType m_type; + Codec m_codec; QUdpSocket *m_udpSocket; RTPSink *m_rtpBufferAudio; + AudioCompressor m_audioCompressor; char m_data[65536]; unsigned int m_bufferIndex; QHostAddress m_address; diff --git a/sdrbase/audio/audiooutput.cpp b/sdrbase/audio/audiooutput.cpp index bd1d7def9..2155e4653 100644 --- a/sdrbase/audio/audiooutput.cpp +++ b/sdrbase/audio/audiooutput.cpp @@ -29,6 +29,7 @@ AudioOutput::AudioOutput() : m_audioNetSink(0), m_copyAudioToUdp(false), m_udpChannelMode(UDPChannelLeft), + m_udpChannelCodec(UDPCodecL16), m_audioUsageCount(0), m_onExit(false), m_audioFifos() @@ -200,10 +201,12 @@ void AudioOutput::setUdpChannelMode(UDPChannelMode udpChannelMode) m_udpChannelMode = udpChannelMode; } -void AudioOutput::setUdpChannelFormat(bool stereo, int sampleRate) +void AudioOutput::setUdpChannelFormat(UDPChannelCodec udpChannelCodec, bool stereo, int sampleRate) { + m_udpChannelCodec = udpChannelCodec; + if (m_audioNetSink) { - m_audioNetSink->setParameters(stereo, sampleRate); + m_audioNetSink->setParameters((AudioNetSink::Codec) m_udpChannelCodec, stereo, sampleRate); } } diff --git a/sdrbase/audio/audiooutput.h b/sdrbase/audio/audiooutput.h index 34da30f3e..0e9fb8dc9 100644 --- a/sdrbase/audio/audiooutput.h +++ b/sdrbase/audio/audiooutput.h @@ -41,6 +41,13 @@ public: UDPChannelStereo }; + enum UDPChannelCodec + { + UDPCodecL16, //!< Linear 16 bit (no codec) + UDPCodecALaw, + UDPCodecULaw + }; + AudioOutput(); virtual ~AudioOutput(); @@ -58,7 +65,7 @@ public: void setUdpCopyToUDP(bool copyToUDP); void setUdpUseRTP(bool useRTP); void setUdpChannelMode(UDPChannelMode udpChannelMode); - void setUdpChannelFormat(bool stereo, int sampleRate); + void setUdpChannelFormat(UDPChannelCodec udpChannelCodec, bool stereo, int sampleRate); private: QMutex m_mutex; @@ -66,6 +73,7 @@ private: AudioNetSink* m_audioNetSink; bool m_copyAudioToUdp; UDPChannelMode m_udpChannelMode; + UDPChannelCodec m_udpChannelCodec; uint m_audioUsageCount; bool m_onExit; diff --git a/sdrbase/util/rtpsink.cpp b/sdrbase/util/rtpsink.cpp index 71ea98cbf..791e0ef3e 100644 --- a/sdrbase/util/rtpsink.cpp +++ b/sdrbase/util/rtpsink.cpp @@ -76,24 +76,37 @@ void RTPSink::setPayloadInformation(PayloadType payloadType, int sampleRate) uint32_t timestampinc; QMutexLocker locker(&m_mutex); - qDebug("RTPSink::setPayloadInformation: %d sampleRate: %d", payloadType, sampleRate); + qDebug("RTPSink::setPayloadInformation: payloadType: %d sampleRate: %d", payloadType, sampleRate); switch (payloadType) { + case PayloadPCMA8: + m_sampleBytes = 1; + m_rtpSession.SetDefaultPayloadType(8); + m_packetSamples = m_sampleRate / 50; // 20ms packet samples + timestampinc = m_sampleRate / 50; // 8k -> 160 packets in 20ms + break; + case PayloadPCMU8: + m_sampleBytes = 1; + m_rtpSession.SetDefaultPayloadType(0); + m_packetSamples = m_sampleRate / 50; // 20ms packet samples + timestampinc = m_sampleRate / 50; // 8k -> 160 packets in 20ms + break; case PayloadL16Stereo: m_sampleBytes = 4; m_rtpSession.SetDefaultPayloadType(96); + m_packetSamples = m_sampleRate / 50; // 20ms packet samples timestampinc = m_sampleRate / 100; break; case PayloadL16Mono: default: m_sampleBytes = 2; m_rtpSession.SetDefaultPayloadType(96); + m_packetSamples = m_sampleRate / 50; // 20ms packet samples timestampinc = m_sampleRate / 50; break; } - m_packetSamples = m_sampleRate/50; // 20ms packet samples m_bufferSize = m_packetSamples * m_sampleBytes; if (m_byteBuffer) { @@ -299,6 +312,10 @@ unsigned int RTPSink::elemLength(PayloadType payloadType) { switch (payloadType) { + case PayloadPCMA8: + case PayloadPCMU8: + return sizeof(int8_t); + break; case PayloadL16Stereo: return sizeof(int16_t); break; diff --git a/sdrbase/util/rtpsink.h b/sdrbase/util/rtpsink.h index 424dca772..568d44551 100644 --- a/sdrbase/util/rtpsink.h +++ b/sdrbase/util/rtpsink.h @@ -42,6 +42,8 @@ public: { PayloadL16Mono, PayloadL16Stereo, + PayloadPCMA8, + PayloadPCMU8 } PayloadType; RTPSink(QUdpSocket *udpSocket, int sampleRate, bool stereo); diff --git a/sdrgui/gui/audiodialog.cpp b/sdrgui/gui/audiodialog.cpp index 3f9759a29..3ae10455b 100644 --- a/sdrgui/gui/audiodialog.cpp +++ b/sdrgui/gui/audiodialog.cpp @@ -219,6 +219,7 @@ void AudioDialogX::updateOutputDisplay() ui->outputUDPCopy->setChecked(m_outputDeviceInfo.copyToUDP); ui->outputUDPUseRTP->setChecked(m_outputDeviceInfo.udpUseRTP); ui->outputUDPChannelMode->setCurrentIndex((int) m_outputDeviceInfo.udpChannelMode); + ui->outputUDPChannelCodec->setCurrentIndex((int) m_outputDeviceInfo.udpChannelCodec); } void AudioDialogX::updateOutputDeviceInfo() @@ -229,5 +230,6 @@ void AudioDialogX::updateOutputDeviceInfo() m_outputDeviceInfo.copyToUDP = ui->outputUDPCopy->isChecked(); m_outputDeviceInfo.udpUseRTP = ui->outputUDPUseRTP->isChecked(); m_outputDeviceInfo.udpChannelMode = (AudioOutput::UDPChannelMode) ui->outputUDPChannelMode->currentIndex(); + m_outputDeviceInfo.udpChannelCodec = (AudioOutput::UDPChannelCodec) ui->outputUDPChannelCodec->currentIndex(); } diff --git a/sdrgui/gui/audiodialog.ui b/sdrgui/gui/audiodialog.ui index 4bc3625a8..e0f14fce4 100644 --- a/sdrgui/gui/audiodialog.ui +++ b/sdrgui/gui/audiodialog.ui @@ -6,10 +6,16 @@ 0 0 - 472 - 349 + 560 + 400 + + + 560 + 400 + + Liberation Sans @@ -231,6 +237,34 @@ + + + + + 85 + 0 + + + + Encoding + + + + L16 + + + + + PCMA/8k + + + + + PCMU/8k + + + +