Merge pull request #1368 from PepperDash/generic-sink

generic sink
This commit is contained in:
Andrew Welker
2025-12-16 11:09:40 -05:00
committed by GitHub
3 changed files with 82 additions and 20 deletions

View File

@@ -1,11 +1,11 @@
using Crestron.SimplSharpPro.Keypads; using System;
using PepperDash.Essentials.Core.Queues;
using PepperDash.Essentials.Core.Routing;
using Serilog.Events;
using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Diagnostics; using System.Diagnostics;
using System.Linq; using System.Linq;
using Crestron.SimplSharpPro.Keypads;
using PepperDash.Essentials.Core.Queues;
using PepperDash.Essentials.Core.Routing;
using Serilog.Events;
using Debug = PepperDash.Core.Debug; using Debug = PepperDash.Core.Debug;
@@ -115,7 +115,7 @@ namespace PepperDash.Essentials.Core
public static (RouteDescriptor, RouteDescriptor) GetRouteToSource(this IRoutingInputs destination, IRoutingOutputs source, eRoutingSignalType signalType, RoutingInputPort destinationPort, RoutingOutputPort sourcePort) public static (RouteDescriptor, RouteDescriptor) GetRouteToSource(this IRoutingInputs destination, IRoutingOutputs source, eRoutingSignalType signalType, RoutingInputPort destinationPort, RoutingOutputPort sourcePort)
{ {
// if it's a single signal type, find the route // if it's a single signal type, find the route
if (!signalType.HasFlag(eRoutingSignalType.AudioVideo) && if (!signalType.HasFlag(eRoutingSignalType.AudioVideo) &&
!(signalType.HasFlag(eRoutingSignalType.Video) && signalType.HasFlag(eRoutingSignalType.SecondaryAudio))) !(signalType.HasFlag(eRoutingSignalType.Video) && signalType.HasFlag(eRoutingSignalType.SecondaryAudio)))
{ {
var singleTypeRouteDescriptor = new RouteDescriptor(source, destination, destinationPort, signalType); var singleTypeRouteDescriptor = new RouteDescriptor(source, destination, destinationPort, signalType);
@@ -134,14 +134,15 @@ namespace PepperDash.Essentials.Core
} }
// otherwise, audioVideo needs to be handled as two steps. // otherwise, audioVideo needs to be handled as two steps.
Debug.LogMessage(LogEventLevel.Debug, "Attempting to build source route from {sourceKey} of type {type}", destination, source.Key); Debug.LogMessage(LogEventLevel.Debug, "Attempting to build source route from {destinationKey} to {sourceKey} of type {type}", destination, source.Key, signalType);
RouteDescriptor audioRouteDescriptor; RouteDescriptor audioRouteDescriptor;
if (signalType.HasFlag(eRoutingSignalType.SecondaryAudio)) if (signalType.HasFlag(eRoutingSignalType.SecondaryAudio))
{ {
audioRouteDescriptor = new RouteDescriptor(source, destination, destinationPort, eRoutingSignalType.SecondaryAudio); audioRouteDescriptor = new RouteDescriptor(source, destination, destinationPort, eRoutingSignalType.SecondaryAudio);
} else }
else
{ {
audioRouteDescriptor = new RouteDescriptor(source, destination, destinationPort, eRoutingSignalType.Audio); audioRouteDescriptor = new RouteDescriptor(source, destination, destinationPort, eRoutingSignalType.Audio);
} }
@@ -199,13 +200,13 @@ namespace PepperDash.Essentials.Core
Source = source, Source = source,
SourcePort = sourcePort, SourcePort = sourcePort,
SignalType = signalType SignalType = signalType
}; };
var coolingDevice = destination as IWarmingCooling; var coolingDevice = destination as IWarmingCooling;
//We already have a route request for this device, and it's a cooling device and is cooling //We already have a route request for this device, and it's a cooling device and is cooling
if (RouteRequests.TryGetValue(destination.Key, out RouteRequest existingRouteRequest) && coolingDevice != null && coolingDevice.IsCoolingDownFeedback.BoolValue == true) if (RouteRequests.TryGetValue(destination.Key, out RouteRequest existingRouteRequest) && coolingDevice != null && coolingDevice.IsCoolingDownFeedback.BoolValue == true)
{ {
coolingDevice.IsCoolingDownFeedback.OutputChange -= existingRouteRequest.HandleCooldown; coolingDevice.IsCoolingDownFeedback.OutputChange -= existingRouteRequest.HandleCooldown;
coolingDevice.IsCoolingDownFeedback.OutputChange += routeRequest.HandleCooldown; coolingDevice.IsCoolingDownFeedback.OutputChange += routeRequest.HandleCooldown;
@@ -219,7 +220,7 @@ namespace PepperDash.Essentials.Core
//New Request //New Request
if (coolingDevice != null && coolingDevice.IsCoolingDownFeedback.BoolValue == true) if (coolingDevice != null && coolingDevice.IsCoolingDownFeedback.BoolValue == true)
{ {
coolingDevice.IsCoolingDownFeedback.OutputChange += routeRequest.HandleCooldown; coolingDevice.IsCoolingDownFeedback.OutputChange += routeRequest.HandleCooldown;
RouteRequests.Add(destination.Key, routeRequest); RouteRequests.Add(destination.Key, routeRequest);
@@ -239,9 +240,9 @@ namespace PepperDash.Essentials.Core
Debug.LogMessage(LogEventLevel.Information, "Device: {destination} is NOT cooling down. Removing stored route request and routing to source key: {sourceKey}", null, destination.Key, routeRequest.Source.Key); Debug.LogMessage(LogEventLevel.Information, "Device: {destination} is NOT cooling down. Removing stored route request and routing to source key: {sourceKey}", null, destination.Key, routeRequest.Source.Key);
} }
routeRequestQueue.Enqueue(new ReleaseRouteQueueItem(ReleaseRouteInternal, destination,destinationPort?.Key ?? string.Empty, false)); routeRequestQueue.Enqueue(new ReleaseRouteQueueItem(ReleaseRouteInternal, destination, destinationPort?.Key ?? string.Empty, false));
routeRequestQueue.Enqueue(new RouteRequestQueueItem(RunRouteRequest, routeRequest)); routeRequestQueue.Enqueue(new RouteRequestQueueItem(RunRouteRequest, routeRequest));
} }
/// <summary> /// <summary>
@@ -272,7 +273,8 @@ namespace PepperDash.Essentials.Core
audioOrSingleRoute.ExecuteRoutes(); audioOrSingleRoute.ExecuteRoutes();
videoRoute?.ExecuteRoutes(); videoRoute?.ExecuteRoutes();
} catch(Exception ex) }
catch (Exception ex)
{ {
Debug.LogMessage(ex, "Exception Running Route Request {request}", null, request); Debug.LogMessage(ex, "Exception Running Route Request {request}", null, request);
} }
@@ -305,9 +307,10 @@ namespace PepperDash.Essentials.Core
Debug.LogMessage(LogEventLevel.Information, "Releasing current route: {0}", destination, current.Source.Key); Debug.LogMessage(LogEventLevel.Information, "Releasing current route: {0}", destination, current.Source.Key);
current.ReleaseRoutes(clearRoute); current.ReleaseRoutes(clearRoute);
} }
} catch (Exception ex) }
catch (Exception ex)
{ {
Debug.LogMessage(ex, "Exception releasing route for '{destination}':'{inputPortKey}'",null, destination?.Key ?? null, string.IsNullOrEmpty(inputPortKey) ? "auto" : inputPortKey); Debug.LogMessage(ex, "Exception releasing route for '{destination}':'{inputPortKey}'", null, destination?.Key ?? null, string.IsNullOrEmpty(inputPortKey) ? "auto" : inputPortKey);
} }
} }

