Merge pull request #808 from PepperDash/hotfix/4series-cultureinfo-for-time-formats-and-dm-4kz-fix

Hotfix/4series cultureinfo for time formats and dm 4kz fix
This commit is contained in:
Andrew Welker 2021-08-26 18:15:18 -06:00 committed by GitHub
commit b853e8ed37
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
16 changed files with 737 additions and 374 deletions

View file

@ -948,5 +948,24 @@ namespace PepperDash.Essentials
/// 15214 /// 15214
/// </summary> /// </summary>
public const uint PinDialogDot4 = 15214; public const uint PinDialogDot4 = 15214;
// Password Prompt Dialog **************************
/// <summary>
/// 15301
/// </summary>
public const uint PasswordPromptDialogVisible = 15301;
/// <summary>
/// 15302
/// </summary>
public const uint PasswordPromptTextPress = 15302;
/// <summary>
/// 15306
/// </summary>
public const uint PasswordPromptCancelPress = 15306;
/// <summary>
/// 15307
/// </summary>
public const uint PasswordPromptErrorVisible = 15307;
} }
} }

View file

@ -118,6 +118,14 @@ namespace PepperDash.Essentials
//----- through 3120 //----- through 3120
/// <summary>
/// 3201
/// </summary>
public const uint PasswordPromptMessageText = 3201;
/// <summary>
/// 3202
/// </summary>
public const uint PasswordPromptPasswordText = 3202;
/// <summary> /// <summary>
/// 3812 /// 3812

View file

@ -1,6 +1,7 @@
using System; using System;
using System.Linq; using System.Linq;
using System.Collections.Generic; using System.Collections.Generic;
using System.Globalization;
using Crestron.SimplSharp; using Crestron.SimplSharp;
using Crestron.SimplSharpPro; using Crestron.SimplSharpPro;
using Crestron.SimplSharpPro.UI; using Crestron.SimplSharpPro.UI;
@ -470,12 +471,16 @@ namespace PepperDash.Essentials
Debug.Console(0, "*#* Room on: {0}, lastMeetingDismissedId: {1} {2} *#*", Debug.Console(0, "*#* Room on: {0}, lastMeetingDismissedId: {1} {2} *#*",
CurrentRoom.OnFeedback.BoolValue, CurrentRoom.OnFeedback.BoolValue,
LastMeetingDismissedId, LastMeetingDismissedId,
lastMeetingDismissed != null ? lastMeetingDismissed.StartTime.ToShortTimeString() : ""); lastMeetingDismissed != null ? lastMeetingDismissed.StartTime.ToString("t", Global.Culture) : "");
var meeting = meetings.LastOrDefault(m => m.Joinable); var meeting = meetings.LastOrDefault(m => m.Joinable);
if (CurrentRoom.OnFeedback.BoolValue if (CurrentRoom.OnFeedback.BoolValue
&& lastMeetingDismissed == meeting) && lastMeetingDismissed == meeting)
{ {
// meeting no longer joinable, hide popup
if(meeting == null)
HideNextMeetingPopup();
return; return;
} }
@ -487,9 +492,11 @@ namespace PepperDash.Essentials
} }
else else
{ {
TriList.SetString(UIStringJoin.MeetingsOrContactMethodListTitleText, "Upcoming meeting"); TriList.SetString(UIStringJoin.MeetingsOrContactMethodListTitleText, "Upcoming meeting");
TriList.SetString(UIStringJoin.NextMeetingStartTimeText, meeting.StartTime.ToShortTimeString()); TriList.SetString(UIStringJoin.NextMeetingStartTimeText, meeting.StartTime.ToString("t", Global.Culture));
TriList.SetString(UIStringJoin.NextMeetingEndTimeText, meeting.EndTime.ToShortTimeString()); TriList.SetString(UIStringJoin.NextMeetingEndTimeText, meeting.EndTime.ToString("t", Global.Culture));
TriList.SetString(UIStringJoin.NextMeetingTitleText, meeting.Title); TriList.SetString(UIStringJoin.NextMeetingTitleText, meeting.Title);
TriList.SetString(UIStringJoin.NextMeetingNameText, meeting.Organizer); TriList.SetString(UIStringJoin.NextMeetingNameText, meeting.Organizer);
TriList.SetString(UIStringJoin.NextMeetingButtonLabel, "Join"); TriList.SetString(UIStringJoin.NextMeetingButtonLabel, "Join");
@ -512,7 +519,7 @@ namespace PepperDash.Essentials
// indexOf = 3, 4 meetings : // indexOf = 3, 4 meetings :
if (indexOfNext < meetings.Count) if (indexOfNext < meetings.Count)
TriList.SetString(UIStringJoin.NextMeetingFollowingMeetingText, TriList.SetString(UIStringJoin.NextMeetingFollowingMeetingText,
meetings[indexOfNext].StartTime.ToShortTimeString()); meetings[indexOfNext].StartTime.ToString("t", Global.Culture));
else else
TriList.SetString(UIStringJoin.NextMeetingFollowingMeetingText, "No more meetings today"); TriList.SetString(UIStringJoin.NextMeetingFollowingMeetingText, "No more meetings today");
@ -1209,8 +1216,8 @@ namespace PepperDash.Essentials
foreach (var m in CurrentRoom.ScheduleSource.CodecSchedule.Meetings) foreach (var m in CurrentRoom.ScheduleSource.CodecSchedule.Meetings)
{ {
i++; i++;
MeetingOrContactMethodModalSrl.StringInputSig(i, 1).StringValue = m.StartTime.ToShortTimeString(); MeetingOrContactMethodModalSrl.StringInputSig(i, 1).StringValue = m.StartTime.ToString("t", Global.Culture);
MeetingOrContactMethodModalSrl.StringInputSig(i, 2).StringValue = m.EndTime.ToShortTimeString(); MeetingOrContactMethodModalSrl.StringInputSig(i, 2).StringValue = m.EndTime.ToString("t", Global.Culture);
MeetingOrContactMethodModalSrl.StringInputSig(i, 3).StringValue = m.Title; MeetingOrContactMethodModalSrl.StringInputSig(i, 3).StringValue = m.Title;
MeetingOrContactMethodModalSrl.StringInputSig(i, 4).StringValue = string.Format("<br>{0}",m.Organizer); MeetingOrContactMethodModalSrl.StringInputSig(i, 4).StringValue = string.Format("<br>{0}",m.Organizer);
MeetingOrContactMethodModalSrl.StringInputSig(i, 5).StringValue = "Join"; MeetingOrContactMethodModalSrl.StringInputSig(i, 5).StringValue = "Join";

View file

@ -2,6 +2,7 @@
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Text; using System.Text;
using System.Globalization;
using System.Text.RegularExpressions; using System.Text.RegularExpressions;
using Crestron.SimplSharp; using Crestron.SimplSharp;
using Crestron.SimplSharpPro; using Crestron.SimplSharpPro;
@ -83,6 +84,9 @@ namespace PepperDash.Essentials.UIDrivers.VC
StringBuilder SearchStringBuilder = new StringBuilder(); StringBuilder SearchStringBuilder = new StringBuilder();
BoolFeedback SearchStringBackspaceVisibleFeedback; BoolFeedback SearchStringBackspaceVisibleFeedback;
StringFeedback PasswordStringFeedback;
StringBuilder PasswordStringBuilder = new StringBuilder();
ModalDialog IncomingCallModal; ModalDialog IncomingCallModal;
eKeypadMode KeypadMode; eKeypadMode KeypadMode;
@ -180,8 +184,22 @@ namespace PepperDash.Essentials.UIDrivers.VC
}); });
SearchStringFeedback.LinkInputSig(triList.StringInput[UIStringJoin.CodecDirectorySearchEntryText]); SearchStringFeedback.LinkInputSig(triList.StringInput[UIStringJoin.CodecDirectorySearchEntryText]);
SetupDirectoryList(); PasswordStringFeedback = new StringFeedback(() =>
{
if (PasswordStringBuilder.Length > 0)
{
Parent.Keyboard.EnableGoButton();
return PasswordStringBuilder.ToString();
}
else
{
Parent.Keyboard.DisableGoButton();
return "";
}
});
PasswordStringFeedback.LinkInputSig(triList.StringInput[UIStringJoin.PasswordPromptPasswordText]);
SetupDirectoryList();
SearchStringBackspaceVisibleFeedback = new BoolFeedback(() => SearchStringBuilder.Length > 0); SearchStringBackspaceVisibleFeedback = new BoolFeedback(() => SearchStringBuilder.Length > 0);
SearchStringBackspaceVisibleFeedback.LinkInputSig(triList.BooleanInput[UIBoolJoin.VCDirectoryBackspaceVisible]); SearchStringBackspaceVisibleFeedback.LinkInputSig(triList.BooleanInput[UIBoolJoin.VCDirectoryBackspaceVisible]);
@ -199,6 +217,12 @@ namespace PepperDash.Essentials.UIDrivers.VC
triList.SetSigHeldAction(UIBoolJoin.VCDirectoryBackspacePress, 500, triList.SetSigHeldAction(UIBoolJoin.VCDirectoryBackspacePress, 500,
StartSearchBackspaceRepeat, StopSearchBackspaceRepeat, SearchKeypadBackspacePress); StartSearchBackspaceRepeat, StopSearchBackspaceRepeat, SearchKeypadBackspacePress);
if (Codec is IPasswordPrompt)
{
SetupPasswordPrompt();
}
} }
catch (Exception e) catch (Exception e)
{ {
@ -299,6 +323,7 @@ namespace PepperDash.Essentials.UIDrivers.VC
{ {
case eCodecCallStatus.Connected: case eCodecCallStatus.Connected:
// fire at SRL item // fire at SRL item
HidePasswordPrompt();
KeypadMode = eKeypadMode.DTMF; KeypadMode = eKeypadMode.DTMF;
DialStringBuilder.Remove(0, DialStringBuilder.Length); DialStringBuilder.Remove(0, DialStringBuilder.Length);
DialStringFeedback.FireUpdate(); DialStringFeedback.FireUpdate();
@ -984,7 +1009,7 @@ namespace PepperDash.Essentials.UIDrivers.VC
// if it's today, show a simpler string // if it's today, show a simpler string
string timeText = null; string timeText = null;
if (c.StartTime.Date == DateTime.Now.Date) if (c.StartTime.Date == DateTime.Now.Date)
timeText = c.StartTime.ToShortTimeString(); timeText = c.StartTime.ToString("t", Global.Culture);
else if (c.StartTime == DateTime.MinValue) else if (c.StartTime == DateTime.MinValue)
timeText = ""; timeText = "";
else else
@ -1328,7 +1353,21 @@ namespace PepperDash.Essentials.UIDrivers.VC
/// </summary> /// </summary>
void RevealKeyboard() void RevealKeyboard()
{ {
if (VCControlsInterlock.CurrentJoin == UIBoolJoin.VCKeypadWithFavoritesVisible && KeypadMode == eKeypadMode.Dial) if (_passwordPromptDialogVisible)
{
Debug.Console(2, "Attaching Keyboard to PasswordPromptDialog");
DetachDialKeyboard();
DetachSearchKeyboard();
var kb = Parent.Keyboard;
kb.KeyPress -= Keyboard_PasswordKeyPress;
kb.KeyPress += Keyboard_PasswordKeyPress;
kb.HideAction = this.DetachPasswordKeyboard;
kb.GoButtonText = "Submit";
kb.GoButtonVisible = true;
PasswordStringCheckEnables();
kb.Show();
}
else if (VCControlsInterlock.CurrentJoin == UIBoolJoin.VCKeypadWithFavoritesVisible && KeypadMode == eKeypadMode.Dial)
{ {
var kb = Parent.Keyboard; var kb = Parent.Keyboard;
kb.KeyPress -= Keyboard_DialKeyPress; kb.KeyPress -= Keyboard_DialKeyPress;
@ -1350,6 +1389,7 @@ namespace PepperDash.Essentials.UIDrivers.VC
SearchStringKeypadCheckEnables(); SearchStringKeypadCheckEnables();
kb.Show(); kb.Show();
} }
} }
/// <summary> /// <summary>
@ -1405,6 +1445,32 @@ namespace PepperDash.Essentials.UIDrivers.VC
} }
} }
/// <summary>
/// Event handler for keyboard dialing
/// </summary>
void Keyboard_PasswordKeyPress(object sender, PepperDash.Essentials.Core.Touchpanels.Keyboards.KeyboardControllerPressEventArgs e)
{
if (_passwordPromptDialogVisible)
{
if (e.Text != null)
PasswordStringBuilder.Append(e.Text);
else
{
if (e.SpecialKey == KeyboardSpecialKey.Backspace)
PasswordKeypadBackspacePress();
else if (e.SpecialKey == KeyboardSpecialKey.Clear)
PasswordKeypadClear();
else if (e.SpecialKey == KeyboardSpecialKey.GoButton)
{
(Codec as IPasswordPrompt).SubmitPassword(PasswordStringBuilder.ToString());
HidePasswordPrompt();
}
}
PasswordStringFeedback.FireUpdate();
PasswordStringCheckEnables();
}
}
/// <summary> /// <summary>
/// Call /// Call
/// </summary> /// </summary>
@ -1418,6 +1484,11 @@ namespace PepperDash.Essentials.UIDrivers.VC
Parent.Keyboard.KeyPress -= Keyboard_SearchKeyPress; Parent.Keyboard.KeyPress -= Keyboard_SearchKeyPress;
} }
void DetachPasswordKeyboard()
{
Parent.Keyboard.KeyPress -= Keyboard_PasswordKeyPress;
}
/// <summary> /// <summary>
/// Shows the camera controls subpage /// Shows the camera controls subpage
/// </summary> /// </summary>
@ -1671,6 +1742,40 @@ namespace PepperDash.Essentials.UIDrivers.VC
Parent.Keyboard.DisableGoButton(); Parent.Keyboard.DisableGoButton();
} }
/// <summary>
/// Clears the Password keypad
/// </summary>
void PasswordKeypadClear()
{
PasswordStringBuilder.Remove(0, SearchStringBuilder.Length);
PasswordStringFeedback.FireUpdate();
PasswordStringCheckEnables();
}
/// <summary>
///
/// </summary>
void PasswordKeypadBackspacePress()
{
PasswordStringBuilder.Remove(PasswordStringBuilder.Length - 1, 1);
PasswordStringFeedback.FireUpdate();
PasswordStringCheckEnables();
}
/// <summary>
/// Checks the enabled states of various elements around the keypad
/// </summary>
void PasswordStringCheckEnables()
{
var textIsEntered = PasswordStringBuilder.Length > 0;
if (textIsEntered)
Parent.Keyboard.EnableGoButton();
else
Parent.Keyboard.DisableGoButton();
}
/// <summary> /// <summary>
/// Returns the text value for the keypad dial entry field /// Returns the text value for the keypad dial entry field
@ -1716,5 +1821,61 @@ namespace PepperDash.Essentials.UIDrivers.VC
Dial = 0, Dial = 0,
DTMF DTMF
} }
void SetupPasswordPrompt()
{
var passwordPromptCodec = Codec as IPasswordPrompt;
passwordPromptCodec.PasswordRequired += new EventHandler<PasswordPromptEventArgs>(passwordPromptCodec_PasswordRequired);
TriList.SetSigFalseAction(UIBoolJoin.PasswordPromptCancelPress, HidePasswordPrompt);
TriList.SetSigFalseAction(UIBoolJoin.PasswordPromptTextPress, RevealKeyboard);
}
void passwordPromptCodec_PasswordRequired(object sender, PasswordPromptEventArgs e)
{
if (e.LoginAttemptCancelled)
{
HidePasswordPrompt();
return;
}
if (!string.IsNullOrEmpty(e.Message))
{
TriList.SetString(UIStringJoin.PasswordPromptMessageText, e.Message);
}
if (e.LoginAttemptFailed)
{
// TODO: Show a message modal to indicate the login attempt failed
return;
}
TriList.SetBool(UIBoolJoin.PasswordPromptErrorVisible, e.LastAttemptWasIncorrect);
ShowPasswordPrompt();
}
private bool _passwordPromptDialogVisible;
void ShowPasswordPrompt()
{
// Clear out any previous data
PasswordKeypadClear();
_passwordPromptDialogVisible = true;
TriList.SetBool(UIBoolJoin.PasswordPromptDialogVisible, _passwordPromptDialogVisible);
RevealKeyboard();
}
void HidePasswordPrompt()
{
if (_passwordPromptDialogVisible)
{
_passwordPromptDialogVisible = false;
Parent.Keyboard.Hide();
TriList.SetBool(UIBoolJoin.PasswordPromptDialogVisible, _passwordPromptDialogVisible);
}
}
} }
} }

View file

