diff --git a/src/PepperDash.Essentials.Core/Routing/Extensions.cs b/src/PepperDash.Essentials.Core/Routing/Extensions.cs
index 1e31127d..f12f7f53 100644
--- a/src/PepperDash.Essentials.Core/Routing/Extensions.cs
+++ b/src/PepperDash.Essentials.Core/Routing/Extensions.cs
@@ -222,7 +222,7 @@ public static class Extensions
// if it's a single signal type, find the route
if (!signalType.HasFlag(eRoutingSignalType.AudioVideo))
{
- var singleTypeRouteDescriptor = new RouteDescriptor(source, destination, destinationPort, signalType);
+ var singleTypeRouteDescriptor = new RouteDescriptor(source, destination, destinationPort, sourcePort, signalType);
Debug.LogMessage(LogEventLevel.Debug, "Attempting to build source route from {sourceKey} of type {type}", destination, source.Key, signalType);
if (!destination.GetRouteToSource(source, null, null, signalType, 0, singleTypeRouteDescriptor, destinationPort, sourcePort))
@@ -240,14 +240,14 @@ public static class Extensions
Debug.LogMessage(LogEventLevel.Debug, "Attempting to build source route from {sourceKey} of type {type}", destination, source.Key);
- var audioRouteDescriptor = new RouteDescriptor(source, destination, destinationPort, eRoutingSignalType.Audio);
+ var audioRouteDescriptor = new RouteDescriptor(source, destination, destinationPort, sourcePort, eRoutingSignalType.Audio);
var audioSuccess = destination.GetRouteToSource(source, null, null, eRoutingSignalType.Audio, 0, audioRouteDescriptor, destinationPort, sourcePort);
if (!audioSuccess)
Debug.LogMessage(LogEventLevel.Debug, "Cannot find audio route to {0}", destination, source.Key);
- var videoRouteDescriptor = new RouteDescriptor(source, destination, destinationPort, eRoutingSignalType.Video);
+ var videoRouteDescriptor = new RouteDescriptor(source, destination, destinationPort, sourcePort, eRoutingSignalType.Video);
var videoSuccess = destination.GetRouteToSource(source, null, null, eRoutingSignalType.Video, 0, videoRouteDescriptor, destinationPort, sourcePort);
@@ -366,7 +366,8 @@ public static class Extensions
audioOrSingleRoute = audioCollection.Descriptors.FirstOrDefault(d =>
d.Source.Key == request.Source.Key &&
d.Destination.Key == request.Destination.Key &&
- (request.DestinationPort == null || d.InputPort?.Key == request.DestinationPort.Key));
+ (request.DestinationPort == null || d.InputPort?.Key == request.DestinationPort.Key) &&
+ (request.SourcePort == null || d.OutputPort?.Key == request.SourcePort.Key));
}
if (RouteDescriptors.TryGetValue(eRoutingSignalType.Video, out RouteDescriptorCollection videoCollection))
@@ -374,7 +375,8 @@ public static class Extensions
videoRoute = videoCollection.Descriptors.FirstOrDefault(d =>
d.Source.Key == request.Source.Key &&
d.Destination.Key == request.Destination.Key &&
- (request.DestinationPort == null || d.InputPort?.Key == request.DestinationPort.Key));
+ (request.DestinationPort == null || d.InputPort?.Key == request.DestinationPort.Key) &&
+ (request.SourcePort == null || d.OutputPort?.Key == request.SourcePort.Key));
}
}
else
@@ -385,7 +387,8 @@ public static class Extensions
audioOrSingleRoute = collection.Descriptors.FirstOrDefault(d =>
d.Source.Key == request.Source.Key &&
d.Destination.Key == request.Destination.Key &&
- (request.DestinationPort == null || d.InputPort?.Key == request.DestinationPort.Key));
+ (request.DestinationPort == null || d.InputPort?.Key == request.DestinationPort.Key) &&
+ (request.SourcePort == null || d.OutputPort?.Key == request.SourcePort.Key));
}
}
diff --git a/src/PepperDash.Essentials.Core/Routing/RouteDescriptor.cs b/src/PepperDash.Essentials.Core/Routing/RouteDescriptor.cs
index 631aff62..32822d0d 100644
--- a/src/PepperDash.Essentials.Core/Routing/RouteDescriptor.cs
+++ b/src/PepperDash.Essentials.Core/Routing/RouteDescriptor.cs
@@ -7,137 +7,160 @@ using PepperDash.Core;
using Serilog.Events;
-namespace PepperDash.Essentials.Core;
-
-///
-/// Represents a collection of individual route steps between a Source and a Destination device for a specific signal type.
-///
-public class RouteDescriptor
+namespace PepperDash.Essentials.Core
{
///
- /// The destination device (sink or midpoint) for the route.
+ /// Represents a collection of individual route steps between a Source and a Destination device for a specific signal type.
///
- public IRoutingInputs Destination { get; private set; }
-
- ///
- /// The specific input port on the destination device used for this route. Can be null if not specified or applicable.
- ///
- public RoutingInputPort InputPort { get; private set; }
-
- ///
- /// The source device for the route.
- ///
- public IRoutingOutputs Source { get; private set; }
-
- ///
- /// The type of signal being routed (e.g., Audio, Video). This descriptor represents a single signal type.
- ///
- public eRoutingSignalType SignalType { get; private set; }
-
- ///
- /// A list of individual switching steps required to establish the route.
- ///
- public List Routes { get; private set; }
-
- ///
- /// Initializes a new instance of the class for a route without a specific destination input port.
- ///
- /// The source device.
- /// The destination device.
- /// The type of signal being routed.
- public RouteDescriptor(IRoutingOutputs source, IRoutingInputs destination, eRoutingSignalType signalType) : this(source, destination, null, signalType)
+ public class RouteDescriptor
{
- }
+ ///
+ /// The destination device (sink or midpoint) for the route.
+ ///
+ public IRoutingInputs Destination { get; private set; }
- ///
- /// Initializes a new instance of the class for a route with a specific destination input port.
- ///
- /// The source device.
- /// The destination device.
- /// The destination input port (optional).
- /// The signal type for this route.
- public RouteDescriptor(IRoutingOutputs source, IRoutingInputs destination, RoutingInputPort inputPort, eRoutingSignalType signalType)
- {
- Destination = destination;
- InputPort = inputPort;
- Source = source;
- SignalType = signalType;
- Routes = new List();
- }
+ ///
+ /// The InputPort on the destination device for this route, if applicable. May be null if the route is not for a specific input port.
+ ///
+ public RoutingInputPort InputPort { get; private set; }
- ///
- /// Executes all the switching steps defined in the list.
- ///
- public void ExecuteRoutes()
- {
- foreach (var route in Routes)
+ ///
+ /// Gets the source device (sink or midpoint) for the route.
+ ///
+ public IRoutingOutputs Source { get; private set; }
+
+ ///
+ /// Gets the OutputPort on the source device for this route, if applicable. May be null if the route is not for a specific output port.
+ ///
+ public RoutingOutputPort OutputPort { get; private set; }
+
+ ///
+ /// Gets the signal type for this route.
+ ///
+ public eRoutingSignalType SignalType { get; private set; }
+
+ ///
+ /// Gets the collection of route switch descriptors for this route.
+ ///
+ public List Routes { get; private set; }
+
+ ///
+ /// Initializes a new instance of the class for a route without a specific destination input port.
+ ///
+ /// The source device.
+ /// The destination device.
+ /// The type of signal being routed.
+ public RouteDescriptor(IRoutingOutputs source, IRoutingInputs destination, eRoutingSignalType signalType) : this(source, destination, null, signalType)
{
- Debug.LogMessage(LogEventLevel.Verbose, "ExecuteRoutes: {0}", null, route.ToString());
-
- if (route.SwitchingDevice is IRoutingSinkWithFeedback sink)
- {
- sink.ExecuteSwitch(route.InputPort.Selector);
- continue;
- }
-
- if (route.SwitchingDevice is IRoutingMidpointWithFeedback switchingDevice)
- {
- switchingDevice.ExecuteSwitch(route.InputPort.Selector, route.OutputPort.Selector, SignalType);
-
- route.OutputPort.InUseTracker.AddUser(Destination, "destination-" + SignalType);
-
- Debug.LogMessage(LogEventLevel.Verbose, "Output port {0} routing. Count={1}", null, route.OutputPort.Key, route.OutputPort.InUseTracker.InUseCountFeedback.UShortValue);
- }
}
- }
- ///
- /// Releases the usage tracking for the route and optionally clears the route on the switching devices.
- ///
- /// If true, attempts to clear the route on the switching devices (e.g., set input to null/0).
- public void ReleaseRoutes(bool clearRoute = false)
- {
- foreach (var route in Routes.Where(r => r.SwitchingDevice is IRoutingMidpointWithFeedback))
+ ///
+ /// Initializes a new instance of the class for a route with a specific destination input port.
+ ///
+ /// The source device.
+ /// The destination device.
+ /// The destination input port (optional).
+ /// The signal type for this route.
+ public RouteDescriptor(IRoutingOutputs source, IRoutingInputs destination, RoutingInputPort inputPort, eRoutingSignalType signalType) : this(source, destination, inputPort, null, signalType)
{
- if (route.SwitchingDevice is IRoutingMidpointWithFeedback switchingDevice)
- {
- if (clearRoute)
- {
- try
- {
- switchingDevice.ExecuteSwitch(null, route.OutputPort.Selector, SignalType);
- }
- catch (Exception e)
- {
- Debug.LogError("Error executing switch: {exception}", e.Message);
- }
- }
+ }
- if (route.OutputPort == null)
+ ///
+ /// Initializes a new instance of the class for a route with specific destination input and source output ports.
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ public RouteDescriptor(IRoutingOutputs source, IRoutingInputs destination, RoutingInputPort inputPort, RoutingOutputPort outputPort, eRoutingSignalType signalType)
+ {
+ Destination = destination;
+ InputPort = inputPort;
+ Source = source;
+ OutputPort = outputPort;
+ SignalType = signalType;
+ Routes = new List();
+ }
+
+ ///
+ /// ExecuteRoutes method
+ ///
+ public void ExecuteRoutes()
+ {
+ foreach (var route in Routes)
+ {
+ Debug.LogVerbose("ExecuteRoutes: {0}", route.ToString());
+
+ if (route.SwitchingDevice is IRoutingSinkWithFeedback sink)
{
+ sink.ExecuteSwitch(route.InputPort.Selector);
continue;
}
- if (route.OutputPort.InUseTracker != null)
+ if (route.SwitchingDevice is IRoutingMidpointWithFeedback switchingDevice)
{
- route.OutputPort.InUseTracker.RemoveUser(Destination, "destination-" + SignalType);
- Debug.LogMessage(LogEventLevel.Verbose, "Port {0} releasing. Count={1}", null, route.OutputPort.Key, route.OutputPort.InUseTracker.InUseCountFeedback.UShortValue);
- }
- else
- {
- Debug.LogMessage(LogEventLevel.Error, "InUseTracker is null for OutputPort {0}", null, route.OutputPort.Key);
+ switchingDevice.ExecuteSwitch(route.InputPort.Selector, route.OutputPort.Selector, SignalType);
+
+ route.OutputPort.InUseTracker.AddUser(Destination, "destination-" + SignalType);
+
+ Debug.LogVerbose("Output port {0} routing. Count={1}", route.OutputPort.Key, route.OutputPort.InUseTracker.InUseCountFeedback.UShortValue);
}
}
}
+
+ ///
+ /// Releases the usage tracking for the route and optionally clears the route on the switching devices.
+ ///
+ /// If true, attempts to clear the route on the switching devices (e.g., set input to null/0).
+
+
+ public void ReleaseRoutes(bool clearRoute = false)
+ {
+ foreach (var route in Routes.Where(r => r.SwitchingDevice is IRoutingMidpointWithFeedback))
+ {
+ if (route.SwitchingDevice is IRoutingMidpointWithFeedback switchingDevice)
+ {
+ if (clearRoute)
+ {
+ try
+ {
+ switchingDevice.ExecuteSwitch(null, route.OutputPort.Selector, SignalType);
+ }
+ catch (Exception e)
+ {
+ Debug.LogError("Error executing switch: {exception}", e.Message);
+ Debug.LogDebug(e, "Stack Trace: ");
+ }
+ }
+
+ if (route.OutputPort == null)
+ {
+ continue;
+ }
+
+ if (route.OutputPort.InUseTracker != null)
+ {
+ route.OutputPort.InUseTracker.RemoveUser(Destination, "destination-" + SignalType);
+ Debug.LogVerbose("Port {0} releasing. Count={1}", route.OutputPort.Key, route.OutputPort.InUseTracker.InUseCountFeedback.UShortValue);
+ }
+ else
+ {
+ Debug.LogVerbose("InUseTracker is null for OutputPort {0}", route.OutputPort.Key);
+ }
+ }
+ }
+ }
+
+ ///
+ /// Returns a string representation of the route descriptor, including source, destination, and individual route steps.
+ ///
+ /// A string describing the route.
+ public override string ToString()
+ {
+ var routesText = Routes.Select(r => r.ToString()).ToArray();
+ return $"Route table from {Source.Key} to {Destination.Key} for {SignalType}:\r\n {string.Join("\r\n ", routesText)}";
+ }
}
- ///
- /// Returns a string representation of the route descriptor, including source, destination, and individual route steps.
- ///
- /// A string describing the route.
- public override string ToString()
- {
- var routesText = Routes.Select(r => r.ToString()).ToArray();
- return $"Route table from {Source.Key} to {Destination.Key} for {SignalType}:\r\n {string.Join("\r\n ", routesText)}";
- }
}
\ No newline at end of file
diff --git a/src/PepperDash.Essentials.Core/Routing/RouteDescriptorCollection.cs b/src/PepperDash.Essentials.Core/Routing/RouteDescriptorCollection.cs
index f75196a2..d17ca8fe 100644
--- a/src/PepperDash.Essentials.Core/Routing/RouteDescriptorCollection.cs
+++ b/src/PepperDash.Essentials.Core/Routing/RouteDescriptorCollection.cs
@@ -28,6 +28,9 @@ public class RouteDescriptorCollection
private readonly List RouteDescriptors = new List();
+ ///
+ /// Event raised when the collection of RouteDescriptors changes (add/remove). This is useful for updating routing status in the UI, for example.
+ ///
public event EventHandler RouteDescriptorCollectionChanged;
///
diff --git a/src/PepperDash.Essentials.Core/Routing/RouteSwitchDescriptor.cs b/src/PepperDash.Essentials.Core/Routing/RouteSwitchDescriptor.cs
index 38d56b93..2e526589 100644
--- a/src/PepperDash.Essentials.Core/Routing/RouteSwitchDescriptor.cs
+++ b/src/PepperDash.Essentials.Core/Routing/RouteSwitchDescriptor.cs
@@ -2,6 +2,7 @@
{
///
/// Represents a RouteSwitchDescriptor
+ /// This represents a switch to be made on an IRoutingInputs device, which could be a matrix switcher or a sink device.
///
public class RouteSwitchDescriptor
{
diff --git a/src/PepperDash.Essentials.Core/Routing/RoutingFeedbackManager.cs b/src/PepperDash.Essentials.Core/Routing/RoutingFeedbackManager.cs
index 15855cf4..0eb741bb 100644
--- a/src/PepperDash.Essentials.Core/Routing/RoutingFeedbackManager.cs
+++ b/src/PepperDash.Essentials.Core/Routing/RoutingFeedbackManager.cs
@@ -225,6 +225,7 @@ namespace PepperDash.Essentials.Core.Routing
try
{
UpdateDestination(sender, currentInputPort);
+
}
catch (Exception ex)
{
@@ -340,11 +341,6 @@ namespace PepperDash.Essentials.Core.Routing
inputPort
);
- var tempSourceListItem = new SourceListItem
- {
- SourceKey = "$transient",
- Name = inputPort.Key,
- };
return;
}
@@ -371,12 +367,16 @@ namespace PepperDash.Essentials.Core.Routing
inputPort
);
- var tempSourceListItem = new SourceListItem
- {
- SourceKey = "$transient",
- Name = "None",
- };
+ // determine all the tie lines between the source and destination to determine the signal type
+ // the type is the union of all the tie lines between the source and destination
+
+ // For now we assume the type matches the tie line connected to the destination
+ destination.SetCurrentSource(firstTieLine.Type, null);
+
+ // remove existing descriptor if any
+ RouteDescriptorCollection.DefaultCollection.RemoveRouteDescriptor(destination, inputPort.Key);
+
return;
}
}
@@ -386,83 +386,24 @@ namespace PepperDash.Essentials.Core.Routing
return;
}
- // Debug.LogMessage(Serilog.Events.LogEventLevel.Verbose, "Found root TieLine {tieLine}", this, sourceTieLine);
- // Does not handle combinable scenarios or other scenarios where a display might be part of multiple rooms yet.
- var room = DeviceManager
- .AllDevices.OfType()
- .FirstOrDefault(
- (r) =>
- {
+ // Get the routes from the destination to the source using the existing GetRouteToSource method
+ var routes = destination.GetRouteToSource(
+ sourceTieLine.SourcePort.ParentDevice as IRoutingOutputs,
+ sourceTieLine.Type,
+ inputPort,
+ sourceTieLine.SourcePort
+ );
- if (r is IHasDefaultDisplay roomDefaultDisplay)
- {
- return roomDefaultDisplay.DefaultDisplay.Key == destination.Key;
- }
+ // remove existing descriptor if any
+ RouteDescriptorCollection.DefaultCollection.RemoveRouteDescriptor(destination, inputPort.Key);
- return false;
- }
- );
+ // Add the new route descriptors to the collection
+ RouteDescriptorCollection.DefaultCollection.AddRouteDescriptor(routes.Item1);
- if (room == null)
+ if(routes.Item2 != null)
{
- Debug.LogMessage(
- Serilog.Events.LogEventLevel.Debug,
- "No room found for display {destination}",
- this,
- destination.Key
- );
- return;
- }
-
- // Debug.LogMessage(Serilog.Events.LogEventLevel.Verbose, "Found room {room} for destination {destination}", this, room.Key, destination.Key);
-
- var sourceList = ConfigReader.ConfigObject.GetSourceListForKey(room.SourceListKey);
-
- if (sourceList == null)
- {
- Debug.LogMessage(
- Serilog.Events.LogEventLevel.Debug,
- "No source list found for source list key {key}. Unable to find source for tieLine {sourceTieLine}",
- this,
- room.SourceListKey,
- sourceTieLine
- );
- return;
- }
-
- // Debug.LogMessage(Serilog.Events.LogEventLevel.Verbose, "Found sourceList for room {room}", this, room.Key);
-
- var sourceListItem = sourceList.FirstOrDefault(sli =>
- {
- //// Debug.LogMessage(Serilog.Events.LogEventLevel.Verbose,
- // "SourceListItem {sourceListItem}:{sourceKey} tieLine sourceport device key {sourcePortDeviceKey}",
- // this,
- // sli.Key,
- // sli.Value.SourceKey,
- // sourceTieLine.SourcePort.ParentDevice.Key);
-
- return sli.Value.SourceKey.Equals(
- sourceTieLine.SourcePort.ParentDevice.Key,
- StringComparison.InvariantCultureIgnoreCase
- );
- });
-
- var source = sourceListItem.Value;
- var sourceKey = sourceListItem.Key;
-
- if (source == null)
- {
- Debug.LogMessage(
- Serilog.Events.LogEventLevel.Debug,
- "No source found for device {key}. Creating transient source for {destination}",
- this,
- sourceTieLine.SourcePort.ParentDevice.Key,
- destination
- );
-
-
- return;
+ RouteDescriptorCollection.DefaultCollection.AddRouteDescriptor(routes.Item2);
}
}