mirror of
https://git.vladimir.cc/vladimir/ewsdr.git
synced 2026-08-25 17:27:32 +00:00
perf(dsp): молчащие слайсы считались от одного факта, что поднят TCI-сервер
RX_AUDIO по TCI снимается ДО громкости и мьюта, поэтому замьюченный слайс обязан продолжать считаться, пока его кто-то качает по сети — иначе клиент остаётся без звука ровно потому, что оператор убрал его у себя в комнате. Гейт в ProcessSlicesFor это и делал, но спрашивал ГЛОБАЛЬНЫЙ флаг «тапы аудио установлены», а его взводит SetTaps(True) на старте сервера. То есть галка «Enable TCI server» одна, без единого клиента, заставляла гонять полный fexchange0 по каждому молчащему слайсу — до шести штук, ~47 блоков в секунду на каждый, плюс два входа в критические секции на блок в DSP-потоке. Клиент, качающий один слайс из шести или вообще только IQ, оплачивал остальные так же. Флаг стал ПОСЛАЙСОВЫМ (TSliceChan.TapWanted, SetSliceTapWanted). Кто его выставляет — владелец потоков: TTCIAdapter.PushTapWants полностью пересчитывает картину по FStreams и раскладывает по слотам. Считаются только потоки RX_AUDIO: LINE_OUT и рекордер снимаются ПОСЛЕ мьюта, и на молчащем слайсе им достаётся тишина независимо от того, посчитали его или нет. Пересчёт зовётся отовсюду, где множество потоков или карта слайсов меняются: StartStream (синхронно и ДО ответа клиенту — тогда не теряется ни один блок), StopStream, DropClientStreams, DropDeadRxStreams, StopAllStreams и OnState по MapChanged — слот мог сменить хозяина, и разрешение обязано переехать вместе с ним. Список слушателей снимается под FStreamLock, и лок отпускается ДО похода в движок: DSP-поток входит в тап, уже держа FSliceLock движка, и берёт в нём FStreamLock — обратный порядок дал бы клин. Глобальные FAudioTapsActive/SetAudioTapsActive/PushAudioTapsActive удалены. FAudioTapCount остаётся: он по-прежнему гейтит сам вызов тапов (FireAudioTap) и сборку звука DMR. Из AttachEngineCallbacks флаг не восстанавливается намеренно — слайсы пересозданный движок не наследует вовсе. Заодно: StopStream завершал перебор через Exit прямо из-под try, минуя хвост процедуры, — заменено на Break. Стенд (+3 проверки, негативный контроль в обе стороны): мьют слайса не глушит RX_AUDIO по TCI; без потока молчащий слайс не считается вовсе (наблюдатель — обычный аудио-тап, который теперь права требовать демодуляции не имеет); попросили поток снова — слайс снова в работе. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
+24
-10
@@ -255,6 +255,7 @@ type
|
||||
FMSQLevel: Integer; // порог squelch 0..100
|
||||
SMeter: Double; // последнее показание S-метра канала (dBm), пишет DSP-поток
|
||||
Opened: Boolean; // WDSP-канал реально открыт (после Open движка)
|
||||
TapWanted: Boolean; // этот слайс слушает внешний потребитель (RX_AUDIO по TCI)
|
||||
end;
|
||||
|
||||
// Доп. панадаптер (этап 3): свой DDC-поток (rate 192-768к), свой analyzer
|
||||
@@ -532,7 +533,6 @@ type
|
||||
FIQTapOn: Boolean; // дешёвая проверка «тап вообще есть»
|
||||
// Кто-то (TCI/web) слушает аудио помимо динамика: тогда молчащий (mute)
|
||||
// слайс всё равно надо считать — RX_AUDIO снимается ДО громкости и мьюта.
|
||||
FAudioTapsActive: Boolean;
|
||||
|
||||
function ModeToWDSP(Mode: Integer): Integer;
|
||||
function ModeToWDSPTX(Mode: Integer): Integer;
|
||||
@@ -647,10 +647,14 @@ type
|
||||
// Тап сырого RX-IQ наружу (потоки IQ по TCI). nil — снять. Ставит и
|
||||
// снимает поток контроллера; вызывается тап из DSP-потока.
|
||||
procedure SetIQTap(T: TIQTapEvent);
|
||||
// Есть ли слушатели аудио-тапов (TCI/web). Влияет только на молчащие
|
||||
// слайсы: с ними их всё равно надо считать, иначе клиент TCI остаётся без
|
||||
// Слушает ли слайс кто-то снаружи (поток RX_AUDIO по TCI). Влияет только
|
||||
// на молчащие слайсы: их всё равно надо считать, иначе клиент остаётся без
|
||||
// RX_AUDIO ровно потому, что оператор убрал звук у себя в комнате.
|
||||
procedure SetAudioTapsActive(V: Boolean);
|
||||
// ★Флаг именно ПОСЛАЙСОВЫЙ. Общий «тапы включены» означал бы, что поднятый
|
||||
// TCI-сервер заставляет считать ВСЕ молчащие слайсы — и без клиентов, и
|
||||
// когда клиент качает один слайс из шести, и когда ему нужен только IQ.
|
||||
// Ставит поток контроллера, читает DSP-поток (оба под FSliceLock).
|
||||
procedure SetSliceTapWanted(Id: Integer; V: Boolean);
|
||||
|
||||
// --- Панадаптеры на аппаратных DDC (этап 3.2) ---
|
||||
// Создаёт доп. пан PanId (1..MAX_PANS-1): аккумулятор + analyzer
|
||||
@@ -1522,7 +1526,6 @@ begin
|
||||
// Тап IQ наружу (TCI)
|
||||
FIQTapLock := TCriticalSection.Create;
|
||||
FIQTapOn := False;
|
||||
FAudioTapsActive := False;
|
||||
|
||||
// Мультислайсы
|
||||
FSliceLock := TCriticalSection.Create;
|
||||
@@ -2455,10 +2458,6 @@ begin
|
||||
end;
|
||||
end;
|
||||
|
||||
procedure TWDSPEngine.SetAudioTapsActive(V: Boolean);
|
||||
begin
|
||||
FAudioTapsActive := V;
|
||||
end;
|
||||
|
||||
procedure TWDSPEngine.PushDDCPacket(const Buf: array of Byte;
|
||||
DataOffset: Integer; IQPairs: Integer);
|
||||
@@ -2977,7 +2976,7 @@ begin
|
||||
// ★То же и для тапов: RX_AUDIO по TCI снимается ДО громкости и мьюта, и
|
||||
// молчащий в комнате слайс обязан продолжать отдавать звук клиенту.
|
||||
if FSlices[s].Muted and not (FSlices[s].Mode in [MODE_DMR, MODE_FMRAW])
|
||||
and not FAudioTapsActive then Continue;
|
||||
and not FSlices[s].TapWanted then Continue;
|
||||
// Свежая копия входного IQ — fexchange0 портит вход in-place.
|
||||
for i := 0 to N - 1 do
|
||||
begin
|
||||
@@ -3167,6 +3166,9 @@ begin
|
||||
FSlices[slot].ANFOn := False;
|
||||
FSlices[slot].SMeter := -130.0;
|
||||
FSlices[slot].Opened := False;
|
||||
// Слушателей у нового слайса нет: их проставит владелец потоков (TCI),
|
||||
// когда клиент попросит RX_AUDIO именно с него.
|
||||
FSlices[slot].TapWanted := False;
|
||||
if FInitialized then OpenSliceChannel(slot);
|
||||
Result := True;
|
||||
finally
|
||||
@@ -3289,6 +3291,18 @@ begin
|
||||
end;
|
||||
end;
|
||||
|
||||
procedure TWDSPEngine.SetSliceTapWanted(Id: Integer; V: Boolean);
|
||||
var idx: Integer;
|
||||
begin
|
||||
FSliceLock.Enter;
|
||||
try
|
||||
idx := FindSliceIdx(Id); if idx < 0 then Exit;
|
||||
FSlices[idx].TapWanted := V;
|
||||
finally
|
||||
FSliceLock.Leave;
|
||||
end;
|
||||
end;
|
||||
|
||||
procedure TWDSPEngine.SetSliceMute(Id: Integer; Mute: Boolean);
|
||||
var idx: Integer;
|
||||
begin
|
||||
|
||||
Reference in New Issue
Block a user