mirror of
https://git.vladimir.cc/vladimir/ewsdr.git
synced 2026-08-25 17:27:32 +00:00
feature(tx): слайс в FM RAW можно назначать источником передачи
TX-бейдж на флаге слайса был заблокирован и для DMR, и для FM RAW, хотя тракт FM RAW передавать умеет: SetTxSlice отбрасывает только DMR, а SetTXMode уводит FM RAW в WFM с плоской девиацией. RX-only остаётся один DMR (нет AMBE-кодера). - VfoOverlay.TxSelectionAllowed: запрет сузился до DMR. - RadioController.SetSliceMode: если режим меняют у слайса, который сейчас источник TX, передающий тракт перестраивается под новый режим. Без этого выбор FM RAW на уже выбранном TX-слайсе оставлял в эфире прежнюю модуляцию до следующего клика по бейджу. На переходах в/из FM RAW заодно пересматривается источник модуляции (внешний PCM) со сбросом кольца входа — как в главном SetMode. Заодно снята временная диагностика [MIC] (MicDbg и её вызовы) из mic-пула: зависание при выборе на слайсе входа из настроек больше не воспроизводится. Проверено на железе: TX со слайса в FM RAW работает. Подробное тестирование — следующим шагом. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
+17
-37
@@ -2019,6 +2019,21 @@ begin
|
||||
if (Mode = MODE_DMR) and (FTxSliceId = Id) then SetTxSlice(0);
|
||||
if (OldMode = MODE_DMR) and (Mode <> MODE_DMR) then
|
||||
FreeAndNil(FSlices[idx].DMR);
|
||||
// Этот слайс — источник передачи: передающий тракт идёт за его режимом
|
||||
// (иначе после смены режима в эфир ушёл бы прежний вид модуляции). Вход FM
|
||||
// RAW — внешний PCM, поэтому заодно пересматриваем источник модуляции.
|
||||
if (FTxSliceId = Id) and (Mode <> OldMode) and
|
||||
FWDSPReady and Assigned(FDSPEngine) then
|
||||
begin
|
||||
FDSPEngine.SetTXMode(ActiveTXMode);
|
||||
if (Mode = MODE_FMRAW) or (OldMode = MODE_FMRAW) then
|
||||
begin
|
||||
if Mode = MODE_FMRAW then FWebMicActive := False;
|
||||
FDSPEngine.SetTXMicSource(DefaultMicSource);
|
||||
if Assigned(ActiveMicInput) and ActiveMicInput.IsOpen then
|
||||
ActiveMicInput.Flush;
|
||||
end;
|
||||
end;
|
||||
end;
|
||||
|
||||
procedure TRadioController.SetSliceFilter(Id, Low, High: Integer);
|
||||
@@ -2197,14 +2212,6 @@ end;
|
||||
|
||||
// --- Пул входных потоков -----------------------------------------------------
|
||||
|
||||
procedure MicDbg(const S: string);
|
||||
// ВРЕМЕННО: диагностика mic-пула в stderr (поиск причины зависания/отказа
|
||||
// Pa_OpenStream при выборе входа на слайсе). Снять после разбора.
|
||||
begin
|
||||
WriteLn(StdErr, '[MIC] ', S);
|
||||
Flush(StdErr);
|
||||
end;
|
||||
|
||||
function TRadioController.AcquireMicInput(DevIndex: Integer): TAudioInput;
|
||||
// Ссылка на открытый поток устройства DevIndex (создаёт при первом обращении).
|
||||
// DevIndex<0 = «своего входа нет» → nil (читатель упадёт на общий FAudioIn).
|
||||
@@ -2213,25 +2220,14 @@ var
|
||||
AI: TAudioInput;
|
||||
begin
|
||||
Result := nil;
|
||||
if Assigned(FAudioIn) then
|
||||
MicDbg(Format('Acquire(dev=%d): main FAudioIn dev=%d open=%s name="%s"',
|
||||
[DevIndex, FAudioIn.DeviceIndex, BoolToStr(FAudioIn.IsOpen, True),
|
||||
FAudioInDevName]))
|
||||
else
|
||||
MicDbg(Format('Acquire(dev=%d): FAudioIn=nil', [DevIndex]));
|
||||
if DevIndex < 0 then Exit;
|
||||
// Общий вход уже открыт на этом же устройстве — переиспользуем его: второй
|
||||
// Open того же PA-устройства на эксклюзивном ALSA-hw просто не прошёл бы.
|
||||
if Assigned(FAudioIn) and (FAudioIn.DeviceIndex = DevIndex) then
|
||||
begin
|
||||
MicDbg(' -> общий FAudioIn (без открытия)');
|
||||
Exit(FAudioIn);
|
||||
end;
|
||||
for i := 0 to High(FMicPool) do
|
||||
if FMicPool[i].DevIdx = DevIndex then
|
||||
begin
|
||||
MicDbg(Format(' -> пул[%d] refs=%d open=%s',
|
||||
[i, FMicPool[i].Refs, BoolToStr(FMicPool[i].AI.IsOpen, True)]));
|
||||
// Запись с Refs=0 — поток закрыт, но объект жив (см. ReleaseMicInput).
|
||||
if (FMicPool[i].Refs <= 0) and FLocalAudio and
|
||||
(not FMicPool[i].AI.IsOpen) then
|
||||
@@ -2242,15 +2238,7 @@ begin
|
||||
AI := TAudioInput.Create(48000);
|
||||
AI.DeviceIndex := DevIndex;
|
||||
if FLocalAudio then
|
||||
begin
|
||||
MicDbg(Format(' новый поток: Open(dev=%d) ...', [DevIndex]));
|
||||
try
|
||||
MicDbg(Format(' Open(dev=%d) = %s err="%s"',
|
||||
[DevIndex, BoolToStr(AI.Open, True), AI.LastError]));
|
||||
except
|
||||
on E: Exception do MicDbg(' Open исключение: ' + E.Message);
|
||||
end;
|
||||
end;
|
||||
try AI.Open; except end;
|
||||
n := Length(FMicPool);
|
||||
SetLength(FMicPool, n + 1);
|
||||
FMicPool[n].DevIdx := DevIndex;
|
||||
@@ -2304,8 +2292,6 @@ procedure TRadioController.SetSliceInDeviceIdx(Idx, DevIndex: Integer;
|
||||
const DevName: string);
|
||||
begin
|
||||
if (Idx < 0) or (Idx >= MAX_SLICES) or (not FSlices[Idx].Active) then Exit;
|
||||
MicDbg(Format('SetSliceInDevice: slot=%d id=%d dev=%d name="%s"',
|
||||
[Idx, FSlices[Idx].Id, DevIndex, DevName]));
|
||||
if DevName = '' then DevIndex := -1;
|
||||
ReleaseMicInput(FSlices[Idx].AudioIn);
|
||||
FSlices[Idx].InDeviceIndex := DevIndex;
|
||||
@@ -2321,18 +2307,12 @@ procedure TRadioController.SetMainMicDevice(DevIndex: Integer;
|
||||
const DevName: string);
|
||||
var i: Integer;
|
||||
begin
|
||||
MicDbg(Format('SetMainMicDevice: dev=%d name="%s"', [DevIndex, DevName]));
|
||||
if Assigned(FAudioIn) then
|
||||
begin
|
||||
if FAudioIn.IsOpen then FAudioIn.Close;
|
||||
FAudioIn.DeviceIndex := DevIndex;
|
||||
if (DevIndex >= 0) and FLocalAudio then
|
||||
try
|
||||
MicDbg(Format(' main Open(dev=%d) = %s err="%s"',
|
||||
[DevIndex, BoolToStr(FAudioIn.Open, True), FAudioIn.LastError]));
|
||||
except
|
||||
on E: Exception do MicDbg(' main Open исключение: ' + E.Message);
|
||||
end;
|
||||
try FAudioIn.Open; except end;
|
||||
end;
|
||||
FAudioInDevName := DevName;
|
||||
// Слайсы могли ссылаться на общий вход (или держать свой поток на устройстве,
|
||||
|
||||
Reference in New Issue
Block a user