fix(tci): пара «клиент+приёмник» только по факту передачи; перебор имён .part

[P1] FTxClient/FTxRx писались ДО Invoke, и команда, которая ничего не сделала,
всё равно их перебивала. Клиент, уже передающий с приёмника 1, шлёт
trx:0,true,tci — передатчик занят, SyncSetTRX не делает ничего (Started=False),
а маркеры ИДУЩЕЙ передачи с этого мига уходят под номером 0. MSHV такие блоки
отбрасывает (network.cpp:231), то есть передача просто замолкает. Теперь пара
назначается после Invoke и только при Started — тем же признаком, по которому
назначается хозяин эфира. Тот же гейт закрывает близнеца: trx:<N>,true без
',tci' поверх своей же передачи больше не снимает источник модуляции. Снятие
(',false') работает как прежде.

[P2] Имя временного файла (pid + счётчик) уникально внутри процесса, но не
между запусками: «.part», оставшийся от прошлой жизни (публиковать было
нечем), плюс повторно выданный системой pid дают EEXIST на создании — и
задание пропадало молча. TCICreateTempNear перебирает до 64 имён, но только
пока ошибка — «имя занято»: нет прав или каталога перебором не лечится.

Стенд test/tci: 219 проверок (было 217). Новое — занятое имя «.part» записи не
теряет (стенд занимает ровно то имя, которое возьмёт писатель) и пустая
команда TRX не меняет номер приёмника в маркерах. Негативный контроль на обе
правки. Попутно в тесте поправлены два комментария, описывавшие прежнюю
реализацию публикации.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
2026-08-19 22:02:40 +03:00
co-authored by Claude Opus 5
parent ecd42c32f8
commit 66892fc7e0
4 changed files with 143 additions and 24 deletions
+29 -8
View File
@@ -1962,14 +1962,6 @@ begin
Tune := M.Name = 'TUNE';
Name := LowerCase(Trim(TCIArg(M, 2)));
FromTCI := B and (not Tune) and (Name = 'tci') and HasAudioStream(Client);
FTxLock.Enter;
try
// ★Вместе с клиентом запоминаем НОМЕР ПРИЁМНИКА, которым он назвался:
// маркеры TX_CHRONO обязаны идти под ним же (см. PushTxChrono).
if FromTCI then begin FTxClient := Client; FTxRx := Rx; end
else if (not Tune) and (FTxClient = Client) then
begin FTxClient := nil; FTxRx := 0; end;
finally FTxLock.Leave; end;
Started := False;
FLock.Enter;
try
@@ -1991,6 +1983,35 @@ begin
try
if Started then FTrxOwner := Client
else if (not B) and (FTrxOwner = Client) then FTrxOwner := nil;
// Источник модуляции и НОМЕР ПРИЁМНИКА, под которым идут маркеры
// TX_CHRONO (см. PushTxChrono), — по тому же правилу: меняем их
// ТОЛЬКО когда команда и правда что-то сделала.
// ★Раньше пара «клиент+приёмник» писалась до Invoke, и команда, которая
// ничего не изменила, всё равно её перебивала: клиент, уже
// передававший с приёмника 1, присылает trx:0,true,tci — передатчик
// занят, SyncSetTRX не делает ничего, а маркеры его же идущей передачи
// с этого мига уходят под номером 0. MSHV такие блоки отбрасывает
// (network.cpp:231), то есть передача просто замолкает.
if B then
begin
if Started and FromTCI then
begin
FTxClient := Client;
FTxRx := Rx;
end
// Эфир поднял он же, но модуляцию просит НЕ из TCI — снимаем свою.
else if Started and (not Tune) and (FTxClient = Client) then
begin
FTxClient := nil;
FTxRx := 0;
end;
end
// Сам просит выключить — источник ему больше не нужен в любом случае.
else if (not Tune) and (FTxClient = Client) then
begin
FTxClient := nil;
FTxRx := 0;
end;
finally FTxLock.Leave; end;
end;
// ★Автору отвечаем ЕГО номером приёмника (см. StrTrx): клиент фильтрует