Skip to content

fix: name unconfigured HD-PS622 ports to prevent load failure - #44

Open
equinoy wants to merge 46 commits into
feature/add-essentials-v3-compatibilityfrom
fix/hdps622-unnamed-port-keynotfound
Open

equinoy wants to merge 46 commits into
feature/add-essentials-v3-compatibilityfrom
fix/hdps622-unnamed-port-keynotfound

Conversation

@equinoy

@equinoy equinoy commented Sep 25, 2026

Copy link
Copy Markdown
Contributor

Problem

HdPsXxxController looked up InputNames[index] / OutputNames[index] with the throwing dictionary indexer. Any physical port the config does not name therefore raised KeyNotFoundException during construction.

On an HD‑PS622 the chassis exposes 8 inputs (HDMI 1‑6 + DM 7‑8) and 4 outputs (HDMI/DM‑Lite pairs), but a typical config only names the HDMI ports it uses (1‑6). SetupInputs then hit InputNames[7] and threw. Because this happened in the constructor, the device failed to load as a generic "Cannot load unknown device type 'hdps622'", and every tie line targeting the switcher dropped — routing was silently dead.

Observed on a processor:

[switcher] Adding Input port: hdmiIn1..6
ERROR: Cannot load unknown device type 'hdps622', key 'switcher'.
...
Cannot create tie line: Routable destination not found   (x8)

Fix

Backfill default names for all physical inputs/outputs (HDMI Input N / DM Input N / Output N) before setup, so name lookups never throw for a port the integrator didn't name. Config‑supplied names still win. This also hardens the bridge/feedback paths that index the same dictionaries.

Result (verified on hardware)

[switcher] Adding Input port: hdmiIn1..6, dmLiteIn7 - DM Input 7, dmLiteIn8 - DM Input 8
[switcher] Adding Output port: hdmiOut1/dmLiteOut1/hdmiOut2/dmLiteOut2
Register device result: 'switcher', type 'HD-PS622 IP-ID-D0', result Success
All Tie Lines Loaded.  →  listtielines: Total 9 tielines

Routing resolves end‑to‑end through the switcher; GETROUTINGPORTS shows all 8 inputs / 4 outputs.

Note for reviewers

This branch also pins PepperDashEssentials to 3.0.0-rc.4 (was 3.0.0-feat-routing-slot-online-sync.1) to match the deployment target. That's a baseline change for the repo — please confirm it's the intended Essentials line for feature/add-essentials-v3-compatibility before merge. If not, I can drop that hunk and keep only the port‑naming fix.

Built clean against rc.4 (0 Error(s)).

