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.
 
 
 
 
 
 

85 lines
2.7 KiB

/* Запись голосового сообщения: capture 48 kHz mono → очередь → worker PCM/компрессора.
* GUI управляет init/start/stop/shutdown; meterOnly измеряет уровень без накопления записи.
* takeRecording передаёт остановленные PCM/компрессор в attachment_send_req для фоновой подготовки. */
#pragma once
#include <QObject>
#include <QString>
#include <QTimer>
#include <vector>
#include <cstdint>
#include "audio_device.h"
#include "audio_event_queue.h"
#include <thread>
#include <mutex>
#include <condition_variable>
extern "C" {
#include "audio_compressor.h"
}
struct ma_device;
struct audio_compressor;
struct attachment_send_req;
class AudioRecorder : public QObject {
Q_OBJECT
public:
explicit AudioRecorder(QObject* parent = nullptr);
~AudioRecorder() override;
bool init();
void shutdown();
bool isInitialized() const { return m_initialized; }
void setCaptureDevice(const QString& id) { m_captureId = id; m_customDevice = true; }
void startRecording(bool meterOnly = false);
void stopRecording();
bool isRecording() const { return m_recording; }
float peakLevel() const;
int durationMs() const;
bool takeRecording(struct attachment_send_req* request); /* Передать остановленную запись без копии PCM. */
void configureCompressor(const audio_compressor_config_t& config);
void setCompressorEnabled(bool enabled);
bool isCompressorEnabled() const { return m_compressorEnabled; }
signals:
void recordingStarted();
void recordingStopped(int durationMs);
void durationChanged(int ms);
private:
AudioDevice m_capture;
QTimer m_recoveryTimer;
void recoverCapture();
void captureCallback(const void* input, unsigned int frames);
void recordLoop();
struct CaptureBlock { unsigned frames = 0; int16_t pcm[1920]{}; };
AudioEventQueue<CaptureBlock, 32> m_captureQueue;
std::thread m_recordWorker;
std::mutex m_waitMutex;
std::condition_variable m_wake;
std::atomic<bool> m_workerRunning{false}, m_captureFailed{false};
bool m_meterOnly = false;
bool m_initialized = false;
std::atomic<bool> m_recording{false};
int m_sampleRate = 48000;
int m_channels = 1;
QString m_captureId;
bool m_customDevice = false;
std::vector<int16_t> m_pcmBuffer;
mutable std::atomic<float> m_peakLevel{0.0f};
std::atomic<uint64_t> m_recordedFrames{0};
QTimer m_durationTimer;
int m_elapsedMs = 0;
struct audio_compressor* m_compressor = nullptr;
bool m_compressorEnabled = false;
bool m_captureCompressorEnabled = false;
audio_compressor_config_t m_compressorConfig{};
};