Skip to content

Advertise real device capabilities in the ESCL server - #888

Open
zomars wants to merge 1 commit into
cyanfish:masterfrom
zomars:feature/escl-server-real-capabilities
Open

Advertise real device capabilities in the ESCL server#888
zomars wants to merge 1 commit into
cyanfish:masterfrom
zomars:feature/escl-server-real-capabilities

Conversation

@zomars

@zomars zomars commented Aug 20, 2026

Copy link
Copy Markdown
Contributor

This closes the TODO in ScanServer.MakeEsclDeviceConfig ("Ideally we want to get the actual device capabilities (flatbed/feeder, resolution etc.)").

What changes

  • EsclDeviceConfig gets an optional CapabilitiesProvider callback that can asynchronously supply full EsclCapabilities.
  • ScanServer implements the provider by calling ScanController.GetCaps() (the same API the profile dialog uses via DeviceCapsCache) and mapping ScanCaps/PerSourceCaps to the existing EsclCapabilities.PlatenCaps/AdfSimplexCaps/AdfDuplexCaps fields, which so far were only used by the ESCL client.
  • EsclApiController.GetScannerCapabilities generates the Platen/Adf sections from those fields when they are populated, advertising only the paper sources the device actually has, with its real resolutions, color modes and max scan area.

Design notes

  • Lazy + cached: capabilities are queried on the first ScannerCapabilities request rather than at registration, so sharing devices doesn't open device sessions at startup and server startup is never blocked. A successful query is cached for the lifetime of the registration; a failed query falls back to the defaults and is retried on the next request (same policy as DeviceCapsCache).
  • Unchanged fallback: if the driver doesn't provide capabilities (e.g. the current WIA/TWAIN paths), the device is offline, or the query fails, the generated XML is exactly the same as before (Platen + AdfSimplex + AdfDuplex with the default 100-4800 resolution list and A3 max size). No behavior change for setups without caps.
  • Resolutions are taken from DpiCaps.CommonValues rather than Values, since some drivers (e.g. Apple/ICA) report a continuous range with thousands of values that would be unreasonable to enumerate in the XML.
  • The ESCL client is untouched; standard clients (AirScan/iOS, sane-airscan) that respect the advertised capabilities are the main beneficiaries, since they will no longer offer a non-existent ADF or out-of-range resolutions/page sizes.

Testing

  • New ScanServerTests.GetCaps round-trip test (server announces caps from a mock backend, ESCL client parses them back) and ScanServerTests.GetCapsWhenUnavailable fallback test; ran the Remoting test suite plus NAPS2.Escl.Tests on macOS (arm64). One pre-existing failure (ScanWithCorrectOptions, DeviceBusyException when running the whole suite in parallel) reproduces identically on clean master on this machine and is unrelated.
  • Tested against real hardware: an EPSON L3210 (flatbed-only) shared through the Apple/ICA driver on macOS. The server now advertises Platen only (no phantom ADF), the real 8.5x11.7" scan area (2550x3509 in 1/300"), the device serial number, and the driver's preferred resolutions (75-9600), and falls back to the previous XML while the device query hasn't succeeded yet. Verified the cached path returns the same document.

Note: for correct results with the Apple driver this depends on #887 (flatbed/feeder swap in DeviceOperator.GetCaps); without it a flatbed-only Mac device is reported as feeder-only. The two PRs are independent code-wise.

Closes the TODO in ScanServer.MakeEsclDeviceConfig by querying the shared
device's actual capabilities via ScanController.GetCaps and using them to
generate the ScannerCapabilities XML, so only the paper sources the device
actually has are advertised (with its real resolutions, color modes and
scan area).

Capabilities are queried lazily on the first ScannerCapabilities request
and cached; if the query fails or the driver doesn't provide capabilities,
the previous hardcoded capabilities are served unchanged.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant