77 lines
2.9 KiB
C++
77 lines
2.9 KiB
C++
#pragma once
|
|
|
|
#include <QObject>
|
|
#include <atomic>
|
|
#include <cstdint>
|
|
#include <vector>
|
|
#include <QTimer>
|
|
#include "audio_device.h"
|
|
#include "audio_capture_lease.h"
|
|
#include "voice_audio_io.h"
|
|
|
|
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 CallAudioEngine : public QObject {
|
|
Q_OBJECT
|
|
public:
|
|
static CallAudioEngine* instance();
|
|
|
|
/* Запустить полнодуплекс для звонка (после ACCEPTED). 0 = успех. */
|
|
int start(quint64 callId);
|
|
|
|
/* По CALL_ENDED: тон завершения (~450мс), затем авто-teardown. */
|
|
void beginEnd(quint64 callId);
|
|
|
|
/* Немедленный teardown (device + освобождение call_audio). */
|
|
void stop();
|
|
|
|
bool isActive() const { return m_active.load(); }
|
|
quint64 callId() const { return m_callId.load(); }
|
|
VoiceAudioIo::OutputLatency outputLatency() const { return m_voice.outputLatency(); }
|
|
QString captureError() const { return m_captureError; }
|
|
|
|
/* Mute: пир слышит тишину (отправляем нулевые кадры вместо захваченного PCM). */
|
|
void setMuted(bool muted);
|
|
bool isMuted() const { return m_muted.load(); }
|
|
|
|
/* Backend ID (пустой = default). Смена пересоздаёт только соответствующее устройство. */
|
|
void setPlaybackDevice(const QString& id);
|
|
QString playbackDevice() const { return m_playbackId; }
|
|
void setCaptureDevice(const QString& id);
|
|
|
|
/* Hardware capture callback: без DSP и растущих буферов. */
|
|
void dataCallback(const void* in, void* out, unsigned int frames);
|
|
|
|
signals:
|
|
void captureErrorChanged();
|
|
|
|
private:
|
|
CallAudioEngine();
|
|
bool openCapture();
|
|
void recoverDevices();
|
|
void pauseDevices();
|
|
|
|
std::atomic<bool> m_active{false};
|
|
std::atomic<uint64_t> m_callId{0};
|
|
std::atomic<bool> m_muted{false};
|
|
|
|
QString m_playbackId; /* только GUI-поток */
|
|
|
|
QString m_captureId;
|
|
QString m_captureError;
|
|
AudioDevice m_capture;
|
|
AudioCaptureLease m_microphone;
|
|
VoiceAudioIo m_voice;
|
|
bool m_outputAttached = false;
|
|
QTimer m_recoveryTimer;
|
|
uint64_t m_generation = 0;
|
|
bool m_ending = false;
|
|
|
|
};
|