@ -0,0 +1,56 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Crestron.SimplSharp;
namespace PepperDash.Essentials.Core
{
/// <summary>
/// Describes the functionality required to prompt a user to enter a password
/// </summary>
public interface IPasswordPrompt
{
/// <summary>
/// Notifies when a password is required or is entered incorrectly
/// </summary>
event EventHandler<PasswordPromptEventArgs> PasswordRequired;
/// <summary>
/// Submits the password
/// </summary>
/// <param name="password"></param>
void SubmitPassword(string password);
}
public class PasswordPromptEventArgs : EventArgs
{
/// <summary>
/// Indicates if the last submitted password was incorrect
/// </summary>
public bool LastAttemptWasIncorrect { get; private set; }
/// <summary>
/// Indicates that the login attempt has failed
/// </summary>
public bool LoginAttemptFailed { get; private set; }
/// <summary>
/// Indicates that the process was cancelled and the prompt should be dismissed
/// </summary>
public bool LoginAttemptCancelled { get; private set; }
/// <summary>
/// A message to be displayed to the user
/// </summary>
public string Message { get; private set; }
public PasswordPromptEventArgs(bool lastAttemptIncorrect, bool loginFailed, bool loginCancelled, string message)
{
LastAttemptWasIncorrect = lastAttemptIncorrect;
LoginAttemptFailed = loginFailed;
LoginAttemptCancelled = loginCancelled;
Message = message;
}
}
}

View file

@ -1,5 +1,6 @@
using System; using System;
using System.Text.RegularExpressions; using System.Text.RegularExpressions;
using System.Globalization;
using Crestron.SimplSharp; using Crestron.SimplSharp;
using System.Collections.Generic; using System.Collections.Generic;
using Crestron.SimplSharp.CrestronIO; using Crestron.SimplSharp.CrestronIO;
@ -28,6 +29,10 @@ namespace PepperDash.Essentials.Core
public static eCrestronSeries ProcessorSeries { get { return CrestronEnvironment.ProgramCompatibility; } } public static eCrestronSeries ProcessorSeries { get { return CrestronEnvironment.ProgramCompatibility; } }
// TODO: consider making this configurable later
public static IFormatProvider Culture = CultureInfo.CreateSpecificCulture("en-US");
/// <summary> /// <summary>
/// The file path prefix to the folder containing configuration files /// The file path prefix to the folder containing configuration files
/// </summary> /// </summary>

View file

@ -203,6 +203,7 @@
<Compile Include="Devices\PC\Laptop.cs" /> <Compile Include="Devices\PC\Laptop.cs" />
<Compile Include="Devices\ReconfigurableDevice.cs" /> <Compile Include="Devices\ReconfigurableDevice.cs" />
<Compile Include="Devices\VolumeDeviceChangeEventArgs.cs" /> <Compile Include="Devices\VolumeDeviceChangeEventArgs.cs" />
<Compile Include="DeviceTypeInterfaces\IPasswordPrompt.cs" />
<Compile Include="DeviceTypeInterfaces\ITvPresetsProvider.cs" /> <Compile Include="DeviceTypeInterfaces\ITvPresetsProvider.cs" />
<Compile Include="DeviceTypeInterfaces\LanguageLabel.cs" /> <Compile Include="DeviceTypeInterfaces\LanguageLabel.cs" />
<Compile Include="DeviceTypeInterfaces\ILanguageProvider.cs" /> <Compile Include="DeviceTypeInterfaces\ILanguageProvider.cs" />

View file

@ -1,40 +1,40 @@
using Crestron.SimplSharpPro; using Crestron.SimplSharpPro;
using System; using System;
using System.Linq; using System.Linq;
//using Crestron.SimplSharpPro.DeviceSupport; //using Crestron.SimplSharpPro.DeviceSupport;
using Crestron.SimplSharpPro.DeviceSupport; using Crestron.SimplSharpPro.DeviceSupport;
using Crestron.SimplSharpPro.DM; using Crestron.SimplSharpPro.DM;
using Crestron.SimplSharpPro.DM.Endpoints; using Crestron.SimplSharpPro.DM.Endpoints;
using Crestron.SimplSharpPro.DM.Endpoints.Transmitters; using Crestron.SimplSharpPro.DM.Endpoints.Transmitters;
using PepperDash.Core; using PepperDash.Core;
using PepperDash.Essentials.Core; using PepperDash.Essentials.Core;
using PepperDash.Essentials.Core.Bridges; using PepperDash.Essentials.Core.Bridges;
namespace PepperDash.Essentials.DM namespace PepperDash.Essentials.DM
{ {
using eVst = eX02VideoSourceType; using eVst = eX02VideoSourceType;
using eAst = eX02AudioSourceType; using eAst = eX02AudioSourceType;
public class DmTx4kz202CController : DmTxControllerBase, ITxRoutingWithFeedback, public class DmTx4kz202CController : DmTxControllerBase, ITxRoutingWithFeedback,
IIROutputPorts, IComPorts IIROutputPorts, IComPorts
{ {
public DmTx4kz202C Tx { get; private set; } public DmTx4kz202C Tx { get; private set; }
public RoutingInputPortWithVideoStatuses HdmiIn1 { get; private set; } public RoutingInputPortWithVideoStatuses HdmiIn1 { get; private set; }
public RoutingInputPortWithVideoStatuses HdmiIn2 { get; private set; } public RoutingInputPortWithVideoStatuses HdmiIn2 { get; private set; }
public RoutingOutputPort DmOut { get; private set; } public RoutingOutputPort DmOut { get; private set; }
public RoutingOutputPort HdmiLoopOut { get; private set; } public RoutingOutputPort HdmiLoopOut { get; private set; }
public override StringFeedback ActiveVideoInputFeedback { get; protected set; } public override StringFeedback ActiveVideoInputFeedback { get; protected set; }
public IntFeedback VideoSourceNumericFeedback { get; protected set; } public IntFeedback VideoSourceNumericFeedback { get; protected set; }
public IntFeedback AudioSourceNumericFeedback { get; protected set; } public IntFeedback AudioSourceNumericFeedback { get; protected set; }
public IntFeedback HdmiIn1HdcpCapabilityFeedback { get; protected set; } public IntFeedback HdmiIn1HdcpCapabilityFeedback { get; protected set; }
public IntFeedback HdmiIn2HdcpCapabilityFeedback { get; protected set; } public IntFeedback HdmiIn2HdcpCapabilityFeedback { get; protected set; }
public BoolFeedback Hdmi1VideoSyncFeedback { get; protected set; } public BoolFeedback Hdmi1VideoSyncFeedback { get; protected set; }
public BoolFeedback Hdmi2VideoSyncFeedback { get; protected set; } public BoolFeedback Hdmi2VideoSyncFeedback { get; protected set; }
//public override IntFeedback HdcpSupportAllFeedback { get; protected set; } //public override IntFeedback HdcpSupportAllFeedback { get; protected set; }
//public override ushort HdcpSupportCapability { get; protected set; } //public override ushort HdcpSupportCapability { get; protected set; }
//IroutingNumericEvent //IroutingNumericEvent
public event EventHandler<RoutingNumericEventArgs> NumericSwitchChange; public event EventHandler<RoutingNumericEventArgs> NumericSwitchChange;
@ -47,48 +47,48 @@ namespace PepperDash.Essentials.DM
{ {
var newEvent = NumericSwitchChange; var newEvent = NumericSwitchChange;
if (newEvent != null) newEvent(this, e); if (newEvent != null) newEvent(this, e);
} }
/// <summary> /// <summary>
/// Helps get the "real" inputs, including when in Auto /// Helps get the "real" inputs, including when in Auto
/// </summary> /// </summary>
public eX02VideoSourceType ActualActiveVideoInput public eX02VideoSourceType ActualActiveVideoInput
{ {
get get
{ {
if (Tx.VideoSourceFeedback != eVst.Auto) if (Tx.VideoSourceFeedback != eVst.Auto)
return Tx.VideoSourceFeedback; return Tx.VideoSourceFeedback;
if (Tx.HdmiInputs[1].SyncDetectedFeedback.BoolValue) if (Tx.HdmiInputs[1].SyncDetectedFeedback.BoolValue)
return eVst.Hdmi1; return eVst.Hdmi1;
return Tx.HdmiInputs[2].SyncDetectedFeedback.BoolValue ? eVst.Hdmi2 : eVst.AllDisabled; return Tx.HdmiInputs[2].SyncDetectedFeedback.BoolValue ? eVst.Hdmi2 : eVst.AllDisabled;
} }
} }
public RoutingPortCollection<RoutingInputPort> InputPorts public RoutingPortCollection<RoutingInputPort> InputPorts
{ {
get get
{ {
return new RoutingPortCollection<RoutingInputPort> return new RoutingPortCollection<RoutingInputPort>
{ {
HdmiIn1, HdmiIn1,
HdmiIn2, HdmiIn2,
AnyVideoInput AnyVideoInput
}; };
} }
} }
public RoutingPortCollection<RoutingOutputPort> OutputPorts public RoutingPortCollection<RoutingOutputPort> OutputPorts
{ {
get get
{ {
return new RoutingPortCollection<RoutingOutputPort> { DmOut, HdmiLoopOut }; return new RoutingPortCollection<RoutingOutputPort> { DmOut, HdmiLoopOut };
} }
} }
public DmTx4kz202CController(string key, string name, DmTx4kz202C tx) public DmTx4kz202CController(string key, string name, DmTx4kz202C tx)
: base(key, name, tx) : base(key, name, tx)
{ {
Tx = tx; Tx = tx;
HdmiIn1 = new RoutingInputPortWithVideoStatuses(DmPortName.HdmiIn1, HdmiIn1 = new RoutingInputPortWithVideoStatuses(DmPortName.HdmiIn1,
@ -104,208 +104,208 @@ namespace PepperDash.Essentials.DM
FeedbackMatchObject = eVst.Hdmi2 FeedbackMatchObject = eVst.Hdmi2
}; };
ActiveVideoInputFeedback = new StringFeedback("ActiveVideoInput", ActiveVideoInputFeedback = new StringFeedback("ActiveVideoInput",
() => ActualActiveVideoInput.ToString()); () => ActualActiveVideoInput.ToString());
Tx.HdmiInputs[1].InputStreamChange += InputStreamChangeEvent; Tx.HdmiInputs[1].InputStreamChange += InputStreamChangeEvent;
Tx.HdmiInputs[2].InputStreamChange += InputStreamChangeEvent; Tx.HdmiInputs[2].InputStreamChange += InputStreamChangeEvent;
Tx.BaseEvent += Tx_BaseEvent; Tx.BaseEvent += Tx_BaseEvent;
Tx.OnlineStatusChange += Tx_OnlineStatusChange; Tx.OnlineStatusChange += Tx_OnlineStatusChange;
VideoSourceNumericFeedback = new IntFeedback(() => (int)Tx.VideoSourceFeedback); VideoSourceNumericFeedback = new IntFeedback(() => (int)Tx.VideoSourceFeedback);
//Return VideoSourceFeedback here as DM-TX-4KZ-202-C does not support audio breakaway //Return VideoSourceFeedback here as DM-TX-4KZ-202-C does not support audio breakaway
AudioSourceNumericFeedback = new IntFeedback(() => (int)Tx.VideoSourceFeedback); AudioSourceNumericFeedback = new IntFeedback(() => (int)Tx.VideoSourceFeedback);
HdmiIn1HdcpCapabilityFeedback = new IntFeedback("HdmiIn1HdcpCapability", () => (int)tx.HdmiInputs[1].HdcpCapabilityFeedback); HdmiIn1HdcpCapabilityFeedback = new IntFeedback("HdmiIn1HdcpCapability", () => (int)tx.HdmiInputs[1].HdcpCapabilityFeedback);
HdmiIn2HdcpCapabilityFeedback = new IntFeedback("HdmiIn2HdcpCapability", () => (int)tx.HdmiInputs[2].HdcpCapabilityFeedback); HdmiIn2HdcpCapabilityFeedback = new IntFeedback("HdmiIn2HdcpCapability", () => (int)tx.HdmiInputs[2].HdcpCapabilityFeedback);
HdcpStateFeedback = HdcpStateFeedback =
new IntFeedback( new IntFeedback(
() => () =>
tx.HdmiInputs[1].HdcpCapabilityFeedback > tx.HdmiInputs[2].HdcpCapabilityFeedback tx.HdmiInputs[1].HdcpCapabilityFeedback > tx.HdmiInputs[2].HdcpCapabilityFeedback
? (int)tx.HdmiInputs[1].HdcpCapabilityFeedback ? (int)tx.HdmiInputs[1].HdcpCapabilityFeedback
: (int)tx.HdmiInputs[2].HdcpCapabilityFeedback); : (int)tx.HdmiInputs[2].HdcpCapabilityFeedback);
HdcpSupportCapability = eHdcpCapabilityType.Hdcp2_2Support; HdcpSupportCapability = eHdcpCapabilityType.Hdcp2_2Support;
Hdmi1VideoSyncFeedback = new BoolFeedback(() => (bool)tx.HdmiInputs[1].SyncDetectedFeedback.BoolValue); Hdmi1VideoSyncFeedback = new BoolFeedback(() => (bool)tx.HdmiInputs[1].SyncDetectedFeedback.BoolValue);
Hdmi2VideoSyncFeedback = new BoolFeedback(() => (bool)tx.HdmiInputs[2].SyncDetectedFeedback.BoolValue); Hdmi2VideoSyncFeedback = new BoolFeedback(() => (bool)tx.HdmiInputs[2].SyncDetectedFeedback.BoolValue);
var combinedFuncs = new VideoStatusFuncsWrapper var combinedFuncs = new VideoStatusFuncsWrapper
{ {
HdcpActiveFeedbackFunc = () => HdcpActiveFeedbackFunc = () =>
(ActualActiveVideoInput == eVst.Hdmi1 (ActualActiveVideoInput == eVst.Hdmi1
&& tx.HdmiInputs[1].VideoAttributes.HdcpActiveFeedback.BoolValue) && tx.HdmiInputs[1].VideoAttributes.HdcpActiveFeedback.BoolValue)
|| (ActualActiveVideoInput == eVst.Hdmi2 || (ActualActiveVideoInput == eVst.Hdmi2
&& tx.HdmiInputs[2].VideoAttributes.HdcpActiveFeedback.BoolValue), && tx.HdmiInputs[2].VideoAttributes.HdcpActiveFeedback.BoolValue),
HdcpStateFeedbackFunc = () => HdcpStateFeedbackFunc = () =>
{ {
if (ActualActiveVideoInput == eVst.Hdmi1) if (ActualActiveVideoInput == eVst.Hdmi1)
return tx.HdmiInputs[1].VideoAttributes.HdcpStateFeedback.ToString(); return tx.HdmiInputs[1].VideoAttributes.HdcpStateFeedback.ToString();
if (ActualActiveVideoInput == eVst.Hdmi2) if (ActualActiveVideoInput == eVst.Hdmi2)
return tx.HdmiInputs[2].VideoAttributes.HdcpStateFeedback.ToString(); return tx.HdmiInputs[2].VideoAttributes.HdcpStateFeedback.ToString();
return ""; return "";
}, },
VideoResolutionFeedbackFunc = () => VideoResolutionFeedbackFunc = () =>
{ {
if (ActualActiveVideoInput == eVst.Hdmi1) if (ActualActiveVideoInput == eVst.Hdmi1)
return tx.HdmiInputs[1].VideoAttributes.GetVideoResolutionString(); return tx.HdmiInputs[1].VideoAttributes.GetVideoResolutionString();
if (ActualActiveVideoInput == eVst.Hdmi2) if (ActualActiveVideoInput == eVst.Hdmi2)
return tx.HdmiInputs[2].VideoAttributes.GetVideoResolutionString(); return tx.HdmiInputs[2].VideoAttributes.GetVideoResolutionString();
return ""; return "";
}, },
VideoSyncFeedbackFunc = () => VideoSyncFeedbackFunc = () =>
(ActualActiveVideoInput == eVst.Hdmi1 (ActualActiveVideoInput == eVst.Hdmi1
&& tx.HdmiInputs[1].SyncDetectedFeedback.BoolValue) && tx.HdmiInputs[1].SyncDetectedFeedback.BoolValue)
|| (ActualActiveVideoInput == eVst.Hdmi2 || (ActualActiveVideoInput == eVst.Hdmi2
&& tx.HdmiInputs[2].SyncDetectedFeedback.BoolValue) && tx.HdmiInputs[2].SyncDetectedFeedback.BoolValue)
}; };
AnyVideoInput = new RoutingInputPortWithVideoStatuses(DmPortName.AnyVideoIn, AnyVideoInput = new RoutingInputPortWithVideoStatuses(DmPortName.AnyVideoIn,
eRoutingSignalType.Audio | eRoutingSignalType.Video, eRoutingPortConnectionType.None, 0, this, combinedFuncs); eRoutingSignalType.Audio | eRoutingSignalType.Video, eRoutingPortConnectionType.None, 0, this, combinedFuncs);
DmOut = new RoutingOutputPort(DmPortName.DmOut, eRoutingSignalType.Audio | eRoutingSignalType.Video, DmOut = new RoutingOutputPort(DmPortName.DmOut, eRoutingSignalType.Audio | eRoutingSignalType.Video,
eRoutingPortConnectionType.DmCat, null, this); eRoutingPortConnectionType.DmCat, null, this);
HdmiLoopOut = new RoutingOutputPort(DmPortName.HdmiLoopOut, eRoutingSignalType.Audio | eRoutingSignalType.Video, HdmiLoopOut = new RoutingOutputPort(DmPortName.HdmiLoopOut, eRoutingSignalType.Audio | eRoutingSignalType.Video,
eRoutingPortConnectionType.Hdmi, null, this); eRoutingPortConnectionType.Hdmi, null, this);
AddToFeedbackList(ActiveVideoInputFeedback, VideoSourceNumericFeedback, AudioSourceNumericFeedback, AddToFeedbackList(ActiveVideoInputFeedback, VideoSourceNumericFeedback, AudioSourceNumericFeedback,
AnyVideoInput.VideoStatus.HasVideoStatusFeedback, AnyVideoInput.VideoStatus.HdcpActiveFeedback, AnyVideoInput.VideoStatus.HasVideoStatusFeedback, AnyVideoInput.VideoStatus.HdcpActiveFeedback,
AnyVideoInput.VideoStatus.HdcpStateFeedback, AnyVideoInput.VideoStatus.VideoResolutionFeedback, AnyVideoInput.VideoStatus.HdcpStateFeedback, AnyVideoInput.VideoStatus.VideoResolutionFeedback,
AnyVideoInput.VideoStatus.VideoSyncFeedback, HdmiIn1HdcpCapabilityFeedback, HdmiIn2HdcpCapabilityFeedback, AnyVideoInput.VideoStatus.VideoSyncFeedback, HdmiIn1HdcpCapabilityFeedback, HdmiIn2HdcpCapabilityFeedback,
Hdmi1VideoSyncFeedback, Hdmi2VideoSyncFeedback); Hdmi1VideoSyncFeedback, Hdmi2VideoSyncFeedback);
// Set Ports for CEC // Set Ports for CEC
HdmiIn1.Port = Tx.HdmiInputs[1]; HdmiIn1.Port = Tx.HdmiInputs[1];
HdmiIn2.Port = Tx.HdmiInputs[2]; HdmiIn2.Port = Tx.HdmiInputs[2];
HdmiLoopOut.Port = Tx.HdmiOutput; HdmiLoopOut.Port = Tx.HdmiOutput;
DmOut.Port = Tx.DmOutput; DmOut.Port = Tx.DmOutput;
} }
public override bool CustomActivate() public override bool CustomActivate()
{ {
// Link up all of these damned events to the various RoutingPorts via a helper handler // Link up all of these damned events to the various RoutingPorts via a helper handler
Tx.HdmiInputs[1].InputStreamChange += (o, a) => FowardInputStreamChange(HdmiIn1, a.EventId); Tx.HdmiInputs[1].InputStreamChange += (o, a) => FowardInputStreamChange(HdmiIn1, a.EventId);
Tx.HdmiInputs[1].VideoAttributes.AttributeChange += (o, a) => ForwardVideoAttributeChange(HdmiIn1, a.EventId); Tx.HdmiInputs[1].VideoAttributes.AttributeChange += (o, a) => ForwardVideoAttributeChange(HdmiIn1, a.EventId);
Tx.HdmiInputs[2].InputStreamChange += (o, a) => FowardInputStreamChange(HdmiIn2, a.EventId); Tx.HdmiInputs[2].InputStreamChange += (o, a) => FowardInputStreamChange(HdmiIn2, a.EventId);
Tx.HdmiInputs[2].VideoAttributes.AttributeChange += (o, a) => ForwardVideoAttributeChange(HdmiIn2, a.EventId); Tx.HdmiInputs[2].VideoAttributes.AttributeChange += (o, a) => ForwardVideoAttributeChange(HdmiIn2, a.EventId);
// Base does register and sets up comm monitoring. // Base does register and sets up comm monitoring.
return base.CustomActivate(); return base.CustomActivate();
} }
public override void LinkToApi(BasicTriList trilist, uint joinStart, string joinMapKey, EiscApiAdvanced bridge) public override void LinkToApi(BasicTriList trilist, uint joinStart, string joinMapKey, EiscApiAdvanced bridge)
{ {
var joinMap = GetDmTxJoinMap(joinStart, joinMapKey); var joinMap = GetDmTxJoinMap(joinStart, joinMapKey);
if (Hdmi1VideoSyncFeedback != null) if (Hdmi1VideoSyncFeedback != null)
{ {
Hdmi1VideoSyncFeedback.LinkInputSig(trilist.BooleanInput[joinMap.Input1VideoSyncStatus.JoinNumber]); Hdmi1VideoSyncFeedback.LinkInputSig(trilist.BooleanInput[joinMap.Input1VideoSyncStatus.JoinNumber]);
} }
if (Hdmi2VideoSyncFeedback != null) if (Hdmi2VideoSyncFeedback != null)
{ {
Hdmi2VideoSyncFeedback.LinkInputSig(trilist.BooleanInput[joinMap.Input2VideoSyncStatus.JoinNumber]); Hdmi2VideoSyncFeedback.LinkInputSig(trilist.BooleanInput[joinMap.Input2VideoSyncStatus.JoinNumber]);
} }
LinkDmTxToApi(this, trilist, joinMap, bridge); LinkDmTxToApi(this, trilist, joinMap, bridge);
} }
public void ExecuteNumericSwitch(ushort input, ushort output, eRoutingSignalType type) public void ExecuteNumericSwitch(ushort input, ushort output, eRoutingSignalType type)
{ {
Debug.Console(2, this, "Executing Numeric Switch to input {0}.", input); Debug.Console(2, this, "Executing Numeric Switch to input {0}.", input);
switch (type) switch (type)
{ {
case eRoutingSignalType.Video: case eRoutingSignalType.Video:
switch (input) switch (input)
{ {
case 0: case 0:
{ {
ExecuteSwitch(eVst.Auto, null, type); ExecuteSwitch(eVst.Auto, null, type);
break; break;
} }
case 1: case 1:
{ {
ExecuteSwitch(HdmiIn1.Selector, null, type); ExecuteSwitch(HdmiIn1.Selector, null, type);
break; break;
} }
case 2: case 2:
{ {
ExecuteSwitch(HdmiIn2.Selector, null, type); ExecuteSwitch(HdmiIn2.Selector, null, type);
break; break;
} }
case 3: case 3:
{ {
ExecuteSwitch(eVst.AllDisabled, null, type); ExecuteSwitch(eVst.AllDisabled, null, type);
break; break;
} }
} }
break; break;
case eRoutingSignalType.Audio: case eRoutingSignalType.Audio:
switch (input) switch (input)
{ {
case 0: case 0:
{ {
ExecuteSwitch(eAst.Auto, null, type); ExecuteSwitch(eAst.Auto, null, type);
break; break;
} }
case 1: case 1:
{ {
ExecuteSwitch(eAst.Hdmi1, null, type); ExecuteSwitch(eAst.Hdmi1, null, type);
break; break;
} }
case 2: case 2:
{ {
ExecuteSwitch(eAst.Hdmi2, null, type); ExecuteSwitch(eAst.Hdmi2, null, type);
break; break;
} }
case 3: case 3:
{ {
ExecuteSwitch(eAst.AllDisabled, null, type); ExecuteSwitch(eAst.AllDisabled, null, type);
break; break;
} }
} }
break; break;
} }
} }
public void ExecuteSwitch(object inputSelector, object outputSelector, eRoutingSignalType signalType) public void ExecuteSwitch(object inputSelector, object outputSelector, eRoutingSignalType signalType)
{ {
if ((signalType & eRoutingSignalType.Video) == eRoutingSignalType.Video) if ((signalType & eRoutingSignalType.Video) == eRoutingSignalType.Video)
Tx.VideoSource = (eVst)inputSelector; Tx.VideoSource = (eVst)inputSelector;
if(((signalType & eRoutingSignalType.Audio) == eRoutingSignalType.Audio)) if(((signalType & eRoutingSignalType.Audio) == eRoutingSignalType.Audio))
Debug.Console(2, this, "Unable to execute audio-only switch for tx {0}", Key); Debug.Console(2, this, "Unable to execute audio-only switch for tx {0}", Key);
} }
void InputStreamChangeEvent(EndpointInputStream inputStream, EndpointInputStreamEventArgs args) void InputStreamChangeEvent(EndpointInputStream inputStream, EndpointInputStreamEventArgs args)
{ {
Debug.Console(2, "{0} event {1} stream {2}", Tx.ToString(), inputStream.ToString(), args.EventId.ToString()); Debug.Console(2, "{0} event {1} stream {2}", Tx.ToString(), inputStream.ToString(), args.EventId.ToString());
switch (args.EventId) switch (args.EventId)
{ {
case EndpointInputStreamEventIds.HdcpSupportOffFeedbackEventId: case EndpointInputStreamEventIds.HdcpSupportOffFeedbackEventId:
case EndpointInputStreamEventIds.HdcpSupportOnFeedbackEventId: case EndpointInputStreamEventIds.HdcpSupportOnFeedbackEventId:
case EndpointInputStreamEventIds.HdcpCapabilityFeedbackEventId: case EndpointInputStreamEventIds.HdcpCapabilityFeedbackEventId:
if (inputStream == Tx.HdmiInputs[1]) HdmiIn1HdcpCapabilityFeedback.FireUpdate(); if (inputStream == Tx.HdmiInputs[1]) HdmiIn1HdcpCapabilityFeedback.FireUpdate();
if (inputStream == Tx.HdmiInputs[2]) HdmiIn2HdcpCapabilityFeedback.FireUpdate(); if (inputStream == Tx.HdmiInputs[2]) HdmiIn2HdcpCapabilityFeedback.FireUpdate();
break; break;
case EndpointInputStreamEventIds.SyncDetectedFeedbackEventId: case EndpointInputStreamEventIds.SyncDetectedFeedbackEventId:
if (inputStream == Tx.HdmiInputs[1]) Hdmi1VideoSyncFeedback.FireUpdate(); if (inputStream == Tx.HdmiInputs[1]) Hdmi1VideoSyncFeedback.FireUpdate();
if (inputStream == Tx.HdmiInputs[2]) Hdmi2VideoSyncFeedback.FireUpdate(); if (inputStream == Tx.HdmiInputs[2]) Hdmi2VideoSyncFeedback.FireUpdate();
break; break;
} }
} }
void Tx_OnlineStatusChange(GenericBase currentDevice, OnlineOfflineEventArgs args) void Tx_OnlineStatusChange(GenericBase currentDevice, OnlineOfflineEventArgs args)
@ -313,7 +313,7 @@ namespace PepperDash.Essentials.DM
var localVideoInputPort = var localVideoInputPort =
InputPorts.FirstOrDefault(p => (eVst)p.Selector == Tx.VideoSourceFeedback); InputPorts.FirstOrDefault(p => (eVst)p.Selector == Tx.VideoSourceFeedback);
var localAudioInputPort = var localAudioInputPort =
InputPorts.FirstOrDefault(p => (eAst)p.Selector == Tx.AudioSourceFeedback); InputPorts.FirstOrDefault(p => (eVst)p.Selector == Tx.VideoSourceFeedback);
ActiveVideoInputFeedback.FireUpdate(); ActiveVideoInputFeedback.FireUpdate();
VideoSourceNumericFeedback.FireUpdate(); VideoSourceNumericFeedback.FireUpdate();
@ -338,68 +338,68 @@ namespace PepperDash.Essentials.DM
OnSwitchChange(new RoutingNumericEventArgs(1, VideoSourceNumericFeedback.UShortValue, OutputPorts.First(), localVideoInputPort, eRoutingSignalType.Video)); OnSwitchChange(new RoutingNumericEventArgs(1, VideoSourceNumericFeedback.UShortValue, OutputPorts.First(), localVideoInputPort, eRoutingSignalType.Video));
break; break;
case EndpointTransmitterBase.AudioSourceFeedbackEventId: case EndpointTransmitterBase.AudioSourceFeedbackEventId:
var localInputAudioPort = InputPorts.FirstOrDefault(p => (eAst)p.Selector == Tx.AudioSourceFeedback); var localInputAudioPort = InputPorts.FirstOrDefault(p => (eVst)p.Selector == Tx.VideoSourceFeedback);
Debug.Console(2, this, " Audio Source: {0}", Tx.AudioSourceFeedback); Debug.Console(2, this, " Audio Source: {0}", Tx.VideoSourceFeedback);
AudioSourceNumericFeedback.FireUpdate(); AudioSourceNumericFeedback.FireUpdate();
OnSwitchChange(new RoutingNumericEventArgs(1, AudioSourceNumericFeedback.UShortValue, OutputPorts.First(), localInputAudioPort, eRoutingSignalType.Audio)); OnSwitchChange(new RoutingNumericEventArgs(1, AudioSourceNumericFeedback.UShortValue, OutputPorts.First(), localInputAudioPort, eRoutingSignalType.Audio));
break; break;
} }
} }
/// <summary> /// <summary>
/// Relays the input stream change to the appropriate RoutingInputPort. /// Relays the input stream change to the appropriate RoutingInputPort.
/// </summary> /// </summary>
void FowardInputStreamChange(RoutingInputPortWithVideoStatuses inputPort, int eventId) void FowardInputStreamChange(RoutingInputPortWithVideoStatuses inputPort, int eventId)
{ {
if (eventId != EndpointInputStreamEventIds.SyncDetectedFeedbackEventId) if (eventId != EndpointInputStreamEventIds.SyncDetectedFeedbackEventId)
{ {
return; return;
} }
inputPort.VideoStatus.VideoSyncFeedback.FireUpdate(); inputPort.VideoStatus.VideoSyncFeedback.FireUpdate();
AnyVideoInput.VideoStatus.VideoSyncFeedback.FireUpdate(); AnyVideoInput.VideoStatus.VideoSyncFeedback.FireUpdate();
} }
/// <summary> /// <summary>
/// Relays the VideoAttributes change to a RoutingInputPort /// Relays the VideoAttributes change to a RoutingInputPort
/// </summary> /// </summary>
void ForwardVideoAttributeChange(RoutingInputPortWithVideoStatuses inputPort, int eventId) void ForwardVideoAttributeChange(RoutingInputPortWithVideoStatuses inputPort, int eventId)
{ {
//// LOCATION: Crestron.SimplSharpPro.DM.VideoAttributeEventIds //// LOCATION: Crestron.SimplSharpPro.DM.VideoAttributeEventIds
//Debug.Console(2, this, "VideoAttributes_AttributeChange event id={0} from {1}", //Debug.Console(2, this, "VideoAttributes_AttributeChange event id={0} from {1}",
// args.EventId, (sender as VideoAttributesEnhanced).Owner.GetType()); // args.EventId, (sender as VideoAttributesEnhanced).Owner.GetType());
switch (eventId) switch (eventId)
{ {
case VideoAttributeEventIds.HdcpActiveFeedbackEventId: case VideoAttributeEventIds.HdcpActiveFeedbackEventId:
inputPort.VideoStatus.HdcpActiveFeedback.FireUpdate(); inputPort.VideoStatus.HdcpActiveFeedback.FireUpdate();
AnyVideoInput.VideoStatus.HdcpActiveFeedback.FireUpdate(); AnyVideoInput.VideoStatus.HdcpActiveFeedback.FireUpdate();
break; break;
case VideoAttributeEventIds.HdcpStateFeedbackEventId: case VideoAttributeEventIds.HdcpStateFeedbackEventId:
inputPort.VideoStatus.HdcpStateFeedback.FireUpdate(); inputPort.VideoStatus.HdcpStateFeedback.FireUpdate();
AnyVideoInput.VideoStatus.HdcpStateFeedback.FireUpdate(); AnyVideoInput.VideoStatus.HdcpStateFeedback.FireUpdate();
break; break;
case VideoAttributeEventIds.HorizontalResolutionFeedbackEventId: case VideoAttributeEventIds.HorizontalResolutionFeedbackEventId:
case VideoAttributeEventIds.VerticalResolutionFeedbackEventId: case VideoAttributeEventIds.VerticalResolutionFeedbackEventId:
inputPort.VideoStatus.VideoResolutionFeedback.FireUpdate(); inputPort.VideoStatus.VideoResolutionFeedback.FireUpdate();
AnyVideoInput.VideoStatus.VideoResolutionFeedback.FireUpdate(); AnyVideoInput.VideoStatus.VideoResolutionFeedback.FireUpdate();
break; break;
case VideoAttributeEventIds.FramesPerSecondFeedbackEventId: case VideoAttributeEventIds.FramesPerSecondFeedbackEventId:
inputPort.VideoStatus.VideoResolutionFeedback.FireUpdate(); inputPort.VideoStatus.VideoResolutionFeedback.FireUpdate();
AnyVideoInput.VideoStatus.VideoResolutionFeedback.FireUpdate(); AnyVideoInput.VideoStatus.VideoResolutionFeedback.FireUpdate();
break; break;
} }
} }
#region IIROutputPorts Members #region IIROutputPorts Members
public CrestronCollection<IROutputPort> IROutputPorts { get { return Tx.IROutputPorts; } } public CrestronCollection<IROutputPort> IROutputPorts { get { return Tx.IROutputPorts; } }
public int NumberOfIROutputPorts { get { return Tx.NumberOfIROutputPorts; } } public int NumberOfIROutputPorts { get { return Tx.NumberOfIROutputPorts; } }
#endregion #endregion
#region IComPorts Members #region IComPorts Members
public CrestronCollection<ComPort> ComPorts { get { return Tx.ComPorts; } } public CrestronCollection<ComPort> ComPorts { get { return Tx.ComPorts; } }
public int NumberOfComPorts { get { return Tx.NumberOfComPorts; } } public int NumberOfComPorts { get { return Tx.NumberOfComPorts; } }
#endregion #endregion
} }
} }

View file

@ -339,7 +339,7 @@ namespace PepperDash.Essentials.DM
var localVideoInputPort = var localVideoInputPort =
InputPorts.FirstOrDefault(p => (eVst)p.Selector == Tx.VideoSourceFeedback); InputPorts.FirstOrDefault(p => (eVst)p.Selector == Tx.VideoSourceFeedback);
var localAudioInputPort = var localAudioInputPort =
InputPorts.FirstOrDefault(p => (eAst)p.Selector == Tx.AudioSourceFeedback); InputPorts.FirstOrDefault(p => (eVst)p.Selector == Tx.VideoSourceFeedback);
ActiveVideoInputFeedback.FireUpdate(); ActiveVideoInputFeedback.FireUpdate();
VideoSourceNumericFeedback.FireUpdate(); VideoSourceNumericFeedback.FireUpdate();
@ -364,8 +364,8 @@ namespace PepperDash.Essentials.DM
OnSwitchChange(new RoutingNumericEventArgs(1, VideoSourceNumericFeedback.UShortValue, OutputPorts.First(), localVideoInputPort, eRoutingSignalType.Video)); OnSwitchChange(new RoutingNumericEventArgs(1, VideoSourceNumericFeedback.UShortValue, OutputPorts.First(), localVideoInputPort, eRoutingSignalType.Video));
break; break;
case EndpointTransmitterBase.AudioSourceFeedbackEventId: case EndpointTransmitterBase.AudioSourceFeedbackEventId:
var localInputAudioPort = InputPorts.FirstOrDefault(p => (eAst)p.Selector == Tx.AudioSourceFeedback); var localInputAudioPort = InputPorts.FirstOrDefault(p => (eVst)p.Selector == Tx.VideoSourceFeedback);
Debug.Console(2, this, " Audio Source: {0}", Tx.AudioSourceFeedback); Debug.Console(2, this, " Audio Source: {0}", Tx.VideoSourceFeedback);
AudioSourceNumericFeedback.FireUpdate(); AudioSourceNumericFeedback.FireUpdate();
OnSwitchChange(new RoutingNumericEventArgs(1, AudioSourceNumericFeedback.UShortValue, OutputPorts.First(), localInputAudioPort, eRoutingSignalType.Audio)); OnSwitchChange(new RoutingNumericEventArgs(1, AudioSourceNumericFeedback.UShortValue, OutputPorts.First(), localInputAudioPort, eRoutingSignalType.Audio));
break; break;