cdenig and others added 30 commits April 8, 2026 14:21
- input '0' value caused null reference exception
Improved logging clarity and consistency by explicitly importing PepperDash.Core.Logging and updating log statements. Enhanced feedback handling, especially for video sync detection and input resolution changes. Removed redundant lines and improved formatting for better readability and maintainability. No changes to core functionality.
…tputController (#29)

Update PepperDashEssentials NuGet reference from v2.7.0 to v2.29.0.

IBasicVolumeControls now extends IKeyName, requiring Key and Name
properties. DmpsAudioOutput and DmCardAudioOutputController implement IBasicVolumeWithFeedback but are not EssentialsDevice subclasses, so they lacked these properties, causing VTable initialization failures at runtime on processors running Essentials v2.29.0."
DmCardAudioOutputController and DmpsAudioOutput implement
IBasicVolumeWithFeedback, which now chains to IKeyName/IKeyed and requires
Key and Name members. Add them via an optional constructor parameter with a
sensible derived default, threading unique keys at the DmCardAudioOutputController
chassis call sites. These helpers are not registered with DeviceManager, so the
values are used for identification/logging only.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Implement the new IHasWirelessSharing interface on AirMediaController so room
plugins and other consumers can react to wireless sharing activity without
depending on the concrete device type. IsSharingFeedback aliases the existing
IsInSessionFeedback, and a SharingChanged event is raised from the existing
AirMedia status handler.

Bump PepperDashEssentials to 2.37.0-feature-air-media-sharing-interface.1, the
version that introduces IHasWirelessSharing.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
routing.21 removed the routing-interface family this plugin used. Migrate onto
the consolidated replacements without changing hardware-switching behavior:

- Bump PepperDashEssentials to 3.0.0-dev-v3-routing.21.
- Add plugin-local IDmInputSlot / IDmOutputSlot (replace removed
  IRoutingInputSlot / IRoutingOutputSlot; slot model is plugin-internal) and
  plugin-local ITxRouting(WithFeedback) / IRmcRouting(WithFeedback)
  : IRoutingMidpointWithFeedback.
- IRoutingInputsOutputs -> IRoutingMidpoint on endpoint/passthrough controllers.
- IRoutingNumeric(WithFeedback) / IRouting / IMatrixRouting -> consolidated
  IRoutingMidpointWithFeedback on chassis/midpoint controllers; add the
  newly-required ClearRoute / CurrentRoutes / RouteChanged members, populated
  from existing switch feedback. Shared TX members implemented once in
  DmTxControllerBase.
- DmChassisController: drop IMatrixRouting (kept IRoutingMidpointWithFeedback);
  retype InputSlots/OutputSlots to the plugin-local slot interfaces.

Crestron switching logic (DMOutput.VideoOut/AudioOut/USBRoutedTo, off-timers,
feedback wiring) is unchanged. Builds clean against routing.21; all 84 plugin
validation tests pass. Hardware validation pending.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
… Wyrestorm)

Brings the DM routing-feedback surface in line with the reviewed
Wyrestorm NetworkHD migration:

- IDmOutputSlot/DmMatrixOutput.CurrentRoutes now exposed as
  IReadOnlyDictionary so route state can't be mutated outside
  SetInputRoute (which raises OutputSlotChanged).
- DmMatrixClearInput (the "none"/route-off sentinel) caches a single
  IsOnline BoolFeedback reporting online, instead of allocating a new
  offline feedback on every access.
- Removed the dead VideoSyncDetected/VideoSyncChanged surface from
  IDmInputSlot (no consumers); kept concrete on DmMatrixInput only.
  Drops the CS0067 pragma from the sentinel.
- DmMatrixOutput ctor no longer swallows exceptions into a half-built,
  still-registered slot; it validates/throws and the chassis call site
  skips-and-logs a failed slot so one bad card can't poison startup.

Build clean (0 warnings); 84 tests pass. Hardware-switching logic
unchanged. The chassis breakaway CurrentRoutes clobber (output-only
removal key) is tracked separately and not addressed here.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
- Log a warning when chassis video/audio route feedback can't resolve a
  matching output/input port (distinguishes a genuine route-off from a
  lookup miss that would otherwise silently report no source).
- Drop the dead Usb seed from DmMatrixOutput.currentRoutes (never set;
  the output only tracks Video/Audio from hardware feedback).
- Null-guard the DmMatrixInput constructor (device/videoSyncfeedback).
- Comment accuracy: document the known output-only keying limitation on
  UpdateCurrentRoute (breakaway A/V clobber, tracked separately); correct
  the "plugin-private" slot-dictionary claim (they're public members, just
  no longer part of a core routing contract); fix the orphaned doc block
  on Chassis_DMOutputChange.

Build clean (0 warnings); 84 tests pass.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…t tests

Fixes the breakaway-routing clobber in the new IRoutingMidpointWithFeedback
surface (#1) and adds the first laptop unit tests of the route-feedback
bookkeeping (#10).

Problem: the chassis recorded CurrentRoutes keyed on the output port only.
DM output/input ports are typed Audio|Video and the same RoutingOutputPort
instance is reported for both the video and audio feedback events, so an
audio route and a video route to the same output overwrote each other — DM
breakaway (independent A/V) routes could not be represented, and RouteChanged
reported the wrong/missing signal.

Change:
- New DmRouteFeedbackTracker maintains CurrentRoutes keyed on the explicit
  (output port, signal type) pair — signal type from the feedback event is
  the only reliable discriminator since the ports are AudioVideo-typed. Pure
  bookkeeping over Crestron-free Essentials.Core routing types.
- DmChassisController, DmTxControllerBase, and DmRmc4kZScalerCController now
  delegate to the shared tracker, replacing three near-duplicate, divergent
  implementations (the chassis keyed output-only; the TX keyed on InputPort
  .Type, which also fails when input ports are AudioVideo).
- Tests: tests/DmRouteFeedbackTrackerTests.cs links the production helper and
  exercises breakaway coexistence, per-signal replace, per-signal route-off,
  multi-output isolation, null-output guard, Clear(), and list-instance
  stability. Required referencing PepperDash.Essentials.Core in the test
  project (the routing port/descriptor types are Crestron-free, so they load
  in the test host even though the plugin itself is reflection-only).

Build clean (0 warnings); 91 tests pass (84 existing + 7 new).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Essentials 2.28.1 added IKeyed and IKeyName to IBasicVolumeWithFeedback.
DmpsAudioOutput and DmCardAudioOutputController did not implement Key or
Name, so Mono vtable setup failed at type load and the plugin loader logged
errors for DmpsAudioOutput, DmpsAudioOutputWithMixer, and
DmpsAudioOutputWithMixerAndEq on every processor.

Add Key/Name to both classes, thread a key through the DmpsAudioOutput
hierarchy and its call sites, bump PepperDashEssentials to 2.39.0, and raise
MinimumEssentialsFrameworkVersion to 2.28.1 across the factories.
Co-authored-by: erikdred <88980320+erikdred@users.noreply.github.com>
…utput' into feature/routing21-migration

# Conflicts:
#	src/Chassis/DmCardAudioOutput.cs
#	src/Chassis/DmChassisController.cs
#	src/PepperDash.Essentials.DM.csproj
erikdred and others added 14 commits August 19, 2026 14:23
…ace' into feature/routing21-migration

# Conflicts:
#	src/AirMedia/AirMediaController.cs
#	src/Chassis/DmCardAudioOutput.cs
#	src/Chassis/DmpsAudioOutputController.cs
#	src/PepperDash.Essentials.DM.csproj
…ons' into feature/routing21-migration

# Conflicts:
#	src/AirMedia/AirMediaController.cs
#	src/Chassis/DmBladeChassisController.cs
#	src/Chassis/DmCardAudioOutput.cs
#	src/Chassis/DmChassisController.cs
#	src/Chassis/DmpsAudioOutputController.cs
#	src/Chassis/DmpsRoutingController.cs
#	src/Chassis/HdMd8xNController.cs
#	src/Chassis/HdMdNxM4kEBridgeableController.cs
#	src/Chassis/HdPsXxxController.cs
#	src/DmLite/HdMdxxxCEController.cs
#	src/Endpoints/DGEs/Dge100Controller.cs
#	src/Endpoints/DGEs/DmDge200CController.cs
#	src/Endpoints/Receivers/DmRmcHelper.cs
#	src/Endpoints/Transmitters/DmTxHelpers.cs
#	src/PepperDash.Essentials.DM.csproj
#	src/VideoWindowing/HdWp4k401cController.cs
…ew.1

The public 3.0.0-rc.2 Core package does not contain IHasWirelessSharing (that interface only shipped on the release/feature tags, never merged into rc), so CI could not compile AirMediaController and the release build produced no artifact. Repin both PepperDashEssentials and PepperDash.Essentials.Core to the published 3.0.0-feat-update-ihaswebview.1, which contains the interface, and drop the stale local-override comment.
Add named input/output routing slots (per-signal-type route feedback for the mobile-control matrix routing page) to the seven DM matrix midpoints that had IRoutingMidpointWithFeedback but not IHasNamedRoutingSlots: DmBladeChassisController, HdMd8xNController, HdMdNxM4kEBridgeableController, HdMdNxM4kzEController, HdPsXxxController, HdMdxxxCEController, DmpsRoutingController. DmChassisController already had it.

New reusable RoutingPortNamedSlots helper builds slots from each controller's InputPorts/OutputPorts and tracks the routed input per signal type (lazy-built so port-population timing is irrelevant); fed from each controller's existing route-feedback hook. Adds 8 Crestron-free xUnit tests.
The plugin references PepperDashEssentials with <ExcludeAssets>runtime</ExcludeAssets> (so the .cplz doesn't ship framework DLLs), which strips the Essentials assemblies (Core, mobile-control-messengers, ...) from both the plugin output dir and its deps.json. The FactoryDiscoveryTests' MetadataLoadContext resolver relied on exactly those sources, so GetTypes() threw 'Could not find assembly' for every factory (19 failures).

Resolve the full restore graph from the plugin's project.assets.json libraries list (which ExcludeAssets does not strip) by enumerating each package's lib folder on disk - the assets file's per-target runtime section is itself reduced to a _._ placeholder, so it can't be used. Also add the test host output dir as a resolution source. Plugin packaging is unchanged; all 99 tests now pass.
Devices implementing IHasNamedRoutingSlots publish slot keys that mobile
control's matrix routing sends straight back as the route selector, but every
ExecuteSwitch here cast the selector directly to its Crestron type. A string
selector cast to null, so the switch was dropped with "Unable to execute switch
for inputSelector matrixInput-1 to outputSelector matrixOutput-4" and routing
from the matrix page did nothing. MockRoutingMidpoint works only because it
makes slot key, port name and port Selector the same string.

The two slot models need different translations, so each resolves its own:

- DmChassisController publishes "matrixInput-N"/"matrixOutput-N" from
  DmMatrixInput/DmMatrixOutput, so it maps a key through the slot's SlotNumber
  (read off the hardware object, not parsed from the key, which matters for the
  dual-output cards whose keys are derived as 2n-1/2n) to Chassis.Inputs and
  Chassis.Outputs. Also applied to the two USB out-to-out casts.
- The blade chassis and the HdMd/HdPs controllers publish port keys through
  RoutingPortNamedSlots, so the shared RoutingSelectorResolver looks the key up
  in the port collection and returns that port's Selector.

Both keep passing a real selector object straight through, so existing callers
are unaffected, and both return null for a null selector so ClearRoute (which
delegates to ExecuteSwitch) still reads it as "clear this output".

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01NuA3AHfaUo9qJxhDyRU3pD
f5b2955 covered five of the eight controllers implementing IHasNamedRoutingSlots
here; HdMd8xNController, DmpsRoutingController and HdMdxxxCEController were
missed and still drop every route sent from mobile control's matrix page.

The first two take the same fix as their siblings. HdMdxxxCEController selects by
slot number rather than by a Crestron object, so Resolve<T>'s reference-type
constraint does not fit it: ResolveSelector is the same lookup untyped, with
Resolve<T> now delegating to it so there is still one implementation. Its
Convert.ToUInt32 also threw straight out of the messenger action on any
non-numeric selector, so it now logs and returns like every other controller
here.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01NuA3AHfaUo9qJxhDyRU3pD
…nterfaces

Implement the new core IRoutingInputSlotInfo/IRoutingOutputSlotStatus on the
NVX matrix slot abstractions so the shared IHasNamedRoutingSlotsMessenger emits
per-endpoint isOnline and videoSyncDetected to mobile control. INvxInputSlot/
INvxOutputSlot now extend the core interfaces (the slot classes already exposed
the members); add IsOnline to NvxMatrixOutput.

Bump PepperDashEssentials to 3.0.0-feat-routing-slot-online-sync.1.
The test project pinned PepperDash.Essentials.Core
3.0.0-feat-named-routing-slots.1 while the main project references
PepperDashEssentials 3.0.0-feat-routing-slot-online-sync.1. That older
Core lacks the IRoutingInputSlotInfo/IRoutingOutputSlotStatus sync
members the DM slots now implement, so tests loaded stale interfaces.
Bump the test reference to 3.0.0-feat-routing-slot-online-sync.1 to
match.
DmMatrixClearInput only imported PepperDash.Essentials.Core, so
EventHandler was unresolved (CS0246) and its VideoSyncChanged event
failed to satisfy IRoutingInputSlotInfo.VideoSyncChanged (CS0738).
Add `using System;`.
HdPsXxxController indexed InputNames/OutputNames with the throwing dictionary indexer, so any physical port the config did not name (e.g. the HD-PS622's DM inputs 7-8 on top of HDMI 1-6) raised KeyNotFoundException during construction. The device then failed to load as a generic 'unknown device type' and every tie line to it dropped.

Backfill default names for all physical inputs/outputs so lookups never throw. Also pins PepperDashEssentials to 3.0.0-rc.4.

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot review overview

🟡 Changes recommended

Unresolved critical findings affect midpoint route feedback and route clearing, and the test dependency does not match rc.4.

Get a fresh assessment by requesting another Copilot review.

Review effort: Lite
Findings: 6 High severity

Open (6)
What changed in this PR

Updates Essentials v3 routing compatibility and prevents unconfigured HD-PS622 ports from failing device construction.

Changes:

  • Adds default HDMI, DM-Lite, and output names.
  • Introduces named routing slots, selector resolution, and feedback tracking.
  • Migrates controllers, tests, fixtures, schemas, and pins Essentials to 3.0.0-rc.4.
File Reviewed change
tests/​RoutingSelectorResolverTests.cs Tests selector translation.
tests/​RoutingPortNamedSlotsTests.cs Tests named-slot behavior.
tests/​PepperDash.Essentials.DM.Tests.csproj Adds routing test dependencies.
tests/​DmRouteFeedbackTrackerTests.cs Tests route tracking.
tests/​AssemblyFixture.cs Expands dependency resolution.
tests/​_testFiles/​dm-md8x8-test-configurationFile.json Adds test configuration.
tests/​_testFiles/​dm-md8x8-devjson-test-commands.md Adds routing command fixtures.
src/​VideoWindowing/​HdWp4k401cController.cs Prevents duplicate feedback keys.
src/​Routing/​RoutingSelectorResolver.cs Resolves named selectors.
src/​Routing/​RoutingPortNamedSlots.cs Provides reusable named slots.
src/​Routing/​ITxRouting.cs Defines transmitter routing interfaces.
src/​Routing/​IRmcRouting.cs Defines receiver routing interfaces.
src/​Routing/​IDmOutputSlot.cs Adds output-slot abstraction.
src/​Routing/​IDmInputSlot.cs Adds input-slot abstraction.
src/​Routing/​DmRouteFeedbackTracker.cs Tracks signal-specific routes.
src/​Routing/​DmMatrixOutput.cs Migrates output slots.
src/​Routing/​DmMatrixInput.cs Migrates input slots.
src/​Routing/​DmMatrixClearInput.cs Updates clear-route handling.
src/​PepperDash.Essentials.DM.csproj Pins Essentials to 3.0.0-rc.4.
src/​Endpoints/​Transmitters/​HDBaseTTxController.cs Migrates transmitter routing.
src/​Endpoints/​Transmitters/​DmTxHelpers.cs Adds transmitter route tracking.
src/​Endpoints/​Transmitters/​DmTx4kz302CController.cs Updates transmitter feedback routing.
src/​Endpoints/​Transmitters/​DmTx4kz202CController.cs Updates transmitter feedback routing.
src/​Endpoints/​Transmitters/​DmTx4kz100Controller.cs Migrates transmitter interfaces.
src/​Endpoints/​Transmitters/​DmTx4k302CController.cs Updates transmitter feedback routing.
src/​Endpoints/​Transmitters/​DmTx4k202CController.cs Updates transmitter feedback routing.
src/​Endpoints/​Transmitters/​DmTx4k100Controller.cs Migrates transmitter interfaces.
src/​Endpoints/​Transmitters/​DmTx401CController.cs Updates transmitter feedback routing.
src/​Endpoints/​Transmitters/​DmTx201SController.cs Updates transmitter feedback routing.
src/​Endpoints/​Transmitters/​DmTx201CController.cs Updates transmitter feedback routing.
src/​Endpoints/​Transmitters/​DmTx200Controller.cs Updates transmitter feedback routing.
src/​Endpoints/​Receivers/​DmRmcX100CController.cs Migrates receiver interfaces.
src/​Endpoints/​Receivers/​DmRmcScalerSController.cs Migrates receiver interfaces.
src/​Endpoints/​Receivers/​DmRmcScalerS2Controller.cs Migrates receiver interfaces.
src/​Endpoints/​Receivers/​DmRmcScalerCController.cs Migrates receiver interfaces.
src/​Endpoints/​Receivers/​DmRmcHelper.cs Uses v3 routing abstractions.
src/​Endpoints/​Receivers/​DmRmc4kZScalerCController.cs Adds receiver route tracking.
src/​Endpoints/​Receivers/​DmRmc4kScalerCDspController.cs Migrates receiver interfaces.
src/​Endpoints/​Receivers/​DmRmc4KScalerCController.cs Migrates receiver interfaces.
src/​Endpoints/​Receivers/​DmRmc4k100C1GController.cs Migrates receiver interfaces.
src/​Endpoints/​Receivers/​DmRmc200SController.cs Migrates receiver interfaces.
src/​Endpoints/​Receivers/​DmRmc200S2Controller.cs Migrates receiver interfaces.
src/​Endpoints/​Receivers/​DmRmc200CController.cs Migrates receiver interfaces.
src/​Endpoints/​Receivers/​DmRmc150SController.cs Migrates receiver interfaces.
src/​Endpoints/​Receivers/​DmRmc100SController.cs Migrates receiver interfaces.
src/​Endpoints/​Receivers/​DmHdBaseTEndpointController.cs Migrates receiver interfaces.
src/​Endpoints/​DGEs/​DmDge200CController.cs Migrates DGE routing.
src/​DmLite/​HdMdxxxCEController.cs Adds named-slot routing support.
src/​Config/​hdmd4x14kze.schema.json Adds device configuration schema.
src/​Chassis/​HdPsXxxController.cs Backfills HD-PS port names and adds routing support.
src/​Chassis/​HdMdNxM4KzEController.cs Adds named slots and route feedback.
src/​Chassis/​HdMdNxM4kEController.cs Migrates the controller interface.
src/​Chassis/​HdMdNxM4kEBridgeableController.cs Adds named slots and route feedback.
src/​Chassis/​HdMd8xNController.cs Adds named slots and route feedback.
src/​Chassis/​DmpsRoutingController.cs Adds named slots and midpoint routing.
src/​Chassis/​DmpsInternalVirtualDmTxController.cs Adds midpoint routing compatibility.
src/​Chassis/​DmpsDigitalOutputController.cs Adds midpoint routing compatibility.
src/​Chassis/​DmpsAudioOutputController.cs Adds unique audio-control keys.
src/​Chassis/​DmChassisController.cs Migrates chassis slots and routing.
src/​Chassis/​DmCardAudioOutput.cs Supports unique audio-control identity.
src/​Chassis/​DmBladeChassisController.cs Adds named slots and midpoint routing.
src/​AirMedia/​AirMediaController.cs Adds midpoint and wireless-sharing interfaces.
.github/​copilot-instructions.md Documents commit conventions.

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

/// Currently active routes, per IRoutingMidpointWithFeedback. Route state is surfaced via
/// AudioSourceNumericFeedback; this list is kept empty to satisfy the interface contract.
/// </summary>
public List<RouteSwitchDescriptor> CurrentRoutes { get; } = new List<RouteSwitchDescriptor>();
Comment on lines +299 to +307
/// Currently active routes, per IRoutingMidpointWithFeedback. This virtual input controller
/// selects an internal source; route state is carried by Video/AudioSourceNumericFeedback, so
/// this list is kept empty to satisfy the interface contract.
/// </summary>
public List<RouteSwitchDescriptor> CurrentRoutes { get; } = new List<RouteSwitchDescriptor>();

/// <summary>
/// Raised when a route changes, per IRoutingMidpointWithFeedback. Route feedback is carried by
/// the numeric source feedbacks; implemented as a no-op event to stay warning-clean.
{
var newEvent = NumericSwitchChange;
if (newEvent != null) newEvent(this, e);
UpdateCurrentRoute(e);
if (e == null || e.OutputPort == null)
return;

CurrentRoutes.RemoveAll(r => ReferenceEquals(r.OutputPort, e.OutputPort));
/// Currently active routes, per IRoutingMidpointWithFeedback. Route state for this kit is
/// surfaced via VideoSourceFeedback; this list is kept empty to satisfy the interface contract.
/// </summary>
public List<RouteSwitchDescriptor> CurrentRoutes { get; } = new List<RouteSwitchDescriptor>();
Comment on lines +291 to +295
public virtual void ClearRoute(object outputSelector, eRoutingSignalType signalType)
{
if (_routeTracker.Clear())
OnRouteChanged(null);
}
ediablo and others added 2 commits September 30, 2026 12:36
One physical output is exposed as two routing ports, hdmiOut{n} and
dmLiteOut{n}, sharing a FeedbackMatchObject. UpdateCurrentRoute recorded
the route against only the port carried on the event, which is whichever
the resolving FirstOrDefault reached first - always the HDMI one.

A consumer that matches on port key, as an EssentialsRouteTrace does when
walking a tie line, therefore found nothing for a display wired to the DM
Lite leg and reported that output as carrying no source.

Record the route against every output port sharing the event port's
FeedbackMatchObject. RouteChanged still fires once, for the event's own
port: this is one route change on one physical output, and subscribers
recompute from CurrentRoutes rather than counting events.

Not verified against hardware - CurrentRoutes is populated solely from
DMOutputChange, which does not fire with no chassis answering at the IPID.
Reasoned from the SDK surface and the port construction in this file.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
The HD-PS622's AUX outputs had no routing port, so a room could not name
the DSP feed as an audio destination.

An AUX output is not an independently routable output. Each is a
10-channel mixer: two program channels carrying the audio of HDMI/DM Lite
outputs 1 and 2, plus eight mono mic/line channels. HdPsXxxAnalogAuxMixer
has volume, delay and per-channel mutes and no route property. An aux can
only carry what an output already carries, so the port models following
rather than switching.

- auxOut{n}, eRoutingSignalType.Audio / LineAudio, one per aux mixer.
- auxAudioFollowsOutput config maps aux number to output number,
  defaulting aux N to output N and clamped to the chassis' real outputs.
- Route feedback is mirrored from the followed output so a trace to an
  audio destination resolves. It calls UpdateCurrentRoute directly rather
  than OnSwitchChange, to stay out of NumericSwitchChange, whose output
  numbering an aux number would collide with.
- ExecuteSwitch against an aux port delegates to the followed output. A
  no-op where the room sends one source to both a display and its audio;
  where it does not, it moves that output's video too - the only way an
  aux can carry a different source - and says so at Information.
- applyAuxSourceMix, default false, mutes the other program channels.
  Off by default because that mix is normally set in the device's own web
  UI and enabling it writes over that.

Bench-verified on a CP4N with no chassis at the IPID, across six source
buttons and source-to-source cycling: the trace builds through auxOut1,
the follow mapping applies, the switch delegates to the right output, and
in-use counts stay clean. Route feedback is unverified - it needs a real
chassis for DMOutputChange to fire.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
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.

10 participants