- src/call/: сигналинг (call.c, call_proto.h, ETCP_RT_ID_CALL 0x36) + релей медиа + headless аудио-сокет (call_headless.c, call_audio_bind) + Opus/jitter/тоны - chat: события CHAT_EVT_CALL_* (34–40), CHAT_EVT_DM_MESSAGES (41), DM-трамплины - chatgui: call window, miniaudio I/O, audio_frame_ring, test_audio_jitter - chatgui-android: CallScreen/IncomingCallDialog, аудио-роутинг, JNI, рингтон - tests: test_call, test_call_headless
63 lines
2.4 KiB
C++
63 lines
2.4 KiB
C++
#pragma once
|
|
|
|
#include <QObject>
|
|
#include <atomic>
|
|
#include <cstdint>
|
|
#include <vector>
|
|
|
|
struct ma_device;
|
|
|
|
/* Аудио-контур звонка (desktop): только miniaudio I/O + захват/воспроизведение.
|
|
* Весь аудиопроцессинг (Opus, джиттер-буфер, time-stretch, тоны) — в сервисном
|
|
* слое src/call/call_audio.c; сюда приходит/отсюда уходит финальный PCM.
|
|
*
|
|
* Потоки:
|
|
* - аудио-поток (miniaudio callback): capture → call_audio_feed_pcm,
|
|
* call_audio_pull_pcm → playback;
|
|
* - GUI-поток: start()/beginEnd()/stop() по ACCEPTED/ENDED. */
|
|
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(); }
|
|
|
|
/* Mute: пир слышит тишину (отправляем нулевые кадры вместо захваченного PCM). */
|
|
void setMuted(bool muted);
|
|
bool isMuted() const { return m_muted.load(); }
|
|
|
|
/* Устройство вывода звонка (-1 = default). Смена на лету пересоздаёт ma_device. */
|
|
void setPlaybackDeviceIndex(int index);
|
|
int playbackDeviceIndex() const { return m_playbackDeviceIndex; }
|
|
|
|
/* аудио-поток: miniaudio data callback (захват + воспроизведение) */
|
|
void dataCallback(const void* in, void* out, unsigned int frames);
|
|
|
|
private:
|
|
CallAudioEngine() = default;
|
|
void teardownDevice();
|
|
int initDevice();
|
|
|
|
std::atomic<bool> m_active{false};
|
|
std::atomic<uint64_t> m_callId{0};
|
|
std::atomic<bool> m_muted{false};
|
|
|
|
int m_playbackDeviceIndex = -1; /* только GUI-поток */
|
|
|
|
ma_device* m_device = nullptr;
|
|
bool m_deviceStarted = false;
|
|
|
|
std::vector<int16_t> m_captureBuf; /* 960 samples, аудио-поток */
|
|
int m_capturePos = 0;
|
|
};
|