#ifndef AUDIOCONVERTER_H #define AUDIOCONVERTER_H #include #include #include #include #include #include #include /* Opus and Eigen */ #ifdef Q_OS_WIN #include "opus.h" #include #else #include "opus/opus.h" #include #endif enum audioType {qtAudio,portAudio,rtAudio}; #include "resampler/speex_resampler.h" #include "packettypes.h" struct audioPacket { quint32 seq; QTime time; quint16 sent; QByteArray data; quint8 guid[GUIDLEN]; float amplitudePeak; float amplitudeRMS; qreal volume = 1.0; }; struct audioSetup { audioType type; QString name; quint16 latency; quint8 codec; bool ulaw = false; bool isinput; quint32 sampleRate; QAudioDeviceInfo port; int portInt; quint8 resampleQuality; unsigned char localAFgain; quint16 blockSize = 20; // Each 'block' of audio is 20ms long by default. quint8 guid[GUIDLEN]; }; class audioConverter : public QObject { Q_OBJECT public: explicit audioConverter(QObject* parent = nullptr);; ~audioConverter(); public slots: bool init(QAudioFormat inFormat, QAudioFormat outFormat, quint8 opusComplexity, quint8 resampleQuality); bool convert(audioPacket audio); signals: void converted(audioPacket audio); protected: QAudioFormat inFormat; QAudioFormat outFormat; OpusEncoder* opusEncoder = Q_NULLPTR; OpusDecoder* opusDecoder = Q_NULLPTR; SpeexResamplerState* resampler = Q_NULLPTR; quint8 opusComplexity; quint8 resampleQuality = 4; double resampleRatio=1.0; // Default resample ratio is 1:1 quint32 lastAudioSequence; }; // Various audio handling functions declared inline typedef Eigen::Matrix VectorXuint8; typedef Eigen::Matrix VectorXint8; typedef Eigen::Matrix VectorXint16; typedef Eigen::Matrix VectorXint32; static inline QAudioFormat toQAudioFormat(quint8 codec, quint32 sampleRate) { QAudioFormat format; /* 0x01 uLaw 1ch 8bit 0x02 PCM 1ch 8bit 0x04 PCM 1ch 16bit 0x08 PCM 2ch 8bit 0x10 PCM 2ch 16bit 0x20 uLaw 2ch 8bit 0x40 Opus 1ch 0x80 Opus 2ch */ format.setByteOrder(QAudioFormat::LittleEndian); format.setCodec("audio/pcm"); format.setSampleRate(sampleRate); if (codec == 0x01 || codec == 0x20) { /* Set sample to be what is expected by the encoder and the output of the decoder */ format.setSampleSize(16); format.setSampleType(QAudioFormat::SignedInt); format.setCodec("audio/PCMU"); } if (codec == 0x02 || codec == 0x08) { format.setSampleSize(8); format.setSampleType(QAudioFormat::UnSignedInt); } if (codec == 0x08 || codec == 0x10 || codec == 0x20 || codec == 0x80) { format.setChannelCount(2); } else { format.setChannelCount(1); } if (codec == 0x04 || codec == 0x10) { format.setSampleSize(16); format.setSampleType(QAudioFormat::SignedInt); } if (codec == 0x40 || codec == 0x80) { format.setSampleSize(32); format.setSampleType(QAudioFormat::Float); format.setCodec("audio/opus"); } return format; } #endif