View file

@ -160,7 +160,19 @@ namespace PepperDash.Essentials.Devices.Common.Codec
/// </summary> /// </summary>
public interface IInvitableContact public interface IInvitableContact
{ {
bool IsInvitableContact { get; }
}
public class InvitableDirectoryContact : DirectoryContact, IInvitableContact
{
[JsonProperty("isInvitableContact")]
public bool IsInvitableContact
{
get
{
return this is IInvitableContact;
}
}
} }
/// <summary> /// <summary>
@ -209,8 +221,6 @@ namespace PepperDash.Essentials.Devices.Common.Codec
[JsonProperty("title")] [JsonProperty("title")]
public string Title { get; set; } public string Title { get; set; }
[JsonProperty("contactMethods")] [JsonProperty("contactMethods")]
public List<ContactMethod> ContactMethods { get; set; } public List<ContactMethod> ContactMethods { get; set; }

View file

@ -123,6 +123,7 @@
<Compile Include="VideoCodec\Interfaces\IHasParticipants.cs" /> <Compile Include="VideoCodec\Interfaces\IHasParticipants.cs" />
<Compile Include="VideoCodec\Interfaces\IHasSelfviewPosition.cs" /> <Compile Include="VideoCodec\Interfaces\IHasSelfviewPosition.cs" />
<Compile Include="VideoCodec\Interfaces\IHasSelfviewSize.cs" /> <Compile Include="VideoCodec\Interfaces\IHasSelfviewSize.cs" />
<Compile Include="VideoCodec\Interfaces\IHasStartMeeting.cs" />
<Compile Include="VideoCodec\Interfaces\iVideoCodecInfo.cs" /> <Compile Include="VideoCodec\Interfaces\iVideoCodecInfo.cs" />
<Compile Include="Codec\iHasCallFavorites.cs" /> <Compile Include="Codec\iHasCallFavorites.cs" />
<Compile Include="Codec\iHasCallHistory.cs" /> <Compile Include="Codec\iHasCallHistory.cs" />

