mirror of
https://github.com/wf-group/wfview
synced 2026-08-13 17:32:59 -04:00
127 lines
3.5 KiB
C++
127 lines
3.5 KiB
C++
#ifndef AUDIOHANDLERBASE_H
|
|
#define AUDIOHANDLERBASE_H
|
|
|
|
// =============================
|
|
// audiohandler_base.h/.cpp (renamed to lowercase)
|
|
// =============================
|
|
#pragma once
|
|
|
|
#include <QObject>
|
|
#include <QByteArray>
|
|
#include <QMutex>
|
|
#include <QThread>
|
|
#include <QElapsedTimer>
|
|
#include <QTimer>
|
|
#include <QAudio>
|
|
#include <QAudioFormat>
|
|
#include <QIODevice>
|
|
#include <atomic>
|
|
#include <cstring>
|
|
|
|
#if (QT_VERSION < QT_VERSION_CHECK(6,0,0))
|
|
#include <QAudioInput>
|
|
#include <QAudioOutput>
|
|
#include <QAudioDeviceInfo>
|
|
#else
|
|
#include <QAudioSource>
|
|
#include <QAudioSink>
|
|
#include <QAudioDevice>
|
|
#include <QMediaDevices>
|
|
#endif
|
|
|
|
#include "packettypes.h"
|
|
#include "audiotaper.h"
|
|
#include "audioconverter.h"
|
|
#include "logcategories.h"
|
|
#ifndef BUILD_WFSERVER
|
|
#include "txaudioprocessor.h"
|
|
#include "rxaudioprocessor.h"
|
|
#else
|
|
class TxAudioProcessor;
|
|
class RxAudioProcessor;
|
|
#endif
|
|
|
|
class audioHandlerBase : public QObject
|
|
{
|
|
Q_OBJECT
|
|
public:
|
|
explicit audioHandlerBase(QObject* parent = nullptr);
|
|
~audioHandlerBase() override;
|
|
|
|
int latencyMs() const noexcept { return static_cast<int>(currentLatency.load(std::memory_order_relaxed)); }
|
|
quint16 amplitudePeak() const noexcept { return static_cast<quint16>(amplitude.load(std::memory_order_relaxed) * 255.0f); }
|
|
|
|
void dispose();
|
|
virtual void start();
|
|
virtual void stop();
|
|
|
|
// Returns the TX/RX processor pointers set in audioSetup (null when not set).
|
|
#ifndef BUILD_WFSERVER
|
|
TxAudioProcessor* txProcessor() const { return setupData.txProc; }
|
|
RxAudioProcessor* rxProcessor() const { return setupData.rxProc; }
|
|
#endif
|
|
|
|
signals:
|
|
void initFailed();
|
|
void audioMessage(QString message);
|
|
void haveAudioData(const audioPacket& data);
|
|
void haveLevels(quint16 amplitudePeak, quint16 amplitudeRMS, quint16 configuredLatency, quint16 measuredLatency, bool underrun, bool overrun);
|
|
void setupConverter(QAudioFormat in, codecType codecIn, QAudioFormat out, codecType codecOut, quint8 opusApp, quint8 resampQuality);
|
|
void sendToConverter(audioPacket audio);
|
|
|
|
public slots:
|
|
bool init(const audioSetup& setup);
|
|
void setVolume(quint8 volumeIdx);
|
|
void changeLatency(quint16 newLatencyMs);
|
|
void stateChanged(QAudio::State state);
|
|
void clearUnderrun();
|
|
|
|
protected:
|
|
virtual bool openDevice() noexcept = 0;
|
|
|
|
virtual void closeDevice() = 0;
|
|
virtual QString role() const = 0;
|
|
|
|
bool negotiateFormat(int minSampleRate = 48000);
|
|
|
|
virtual QAudioFormat getNativeFormat() { qCritical(logAudio()) << "No getNativeFormat()!!"; return QAudioFormat(); };
|
|
virtual bool isFormatSupported(QAudioFormat f) { Q_UNUSED(f) qCritical(logAudio()) << "No isFormatSupported()!"; return false; };
|
|
|
|
void reportError(const QString& msg);
|
|
|
|
protected:
|
|
audioSetup setupData{};
|
|
QAudioFormat radioFormat;
|
|
QAudioFormat nativeFormat;
|
|
|
|
#if (QT_VERSION < QT_VERSION_CHECK(6,0,0))
|
|
QAudioDeviceInfo deviceInfo;
|
|
#else
|
|
QAudioDevice deviceInfo;
|
|
#endif
|
|
|
|
audioConverter* converter {nullptr};
|
|
QThread* converterThread {nullptr};
|
|
QTimer* underTimer {nullptr};
|
|
|
|
codecType codec {codecType::LPCM};
|
|
|
|
std::atomic<int> currentLatency {0};
|
|
std::atomic<float> amplitude {0.0f};
|
|
std::atomic<bool> isUnderrun {false};
|
|
std::atomic<bool> isOverrun {false};
|
|
|
|
QElapsedTimer lastReceived;
|
|
|
|
qreal volume {1.0};
|
|
|
|
bool initialized {false};
|
|
|
|
QMutex devMutex;
|
|
std::atomic<bool> disposed{false};
|
|
audioPacket tempBuf;
|
|
|
|
};
|
|
|
|
|
|
#endif // AUDIOHANDLERBASE_H
|