mirror of
https://github.com/PepperDash/Essentials.git
synced 2026-08-31 19:08:29 +00:00
feat: Refactor routing interfaces and feedback mechanisms
- Removed ITxRouting and ITxRoutingWithFeedback interfaces as they were redundant. - Updated RouteDescriptor and RouteSwitchDescriptor to use new feedback interfaces. - Modified RoutingFeedbackManager to utilize IRoutingSinkWithFeedback and IRoutingMidpointWithFeedback. - Adjusted GenericAudioOut, BlueJeansPc, and other device classes to implement new feedback interfaces. - Introduced new messenger classes for IRoutingSinkWithFeedback and IRoutingMidpointWithFeedback. - Cleaned up unused messenger interfaces and consolidated routing logic. - Updated MobileControlEssentialsRoomBridge to remove dependency on IHasCurrentSourceInfoChange.
This commit is contained in:
parent
b9dcec587d
commit
f64b595fd7
46 changed files with 324 additions and 872 deletions
|
|
@ -155,10 +155,10 @@ namespace PepperDash.Essentials.Core;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
var inputsOutputs = dev as IRoutingInputsOutputs;
|
var inputsOutputs = dev as IRoutingMidpoint;
|
||||||
if (inputsOutputs == null)
|
if (inputsOutputs == null)
|
||||||
{
|
{
|
||||||
Debug.LogMessage(LogEventLevel.Information, "GetCecPort: Device '{0}' does not support IRoutingInputsOutputs, failed to get CEC port called '{1}'",
|
Debug.LogMessage(LogEventLevel.Information, "GetCecPort: Device '{0}' does not support IRoutingMidpoint, failed to get CEC port called '{1}'",
|
||||||
config.ControlPortDevKey, config.ControlPortName);
|
config.ControlPortDevKey, config.ControlPortName);
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,7 @@ namespace PepperDash.Essentials.Core
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Identifies a device that contains audio zones
|
/// Identifies a device that contains audio zones
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public interface IAudioZones : IRouting
|
public interface IAudioZones : IRoutingMidpointWithFeedback
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the collection of audio zones
|
/// Gets the collection of audio zones
|
||||||
|
|
|
||||||
|
|
@ -9,6 +9,6 @@ namespace PepperDash.Essentials.Core.DeviceTypeInterfaces;
|
||||||
/// It is designed to be implemented by devices that require these capabilities,
|
/// It is designed to be implemented by devices that require these capabilities,
|
||||||
/// such as projectors, displays, and other visual output devices.
|
/// such as projectors, displays, and other visual output devices.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public interface IDisplay : IHasFeedback, IRoutingSinkWithSwitching, IHasPowerControl, IWarmingCooling, IUsageTracking, IKeyName
|
public interface IDisplay : IHasFeedback, IRoutingSinkWithFeedback, IHasPowerControl, IWarmingCooling, IUsageTracking, IKeyName
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -18,16 +18,16 @@ public class DestinationListItem
|
||||||
[JsonProperty("sinkKey")]
|
[JsonProperty("sinkKey")]
|
||||||
public string SinkKey { get; set; }
|
public string SinkKey { get; set; }
|
||||||
|
|
||||||
private IRoutingSink _sinkDevice;
|
private IRoutingSinkWithFeedback _sinkDevice;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the actual device instance for this destination.
|
/// Gets the actual device instance for this destination.
|
||||||
/// Lazily loads the device from the DeviceManager using the SinkKey.
|
/// Lazily loads the device from the DeviceManager using the SinkKey.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[JsonIgnore]
|
[JsonIgnore]
|
||||||
public IRoutingSink SinkDevice
|
public IRoutingSinkWithFeedback SinkDevice
|
||||||
{
|
{
|
||||||
get { return _sinkDevice ?? (_sinkDevice = DeviceManager.GetDeviceForKey(SinkKey) as IRoutingSink); }
|
get { return _sinkDevice ?? (_sinkDevice = DeviceManager.GetDeviceForKey(SinkKey) as IRoutingSinkWithFeedback); }
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|
|
||||||
|
|
@ -25,7 +25,7 @@ public interface IHasDefaultDisplay
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The default display for the room, used for presentation routing and other default routes
|
/// The default display for the room, used for presentation routing and other default routes
|
||||||
/// </summary>
|
/// </summary>
|
||||||
IRoutingSink DefaultDisplay { get; }
|
IRoutingSinkWithFeedback DefaultDisplay { get; }
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|
|
||||||
|
|
@ -465,8 +465,8 @@ public static class Extensions
|
||||||
IndexTieLines();
|
IndexTieLines();
|
||||||
}
|
}
|
||||||
|
|
||||||
var sinks = DeviceManager.AllDevices.OfType<IRoutingInputs>().Where(d => !(d is IRoutingInputsOutputs));
|
var sinks = DeviceManager.AllDevices.OfType<IRoutingInputs>().Where(d => !(d is IRoutingMidpoint));
|
||||||
var sources = DeviceManager.AllDevices.OfType<IRoutingOutputs>().Where(d => !(d is IRoutingInputsOutputs));
|
var sources = DeviceManager.AllDevices.OfType<IRoutingOutputs>().Where(d => !(d is IRoutingMidpoint));
|
||||||
|
|
||||||
foreach (var sink in sinks)
|
foreach (var sink in sinks)
|
||||||
{
|
{
|
||||||
|
|
@ -544,7 +544,7 @@ public static class Extensions
|
||||||
/// <param name="routeTable">The RouteDescriptor being populated as the route is discovered</param>
|
/// <param name="routeTable">The RouteDescriptor being populated as the route is discovered</param>
|
||||||
/// <returns>true if source is hit</returns>
|
/// <returns>true if source is hit</returns>
|
||||||
private static bool GetRouteToSource(this IRoutingInputs destination, IRoutingOutputs source,
|
private static bool GetRouteToSource(this IRoutingInputs destination, IRoutingOutputs source,
|
||||||
RoutingOutputPort outputPortToUse, List<IRoutingInputsOutputs> alreadyCheckedDevices,
|
RoutingOutputPort outputPortToUse, List<IRoutingMidpoint> alreadyCheckedDevices,
|
||||||
eRoutingSignalType signalType, int cycle, RouteDescriptor routeTable, RoutingInputPort destinationPort, RoutingOutputPort sourcePort)
|
eRoutingSignalType signalType, int cycle, RouteDescriptor routeTable, RoutingInputPort destinationPort, RoutingOutputPort sourcePort)
|
||||||
{
|
{
|
||||||
cycle++;
|
cycle++;
|
||||||
|
|
@ -608,16 +608,16 @@ public static class Extensions
|
||||||
|
|
||||||
// No direct tie? Run back out on the inputs' attached devices...
|
// No direct tie? Run back out on the inputs' attached devices...
|
||||||
// Only the ones that are routing devices
|
// Only the ones that are routing devices
|
||||||
var midpointTieLines = destinationTieLines.Where(t => t.SourcePort.ParentDevice is IRoutingInputsOutputs);
|
var midpointTieLines = destinationTieLines.Where(t => t.SourcePort.ParentDevice is IRoutingMidpoint);
|
||||||
|
|
||||||
//Create a list for tracking already checked devices to avoid loops, if it doesn't already exist from previous iteration
|
//Create a list for tracking already checked devices to avoid loops, if it doesn't already exist from previous iteration
|
||||||
if (alreadyCheckedDevices == null)
|
if (alreadyCheckedDevices == null)
|
||||||
alreadyCheckedDevices = new List<IRoutingInputsOutputs>();
|
alreadyCheckedDevices = new List<IRoutingMidpoint>();
|
||||||
alreadyCheckedDevices.Add(destination as IRoutingInputsOutputs);
|
alreadyCheckedDevices.Add(destination as IRoutingMidpoint);
|
||||||
|
|
||||||
foreach (var tieLine in midpointTieLines)
|
foreach (var tieLine in midpointTieLines)
|
||||||
{
|
{
|
||||||
var midpointDevice = tieLine.SourcePort.ParentDevice as IRoutingInputsOutputs;
|
var midpointDevice = tieLine.SourcePort.ParentDevice as IRoutingMidpoint;
|
||||||
|
|
||||||
// Check if this previous device has already been walked
|
// Check if this previous device has already been walked
|
||||||
if (alreadyCheckedDevices.Contains(midpointDevice))
|
if (alreadyCheckedDevices.Contains(midpointDevice))
|
||||||
|
|
@ -659,12 +659,12 @@ public static class Extensions
|
||||||
|
|
||||||
// we have a route on corresponding inputPort. *** Do the route ***
|
// we have a route on corresponding inputPort. *** Do the route ***
|
||||||
|
|
||||||
if (destination is IRoutingSink)
|
if (destination is IRoutingSinkWithFeedback)
|
||||||
{
|
{
|
||||||
// it's a sink device
|
// it's a sink device
|
||||||
routeTable.Routes.Add(new RouteSwitchDescriptor(goodInputPort));
|
routeTable.Routes.Add(new RouteSwitchDescriptor(goodInputPort));
|
||||||
}
|
}
|
||||||
else if (destination is IRouting)
|
else if (destination is IRoutingMidpointWithFeedback)
|
||||||
{
|
{
|
||||||
routeTable.Routes.Add(new RouteSwitchDescriptor(outputPortToUse, goodInputPort));
|
routeTable.Routes.Add(new RouteSwitchDescriptor(outputPortToUse, goodInputPort));
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,35 +0,0 @@
|
||||||
using System;
|
|
||||||
|
|
||||||
namespace PepperDash.Essentials.Core
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Delegate for SourceInfoChangeHandler
|
|
||||||
/// </summary>
|
|
||||||
public delegate void SourceInfoChangeHandler(SourceListItem info, ChangeType type);
|
|
||||||
//*******************************************************************************************
|
|
||||||
// Interfaces
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// For rooms with a single presentation source, change event
|
|
||||||
/// </summary>
|
|
||||||
[Obsolete("Use ICurrentSources instead")]
|
|
||||||
public interface IHasCurrentSourceInfoChange
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// The key for the current source info, used to look up the source in the SourceList
|
|
||||||
/// </summary>
|
|
||||||
string CurrentSourceInfoKey { get; set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// The current source info for the room, used to look up the source in the SourceList
|
|
||||||
/// </summary>
|
|
||||||
SourceListItem CurrentSourceInfo { get; set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Event that is raised when the current source info changes.
|
|
||||||
/// This is used to notify the system of changes to the current source info.
|
|
||||||
/// The event handler receives the new source info and the type of change that occurred.
|
|
||||||
/// </summary>
|
|
||||||
event SourceInfoChangeHandler CurrentSourceChange;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,28 +0,0 @@
|
||||||
using System.Collections.Generic;
|
|
||||||
|
|
||||||
namespace PepperDash.Essentials.Core.Routing
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Defines the contract for IMatrixRouting
|
|
||||||
/// </summary>
|
|
||||||
public interface IMatrixRouting
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Gets the input slots
|
|
||||||
/// </summary>
|
|
||||||
Dictionary<string, IRoutingInputSlot> InputSlots { get; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets the output slots
|
|
||||||
/// </summary>
|
|
||||||
Dictionary<string, IRoutingOutputSlot> OutputSlots { get; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Routes the specified input slot to the specified output slot for the specified signal type
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="inputSlotKey">key of the input slot</param>
|
|
||||||
/// <param name="outputSlotKey">key of the output slot</param>
|
|
||||||
/// <param name="type">signal type</param>
|
|
||||||
void Route(string inputSlotKey, string outputSlotKey, eRoutingSignalType type);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,13 +0,0 @@
|
||||||
namespace PepperDash.Essentials.Core;
|
|
||||||
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Defines the contract for IRmcRouting
|
|
||||||
/// </summary>
|
|
||||||
public interface IRmcRouting : IRoutingNumeric
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Feedback for the current Audio/Video source as a number
|
|
||||||
/// </summary>
|
|
||||||
IntFeedback AudioVideoSourceNumericFeedback { get; }
|
|
||||||
}
|
|
||||||
|
|
@ -1,8 +0,0 @@
|
||||||
namespace PepperDash.Essentials.Core;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Defines an IRmcRouting with a feedback event
|
|
||||||
/// </summary>
|
|
||||||
public interface IRmcRoutingWithFeedback : IRmcRouting
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
@ -1,21 +0,0 @@
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
|
|
||||||
namespace PepperDash.Essentials.Core;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Defines a midpoint device as have internal routing. Any devices in the middle of the
|
|
||||||
/// signal chain, that do switching, must implement this for routing to work otherwise
|
|
||||||
/// the routing algorithm will treat the IRoutingInputsOutputs device as a passthrough
|
|
||||||
/// device.
|
|
||||||
/// </summary>
|
|
||||||
public interface IRouting : IRoutingInputsOutputs
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Executes a switch on the device
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="inputSelector">input selector</param>
|
|
||||||
/// <param name="outputSelector">output selector</param>
|
|
||||||
/// <param name="signalType">type of signal</param>
|
|
||||||
void ExecuteSwitch(object inputSelector, object outputSelector, eRoutingSignalType signalType);
|
|
||||||
}
|
|
||||||
|
|
@ -1,15 +0,0 @@
|
||||||
using System;
|
|
||||||
using PepperDash.Core;
|
|
||||||
namespace PepperDash.Essentials.Core;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Defines the contract for IRoutingFeedback
|
|
||||||
/// </summary>
|
|
||||||
public interface IRoutingFeedback : IKeyName
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Event raised when a numeric switch changes
|
|
||||||
/// </summary>
|
|
||||||
event EventHandler<RoutingNumericEventArgs> NumericSwitchChange;
|
|
||||||
//void OnSwitchChange(RoutingNumericEventArgs e);
|
|
||||||
}
|
|
||||||
|
|
@ -1,14 +0,0 @@
|
||||||
namespace PepperDash.Essentials.Core.Routing;
|
|
||||||
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Defines the contract for IRoutingInputSlot
|
|
||||||
/// </summary>
|
|
||||||
public interface IRoutingInputSlot : IRoutingSlot, IOnline, IVideoSync
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Gets the Tx device key
|
|
||||||
/// </summary>
|
|
||||||
string TxDeviceKey { get; }
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
@ -1,9 +0,0 @@
|
||||||
namespace PepperDash.Essentials.Core;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Defines the contract for IRoutingInputsOutputs
|
|
||||||
/// </summary>
|
|
||||||
public interface IRoutingInputsOutputs : IRoutingInputs, IRoutingOutputs
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
10
src/PepperDash.Essentials.Core/Routing/IRoutingMidpoint.cs
Normal file
10
src/PepperDash.Essentials.Core/Routing/IRoutingMidpoint.cs
Normal file
|
|
@ -0,0 +1,10 @@
|
||||||
|
namespace PepperDash.Essentials.Core;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Defines a midpoint (passthrough) device that has both input and output routing ports
|
||||||
|
/// but does not perform active switching. For switching midpoints, see <see cref="IRoutingMidpointWithFeedback"/>.
|
||||||
|
/// </summary>
|
||||||
|
public interface IRoutingMidpoint : IRoutingInputs, IRoutingOutputs
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
|
@ -0,0 +1,43 @@
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System;
|
||||||
|
|
||||||
|
namespace PepperDash.Essentials.Core;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Delegate for RouteChangedEventHandler.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="midpoint">The routing device where the change occurred.</param>
|
||||||
|
/// <param name="newRoute">A descriptor of the new route that was established.</param>
|
||||||
|
public delegate void RouteChangedEventHandler(IRoutingMidpointWithFeedback midpoint, RouteSwitchDescriptor newRoute);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Defines a midpoint device that performs active switching and provides feedback about its current routes.
|
||||||
|
/// Combines the capabilities of the former IRouting, IRoutingWithFeedback, and IRoutingWithClear interfaces.
|
||||||
|
/// </summary>
|
||||||
|
public interface IRoutingMidpointWithFeedback : IRoutingMidpoint
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Executes a switch on the device.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="inputSelector">Input selector.</param>
|
||||||
|
/// <param name="outputSelector">Output selector.</param>
|
||||||
|
/// <param name="signalType">Type of signal.</param>
|
||||||
|
void ExecuteSwitch(object inputSelector, object outputSelector, eRoutingSignalType signalType);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Clears a route to an output.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="outputSelector">Output to clear.</param>
|
||||||
|
/// <param name="signalType">Signal type to clear.</param>
|
||||||
|
void ClearRoute(object outputSelector, eRoutingSignalType signalType);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets a list describing the currently active routes on this device.
|
||||||
|
/// </summary>
|
||||||
|
List<RouteSwitchDescriptor> CurrentRoutes { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Event triggered when a route changes on this device.
|
||||||
|
/// </summary>
|
||||||
|
event RouteChangedEventHandler RouteChanged;
|
||||||
|
}
|
||||||
|
|
@ -1,16 +0,0 @@
|
||||||
namespace PepperDash.Essentials.Core;
|
|
||||||
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Defines the contract for IRoutingNumeric
|
|
||||||
/// </summary>
|
|
||||||
public interface IRoutingNumeric : IRouting
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Executes a numeric switch on the device
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="input">input selector</param>
|
|
||||||
/// <param name="output">output selector</param>
|
|
||||||
/// <param name="type">type of signal</param>
|
|
||||||
void ExecuteNumericSwitch(ushort input, ushort output, eRoutingSignalType type);
|
|
||||||
}
|
|
||||||
|
|
@ -1,8 +0,0 @@
|
||||||
namespace PepperDash.Essentials.Core;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Defines an IRoutingNumeric with a feedback event
|
|
||||||
/// </summary>
|
|
||||||
public interface IRoutingNumericWithFeedback : IRoutingNumeric, IRoutingFeedback
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
@ -1,27 +0,0 @@
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
|
|
||||||
namespace PepperDash.Essentials.Core.Routing;
|
|
||||||
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Defines the contract for IRoutingOutputSlot
|
|
||||||
/// </summary>
|
|
||||||
public interface IRoutingOutputSlot : IRoutingSlot
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Event raised when output slot changes
|
|
||||||
/// </summary>
|
|
||||||
event EventHandler OutputSlotChanged;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets the Rx device key
|
|
||||||
/// </summary>
|
|
||||||
string RxDeviceKey { get; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets the current routes
|
|
||||||
/// </summary>
|
|
||||||
Dictionary<eRoutingSignalType, IRoutingInputSlot> CurrentRoutes { get; }
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
@ -1,24 +0,0 @@
|
||||||
using PepperDash.Core;
|
|
||||||
using PepperDash.Essentials.Core.Routing;
|
|
||||||
|
|
||||||
namespace PepperDash.Essentials.Core;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Defines the contract for IRoutingSink
|
|
||||||
/// </summary>
|
|
||||||
public interface IRoutingSink : IRoutingInputs, IKeyName, ICurrentSources
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// For fixed-source endpoint devices with an input port
|
|
||||||
/// </summary>
|
|
||||||
public interface IRoutingSinkWithInputPort : IRoutingSink
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Gets the current input port for this routing sink.
|
|
||||||
/// </summary>
|
|
||||||
RoutingInputPort CurrentInputPort { get; }
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -1,12 +1,37 @@
|
||||||
namespace PepperDash.Essentials.Core;
|
using PepperDash.Core;
|
||||||
|
using PepperDash.Essentials.Core.Routing;
|
||||||
|
|
||||||
|
namespace PepperDash.Essentials.Core;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Defines the contract for IRoutingSinkWithFeedback
|
/// Delegate for InputChangedEventHandler.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public interface IRoutingSinkWithFeedback : IRoutingSink
|
/// <param name="destination">The sink device that changed input.</param>
|
||||||
|
/// <param name="currentPort">The new input port selected on the sink device.</param>
|
||||||
|
public delegate void InputChangedEventHandler(IRoutingSinkWithFeedback destination, RoutingInputPort currentPort);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Defines a routing sink (endpoint) device that can switch inputs and provides feedback.
|
||||||
|
/// Consolidates the former IRoutingSink, IRoutingSinkWithInputPort, IRoutingSinkWithSwitching,
|
||||||
|
/// IRoutingSinkWithSwitchingWithInputPort, and IRoutingSinkWithFeedback interfaces.
|
||||||
|
/// </summary>
|
||||||
|
public interface IRoutingSinkWithFeedback : IRoutingInputs, IKeyName, ICurrentSources
|
||||||
{
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Executes a switch on the device.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="inputSelector">Input selector.</param>
|
||||||
|
void ExecuteSwitch(object inputSelector);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the current input port for this routing sink.
|
||||||
|
/// </summary>
|
||||||
|
RoutingInputPort CurrentInputPort { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Event raised when the input changes.
|
||||||
|
/// </summary>
|
||||||
|
event InputChangedEventHandler InputChanged;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,30 +0,0 @@
|
||||||
|
|
||||||
namespace PepperDash.Essentials.Core;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Delegate for InputChangedEventHandler
|
|
||||||
/// </summary>
|
|
||||||
public delegate void InputChangedEventHandler(IRoutingSinkWithSwitching destination, RoutingInputPort currentPort);
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Defines the contract for IRoutingSinkWithSwitching
|
|
||||||
/// </summary>
|
|
||||||
public interface IRoutingSinkWithSwitching : IRoutingSink
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Executes a switch on the device
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="inputSelector">input selector</param>
|
|
||||||
void ExecuteSwitch(object inputSelector);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Defines the contract for IRoutingSinkWithSwitchingWithInputPort
|
|
||||||
/// </summary>
|
|
||||||
public interface IRoutingSinkWithSwitchingWithInputPort : IRoutingSinkWithSwitching, IRoutingSinkWithInputPort
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Event raised when the input changes
|
|
||||||
/// </summary>
|
|
||||||
event InputChangedEventHandler InputChanged;
|
|
||||||
}
|
|
||||||
|
|
@ -1,20 +0,0 @@
|
||||||
using PepperDash.Core;
|
|
||||||
|
|
||||||
namespace PepperDash.Essentials.Core.Routing
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Defines the contract for IRoutingSlot
|
|
||||||
/// </summary>
|
|
||||||
public interface IRoutingSlot:IKeyName
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Gets the slot number
|
|
||||||
/// </summary>
|
|
||||||
int SlotNumber { get; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets the supported signal types
|
|
||||||
/// </summary>
|
|
||||||
eRoutingSignalType SupportedSignalTypes { get; }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,14 +0,0 @@
|
||||||
namespace PepperDash.Essentials.Core;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Defines a routing device (<see cref="IRouting"/>) that supports explicitly clearing a route on an output.
|
|
||||||
/// </summary>
|
|
||||||
public interface IRoutingWithClear : IRouting
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Clears a route to an output, however a device needs to do that
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="outputSelector">Output to clear</param>
|
|
||||||
/// <param name="signalType">signal type to clear</param>
|
|
||||||
void ClearRoute(object outputSelector, eRoutingSignalType signalType);
|
|
||||||
}
|
|
||||||
|
|
@ -1,29 +0,0 @@
|
||||||
using System.Collections.Generic;
|
|
||||||
using System;
|
|
||||||
|
|
||||||
namespace PepperDash.Essentials.Core;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets a list describing the currently active routes on this device.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="midpoint">The routing device where the change occurred.</param>
|
|
||||||
/// <param name="newRoute">A descriptor of the new route that was established.</param>
|
|
||||||
/// <summary>
|
|
||||||
/// Delegate for RouteChangedEventHandler
|
|
||||||
/// </summary>
|
|
||||||
public delegate void RouteChangedEventHandler(IRoutingWithFeedback midpoint, RouteSwitchDescriptor newRoute);
|
|
||||||
/// <summary>
|
|
||||||
/// Defines a routing device (<see cref="IRouting"/>) that provides feedback about its current routes.
|
|
||||||
/// </summary>
|
|
||||||
public interface IRoutingWithFeedback : IRouting
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Gets a list describing the currently active routes on this device.
|
|
||||||
/// </summary>
|
|
||||||
List<RouteSwitchDescriptor> CurrentRoutes { get; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Event triggered when a route changes on this device.
|
|
||||||
/// </summary>
|
|
||||||
event RouteChangedEventHandler RouteChanged;
|
|
||||||
}
|
|
||||||
|
|
@ -1,17 +0,0 @@
|
||||||
namespace PepperDash.Essentials.Core;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Represents a routing device (typically a transmitter or source) that provides numeric feedback for its current route.
|
|
||||||
/// Extends <see cref="IRoutingNumeric"/>.
|
|
||||||
/// </summary>
|
|
||||||
public interface ITxRouting : IRoutingNumeric
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Feedback indicating the currently routed video source by its numeric identifier.
|
|
||||||
/// </summary>
|
|
||||||
IntFeedback VideoSourceNumericFeedback { get; }
|
|
||||||
/// <summary>
|
|
||||||
/// Feedback indicating the currently routed audio source by its numeric identifier.
|
|
||||||
/// </summary>
|
|
||||||
IntFeedback AudioSourceNumericFeedback { get; }
|
|
||||||
}
|
|
||||||
|
|
@ -1,8 +0,0 @@
|
||||||
namespace PepperDash.Essentials.Core;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Defines an IRmcRouting with a feedback event
|
|
||||||
/// </summary>
|
|
||||||
public interface ITxRoutingWithFeedback : ITxRouting
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
@ -74,13 +74,13 @@ public class RouteDescriptor
|
||||||
{
|
{
|
||||||
Debug.LogMessage(LogEventLevel.Verbose, "ExecuteRoutes: {0}", null, route.ToString());
|
Debug.LogMessage(LogEventLevel.Verbose, "ExecuteRoutes: {0}", null, route.ToString());
|
||||||
|
|
||||||
if (route.SwitchingDevice is IRoutingSinkWithSwitching sink)
|
if (route.SwitchingDevice is IRoutingSinkWithFeedback sink)
|
||||||
{
|
{
|
||||||
sink.ExecuteSwitch(route.InputPort.Selector);
|
sink.ExecuteSwitch(route.InputPort.Selector);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (route.SwitchingDevice is IRouting switchingDevice)
|
if (route.SwitchingDevice is IRoutingMidpointWithFeedback switchingDevice)
|
||||||
{
|
{
|
||||||
switchingDevice.ExecuteSwitch(route.InputPort.Selector, route.OutputPort.Selector, SignalType);
|
switchingDevice.ExecuteSwitch(route.InputPort.Selector, route.OutputPort.Selector, SignalType);
|
||||||
|
|
||||||
|
|
@ -97,9 +97,9 @@ public class RouteDescriptor
|
||||||
/// <param name="clearRoute">If true, attempts to clear the route on the switching devices (e.g., set input to null/0).</param>
|
/// <param name="clearRoute">If true, attempts to clear the route on the switching devices (e.g., set input to null/0).</param>
|
||||||
public void ReleaseRoutes(bool clearRoute = false)
|
public void ReleaseRoutes(bool clearRoute = false)
|
||||||
{
|
{
|
||||||
foreach (var route in Routes.Where(r => r.SwitchingDevice is IRouting))
|
foreach (var route in Routes.Where(r => r.SwitchingDevice is IRoutingMidpointWithFeedback))
|
||||||
{
|
{
|
||||||
if (route.SwitchingDevice is IRouting switchingDevice)
|
if (route.SwitchingDevice is IRoutingMidpointWithFeedback switchingDevice)
|
||||||
{
|
{
|
||||||
if (clearRoute)
|
if (clearRoute)
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -45,7 +45,7 @@
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public override string ToString()
|
public override string ToString()
|
||||||
{
|
{
|
||||||
if (SwitchingDevice is IRouting)
|
if (SwitchingDevice is IRoutingMidpointWithFeedback)
|
||||||
return $"{(SwitchingDevice != null ? SwitchingDevice.Key : "No Device")} switches output {(OutputPort != null ? OutputPort.Key : "No output port")} to input {(InputPort != null ? InputPort.Key : "No input port")}";
|
return $"{(SwitchingDevice != null ? SwitchingDevice.Key : "No Device")} switches output {(OutputPort != null ? OutputPort.Key : "No output port")} to input {(InputPort != null ? InputPort.Key : "No input port")}";
|
||||||
else
|
else
|
||||||
return $"{(SwitchingDevice != null ? SwitchingDevice.Key : "No Device")} switches to input {(InputPort != null ? InputPort.Key : "No input port")}";
|
return $"{(SwitchingDevice != null ? SwitchingDevice.Key : "No Device")} switches to input {(InputPort != null ? InputPort.Key : "No input port")}";
|
||||||
|
|
|
||||||
|
|
@ -49,8 +49,8 @@ namespace PepperDash.Essentials.Core.Routing
|
||||||
{
|
{
|
||||||
midpointToSinksMap = new Dictionary<string, HashSet<string>>();
|
midpointToSinksMap = new Dictionary<string, HashSet<string>>();
|
||||||
|
|
||||||
var sinks = DeviceManager.AllDevices.OfType<IRoutingSinkWithSwitchingWithInputPort>();
|
var sinks = DeviceManager.AllDevices.OfType<IRoutingSinkWithFeedback>();
|
||||||
var midpoints = DeviceManager.AllDevices.OfType<IRoutingWithFeedback>();
|
var midpoints = DeviceManager.AllDevices.OfType<IRoutingMidpointWithFeedback>();
|
||||||
|
|
||||||
foreach (var sink in sinks)
|
foreach (var sink in sinks)
|
||||||
{
|
{
|
||||||
|
|
@ -80,7 +80,7 @@ namespace PepperDash.Essentials.Core.Routing
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets all upstream midpoint device keys for a given sink
|
/// Gets all upstream midpoint device keys for a given sink
|
||||||
/// </summary>
|
/// </summary>
|
||||||
private HashSet<string> GetUpstreamMidpoints(IRoutingSinkWithSwitchingWithInputPort sink)
|
private HashSet<string> GetUpstreamMidpoints(IRoutingSinkWithFeedback sink)
|
||||||
{
|
{
|
||||||
var result = new HashSet<string>();
|
var result = new HashSet<string>();
|
||||||
var visited = new HashSet<string>();
|
var visited = new HashSet<string>();
|
||||||
|
|
@ -109,7 +109,7 @@ namespace PepperDash.Essentials.Core.Routing
|
||||||
|
|
||||||
visited.Add(tieLine.SourcePort.ParentDevice.Key);
|
visited.Add(tieLine.SourcePort.ParentDevice.Key);
|
||||||
|
|
||||||
if (tieLine.SourcePort.ParentDevice is IRoutingWithFeedback midpoint)
|
if (tieLine.SourcePort.ParentDevice is IRoutingMidpointWithFeedback midpoint)
|
||||||
{
|
{
|
||||||
midpoints.Add(midpoint.Key);
|
midpoints.Add(midpoint.Key);
|
||||||
|
|
||||||
|
|
@ -131,11 +131,11 @@ namespace PepperDash.Essentials.Core.Routing
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Subscribes to the RouteChanged event on all devices implementing <see cref="IRoutingWithFeedback"/>.
|
/// Subscribes to the RouteChanged event on all devices implementing <see cref="IRoutingMidpointWithFeedback"/>.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
private void SubscribeForMidpointFeedback()
|
private void SubscribeForMidpointFeedback()
|
||||||
{
|
{
|
||||||
var midpointDevices = DeviceManager.AllDevices.OfType<IRoutingWithFeedback>();
|
var midpointDevices = DeviceManager.AllDevices.OfType<IRoutingMidpointWithFeedback>();
|
||||||
|
|
||||||
foreach (var device in midpointDevices)
|
foreach (var device in midpointDevices)
|
||||||
{
|
{
|
||||||
|
|
@ -144,12 +144,12 @@ namespace PepperDash.Essentials.Core.Routing
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Subscribes to the InputChanged event on all devices implementing <see cref="IRoutingSinkWithSwitchingWithInputPort"/>.
|
/// Subscribes to the InputChanged event on all devices implementing <see cref="IRoutingSinkWithFeedback"/>.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
private void SubscribeForSinkFeedback()
|
private void SubscribeForSinkFeedback()
|
||||||
{
|
{
|
||||||
var sinkDevices =
|
var sinkDevices =
|
||||||
DeviceManager.AllDevices.OfType<IRoutingSinkWithSwitchingWithInputPort>();
|
DeviceManager.AllDevices.OfType<IRoutingSinkWithFeedback>();
|
||||||
|
|
||||||
foreach (var device in sinkDevices)
|
foreach (var device in sinkDevices)
|
||||||
{
|
{
|
||||||
|
|
@ -164,7 +164,7 @@ namespace PepperDash.Essentials.Core.Routing
|
||||||
/// <param name="midpoint">The midpoint device that reported a route change.</param>
|
/// <param name="midpoint">The midpoint device that reported a route change.</param>
|
||||||
/// <param name="newRoute">The descriptor of the new route.</param>
|
/// <param name="newRoute">The descriptor of the new route.</param>
|
||||||
private void HandleMidpointUpdate(
|
private void HandleMidpointUpdate(
|
||||||
IRoutingWithFeedback midpoint,
|
IRoutingMidpointWithFeedback midpoint,
|
||||||
RouteSwitchDescriptor newRoute
|
RouteSwitchDescriptor newRoute
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
|
|
@ -183,7 +183,7 @@ namespace PepperDash.Essentials.Core.Routing
|
||||||
|
|
||||||
foreach (var sinkKey in affectedSinkKeys)
|
foreach (var sinkKey in affectedSinkKeys)
|
||||||
{
|
{
|
||||||
if (DeviceManager.GetDeviceForKey(sinkKey) is IRoutingSinkWithSwitchingWithInputPort sink)
|
if (DeviceManager.GetDeviceForKey(sinkKey) is IRoutingSinkWithFeedback sink)
|
||||||
{
|
{
|
||||||
UpdateDestination(sink, sink.CurrentInputPort);
|
UpdateDestination(sink, sink.CurrentInputPort);
|
||||||
}
|
}
|
||||||
|
|
@ -218,7 +218,7 @@ namespace PepperDash.Essentials.Core.Routing
|
||||||
/// <param name="sender">The sink device that reported an input change.</param>
|
/// <param name="sender">The sink device that reported an input change.</param>
|
||||||
/// <param name="currentInputPort">The new input port selected on the sink device.</param>
|
/// <param name="currentInputPort">The new input port selected on the sink device.</param>
|
||||||
private void HandleSinkUpdate(
|
private void HandleSinkUpdate(
|
||||||
IRoutingSinkWithSwitching sender,
|
IRoutingSinkWithFeedback sender,
|
||||||
RoutingInputPort currentInputPort
|
RoutingInputPort currentInputPort
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
|
|
@ -246,7 +246,7 @@ namespace PepperDash.Essentials.Core.Routing
|
||||||
/// <param name="destination">The destination sink device to update.</param>
|
/// <param name="destination">The destination sink device to update.</param>
|
||||||
/// <param name="inputPort">The currently selected input port on the destination device.</param>
|
/// <param name="inputPort">The currently selected input port on the destination device.</param>
|
||||||
private void UpdateDestination(
|
private void UpdateDestination(
|
||||||
IRoutingSinkWithSwitching destination,
|
IRoutingSinkWithFeedback destination,
|
||||||
RoutingInputPort inputPort
|
RoutingInputPort inputPort
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
|
|
@ -298,7 +298,7 @@ namespace PepperDash.Essentials.Core.Routing
|
||||||
/// Called after debounce delay.
|
/// Called after debounce delay.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
private void UpdateDestinationImmediate(
|
private void UpdateDestinationImmediate(
|
||||||
IRoutingSinkWithSwitching destination,
|
IRoutingSinkWithFeedback destination,
|
||||||
RoutingInputPort inputPort
|
RoutingInputPort inputPort
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
|
|
@ -491,7 +491,7 @@ namespace PepperDash.Essentials.Core.Routing
|
||||||
// Get all potential sources (devices that only have outputs, not inputs+outputs)
|
// Get all potential sources (devices that only have outputs, not inputs+outputs)
|
||||||
var sources = DeviceManager.AllDevices
|
var sources = DeviceManager.AllDevices
|
||||||
.OfType<IRoutingOutputs>()
|
.OfType<IRoutingOutputs>()
|
||||||
.Where(s => !(s is IRoutingInputsOutputs));
|
.Where(s => !(s is IRoutingMidpoint));
|
||||||
|
|
||||||
// Try each signal type that this TieLine supports
|
// Try each signal type that this TieLine supports
|
||||||
var signalTypes = new[]
|
var signalTypes = new[]
|
||||||
|
|
|
||||||
|
|
@ -62,8 +62,8 @@ namespace PepperDash.Essentials.Core.Web.RequestHandlers
|
||||||
})];
|
})];
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check if device implements IRoutingInputsOutputs
|
// Check if device implements IRoutingMidpoint
|
||||||
if (device is IRoutingInputsOutputs)
|
if (device is IRoutingMidpoint)
|
||||||
{
|
{
|
||||||
deviceInfo.HasInputsAndOutputs = true;
|
deviceInfo.HasInputsAndOutputs = true;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -12,11 +12,16 @@ namespace PepperDash.Essentials.Devices.Common;
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Represents and audio endpoint
|
/// Represents and audio endpoint
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class GenericAudioOut : EssentialsDevice, IRoutingSink
|
public class GenericAudioOut : EssentialsDevice, IRoutingSinkWithFeedback
|
||||||
{
|
{
|
||||||
/// <inheritdoc/>
|
/// <inheritdoc/>
|
||||||
public RoutingInputPort CurrentInputPort => AnyAudioIn;
|
public RoutingInputPort CurrentInputPort => AnyAudioIn;
|
||||||
|
|
||||||
|
/// <inheritdoc/>
|
||||||
|
public event InputChangedEventHandler InputChanged;
|
||||||
|
|
||||||
|
/// <inheritdoc/>
|
||||||
|
public void ExecuteSwitch(object inputSelector) { }
|
||||||
|
|
||||||
/// <inheritdoc/>
|
/// <inheritdoc/>
|
||||||
public Dictionary<eRoutingSignalType, IRoutingSource> CurrentSources { get; private set; }
|
public Dictionary<eRoutingSignalType, IRoutingSource> CurrentSources { get; private set; }
|
||||||
|
|
|
||||||
|
|
@ -229,7 +229,7 @@ public class BasicIrDisplay : DisplayBase, IBasicVolumeControls, IBridgeAdvanced
|
||||||
t.Start();
|
t.Start();
|
||||||
}
|
}
|
||||||
|
|
||||||
#region IRoutingSink Members
|
#region IRoutingSinkWithFeedback Members
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Typically called by the discovery routing algorithm.
|
/// Typically called by the discovery routing algorithm.
|
||||||
|
|
|
||||||
|
|
@ -15,7 +15,7 @@ namespace PepperDash.Essentials.Devices.Common.Displays;
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Represents a mock display device for testing and simulation purposes.
|
/// Represents a mock display device for testing and simulation purposes.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class MockDisplay : TwoWayDisplayBase, IBasicVolumeWithFeedback, IBridgeAdvanced, IHasInputs<string>, IRoutingSinkWithSwitchingWithInputPort, IHasPowerControlWithFeedback
|
public class MockDisplay : TwoWayDisplayBase, IBasicVolumeWithFeedback, IBridgeAdvanced, IHasInputs<string>, IHasPowerControlWithFeedback
|
||||||
{
|
{
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public ISelectableItems<string> Inputs { get; private set; }
|
public ISelectableItems<string> Inputs { get; private set; }
|
||||||
|
|
|
||||||
|
|
@ -7,7 +7,7 @@ namespace PepperDash.Essentials.Devices.Common.Displays
|
||||||
/// Abstract base class for two-way display devices that provide feedback capabilities.
|
/// Abstract base class for two-way display devices that provide feedback capabilities.
|
||||||
/// Extends DisplayBase with routing feedback and power control feedback functionality.
|
/// Extends DisplayBase with routing feedback and power control feedback functionality.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public abstract class TwoWayDisplayBase : DisplayBase, IRoutingFeedback, IHasPowerControlWithFeedback
|
public abstract class TwoWayDisplayBase : DisplayBase, IHasPowerControlWithFeedback
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets feedback for the current input selection on the display.
|
/// Gets feedback for the current input selection on the display.
|
||||||
|
|
|
||||||
|
|
@ -12,7 +12,7 @@ namespace PepperDash.Essentials.Devices.Common.Generic;
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Represents a GenericSink
|
/// Represents a GenericSink
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class GenericSink : EssentialsDevice, IRoutingSinkWithSwitchingWithInputPort, ICurrentSources
|
public class GenericSink : EssentialsDevice, IRoutingSinkWithFeedback
|
||||||
{
|
{
|
||||||
/// <inheritdoc/>
|
/// <inheritdoc/>
|
||||||
public Dictionary<eRoutingSignalType, IRoutingSource> CurrentSources { get; private set; }
|
public Dictionary<eRoutingSignalType, IRoutingSource> CurrentSources { get; private set; }
|
||||||
|
|
@ -104,43 +104,13 @@ public class GenericSink : EssentialsDevice, IRoutingSinkWithSwitchingWithInputP
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public RoutingPortCollection<RoutingInputPort> InputPorts { get; private set; }
|
public RoutingPortCollection<RoutingInputPort> InputPorts { get; private set; }
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets or sets the CurrentSourceInfoKey
|
|
||||||
/// </summary>
|
|
||||||
public string CurrentSourceInfoKey { get; set; }
|
|
||||||
|
|
||||||
private SourceListItem _currentSource;
|
private SourceListItem _currentSource;
|
||||||
/// <summary>
|
|
||||||
/// Gets or sets the CurrentSourceInfo
|
|
||||||
/// </summary>
|
|
||||||
public SourceListItem CurrentSourceInfo
|
|
||||||
{
|
|
||||||
get => _currentSource;
|
|
||||||
set
|
|
||||||
{
|
|
||||||
if (value == _currentSource)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
CurrentSourceChange?.Invoke(_currentSource, ChangeType.WillChange);
|
|
||||||
|
|
||||||
_currentSource = value;
|
|
||||||
|
|
||||||
CurrentSourceChange?.Invoke(_currentSource, ChangeType.DidChange);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the current input port
|
/// Gets the current input port
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public RoutingInputPort CurrentInputPort => InputPorts[0];
|
public RoutingInputPort CurrentInputPort => InputPorts[0];
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Event fired when the current source changes
|
|
||||||
/// </summary>
|
|
||||||
public event SourceInfoChangeHandler CurrentSourceChange;
|
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public event InputChangedEventHandler InputChanged;
|
public event InputChangedEventHandler InputChanged;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -15,7 +15,7 @@ namespace PepperDash.Essentials.Devices.Common.SoftCodec;
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Class representing a BlueJeans soft codec running on an in-room PC.
|
/// Class representing a BlueJeans soft codec running on an in-room PC.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class BlueJeansPc : InRoomPc, IRunRouteAction, IRoutingSink
|
public class BlueJeansPc : InRoomPc, IRunRouteAction, IRoutingSinkWithFeedback
|
||||||
{
|
{
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|
@ -29,6 +29,12 @@ public class BlueJeansPc : InRoomPc, IRunRouteAction, IRoutingSink
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public RoutingInputPort CurrentInputPort => AnyVideoIn;
|
public RoutingInputPort CurrentInputPort => AnyVideoIn;
|
||||||
|
|
||||||
|
/// <inheritdoc/>
|
||||||
|
public event InputChangedEventHandler InputChanged;
|
||||||
|
|
||||||
|
/// <inheritdoc/>
|
||||||
|
public void ExecuteSwitch(object inputSelector) { }
|
||||||
|
|
||||||
/// <inheritdoc/>
|
/// <inheritdoc/>
|
||||||
public Dictionary<eRoutingSignalType, IRoutingSource> CurrentSources { get; private set; }
|
public Dictionary<eRoutingSignalType, IRoutingSource> CurrentSources { get; private set; }
|
||||||
|
|
||||||
|
|
@ -170,16 +176,7 @@ public class BlueJeansPc : InRoomPc, IRunRouteAction, IRoutingSink
|
||||||
}
|
}
|
||||||
|
|
||||||
// store the name and UI info for routes
|
// store the name and UI info for routes
|
||||||
if (item.SourceKey == "none")
|
// CurrentSourceInfo tracking removed in v3 interface consolidation
|
||||||
{
|
|
||||||
CurrentSourceInfoKey = routeKey;
|
|
||||||
CurrentSourceInfo = null;
|
|
||||||
}
|
|
||||||
else if (item.SourceKey != null)
|
|
||||||
{
|
|
||||||
CurrentSourceInfoKey = routeKey;
|
|
||||||
CurrentSourceInfo = item;
|
|
||||||
}
|
|
||||||
|
|
||||||
// report back when done
|
// report back when done
|
||||||
if (successCallback != null)
|
if (successCallback != null)
|
||||||
|
|
@ -196,9 +193,9 @@ public class BlueJeansPc : InRoomPc, IRunRouteAction, IRoutingSink
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
bool DoRoute(SourceRouteListItem route)
|
bool DoRoute(SourceRouteListItem route)
|
||||||
{
|
{
|
||||||
IRoutingSink dest = null;
|
IRoutingSinkWithFeedback dest = null;
|
||||||
|
|
||||||
dest = DeviceManager.GetDeviceForKey(route.DestinationKey) as IRoutingSink;
|
dest = DeviceManager.GetDeviceForKey(route.DestinationKey) as IRoutingSinkWithFeedback;
|
||||||
|
|
||||||
if (dest == null)
|
if (dest == null)
|
||||||
{
|
{
|
||||||
|
|
@ -227,42 +224,5 @@ public class BlueJeansPc : InRoomPc, IRunRouteAction, IRoutingSink
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#region IHasCurrentSourceInfoChange Members
|
|
||||||
|
|
||||||
/// <inheritdoc />
|
|
||||||
public string CurrentSourceInfoKey { get; set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// The SourceListItem last run - containing names and icons
|
|
||||||
/// </summary>
|
|
||||||
public SourceListItem CurrentSourceInfo
|
|
||||||
{
|
|
||||||
get { return _CurrentSourceInfo; }
|
|
||||||
set
|
|
||||||
{
|
|
||||||
if (value == _CurrentSourceInfo) return;
|
|
||||||
|
|
||||||
var handler = CurrentSourceChange;
|
|
||||||
// remove from in-use tracker, if so equipped
|
|
||||||
if (_CurrentSourceInfo != null && _CurrentSourceInfo.SourceDevice is IInUseTracking)
|
|
||||||
(_CurrentSourceInfo.SourceDevice as IInUseTracking).InUseTracker.RemoveUser(this, "control");
|
|
||||||
|
|
||||||
if (handler != null)
|
|
||||||
handler(_CurrentSourceInfo, ChangeType.WillChange);
|
|
||||||
|
|
||||||
_CurrentSourceInfo = value;
|
|
||||||
|
|
||||||
// add to in-use tracking
|
|
||||||
if (_CurrentSourceInfo != null && _CurrentSourceInfo.SourceDevice is IInUseTracking)
|
|
||||||
(_CurrentSourceInfo.SourceDevice as IInUseTracking).InUseTracker.AddUser(this, "control");
|
|
||||||
if (handler != null)
|
|
||||||
handler(_CurrentSourceInfo, ChangeType.DidChange);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
SourceListItem _CurrentSourceInfo;
|
|
||||||
|
|
||||||
/// <inheritdoc />
|
|
||||||
public event SourceInfoChangeHandler CurrentSourceChange;
|
|
||||||
|
|
||||||
#endregion
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -12,7 +12,7 @@ namespace PepperDash.Essentials.Devices.Common.SoftCodec;
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Represents a GenericSoftCodec
|
/// Represents a GenericSoftCodec
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class GenericSoftCodec : EssentialsDevice, IRoutingSource, IRoutingSinkWithSwitchingWithInputPort
|
public class GenericSoftCodec : EssentialsDevice, IRoutingSource, IRoutingSinkWithFeedback
|
||||||
{
|
{
|
||||||
private RoutingInputPort _currentInputPort;
|
private RoutingInputPort _currentInputPort;
|
||||||
|
|
||||||
|
|
@ -141,46 +141,11 @@ public class GenericSoftCodec : EssentialsDevice, IRoutingSource, IRoutingSinkWi
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public RoutingPortCollection<RoutingInputPort> InputPorts { get; private set; }
|
public RoutingPortCollection<RoutingInputPort> InputPorts { get; private set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets or sets the OutputPorts
|
/// Gets or sets the OutputPorts
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public RoutingPortCollection<RoutingOutputPort> OutputPorts { get; private set; }
|
public RoutingPortCollection<RoutingOutputPort> OutputPorts { get; private set; }
|
||||||
/// <summary>
|
|
||||||
/// Gets or sets the CurrentSourceInfoKey
|
|
||||||
/// </summary>
|
|
||||||
public string CurrentSourceInfoKey { get; set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets or sets the CurrentSourceInfo
|
|
||||||
/// </summary>
|
|
||||||
public SourceListItem CurrentSourceInfo
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
return _CurrentSourceInfo;
|
|
||||||
}
|
|
||||||
set
|
|
||||||
{
|
|
||||||
if (value == _CurrentSourceInfo) return;
|
|
||||||
|
|
||||||
var handler = CurrentSourceChange;
|
|
||||||
|
|
||||||
if (handler != null)
|
|
||||||
handler(_CurrentSourceInfo, ChangeType.WillChange);
|
|
||||||
|
|
||||||
_CurrentSourceInfo = value;
|
|
||||||
|
|
||||||
if (handler != null)
|
|
||||||
handler(_CurrentSourceInfo, ChangeType.DidChange);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
SourceListItem _CurrentSourceInfo;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Event fired when the current source changes
|
|
||||||
/// </summary>
|
|
||||||
public event SourceInfoChangeHandler CurrentSourceChange;
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Event fired when the input changes
|
/// Event fired when the input changes
|
||||||
|
|
|
||||||
|
|
@ -27,7 +27,7 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec;
|
||||||
/// Base class for video codecs. Contains common properties, methods, and feedback for video codecs.
|
/// Base class for video codecs. Contains common properties, methods, and feedback for video codecs.
|
||||||
/// Also contains the logic to link commonly implemented interfaces to the API bridge.
|
/// Also contains the logic to link commonly implemented interfaces to the API bridge.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public abstract class VideoCodecBase : ReconfigurableDevice, IRoutingInputsOutputs,
|
public abstract class VideoCodecBase : ReconfigurableDevice, IRoutingMidpoint,
|
||||||
IUsageTracking, ICodecCallControls, IHasContentSharing, ICodecAudio, IVideoCodecInfo, IBridgeAdvanced, IHasStandbyMode, IHasReady
|
IUsageTracking, ICodecCallControls, IHasContentSharing, ICodecAudio, IVideoCodecInfo, IBridgeAdvanced, IHasStandbyMode, IHasReady
|
||||||
{
|
{
|
||||||
private const int XSigEncoding = 28591;
|
private const int XSigEncoding = 28591;
|
||||||
|
|
@ -302,7 +302,7 @@ public abstract class VideoCodecBase : ReconfigurableDevice, IRoutingInputsOutpu
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region IRoutingInputsOutputs Members
|
#region IRoutingMidpoint Members
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets or sets the InputPorts
|
/// Gets or sets the InputPorts
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,72 @@
|
||||||
|
using Newtonsoft.Json.Linq;
|
||||||
|
using PepperDash.Core;
|
||||||
|
using PepperDash.Core.Logging;
|
||||||
|
using PepperDash.Essentials.AppServer;
|
||||||
|
using PepperDash.Essentials.AppServer.Messengers;
|
||||||
|
using PepperDash.Essentials.Core;
|
||||||
|
using PepperDash.Essentials.Core.Routing;
|
||||||
|
using System.Linq;
|
||||||
|
using DisplayBase = PepperDash.Essentials.Devices.Common.Displays.DisplayBase;
|
||||||
|
|
||||||
|
namespace PepperDash.Essentials.Room.MobileControl
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Represents a DisplayBaseMessenger
|
||||||
|
/// </summary>
|
||||||
|
public class IRoutingSinkWithFeedbackMessenger : MessengerBase
|
||||||
|
{
|
||||||
|
private readonly IRoutingSinkWithFeedback display;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Create an instance of the <see cref="IRoutingSinkWithFeedbackMessenger"/> class.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="key"></param>
|
||||||
|
/// <param name="messagePath"></param>
|
||||||
|
/// <param name="device"></param>
|
||||||
|
public IRoutingSinkWithFeedbackMessenger(string key, string messagePath, IRoutingSinkWithFeedback device) : base(key, messagePath, device)
|
||||||
|
{
|
||||||
|
display = device;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
protected override void RegisterActions()
|
||||||
|
{
|
||||||
|
base.RegisterActions();
|
||||||
|
|
||||||
|
/*AddAction("/powerOn", (id, content) => display.PowerOn());
|
||||||
|
AddAction("/powerOff", (id, content) => display.PowerOff());
|
||||||
|
AddAction("/powerToggle", (id, content) => display.PowerToggle());*/
|
||||||
|
|
||||||
|
AddAction("/inputSelect", (id, content) =>
|
||||||
|
{
|
||||||
|
var s = content.ToObject<MobileControlSimpleContent<string>>();
|
||||||
|
|
||||||
|
var inputPort = display.InputPorts.FirstOrDefault(i => i.Key == s.Value);
|
||||||
|
|
||||||
|
if (inputPort == null)
|
||||||
|
{
|
||||||
|
this.LogWarning("No input named {inputName} found for {deviceKey}", s, display.Key);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
display.ExecuteSwitch(inputPort.Selector);
|
||||||
|
});
|
||||||
|
|
||||||
|
AddAction("/inputs", (id, content) =>
|
||||||
|
{
|
||||||
|
var inputsList = display.InputPorts.Select(p => p.Key).ToList();
|
||||||
|
|
||||||
|
var messageObject = new MobileControlMessage
|
||||||
|
{
|
||||||
|
Type = MessagePath + "/inputs",
|
||||||
|
Content = JToken.FromObject(new
|
||||||
|
{
|
||||||
|
inputKeys = inputsList,
|
||||||
|
})
|
||||||
|
};
|
||||||
|
|
||||||
|
AppServerController.SendMessageObject(messageObject);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -12,17 +12,17 @@ namespace PepperDash.Essentials.Room.MobileControl
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Represents a DisplayBaseMessenger
|
/// Represents a DisplayBaseMessenger
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class IRoutingSinkWithSwitchingMessenger : MessengerBase
|
public class IRoutingSinkWithFeedbackMessenger : MessengerBase
|
||||||
{
|
{
|
||||||
private readonly IRoutingSinkWithSwitching display;
|
private readonly IRoutingSinkWithFeedback display;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Create an instance of the <see cref="IRoutingSinkWithSwitchingMessenger"/> class.
|
/// Create an instance of the <see cref="IRoutingSinkWithFeedbackMessenger"/> class.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="key"></param>
|
/// <param name="key"></param>
|
||||||
/// <param name="messagePath"></param>
|
/// <param name="messagePath"></param>
|
||||||
/// <param name="device"></param>
|
/// <param name="device"></param>
|
||||||
public IRoutingSinkWithSwitchingMessenger(string key, string messagePath, IRoutingSinkWithSwitching device) : base(key, messagePath, device)
|
public IRoutingSinkWithFeedbackMessenger(string key, string messagePath, IRoutingSinkWithFeedback device) : base(key, messagePath, device)
|
||||||
{
|
{
|
||||||
display = device;
|
display = device;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,76 +0,0 @@
|
||||||
using Newtonsoft.Json;
|
|
||||||
using Newtonsoft.Json.Linq;
|
|
||||||
using PepperDash.Core;
|
|
||||||
using PepperDash.Essentials.Core;
|
|
||||||
|
|
||||||
namespace PepperDash.Essentials.AppServer.Messengers
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Represents a IHasCurrentSourceInfoMessenger
|
|
||||||
/// </summary>
|
|
||||||
public class IHasCurrentSourceInfoMessenger : MessengerBase
|
|
||||||
{
|
|
||||||
private readonly IHasCurrentSourceInfoChange sourceDevice;
|
|
||||||
|
|
||||||
public IHasCurrentSourceInfoMessenger(string key, string messagePath, IHasCurrentSourceInfoChange device) : base(key, messagePath, device as IKeyName)
|
|
||||||
{
|
|
||||||
sourceDevice = device;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override void RegisterActions()
|
|
||||||
{
|
|
||||||
base.RegisterActions();
|
|
||||||
|
|
||||||
AddAction("/fullStatus", (id, content) => SendFullStatus(id));
|
|
||||||
|
|
||||||
AddAction("/currentSourceInfoStatus", (id, content) => SendFullStatus(id));
|
|
||||||
|
|
||||||
sourceDevice.CurrentSourceChange += (sender, e) =>
|
|
||||||
{
|
|
||||||
switch (e)
|
|
||||||
{
|
|
||||||
case ChangeType.DidChange:
|
|
||||||
{
|
|
||||||
PostStatusMessage(JToken.FromObject(new
|
|
||||||
{
|
|
||||||
currentSourceKey = string.IsNullOrEmpty(sourceDevice.CurrentSourceInfoKey) ? string.Empty : sourceDevice.CurrentSourceInfoKey,
|
|
||||||
currentSource = sourceDevice.CurrentSourceInfo
|
|
||||||
}));
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
private void SendFullStatus(string id = null)
|
|
||||||
{
|
|
||||||
var message = new CurrentSourceStateMessage
|
|
||||||
{
|
|
||||||
CurrentSourceKey = sourceDevice.CurrentSourceInfoKey,
|
|
||||||
CurrentSource = sourceDevice.CurrentSourceInfo
|
|
||||||
};
|
|
||||||
|
|
||||||
PostStatusMessage(message, id);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Represents a CurrentSourceStateMessage
|
|
||||||
/// </summary>
|
|
||||||
public class CurrentSourceStateMessage : DeviceStateMessageBase
|
|
||||||
{
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets or sets the CurrentSourceKey
|
|
||||||
/// </summary>
|
|
||||||
[JsonProperty("currentSourceKey", NullValueHandling = NullValueHandling.Ignore)]
|
|
||||||
public string CurrentSourceKey { get; set; }
|
|
||||||
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets or sets the CurrentSource
|
|
||||||
/// </summary>
|
|
||||||
[JsonProperty("currentSource")]
|
|
||||||
public SourceListItem CurrentSource { get; set; }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,267 +0,0 @@
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using Newtonsoft.Json;
|
|
||||||
using Newtonsoft.Json.Linq;
|
|
||||||
using PepperDash.Core;
|
|
||||||
using PepperDash.Essentials.Core;
|
|
||||||
using PepperDash.Essentials.Core.Routing;
|
|
||||||
using Serilog.Events;
|
|
||||||
|
|
||||||
namespace PepperDash.Essentials.AppServer.Messengers
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Messenger for devices that implment IMatrixRouting
|
|
||||||
/// </summary>
|
|
||||||
public class IMatrixRoutingMessenger : MessengerBase
|
|
||||||
{
|
|
||||||
private readonly IMatrixRouting matrixDevice;
|
|
||||||
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Initializes a new instance of the <see cref="IMatrixRoutingMessenger"/> class.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="key"></param>
|
|
||||||
/// <param name="messagePath"></param>
|
|
||||||
/// <param name="device"></param>
|
|
||||||
public IMatrixRoutingMessenger(string key, string messagePath, IMatrixRouting device) : base(key, messagePath, device as IKeyName)
|
|
||||||
{
|
|
||||||
matrixDevice = device;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <inheritdoc />
|
|
||||||
protected override void RegisterActions()
|
|
||||||
{
|
|
||||||
base.RegisterActions();
|
|
||||||
|
|
||||||
AddAction("/fullStatus", (id, content) => SendFullStatus(id));
|
|
||||||
|
|
||||||
AddAction("/matrixStatus", (id, content) => SendFullStatus(id));
|
|
||||||
|
|
||||||
AddAction("/route", (id, content) =>
|
|
||||||
{
|
|
||||||
var request = content.ToObject<MatrixRouteRequest>();
|
|
||||||
|
|
||||||
matrixDevice.Route(request.InputKey, request.OutputKey, request.RouteType);
|
|
||||||
});
|
|
||||||
|
|
||||||
foreach (var output in matrixDevice.OutputSlots)
|
|
||||||
{
|
|
||||||
var key = output.Key;
|
|
||||||
var outputSlot = output.Value;
|
|
||||||
|
|
||||||
outputSlot.OutputSlotChanged += (sender, args) =>
|
|
||||||
{
|
|
||||||
PostStatusMessage(JToken.FromObject(new
|
|
||||||
{
|
|
||||||
outputs = matrixDevice.OutputSlots.ToDictionary(kvp => kvp.Key, kvp => new RoutingOutput(kvp.Value))
|
|
||||||
}));
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
foreach (var input in matrixDevice.InputSlots)
|
|
||||||
{
|
|
||||||
var key = input.Key;
|
|
||||||
var inputSlot = input.Value;
|
|
||||||
|
|
||||||
inputSlot.VideoSyncChanged += (sender, args) =>
|
|
||||||
{
|
|
||||||
PostStatusMessage(JToken.FromObject(new
|
|
||||||
{
|
|
||||||
inputs = matrixDevice.InputSlots.ToDictionary(kvp => kvp.Key, kvp => new RoutingInput(kvp.Value))
|
|
||||||
}));
|
|
||||||
};
|
|
||||||
|
|
||||||
inputSlot.IsOnline.OutputChange += (sender, args) =>
|
|
||||||
{
|
|
||||||
PostStatusMessage(JToken.FromObject(new
|
|
||||||
{
|
|
||||||
inputs = matrixDevice.InputSlots.ToDictionary(kvp => kvp.Key, kvp => new RoutingInput(kvp.Value))
|
|
||||||
}));
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void SendFullStatus(string id = null)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
Debug.LogMessage(LogEventLevel.Verbose, "InputCount: {inputCount}, OutputCount: {outputCount}", this, matrixDevice.InputSlots.Count, matrixDevice.OutputSlots.Count);
|
|
||||||
var message = new MatrixStateMessage
|
|
||||||
{
|
|
||||||
Outputs = matrixDevice.OutputSlots.ToDictionary(kvp => kvp.Key, kvp => new RoutingOutput(kvp.Value)),
|
|
||||||
Inputs = matrixDevice.InputSlots.ToDictionary(kvp => kvp.Key, kvp => new RoutingInput(kvp.Value)),
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
PostStatusMessage(message, id);
|
|
||||||
}
|
|
||||||
catch (Exception e)
|
|
||||||
{
|
|
||||||
Debug.LogMessage(e, "Exception Getting full status: {@exception}", this, e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Represents a MatrixStateMessage
|
|
||||||
/// </summary>
|
|
||||||
public class MatrixStateMessage : DeviceStateMessageBase
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Gets or sets the Outputs
|
|
||||||
/// </summary>
|
|
||||||
[JsonProperty("outputs")]
|
|
||||||
public Dictionary<string, RoutingOutput> Outputs;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets or sets the Inputs
|
|
||||||
/// </summary>
|
|
||||||
[JsonProperty("inputs")]
|
|
||||||
public Dictionary<string, RoutingInput> Inputs;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Represents a RoutingInput
|
|
||||||
/// </summary>
|
|
||||||
public class RoutingInput : IKeyName
|
|
||||||
{
|
|
||||||
private IRoutingInputSlot _input;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets the TxDeviceKey of the input slot
|
|
||||||
/// </summary>
|
|
||||||
[JsonProperty("txDeviceKey", NullValueHandling = NullValueHandling.Ignore)]
|
|
||||||
public string TxDeviceKey => _input?.TxDeviceKey;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets the SlotNumber of the input slot
|
|
||||||
///
|
|
||||||
/// </summary>
|
|
||||||
[JsonProperty("slotNumber", NullValueHandling = NullValueHandling.Ignore)]
|
|
||||||
public int? SlotNumber => _input?.SlotNumber;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets the SupportedSignalTypes of the input slot
|
|
||||||
/// </summary>
|
|
||||||
[JsonConverter(typeof(Newtonsoft.Json.Converters.StringEnumConverter))]
|
|
||||||
[JsonProperty("supportedSignalTypes", NullValueHandling = NullValueHandling.Ignore)]
|
|
||||||
public eRoutingSignalType? SupportedSignalTypes => _input?.SupportedSignalTypes;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets the Name of the input slot
|
|
||||||
/// </summary>
|
|
||||||
[JsonProperty("name", NullValueHandling = NullValueHandling.Ignore)]
|
|
||||||
public string Name => _input?.Name;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets the IsOnline of the input slot
|
|
||||||
///
|
|
||||||
/// </summary>
|
|
||||||
[JsonProperty("isOnline", NullValueHandling = NullValueHandling.Ignore)]
|
|
||||||
public bool? IsOnline => _input?.IsOnline.BoolValue;
|
|
||||||
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets the VideoSyncDetected of the input slot
|
|
||||||
/// </summary>
|
|
||||||
[JsonProperty("videoSyncDetected", NullValueHandling = NullValueHandling.Ignore)]
|
|
||||||
public bool? VideoSyncDetected => _input?.VideoSyncDetected;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets the Key of the input slot
|
|
||||||
/// </summary>
|
|
||||||
[JsonProperty("key", NullValueHandling = NullValueHandling.Ignore)]
|
|
||||||
public string Key => _input?.Key;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Initializes a new instance of the <see cref="RoutingInput"/> class.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="input"></param>
|
|
||||||
public RoutingInput(IRoutingInputSlot input)
|
|
||||||
{
|
|
||||||
_input = input;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Represents a RoutingOutput
|
|
||||||
/// </summary>
|
|
||||||
public class RoutingOutput : IKeyName
|
|
||||||
{
|
|
||||||
private IRoutingOutputSlot _output;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Initializes a new instance of the <see cref="RoutingOutput"/> class.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="output"></param>
|
|
||||||
public RoutingOutput(IRoutingOutputSlot output)
|
|
||||||
{
|
|
||||||
_output = output;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets the RxDeviceKey of the output slot
|
|
||||||
/// </summary>
|
|
||||||
[JsonProperty("rxDeviceKey")]
|
|
||||||
public string RxDeviceKey => _output.RxDeviceKey;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets the CurrentRoutes of the output slot
|
|
||||||
/// </summary>
|
|
||||||
[JsonProperty("currentRoutes")]
|
|
||||||
public Dictionary<string, RoutingInput> CurrentRoutes => _output.CurrentRoutes.ToDictionary(kvp => kvp.Key.ToString(), kvp => new RoutingInput(kvp.Value));
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets the SlotNumber of the output slot
|
|
||||||
/// </summary>
|
|
||||||
[JsonProperty("slotNumber")]
|
|
||||||
public int SlotNumber => _output.SlotNumber;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets the SupportedSignalTypes of the output slot
|
|
||||||
/// </summary>
|
|
||||||
[JsonConverter(typeof(Newtonsoft.Json.Converters.StringEnumConverter))]
|
|
||||||
[JsonProperty("supportedSignalTypes")]
|
|
||||||
public eRoutingSignalType SupportedSignalTypes => _output.SupportedSignalTypes;
|
|
||||||
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets the Name of the output slot
|
|
||||||
/// </summary>
|
|
||||||
[JsonProperty("name")]
|
|
||||||
public string Name => _output.Name;
|
|
||||||
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets the Key of the output slot
|
|
||||||
/// </summary>
|
|
||||||
[JsonProperty("key")]
|
|
||||||
public string Key => _output.Key;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Represents a MatrixRouteRequest
|
|
||||||
/// </summary>
|
|
||||||
public class MatrixRouteRequest
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Gets or sets the OutputKey
|
|
||||||
/// </summary>
|
|
||||||
[JsonProperty("outputKey")]
|
|
||||||
public string OutputKey { get; set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets or sets the InputKey
|
|
||||||
/// </summary>
|
|
||||||
[JsonProperty("inputKey")]
|
|
||||||
public string InputKey { get; set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets or sets the RouteType
|
|
||||||
/// </summary>
|
|
||||||
[JsonConverter(typeof(Newtonsoft.Json.Converters.StringEnumConverter))]
|
|
||||||
[JsonProperty("routeType")]
|
|
||||||
public eRoutingSignalType RouteType { get; set; }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -0,0 +1,95 @@
|
||||||
|
using System.Linq;
|
||||||
|
using Newtonsoft.Json;
|
||||||
|
using Newtonsoft.Json.Linq;
|
||||||
|
using PepperDash.Core;
|
||||||
|
using PepperDash.Essentials.Core;
|
||||||
|
using PepperDash.Essentials.Core.Routing;
|
||||||
|
|
||||||
|
namespace PepperDash.Essentials.AppServer.Messengers
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Messenger for devices that implement IRoutingMidpointWithFeedback
|
||||||
|
/// </summary>
|
||||||
|
public class IRoutingMidpointWithFeedbackMessenger : MessengerBase
|
||||||
|
{
|
||||||
|
private readonly IRoutingMidpointWithFeedback _device;
|
||||||
|
|
||||||
|
public IRoutingMidpointWithFeedbackMessenger(string key, string messagePath, IRoutingMidpointWithFeedback device)
|
||||||
|
: base(key, messagePath, device as IKeyName)
|
||||||
|
{
|
||||||
|
_device = device;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void RegisterActions()
|
||||||
|
{
|
||||||
|
base.RegisterActions();
|
||||||
|
|
||||||
|
AddAction("/fullStatus", (id, content) => SendFullStatus(id));
|
||||||
|
|
||||||
|
AddAction("/route", (id, content) =>
|
||||||
|
{
|
||||||
|
var request = content.ToObject<MidpointRouteRequest>();
|
||||||
|
_device.ExecuteSwitch(request.InputSelector, request.OutputSelector, request.SignalType);
|
||||||
|
});
|
||||||
|
|
||||||
|
AddAction("/clearRoute", (id, content) =>
|
||||||
|
{
|
||||||
|
var request = content.ToObject<MidpointClearRouteRequest>();
|
||||||
|
_device.ClearRoute(request.OutputSelector, request.SignalType);
|
||||||
|
});
|
||||||
|
|
||||||
|
_device.RouteChanged += OnRouteChanged;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnRouteChanged(IRoutingMidpointWithFeedback midpoint, RouteSwitchDescriptor newRoute)
|
||||||
|
{
|
||||||
|
PostStatusMessage(JToken.FromObject(new
|
||||||
|
{
|
||||||
|
currentRoutes = _device.CurrentRoutes.Select(r => new
|
||||||
|
{
|
||||||
|
inputPort = r.InputPort?.Key,
|
||||||
|
outputPort = r.OutputPort?.Key
|
||||||
|
})
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
|
private void SendFullStatus(string id = null)
|
||||||
|
{
|
||||||
|
var message = JToken.FromObject(new
|
||||||
|
{
|
||||||
|
inputPorts = _device.InputPorts.Select(p => new { key = p.Key }),
|
||||||
|
outputPorts = _device.OutputPorts.Select(p => new { key = p.Key }),
|
||||||
|
currentRoutes = _device.CurrentRoutes.Select(r => new
|
||||||
|
{
|
||||||
|
inputPort = r.InputPort?.Key,
|
||||||
|
outputPort = r.OutputPort?.Key
|
||||||
|
})
|
||||||
|
});
|
||||||
|
|
||||||
|
PostStatusMessage(message, id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public class MidpointRouteRequest
|
||||||
|
{
|
||||||
|
[JsonProperty("inputSelector")]
|
||||||
|
public object InputSelector { get; set; }
|
||||||
|
|
||||||
|
[JsonProperty("outputSelector")]
|
||||||
|
public object OutputSelector { get; set; }
|
||||||
|
|
||||||
|
[JsonConverter(typeof(Newtonsoft.Json.Converters.StringEnumConverter))]
|
||||||
|
[JsonProperty("signalType")]
|
||||||
|
public eRoutingSignalType SignalType { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public class MidpointClearRouteRequest
|
||||||
|
{
|
||||||
|
[JsonProperty("outputSelector")]
|
||||||
|
public object OutputSelector { get; set; }
|
||||||
|
|
||||||
|
[JsonConverter(typeof(Newtonsoft.Json.Converters.StringEnumConverter))]
|
||||||
|
[JsonProperty("signalType")]
|
||||||
|
public eRoutingSignalType SignalType { get; set; }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -116,9 +116,9 @@ namespace PepperDash.Essentials
|
||||||
|
|
||||||
// ── Displays ─────────────────────────────────────────────────────────────
|
// ── Displays ─────────────────────────────────────────────────────────────
|
||||||
new MessengerFactoryEntry(
|
new MessengerFactoryEntry(
|
||||||
typeof(IRoutingSinkWithSwitching),
|
typeof(IRoutingSinkWithFeedback),
|
||||||
(d, mp, ck) => new IRoutingSinkWithSwitchingMessenger(
|
(d, mp, ck) => new IRoutingSinkWithFeedbackMessenger(
|
||||||
$"{d.Key}-displayBase-{ck}", mp, (IRoutingSinkWithSwitching)d)
|
$"{d.Key}-displayBase-{ck}", mp, (IRoutingSinkWithFeedback)d)
|
||||||
),
|
),
|
||||||
new MessengerFactoryEntry(
|
new MessengerFactoryEntry(
|
||||||
typeof(IDisplayCurrentInput),
|
typeof(IDisplayCurrentInput),
|
||||||
|
|
@ -337,9 +337,9 @@ namespace PepperDash.Essentials
|
||||||
// ── Matrix routing ────────────────────────────────────────────────────────
|
// ── Matrix routing ────────────────────────────────────────────────────────
|
||||||
// Preserving original key format (no controller key suffix)
|
// Preserving original key format (no controller key suffix)
|
||||||
new MessengerFactoryEntry(
|
new MessengerFactoryEntry(
|
||||||
typeof(IMatrixRouting),
|
typeof(IRoutingMidpointWithFeedback),
|
||||||
(d, mp, _) => new IMatrixRoutingMessenger(
|
(d, mp, _) => new IRoutingMidpointWithFeedbackMessenger(
|
||||||
$"{d.Key}-matrixRouting", mp, (IMatrixRouting)d)
|
$"{d.Key}-matrixRouting", mp, (IRoutingMidpointWithFeedback)d)
|
||||||
),
|
),
|
||||||
|
|
||||||
// ── Environmental sensors ─────────────────────────────────────────────────
|
// ── Environmental sensors ─────────────────────────────────────────────────
|
||||||
|
|
|
||||||
|
|
@ -140,9 +140,6 @@ namespace PepperDash.Essentials.RoomBridges
|
||||||
if (Room is IRunDefaultPresentRoute defaultRoom)
|
if (Room is IRunDefaultPresentRoute defaultRoom)
|
||||||
AddAction("/defaultsource", (id, content) => defaultRoom.RunDefaultPresentRoute());
|
AddAction("/defaultsource", (id, content) => defaultRoom.RunDefaultPresentRoute());
|
||||||
|
|
||||||
if (Room is IHasCurrentSourceInfoChange sscRoom)
|
|
||||||
sscRoom.CurrentSourceChange += Room_CurrentSingleSourceChange;
|
|
||||||
|
|
||||||
|
|
||||||
if (Room is IPrivacy privacyRoom)
|
if (Room is IPrivacy privacyRoom)
|
||||||
{
|
{
|
||||||
|
|
@ -353,9 +350,9 @@ namespace PepperDash.Essentials.RoomBridges
|
||||||
string shareText;
|
string shareText;
|
||||||
bool isSharing;
|
bool isSharing;
|
||||||
|
|
||||||
if (Room is IHasCurrentSourceInfoChange srcInfoRoom && Room is IHasVideoCodec vcRoom && vcRoom.VideoCodec.SharingContentIsOnFeedback.BoolValue && srcInfoRoom.CurrentSourceInfo != null)
|
if (Room is IHasVideoCodec vcRoom && vcRoom.VideoCodec.SharingContentIsOnFeedback.BoolValue)
|
||||||
{
|
{
|
||||||
shareText = srcInfoRoom.CurrentSourceInfo.PreferredName;
|
shareText = "Sharing";
|
||||||
isSharing = true;
|
isSharing = true;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
|
@ -470,18 +467,7 @@ namespace PepperDash.Essentials.RoomBridges
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private void Room_CurrentSingleSourceChange(SourceListItem info, ChangeType type)
|
|
||||||
{
|
|
||||||
/* Example message
|
|
||||||
* {
|
|
||||||
"type":"/room/status",
|
|
||||||
"content": {
|
|
||||||
"selectedSourceKey": "off",
|
|
||||||
}
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Sends the full status of the room to the server
|
/// Sends the full status of the room to the server
|
||||||
|
|
@ -512,7 +498,7 @@ namespace PepperDash.Essentials.RoomBridges
|
||||||
{
|
{
|
||||||
this.LogVerbose("GetFullStatus");
|
this.LogVerbose("GetFullStatus");
|
||||||
|
|
||||||
var sourceKey = room is IHasCurrentSourceInfoChange ? (room as IHasCurrentSourceInfoChange).CurrentSourceInfoKey : null;
|
var sourceKey = (string)null;
|
||||||
|
|
||||||
var volumes = new Dictionary<string, Volume>();
|
var volumes = new Dictionary<string, Volume>();
|
||||||
if (room is IHasCurrentVolumeControls rmVc)
|
if (room is IHasCurrentVolumeControls rmVc)
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue