Раздели аудиопотоки и привяжи AEC к фактическому общему выходу

This commit is contained in:
evgeny committed 2026-10-02 10:22:34 +03:00
1 parent d7fb0c83f9
commit bd082a26bf
30 files changed
+1839 -412

No files matched your search

+35
View File
@@ -3,6 +3,11 @@
#include "debug_config.h"
#include <algorithm>
#include <utility>
#include <chrono>
extern "C" int64_t audio_stream_frame_time(ma_device* device, unsigned int frames, int* valid);
extern "C" uint64_t audio_stream_route(ma_device* device, int capture);
extern "C" int audio_stream_capture_missing(ma_device* device);
extern "C" void audio_stream_log_route(ma_device* device, int capture);
AudioDevice::AudioDevice() { m_clock.start(); }
AudioDevice::~AudioDevice() { close(); }
@@ -14,6 +19,7 @@ bool AudioDevice::init(ma_context* context, ma_device_config config, const char*
if (!context) { retryLater(); return false; }
auto* device = new ma_device{};
config.dataCallback = data;
config.noFixedSizedCallback = MA_TRUE; // Аппаратные чанки не требуют скрытого накопителя miniaudio.
config.notificationCallback = notification;
config.pUserData = this;
ma_result result = ma_device_init(context, &config, device);
@@ -25,6 +31,8 @@ bool AudioDevice::init(ma_context* context, ma_device_config config, const char*
}
m_device = device;
m_frames = 0;
m_route = 0; m_reportedRoute = 0;
m_timingMeasured = false; m_reportedTiming = -1;
m_seenFrames = 0;
m_suspended = false;
audio_diag_label(device, session, role);
@@ -56,10 +64,30 @@ void AudioDevice::close() {
DEBUG_INFO(DEBUG_CATEGORY_CALL, "audio: %s closed", m_role);
}
m_callback = {};
m_route = 0;
}
void AudioDevice::pause() {
if (!m_device) return;
ma_result result = ma_device_stop(m_device);
if (result != MA_SUCCESS) {
DEBUG_ERROR(DEBUG_CATEGORY_CALL, "audio: %s pause failed result=%d", m_role, result);
close();
}
}
void AudioDevice::data(ma_device* device, void* out, const void* in, ma_uint32 frames) {
auto* self = static_cast<AudioDevice*>(device->pUserData);
int valid = 0;
bool capture = device->type == ma_device_type_capture;
int64_t time = audio_stream_frame_time(device, frames, &valid);
int64_t now = std::chrono::duration_cast<std::chrono::microseconds>(std::chrono::steady_clock::now().time_since_epoch()).count();
if (!time) time = capture ? now - (int64_t)frames * 1000000 / device->sampleRate : now;
self->m_callbackTime.store(time, std::memory_order_relaxed);
self->m_timingMeasured.store(valid, std::memory_order_relaxed);
uint64_t route = audio_stream_route(device, capture);
if (route != self->m_route.exchange(route, std::memory_order_relaxed)) audio_stream_log_route(device, capture);
self->m_captureMissing.store(audio_stream_capture_missing(device), std::memory_order_relaxed);
if (self->m_callback) self->m_callback(in, out, frames);
self->m_frames.fetch_add(frames, std::memory_order_relaxed);
}
@@ -73,6 +101,13 @@ void AudioDevice::notification(const ma_device_notification* event) {
bool AudioDevice::needsRecovery() {
if (!m_device) return false;
uint64_t frames = m_frames.load(std::memory_order_relaxed);
uint64_t route = m_route.load();
int measured = m_timingMeasured.load();
if (frames && (route != m_reportedRoute || measured != m_reportedTiming)) {
DEBUG_INFO(DEBUG_CATEGORY_AEC, "audio: %s timing=%s physical_route=%016llx", m_role,
measured ? "backend-snapshot" : "callback-estimate", (unsigned long long)route);
m_reportedRoute = route; m_reportedTiming = measured;
}
qint64 now = m_clock.elapsed();
if (frames != m_seenFrames || m_suspended.load()) {
m_seenFrames = frames;