mirror of
https://git.vladimir.cc/vladimir/ewsdr.git
synced 2026-08-25 20:37:33 +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:
+13
-12
@@ -251,7 +251,6 @@ type
|
||||
FAudioTapCount: LongInt; // быстрый гейт: без тапов не берём и лок
|
||||
FIQTap: TIQTapEvent; // тап IQ (TCI): помним ради пересоздания движка
|
||||
procedure Changed(Field: TRadioField);
|
||||
procedure PushAudioTapsActive;
|
||||
procedure FireAudioTap(Kind: TRadioAudioKind; PanId, SliceId: Integer;
|
||||
const Left, Right: array of Single; Count: Integer);
|
||||
// --- Мультислайсы ---
|
||||
@@ -911,6 +910,11 @@ type
|
||||
procedure SetSliceAGCMode(Id: Integer; AGC: TWDSPAGCMode);
|
||||
procedure SetSliceVolume(Id: Integer; Vol: Double); // 0..1
|
||||
procedure SetSliceMute(Id: Integer; Mute: Boolean);
|
||||
// Слайс слушает внешний потребитель (поток RX_AUDIO по TCI): молчащий в
|
||||
// комнате слайс обязан считаться, пока его кто-то качает по сети. Зеркала
|
||||
// в TCtrlSlice нет намеренно — флаг принадлежит владельцу потоков, а не
|
||||
// модели, и пересоздание движка слайсы всё равно не переживают.
|
||||
procedure SetSliceTapWanted(Id: Integer; V: Boolean);
|
||||
procedure SetSliceRxMuteOnTx(Id: Integer; On_: Boolean); // self-monitor слайса на TX
|
||||
function PanPrimarySliceId(PanId: Integer): Integer; // первый созданный слайс пана
|
||||
function PanHasFMSlice(PanId: Integer): Boolean; // есть слайс в канальном режиме (FM/DMR/FMRAW)?
|
||||
@@ -1425,7 +1429,9 @@ begin
|
||||
FDSPEngine.SetDisplayResLimit(FDisplayPixels);
|
||||
// Тапы наружу (TCI): их владелец живёт дольше движка.
|
||||
FDSPEngine.SetIQTap(FIQTap);
|
||||
PushAudioTapsActive;
|
||||
// Послайсовые флаги «этот слайс слушают» сюда не входят: слайсы пересозданный
|
||||
// движок не наследует вовсе (их заводит заново тот, кто их создавал), а
|
||||
// владелец потоков расставит флаги на первом же обновлении карты слайсов.
|
||||
// Декодер маяка QO-100 создаётся позже самого движка (в CreateEngines ниже),
|
||||
// зато при ПЕРЕсоздании движка он уже есть и его надо вернуть на место.
|
||||
if Assigned(FBeaconDec) then FDSPEngine.SetBeaconDecoder(FBeaconDec);
|
||||
@@ -1585,7 +1591,6 @@ begin
|
||||
finally
|
||||
FAudioTapLock.Leave;
|
||||
end;
|
||||
PushAudioTapsActive;
|
||||
end;
|
||||
|
||||
procedure TRadioController.RemoveAudioTap(T: TRadioAudioTapEvent);
|
||||
@@ -1606,15 +1611,6 @@ begin
|
||||
finally
|
||||
FAudioTapLock.Leave;
|
||||
end;
|
||||
PushAudioTapsActive;
|
||||
end;
|
||||
|
||||
procedure TRadioController.PushAudioTapsActive;
|
||||
// Движку интересен только факт «слушатели есть»: от него зависит, считать ли
|
||||
// молчащие (mute) слайсы — их звук всё равно уходит в RX_AUDIO по TCI.
|
||||
begin
|
||||
if Assigned(FDSPEngine) then
|
||||
FDSPEngine.SetAudioTapsActive(FAudioTapCount > 0);
|
||||
end;
|
||||
|
||||
procedure TRadioController.FireAudioTap(Kind: TRadioAudioKind;
|
||||
@@ -2847,6 +2843,11 @@ begin
|
||||
SliceStateChanged(Id);
|
||||
end;
|
||||
|
||||
procedure TRadioController.SetSliceTapWanted(Id: Integer; V: Boolean);
|
||||
begin
|
||||
if Assigned(FDSPEngine) then FDSPEngine.SetSliceTapWanted(Id, V);
|
||||
end;
|
||||
|
||||
procedure TRadioController.SetSliceRxMuteOnTx(Id: Integer; On_: Boolean);
|
||||
var idx: Integer;
|
||||
begin
|
||||
|
||||
Reference in New Issue
Block a user