using System; using System.Collections.Generic; using System.Linq; using System.Text; using Crestron.SimplSharp; using Crestron.SimplSharpPro; using Crestron.SimplSharpPro.DM; using Crestron.SimplSharpPro.DM.Cards; using Crestron.SimplSharpPro.DM.Endpoints; using Crestron.SimplSharpPro.DM.Endpoints.Receivers; using PepperDash.Core; using PepperDash.Essentials.Core; using PepperDash.Essentials.DM.Config; namespace PepperDash.Essentials.DM { public class DmpsRoutingController : Device, IRoutingInputsOutputs, IRouting, IHasFeedback { public CrestronControlSystem Dmps { get; set; } public ISystemControl SystemControl { get; private set; } // Feedbacks for EssentialDM public Dictionary VideoOutputFeedbacks { get; private set; } public Dictionary AudioOutputFeedbacks { get; private set; } public Dictionary VideoInputSyncFeedbacks { get; private set; } public Dictionary InputEndpointOnlineFeedbacks { get; private set; } public Dictionary OutputEndpointOnlineFeedbacks { get; private set; } public Dictionary InputNameFeedbacks { get; private set; } public Dictionary OutputNameFeedbacks { get; private set; } public Dictionary OutputVideoRouteNameFeedbacks { get; private set; } public Dictionary OutputAudioRouteNameFeedbacks { get; private set; } public FeedbackCollection Feedbacks { get; private set; } // Need a couple Lists of generic Backplane ports public RoutingPortCollection InputPorts { get; private set; } public RoutingPortCollection OutputPorts { get; private set; } public Dictionary TxDictionary { get; set; } public Dictionary RxDictionary { get; set; } public Dictionary InputNames { get; set; } public Dictionary OutputNames { get; set; } public Dictionary VolumeControls { get; private set; } public const int RouteOffTime = 500; Dictionary RouteOffTimers = new Dictionary(); public static DmpsRoutingController GetDmpsRoutingController(string key, string name, DmpsRoutingPropertiesConfig properties) { try { ISystemControl systemControl = null; systemControl = Global.ControlSystem.SystemControl as ISystemControl; if (systemControl == null) { return null; } var controller = new DmpsRoutingController(key, name, systemControl); controller.InputNames = properties.InputNames; controller.OutputNames = properties.OutputNames; return controller; } catch (System.Exception e) { Debug.Console(0, "Error getting DMPS Controller:\r{0}", e); } return null; } /// /// /// /// /// /// public DmpsRoutingController(string key, string name, ISystemControl systemControl) : base(key, name) { Dmps = Global.ControlSystem; SystemControl = systemControl; InputPorts = new RoutingPortCollection(); OutputPorts = new RoutingPortCollection(); VolumeControls = new Dictionary(); TxDictionary = new Dictionary(); RxDictionary = new Dictionary(); VideoOutputFeedbacks = new Dictionary(); AudioOutputFeedbacks = new Dictionary(); VideoInputSyncFeedbacks = new Dictionary(); InputNameFeedbacks = new Dictionary(); OutputNameFeedbacks = new Dictionary(); OutputVideoRouteNameFeedbacks = new Dictionary(); OutputAudioRouteNameFeedbacks = new Dictionary(); InputEndpointOnlineFeedbacks = new Dictionary(); OutputEndpointOnlineFeedbacks = new Dictionary(); Debug.Console(1, this, "{0} Switcher Inputs Present.", Dmps.SwitcherInputs.Count); Debug.Console(1, this, "{0} Switcher Outputs Present.", Dmps.SwitcherOutputs.Count); SetupOutputCards(); SetupInputCards(); } public override bool CustomActivate() { // Set input and output names from config if (InputNames != null) foreach (var kvp in InputNames) (Dmps.SwitcherInputs[kvp.Key] as DMInput).Name.StringValue = kvp.Value; if (OutputNames != null) foreach (var kvp in OutputNames) (Dmps.SwitcherOutputs[kvp.Key] as Card.Dmps3OutputBase).Name.StringValue = kvp.Value; // Subscribe to events Dmps.DMInputChange += new DMInputEventHandler(Dmps_DMInputChange); Dmps.DMOutputChange += new DMOutputEventHandler(Dmps_DMOutputChange); return base.CustomActivate(); } /// /// Iterate the SwitcherOutputs collection to setup feedbacks and add routing ports /// void SetupOutputCards() { foreach (var card in Dmps.SwitcherOutputs) { var outputCard = card as DMOutput; Debug.Console(1, this, "Adding Output Card Number {0} Type: {1}", outputCard.Number, outputCard.CardInputOutputType.ToString()); if (outputCard != null) { VideoOutputFeedbacks[outputCard.Number] = new IntFeedback(() => { if (outputCard.VideoOutFeedback != null) { return (ushort)outputCard.VideoOutFeedback.Number; } else { return 0; }; }); AudioOutputFeedbacks[outputCard.Number] = new IntFeedback(() => { if (outputCard.AudioOutFeedback != null) { return (ushort)outputCard.AudioOutFeedback.Number; } else { return 0; }; }); OutputNameFeedbacks[outputCard.Number] = new StringFeedback(() => { if (outputCard.NameFeedback != null && !string.IsNullOrEmpty(outputCard.NameFeedback.StringValue)) { Debug.Console(2, this, "Output Card {0} Name: {1}", outputCard.Number, outputCard.NameFeedback.StringValue); return outputCard.NameFeedback.StringValue; } else { return ""; } }); OutputVideoRouteNameFeedbacks[outputCard.Number] = new StringFeedback(() => { if (outputCard.VideoOutFeedback != null && outputCard.VideoOutFeedback.NameFeedback != null) { return outputCard.VideoOutFeedback.NameFeedback.StringValue; } else { return ""; } }); OutputAudioRouteNameFeedbacks[outputCard.Number] = new StringFeedback(() => { if (outputCard.AudioOutFeedback != null && outputCard.AudioOutFeedback.NameFeedback != null) { return outputCard.AudioOutFeedback.NameFeedback.StringValue; } else { return ""; } }); OutputEndpointOnlineFeedbacks[outputCard.Number] = new BoolFeedback(() => { return outputCard.EndpointOnlineFeedback; }); AddOutputCard(outputCard.Number, outputCard); } } } /// /// Iterate the SwitcherInputs collection to setup feedbacks and add routing ports /// void SetupInputCards() { foreach (var card in Dmps.SwitcherInputs) { var inputCard = card as DMInput; if (inputCard != null) { Debug.Console(1, this, "Adding Input Card Number {0} Type: {1}", inputCard.Number, inputCard.CardInputOutputType.ToString()); InputEndpointOnlineFeedbacks[inputCard.Number] = new BoolFeedback(() => { return inputCard.EndpointOnlineFeedback; }); if (inputCard.VideoDetectedFeedback != null) { VideoInputSyncFeedbacks[inputCard.Number] = new BoolFeedback(() => { return inputCard.VideoDetectedFeedback.BoolValue; }); } InputNameFeedbacks[inputCard.Number] = new StringFeedback(() => { if (inputCard.NameFeedback != null && !string.IsNullOrEmpty(inputCard.NameFeedback.StringValue)) { Debug.Console(2, this, "Input Card {0} Name: {1}", inputCard.Number, inputCard.NameFeedback.StringValue); return inputCard.NameFeedback.StringValue; } else { Debug.Console(2, this, "Input Card {0} Name is null", inputCard.Number); return ""; } }); AddInputCard(inputCard.Number, inputCard); } else { Debug.Console(2, this, "***********Input Card of type {0} is cannot be cast as DMInput*************", card.CardInputOutputType); } } } /// /// Builds the appropriate ports aand callst the appropreate add port method /// /// /// public void AddInputCard(uint number, DMInput inputCard) { if (inputCard is Card.Dmps3HdmiInputWithoutAnalogAudio) { var hdmiInputCard = inputCard as Card.Dmps3HdmiInput; var cecPort = hdmiInputCard.HdmiInputPort; AddInputPortWithDebug(number, string.Format("HdmiIn{0}", number), eRoutingSignalType.Audio | eRoutingSignalType.Video, eRoutingPortConnectionType.Hdmi, cecPort); } else if (inputCard is Card.Dmps3HdmiInput) { var hdmiInputCard = inputCard as Card.Dmps3HdmiInput; var cecPort = hdmiInputCard.HdmiInputPort; AddInputPortWithDebug(number, string.Format("HdmiIn{0}", number), eRoutingSignalType.Audio | eRoutingSignalType.Video, eRoutingPortConnectionType.Hdmi, cecPort); AddInputPortWithDebug(number, string.Format("HudioIn{1}", number), eRoutingSignalType.Audio, eRoutingPortConnectionType.LineAudio); } else if (inputCard is Card.Dmps3HdmiVgaInput) { // TODO: Build a virtual TX device and assign the ports to it var hdmiVgaInputCard = inputCard as Card.Dmps3HdmiVgaInput; DmpsInternalVirtualHdmiVgaInputController inputCardController = new DmpsInternalVirtualHdmiVgaInputController(Key + string.Format("-HdmiVgaIn{0}", number), string.Format("InternalInputController-{0}", number), hdmiVgaInputCard); DeviceManager.AddDevice(inputCardController); AddInputPortWithDebug(number, string.Format("HdmiVgaIn{0}", number), eRoutingSignalType.Audio | eRoutingSignalType.Video, eRoutingPortConnectionType.BackplaneOnly); } else if (inputCard is Card.Dmps3HdmiVgaBncInput) { // TODO: Build a virtual TX device and assign the ports to it var hdmiVgaBncInputCard = inputCard as Card.Dmps3HdmiVgaBncInput; DmpsInternalVirtualHdmiVgaBncInputController inputCardController = new DmpsInternalVirtualHdmiVgaBncInputController(Key + string.Format("-HdmiVgaBncIn{0}", number), string.Format("InternalInputController-{0}", number), hdmiVgaBncInputCard); DeviceManager.AddDevice(inputCardController); AddInputPortWithDebug(number, string.Format("HdmiVgaBncIn{0}", number), eRoutingSignalType.Audio | eRoutingSignalType.Video, eRoutingPortConnectionType.BackplaneOnly); } else if (inputCard is Card.Dmps3DmInput) { var hdmiInputCard = inputCard as Card.Dmps3DmInput; var cecPort = hdmiInputCard.DmInputPort; AddInputPortWithDebug(number, string.Format("DmIn{0}", number), eRoutingSignalType.Audio | eRoutingSignalType.Video, eRoutingPortConnectionType.DmCat, cecPort); } else if (inputCard is Card.Dmps3AirMediaInput) { var airMediaInputCard = inputCard as Card.Dmps3AirMediaInput; AddInputPortWithDebug(number, string.Format("AirMediaIn{0}", number), eRoutingSignalType.Audio | eRoutingSignalType.Video, eRoutingPortConnectionType.Streaming); } } /// /// Adds InputPort /// void AddInputPortWithDebug(uint cardNum, string portName, eRoutingSignalType sigType, eRoutingPortConnectionType portType) { var portKey = string.Format("inputCard{0}--{1}", cardNum, portName); Debug.Console(2, this, "Adding input port '{0}'", portKey); var inputPort = new RoutingInputPort(portKey, sigType, portType, cardNum, this); InputPorts.Add(inputPort); } /// /// Adds InputPort and sets Port as ICec object /// void AddInputPortWithDebug(uint cardNum, string portName, eRoutingSignalType sigType, eRoutingPortConnectionType portType, ICec cecPort) { var portKey = string.Format("inputCard{0}--{1}", cardNum, portName); Debug.Console(2, this, "Adding input port '{0}'", portKey); var inputPort = new RoutingInputPort(portKey, sigType, portType, cardNum, this); if (cecPort != null) inputPort.Port = cecPort; InputPorts.Add(inputPort); } /// /// Builds the appropriate ports and calls the appropriate add port method /// /// /// public void AddOutputCard(uint number, DMOutput outputCard) { if (outputCard is Card.Dmps3HdmiOutput) { var hdmiOutputCard = outputCard as Card.Dmps3HdmiOutput; var cecPort = hdmiOutputCard.HdmiOutputPort; AddHdmiOutputPort(number, cecPort); return; } else if (outputCard is Card.Dmps3DmOutput) { var dmOutputCard = outputCard as Card.Dmps3DmOutput; var cecPort = dmOutputCard.DmOutputPort; AddDmOutputPort(number); return; } else if (outputCard is Card.Dmps3ProgramOutput) { AddAudioOnlyOutputPort(number, "Program"); var programOutput = new DmpsAudioOutputController(string.Format("processor-programAudioOutput"), "Program Audio Output", outputCard as Card.Dmps3OutputBase); DeviceManager.AddDevice(programOutput); return; } else if (outputCard is Card.Dmps3AuxOutput) { if (outputCard.CardInputOutputType == eCardInputOutputType.Dmps3Aux1Output) { AddAudioOnlyOutputPort(number, "Aux1"); var aux1Output = new DmpsAudioOutputController(string.Format("processor-aux1AudioOutput"), "Program Audio Output", outputCard as Card.Dmps3OutputBase); DeviceManager.AddDevice(aux1Output); } else if (outputCard.CardInputOutputType == eCardInputOutputType.Dmps3Aux2Output) { AddAudioOnlyOutputPort(number, "Aux2"); var aux2Output = new DmpsAudioOutputController(string.Format("processor-aux2AudioOutput"), "Program Audio Output", outputCard as Card.Dmps3OutputBase); DeviceManager.AddDevice(aux2Output); } return; } else if (outputCard is Card.Dmps3CodecOutput) { if (number == (uint)CrestronControlSystem.eDmps300cOutputs.Codec1 || number == (uint)CrestronControlSystem.eDmps3200cOutputs.Codec1 || number == (uint)CrestronControlSystem.eDmps3300cAecOutputs.Codec1 || number == (uint)CrestronControlSystem.eDmps34K250COutputs.Codec1 || number == (uint)CrestronControlSystem.eDmps34K350COutputs.Codec1) AddAudioOnlyOutputPort(number, CrestronControlSystem.eDmps300cOutputs.Codec1.ToString()); else if (number == (uint)CrestronControlSystem.eDmps300cOutputs.Codec2 || number == (uint)CrestronControlSystem.eDmps3200cOutputs.Codec2 || number == (uint)CrestronControlSystem.eDmps3300cAecOutputs.Codec2 || number == (uint)CrestronControlSystem.eDmps34K250COutputs.Codec2 || number == (uint)CrestronControlSystem.eDmps34K350COutputs.Codec2) AddAudioOnlyOutputPort(number, CrestronControlSystem.eDmps300cOutputs.Codec2.ToString()); return; } else if (outputCard is Card.Dmps3DialerOutput) { AddAudioOnlyOutputPort(number, "Dialer"); return; } else if (outputCard is Card.Dmps3DigitalMixOutput) { if (number == (uint)CrestronControlSystem.eDmps34K250COutputs.Mix1 || number == (uint)CrestronControlSystem.eDmps34K300COutputs.Mix1 || number == (uint)CrestronControlSystem.eDmps34K350COutputs.Mix1) AddAudioOnlyOutputPort(number, CrestronControlSystem.eDmps34K250COutputs.Mix1.ToString()); if (number == (uint)CrestronControlSystem.eDmps34K250COutputs.Mix2 || number == (uint)CrestronControlSystem.eDmps34K300COutputs.Mix2 || number == (uint)CrestronControlSystem.eDmps34K350COutputs.Mix2) AddAudioOnlyOutputPort(number, CrestronControlSystem.eDmps34K250COutputs.Mix2.ToString()); return; } else if (outputCard is Card.Dmps3AecOutput) { AddAudioOnlyOutputPort(number, "Aec"); return; } else { Debug.Console(1, this, "Output Card is of a type not currently handled:", outputCard.CardInputOutputType.ToString()); } } /// /// Adds an Audio only output port /// /// void AddAudioOnlyOutputPort(uint number, string portName) { AddOutputPortWithDebug(number, portName, eRoutingSignalType.Audio, eRoutingPortConnectionType.LineAudio, number); } /// /// Adds an HDMI output port /// /// /// void AddHdmiOutputPort(uint number, ICec cecPort) { AddOutputPortWithDebug(number, string.Format("hdmiOut{0}", number), eRoutingSignalType.Audio | eRoutingSignalType.Video, eRoutingPortConnectionType.Hdmi, number, cecPort); } /// /// Adds a DM output port /// /// void AddDmOutputPort(uint number) { AddOutputPortWithDebug(number, string.Format("dmOut{0}", number), eRoutingSignalType.Audio | eRoutingSignalType.Video, eRoutingPortConnectionType.DmCat, number); } /// /// Adds OutputPort /// void AddOutputPortWithDebug(uint cardNum, string portName, eRoutingSignalType sigType, eRoutingPortConnectionType portType, object selector) { var portKey = string.Format("outputCard{0}--{1}", cardNum, portName); Debug.Console(2, this, "Adding output port '{0}'", portKey); OutputPorts.Add(new RoutingOutputPort(portKey, sigType, portType, selector, this)); } /// /// Adds OutputPort and sets Port as ICec object /// void AddOutputPortWithDebug(uint cardNum, string portName, eRoutingSignalType sigType, eRoutingPortConnectionType portType, object selector, ICec cecPort) { var portKey = string.Format("outputCard{0}--{1}", cardNum, portName); Debug.Console(2, this, "Adding output port '{0}'", portKey); var outputPort = new RoutingOutputPort(portKey, sigType, portType, selector, this); if (cecPort != null) outputPort.Port = cecPort; OutputPorts.Add(outputPort); } /// /// /// void AddVolumeControl(uint number, Audio.Output audio) { VolumeControls.Add(number, new DmCardAudioOutputController(audio)); } void Dmps_DMInputChange(Switch device, DMInputEventArgs args) { //Debug.Console(2, this, "DMSwitch:{0} Input:{1} Event:{2}'", this.Name, args.Number, args.EventId.ToString()); switch (args.EventId) { case (DMInputEventIds.OnlineFeedbackEventId): { Debug.Console(2, this, "DM Input OnlineFeedbackEventId for input: {0}. State: {1}", args.Number, device.Inputs[args.Number].EndpointOnlineFeedback); InputEndpointOnlineFeedbacks[args.Number].FireUpdate(); break; } case (DMInputEventIds.VideoDetectedEventId): { Debug.Console(2, this, "DM Input {0} VideoDetectedEventId", args.Number); VideoInputSyncFeedbacks[args.Number].FireUpdate(); break; } case (DMInputEventIds.InputNameEventId): { Debug.Console(2, this, "DM Input {0} NameFeedbackEventId", args.Number); InputNameFeedbacks[args.Number].FireUpdate(); break; } } } /// /// void Dmps_DMOutputChange(Switch device, DMOutputEventArgs args) { Debug.Console(2, this, "DMOutputChange Output: {0} EventId: {1}", args.Number, args.EventId.ToString()); var output = args.Number; DMOutput outputCard = Dmps.SwitcherOutputs[output] as DMOutput; if (args.EventId == DMOutputEventIds.VolumeEventId && VolumeControls.ContainsKey(output)) { VolumeControls[args.Number].VolumeEventFromChassis(); } else if (args.EventId == DMOutputEventIds.OnlineFeedbackEventId && OutputEndpointOnlineFeedbacks.ContainsKey(output)) { OutputEndpointOnlineFeedbacks[output].FireUpdate(); } else if (args.EventId == DMOutputEventIds.VideoOutEventId) { if (outputCard != null && outputCard.VideoOutFeedback != null) { Debug.Console(2, this, "DMSwitchVideo:{0} Routed Input:{1} Output:{2}'", this.Name, outputCard.VideoOutFeedback.Number, output); } if (VideoOutputFeedbacks.ContainsKey(output)) { VideoOutputFeedbacks[output].FireUpdate(); } if (OutputVideoRouteNameFeedbacks.ContainsKey(output)) { OutputVideoRouteNameFeedbacks[output].FireUpdate(); } } else if (args.EventId == DMOutputEventIds.AudioOutEventId) { if (outputCard != null && outputCard.AudioOutFeedback != null) { Debug.Console(2, this, "DMSwitchAudio:{0} Routed Input:{1} Output:{2}'", this.Name, outputCard.AudioOutFeedback.Number, output); } if (AudioOutputFeedbacks.ContainsKey(output)) { AudioOutputFeedbacks[output].FireUpdate(); } } else if (args.EventId == DMOutputEventIds.OutputNameEventId && OutputNameFeedbacks.ContainsKey(output)) { Debug.Console(2, this, "DM Output {0} NameFeedbackEventId", output); OutputNameFeedbacks[output].FireUpdate(); } } /// /// /// /// void StartOffTimer(PortNumberType pnt) { if (RouteOffTimers.ContainsKey(pnt)) return; RouteOffTimers[pnt] = new CTimer(o => { ExecuteSwitch(0, pnt.Number, pnt.Type); }, RouteOffTime); } #region IRouting Members public void ExecuteSwitch(object inputSelector, object outputSelector, eRoutingSignalType sigType) { try { Debug.Console(2, this, "Attempting a DM route from input {0} to output {1} {2}", inputSelector, outputSelector, sigType); var input = Convert.ToUInt32(inputSelector); // Cast can sometimes fail var output = Convert.ToUInt32(outputSelector); if (input <= Dmps.NumberOfSwitcherInputs && output <= Dmps.NumberOfSwitcherOutputs) { // Check to see if there's an off timer waiting on this and if so, cancel var key = new PortNumberType(output, sigType); if (input == 0) { StartOffTimer(key); } else if (key.Number > 0) { if (RouteOffTimers.ContainsKey(key)) { Debug.Console(2, this, "{0} cancelling route off due to new source", output); RouteOffTimers[key].Stop(); RouteOffTimers.Remove(key); } } DMInput inCard = input == 0 ? null : Dmps.SwitcherInputs[input] as DMInput; Card.Dmps3OutputBase outCard = output == 0 ? null : Dmps.SwitcherOutputs[output] as Card.Dmps3OutputBase; if (inCard != null) { // NOTE THAT BITWISE COMPARISONS - TO CATCH ALL ROUTING TYPES if ((sigType | eRoutingSignalType.Video) == eRoutingSignalType.Video) { //SystemControl.VideoEnter.BoolValue = true; if (outCard != null && outCard.VideoOut != null) outCard.VideoOut = inCard; } if ((sigType | eRoutingSignalType.Audio) == eRoutingSignalType.Audio) { if (outCard != null && outCard.AudioOut != null) outCard.AudioOut = inCard; } if ((sigType | eRoutingSignalType.UsbOutput) == eRoutingSignalType.UsbOutput) { if (outCard != null && outCard.USBRoutedTo != null) outCard.USBRoutedTo = inCard; } if ((sigType | eRoutingSignalType.UsbInput) == eRoutingSignalType.UsbInput) { if (inCard != null && inCard.USBRoutedTo != null) inCard.USBRoutedTo = outCard; } } else { Debug.Console(1, this, "Unable to execute route from input {0} to output {1}. Input card not available", inputSelector, outputSelector); } } else { Debug.Console(1, this, "Unable to execute route from input {0} to output {1}", inputSelector, outputSelector); } } catch (Exception e) { Debug.Console(1, this, "Error executing switch: {0}", e); } } #endregion } }