mirror of
https://github.com/PepperDash/Essentials.git
synced 2026-08-31 19:08:29 +00:00
refactor: routing interfaces and implementations to support current sources
- Updated ICurrentSources interface to use IRoutingSource instead of SourceListItem. - Introduced CurrentSourcesChangedEventArgs for detailed event notifications. - Modified IRoutingOutputs and IRoutingSource interfaces to include JSON properties for serialization. - Enhanced IRoutingSink and related interfaces to implement ICurrentSources for better source management. - Refactored RoutingFeedbackManager to utilize new current source handling. - Updated GenericAudioOut, GenericSink, and BlueJeansPc classes to implement new current source logic. - Adjusted MobileControl messengers to accommodate changes in current source handling. - Removed deprecated destination handling in MobileControlEssentialsRoomBridge.
This commit is contained in:
parent
43a9661e08
commit
b4d53dbe0e
19 changed files with 439 additions and 350 deletions
|
|
@ -6,6 +6,7 @@ namespace PepperDash.Essentials.Core.Routing
|
|||
/// <summary>
|
||||
/// The current sources for the room, keyed by eRoutingSignalType.
|
||||
/// This allows for multiple sources to be tracked, such as audio and video.
|
||||
/// Intended to be implemented on a DestinationListItem to provide access to the current sources for the room in its context.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// This interface is used to provide access to the current sources in a room,
|
||||
|
|
@ -17,7 +18,7 @@ namespace PepperDash.Essentials.Core.Routing
|
|||
/// Gets the current sources for the room, keyed by eRoutingSignalType.
|
||||
/// This dictionary contains the current source for each signal type, such as audio, video, and control signals.
|
||||
/// </summary>
|
||||
Dictionary<eRoutingSignalType, SourceListItem> CurrentSources { get; }
|
||||
Dictionary<eRoutingSignalType, IRoutingSource> CurrentSources { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the current source keys for the room, keyed by eRoutingSignalType.
|
||||
|
|
@ -28,16 +29,51 @@ namespace PepperDash.Essentials.Core.Routing
|
|||
/// <summary>
|
||||
/// Event raised when the current sources change.
|
||||
/// </summary>
|
||||
event EventHandler CurrentSourcesChanged;
|
||||
event EventHandler<CurrentSourcesChangedEventArgs> CurrentSourcesChanged;
|
||||
|
||||
/// <summary>
|
||||
/// Sets the current source for a specific signal type.
|
||||
/// This method updates the current source for the specified signal type and notifies any subscribers of the change.
|
||||
/// </summary>
|
||||
/// <param name="signalType">The signal type to update.</param>
|
||||
/// <param name="sourceListKey">The key for the source list.</param>
|
||||
/// <param name="sourceListItem">The source list item to set as the current source.</param>
|
||||
void SetCurrentSource(eRoutingSignalType signalType, string sourceListKey, SourceListItem sourceListItem);
|
||||
/// <param name="sourceDevice">The source device to set as the current source.</param>
|
||||
void SetCurrentSource(eRoutingSignalType signalType, IRoutingSource sourceDevice);
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Event arguments for the CurrentSourcesChanged event, providing details about the signal type and the previous and new sources.
|
||||
/// </summary>
|
||||
public class CurrentSourcesChangedEventArgs : EventArgs
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets the signal type for which the current source has changed.
|
||||
/// </summary>
|
||||
public eRoutingSignalType SignalType { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the previous source for the signal type before the change occurred.
|
||||
/// </summary>
|
||||
public IRoutingSource PreviousSource { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the new source for the signal type after the change occurred.
|
||||
/// </summary>
|
||||
public IRoutingSource NewSource { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the CurrentSourcesChangedEventArgs class with the specified signal type, previous source, and new source.
|
||||
/// </summary>
|
||||
/// <param name="signalType">The signal type for which the current source has changed.</param>
|
||||
/// <param name="previousSource">The previous source for the signal type before the change occurred.</param>
|
||||
/// <param name="newSource">The new source for the signal type after the change occurred.</param>
|
||||
public CurrentSourcesChangedEventArgs(eRoutingSignalType signalType, IRoutingSource previousSource, IRoutingSource newSource)
|
||||
{
|
||||
SignalType = signalType;
|
||||
PreviousSource = previousSource;
|
||||
NewSource = newSource;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,4 +1,5 @@
|
|||
using PepperDash.Core;
|
||||
using Newtonsoft.Json;
|
||||
using PepperDash.Core;
|
||||
|
||||
|
||||
namespace PepperDash.Essentials.Core;
|
||||
|
|
@ -11,6 +12,7 @@ public interface IRoutingOutputs : IKeyed
|
|||
/// <summary>
|
||||
/// Collection of Output Ports
|
||||
/// </summary>
|
||||
[JsonProperty("outputPorts")]
|
||||
RoutingPortCollection<RoutingOutputPort> OutputPorts { get; }
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
using PepperDash.Core;
|
||||
using PepperDash.Essentials.Core.Routing;
|
||||
|
||||
namespace PepperDash.Essentials.Core;
|
||||
|
|
@ -5,7 +6,7 @@ namespace PepperDash.Essentials.Core;
|
|||
/// <summary>
|
||||
/// Defines the contract for IRoutingSink
|
||||
/// </summary>
|
||||
public interface IRoutingSink : IRoutingInputs, IHasCurrentSourceInfoChange
|
||||
public interface IRoutingSink : IRoutingInputs, IKeyName, ICurrentSources
|
||||
{
|
||||
}
|
||||
|
||||
|
|
@ -20,10 +21,4 @@ public interface IRoutingSinkWithInputPort : IRoutingSink
|
|||
RoutingInputPort CurrentInputPort { get; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Interface for routing sinks that have access to the current source information.
|
||||
/// </summary>
|
||||
public interface IRoutingSinkWithCurrentSources : IRoutingSink, ICurrentSources
|
||||
{
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -5,8 +5,9 @@
|
|||
/// <summary>
|
||||
/// Defines the contract for IRoutingSinkWithFeedback
|
||||
/// </summary>
|
||||
public interface IRoutingSinkWithFeedback : IRoutingSinkWithSwitching
|
||||
public interface IRoutingSinkWithFeedback : IRoutingSink
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -1,8 +1,10 @@
|
|||
namespace PepperDash.Essentials.Core;
|
||||
using PepperDash.Core;
|
||||
|
||||
namespace PepperDash.Essentials.Core;
|
||||
|
||||
/// <summary>
|
||||
/// Marker interface to identify a device that acts as the origin of a signal path (<see cref="IRoutingOutputs"/>).
|
||||
/// </summary>
|
||||
public interface IRoutingSource : IRoutingOutputs
|
||||
public interface IRoutingSource : IRoutingOutputs, IKeyName
|
||||
{
|
||||
}
|
||||
|
|
@ -9,15 +9,15 @@ namespace PepperDash.Essentials.Core.Routing;
|
|||
/// Manages routing feedback by subscribing to route changes on midpoint and sink devices,
|
||||
/// tracing the route back to the original source, and updating the CurrentSourceInfo on sink devices.
|
||||
/// </summary>
|
||||
public class RoutingFeedbackManager: EssentialsDevice
|
||||
public class RoutingFeedbackManager : EssentialsDevice
|
||||
{
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="RoutingFeedbackManager"/> class.
|
||||
/// </summary>
|
||||
/// <param name="key">The unique key for this manager device.</param>
|
||||
/// <param name="name">The name of this manager device.</param>
|
||||
public RoutingFeedbackManager(string key, string name): base(key, name)
|
||||
{
|
||||
public RoutingFeedbackManager(string key, string name) : base(key, name)
|
||||
{
|
||||
AddPreActivationAction(SubscribeForMidpointFeedback);
|
||||
AddPreActivationAction(SubscribeForSinkFeedback);
|
||||
}
|
||||
|
|
@ -41,12 +41,12 @@ public class RoutingFeedbackManager: EssentialsDevice
|
|||
/// </summary>
|
||||
private void SubscribeForSinkFeedback()
|
||||
{
|
||||
var sinkDevices = DeviceManager.AllDevices.OfType<IRoutingSinkWithSwitchingWithInputPort>();
|
||||
var sinkDevices = DeviceManager.AllDevices.OfType<IRoutingSinkWithSwitchingWithInputPort>();
|
||||
|
||||
foreach (var device in sinkDevices)
|
||||
{
|
||||
device.InputChanged += HandleSinkUpdate;
|
||||
}
|
||||
foreach (var device in sinkDevices)
|
||||
{
|
||||
device.InputChanged += HandleSinkUpdate;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
|
@ -59,7 +59,7 @@ public class RoutingFeedbackManager: EssentialsDevice
|
|||
{
|
||||
try
|
||||
{
|
||||
var devices = DeviceManager.AllDevices.OfType<IRoutingSinkWithSwitchingWithInputPort>();
|
||||
var devices = DeviceManager.AllDevices.OfType<IRoutingSinkWithInputPort>();
|
||||
|
||||
foreach (var device in devices)
|
||||
{
|
||||
|
|
@ -96,13 +96,13 @@ public class RoutingFeedbackManager: EssentialsDevice
|
|||
/// </summary>
|
||||
/// <param name="destination">The destination sink device to update.</param>
|
||||
/// <param name="inputPort">The currently selected input port on the destination device.</param>
|
||||
private void UpdateDestination(IRoutingSinkWithSwitching destination, RoutingInputPort inputPort)
|
||||
{
|
||||
private void UpdateDestination(IRoutingSink destination, RoutingInputPort inputPort)
|
||||
{
|
||||
// Debug.LogMessage(Serilog.Events.LogEventLevel.Verbose, "Updating destination {destination} with inputPort {inputPort}", this,destination?.Key, inputPort?.Key);
|
||||
|
||||
if(inputPort == null)
|
||||
if (inputPort == null)
|
||||
{
|
||||
Debug.LogMessage(Serilog.Events.LogEventLevel.Warning, "Destination {destination} has not reported an input port yet", this,destination.Key);
|
||||
Debug.LogMessage(Serilog.Events.LogEventLevel.Warning, "Destination {destination} has not reported an input port yet", this, destination.Key);
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -116,19 +116,10 @@ public class RoutingFeedbackManager: EssentialsDevice
|
|||
if (firstTieLine == null)
|
||||
{
|
||||
Debug.LogMessage(Serilog.Events.LogEventLevel.Information, "No tieline found for inputPort {inputPort}. Clearing current source", this, inputPort);
|
||||
|
||||
var tempSourceListItem = new SourceListItem
|
||||
{
|
||||
SourceKey = "$transient",
|
||||
Name = inputPort.Key,
|
||||
};
|
||||
|
||||
|
||||
destination.CurrentSourceInfo = tempSourceListItem; ;
|
||||
destination.CurrentSourceInfoKey = "$transient";
|
||||
return;
|
||||
}
|
||||
} catch (Exception ex)
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Debug.LogMessage(ex, "Error getting first tieline: {Exception}", this, ex);
|
||||
return;
|
||||
|
|
@ -136,6 +127,7 @@ public class RoutingFeedbackManager: EssentialsDevice
|
|||
|
||||
// Debug.LogMessage(Serilog.Events.LogEventLevel.Verbose, "Getting source for first TieLine {tieLine}", this, firstTieLine);
|
||||
|
||||
|
||||
TieLine sourceTieLine;
|
||||
try
|
||||
{
|
||||
|
|
@ -145,91 +137,34 @@ public class RoutingFeedbackManager: EssentialsDevice
|
|||
{
|
||||
Debug.LogMessage(Serilog.Events.LogEventLevel.Information, "No route found to source for inputPort {inputPort}. Clearing current source", this, inputPort);
|
||||
|
||||
var tempSourceListItem = new SourceListItem
|
||||
{
|
||||
SourceKey = "$transient",
|
||||
Name = "None",
|
||||
};
|
||||
|
||||
destination.CurrentSourceInfo = tempSourceListItem;
|
||||
destination.CurrentSourceInfoKey = string.Empty;
|
||||
destination.SetCurrentSource(sourceTieLine.Type, null);
|
||||
|
||||
|
||||
return;
|
||||
}
|
||||
} catch(Exception ex)
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Debug.LogMessage(ex, "Error getting sourceTieLine: {Exception}", this, ex);
|
||||
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<IEssentialsRoom>().FirstOrDefault((r) => {
|
||||
if(r is IHasMultipleDisplays roomMultipleDisplays)
|
||||
{
|
||||
return roomMultipleDisplays.Displays.Any(d => d.Value.Key == destination.Key);
|
||||
}
|
||||
|
||||
if(r is IHasDefaultDisplay roomDefaultDisplay)
|
||||
{
|
||||
return roomDefaultDisplay.DefaultDisplay.Key == destination.Key;
|
||||
}
|
||||
|
||||
return false;
|
||||
});
|
||||
|
||||
if(room == null)
|
||||
{
|
||||
Debug.LogMessage(Serilog.Events.LogEventLevel.Warning, "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.Warning, "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)
|
||||
if (sourceTieLine.SourcePort.ParentDevice == null)
|
||||
{
|
||||
Debug.LogMessage(Serilog.Events.LogEventLevel.Information, "No source found for device {key}. Creating transient source for {destination}", this, sourceTieLine.SourcePort.ParentDevice.Key, destination);
|
||||
|
||||
var tempSourceListItem = new SourceListItem
|
||||
{
|
||||
SourceKey = "$transient",
|
||||
Name = sourceTieLine.SourcePort.Key,
|
||||
};
|
||||
destination.SetCurrentSource(sourceTieLine.Type, null);
|
||||
|
||||
destination.CurrentSourceInfoKey = "$transient";
|
||||
destination.CurrentSourceInfo = tempSourceListItem;
|
||||
return;
|
||||
}
|
||||
|
||||
//Debug.LogMessage(Serilog.Events.LogEventLevel.Verbose, "Got Source {@source} with key {sourceKey}", this, source, sourceKey);
|
||||
|
||||
destination.CurrentSourceInfoKey = sourceKey;
|
||||
destination.CurrentSourceInfo = source;
|
||||
|
||||
if (sourceTieLine.SourcePort.ParentDevice is IRoutingSource sourceDevice)
|
||||
{
|
||||
destination.SetCurrentSource(sourceTieLine.Type, sourceDevice);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
|
@ -249,13 +184,14 @@ public class RoutingFeedbackManager: EssentialsDevice
|
|||
{
|
||||
// Debug.LogMessage(Serilog.Events.LogEventLevel.Verbose, "TieLine Source device {sourceDevice} is midpoint", this, midpoint);
|
||||
|
||||
if(midpoint.CurrentRoutes == null || midpoint.CurrentRoutes.Count == 0)
|
||||
if (midpoint.CurrentRoutes == null || midpoint.CurrentRoutes.Count == 0)
|
||||
{
|
||||
Debug.LogMessage(Serilog.Events.LogEventLevel.Information, "Midpoint {midpointKey} has no routes",this, midpoint.Key);
|
||||
Debug.LogMessage(Serilog.Events.LogEventLevel.Information, "Midpoint {midpointKey} has no routes", this, midpoint.Key);
|
||||
return null;
|
||||
}
|
||||
|
||||
var currentRoute = midpoint.CurrentRoutes.FirstOrDefault(route => {
|
||||
var currentRoute = midpoint.CurrentRoutes.FirstOrDefault(route =>
|
||||
{
|
||||
//Debug.LogMessage(Serilog.Events.LogEventLevel.Verbose, "Checking {route} against {tieLine}", this, route, tieLine);
|
||||
|
||||
return route.OutputPort != null && route.InputPort != null && route.OutputPort?.Key == tieLine.SourcePort.Key && route.OutputPort?.ParentDevice.Key == tieLine.SourcePort.ParentDevice.Key;
|
||||
|
|
@ -269,9 +205,11 @@ public class RoutingFeedbackManager: EssentialsDevice
|
|||
|
||||
//Debug.LogMessage(Serilog.Events.LogEventLevel.Verbose, "Found currentRoute {currentRoute} through {midpoint}", this, currentRoute, midpoint);
|
||||
|
||||
nextTieLine = TieLineCollection.Default.FirstOrDefault(tl => {
|
||||
nextTieLine = TieLineCollection.Default.FirstOrDefault(tl =>
|
||||
{
|
||||
//Debug.LogMessage(Serilog.Events.LogEventLevel.Verbose, "Checking {route} against {tieLine}", tl.DestinationPort.Key, currentRoute.InputPort.Key);
|
||||
return tl.DestinationPort.Key == currentRoute.InputPort.Key && tl.DestinationPort.ParentDevice.Key == currentRoute.InputPort.ParentDevice.Key; });
|
||||
return tl.DestinationPort.Key == currentRoute.InputPort.Key && tl.DestinationPort.ParentDevice.Key == currentRoute.InputPort.ParentDevice.Key;
|
||||
});
|
||||
|
||||
if (nextTieLine != null)
|
||||
{
|
||||
|
|
@ -292,13 +230,14 @@ public class RoutingFeedbackManager: EssentialsDevice
|
|||
return tieLine;
|
||||
}
|
||||
|
||||
nextTieLine = TieLineCollection.Default.FirstOrDefault(tl => tl.DestinationPort.Key == tieLine.SourcePort.Key && tl.DestinationPort.ParentDevice.Key == tieLine.SourcePort.ParentDevice.Key );
|
||||
nextTieLine = TieLineCollection.Default.FirstOrDefault(tl => tl.DestinationPort.Key == tieLine.SourcePort.Key && tl.DestinationPort.ParentDevice.Key == tieLine.SourcePort.ParentDevice.Key);
|
||||
|
||||
if (nextTieLine != null)
|
||||
{
|
||||
return GetRootTieLine(nextTieLine);
|
||||
}
|
||||
} catch (Exception ex)
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Debug.LogMessage(ex, "Error walking tieLines: {Exception}", this, ex);
|
||||
return null;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue