Files
utun2/tools/chatgui/src/audio_capture.h
T

51 lines
2.1 KiB
C++

#pragma once
#include <QString>
#include <cstdint>
#include <functional>
#include <memory>
#include <atomic>
#include <thread>
/* GUI владеет подпиской, сессия — устройством. Одинаковый выбранный вход открывается один раз.
* Профиль трансляции имеет приоритет и сохраняется для рации после её остановки.
* Callback только копирует PCM; ready/stopped вызываются в GUI вне аппаратного callback.
* close() ждёт завершения своего callback, не останавливая устройство другого потребителя. */
class AudioCapture {
public:
enum class Role { Stream, Radio };
struct Frame {
const int16_t* pcm;
unsigned frames;
int channels;
int64_t timeUs;
uint64_t route;
bool measured, missing;
};
using Ready = std::function<bool(int channels, int nativeChannels)>;
using Callback = std::function<void(const Frame&)>;
AudioCapture() = default;
~AudioCapture();
AudioCapture(const AudioCapture&) = delete;
AudioCapture& operator=(const AudioCapture&) = delete;
bool open(const QString& input, Role role, int channels, uint64_t tag, Ready ready,
std::function<void()> stopped, Callback callback);
void close();
void closeAsync(); // GUI отсоединяет подписчика; последний backend закрывается в worker.
bool closing() const; // Включает переоткрытие общего backend для подстройки буфера.
void recover();
bool subscribed() const { return bool(m_session); }
bool running() const;
bool captureTimedOut() const;
private:
struct Session;
std::shared_ptr<Session> detach();
std::shared_ptr<Session> m_session;
std::thread m_closeThread;
std::atomic<bool> m_closeDone{true};
Ready m_ready;
std::function<void()> m_stopped;
Callback m_callback;
Role m_role = Role::Radio;
bool m_prepared = false;
};