#ifndef AUDIOHANDLER_H #define AUDIOHANDLER_H #include #include #include #include #include #if defined(RTAUDIO) #ifdef Q_OS_WIN #include "RtAudio.h" #else #include "rtaudio/RtAudio.h" #endif #elif defined (PORTAUDIO) #include "portaudio.h" //#error "PORTAUDIO is not currently supported" #else #include #include #include #include #include #endif #include "packettypes.h" typedef signed short MY_TYPE; #define FORMAT RTAUDIO_SINT16 #include #include #include #include #include "resampler/speex_resampler.h" #include "ring/ring.h" #ifdef Q_OS_WIN #include "opus.h" #else #include "opus/opus.h" #endif #include "audiotaper.h" #ifdef Q_OS_LINUX #include #else #include #endif //#include //#include #include //#define BUFFER_SIZE (32*1024) #define INTERNAL_SAMPLE_RATE 48000 #define MULAW_BIAS 33 #define MULAW_MAX 0x1fff struct audioPacket { quint32 seq; QTime time; quint16 sent; QByteArray data; quint8 guid[GUIDLEN]; }; struct audioSetup { QString name; quint16 latency; quint8 codec; bool ulaw = false; bool isinput; QAudioFormat format; // Use this for all audio APIs QAudioDeviceInfo port; quint8 resampleQuality; unsigned char localAFgain; }; // For QtMultimedia, use a native QIODevice class audioHandler : public QObject { Q_OBJECT public: audioHandler(QObject* parent = 0); ~audioHandler(); int getLatency(); void start(); void stop(); void getNextAudioChunk(QByteArray &data); quint16 getAmplitude(); public slots: bool init(audioSetup setup); void changeLatency(const quint16 newSize); void setVolume(unsigned char volume); void incomingAudio(const audioPacket data); private slots: signals: void audioMessage(QString message); void sendLatency(quint16 newSize); void haveAudioData(const QByteArray& data); private: qint64 writeData(const char* data, qint64 nBytes); bool isInitialized=false; bool isReady = false; bool audioBuffered = false; QAudioOutput* audioOutput=Q_NULLPTR; QAudioInput* audioInput=Q_NULLPTR; QIODevice* audioDevice=Q_NULLPTR; QAudioFormat format; QAudioDeviceInfo deviceInfo; SpeexResamplerState* resampler = Q_NULLPTR; //r8b::CFixedBuffer* resampBufs; //r8b::CPtrKeeper* resamps; quint16 audioLatency; unsigned int chunkSize; bool chunkAvailable; quint32 lastSeq; quint32 lastSentSeq=0; qint64 elapsedMs = 0; quint16 nativeSampleRate=0; quint8 radioSampleBits; quint8 radioChannels; int delayedPackets=0; QMapaudioBuffer; double resampleRatio; wilt::Ring *ringBuf=Q_NULLPTR; volatile bool ready = false; audioPacket tempBuf; quint16 currentLatency; float amplitude; qreal volume=1.0; int devChannels; audioSetup setup; OpusEncoder* encoder=Q_NULLPTR; OpusDecoder* decoder=Q_NULLPTR; }; // Various audio handling functions declared inline static inline qint64 getAudioSize(qint64 timeInMs, const QAudioFormat& format) { #ifdef Q_OS_LINUX qint64 value = qint64(qCeil(format.channelCount() * (format.sampleSize() / 8) * format.sampleRate() / qreal(1000) * timeInMs)); #else qint64 value = qint64(qCeil(format.channelCount() * (format.sampleSize() / 8) * format.sampleRate() / qreal(10000) * timeInMs)); #endif if (value % (format.channelCount() * (format.sampleSize() / 8)) != 0) value += (format.channelCount() * (format.sampleSize() / 8) - value % (format.channelCount() * (format.sampleSize() / 8))); return value; } static inline qint64 getAudioDuration(qint64 bytes, const QAudioFormat& format) { return qint64(qFloor(bytes / (format.channelCount() * (format.sampleSize() / 8) * format.sampleRate() / qreal(1000)))); } typedef Eigen::Matrix VectorXuint8; typedef Eigen::Matrix VectorXint8; typedef Eigen::Matrix VectorXint16; typedef Eigen::Matrix VectorXint32; static inline QByteArray samplesToInt(const QByteArray& data, const QAudioFormat& supported_format) { QByteArray input = data; switch (supported_format.sampleSize()) { case 8: { switch (supported_format.sampleType()) { case QAudioFormat::UnSignedInt: { Eigen::Ref samples_float = Eigen::Map(reinterpret_cast(input.data()), input.size() / int(sizeof(float))); Eigen::VectorXf samples_int_tmp = samples_float * float(std::numeric_limits::max()); VectorXuint8 samples_int = samples_int_tmp.cast(); QByteArray raw = QByteArray(reinterpret_cast(samples_int.data()), int(samples_int.size()) * int(sizeof(quint8))); return raw; } case QAudioFormat::SignedInt: { Eigen::Ref samples_float = Eigen::Map(reinterpret_cast(input.data()), input.size() / int(sizeof(float))); Eigen::VectorXf samples_int_tmp = samples_float * float(std::numeric_limits::max()); VectorXint8 samples_int = samples_int_tmp.cast(); QByteArray raw = QByteArray(reinterpret_cast(samples_int.data()), int(samples_int.size()) * int(sizeof(qint8))); return raw; } default: break; } break; } case 16: { switch (supported_format.sampleType()) { case QAudioFormat::SignedInt: { Eigen::Ref samples_float = Eigen::Map(reinterpret_cast(input.data()), input.size() / int(sizeof(float))); Eigen::VectorXf samples_int_tmp = samples_float * float(std::numeric_limits::max()); VectorXint16 samples_int = samples_int_tmp.cast(); QByteArray raw = QByteArray(reinterpret_cast(samples_int.data()), int(samples_int.size()) * int(sizeof(qint16))); return raw; } default: break; } break; } case 32: { switch (supported_format.sampleType()) { case QAudioFormat::SignedInt: { Eigen::Ref samples_float = Eigen::Map(reinterpret_cast(input.data()), input.size() / int(sizeof(float))); Eigen::VectorXf samples_int_tmp = samples_float * float(std::numeric_limits::max()); VectorXint32 samples_int = samples_int_tmp.cast(); QByteArray raw = QByteArray(reinterpret_cast(samples_int.data()), int(samples_int.size()) * int(sizeof(qint32))); return raw; } default: break; } break; } default: break; } return QByteArray(); } static inline QByteArray samplesToFloat(const QByteArray& data, const QAudioFormat& supported_format) { QByteArray input = data; switch (supported_format.sampleSize()) { case 8: { switch (supported_format.sampleType()) { case QAudioFormat::UnSignedInt: { QByteArray raw = input; Eigen::Ref samples_int = Eigen::Map(reinterpret_cast(raw.data()), raw.size() / int(sizeof(quint8))); Eigen::VectorXf samples_float = samples_int.cast() / float(std::numeric_limits::max()); return QByteArray(reinterpret_cast(samples_float.data()), int(samples_float.size()) * int(sizeof(float))); } case QAudioFormat::SignedInt: { QByteArray raw = input; Eigen::Ref samples_int = Eigen::Map(reinterpret_cast(raw.data()), raw.size() / int(sizeof(qint8))); Eigen::VectorXf samples_float = samples_int.cast() / float(std::numeric_limits::max()); return QByteArray(reinterpret_cast(samples_float.data()), int(samples_float.size()) * int(sizeof(float))); } default: break; } break; } case 16: { switch (supported_format.sampleType()) { case QAudioFormat::SignedInt: { QByteArray raw = input; Eigen::Ref samples_int = Eigen::Map(reinterpret_cast(raw.data()), raw.size() / int(sizeof(qint16))); Eigen::VectorXf samples_float = samples_int.cast() / float(std::numeric_limits::max()); return QByteArray(reinterpret_cast(samples_float.data()), int(samples_float.size()) * int(sizeof(float))); } default: break; } break; } case 32: { switch (supported_format.sampleType()) { case QAudioFormat::SignedInt: { QByteArray raw = input; Eigen::Ref samples_int = Eigen::Map(reinterpret_cast(raw.data()), raw.size() / int(sizeof(qint32))); Eigen::VectorXf samples_float = samples_int.cast() / float(std::numeric_limits::max()); return QByteArray(reinterpret_cast(samples_float.data()), int(samples_float.size()) * int(sizeof(float))); } default: break; } break; } default: break; } return QByteArray(); } #endif // AUDIOHANDLER_H