View file

@ -743,6 +743,10 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.Cisco
} }
/// <summary>
/// Appends the delimiter and send the command to the codec
/// </summary>
/// <param name="command"></param>
public void SendText(string command) public void SendText(string command)
{ {
if (CommDebuggingIsOn) if (CommDebuggingIsOn)

View file

@ -0,0 +1,25 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Crestron.SimplSharp;
namespace PepperDash.Essentials.Devices.Common.VideoCodec.Interfaces
{
/// <summary>
/// Describes the ability to start an ad-hoc meeting
/// </summary>
public interface IHasStartMeeting
{
/// <summary>
/// The default meeting duration in minutes
/// </summary>
uint DefaultMeetingDurationMin { get; }
/// <summary>
/// Start an ad-hoc meeting for the specified duration
/// </summary>
/// <param name="duration"></param>
void StartMeeting(uint duration);
}
}

View file

@ -836,10 +836,10 @@ ScreenIndexIsPinnedTo: {8} (a{17})
//serials //serials
tokenArray[stringIndex] = new XSigSerialToken(stringIndex + 1, meeting.Organizer); tokenArray[stringIndex] = new XSigSerialToken(stringIndex + 1, meeting.Organizer);
tokenArray[stringIndex + 1] = new XSigSerialToken(stringIndex + 2, meeting.Title); tokenArray[stringIndex + 1] = new XSigSerialToken(stringIndex + 2, meeting.Title);
tokenArray[stringIndex + 2] = new XSigSerialToken(stringIndex + 3, meeting.StartTime.ToShortDateString()); tokenArray[stringIndex + 2] = new XSigSerialToken(stringIndex + 3, meeting.StartTime.ToString("t", Global.Culture));
tokenArray[stringIndex + 3] = new XSigSerialToken(stringIndex + 4, meeting.StartTime.ToShortTimeString()); tokenArray[stringIndex + 3] = new XSigSerialToken(stringIndex + 4, meeting.StartTime.ToString("t", Global.Culture));
tokenArray[stringIndex + 4] = new XSigSerialToken(stringIndex + 5, meeting.EndTime.ToShortDateString()); tokenArray[stringIndex + 4] = new XSigSerialToken(stringIndex + 5, meeting.EndTime.ToString("t", Global.Culture));
tokenArray[stringIndex + 5] = new XSigSerialToken(stringIndex + 6, meeting.EndTime.ToShortTimeString()); tokenArray[stringIndex + 5] = new XSigSerialToken(stringIndex + 6, meeting.EndTime.ToString("t", Global.Culture));
tokenArray[stringIndex + 6] = new XSigSerialToken(stringIndex + 7, meeting.Id); tokenArray[stringIndex + 6] = new XSigSerialToken(stringIndex + 7, meeting.Id);

View file

@ -236,14 +236,6 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.ZoomRoom
} }
} }
/// <summary>
/// Used to be able to inplement IInvitableContact on DirectoryContact
/// </summary>
public class ZoomDirectoryContact : DirectoryContact, IInvitableContact
{
}
public class Phonebook public class Phonebook
{ {
[JsonProperty("Contacts")] [JsonProperty("Contacts")]
@ -302,7 +294,7 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.ZoomRoom
foreach (Contact c in zoomContacts) foreach (Contact c in zoomContacts)
{ {
var contact = new ZoomDirectoryContact { Name = c.ScreenName, ContactId = c.Jid }; var contact = new InvitableDirectoryContact { Name = c.ScreenName, ContactId = c.Jid };
contact.ContactMethods.Add(new ContactMethod() { Number = c.Jid, Device = eContactMethodDevice.Video, CallType = eContactMethodCallType.Video, ContactMethodId = c.Jid }); contact.ContactMethods.Add(new ContactMethod() { Number = c.Jid, Device = eContactMethodDevice.Video, CallType = eContactMethodCallType.Video, ContactMethodId = c.Jid });
@ -927,6 +919,15 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.ZoomRoom
PhoneCallStatus_InCall, PhoneCallStatus_InCall,
PhoneCallStatus_Init, PhoneCallStatus_Init,
} }
public class MeetingNeedsPassword
{
[JsonProperty("needsPassword")]
public bool NeedsPassword { get; set; }
[JsonProperty("wrongAndRetry")]
public bool WrongAndRetry { get; set; }
}
} }
/// <summary> /// <summary>

View file

@ -25,10 +25,11 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.ZoomRoom
IRouting, IRouting,
IHasScheduleAwareness, IHasCodecCameras, IHasParticipants, IHasCameraOff, IHasCameraMute, IHasCameraAutoMode, IHasScheduleAwareness, IHasCodecCameras, IHasParticipants, IHasCameraOff, IHasCameraMute, IHasCameraAutoMode,
IHasFarEndContentStatus, IHasSelfviewPosition, IHasPhoneDialing, IHasZoomRoomLayouts, IHasParticipantPinUnpin, IHasFarEndContentStatus, IHasSelfviewPosition, IHasPhoneDialing, IHasZoomRoomLayouts, IHasParticipantPinUnpin,
IHasParticipantAudioMute, IHasSelfviewSize IHasParticipantAudioMute, IHasSelfviewSize, IPasswordPrompt, IHasStartMeeting
{ {
private const long MeetingRefreshTimer = 60000; private const long MeetingRefreshTimer = 60000;
private const uint DefaultMeetingDurationMin = 30; public uint DefaultMeetingDurationMin { get; private set; }
private const string Delimiter = "\x0D\x0A"; private const string Delimiter = "\x0D\x0A";
private readonly GenericQueue _receiveQueue; private readonly GenericQueue _receiveQueue;
@ -45,12 +46,15 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.ZoomRoom
private StringBuilder _jsonMessage; private StringBuilder _jsonMessage;
private int _previousVolumeLevel; private int _previousVolumeLevel;
private CameraBase _selectedCamera; private CameraBase _selectedCamera;
private string _lastDialedMeetingNumber;
private readonly ZoomRoomPropertiesConfig _props; private readonly ZoomRoomPropertiesConfig _props;
public ZoomRoom(DeviceConfig config, IBasicCommunication comm) public ZoomRoom(DeviceConfig config, IBasicCommunication comm)
: base(config) : base(config)
{ {
DefaultMeetingDurationMin = 30;
_props = JsonConvert.DeserializeObject<ZoomRoomPropertiesConfig>(config.Properties.ToString()); _props = JsonConvert.DeserializeObject<ZoomRoomPropertiesConfig>(config.Properties.ToString());
_receiveQueue = new GenericQueue(Key + "-rxQueue", Thread.eThreadPriority.MediumPriority, 512); _receiveQueue = new GenericQueue(Key + "-rxQueue", Thread.eThreadPriority.MediumPriority, 512);
@ -730,7 +734,7 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.ZoomRoom
ConsoleAccessLevelEnum.AccessOperator); ConsoleAccessLevelEnum.AccessOperator);
if (!_props.DisablePhonebookAutoDownload) if (!_props.DisablePhonebookAutoDownload)
{ {
CrestronConsole.AddNewConsoleCommand(s => SendText("zCommand Phonebook List Offset: 0 Limit: 512"), CrestronConsole.AddNewConsoleCommand(s => SendText("zCommand Phonebook List Offset: 0 Limit: 10000"),
"GetZoomRoomContacts", "Triggers a refresh of the codec phonebook", "GetZoomRoomContacts", "Triggers a refresh of the codec phonebook",
ConsoleAccessLevelEnum.AccessOperator); ConsoleAccessLevelEnum.AccessOperator);
} }
@ -860,7 +864,7 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.ZoomRoom
if (!_props.DisablePhonebookAutoDownload) if (!_props.DisablePhonebookAutoDownload)
{ {
_syncState.AddQueryToQueue("zCommand Phonebook List Offset: 0 Limit: 512"); _syncState.AddQueryToQueue("zCommand Phonebook List Offset: 0 Limit: 10000");
} }
_syncState.AddQueryToQueue("zCommand Bookings List"); _syncState.AddQueryToQueue("zCommand Bookings List");
@ -1358,7 +1362,20 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.ZoomRoom
} }
case "meetingneedspassword": case "meetingneedspassword":
{ {
// TODO: notify user to enter a password var meetingNeedsPassword =
responseObj.ToObject<zEvent.MeetingNeedsPassword>();
if (meetingNeedsPassword.NeedsPassword)
{
var prompt = "Password required to join this meeting. Please enter the meeting password.";
OnPasswordRequired(meetingNeedsPassword.WrongAndRetry, false, false, prompt);
}
else
{
OnPasswordRequired(false, false, true, "");
}
break; break;
} }
case "needwaitforhost": case "needwaitforhost":
@ -2050,9 +2067,21 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.ZoomRoom
public override void Dial(string number) public override void Dial(string number)
{ {
_lastDialedMeetingNumber = number;
SendText(string.Format("zCommand Dial Join meetingNumber: {0}", number)); SendText(string.Format("zCommand Dial Join meetingNumber: {0}", number));
} }
/// <summary>
/// Dials a meeting with a password
/// </summary>
/// <param name="number"></param>
/// <param name="password"></param>
public void Dial(string number, string password)
{
Debug.Console(2, this, "Dialing meeting number: {0} with password: {1}", number, password);
SendText(string.Format("zCommand Dial Join meetingNumber: {0} password: {1}", number, password));
}
/// <summary> /// <summary>
/// Invites a contact to either a new meeting (if not already in a meeting) or the current meeting. /// Invites a contact to either a new meeting (if not already in a meeting) or the current meeting.
/// Currently only invites a single user /// Currently only invites a single user
@ -2060,7 +2089,7 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.ZoomRoom
/// <param name="contact"></param> /// <param name="contact"></param>
public override void Dial(IInvitableContact contact) public override void Dial(IInvitableContact contact)
{ {
var ic = contact as zStatus.ZoomDirectoryContact; var ic = contact as InvitableDirectoryContact;
if (ic != null) if (ic != null)
{ {
@ -2078,6 +2107,21 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.ZoomRoom
} }
} }
/// <summary>
/// Starts a PMI Meeting for the specified duration (or default meeting duration if 0 is specified)
/// </summary>
/// <param name="duration">duration of meeting</param>
public void StartMeeting(uint duration)
{
uint dur = DefaultMeetingDurationMin;
if (duration > 0)
dur = duration;
SendText(string.Format("zCommand Dial StartPmi Duration: {0}", dur));
}
public override void EndCall(CodecActiveCallItem call) public override void EndCall(CodecActiveCallItem call)
{ {
SendText("zCommand Call Disconnect"); SendText("zCommand Call Disconnect");
@ -2681,7 +2725,28 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.ZoomRoom
} }
#endregion #endregion
}
#region IPasswordPrompt Members
public event EventHandler<PasswordPromptEventArgs> PasswordRequired;
public void SubmitPassword(string password)
{
Debug.Console(2, this, "Password Submitted: {0}", password);
Dial(_lastDialedMeetingNumber, password);
}
void OnPasswordRequired(bool lastAttemptIncorrect, bool loginFailed, bool loginCancelled, string message)
{
var handler = PasswordRequired;
if (handler != null)
{
handler(this, new PasswordPromptEventArgs(lastAttemptIncorrect, loginFailed, loginCancelled, message));
}
}
#endregion
}
/// <summary> /// <summary>
/// Zoom Room specific info object /// Zoom Room specific info object