You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
102 lines
4.5 KiB
102 lines
4.5 KiB
#pragma once |
|
|
|
#include <QObject> |
|
#include <atomic> |
|
#include <cstdint> |
|
#include <vector> |
|
#include "audio_device.h" |
|
#include "voice_audio_io.h" |
|
#include <QTimer> |
|
#include <QMap> |
|
#include <array> |
|
|
|
struct ma_device; |
|
|
|
/* Desktop-контур рации: GUI владеет capture device и жизненным циклом. |
|
* Hardware callback копирует PCM в ограниченную очередь VoiceAudioIo. |
|
* Capture worker выполняет AEC и упорядочивает PCM/PTT/mute; независимый RX worker |
|
* получает готовый голос из сервисного слоя. SoundManager смешивает его со всеми |
|
* звуками приложения на том же выходе и возвращает итоговый stereo reference. |
|
* Stop: close capture → join capture worker → detach output → join RX → release core. */ |
|
class RadioAudioEngine : public QObject { |
|
Q_OBJECT |
|
public: |
|
static RadioAudioEngine* instance(); |
|
|
|
/* Включить прослушивание канала (после toggle рации). 0 = успех. */ |
|
int start(quint64 groupId); |
|
|
|
/* Выключить прослушивание канала (toggle рации выключен). */ |
|
void stop(); |
|
|
|
/* PTT: зажата / отпущена (только когда радио канала включено). */ |
|
void talkBegin(); |
|
void talkEnd(); |
|
void setHotkeyTalking(bool pressed); // независимый владелец PTT — глобальная клавиатура |
|
|
|
/* Настройки читаются/применяются в uasync; после подтверждения GUI перезапускает только capture. */ |
|
void loadSettings(const QString& configPath); |
|
bool applySettings(const QMap<QString, int>& values); |
|
int setting(const QString& name) const; |
|
bool settingsReady() const { return m_settingsReady; } |
|
bool settingsBusy() const { return m_settingsBusy; } |
|
bool autoEnabled() const { return m_settings[0] != 0; } |
|
int autoMode() const { return m_settings[6]; } |
|
float inputLevel() const { return m_inputLevel; } |
|
bool inputLevelValid() const { return m_inputLevelValid; } |
|
float vadProbability() const { return m_vadProbability; } |
|
bool vadValid() const { return m_vadValid; } |
|
float vadGain() const { return m_vadGain; } |
|
bool vadCompressorEnabled() const { return m_vadCompressorEnabled; } |
|
bool autoBlocked() const { return m_autoBlocked; } |
|
bool autoAvailable() const { return m_autoAvailable; } |
|
bool captureAvailable() const { return m_captureAvailable; } |
|
bool isTransmitting() const { return m_transmitting; } |
|
QString settingsError() const { return m_settingsError; } |
|
|
|
bool isTalking() const { return m_talking.load(); } |
|
bool isActive() const { return m_active.load(); } |
|
quint64 groupId() const { return m_groupId.load(); } |
|
|
|
/* Hardware capture callback: без DSP и растущих буферов. */ |
|
void captureCallback(const void* in, unsigned int frames); |
|
|
|
signals: |
|
void talkingChanged(bool talking); // GUI-поток, суммарное состояние кнопки и хоткея |
|
void inputLevelChanged(); // снимок измерителя, не чаще 10Гц |
|
void stateChanged(); // фактический TX, доступность capture/VAD и настройки; GUI-поток |
|
|
|
private: |
|
RadioAudioEngine(); |
|
void updateTalking(); |
|
bool m_buttonTalking = false, m_hotkeyTalking = false; // GUI-поток |
|
void pauseDevices(); |
|
void recoverDevices(); |
|
void openCapture(); |
|
void updateState(); |
|
void reconfigureCapture(); |
|
void postSettings(const std::array<int, 9>& values, bool apply); |
|
std::array<int, 9> m_settings{0, 50, 200, 1, 15, 15, 1, -35, -45}; |
|
QString m_configPath; |
|
QString m_settingsError; |
|
bool m_settingsReady = false, m_settingsBusy = false; |
|
bool m_transmitting = false, m_autoAvailable = false, m_captureAvailable = false; |
|
|
|
float m_inputLevel = -120; |
|
bool m_inputLevelValid = false, m_autoBlocked = false; |
|
float m_vadProbability = 0, m_vadGain = 0; |
|
bool m_vadValid = false, m_vadCompressorEnabled = false; |
|
|
|
std::atomic<bool> m_active{false}; |
|
std::atomic<bool> m_talking{false}; |
|
std::atomic<uint64_t> m_groupId{0}; |
|
|
|
AudioDevice m_capture; |
|
VoiceAudioIo m_voice; |
|
bool m_outputAttached = false; |
|
QTimer m_recoveryTimer; |
|
bool m_wantStereo = false; |
|
QString m_captureId, m_playbackId; |
|
|
|
int m_captureChannels = 1; |
|
};
|
|
|