View File

@@ -1,8 +1,10 @@
using System.Collections.Generic; using System;
using System.Collections.Generic;
using PepperDash.Core; using PepperDash.Core;
using PepperDash.Core.Logging; using PepperDash.Core.Logging;
using PepperDash.Essentials.Core; using PepperDash.Essentials.Core;
using PepperDash.Essentials.Core.Config; using PepperDash.Essentials.Core.Config;
using PepperDash.Essentials.Core.Routing;
using Serilog.Events; using Serilog.Events;
namespace PepperDash.Essentials.Devices.Common.Generic namespace PepperDash.Essentials.Devices.Common.Generic
@@ -10,8 +12,17 @@ namespace PepperDash.Essentials.Devices.Common.Generic
/// <summary> /// <summary>
/// Represents a GenericSink /// Represents a GenericSink
/// </summary> /// </summary>
public class GenericSink : EssentialsDevice, IRoutingSinkWithSwitchingWithInputPort public class GenericSink : EssentialsDevice, IRoutingSinkWithSwitchingWithInputPort, ICurrentSources
{ {
/// <inheritdoc/>
public Dictionary<eRoutingSignalType, SourceListItem> CurrentSources { get; private set; }
/// <inheritdoc/>
public Dictionary<eRoutingSignalType, string> CurrentSourceKeys { get; private set; }
/// <inheritdoc />
public event EventHandler CurrentSourcesChanged;
/// <summary> /// <summary>
/// Initializes a new instance of the GenericSink class /// Initializes a new instance of the GenericSink class
/// </summary> /// </summary>
@@ -24,6 +35,49 @@ namespace PepperDash.Essentials.Devices.Common.Generic
var inputPort = new RoutingInputPort(RoutingPortNames.AnyVideoIn, eRoutingSignalType.AudioVideo | eRoutingSignalType.SecondaryAudio, eRoutingPortConnectionType.Hdmi, null, this); var inputPort = new RoutingInputPort(RoutingPortNames.AnyVideoIn, eRoutingSignalType.AudioVideo | eRoutingSignalType.SecondaryAudio, eRoutingPortConnectionType.Hdmi, null, this);
InputPorts.Add(inputPort); InputPorts.Add(inputPort);
CurrentSources = new Dictionary<eRoutingSignalType, SourceListItem>
{
{ eRoutingSignalType.Audio, null },
{ eRoutingSignalType.Video, null },
};
CurrentSourceKeys = new Dictionary<eRoutingSignalType, string>
{
{ eRoutingSignalType.Audio, string.Empty },
{ eRoutingSignalType.Video, string.Empty },
};
}
/// <inheritdoc />
public void SetCurrentSource(eRoutingSignalType signalType, string sourceListKey, SourceListItem sourceListItem)
{
foreach (eRoutingSignalType type in Enum.GetValues(typeof(eRoutingSignalType)))
{
var flagValue = Convert.ToInt32(type);
// Skip if flagValue is 0 or not a power of two (i.e., not a single-bit flag).
// (flagValue & (flagValue - 1)) != 0 checks if more than one bit is set.
if (flagValue == 0 || (flagValue & (flagValue - 1)) != 0)
{
this.LogDebug("Skipping {type}", type);
continue;
}
this.LogDebug("setting {type}", type);
if (signalType.HasFlag(type))
{
UpdateCurrentSources(type, sourceListKey, sourceListItem);
}
}
// Raise the CurrentSourcesChanged event
CurrentSourcesChanged?.Invoke(this, EventArgs.Empty);
}
private void UpdateCurrentSources(eRoutingSignalType signalType, string sourceListKey, SourceListItem sourceListItem)
{
CurrentSources[signalType] = sourceListItem;
CurrentSourceKeys[signalType] = sourceListKey;
} }
/// <summary> /// <summary>

View File

@@ -1,4 +1,5 @@
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq;
using Newtonsoft.Json; using Newtonsoft.Json;
using Newtonsoft.Json.Converters; using Newtonsoft.Json.Converters;
using Newtonsoft.Json.Linq; using Newtonsoft.Json.Linq;
@@ -39,10 +40,14 @@ namespace PepperDash.Essentials.AppServer.Messengers
sourceDevice.CurrentSourcesChanged += (sender, e) => sourceDevice.CurrentSourcesChanged += (sender, e) =>
{ {
// need to copy the dictionaries to avoid enumeration issues
var currentSourceKeys = sourceDevice.CurrentSourceKeys.ToDictionary(kvp => kvp.Key, kvp => kvp.Value);
var currentSources = sourceDevice.CurrentSources.ToDictionary(kvp => kvp.Key, kvp => kvp.Value);
PostStatusMessage(JToken.FromObject(new PostStatusMessage(JToken.FromObject(new
{ {
currentSourceKeys = sourceDevice.CurrentSourceKeys, currentSourceKeys,
currentSources = sourceDevice.CurrentSources currentSources,
})); }));
}; };
} }