feat: Pluto support in headless daemon (connect/autostart/discover/dev_add) + headless audio

The headless daemon (ewsdrd) only ever built HPSDR devices, so Pluto
could not be used: backend is chosen by Dev.Kind and Pluto opens by URI,
neither of which the daemon propagated. Also local audio played on the
host and web Discover never probed network Plutos.

Shared, backend-agnostic helpers in TRadioController (used by GUI + daemon):
- ResolveDevice(IP): discovered->saved lookup restoring Kind/URI/Serial/
  BoardType/MAC. MainForm.ResolveDevice now delegates here.
- AddSavedDevice(name, addr): web dev_add saves Pluto when addr has a URI
  scheme (ip:/usb:/local:), else HPSDR. Both web hosts use it.
- SeedPlutoProbeFromSaved: seed network-probe URIs from saved Plutos
  (no mDNS -> a network Pluto is only found by direct URI probe).
- LocalAudioEnabled flag (GUI=True): when False the local sound card is
  neither opened nor written; RX audio goes only to web (OnAudioConsume).

DeviceStore.AutoStartDevice(out Dev): full autostart record (Kind/URI/
Serial) so a saved Pluto (URI-addressed, empty IPAddress on USB) can
autostart.

Daemon (ewsdrd.lpr): LocalAudioEnabled:=False; SyncConnect via
ResolveDevice; autostart via AutoStartDevice; SyncDiscover seeds probe
URIs then Discover; SyncDevAdd via AddSavedDevice.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
2026-06-23 13:32:05 +03:00
co-authored by Claude Opus 4.8
parent 3115b2b5bf
commit d78d835485
4 changed files with 174 additions and 88 deletions
+16
View File
@@ -62,6 +62,9 @@ type
procedure SetAutoStart(Idx: Integer); // эксклюзивно: только одно autostart
function AutoStartIP: string;
function AutoStartBoardType: Integer;
// Полная autostart-запись (Kind/URI/Serial) — для бэкенд-агностичного автозапуска
// (Pluto открывается по URI, у USB-Pluto IPAddress пуст). False — нет autostart.
function AutoStartDevice(out Dev: TSavedDevice): Boolean;
function SavedBoardType(Idx: Integer): Integer;
function SavedDisplay(Idx: Integer): string; // строка для списка (с * и board)
@@ -242,6 +245,19 @@ begin
end;
end;
function TDeviceStore.AutoStartDevice(out Dev: TSavedDevice): Boolean;
var
I: Integer;
begin
Result := False;
for I := 0 to FSavedCount - 1 do
if FSaved[I].AutoStart then
begin
Dev := FSaved[I];
Exit(True);
end;
end;
function TDeviceStore.SavedBoardType(Idx: Integer): Integer;
begin
if (Idx >= 0) and (Idx < FSavedCount) then