From f9216e51f4a44b048cce1e5344c9b74a6b1f561e Mon Sep 17 00:00:00 2001 From: Trevor Payne Date: Wed, 13 Jul 2022 11:29:59 -0500 Subject: [PATCH 1/8] Fixed missing references --- .../epi-videoCodec-ciscoExtended.csproj | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/epi-videoCodec-ciscoExtended/epi-videoCodec-ciscoExtended.csproj b/epi-videoCodec-ciscoExtended/epi-videoCodec-ciscoExtended.csproj index 6c6dfb5..50edb04 100644 --- a/epi-videoCodec-ciscoExtended/epi-videoCodec-ciscoExtended.csproj +++ b/epi-videoCodec-ciscoExtended/epi-videoCodec-ciscoExtended.csproj @@ -56,24 +56,24 @@ False - ..\..\..\packages\PepperDashEssentials\lib\net35\Essentials Devices Common.dll + ..\packages\PepperDashEssentials\lib\net35\Essentials Devices Common.dll False - ..\..\..\packages\PepperDashEssentials\lib\net35\PepperDashEssentials.dll + ..\packages\PepperDashEssentials\lib\net35\PepperDashEssentials.dll False - ..\..\..\packages\PepperDashEssentials\lib\net35\PepperDash_Core.dll + ..\packages\PepperDashEssentials\lib\net35\PepperDash_Core.dll False - ..\..\..\packages\PepperDashEssentials\lib\net35\PepperDash_Essentials_Core.dll + ..\packages\PepperDashEssentials\lib\net35\PepperDash_Essentials_Core.dll False - ..\..\..\packages\PepperDashEssentials\lib\net35\PepperDash_Essentials_DM.dll + ..\packages\PepperDashEssentials\lib\net35\PepperDash_Essentials_DM.dll False From 521bb46049ea1044663f5f6cd9da120f91ef4fd5 Mon Sep 17 00:00:00 2001 From: Trevor Payne Date: Wed, 13 Jul 2022 11:45:39 -0500 Subject: [PATCH 2/8] Added nuspec file --- .../epi-videoCodec-ciscoExtended.nuspec | 21 +++++++++++++++++++ 1 file changed, 21 insertions(+) create mode 100644 epi-videoCodec-ciscoExtended/epi-videoCodec-ciscoExtended.nuspec diff --git a/epi-videoCodec-ciscoExtended/epi-videoCodec-ciscoExtended.nuspec b/epi-videoCodec-ciscoExtended/epi-videoCodec-ciscoExtended.nuspec new file mode 100644 index 0000000..bd42211 --- /dev/null +++ b/epi-videoCodec-ciscoExtended/epi-videoCodec-ciscoExtended.nuspec @@ -0,0 +1,21 @@ + + + + PepperDash.Essentials.Plugin.CiscoRoomOsCodec + 2.0.2 + Cisco RoomOs Codec Essentials Plugin + PepperDash Technologies + pepperdash + false + MIT + https://github.com/PepperDash/epi-videoCodec-ciscoExtended + Copyright 2022 + This software is a plugin designed to work as a part of PepperDash Essentials for Crestron control processors. This plugin allows for control of a Cisco RoomOs Video Codec using SSH + crestron 3series 4series samsung + + + + + + + \ No newline at end of file From 7695b77747f8bc7699b919352090f186c2c0da1f Mon Sep 17 00:00:00 2001 From: Trevor Payne Date: Wed, 13 Jul 2022 16:20:18 -0500 Subject: [PATCH 3/8] feature: added local and localremote presentation support --- .../CiscoCodecJoinMap.cs | 19 +++++++- .../CiscoRoomOsCodec.cs | 46 +++++++++++++++---- epi-videoCodec-ciscoExtended/xStatus.cs | 2 - 3 files changed, 55 insertions(+), 12 deletions(-) diff --git a/epi-videoCodec-ciscoExtended/CiscoCodecJoinMap.cs b/epi-videoCodec-ciscoExtended/CiscoCodecJoinMap.cs index 8fa570d..cf7fa36 100644 --- a/epi-videoCodec-ciscoExtended/CiscoCodecJoinMap.cs +++ b/epi-videoCodec-ciscoExtended/CiscoCodecJoinMap.cs @@ -19,7 +19,7 @@ public class CiscoCodecJoinMap : VideoCodecControllerJoinMap new JoinMetadata { Description = "Presentation Local Only Feedback", - JoinCapabilities = eJoinCapabilities.ToSIMPL, + JoinCapabilities = eJoinCapabilities.ToFromSIMPL, JoinType = eJoinType.Digital }); @@ -33,10 +33,25 @@ public class CiscoCodecJoinMap : VideoCodecControllerJoinMap new JoinMetadata { Description = "Presentation Local and Remote Feedback", - JoinCapabilities = eJoinCapabilities.ToSIMPL, + JoinCapabilities = eJoinCapabilities.ToFromSIMPL, + JoinType = eJoinType.Digital + }); + + [JoinName("PresentationLocalRemoteToggle")] + public JoinDataComplete PresentationLocalRemoteToggle = new JoinDataComplete( + new JoinData + { + JoinNumber = 207, + JoinSpan = 1 + }, + new JoinMetadata + { + Description = "Presentation Local and Remote Feedback", + JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); + [JoinName("ActivateDoNotDisturbMode")] public JoinDataComplete ActivateDoNotDisturbMode = new JoinDataComplete( new JoinData diff --git a/epi-videoCodec-ciscoExtended/CiscoRoomOsCodec.cs b/epi-videoCodec-ciscoExtended/CiscoRoomOsCodec.cs index c91fde9..50457d2 100644 --- a/epi-videoCodec-ciscoExtended/CiscoRoomOsCodec.cs +++ b/epi-videoCodec-ciscoExtended/CiscoRoomOsCodec.cs @@ -30,6 +30,8 @@ namespace epi_videoCodec_ciscoExtended enum eCommandType { SessionStart, SessionEnd, Command, GetStatus, GetConfiguration }; public enum eExternalSourceType { camera, desktop, document_camera, mediaplayer, PC, whiteboard, other } public enum eExternalSourceMode { Ready, NotReady, Hidden, Error } + public enum eCodecPresentationStates { LocalOnly, LocalRemote } + public class CiscoCodec : VideoCodecBase, IHasCallHistory, IHasCallFavorites, IHasDirectory, IHasScheduleAwareness, IOccupancyStatusProvider, IHasCodecLayoutsAvailable, IHasCodecSelfView, @@ -48,6 +50,8 @@ public class CiscoCodec : VideoCodecBase, IHasCallHistory, IHasCallFavorites, IH private CiscoCodecConfig _config; + public eCodecPresentationStates PresentationStates; + private bool _externalSourceChangeRequested; public event EventHandler DirectoryResultReturned; @@ -288,6 +292,8 @@ protected Func LocalLayoutIsProminentFeedbackFunc public CiscoCodec(DeviceConfig config, IBasicCommunication comm) : base(config) { + PresentationStates = eCodecPresentationStates.LocalOnly; + var props = JsonConvert.DeserializeObject(config.Properties.ToString()); _config = props; @@ -1713,6 +1719,7 @@ public void Dial(string number, string protocol, string callRate, string callTyp public override void EndCall(CodecActiveCallItem activeCall) { EnqueueCommand(string.Format("xCommand Call Disconnect CallId: {0}", activeCall.Id)); + PresentationStates = eCodecPresentationStates.LocalOnly; } public override void EndAllCalls() @@ -1721,6 +1728,7 @@ public override void EndAllCalls() { EnqueueCommand(string.Format("xCommand Call Disconnect CallId: {0}", activeCall.Id)); } + PresentationStates = eCodecPresentationStates.LocalOnly; } public override void AcceptCall(CodecActiveCallItem item) @@ -1844,15 +1852,8 @@ public void SelectPresentationSource2() /// public override void StartSharing() { - string sendingMode = string.Empty; - - if (IsInCall) - sendingMode = "LocalRemote"; - else - sendingMode = "LocalOnly"; - if (_desiredPresentationSource > 0) - EnqueueCommand(string.Format("xCommand Presentation Start PresentationSource: {0} SendingMode: {1}", _desiredPresentationSource, sendingMode)); + EnqueueCommand(string.Format("xCommand Presentation Start PresentationSource: {0} SendingMode: {1}", _desiredPresentationSource, PresentationStates.ToString())); } /// @@ -2008,10 +2009,38 @@ public void LinkCiscoCodecToApi(BasicTriList trilist, CiscoCodecJoinMap joinMap) trilist.SetUShortSigAction(joinMap.PresentationSource.JoinNumber, (u) => SelectPresentationSource(u)); PresentationSourceFeedback.LinkInputSig(trilist.UShortInput[joinMap.PresentationSource.JoinNumber]); + trilist.SetSigTrueAction(joinMap.PresentationLocalOnly.JoinNumber, SetPresentationLocalOnly); + trilist.SetSigTrueAction(joinMap.PresentationLocalRemote.JoinNumber, SetPresentationLocalRemote); + trilist.SetSigTrueAction(joinMap.PresentationLocalRemoteToggle.JoinNumber, SetPresentationLocalRemoteToggle); + + + PresentationSendingLocalOnlyFeedback.LinkInputSig(trilist.BooleanInput[joinMap.PresentationLocalOnly.JoinNumber]); PresentationSendingLocalRemoteFeedback.LinkInputSig(trilist.BooleanInput[joinMap.PresentationLocalRemote.JoinNumber]); } + public void SetPresentationLocalOnly() + { + PresentationStates = eCodecPresentationStates.LocalOnly; + if(CodecStatus.Status.Conference.Presentation.Mode.BoolValue) StartSharing(); + } + + public void SetPresentationLocalRemote() + { + PresentationStates = eCodecPresentationStates.LocalRemote; + if (CodecStatus.Status.Conference.Presentation.Mode.BoolValue) StartSharing(); + } + + public void SetPresentationLocalRemoteToggle() + { + if (PresentationStates == eCodecPresentationStates.LocalRemote) + { + SetPresentationLocalOnly(); + return; + } + SetPresentationLocalRemote(); + } + /// /// Reboots the codec /// @@ -2766,4 +2795,5 @@ public override EssentialsDevice BuildDevice(DeviceConfig dc) } } + } \ No newline at end of file diff --git a/epi-videoCodec-ciscoExtended/xStatus.cs b/epi-videoCodec-ciscoExtended/xStatus.cs index 2123f3d..ff6ccea 100644 --- a/epi-videoCodec-ciscoExtended/xStatus.cs +++ b/epi-videoCodec-ciscoExtended/xStatus.cs @@ -526,8 +526,6 @@ public class Mode2 : ValueProperty public bool BoolValue { get; private set; } - - public string Value { get From 4310573272b08657857001dae2824e058c43f853 Mon Sep 17 00:00:00 2001 From: Trevor Payne Date: Thu, 18 Aug 2022 09:06:48 -0500 Subject: [PATCH 4/8] includes development factory --- .../BookingsDataClasses.cs | 1 + epi-videoCodec-ciscoExtended/CiscoCamera.cs | 7 +- .../CiscoCodecConfig.cs | 8 +- .../CiscoCodecFactory.cs | 48 ++++ .../CiscoCodecJoinMap.cs | 216 ++++++++++++++- .../CiscoCodecPhonebookDataClasses.cs | 3 - .../CiscoRoomOsCodec.cs | 259 +++++++++++++++--- .../epi-videoCodec-ciscoExtended.csproj | 1 + .../xConfiguration.cs | 6 - epi-videoCodec-ciscoExtended/xEvent.cs | 8 +- epi-videoCodec-ciscoExtended/xStatus.cs | 37 ++- packages.config | 2 +- 12 files changed, 526 insertions(+), 70 deletions(-) create mode 100644 epi-videoCodec-ciscoExtended/CiscoCodecFactory.cs diff --git a/epi-videoCodec-ciscoExtended/BookingsDataClasses.cs b/epi-videoCodec-ciscoExtended/BookingsDataClasses.cs index dbc9e73..44ab23e 100644 --- a/epi-videoCodec-ciscoExtended/BookingsDataClasses.cs +++ b/epi-videoCodec-ciscoExtended/BookingsDataClasses.cs @@ -376,5 +376,6 @@ public static List GetGenericMeetingsFromBookingResult(List bo return meetings; } + } } \ No newline at end of file diff --git a/epi-videoCodec-ciscoExtended/CiscoCamera.cs b/epi-videoCodec-ciscoExtended/CiscoCamera.cs index 34d7a96..7e4a4c9 100644 --- a/epi-videoCodec-ciscoExtended/CiscoCamera.cs +++ b/epi-videoCodec-ciscoExtended/CiscoCamera.cs @@ -1,9 +1,4 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using Crestron.SimplSharp; -using Crestron.SimplSharpPro.DeviceSupport; +using Crestron.SimplSharpPro.DeviceSupport; using PepperDash.Essentials.Core.Bridges; using PepperDash.Essentials.Devices.Common.Cameras; diff --git a/epi-videoCodec-ciscoExtended/CiscoCodecConfig.cs b/epi-videoCodec-ciscoExtended/CiscoCodecConfig.cs index 98fa9c7..b041118 100644 --- a/epi-videoCodec-ciscoExtended/CiscoCodecConfig.cs +++ b/epi-videoCodec-ciscoExtended/CiscoCodecConfig.cs @@ -1,10 +1,4 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using Crestron.SimplSharp; - -using PepperDash.Core; +using System.Collections.Generic; using PepperDash.Essentials.Core; using PepperDash.Essentials.Devices.Common.Codec; diff --git a/epi-videoCodec-ciscoExtended/CiscoCodecFactory.cs b/epi-videoCodec-ciscoExtended/CiscoCodecFactory.cs new file mode 100644 index 0000000..960ed44 --- /dev/null +++ b/epi-videoCodec-ciscoExtended/CiscoCodecFactory.cs @@ -0,0 +1,48 @@ +using System.Collections.Generic; +using PepperDash.Core; +using PepperDash.Essentials.Core; +using PepperDash.Essentials.Core.Config; + + +namespace epi_videoCodec_ciscoExtended +{ + public class CiscoCodecFactory : EssentialsPluginDeviceFactory + { + public CiscoCodecFactory() + { + MinimumEssentialsFrameworkVersion = "1.10.6"; + + TypeNames = new List() { "ciscoRoomOS" }; + } + + public override EssentialsDevice BuildDevice(DeviceConfig dc) + { + Debug.Console(1, "Factory Attempting to create new Cisco RoomOs Device"); + + var comm = CommFactory.CreateCommForDevice(dc); + return new CiscoCodec(dc, comm); + } + } + + public class CiscoCodecDevelopmentFactory : EssentialsPluginDevelopmentDeviceFactory + { + public CiscoCodecDevelopmentFactory() + { + MinimumEssentialsFrameworkVersion = "1.10.6"; + + DevelopmentEssentialsFrameworkVersions = new List() {"1.10.6-alpha-1897"}; + + TypeNames = new List() { "ciscoRoomOS-development" }; + } + + public override EssentialsDevice BuildDevice(DeviceConfig dc) + { + Debug.Console(1, "Factory Attempting to create new Cisco RoomOs Development Device"); + + var comm = CommFactory.CreateCommForDevice(dc); + return new CiscoCodec(dc, comm); + } + } + + +} \ No newline at end of file diff --git a/epi-videoCodec-ciscoExtended/CiscoCodecJoinMap.cs b/epi-videoCodec-ciscoExtended/CiscoCodecJoinMap.cs index cf7fa36..3fec50f 100644 --- a/epi-videoCodec-ciscoExtended/CiscoCodecJoinMap.cs +++ b/epi-videoCodec-ciscoExtended/CiscoCodecJoinMap.cs @@ -7,7 +7,120 @@ namespace epi_videoCodec_ciscoExtended { public class CiscoCodecJoinMap : VideoCodecControllerJoinMap { + #region Digital + [JoinName("PhoneBookClearSelected")] + public JoinDataComplete PhoneBookClearSelected = new JoinDataComplete( + new JoinData + { + JoinNumber = 110, + JoinSpan = 1 + }, + new JoinMetadata + { + Description = "Clear Selected Entry and String from Search", + JoinCapabilities = eJoinCapabilities.FromSIMPL, + JoinType = eJoinType.Digital + }); + + + [JoinName("PresenterTrackEnabled")] + public JoinDataComplete PresenterTrackEnabled = new JoinDataComplete( + new JoinData + { + JoinNumber = 130, + JoinSpan = 1 + }, + new JoinMetadata + { + Description = "Presenter Track Enabled Feedback", + JoinCapabilities = eJoinCapabilities.ToSIMPL, + JoinType = eJoinType.Digital + }); + + + [JoinName("PresenterTrackOff")] + public JoinDataComplete PresenterTrackOff = new JoinDataComplete( + new JoinData + { + JoinNumber = 134, + JoinSpan = 1 + }, + new JoinMetadata + { + Description = "Presenter Track Off Get/Set", + JoinCapabilities = eJoinCapabilities.ToFromSIMPL, + JoinType = eJoinType.Digital + }); + [JoinName("PresenterTrackFollow")] + public JoinDataComplete PresenterTrackFollow = new JoinDataComplete( + new JoinData + { + JoinNumber = 135, + JoinSpan = 1 + }, + new JoinMetadata + { + Description = "Presenter Track Follow Get/Set", + JoinCapabilities = eJoinCapabilities.ToFromSIMPL, + JoinType = eJoinType.Digital + }); + [JoinName("PresenterTrackBackground")] + public JoinDataComplete PresenterTrackBackground = new JoinDataComplete( + new JoinData + { + JoinNumber = 136, + JoinSpan = 1 + }, + new JoinMetadata + { + Description = "Presenter Track Background Get/Set", + JoinCapabilities = eJoinCapabilities.ToFromSIMPL, + JoinType = eJoinType.Digital + }); + + [JoinName("PresenterTrackPersistent")] + public JoinDataComplete PresenterTrackPersistent = new JoinDataComplete( + new JoinData + { + JoinNumber = 137, + JoinSpan = 1 + }, + new JoinMetadata + { + Description = "Presenter Track Persistent Get/Set", + JoinCapabilities = eJoinCapabilities.ToFromSIMPL, + JoinType = eJoinType.Digital + }); + + [JoinName("DialMeeting4")] + public JoinDataComplete DialMeeting4 = new JoinDataComplete( + new JoinData + { + JoinNumber = 164, + JoinSpan = 1 + }, + new JoinMetadata + { + Description = "Join fourth meeting", + JoinCapabilities = eJoinCapabilities.FromSIMPL, + JoinType = eJoinType.Digital + }); + + [JoinName("DialMeeting5")] + public JoinDataComplete DialMeeting5 = new JoinDataComplete( + new JoinData + { + JoinNumber = 165, + JoinSpan = 1 + }, + new JoinMetadata + { + Description = "Join fifth meeting", + JoinCapabilities = eJoinCapabilities.FromSIMPL, + JoinType = eJoinType.Digital + }); + [JoinName("PresentationLocalOnly")] public JoinDataComplete PresentationLocalOnly = new JoinDataComplete( @@ -150,6 +263,93 @@ public class CiscoCodecJoinMap : VideoCodecControllerJoinMap JoinType = eJoinType.Digital }); + [JoinName("CodecAvailable")] + public JoinDataComplete CodecAvailable = new JoinDataComplete( + new JoinData + { + JoinNumber = 251, + JoinSpan = 1 + }, + new JoinMetadata + { + Description = "High to indicate that the codec does not have any meetings currently active", + JoinCapabilities = eJoinCapabilities.ToSIMPL, + JoinType = eJoinType.Digital + }); + + [JoinName("CodecMeetingBannerActive")] + public JoinDataComplete CodecMeetingBannerActive = new JoinDataComplete( + new JoinData + { + JoinNumber = 252, + JoinSpan = 1 + }, + new JoinMetadata + { + Description = "High to indicate that the codec has currently active meetings", + JoinCapabilities = eJoinCapabilities.ToSIMPL, + JoinType = eJoinType.Digital + }); + + [JoinName("CodecMeetingBannerWarning")] + public JoinDataComplete CodecMeetingBannerWarning = new JoinDataComplete( + new JoinData + { + JoinNumber = 253, + JoinSpan = 1 + }, + new JoinMetadata + { + Description = "High to indicate that the codec has an impending meeting", + JoinCapabilities = eJoinCapabilities.ToSIMPL, + JoinType = eJoinType.Digital + }); + + [JoinName("PresentationViewDefault")] + public JoinDataComplete PresentationViewDefault = new JoinDataComplete( + new JoinData + { + JoinNumber = 261, + JoinSpan = 1 + }, + new JoinMetadata + { + Description = "Set / Get PresentationView Default mode", + JoinCapabilities = eJoinCapabilities.ToFromSIMPL, + JoinType = eJoinType.Digital + }); + + [JoinName("PresentationViewMaximized")] + public JoinDataComplete PresentationViewMaximized = new JoinDataComplete( + new JoinData + { + JoinNumber = 262, + JoinSpan = 1 + }, + new JoinMetadata + { + Description = "Set / Get PresentationView Maximized mode", + JoinCapabilities = eJoinCapabilities.ToFromSIMPL, + JoinType = eJoinType.Digital + }); + + [JoinName("PresentationViewMinimized")] + public JoinDataComplete PresentationViewMinimized = new JoinDataComplete( + new JoinData + { + JoinNumber = 263, + JoinSpan = 1 + }, + new JoinMetadata + { + Description = "Set / Get PresentationView Minimized mode", + JoinCapabilities = eJoinCapabilities.ToFromSIMPL, + JoinType = eJoinType.Digital + }); + + + + #endregion @@ -169,6 +369,21 @@ public class CiscoCodecJoinMap : VideoCodecControllerJoinMap JoinType = eJoinType.Analog }); + [JoinName("DirectorySelectRowFeedback")] + public JoinDataComplete DirectorySelectRowFeedback = new JoinDataComplete( + new JoinData + { + JoinNumber = 101, + JoinSpan = 1 + }, + new JoinMetadata + { + Description = "Directory Select Row Feedback", + JoinCapabilities = eJoinCapabilities.ToSIMPL, + JoinType = eJoinType.Analog + }); + + [JoinName("PresentationSource")] public JoinDataComplete PresentationSource = new JoinDataComplete( new JoinData @@ -204,7 +419,6 @@ public class CiscoCodecJoinMap : VideoCodecControllerJoinMap }); - #endregion public CiscoCodecJoinMap(uint joinStart) diff --git a/epi-videoCodec-ciscoExtended/CiscoCodecPhonebookDataClasses.cs b/epi-videoCodec-ciscoExtended/CiscoCodecPhonebookDataClasses.cs index 0cf1f16..d8c4ec6 100644 --- a/epi-videoCodec-ciscoExtended/CiscoCodecPhonebookDataClasses.cs +++ b/epi-videoCodec-ciscoExtended/CiscoCodecPhonebookDataClasses.cs @@ -1,9 +1,6 @@ using System; using System.Collections.Generic; using System.Linq; -using System.Text; -using Crestron.SimplSharp; - using PepperDash.Core; using PepperDash.Essentials.Devices.Common.Codec; diff --git a/epi-videoCodec-ciscoExtended/CiscoRoomOsCodec.cs b/epi-videoCodec-ciscoExtended/CiscoRoomOsCodec.cs index 50457d2..4b1140c 100644 --- a/epi-videoCodec-ciscoExtended/CiscoRoomOsCodec.cs +++ b/epi-videoCodec-ciscoExtended/CiscoRoomOsCodec.cs @@ -5,8 +5,6 @@ using System.Text.RegularExpressions; using Crestron.SimplSharp; using Crestron.SimplSharp.CrestronIO; -using Crestron.SimplSharpPro; -using Crestron.SimplSharpPro.CrestronThread; using Crestron.SimplSharpPro.DeviceSupport; using Newtonsoft.Json; using Newtonsoft.Json.Linq; @@ -66,6 +64,10 @@ public class CiscoCodec : VideoCodecBase, IHasCallHistory, IHasCallFavorites, IH public BoolFeedback PresentationViewMaximizedFeedback { get; private set; } + public BoolFeedback PresentationViewMinimizedFeedback { get; private set; } + + public BoolFeedback PresentationViewDefaultFeedback { get; private set; } + private string _currentPresentationView; public BoolFeedback RoomIsOccupiedFeedback { get; private set; } @@ -80,7 +82,7 @@ public class CiscoCodec : VideoCodecBase, IHasCallHistory, IHasCallFavorites, IH public StringFeedback LocalLayoutFeedback { get; private set; } - private string _currentLayout; + private string _currentLayout = string.Empty; public StringFeedback AvailableLocalLayoutsFeedback { get; private set; } @@ -88,6 +90,14 @@ public class CiscoCodec : VideoCodecBase, IHasCallHistory, IHasCallFavorites, IH public BoolFeedback FarEndIsSharingContentFeedback { get; private set; } + public StringFeedback PresenterTrackStatusNameFeedback { get; private set; } + + public BoolFeedback PresenterTrackEnabledFeedback { get; private set; } + public BoolFeedback PresenterTrackStatusOffFeedback { get; private set; } + public BoolFeedback PresenterTrackStatusFollowFeedback { get; private set; } + public BoolFeedback PresenterTrackStatusBackgroundFeedback { get; private set; } + public BoolFeedback PresenterTrackStatusPersistentFeedback { get; private set; } + public IntFeedback RingtoneVolumeFeedback { get; private set; } public List AvailableLocalLayouts { get; private set; } @@ -231,6 +241,37 @@ protected Func LocalLayoutIsProminentFeedbackFunc get { return () => _currentLayout.Contains("Prominent") || _currentLayout.Contains("Stack"); } } + protected Func PresenterTrackStatusNameFeedbackFunc + { + get { return () => CodecStatus.Status.Cameras.PresenterTrack.Status.Value; } + } + + protected Func PresenterTrackEnabledFeedbackFunc + { + get { return () => CodecStatus.Status.Cameras.PresenterTrack.Availability.Value == "Unavailable"; } + } + + protected Func PresenterTrackStatusOffFeedbackFunc + { + get { return () => CodecStatus.Status.Cameras.PresenterTrack.Status.Value == "Off" || CodecStatus.Status.Cameras.PresenterTrack.Availability.Value == "Unavailable"; } + } + + protected Func PresenterTrackStatusFollowFeedbackFunc + { + get { return () => CodecStatus.Status.Cameras.PresenterTrack.Status.Value == "Follow"; } + } + + protected Func PresenterTrackStatusBackgroundFeedbackFunc + { + get { return () => CodecStatus.Status.Cameras.PresenterTrack.Status.Value == "Background"; } + } + protected Func PresenterTrackStatusPersistentFeedbackFunc + { + get { return () => CodecStatus.Status.Cameras.PresenterTrack.Status.Value == "Persistent"; } + } + + + private string _cliFeedbackRegistrationExpression; @@ -317,6 +358,14 @@ public CiscoCodec(DeviceConfig config, IBasicCommunication comm) FarEndIsSharingContentFeedback = new BoolFeedback(FarEndIsSharingContentFeedbackFunc); CameraIsOffFeedback = new BoolFeedback(() => CodecStatus.Status.Video.Input.MainVideoMute.BoolValue); AvailableLocalLayoutsFeedback = new StringFeedback(AvailableLayoutsFeedbackFunc); + PresenterTrackStatusNameFeedback = new StringFeedback(PresenterTrackStatusNameFeedbackFunc); + + + PresenterTrackEnabledFeedback = new BoolFeedback(PresenterTrackEnabledFeedbackFunc); + PresenterTrackStatusOffFeedback = new BoolFeedback(PresenterTrackStatusOffFeedbackFunc); + PresenterTrackStatusFollowFeedback = new BoolFeedback(PresenterTrackStatusFollowFeedbackFunc); + PresenterTrackStatusBackgroundFeedback = new BoolFeedback(PresenterTrackStatusBackgroundFeedbackFunc); + PresenterTrackStatusPersistentFeedback = new BoolFeedback(PresenterTrackStatusPersistentFeedbackFunc); CameraIsMutedFeedback = CameraIsOffFeedback; SupportsCameraOff = true; @@ -326,6 +375,8 @@ public CiscoCodec(DeviceConfig config, IBasicCommunication comm) EnteringStandbyModeFeedback = new BoolFeedback(() => CodecStatus.Status.Standby.State.Value.ToLower() == "enteringstandby"); PresentationViewMaximizedFeedback = new BoolFeedback(() => _currentPresentationView == "Maximized"); + PresentationViewMinimizedFeedback = new BoolFeedback(() => _currentPresentationView == "Minimized"); + PresentationViewDefaultFeedback = new BoolFeedback(() => _currentPresentationView == "Default"); RingtoneVolumeFeedback = new IntFeedback(() => CodecConfiguration.Configuration.Audio.SoundsAndAlerts.RingVolume.Volume); @@ -422,46 +473,74 @@ public CiscoCodec(DeviceConfig config, IBasicCommunication comm) _brandingUrl = props.UiBranding.BrandingUrl; } + private int QuickDebugTest(string description, int data) + { + if (String.IsNullOrEmpty(description)) return 0; + Debug.Console(2, this, "{0} completed step {1}", description, data); + return ++data; + } + private void SetFeedbackActions() { CodecStatus.Status.Audio.Volume.ValueChangedAction = VolumeLevelFeedback.FireUpdate; CodecStatus.Status.Audio.VolumeMute.ValueChangedAction = MuteFeedback.FireUpdate; + CodecStatus.Status.Audio.Microphones.Mute.ValueChangedAction = PrivacyModeIsOnFeedback.FireUpdate; - CodecStatus.Status.Standby.State.ValueChangedAction = new Action(() => + + CodecStatus.Status.Standby.State.ValueChangedAction = () => { StandbyIsOnFeedback.FireUpdate(); HalfWakeModeIsOnFeedback.FireUpdate(); EnteringStandbyModeFeedback.FireUpdate(); - }); + }; + CodecStatus.Status.RoomAnalytics.PeoplePresence.ValueChangedAction = RoomIsOccupiedFeedback.FireUpdate; + CodecStatus.Status.RoomAnalytics.PeopleCount.Current.ValueChangedAction = PeopleCountFeedback.FireUpdate; + CodecStatus.Status.Cameras.SpeakerTrack.Status.ValueChangedAction = CameraAutoModeIsOnFeedback.FireUpdate; + CodecStatus.Status.Cameras.SpeakerTrack.Availability.ValueChangedAction = () => { SupportsCameraAutoMode = CodecStatus.Status.Cameras.SpeakerTrack.Availability.BoolValue; }; + CodecStatus.Status.Video.Selfview.Mode.ValueChangedAction = SelfviewIsOnFeedback.FireUpdate; + CodecStatus.Status.Video.Selfview.PIPPosition.ValueChangedAction = ComputeSelfviewPipStatus; + CodecStatus.Status.Video.Layout.CurrentLayouts.ActiveLayout.ValueChangedAction = LocalLayoutFeedback.FireUpdate; + + CodecStatus.Status.Cameras.PresenterTrack.Status.ValueChangedAction = () => + { + PresenterTrackStatusBackgroundFeedback.FireUpdate(); + PresenterTrackStatusFollowFeedback.FireUpdate(); + PresenterTrackStatusOffFeedback.FireUpdate(); + PresenterTrackStatusPersistentFeedback.FireUpdate(); + }; + //CodecStatus.Status.Video.Layout.LayoutFamily.Local.ValueChangedAction = ComputeLocalLayout; CodecStatus.Status.Conference.Presentation.Mode.ValueChangedAction = () => { SharingContentIsOnFeedback.FireUpdate(); FarEndIsSharingContentFeedback.FireUpdate(); }; + CodecStatus.Status.Conference.DoNotDisturb.ValueChangedAction = DoNotDisturbModeIsOnFeedback.FireUpdate; + CodecConfiguration.Configuration.Audio.SoundsAndAlerts.RingVolume.ValueChangedAction = RingtoneVolumeFeedback.FireUpdate; + try { CodecStatus.Status.Video.Input.MainVideoMute.ValueChangedAction = CameraIsOffFeedback.FireUpdate; } catch (Exception ex) { - Debug.Console(0, this, "Error setting MainVideuMute Action: {0}", ex); + Debug.Console(0, this, "Error setting MainVideoMute Action: {0}", ex); if (ex.InnerException != null) { - Debug.Console(0, this, "Error setting MainVideuMute Action: {0}", ex); + Debug.Console(0, this, "Error setting MainVideoMute Action: {0}", ex); } } } @@ -1231,7 +1310,7 @@ void DeserializeResponse(string response) CodecStatus.Status.RoomPreset = existingRoomPresets; // Generecise the list - NearEndPresets = RoomPresets.GetGenericPresets(existingRoomPresets).Select(a => (CodecRoomPreset)a).ToList(); + NearEndPresets = existingRoomPresets.GetGenericPresets(); var handler = CodecRoomPresetsListHasChanged; if (handler != null) @@ -2013,10 +2092,64 @@ public void LinkCiscoCodecToApi(BasicTriList trilist, CiscoCodecJoinMap joinMap) trilist.SetSigTrueAction(joinMap.PresentationLocalRemote.JoinNumber, SetPresentationLocalRemote); trilist.SetSigTrueAction(joinMap.PresentationLocalRemoteToggle.JoinNumber, SetPresentationLocalRemoteToggle); + PresentationViewDefaultFeedback.LinkInputSig(trilist.BooleanInput[joinMap.PresentationViewDefault.JoinNumber]); + PresentationViewMinimizedFeedback.LinkInputSig(trilist.BooleanInput[joinMap.PresentationViewMinimized.JoinNumber]); + PresentationViewMaximizedFeedback.LinkInputSig(trilist.BooleanInput[joinMap.PresentationViewMinimized.JoinNumber]); + trilist.SetSigTrueAction(joinMap.PresentationViewDefault.JoinNumber, PresentationViewDefaultSet); + trilist.SetSigTrueAction(joinMap.PresentationViewMinimized.JoinNumber, PresentationViewMinimizedzedSet); + trilist.SetSigTrueAction(joinMap.PresentationViewMaximized.JoinNumber, PresentationViewMaximizedSet); PresentationSendingLocalOnlyFeedback.LinkInputSig(trilist.BooleanInput[joinMap.PresentationLocalOnly.JoinNumber]); PresentationSendingLocalRemoteFeedback.LinkInputSig(trilist.BooleanInput[joinMap.PresentationLocalRemote.JoinNumber]); + + PresenterTrackEnabledFeedback.LinkInputSig(trilist.BooleanInput[joinMap.PresenterTrackEnabled.JoinNumber]); + + PresenterTrackStatusOffFeedback.LinkInputSig(trilist.BooleanInput[joinMap.PresenterTrackOff.JoinNumber]); + PresenterTrackStatusFollowFeedback.LinkInputSig(trilist.BooleanInput[joinMap.PresenterTrackFollow.JoinNumber]); + PresenterTrackStatusBackgroundFeedback.LinkInputSig(trilist.BooleanInput[joinMap.PresenterTrackBackground.JoinNumber]); + PresenterTrackStatusPersistentFeedback.LinkInputSig(trilist.BooleanInput[joinMap.PresenterTrackPersistent.JoinNumber]); + + trilist.SetSigTrueAction(joinMap.PresenterTrackOff.JoinNumber, PresenterTrackOff); + trilist.SetSigTrueAction(joinMap.PresenterTrackFollow.JoinNumber, PresenterTrackFollow); + trilist.SetSigTrueAction(joinMap.PresenterTrackBackground.JoinNumber, PresenterTrackBackground); + trilist.SetSigTrueAction(joinMap.PresenterTrackPersistent.JoinNumber, PresenterTrackPersistent); + + CodecSchedule.MeetingEventChange += (sender, args) => + { + if (args.ChangeType == eMeetingEventChangeType.MeetingStartWarning) + { + UpdateMeetingsListEnhanced(this, trilist, joinMap); + } + }; + } + + private static void UpdateMeetingsListEnhanced(IHasScheduleAwareness codec, BasicTriList trilist, + CiscoCodecJoinMap joinMap) + { + var currentTime = DateTime.Now; + + List currentMeetings = codec.CodecSchedule.Meetings.Where(m => m.StartTime >= currentTime || m.EndTime >= currentTime).ToList(); + + if (currentMeetings.Count == 0) + { + trilist.SetBool(joinMap.CodecAvailable.JoinNumber, true); + trilist.SetBool(joinMap.CodecMeetingBannerActive.JoinNumber, false); + trilist.SetBool(joinMap.CodecMeetingBannerWarning.JoinNumber, false); + return; + } + + var upcomingMeeting = + currentMeetings.FirstOrDefault(x => x.StartTime >= currentTime && x.EndTime >= currentTime); + var currentMeeting = + currentMeetings.FirstOrDefault(x => x.StartTime <= currentTime && x.EndTime >= currentTime); + + var warningBanner = upcomingMeeting != null && + upcomingMeeting.StartTime - currentTime <= upcomingMeeting.MeetingWarningMinutes; + + trilist.SetBool(joinMap.CodecAvailable.JoinNumber, currentMeeting == null); + trilist.SetBool(joinMap.CodecMeetingBannerActive.JoinNumber, currentMeeting != null); + trilist.SetBool(joinMap.CodecMeetingBannerWarning.JoinNumber, warningBanner); } public void SetPresentationLocalOnly() @@ -2196,14 +2329,39 @@ public void LocalLayoutToggleSingleProminent() public void MinMaxLayoutToggle() { if (PresentationViewMaximizedFeedback.BoolValue) - _currentPresentationView = "Minimized"; - else - _currentPresentationView = "Maximized"; + { + PresentationViewMinimizedzedSet(); + return; + } + PresentationViewMaximizedSet(); + } + + public void PresentationViewDefaultSet() + { + _currentPresentationView = "Default"; - EnqueueCommand(string.Format("xCommand Video PresentationView Set View: {0}", _currentPresentationView)); + EnqueueCommand(string.Format("xCommand Video PresentationView Set View: {0}", _currentPresentationView)); PresentationViewMaximizedFeedback.FireUpdate(); } + public void PresentationViewMinimizedzedSet() + { + _currentPresentationView = "Minimized"; + + EnqueueCommand(string.Format("xCommand Video PresentationView Set View: {0}", _currentPresentationView)); + PresentationViewMaximizedFeedback.FireUpdate(); + + } + + public void PresentationViewMaximizedSet() + { + _currentPresentationView = "Maximized"; + + EnqueueCommand(string.Format("xCommand Video PresentationView Set View: {0}", _currentPresentationView)); + PresentationViewMaximizedFeedback.FireUpdate(); + + } + /// /// Calculates the current selfview PIP position /// @@ -2239,16 +2397,15 @@ public void CameraAutoModeToggle() { if (!CameraAutoModeIsOnFeedback.BoolValue) { - EnqueueCommand("xCommand Cameras SpeakerTrack Activate"); - } - else - { - EnqueueCommand("xCommand Cameras SpeakerTrack Deactivate"); + CameraAutoModeOn(); + return; } + CameraAutoModeOff(); } public void CameraAutoModeOn() { + if (!CodecStatus.Status.Cameras.SpeakerTrack.Availability.BoolValue) return; if (CameraIsOffFeedback.BoolValue) { CameraMuteOff(); @@ -2269,6 +2426,54 @@ public void CameraAutoModeOff() #endregion + public void PresenterTrackOff() + { + if (!CodecStatus.Status.Cameras.PresenterTrack.Availability.BoolValue) return; + if (CameraIsOffFeedback.BoolValue) + { + CameraMuteOff(); + } + + EnqueueCommand("xCommand Cameras PresenterTrack Set Mode: Off"); + } + + public void PresenterTrackFollow() + { + if (!CodecStatus.Status.Cameras.PresenterTrack.Availability.BoolValue) return; + if (CameraIsOffFeedback.BoolValue) + { + CameraMuteOff(); + } + + EnqueueCommand("xCommand Cameras PresenterTrack Set Mode: Follow"); + } + + public void PresenterTrackBackground() + { + if (!CodecStatus.Status.Cameras.PresenterTrack.Availability.BoolValue) return; + + if (CameraIsOffFeedback.BoolValue) + { + CameraMuteOff(); + } + + EnqueueCommand("xCommand Cameras PresenterTrack Set Mode: Background"); + } + + public void PresenterTrackPersistent() + { + if (!CodecStatus.Status.Cameras.PresenterTrack.Availability.BoolValue) return; + if (CameraIsOffFeedback.BoolValue) + { + CameraMuteOff(); + } + + EnqueueCommand("xCommand Cameras PresenterTrack Set Mode: Persistent"); + } + + + + /// /// Builds the cameras List. Could later be modified to build from config data /// @@ -2769,31 +2974,11 @@ public void UpdateDeviceInfo() raiseEvent(this, args); } } - - - - - } - public class CiscoSparkCodecFactory : EssentialsDeviceFactory - { - public CiscoSparkCodecFactory() - { - TypeNames = new List() { "ciscoRoomOS"}; - } - - public override EssentialsDevice BuildDevice(DeviceConfig dc) - { - Debug.Console(1, "Factory Attempting to create new Cisco RoomOs Device"); - - var comm = CommFactory.CreateCommForDevice(dc); - return new CiscoCodec(dc, comm); - } - } } \ No newline at end of file diff --git a/epi-videoCodec-ciscoExtended/epi-videoCodec-ciscoExtended.csproj b/epi-videoCodec-ciscoExtended/epi-videoCodec-ciscoExtended.csproj index 50edb04..b1d7543 100644 --- a/epi-videoCodec-ciscoExtended/epi-videoCodec-ciscoExtended.csproj +++ b/epi-videoCodec-ciscoExtended/epi-videoCodec-ciscoExtended.csproj @@ -105,6 +105,7 @@ + diff --git a/epi-videoCodec-ciscoExtended/xConfiguration.cs b/epi-videoCodec-ciscoExtended/xConfiguration.cs index d362310..f853bc1 100644 --- a/epi-videoCodec-ciscoExtended/xConfiguration.cs +++ b/epi-videoCodec-ciscoExtended/xConfiguration.cs @@ -1,14 +1,8 @@ using System; using System.Collections.Generic; -using System.Linq; -using System.Text; - -using Crestron.SimplSharp; - using PepperDash.Core; using Newtonsoft.Json; -using Newtonsoft.Json.Linq; namespace epi_videoCodec_ciscoExtended diff --git a/epi-videoCodec-ciscoExtended/xEvent.cs b/epi-videoCodec-ciscoExtended/xEvent.cs index bc3d99d..d0a7848 100644 --- a/epi-videoCodec-ciscoExtended/xEvent.cs +++ b/epi-videoCodec-ciscoExtended/xEvent.cs @@ -1,10 +1,4 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using Crestron.SimplSharp; - -namespace epi_videoCodec_ciscoExtended +namespace epi_videoCodec_ciscoExtended { /// /// This class exists to capture serialized data sent back by a Cisco codec in JSON output mode diff --git a/epi-videoCodec-ciscoExtended/xStatus.cs b/epi-videoCodec-ciscoExtended/xStatus.cs index ff6ccea..304e34c 100644 --- a/epi-videoCodec-ciscoExtended/xStatus.cs +++ b/epi-videoCodec-ciscoExtended/xStatus.cs @@ -28,7 +28,6 @@ protected void OnValueChanged() /// public class CiscoCodecStatus { - public class ConnectionStatus { public string Value { get; set; } @@ -374,16 +373,49 @@ public SpeakerTrack() } } + public class PresenterTrack + { + public Availability Availability { get; set; } + public Status11 Status { get; set; } + + public PresenterTrack() + { + Status = new Status11(); + Availability = new Availability(); + } + + } + + public class Status11 : ValueProperty + { + string _Value; + public string Value + { + get + { + return _Value; + } + set + { + // If the incoming value is "Active" it sets the BoolValue true, otherwise sets it false + _Value = value; + OnValueChanged(); + } + } + } + public class Cameras { // [JsonConverter(typeof(CameraConverter))] public List Camera { get; set; } public SpeakerTrack SpeakerTrack { get; set; } + public PresenterTrack PresenterTrack { get; set; } public Cameras() { Camera = new List(); SpeakerTrack = new SpeakerTrack(); + PresenterTrack = new PresenterTrack(); } } @@ -2283,7 +2315,7 @@ public RoomPreset() Type = new Type5(); } - public PresetBase ReturnConvertedCodecPreset() + public PresetBase ConvertCodecPreset() { try { @@ -2323,6 +2355,7 @@ public class CurrentLayouts public CurrentLayouts() { AvailableLayouts = new List(); + ActiveLayout = new ActiveLayout(); } } diff --git a/packages.config b/packages.config index f05b44c..b3a5914 100644 --- a/packages.config +++ b/packages.config @@ -1,3 +1,3 @@ - + \ No newline at end of file From 9a962e10bcd66573344b38de3759cca6fe46c0ce Mon Sep 17 00:00:00 2001 From: Trevor Payne Date: Tue, 6 Sep 2022 00:14:07 -0500 Subject: [PATCH 5/8] Tested working in BAML Lab --- .../BookingsDataClasses.cs | 27 +- epi-videoCodec-ciscoExtended/CiscoCamera.cs | 14 +- .../CiscoCodecConfig.cs | 23 + .../CiscoCodecJoinMap.cs | 173 +- .../CiscoRoomOsCodec.cs | 2080 ++++++++++++----- .../IHasCiscoCodecLayouts.cs | 33 + .../epi-videoCodec-ciscoExtended.csproj | 5 +- epi-videoCodec-ciscoExtended/xStatus.cs | 104 +- 8 files changed, 1877 insertions(+), 582 deletions(-) create mode 100644 epi-videoCodec-ciscoExtended/IHasCiscoCodecLayouts.cs diff --git a/epi-videoCodec-ciscoExtended/BookingsDataClasses.cs b/epi-videoCodec-ciscoExtended/BookingsDataClasses.cs index 44ab23e..9ce501e 100644 --- a/epi-videoCodec-ciscoExtended/BookingsDataClasses.cs +++ b/epi-videoCodec-ciscoExtended/BookingsDataClasses.cs @@ -228,7 +228,7 @@ public class CallType public string Value { get; set; } } - public class Call + public class CiscoCall { public string id { get; set; } public Number Number { get; set; } @@ -239,7 +239,7 @@ public class Call public class Calls { - public List Call { get; set; } + public List Call { get; set; } } public class ConnectMode @@ -313,32 +313,34 @@ public class RootObject /// /// /// - public static List GetGenericMeetingsFromBookingResult(List bookings) + public static List GetGenericMeetingsFromBookingResult(List bookings, int joinableCooldownSeconds) { var meetings = new List(); - if (Debug.Level > 0) - { - Debug.Console(1, "Meetings List:\n"); - } foreach (Booking b in bookings) { - var meeting = new Meeting(); + var meeting = new Meeting(joinableCooldownSeconds); if (b.Id != null) meeting.Id = b.Id.Value; + if (b.Organizer != null) meeting.Organizer = string.Format("{0}, {1}", b.Organizer.LastName.Value, b.Organizer.FirstName.Value); + if (b.Title != null) meeting.Title = b.Title.Value; + if (b.Agenda != null) meeting.Agenda = b.Agenda.Value; + if (b.Time != null) { meeting.StartTime = b.Time.StartTime.Value; + meeting.MinutesBeforeMeeting = Int32.Parse(b.Time.StartTimeBuffer.Value) / 60; meeting.EndTime = b.Time.EndTime.Value; } + if (b.Privacy != null) meeting.Privacy = CodecCallPrivacy.ConvertToDirectionEnum(b.Privacy.Value); @@ -349,27 +351,26 @@ public static List GetGenericMeetingsFromBookingResult(List bo if (b.DialInfo.Calls.Call != null) { - foreach (Call c in b.DialInfo.Calls.Call) + + foreach (CiscoCall c in b.DialInfo.Calls.Call) { - meeting.Calls.Add(new PepperDash.Essentials.Devices.Common.Codec.Call() + meeting.Calls.Add(new Call() { Number = c.Number.Value, Protocol = c.Protocol.Value, CallRate = c.CallRate.Value, CallType = c.CallType.Value }); + } } meetings.Add(meeting); - if (Debug.Level > 0) - { Debug.Console(1, "Title: {0}, ID: {1}, Organizer: {2}, Agenda: {3}", meeting.Title, meeting.Id, meeting.Organizer, meeting.Agenda); Debug.Console(1, " Start Time: {0}, End Time: {1}, Duration: {2}", meeting.StartTime, meeting.EndTime, meeting.Duration); Debug.Console(1, " Joinable: {0}\n", meeting.Joinable); - } } meetings.OrderBy(m => m.StartTime); diff --git a/epi-videoCodec-ciscoExtended/CiscoCamera.cs b/epi-videoCodec-ciscoExtended/CiscoCamera.cs index 7e4a4c9..e309e33 100644 --- a/epi-videoCodec-ciscoExtended/CiscoCamera.cs +++ b/epi-videoCodec-ciscoExtended/CiscoCamera.cs @@ -37,12 +37,12 @@ public void PositionHome() public void PanLeft() { - ParentCodec.EnqueueCommand(string.Format("xCommand Call FarEndControl Camera Move Value: Left CallId: {0}", CallId)); + ParentCodec.EnqueueCommand(string.Format("xCommand CiscoCall FarEndControl Camera Move Value: Left CallId: {0}", CallId)); } public void PanRight() { - ParentCodec.EnqueueCommand(string.Format("xCommand Call FarEndControl Camera Move Value: Right CallId: {0}", CallId)); + ParentCodec.EnqueueCommand(string.Format("xCommand CiscoCall FarEndControl Camera Move Value: Right CallId: {0}", CallId)); } public void PanStop() @@ -56,12 +56,12 @@ public void PanStop() public void TiltDown() { - ParentCodec.EnqueueCommand(string.Format("xCommand Call FarEndControl Camera Move Value: Down CallId: {0}", CallId)); + ParentCodec.EnqueueCommand(string.Format("xCommand CiscoCall FarEndControl Camera Move Value: Down CallId: {0}", CallId)); } public void TiltUp() { - ParentCodec.EnqueueCommand(string.Format("xCommand Call FarEndControl Camera Move Value: Up CallId: {0}", CallId)); + ParentCodec.EnqueueCommand(string.Format("xCommand CiscoCall FarEndControl Camera Move Value: Up CallId: {0}", CallId)); } public void TiltStop() @@ -75,12 +75,12 @@ public void TiltStop() public void ZoomIn() { - ParentCodec.EnqueueCommand(string.Format("xCommand Call FarEndControl Camera Move Value: ZoomIn CallId: {0}", CallId)); + ParentCodec.EnqueueCommand(string.Format("xCommand CiscoCall FarEndControl Camera Move Value: ZoomIn CallId: {0}", CallId)); } public void ZoomOut() { - ParentCodec.EnqueueCommand(string.Format("xCommand Call FarEndControl Camera Move Value: ZoomOut CallId: {0}", CallId)); + ParentCodec.EnqueueCommand(string.Format("xCommand CiscoCall FarEndControl Camera Move Value: ZoomOut CallId: {0}", CallId)); } public void ZoomStop() @@ -93,7 +93,7 @@ public void ZoomStop() void Stop() { - ParentCodec.EnqueueCommand(string.Format("xCommand Call FarEndControl Camera Stop CallId: {0}", CallId)); + ParentCodec.EnqueueCommand(string.Format("xCommand CiscoCall FarEndControl Camera Stop CallId: {0}", CallId)); } public void LinkToApi(BasicTriList trilist, uint joinStart, string joinMapKey, EiscApiAdvanced bridge) diff --git a/epi-videoCodec-ciscoExtended/CiscoCodecConfig.cs b/epi-videoCodec-ciscoExtended/CiscoCodecConfig.cs index b041118..852a95b 100644 --- a/epi-videoCodec-ciscoExtended/CiscoCodecConfig.cs +++ b/epi-videoCodec-ciscoExtended/CiscoCodecConfig.cs @@ -44,12 +44,35 @@ public class CiscoCodecConfig [JsonProperty("phonebookResultsLimit")] public uint PhonebookResultsLimit { get; set; } + [JsonProperty("overrideMeetingsLimit")] + public bool OverrideMeetingsLimit { get; set; } + + [JsonProperty("phonebookDisableAutoPopulate")] + public bool PhonebookDisableAutoPopulate { get; set; } + + [JsonProperty("phonebookDisableAutoDial")] + public bool PhonebookDisableAutoDial { get; set; } + [JsonProperty("UiBranding")] public BrandingLogoProperties UiBranding { get; set; } [JsonProperty("cameraInfo")] public List CameraInfo { get; set; } + [JsonProperty("defaultTrackingMode")] + public string DefaultCameraTrackingMode { get; set; } + //Valid options "speakerTrack", "presenterTrack", "speaker", or "presenter" + + [JsonProperty("timeFormatSpecifier")] + public string TimeFormatSpecifier { get; set; } + + [JsonProperty("dateFormatSpecifier")] + public string DateFormatSpecifier { get; set; } + + [JsonProperty("joinableCooldownSeconds")] + public int JoinableCooldownSeconds { get; set; } + + public CiscoCodecConfig() { diff --git a/epi-videoCodec-ciscoExtended/CiscoCodecJoinMap.cs b/epi-videoCodec-ciscoExtended/CiscoCodecJoinMap.cs index 3fec50f..b61c7c8 100644 --- a/epi-videoCodec-ciscoExtended/CiscoCodecJoinMap.cs +++ b/epi-videoCodec-ciscoExtended/CiscoCodecJoinMap.cs @@ -24,21 +24,6 @@ public class CiscoCodecJoinMap : VideoCodecControllerJoinMap }); - [JoinName("PresenterTrackEnabled")] - public JoinDataComplete PresenterTrackEnabled = new JoinDataComplete( - new JoinData - { - JoinNumber = 130, - JoinSpan = 1 - }, - new JoinMetadata - { - Description = "Presenter Track Enabled Feedback", - JoinCapabilities = eJoinCapabilities.ToSIMPL, - JoinType = eJoinType.Digital - }); - - [JoinName("PresenterTrackOff")] public JoinDataComplete PresenterTrackOff = new JoinDataComplete( new JoinData @@ -92,6 +77,50 @@ public class CiscoCodecJoinMap : VideoCodecControllerJoinMap JoinCapabilities = eJoinCapabilities.ToFromSIMPL, JoinType = eJoinType.Digital }); + [JoinName("SpeakerTrackAvailable")] + public JoinDataComplete SpeakerTrackAvailable = new JoinDataComplete( + new JoinData + { + JoinNumber = 145, + JoinSpan = 1 + }, + new JoinMetadata + { + Description = "Speaker Track Available", + JoinCapabilities = eJoinCapabilities.ToSIMPL, + JoinType = eJoinType.Digital + }); + + [JoinName("PresenterTrackAvailable")] + public JoinDataComplete PresenterTrackAvailable = new JoinDataComplete( + new JoinData + { + JoinNumber = 146, + JoinSpan = 1 + }, + new JoinMetadata + { + Description = "Presenter Track Availble", + JoinCapabilities = eJoinCapabilities.ToSIMPL, + JoinType = eJoinType.Digital + }); + + [JoinName("DialActiveMeeting")] + public JoinDataComplete DialActiveMeeting = new JoinDataComplete( + new JoinData + { + JoinNumber = 159, + JoinSpan = 1 + }, + new JoinMetadata + { + Description = "Presenter Track Availble", + JoinCapabilities = eJoinCapabilities.FromSIMPL, + JoinType = eJoinType.Digital + }); + + + [JoinName("DialMeeting4")] public JoinDataComplete DialMeeting4 = new JoinDataComplete( @@ -122,6 +151,21 @@ public class CiscoCodecJoinMap : VideoCodecControllerJoinMap }); + [JoinName("PresentationActive")] + public JoinDataComplete PresentationActive = new JoinDataComplete( + new JoinData + { + JoinNumber = 200, + JoinSpan = 1 + }, + new JoinMetadata + { + Description = "Presentation Active", + JoinCapabilities = eJoinCapabilities.ToSIMPL, + JoinType = eJoinType.Digital + }); + + [JoinName("PresentationLocalOnly")] public JoinDataComplete PresentationLocalOnly = new JoinDataComplete( new JoinData @@ -150,6 +194,20 @@ public class CiscoCodecJoinMap : VideoCodecControllerJoinMap JoinType = eJoinType.Digital }); + [JoinName("ResumeAllCalls")] + public JoinDataComplete ResumeAllCalls = new JoinDataComplete( + new JoinData + { + JoinNumber = 230, + JoinSpan = 1 + }, + new JoinMetadata + { + Description = "Resume all held calls", + JoinCapabilities = eJoinCapabilities.FromSIMPL, + JoinType = eJoinType.Digital + }); + [JoinName("PresentationLocalRemoteToggle")] public JoinDataComplete PresentationLocalRemoteToggle = new JoinDataComplete( new JoinData @@ -165,6 +223,7 @@ public class CiscoCodecJoinMap : VideoCodecControllerJoinMap }); + [JoinName("ActivateDoNotDisturbMode")] public JoinDataComplete ActivateDoNotDisturbMode = new JoinDataComplete( new JoinData @@ -369,19 +428,51 @@ public class CiscoCodecJoinMap : VideoCodecControllerJoinMap JoinType = eJoinType.Analog }); - [JoinName("DirectorySelectRowFeedback")] - public JoinDataComplete DirectorySelectRowFeedback = new JoinDataComplete( + [JoinName("TotalMinutesUntilMeeting")] + public JoinDataComplete TotalMinutesUntilMeeting = new JoinDataComplete( + new JoinData + { + JoinNumber = 42, + JoinSpan = 1 + }, + new JoinMetadata + { + Description = "Total minutes until next meeting", + JoinCapabilities = eJoinCapabilities.ToSIMPL, + JoinType = eJoinType.Analog + }); + + + [JoinName("HoursUntilMeeting")] + public JoinDataComplete HoursUntilMeeting = new JoinDataComplete( new JoinData { - JoinNumber = 101, + JoinNumber = 43, JoinSpan = 1 }, new JoinMetadata { - Description = "Directory Select Row Feedback", + Description = "Hours until next meeting", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Analog }); + [JoinName("MinutesUntilMeeting")] + public JoinDataComplete MinutesUntilMeeting = new JoinDataComplete( + new JoinData + { + JoinNumber = 44, + JoinSpan = 1 + }, + new JoinMetadata + { + Description = "Minutes until next meeting", + JoinCapabilities = eJoinCapabilities.ToSIMPL, + JoinType = eJoinType.Analog + }); + + + + [JoinName("PresentationSource")] @@ -417,6 +508,50 @@ public class CiscoCodecJoinMap : VideoCodecControllerJoinMap JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Serial }); + [JoinName("ActiveMeetingData")] + public JoinDataComplete ActiveMeetingDataXSig = new JoinDataComplete( + new JoinData + { + JoinNumber = 104, + JoinSpan = 1 + }, + new JoinMetadata + { + Description = "XSig Containing Data for Active Meeting", + JoinCapabilities = eJoinCapabilities.ToSIMPL, + JoinType = eJoinType.Serial + }); + [JoinName("AvailableTimeRemaining")] + public JoinDataComplete AvailableTimeRemaining = new JoinDataComplete( + new JoinData + { + JoinNumber = 105, + JoinSpan = 1 + }, + new JoinMetadata + { + Description = "Formatted String Showing Time until room no longer available" + + "", + JoinCapabilities = eJoinCapabilities.ToSIMPL, + JoinType = eJoinType.Serial + }); + [JoinName("TimeToNextMeeting")] + public JoinDataComplete TimeToNextMeeting = new JoinDataComplete( + new JoinData + { + JoinNumber = 106, + JoinSpan = 1 + }, + new JoinMetadata + { + Description = "Formatted String Showing Time to next meeting" + + "", + JoinCapabilities = eJoinCapabilities.ToSIMPL, + JoinType = eJoinType.Serial + }); + + + #endregion diff --git a/epi-videoCodec-ciscoExtended/CiscoRoomOsCodec.cs b/epi-videoCodec-ciscoExtended/CiscoRoomOsCodec.cs index 4b1140c..5348a76 100644 --- a/epi-videoCodec-ciscoExtended/CiscoRoomOsCodec.cs +++ b/epi-videoCodec-ciscoExtended/CiscoRoomOsCodec.cs @@ -1,10 +1,13 @@ using System; using System.Collections.Generic; +using System.Globalization; using System.Linq; using System.Text; using System.Text.RegularExpressions; using Crestron.SimplSharp; using Crestron.SimplSharp.CrestronIO; +using Crestron.SimplSharpPro; +using Crestron.SimplSharpPro.CrestronThread; using Crestron.SimplSharpPro.DeviceSupport; using Newtonsoft.Json; using Newtonsoft.Json.Linq; @@ -22,31 +25,92 @@ using PepperDash.Essentials.Devices.Common.Codec; using PepperDash.Essentials.Devices.Common.VideoCodec; using PepperDash.Essentials.Core.Queues; +using Feedback = PepperDash.Essentials.Core.Feedback; namespace epi_videoCodec_ciscoExtended { - enum eCommandType { SessionStart, SessionEnd, Command, GetStatus, GetConfiguration }; - public enum eExternalSourceType { camera, desktop, document_camera, mediaplayer, PC, whiteboard, other } - public enum eExternalSourceMode { Ready, NotReady, Hidden, Error } - public enum eCodecPresentationStates { LocalOnly, LocalRemote } + internal enum eCommandType + { + SessionStart, + SessionEnd, + Command, + GetStatus, + GetConfiguration + }; + + public enum eExternalSourceType + { + camera, + desktop, + document_camera, + mediaplayer, + PC, + whiteboard, + other + } + + public enum eExternalSourceMode + { + Ready, + NotReady, + Hidden, + Error + } + + public enum eCodecPresentationStates + { + LocalOnly, + LocalRemote + } + + public enum eCameraTrackingCapabilities + { + None, + SpeakerTrack, + PresenterTrack, + Both + } - public class CiscoCodec : VideoCodecBase, IHasCallHistory, IHasCallFavorites, IHasDirectory, + public class CiscoCodec : VideoCodecBase, IHasCallHistory, IHasCallFavorites, IHasDirectoryClearSelection, IHasScheduleAwareness, IOccupancyStatusProvider, IHasCodecLayoutsAvailable, IHasCodecSelfView, ICommunicationMonitor, IRouting, IHasCodecCameras, IHasCameraAutoMode, IHasCodecRoomPresets, IHasExternalSourceSwitching, IHasBranding, IHasCameraOff, IHasCameraMute, IHasDoNotDisturbMode, IHasHalfWakeMode, IHasCallHold, IJoinCalls, IDeviceInfoProvider { - public event EventHandler AvailableLayoutsChanged; + + + public event EventHandler AvailableLayoutsChanged; + public event EventHandler CurrentLayoutChanged; + private event EventHandler MinuteChanged; + public EventHandler CodecInfoChanged; + + + public event EventHandler CameraTrackingCapabilitiesChanged; + + public eCameraTrackingCapabilities CameraTrackingCapabilities { get; private set; } + + private CTimer _scheduleCheckTimer; + private DateTime _scheduleCheckLast; + + public Meeting ActiveMeeting { get; private set; } private const int XSigEncoding = 28591; private const string TestedCodecFirmware = "10.11.5.2"; + private Meeting _currentMeeting; + private bool _validFirmware; + private bool _presentationActive; + private readonly bool _phonebookAutoPopulate; + private bool _phonebookInitialSearch; + + private string _lastSearched; private CiscoCodecConfig _config; + private readonly int _joinableCooldownSeconds; public eCodecPresentationStates PresentationStates; @@ -54,6 +118,8 @@ public class CiscoCodec : VideoCodecBase, IHasCallHistory, IHasCallFavorites, IH public event EventHandler DirectoryResultReturned; + private readonly bool _meetingsOverrideLimit; + private CTimer _brandingTimer; public CommunicationGather PortGather { get; private set; } @@ -68,13 +134,17 @@ public class CiscoCodec : VideoCodecBase, IHasCallHistory, IHasCallFavorites, IH public BoolFeedback PresentationViewDefaultFeedback { get; private set; } + public FeedbackGroup PresentationViewFeedbackGroup { get; private set; } + private string _currentPresentationView; + private eCameraTrackingCapabilities _preferredTrackingMode { get; set; } + public BoolFeedback RoomIsOccupiedFeedback { get; private set; } public IntFeedback PeopleCountFeedback { get; private set; } - public BoolFeedback CameraAutoModeIsOnFeedback { get; private set; } + private List _currentMeetings = new List(); public BoolFeedback SelfviewIsOnFeedback { get; private set; } @@ -82,29 +152,55 @@ public class CiscoCodec : VideoCodecBase, IHasCallHistory, IHasCallFavorites, IH public StringFeedback LocalLayoutFeedback { get; private set; } - private string _currentLayout = string.Empty; + public BoolFeedback PresentationActiveFeedback { get; private set; } + + private string _currentLayoutBacker; + + private string _currentLayout + { + get + { + if (_currentLayoutBacker != "Grid") return _currentLayoutBacker; + var reportedLayout = AvailableLayouts.FirstOrDefault(w => w.Label == "Grid"); + return reportedLayout == null ? "Side by Side" : _currentLayoutBacker; + } + set { _currentLayoutBacker = value; } + } - public StringFeedback AvailableLocalLayoutsFeedback { get; private set; } + public StringFeedback AvailableLayoutsFeedback { get; private set; } public BoolFeedback LocalLayoutIsProminentFeedback { get; private set; } public BoolFeedback FarEndIsSharingContentFeedback { get; private set; } - public StringFeedback PresenterTrackStatusNameFeedback { get; private set; } + #region AutoCamera Feedbacks + + public BoolFeedback CameraAutoModeIsOnFeedback { get; private set; } + public BoolFeedback SpeakerTrackStatusOnFeedback { get; private set; } + public BoolFeedback PresenterTrackStatusOnFeedback { get; private set; } - public BoolFeedback PresenterTrackEnabledFeedback { get; private set; } + public StringFeedback PresenterTrackStatusNameFeedback { get; private set; } public BoolFeedback PresenterTrackStatusOffFeedback { get; private set; } public BoolFeedback PresenterTrackStatusFollowFeedback { get; private set; } public BoolFeedback PresenterTrackStatusBackgroundFeedback { get; private set; } public BoolFeedback PresenterTrackStatusPersistentFeedback { get; private set; } + public BoolFeedback CameraAutoModeAvailableFeedback { get; private set; } + public BoolFeedback SpeakerTrackAvailableFeedback { get; private set; } + public BoolFeedback PresenterTrackAvailableFeedback { get; private set; } + + public FeedbackGroup PresenterTrackFeedbackGroup { get; private set; } + + #endregion + public IntFeedback RingtoneVolumeFeedback { get; private set; } - public List AvailableLocalLayouts { get; private set; } + public List AvailableLayouts { get; private set; } private CodecCommandWithLabel _currentSelfviewPipPosition; + /// /// List the available positions for the selfview PIP window /// @@ -206,19 +302,20 @@ protected Func RoomIsOccupiedFeedbackFunc get { return () => CodecStatus.Status.RoomAnalytics.PeoplePresence.BoolValue; } } - protected Func PeopleCountFeedbackFunc + protected Func PresentationActiveFeedbackFunc { - get { return () => CodecStatus.Status.RoomAnalytics.PeopleCount.Current.IntValue; } + get { return () => CodecStatus.Status.Conference.Presentation.Mode.Value != "Off"; } } - protected Func SpeakerTrackIsOnFeedbackFunc + protected Func PeopleCountFeedbackFunc { - get { return () => CodecStatus.Status.Cameras.SpeakerTrack.Status.BoolValue; } + get { return () => CodecStatus.Status.RoomAnalytics.PeopleCount.Current.IntValue; } } + protected Func AvailableLayoutsFeedbackFunc { - get { return () => UpdateLayoutsXSig(AvailableLocalLayouts); } + get { return () => UpdateLayoutsXSig(AvailableLayouts); } } protected Func SelfViewIsOnFeedbackFunc @@ -241,34 +338,78 @@ protected Func LocalLayoutIsProminentFeedbackFunc get { return () => _currentLayout.Contains("Prominent") || _currentLayout.Contains("Stack"); } } + #region CameraAutoTrackingFeedbackFunc + + + protected Func CameraTrackingAvailableFeedbackFunc + { + get + { + return () => CodecStatus.Status.Cameras.PresenterTrack.Availability.BoolValue + || CodecStatus.Status.Cameras.SpeakerTrack.Availability.BoolValue; + } + } + + protected Func CameraTrackingOnFeedbackFunc + { + get + { + return () => CodecStatus.Status.Cameras.SpeakerTrack.Status.BoolValue + || CodecStatus.Status.Cameras.PresenterTrack.Status.BoolValue; + } + } + + protected Func PresenterTrackAvailableFeedbackFunc + { + get { return () => CodecStatus.Status.Cameras.PresenterTrack.Availability.BoolValue; } + } + + protected Func SpeakerTrackAvailableFeedbackFunc + { + get { return () => CodecStatus.Status.Cameras.SpeakerTrack.Availability.BoolValue; } + } + + protected Func SpeakerTrackStatusOnFeedbackFunc + { + get { return () => CodecStatus.Status.Cameras.SpeakerTrack.Status.BoolValue; } + } + protected Func PresenterTrackStatusNameFeedbackFunc { - get { return () => CodecStatus.Status.Cameras.PresenterTrack.Status.Value; } + get { return () => CodecStatus.Status.Cameras.PresenterTrack.Status.StringValue; } } - protected Func PresenterTrackEnabledFeedbackFunc + protected Func PresenterTrackStatusOnFeedbackFunc { - get { return () => CodecStatus.Status.Cameras.PresenterTrack.Availability.Value == "Unavailable"; } + get + { + return () => ((CodecStatus.Status.Cameras.PresenterTrack.Status.StringValue.ToLower() != "off") + || (String.IsNullOrEmpty(CodecStatus.Status.Cameras.PresenterTrack.Status.StringValue))); + } } + protected Func PresenterTrackStatusOffFeedbackFunc { - get { return () => CodecStatus.Status.Cameras.PresenterTrack.Status.Value == "Off" || CodecStatus.Status.Cameras.PresenterTrack.Availability.Value == "Unavailable"; } + get { return () => CodecStatus.Status.Cameras.PresenterTrack.Status.StringValue.ToLower() == "off"; } } protected Func PresenterTrackStatusFollowFeedbackFunc { - get { return () => CodecStatus.Status.Cameras.PresenterTrack.Status.Value == "Follow"; } + get { return () => CodecStatus.Status.Cameras.PresenterTrack.Status.Value.ToLower() == "follow"; } } protected Func PresenterTrackStatusBackgroundFeedbackFunc { - get { return () => CodecStatus.Status.Cameras.PresenterTrack.Status.Value == "Background"; } + get { return () => CodecStatus.Status.Cameras.PresenterTrack.Status.Value.ToLower() == "background"; } } + protected Func PresenterTrackStatusPersistentFeedbackFunc { - get { return () => CodecStatus.Status.Cameras.PresenterTrack.Status.Value == "Persistent"; } - } + get { return () => CodecStatus.Status.Cameras.PresenterTrack.Status.Value.ToLower() == "persistent"; } + } + + #endregion @@ -285,7 +426,7 @@ protected Func PresenterTrackStatusPersistentFeedbackFunc public bool CommDebuggingIsOn; - string Delimiter = "\r\n"; + private string Delimiter = "\r\n"; public IntFeedback PresentationSourceFeedback { get; private set; } @@ -333,12 +474,35 @@ protected Func PresenterTrackStatusPersistentFeedbackFunc public CiscoCodec(DeviceConfig config, IBasicCommunication comm) : base(config) { + DeviceInfo = new DeviceInfo(); + _lastSearched = string.Empty; + _phonebookInitialSearch = true; + _currentLayout = string.Empty; PresentationStates = eCodecPresentationStates.LocalOnly; + var props = JsonConvert.DeserializeObject(config.Properties.ToString()); _config = props; + MeetingsToDisplay = _config.OverrideMeetingsLimit ? 50 : 0; + _timeFormatSpecifier = _config.TimeFormatSpecifier.NullIfEmpty() ?? "t"; + _dateFormatSpecifier = _config.DateFormatSpecifier.NullIfEmpty() ?? "d"; + _joinableCooldownSeconds = _config.JoinableCooldownSeconds; + + _preferredTrackingMode = eCameraTrackingCapabilities.SpeakerTrack; + + var trackingMode = _config.DefaultCameraTrackingMode.ToLower(); + + + if (!String.IsNullOrEmpty(trackingMode)) + { + if (trackingMode.Contains("presenter")) + { + _preferredTrackingMode = eCameraTrackingCapabilities.PresenterTrack; + } + } + // Use the configured phonebook results limit if present if (props.PhonebookResultsLimit > 0) { @@ -350,35 +514,69 @@ public CiscoCodec(DeviceConfig config, IBasicCommunication comm) RoomIsOccupiedFeedback = new BoolFeedback(RoomIsOccupiedFeedbackFunc); PeopleCountFeedback = new IntFeedback(PeopleCountFeedbackFunc); - CameraAutoModeIsOnFeedback = new BoolFeedback(SpeakerTrackIsOnFeedbackFunc); SelfviewIsOnFeedback = new BoolFeedback(SelfViewIsOnFeedbackFunc); SelfviewPipPositionFeedback = new StringFeedback(SelfviewPipPositionFeedbackFunc); LocalLayoutFeedback = new StringFeedback(LocalLayoutFeedbackFunc); LocalLayoutIsProminentFeedback = new BoolFeedback(LocalLayoutIsProminentFeedbackFunc); FarEndIsSharingContentFeedback = new BoolFeedback(FarEndIsSharingContentFeedbackFunc); CameraIsOffFeedback = new BoolFeedback(() => CodecStatus.Status.Video.Input.MainVideoMute.BoolValue); - AvailableLocalLayoutsFeedback = new StringFeedback(AvailableLayoutsFeedbackFunc); - PresenterTrackStatusNameFeedback = new StringFeedback(PresenterTrackStatusNameFeedbackFunc); + AvailableLayoutsFeedback = new StringFeedback(AvailableLayoutsFeedbackFunc); + + PresentationActiveFeedback = new BoolFeedback(PresentationActiveFeedbackFunc); + + #region CameraAutoFeedbackRegistration - PresenterTrackEnabledFeedback = new BoolFeedback(PresenterTrackEnabledFeedbackFunc); + CameraAutoModeIsOnFeedback = new BoolFeedback(CameraTrackingOnFeedbackFunc); + SpeakerTrackStatusOnFeedback = new BoolFeedback(SpeakerTrackStatusOnFeedbackFunc); + PresenterTrackStatusOnFeedback = new BoolFeedback(PresenterTrackStatusOnFeedbackFunc); + + PresenterTrackStatusNameFeedback = new StringFeedback(PresenterTrackStatusNameFeedbackFunc); PresenterTrackStatusOffFeedback = new BoolFeedback(PresenterTrackStatusOffFeedbackFunc); PresenterTrackStatusFollowFeedback = new BoolFeedback(PresenterTrackStatusFollowFeedbackFunc); PresenterTrackStatusBackgroundFeedback = new BoolFeedback(PresenterTrackStatusBackgroundFeedbackFunc); PresenterTrackStatusPersistentFeedback = new BoolFeedback(PresenterTrackStatusPersistentFeedbackFunc); + CameraAutoModeAvailableFeedback = new BoolFeedback(CameraTrackingAvailableFeedbackFunc); + PresenterTrackAvailableFeedback = new BoolFeedback(PresenterTrackAvailableFeedbackFunc); + SpeakerTrackAvailableFeedback = new BoolFeedback(SpeakerTrackAvailableFeedbackFunc); + + PresenterTrackFeedbackGroup = new FeedbackGroup(new FeedbackCollection() + { + PresenterTrackStatusOnFeedback, + PresenterTrackStatusNameFeedback, + PresenterTrackStatusOffFeedback, + PresenterTrackStatusFollowFeedback, + PresenterTrackStatusBackgroundFeedback, + PresenterTrackStatusPersistentFeedback, + }); + + #endregion + + + CameraIsMutedFeedback = CameraIsOffFeedback; SupportsCameraOff = true; DoNotDisturbModeIsOnFeedback = new BoolFeedback(() => CodecStatus.Status.Conference.DoNotDisturb.BoolValue); - HalfWakeModeIsOnFeedback = new BoolFeedback(() => CodecStatus.Status.Standby.State.Value.ToLower() == "halfwake"); - EnteringStandbyModeFeedback = new BoolFeedback(() => CodecStatus.Status.Standby.State.Value.ToLower() == "enteringstandby"); + HalfWakeModeIsOnFeedback = + new BoolFeedback(() => CodecStatus.Status.Standby.State.Value.ToLower() == "halfwake"); + EnteringStandbyModeFeedback = + new BoolFeedback(() => CodecStatus.Status.Standby.State.Value.ToLower() == "enteringstandby"); PresentationViewMaximizedFeedback = new BoolFeedback(() => _currentPresentationView == "Maximized"); PresentationViewMinimizedFeedback = new BoolFeedback(() => _currentPresentationView == "Minimized"); PresentationViewDefaultFeedback = new BoolFeedback(() => _currentPresentationView == "Default"); - RingtoneVolumeFeedback = new IntFeedback(() => CodecConfiguration.Configuration.Audio.SoundsAndAlerts.RingVolume.Volume); + PresentationViewFeedbackGroup = new FeedbackGroup(new FeedbackCollection() + { + PresentationViewMaximizedFeedback, + PresentationViewMinimizedFeedback, + PresentationViewDefaultFeedback + }); + + RingtoneVolumeFeedback = + new IntFeedback(() => CodecConfiguration.Configuration.Audio.SoundsAndAlerts.RingVolume.Volume); PresentationSourceFeedback = new IntFeedback(() => _presentationSource); PresentationSendingLocalOnlyFeedback = new BoolFeedback(() => _presentationLocalOnly); @@ -388,12 +586,14 @@ public CiscoCodec(DeviceConfig config, IBasicCommunication comm) if (props.CommunicationMonitorProperties != null) { - CommunicationMonitor = new GenericCommunicationMonitor(this, Communication, props.CommunicationMonitorProperties); + CommunicationMonitor = new GenericCommunicationMonitor(this, Communication, + props.CommunicationMonitorProperties); } else { - var command = string.Format("xCommand Peripherals HeartBeat ID: {0}{1}", CrestronEthernetHelper.ETHERNET_PARAMETER_TO_GET.GET_MAC_ADDRESS, Delimiter); - CommunicationMonitor = new GenericCommunicationMonitor(this, Communication, 30000, 120000, 300000, command); + var command = string.Format("xStatus SystemUnit Software Version\r"); + CommunicationMonitor = new GenericCommunicationMonitor(this, Communication, 30000, 120000, 300000, + command); } if (props.Sharing != null) @@ -404,6 +604,7 @@ public CiscoCodec(DeviceConfig config, IBasicCommunication comm) DeviceManager.AddDevice(CommunicationMonitor); _phonebookMode = props.PhonebookMode; + _phonebookAutoPopulate = !props.PhonebookDisableAutoPopulate; _syncState = new CodecSyncState(Key + "--Sync", this); @@ -415,7 +616,6 @@ public CiscoCodec(DeviceConfig config, IBasicCommunication comm) PortGather.IncludeDelimiter = true; PortGather.LineReceived += this.Port_LineReceived; - CodecInfo = new CiscoCodecInfo(CodecStatus, CodecConfiguration); CallHistory = new CodecCallHistory(); @@ -440,16 +640,18 @@ public CiscoCodec(DeviceConfig config, IBasicCommunication comm) //Set Feedback Actions SetFeedbackActions(); - CodecOsdIn = new RoutingInputPort(RoutingPortNames.CodecOsd, eRoutingSignalType.Audio | eRoutingSignalType.Video, + CodecOsdIn = new RoutingInputPort(RoutingPortNames.CodecOsd, + eRoutingSignalType.Audio | eRoutingSignalType.Video, eRoutingPortConnectionType.Hdmi, new Action(StopSharing), this); HdmiIn2 = new RoutingInputPort(RoutingPortNames.HdmiIn2, eRoutingSignalType.Audio | eRoutingSignalType.Video, eRoutingPortConnectionType.Hdmi, new Action(SelectPresentationSource1), this); HdmiIn3 = new RoutingInputPort(RoutingPortNames.HdmiIn3, eRoutingSignalType.Audio | eRoutingSignalType.Video, eRoutingPortConnectionType.Hdmi, new Action(SelectPresentationSource2), this); - - HdmiOut1 = new RoutingOutputPort(RoutingPortNames.HdmiOut1, eRoutingSignalType.Audio | eRoutingSignalType.Video, + HdmiOut1 = new RoutingOutputPort(RoutingPortNames.HdmiOut1, + eRoutingSignalType.Audio | eRoutingSignalType.Video, eRoutingPortConnectionType.Hdmi, null, this); - HdmiOut2 = new RoutingOutputPort(RoutingPortNames.HdmiOut2, eRoutingSignalType.Audio | eRoutingSignalType.Video, + HdmiOut2 = new RoutingOutputPort(RoutingPortNames.HdmiOut2, + eRoutingSignalType.Audio | eRoutingSignalType.Video, eRoutingPortConnectionType.Hdmi, null, this); InputPorts.Add(CodecOsdIn); @@ -471,15 +673,159 @@ public CiscoCodec(DeviceConfig config, IBasicCommunication comm) BrandingEnabled = props.UiBranding.Enable; _brandingUrl = props.UiBranding.BrandingUrl; + + AvailableLayoutsChanged += CiscoCodec_AvailableLayoutsChanged; + CurrentLayoutChanged += CiscoCodec_CurrentLayoutChanged; + CallStatusChange += CiscoCodec_CallStatusChange; + } + + private void ScheduleTimeCheck(object time) + { + DateTime currentTime; + + if (time != null) + { + var currentTimeString = (time as string); + if (String.IsNullOrEmpty(currentTimeString)) return; + currentTime = DateTime.ParseExact(currentTimeString, "o", CultureInfo.InvariantCulture); + } + else currentTime = DateTime.Now; + + if (_scheduleCheckLast == DateTime.MinValue) + { + _scheduleCheckLast = currentTime; + return; + } + if (currentTime.Minute == _scheduleCheckLast.Minute) return; + _scheduleCheckLast = currentTime; + OnMinuteChanged(currentTime); + } + + + + private void OnMinuteChanged(DateTime currentTime) + { + var handler = MinuteChanged; + if (MinuteChanged == null) return; + handler(this, new MinuteChangedEventArgs(currentTime)); + } + + private eCameraTrackingCapabilities SetDefaultTracking(string data) + { + try + { + var trackingMode = !data.ToLower().Contains("track") + ? data.ToLower() + "track" + : data.ToLower(); + return + (eCameraTrackingCapabilities) Enum.Parse(typeof (eCameraTrackingCapabilities), trackingMode, true); + + } + catch (Exception) + { + Debug.Console(0, this, "Unable to parse DefaultCameraTrackingMode - SpeakerTrack Set"); + return eCameraTrackingCapabilities.SpeakerTrack; + } + + } + + private void CiscoCodec_CallStatusChange(object sender, CodecCallStatusItemChangeEventArgs e) + { + var callPresent = ActiveCalls.Any(call => call.IsActiveCall); + if (callPresent) return; + OnAvailableLayoutsChanged(new List()); + OnCurrentLayoutChanged(String.Empty); + } + + public void DirectoryClearSelection() + { + DirectoryClearSelectionBase(); } - private int QuickDebugTest(string description, int data) + private string UpdateActiveMeetingXSig(Meeting currentMeeting) { - if (String.IsNullOrEmpty(description)) return 0; - Debug.Console(2, this, "{0} completed step {1}", description, data); - return ++data; + // TODO [ ] hotfix/videocodecbase-max-meeting-xsig-set + //const int _meetingsToDisplay = 3; + const int maxDigitals = 3; + const int maxStrings = 8; + const int offset = maxDigitals + maxStrings; + const int digitalIndex = maxStrings; //15 + const int stringIndex = 0; + const int meetingIndex = 0; + var meeting = currentMeeting; + var tokenArray = new XSigToken[offset]; + /* + * Digitals + * IsJoinable - 1 + * IsDialable - 2 + * IsAvailable - 3 + * + * Serials + * Organizer - 1 + * Title - 2 + * Start Date - 3 + * Start Time - 4 + * End Date - 5 + * End Time - 6 + * Id - 7 + * Active "StartTime - EndTime" - 8 + * TimeRemaining Text - 9 + * TimeRemaining MinutesRemaining Text - 10 + * TimeRemaining MinutesRemaining Analog - 11 + * + */ + if (meeting != null) + { + + //digitals + tokenArray[digitalIndex] = new XSigDigitalToken(digitalIndex + 1, meeting.Joinable); + tokenArray[digitalIndex + 1] = new XSigDigitalToken(digitalIndex + 2, meeting.Id != "0"); + tokenArray[digitalIndex + 2] = new XSigDigitalToken(digitalIndex + 3, true); + + //serials + tokenArray[stringIndex] = new XSigSerialToken(stringIndex + 1, meeting.Organizer); + tokenArray[stringIndex + 1] = new XSigSerialToken(stringIndex + 2, meeting.Title); + tokenArray[stringIndex + 2] = new XSigSerialToken(stringIndex + 3, + meeting.StartTime.ToString(_dateFormatSpecifier, Global.Culture)); + tokenArray[stringIndex + 3] = new XSigSerialToken(stringIndex + 4, + meeting.StartTime.ToString(_timeFormatSpecifier, Global.Culture)); + tokenArray[stringIndex + 4] = new XSigSerialToken(stringIndex + 5, + meeting.EndTime.ToString(_dateFormatSpecifier, Global.Culture)); + tokenArray[stringIndex + 5] = new XSigSerialToken(stringIndex + 6, + meeting.EndTime.ToString(_timeFormatSpecifier, Global.Culture)); + tokenArray[stringIndex + 6] = new XSigSerialToken(stringIndex + 7, meeting.Id); + tokenArray[stringIndex + 7] = new XSigSerialToken(stringIndex + 8, String.Format("{0} - {1}", + meeting.StartTime.ToString(_timeFormatSpecifier, Global.Culture), + meeting.EndTime.ToString(_timeFormatSpecifier, Global.Culture))); + + } + + else + { + Debug.Console(2, this, "Clearing unused data. Meeting Index: {0} MaxMeetings * Offset: {1}", + meetingIndex, offset); + + //digitals + tokenArray[digitalIndex] = new XSigDigitalToken(digitalIndex + 1, false); + tokenArray[digitalIndex + 1] = new XSigDigitalToken(digitalIndex + 2, false); + tokenArray[digitalIndex + 2] = new XSigDigitalToken(digitalIndex + 3, false); + + + //serials + tokenArray[stringIndex] = new XSigSerialToken(stringIndex + 1, String.Empty); + tokenArray[stringIndex + 1] = new XSigSerialToken(stringIndex + 2, String.Empty); + tokenArray[stringIndex + 2] = new XSigSerialToken(stringIndex + 3, String.Empty); + tokenArray[stringIndex + 3] = new XSigSerialToken(stringIndex + 4, String.Empty); + tokenArray[stringIndex + 4] = new XSigSerialToken(stringIndex + 5, String.Empty); + tokenArray[stringIndex + 5] = new XSigSerialToken(stringIndex + 6, String.Empty); + tokenArray[stringIndex + 6] = new XSigSerialToken(stringIndex + 7, String.Empty); + tokenArray[stringIndex + 7] = new XSigSerialToken(stringIndex + 8, String.Empty); + } + + return GetXSigString(tokenArray); } + private void SetFeedbackActions() { CodecStatus.Status.Audio.Volume.ValueChangedAction = VolumeLevelFeedback.FireUpdate; @@ -498,9 +844,7 @@ private void SetFeedbackActions() CodecStatus.Status.RoomAnalytics.PeopleCount.Current.ValueChangedAction = PeopleCountFeedback.FireUpdate; - CodecStatus.Status.Cameras.SpeakerTrack.Status.ValueChangedAction = CameraAutoModeIsOnFeedback.FireUpdate; - CodecStatus.Status.Cameras.SpeakerTrack.Availability.ValueChangedAction = () => { SupportsCameraAutoMode = CodecStatus.Status.Cameras.SpeakerTrack.Availability.BoolValue; }; CodecStatus.Status.Video.Selfview.Mode.ValueChangedAction = SelfviewIsOnFeedback.FireUpdate; @@ -509,26 +853,50 @@ private void SetFeedbackActions() CodecStatus.Status.Video.Layout.CurrentLayouts.ActiveLayout.ValueChangedAction = LocalLayoutFeedback.FireUpdate; - CodecStatus.Status.Cameras.PresenterTrack.Status.ValueChangedAction = () => - { - PresenterTrackStatusBackgroundFeedback.FireUpdate(); - PresenterTrackStatusFollowFeedback.FireUpdate(); - PresenterTrackStatusOffFeedback.FireUpdate(); - PresenterTrackStatusPersistentFeedback.FireUpdate(); - }; - //CodecStatus.Status.Video.Layout.LayoutFamily.Local.ValueChangedAction = ComputeLocalLayout; CodecStatus.Status.Conference.Presentation.Mode.ValueChangedAction = () => { SharingContentIsOnFeedback.FireUpdate(); FarEndIsSharingContentFeedback.FireUpdate(); + PresentationActiveFeedback.FireUpdate(); }; CodecStatus.Status.Conference.DoNotDisturb.ValueChangedAction = DoNotDisturbModeIsOnFeedback.FireUpdate; - CodecConfiguration.Configuration.Audio.SoundsAndAlerts.RingVolume.ValueChangedAction = RingtoneVolumeFeedback.FireUpdate; + CodecConfiguration.Configuration.Audio.SoundsAndAlerts.RingVolume.ValueChangedAction = + RingtoneVolumeFeedback.FireUpdate; + + #region CameraTrackingFeedbackRegistration + + CodecStatus.Status.Cameras.SpeakerTrack.Status.ValueChangedAction = + () => + { + SpeakerTrackStatusOnFeedback.FireUpdate(); + CameraAutoModeIsOnFeedback.FireUpdate(); + }; + CodecStatus.Status.Cameras.PresenterTrack.Status.ValueChangedAction = + () => + { + PresenterTrackFeedbackGroup.FireUpdate(); + CameraAutoModeIsOnFeedback.FireUpdate(); + }; + CodecStatus.Status.Cameras.SpeakerTrack.Availability.ValueChangedAction = + () => + { + SpeakerTrackAvailableFeedback.FireUpdate(); + CameraAutoModeAvailableFeedback.FireUpdate(); + OnCameraTrackingCapabilitiesChanged(); + }; + CodecStatus.Status.Cameras.PresenterTrack.Availability.ValueChangedAction = + () => + { + PresenterTrackAvailableFeedback.FireUpdate(); + CameraAutoModeAvailableFeedback.FireUpdate(); + OnCameraTrackingCapabilitiesChanged(); + }; + #endregion try { @@ -549,7 +917,7 @@ private void SetFeedbackActions() /// Creates the fake OSD source, and connects it's AudioVideo output to the CodecOsdIn input /// to enable routing /// - void CreateOsdSource() + private void CreateOsdSource() { OsdSource = new DummyRoutingInputsDevice(Key + "[osd]"); DeviceManager.AddDevice(OsdSource); @@ -613,7 +981,10 @@ public void InitializeBranding(string roomKey) /// Mobile Control user code private void DisplayUserCode(string code) { - EnqueueCommand(string.Format("xcommand userinterface message alert display title:\"Mobile Control User Code:\" text:\"{0}\" duration: 30", code)); + EnqueueCommand( + string.Format( + "xcommand userinterface message alert display title:\"Mobile Control User Code:\" text:\"{0}\" duration: 30", + code)); } private void SendMcBrandingUrl(IMobileControlRoomBridge mcBridge) @@ -625,8 +996,10 @@ private void SendMcBrandingUrl(IMobileControlRoomBridge mcBridge) Debug.Console(1, this, "Sending url: {0}", mcBridge.QrCodeUrl); - EnqueueCommand("xconfiguration userinterface custommessage: \"Scan the QR code with a mobile phone to get started\""); - EnqueueCommand("xconfiguration userinterface osd halfwakemessage: \"Tap the touch panel or scan the QR code with a mobile phone to get started\""); + EnqueueCommand( + "xconfiguration userinterface custommessage: \"Scan the QR code with a mobile phone to get started\""); + EnqueueCommand( + "xconfiguration userinterface osd halfwakemessage: \"Tap the touch panel or scan the QR code with a mobile phone to get started\""); var checksum = !String.IsNullOrEmpty(mcBridge.QrCodeChecksum) ? String.Format("checksum: {0} ", mcBridge.QrCodeChecksum) @@ -645,26 +1018,61 @@ private void SendBrandingUrl() Debug.Console(1, this, "Sending url: {0}", _brandingUrl); EnqueueCommand(String.Format("xcommand userinterface branding fetch type: branding url: {0}", - _brandingUrl)); + _brandingUrl)); EnqueueCommand(String.Format("xcommand userinterface branding fetch type: halfwakebranding url: {0}", _brandingUrl)); } + /// /// Starts the HTTP feedback server and syncronizes state of codec /// /// public override bool CustomActivate() { - CrestronConsole.AddNewConsoleCommand(SetCommDebug, "SetCodecCommDebug", "0 for Off, 1 for on", ConsoleAccessLevelEnum.AccessOperator); - CrestronConsole.AddNewConsoleCommand(GetPhonebook, "GetCodecPhonebook", "Triggers a refresh of the codec phonebook", ConsoleAccessLevelEnum.AccessOperator); - CrestronConsole.AddNewConsoleCommand(GetBookings, "GetCodecBookings", "Triggers a refresh of the booking data for today", ConsoleAccessLevelEnum.AccessOperator); + CrestronConsole.AddNewConsoleCommand(SetCommDebug, "SetCodecCommDebug", "0 for Off, 1 for on", + ConsoleAccessLevelEnum.AccessOperator); + CrestronConsole.AddNewConsoleCommand(GetPhonebook, "GetCodecPhonebook", + "Triggers a refresh of the codec phonebook", ConsoleAccessLevelEnum.AccessOperator); + CrestronConsole.AddNewConsoleCommand(GetBookings, "GetCodecBookings", + "Triggers a refresh of the booking data for today", ConsoleAccessLevelEnum.AccessOperator); PhonebookSyncState.InitialSyncCompleted += PhonebookSyncState_InitialSyncCompleted; + CameraTrackingCapabilitiesChanged += CiscoCodec_CameraTrackingCapabilitiesChanged; + + + //Reserved for future use + CodecSchedule.MeetingsListHasChanged += (sender, args) => { }; + CodecSchedule.MeetingEventChange += (sender, args) => { }; + + + return base.CustomActivate(); } - void PhonebookSyncState_InitialSyncCompleted(object sender, EventArgs e) + private void CiscoCodec_CameraTrackingCapabilitiesChanged(object sender, CameraTrackingCapabilitiesArgs e) + { + if (e == null) return; + CameraTrackingCapabilities = e.CameraTrackingCapabilites; + SupportsCameraAutoMode = CameraTrackingCapabilities != eCameraTrackingCapabilities.None; + } + + private void CiscoCodec_AvailableLayoutsChanged(object sender, AvailableLayoutsChangedEventArgs e) + { + if (e == null) return; + AvailableLayouts = e.AvailableLayouts; + AvailableLayoutsFeedback.FireUpdate(); + } + + private void CiscoCodec_CurrentLayoutChanged(object sender, CurrentLayoutChangedEventArgs e) + { + if (e == null) return; + _currentLayout = e.CurrentLayout; + LocalLayoutFeedback.FireUpdate(); + } + + + private void PhonebookSyncState_InitialSyncCompleted(object sender, EventArgs e) { OnDirectoryResultReturned(DirectoryRoot); } @@ -673,6 +1081,8 @@ void PhonebookSyncState_InitialSyncCompleted(object sender, EventArgs e) public override void Initialize() { + CodecInfo = new CiscoCodecInfo(this); + var socket = Communication as ISocketStatus; if (socket != null) { @@ -688,33 +1098,40 @@ public override void Initialize() _cliFeedbackRegistrationExpression = prefix + "/Configuration" + Delimiter + prefix + "/Status/Audio" + Delimiter + - prefix + "/Status/Call" + Delimiter + + prefix + "/Status/CiscoCall" + Delimiter + prefix + "/Status/Conference/Presentation" + Delimiter + prefix + "/Status/Conference/DoNotDisturb" + Delimiter + prefix + "/Status/Cameras/SpeakerTrack" + Delimiter + + prefix + "/Status/Cameras/SpeakerTrack/Status" + Delimiter + + prefix + "/Status/Cameras/SpeakerTrack/Availability" + Delimiter + + prefix + "/Status/Cameras/PresenterTrack" + Delimiter + + prefix + "/Status/Cameras/PresenterTrack/Status" + Delimiter + + prefix + "/Status/Cameras/PresenterTrack/Availability" + Delimiter + prefix + "/Status/RoomAnalytics" + Delimiter + prefix + "/Status/RoomPreset" + Delimiter + prefix + "/Status/Standby" + Delimiter + prefix + "/Status/Video/Selfview" + Delimiter + - prefix + "/Status/MediaChannels/Call" + Delimiter + - prefix + "/Status/Video/Layout" + Delimiter + + prefix + "/Status/MediaChannels/CiscoCall" + Delimiter + + prefix + "/Status/Video/Layout/CurrentLayouts" + Delimiter + prefix + "/Status/Video/Input/MainVideoMute" + Delimiter + prefix + "/Bookings" + Delimiter + prefix + "/Event/Bookings" + Delimiter + prefix + "/Event/CameraPresetListUpdated" + Delimiter + prefix + "/Event/UserInterface/Presentation/ExternalSource/Selected/SourceIdentifier" + Delimiter + - prefix + "/Event/CallDisconnect" + Delimiter; // Keep CallDisconnect last to detect when feedback registration completes correctly + prefix + "/Event/CallDisconnect" + Delimiter; + // Keep CallDisconnect last to detect when feedback registration completes correctly } #endregion + /// /// Fires when initial codec sync is completed. Used to then send commands to get call history, phonebook, bookings, etc. /// /// /// - void SyncState_InitialSyncCompleted(object sender, EventArgs e) + private void SyncState_InitialSyncCompleted(object sender, EventArgs e) { // Check for camera config info first if (_config.CameraInfo.Count > 0) @@ -724,7 +1141,8 @@ void SyncState_InitialSyncCompleted(object sender, EventArgs e) } else { - Debug.Console(0, this, "No cameraInfo defined in video codec config. Attempting to get camera info from codec status data"); + Debug.Console(0, this, + "No cameraInfo defined in video codec config. Attempting to get camera info from codec status data"); try { var cameraInfo = new List(); @@ -734,15 +1152,20 @@ void SyncState_InitialSyncCompleted(object sender, EventArgs e) foreach (var camera in CodecStatus.Status.Cameras.Camera) { Debug.Console(0, this, -@"Camera id: {0} + @"Camera id: {0} Name: {1} ConnectorID: {2}" -, camera.id -, camera.Manufacturer.Value -, camera.Model.Value); + , camera.id + , camera.Manufacturer.Value + , camera.Model.Value); var id = Convert.ToUInt16(camera.id); - var info = new CameraInfo() { CameraNumber = id, Name = string.Format("{0} {1}", camera.Manufacturer.Value, camera.Model.Value), SourceId = camera.DetectedConnector.ConnectorId }; + var info = new CameraInfo() + { + CameraNumber = id, + Name = string.Format("{0} {1}", camera.Manufacturer.Value, camera.Model.Value), + SourceId = camera.DetectedConnector.ConnectorId + }; cameraInfo.Add(info); } @@ -760,10 +1183,12 @@ void SyncState_InitialSyncCompleted(object sender, EventArgs e) GetCallHistory(); - PhonebookRefreshTimer = new CTimer(CheckCurrentHour, 3600000, 3600000); // check each hour to see if the phonebook should be downloaded + PhonebookRefreshTimer = new CTimer(CheckCurrentHour, 3600000, 3600000); + // check each hour to see if the phonebook should be downloaded GetPhonebook(null); - BookingsRefreshTimer = new CTimer(GetBookings, 900000, 900000); // 15 minute timer to check for new booking info + BookingsRefreshTimer = new CTimer(GetBookings, 900000, 900000); + // 15 minute timer to check for new booking info GetBookings(null); // Fire the ready event @@ -784,7 +1209,7 @@ public void SetCommDebug(string s) } } - void socket_ConnectionChange(object sender, GenericSocketStatusChageEventArgs e) + private void socket_ConnectionChange(object sender, GenericSocketStatusChageEventArgs e) { Debug.Console(1, this, "Socket status change {0}", e.Client.ClientStatus); if (e.Client.IsConnected) @@ -811,7 +1236,7 @@ void socket_ConnectionChange(object sender, GenericSocketStatusChageEventArgs e) } } - void DisconnectClientAndReconnect() + private void DisconnectClientAndReconnect() { Debug.Console(1, this, "Retrying connection to codec."); @@ -830,7 +1255,7 @@ void DisconnectClientAndReconnect() /// /// /// - void Port_LineReceived(object dev, GenericCommMethodReceiveTextArgs args) + private void Port_LineReceived(object dev, GenericCommMethodReceiveTextArgs args) { if (CommDebuggingIsOn) { @@ -844,7 +1269,7 @@ void Port_LineReceived(object dev, GenericCommMethodReceiveTextArgs args) return; } - if (args.Text == "{" + Delimiter) // Check for the beginning of a new JSON message + if (args.Text == "{" + Delimiter) // Check for the beginning of a new JSON message { _jsonFeedbackMessageIsIncoming = true; @@ -853,7 +1278,7 @@ void Port_LineReceived(object dev, GenericCommMethodReceiveTextArgs args) _jsonMessage = new StringBuilder(); } - else if (args.Text == "}" + Delimiter) // Check for the end of a JSON message + else if (args.Text == "}" + Delimiter) // Check for the end of a JSON message { _jsonFeedbackMessageIsIncoming = false; @@ -882,32 +1307,32 @@ void Port_LineReceived(object dev, GenericCommMethodReceiveTextArgs args) switch (args.Text.Trim().ToLower()) // remove the whitespace { case "*r login successful": - { - _syncState.LoginMessageReceived(); + { + _syncState.LoginMessageReceived(); - if (_loginMessageReceivedTimer != null) - _loginMessageReceivedTimer.Stop(); + if (_loginMessageReceivedTimer != null) + _loginMessageReceivedTimer.Stop(); - //SendText("echo off"); - SendText("xPreferences outputmode json"); - break; - } + //SendText("echo off"); + SendText("xPreferences outputmode json"); + break; + } case "xpreferences outputmode json": - { - if (_syncState.JsonResponseModeSet) - return; + { + if (_syncState.JsonResponseModeSet) + return; - _syncState.JsonResponseModeMessageReceived(); + _syncState.JsonResponseModeMessageReceived(); - if (!_syncState.InitialStatusMessageWasReceived) - SendText("xStatus"); - break; - } + if (!_syncState.InitialStatusMessageWasReceived) + SendText("xStatus"); + break; + } case "xfeedback register /event/calldisconnect": - { - _syncState.FeedbackRegistered(); - break; - } + { + _syncState.FeedbackRegistered(); + break; + } } } } @@ -935,52 +1360,21 @@ public void SendText(string command) Communication.SendText(command + Delimiter); } - private static int CheckVersion(string minimum, string actual) + private static bool CheckVersion(string minimum, string actual) { var semanticActual = actual.Split('.').ToList(); var semanticMinimum = minimum.Split('.').ToList(); - var actualInt = semanticActual.ConvertAll(s => int.Parse(s)); - var minimumInt = semanticMinimum.ConvertAll(s => int.Parse(s)); - - var versionCheck = 0; - - for (var i = 0; i < actualInt.Count; i++) - { - var mod = 0; - switch (mod) - { - case 0: - mod = 1000; - break; - case 1: - mod = 100; - break; - case 2: - mod = 10; - break; - case 3: - mod = 1; - break; - } - - if (actualInt[i] > minimumInt[i]) - { - versionCheck = versionCheck + mod; - } - else if (actualInt[i] < minimumInt[i]) - { - versionCheck = versionCheck - mod; - } - } - - return versionCheck; - + var actualInt = semanticActual.ConvertAll(s => Int16.Parse(Regex.Replace(s, "[^0-9.]", ""))); + var minimumInt = semanticMinimum.ConvertAll(s => Int16.Parse(Regex.Replace(s, "[^0-9.]", ""))); + var minimumVer = new Version(minimumInt[0], minimumInt[1], minimumInt[2]); + var actualVer = new Version(actualInt[0], actualInt[1], actualInt[2]); + return actualVer.CompareTo(minimumVer) >= 0; } - void DeserializeResponse(string response) + private void DeserializeResponse(string response) { try { @@ -992,6 +1386,8 @@ void DeserializeResponse(string response) if (response.IndexOf("\"Status\":{") > -1 || response.IndexOf("\"Status\": {") > -1) { + + // Status Message // Temp object so we can inpsect for call data before simply deserializing @@ -1003,111 +1399,105 @@ void DeserializeResponse(string response) if (system != null && !_syncState.InitialSoftwareVersionMessageWasReceived) { - DeviceInfo.FirmwareVersion = system.Software.Version.Value ?? "Unknown"; - DeviceInfo.SerialNumber = system.Hardware.Module.SerialNumber.Value ?? "Unknown"; - - var parsedSoftware = system.Software.DisplayName.Value; - - if (parsedSoftware != null) + if (DeviceInfo != null) { - var first = ""; - var second = ""; - var third = ""; - var splitSoftware = parsedSoftware.Split(' '); - var ver = CheckVersion(TestedCodecFirmware, splitSoftware[1]); - if (ver != 0) - { - if (ver >= 889) - { - first = "Major"; - second = "greater"; - third = "significant"; - _validFirmware = false; - } - - else if (ver >= 89) - { - first = "Minor"; - second = "greater"; - third = "some"; - _validFirmware = false; - } - - else if (ver >= 9) - { - first = "Patch"; - second = "greater"; - third = "minor"; - _validFirmware = true; - } - - else if (ver <= -889) - { - first = "Major"; - second = "less"; - third = "significant"; - _validFirmware = false; - } + DeviceInfo.FirmwareVersion = system.Software.Version.Value ?? "Unknown"; + DeviceInfo.SerialNumber = system.Hardware.Module.SerialNumber.Value ?? "Unknown"; - else if (ver <= -89) - { - first = "minor"; - second = "less"; - third = "some"; - _validFirmware = false; - } - else if (ver <= -9) - { - first = "patch"; - second = "less"; - third = "minor"; - _validFirmware = true; + var parsedSoftware = system.Software.DisplayName.Value; - } - Debug.Console(0, this, - "Software {0} version is {1} than tested version - {2} api differences likely", - first, second, third); - } - else + if (parsedSoftware != null) { - Debug.Console(0, this, "Software version matches tested version"); - _validFirmware = true; + var splitSoftware = parsedSoftware.Split(' '); + if (!CheckVersion(TestedCodecFirmware, splitSoftware[1])) + Debug.Console(0, this, + "Be advised that codec Firmware does not support this plugin appropriately"); + } + _syncState.InitialSoftwareVersionMessageReceived(); + UpdateDeviceInfo(); } - _syncState.InitialSoftwareVersionMessageReceived(); - UpdateDeviceInfo(); + var multiSiteOptionEnabled = + bool.Parse( + CodecStatus.Status.SystemUnit.Software.OptionKeys.MultiSite.Value.NullIfEmpty() ?? + "false"); + OnCodecInfoChanged(new CodecInfoChangedEventArgs(eCodecInfoChangeType.Multisite) + { + MultiSiteOptionIsEnabled = multiSiteOptionEnabled + }); } - var network = tempCodecStatus.Status.Network; + + var status = tempCodecStatus.Status; + + var network = status == null ? null : status.Network; if (network != null) { - var myNetwork = network.FirstOrDefault(i => i.id == "1"); - if (myNetwork == null) return; - DeviceInfo.HostName = myNetwork.CDP.DeviceId.Value ?? "Unknown"; - DeviceInfo.IpAddress = myNetwork.IPv4.Address.Value ?? "Unknown"; - DeviceInfo.MacAddress = myNetwork.Ethernet.MacAddress.Value - ?? "Unknown"; - UpdateDeviceInfo(); - } + var myNetwork = network.FirstOrDefault(i => i.id == "1"); + if (myNetwork != null) + { + var hostname = myNetwork.CDP.DeviceId.Value.NullIfEmpty() ?? "Unknown"; + var ipAddress = myNetwork.IPv4.Address.Value.NullIfEmpty() ?? "Unknown"; + var macAddress = myNetwork.Ethernet.MacAddress.Value.NullIfEmpty() + ?? "Unknown"; - // Check to see if the message contains /Status/Conference/Presentation/LocalInstance and extract source value - var conference = tempCodecStatus.Status.Conference; + OnCodecInfoChanged(new CodecInfoChangedEventArgs(eCodecInfoChangeType.Network) {IpAddress = ipAddress}); - if (conference.Presentation != null && conference.Presentation.LocalInstance == null) - { - // Handles an empty presentation object response - return; + if (DeviceInfo != null) + { + DeviceInfo.HostName = hostname; + DeviceInfo.IpAddress = ipAddress; + DeviceInfo.MacAddress = macAddress; + UpdateDeviceInfo(); + } + } } - - if (conference.Presentation != null) + var sip = status == null ? null : status.SIP; + if (sip != null) { - if (conference.Presentation.LocalInstance.Count > 0) + string sipPhoneNumber; + string sipUri; + if (sip.Registration.Count > 0) { - if (!string.IsNullOrEmpty(conference.Presentation.LocalInstance[0].ghost)) + sipUri = sip.Registration[0].URI.Value.NullIfEmpty() ?? "Unknown"; + var match = Regex.Match(sipUri, @"(\d+)"); + sipPhoneNumber = match.Success ? match.Groups[1].Value : "Unknown"; + OnCodecInfoChanged(new CodecInfoChangedEventArgs(eCodecInfoChangeType.Sip) + { + SipPhoneNumber = sipPhoneNumber, + SipUri = sipUri + }); + } + } + + // Check to see if the message contains /Status/Conference/Presentation/LocalInstance and extract source value + + var conference = status == null ? null : status.Conference; + + if (conference != null && + (conference.Presentation != null && conference.Presentation.LocalInstance == null)) + { + + // Handles an empty presentation object response + //return; + } + + if (conference != null && conference.Presentation != null) + { + + if (conference.Presentation.LocalInstance != null && + conference.Presentation.LocalInstance.Count > 0) + { + if (conference.Presentation.Mode != null) + { + _presentationActive = conference.Presentation.Mode.Value != "Off"; + CodecPollLayouts(); + } + if (!string.IsNullOrEmpty(conference.Presentation.LocalInstance[0].ghost)) { _presentationSource = 0; _presentationLocalOnly = false; @@ -1135,39 +1525,89 @@ void DeserializeResponse(string response) } } - if (tempCodecStatus.Status.Video.Layout.CurrentLayouts.ActiveLayout != null) - { - _currentLayout = tempCodecStatus.Status.Video.Layout.CurrentLayouts.ActiveLayout.Value; - } - if (tempCodecStatus.Status.Video.Layout.CurrentLayouts.AvailableLayouts != null) + if ((response.IndexOf("\"CurrentLayouts\":{") > -1) || + (response.IndexOf("\"CurrentLayouts\": {") > -1)) { - if(AvailableLocalLayouts == null) - AvailableLocalLayouts = new List(); - AvailableLocalLayouts.Clear(); - foreach (var i in tempCodecStatus.Status.Video.Layout.CurrentLayouts.AvailableLayouts) + if (tempCodecStatus.Status.Video.Layout.CurrentLayouts != null) { - var r = i; - AvailableLocalLayouts.Add( new CodecCommandWithLabel(r.LayoutName.Value, r.LayoutName.Value )); + if ((response.IndexOf("\"AvailableLayouts\":[") > -1) || + (response.IndexOf("\"AvailableLayouts\": [") > -1)) + { + + if (tempCodecStatus.Status.Video.Layout.CurrentLayouts.AvailableLayouts != null) + { + Debug.Console(0, this, "We have parsed {0} Layouts", + tempCodecStatus.Status.Video.Layout.CurrentLayouts.AvailableLayouts.Count); + var availableLayouts = new List(); + + foreach ( + var i in tempCodecStatus.Status.Video.Layout.CurrentLayouts.AvailableLayouts) + { + var r = i; + Debug.Console(0, this, "Adding New layout {0}", r.LayoutName.Value); + availableLayouts.Add(new CodecCommandWithLabel(r.LayoutName.Value, + r.LayoutName.Value)); + } + OnAvailableLayoutsChanged(availableLayouts); + } + } + if ((response.IndexOf("\"ActiveLayout\":{") > -1) || + (response.IndexOf("\"ActiveLayout\": {") > -1)) + { + + if (tempCodecStatus.Status.Video.Layout.CurrentLayouts.ActiveLayout != null) + { + Debug.Console(2, this, "Populated ActiveLayout"); + + var currentLayout = + tempCodecStatus.Status.Video.Layout.CurrentLayouts.ActiveLayout.Value ?? + String.Empty; + Debug.Console(2, this, "CurrentLayout = \"{0}\"", currentLayout); + OnCurrentLayoutChanged(currentLayout); + } + } + } - AvailableLocalLayoutsFeedback.FireUpdate(); - OnAvailableLayoutsChanged(); } + var calls = status.Call ?? null; + // Check to see if this is a call status message received after the initial status message - if (tempCodecStatus.Status.Call.Count > 0) + if (calls != null && calls.Count > 0) { + if (calls.Count == 1 && !_presentationActive) + { + OnAvailableLayoutsChanged(new List()); + OnCurrentLayoutChanged(String.Empty); + } + + Debug.Console(0, this, "Parsing Calls"); // Iterate through the call objects in the response - foreach (var call in tempCodecStatus.Status.Call) + foreach (var c in calls) { - var currentCallType = tempCodecStatus.Status.MediaChannels.Call == null - ? null : CheckCallType(call.id, tempCodecStatus.Status.MediaChannels.Call); + var i = 1; + var call = c; + + var currentCallType = String.Empty; - var tempActiveCall = ActiveCalls.FirstOrDefault(c => c.Id.Equals(call.id)); + if (tempCodecStatus != null && tempCodecStatus.Status != null && + tempCodecStatus.Status.MediaChannels != null) + { + currentCallType = tempCodecStatus.Status.MediaChannels.Call == null + ? null + : CheckCallType(c.id, tempCodecStatus.Status.MediaChannels.Call); + } + + + Debug.Console(1, this, "Current CiscoCall Type = {0}", currentCallType); + var tempActiveCall = ActiveCalls.FirstOrDefault(x => x.Id.Equals(call.id)); if (tempActiveCall != null) { + Debug.Console(1, this, "tempActiveCall Not null"); + var changeDetected = false; var newStatus = eCodecCallStatus.Unknown; @@ -1180,31 +1620,47 @@ void DeserializeResponse(string response) tempActiveCall.IsOnHold = tempActiveCall.Status == eCodecCallStatus.OnHold; if (newStatus == eCodecCallStatus.Connected) + { + GetCallHistory(); + } changeDetected = true; } + if (call.CallType != null || currentCallType != null) - { - tempActiveCall.Type = CodecCallType.ConvertToTypeEnum(currentCallType ?? call.CallType.Value); - changeDetected = true; - } + { + + tempActiveCall.Type = + CodecCallType.ConvertToTypeEnum(currentCallType ?? call.CallType.Value); + changeDetected = true; + } + + + if (call.DisplayName != null) if (!string.IsNullOrEmpty(call.DisplayName.Value)) { tempActiveCall.Name = call.DisplayName.Value; changeDetected = true; } + + if (call.Direction != null) { + Debug.Console(1, this, "CiscoCall Direction Not Null"); if (!string.IsNullOrEmpty(call.Direction.Value)) { - tempActiveCall.Direction = CodecCallDirection.ConvertToDirectionEnum(call.Direction.Value); + tempActiveCall.Direction = + CodecCallDirection.ConvertToDirectionEnum(call.Direction.Value); changeDetected = true; } } if (call.Duration != null) { + Debug.Console(1, this, "CiscoCall Duration Not Null"); + + if (!string.IsNullOrEmpty(call.Duration.Value)) { tempActiveCall.Duration = call.Duration.DurationValue; @@ -1213,24 +1669,27 @@ void DeserializeResponse(string response) } if (call.PlacedOnHold != null) { + + tempActiveCall.IsOnHold = call.PlacedOnHold.BoolValue; changeDetected = true; } - if (changeDetected) - { - SetSelfViewMode(); - OnCallStatusChange(tempActiveCall); - ListCalls(); - } + if (!changeDetected) continue; + + SetSelfViewMode(); + OnCallStatusChange(tempActiveCall); + ListCalls(); + } - else if (call.ghost == null) // if the ghost value is present the call has ended already + else if (call.ghost == null) // if the ghost value is present the call has ended already { + Debug.Console(0, this, "IsGhost"); // Create a new call item var newCallItem = new CodecActiveCallItem() { - + Id = call.id, Status = CodecCallStatus.ConvertToStatusEnum(call.Status.Value), Name = call.DisplayName.Value, @@ -1241,13 +1700,19 @@ void DeserializeResponse(string response) IsOnHold = call.PlacedOnHold.BoolValue, }; + // Add it to the ActiveCalls List ActiveCalls.Add(newCallItem); ListCalls(); SetSelfViewMode(); + OnCallStatusChange(newCallItem); + + OnAvailableLayoutsChanged(new List()); + OnCurrentLayoutChanged(String.Empty); + } } @@ -1260,7 +1725,7 @@ void DeserializeResponse(string response) if (tempPresets.Count > 0) { // Create temporary list to store the existing items from the CiscoCodecStatus.RoomPreset collection - var existingRoomPresets = new List(); + var existingRoomPresets = new List(); // Add the existing items to the temporary list existingRoomPresets.AddRange(CodecStatus.Status.RoomPreset); // Populate the CodecStatus object (this will append new values to the RoomPreset collection @@ -1268,26 +1733,27 @@ void DeserializeResponse(string response) var jResponse = JObject.Parse(response); - var convertedRoomPresets = - existingRoomPresets.Select(a => (CiscoCodecStatus.RoomPreset) a).ToList(); - IList roomPresets = jResponse["Status"]["RoomPreset"].Children().ToList(); // Iterate the new items in this response agains the temporary list. Overwrite any existing items and add new ones. foreach (var camPreset in tempPresets) { - var preset = camPreset as CiscoCodecStatus.RoomPreset; + var preset = camPreset; if (preset == null) continue; // First fine the existing preset that matches the id - var existingPreset = convertedRoomPresets.FirstOrDefault(p => p.id.Equals(preset.id)); + var existingPreset = existingRoomPresets.FirstOrDefault(p => p.id.Equals(preset.id)); if (existingPreset != null) { - Debug.Console(1, this, "Existing Room Preset with ID: {0} found. Updating.", existingPreset.id); + Debug.Console(1, this, "Existing Room Preset with ID: {0} found. Updating.", + existingPreset.id); JToken updatedPreset = null; // Find the JToken from the response with the matching id - foreach (var jPreset in roomPresets.Where(jPreset => jPreset["id"].Value() == existingPreset.id)) + foreach ( + var jPreset in + roomPresets.Where(jPreset => jPreset["id"].Value() == existingPreset.id) + ) { updatedPreset = jPreset; } @@ -1310,7 +1776,8 @@ void DeserializeResponse(string response) CodecStatus.Status.RoomPreset = existingRoomPresets; // Generecise the list - NearEndPresets = existingRoomPresets.GetGenericPresets(); + NearEndPresets = + existingRoomPresets.GetGenericPresets(); var handler = CodecRoomPresetsListHasChanged; if (handler != null) @@ -1336,73 +1803,127 @@ void DeserializeResponse(string response) SendText(_cliFeedbackRegistrationExpression); } - + } } else if (response.IndexOf("\"Configuration\":{") > -1 || response.IndexOf("\"Configuration\": {") > -1) { // Configuration Message + Debug.Console(2, this, "Parse Configuration : {0}", response); + + JsonConvert.PopulateObject(response, CodecConfiguration); + if (CodecConfiguration != null) + { + var h323 = CodecConfiguration.Configuration.H323; + if (h323 != null) + { + string e164; + string h323Id; + if (h323.H323Alias != null) + { + e164 = h323.H323Alias.E164.Value.NullIfEmpty() ?? "unknown"; + h323Id = h323.H323Alias.ID.Value.NullIfEmpty() ?? "unknown"; + OnCodecInfoChanged(new CodecInfoChangedEventArgs(eCodecInfoChangeType.H323) {E164Alias = e164, H323Id = h323Id}); + } + } + bool autoAnswer; + if (CodecConfiguration.Configuration.Conference.AutoAnswer.Mode.Value == null) + autoAnswer = false; + else + { + autoAnswer = + CodecConfiguration.Configuration.Conference.AutoAnswer.Mode.Value.ToLower() == "on"; + } + OnCodecInfoChanged(new CodecInfoChangedEventArgs(eCodecInfoChangeType.AutoAnswer) {AutoAnswerEnabled = autoAnswer}); + } + if (!_syncState.InitialConfigurationMessageWasReceived) { + Debug.Console(2, this, "InitialConfig Received"); _syncState.InitialConfigurationMessageReceived(); if (!_syncState.InitialSoftwareVersionMessageWasReceived) { SendText("xStatus SystemUnit Software Version"); } - } } else if (response.IndexOf("\"Event\":{") > -1 || response.IndexOf("\"Event\": {") > -1) { + Debug.Console(2, this, "Parse Event : {0}", response); if (response.IndexOf("\"CallDisconnect\":{") > -1 || response.IndexOf("\"CallDisconnect\": {") > -1) { + Debug.Console(2, this, "Parse CallDisconnect"); CiscoCodecEvents.RootObject eventReceived = new CiscoCodecEvents.RootObject(); JsonConvert.PopulateObject(response, eventReceived); EvalutateDisconnectEvent(eventReceived); } - else if (response.IndexOf("\"Bookings\":{") > -1 || response.IndexOf("\"Bookings\": {") > -1) // The list has changed, reload it + else if (response.IndexOf("\"Bookings\":{") > -1 || response.IndexOf("\"Bookings\": {") > -1) + // The list has changed, reload it { + Debug.Console(2, this, "Parse Bookings"); + GetBookings(null); } - else if (response.IndexOf("\"UserInterface\":{") > -1 || response.IndexOf("\"UserInterface\": {") > -1) // External Source Trigger + else if (response.IndexOf("\"UserInterface\":{") > -1 || + response.IndexOf("\"UserInterface\": {") > -1) // External Source Trigger { + Debug.Console(2, this, "Parse UserInterface"); + CiscoCodecEvents.RootObject eventReceived = new CiscoCodecEvents.RootObject(); JsonConvert.PopulateObject(response, eventReceived); - Debug.Console(2, this, "*** Got an External Source Selection {0} {1}", eventReceived, eventReceived.Event.UserInterface, eventReceived.Event.UserInterface.Presentation.ExternalSource.Selected.SourceIdentifier.Value); + Debug.Console(2, this, "*** Got an External Source Selection {0} {1}", eventReceived, + eventReceived.Event.UserInterface, + eventReceived.Event.UserInterface.Presentation.ExternalSource.Selected + .SourceIdentifier.Value); if (RunRouteAction != null && !_externalSourceChangeRequested) { - RunRouteAction(eventReceived.Event.UserInterface.Presentation.ExternalSource.Selected.SourceIdentifier.Value, null); + RunRouteAction( + eventReceived.Event.UserInterface.Presentation.ExternalSource.Selected + .SourceIdentifier.Value, null); } _externalSourceChangeRequested = false; } } - else if (response.IndexOf("\"CommandResponse\":{") > -1 || response.IndexOf("\"CommandResponse\": {") > -1) + else if (response.IndexOf("\"CommandResponse\":{") > -1 || + response.IndexOf("\"CommandResponse\": {") > -1) { // CommandResponse Message + Debug.Console(2, this, "Parse CommandResponse - {0}", response); - if (response.IndexOf("\"CallHistoryRecentsResult\":{") > -1 || response.IndexOf("\"CallHistoryRecentsResult\": {") > -1) + + if (response.IndexOf("\"CallHistoryRecentsResult\":{") > -1 || + response.IndexOf("\"CallHistoryRecentsResult\": {") > -1) { + Debug.Console(2, this, "Parse CallHistoryRecentsResult"); + var codecCallHistory = new CiscoCallHistory.RootObject(); JsonConvert.PopulateObject(response, codecCallHistory); - CallHistory.ConvertCiscoCallHistoryToGeneric(codecCallHistory.CommandResponse.CallHistoryRecentsResult.Entry); + CallHistory.ConvertCiscoCallHistoryToGeneric( + codecCallHistory.CommandResponse.CallHistoryRecentsResult.Entry); } - else if (response.IndexOf("\"CallHistoryDeleteEntryResult\":{") > -1 || response.IndexOf("\"CallHistoryDeleteEntryResult\": {") > -1) + else if (response.IndexOf("\"CallHistoryDeleteEntryResult\":{") > -1 || + response.IndexOf("\"CallHistoryDeleteEntryResult\": {") > -1) { + Debug.Console(2, this, "Parse GetCallHistoryDeleteEntryResult"); + GetCallHistory(); } - else if (response.IndexOf("\"PhonebookSearchResult\":{") > -1 || response.IndexOf("\"PhonebookSearchResult\": {") > -1) + else if (response.IndexOf("\"PhonebookSearchResult\":{") > -1 || + response.IndexOf("\"PhonebookSearchResult\": {") > -1) { + Debug.Console(2, this, "Parse PhonebookSearchResult"); + var codecPhonebookResponse = new CiscoCodecExtendedPhonebook.RootObject(); JsonConvert.PopulateObject(response, codecPhonebookResponse); @@ -1412,11 +1933,15 @@ void DeserializeResponse(string response) // Check if the phonebook has any folders PhonebookSyncState.InitialPhonebookFoldersReceived(); - PhonebookSyncState.SetPhonebookHasFolders(codecPhonebookResponse.CommandResponse.PhonebookSearchResult.Folder.Count > 0); + PhonebookSyncState.SetPhonebookHasFolders( + codecPhonebookResponse.CommandResponse.PhonebookSearchResult.Folder.Count > + 0); if (PhonebookSyncState.PhonebookHasFolders) { - DirectoryRoot.AddFoldersToDirectory(CiscoCodecExtendedPhonebook.GetRootFoldersFromSearchResult(codecPhonebookResponse.CommandResponse.PhonebookSearchResult)); + DirectoryRoot.AddFoldersToDirectory( + CiscoCodecExtendedPhonebook.GetRootFoldersFromSearchResult( + codecPhonebookResponse.CommandResponse.PhonebookSearchResult)); } // Get the number of contacts in the phonebook @@ -1425,9 +1950,14 @@ void DeserializeResponse(string response) else if (!PhonebookSyncState.NumberOfContactsWasReceived) { // Store the total number of contacts in the phonebook - PhonebookSyncState.SetNumberOfContacts(Int32.Parse(codecPhonebookResponse.CommandResponse.PhonebookSearchResult.ResultInfo.TotalRows.Value)); + PhonebookSyncState.SetNumberOfContacts( + Int32.Parse( + codecPhonebookResponse.CommandResponse.PhonebookSearchResult.ResultInfo + .TotalRows.Value)); - DirectoryRoot.AddContactsToDirectory(CiscoCodecExtendedPhonebook.GetRootContactsFromSearchResult(codecPhonebookResponse.CommandResponse.PhonebookSearchResult)); + DirectoryRoot.AddContactsToDirectory( + CiscoCodecExtendedPhonebook.GetRootContactsFromSearchResult( + codecPhonebookResponse.CommandResponse.PhonebookSearchResult)); PhonebookSyncState.PhonebookRootEntriesReceived(); @@ -1437,8 +1967,12 @@ void DeserializeResponse(string response) { var directoryResults = new CodecDirectory(); - if (codecPhonebookResponse.CommandResponse.PhonebookSearchResult.ResultInfo.TotalRows.Value != "0") - directoryResults = CiscoCodecExtendedPhonebook.ConvertCiscoPhonebookToGeneric(codecPhonebookResponse.CommandResponse.PhonebookSearchResult); + if ( + codecPhonebookResponse.CommandResponse.PhonebookSearchResult.ResultInfo + .TotalRows.Value != "0") + directoryResults = + CiscoCodecExtendedPhonebook.ConvertCiscoPhonebookToGeneric( + codecPhonebookResponse.CommandResponse.PhonebookSearchResult); PrintDirectory(directoryResults); @@ -1448,14 +1982,20 @@ void DeserializeResponse(string response) } } - else if (response.IndexOf("\"BookingsListResult\":{") > -1) + else if (response.IndexOf("\"BookingsListResult\":{") > -1 + || response.IndexOf("\"BookingsListResult\": {") > -1) { + Debug.Console(2, this, "Parse BookingsListResult - {0}", response); + var codecBookings = new CiscoExtendedCodecBookings.RootObject(); JsonConvert.PopulateObject(response, codecBookings); - if (codecBookings.CommandResponse.BookingsListResult.ResultInfo.TotalRows.Value != "0") - CodecSchedule.Meetings = CiscoExtendedCodecBookings.GetGenericMeetingsFromBookingResult(codecBookings.CommandResponse.BookingsListResult.Booking); + if (codecBookings.CommandResponse.BookingsListResult.ResultInfo.TotalRows.Value != + "0") + CodecSchedule.Meetings = + CiscoExtendedCodecBookings.GetGenericMeetingsFromBookingResult( + codecBookings.CommandResponse.BookingsListResult.Booking, _joinableCooldownSeconds); BookingsRefreshTimer.Reset(900000, 900000); } @@ -1492,11 +2032,18 @@ private string CheckCallType(string id, IEnumerable call } + private int IteratedDebug(int data) + { + data = data++; + //Debug.Console(1, this, "Completed Step {0}", data ); + return data; + } + /// - /// Call when directory results are updated + /// CiscoCall when directory results are updated /// /// - void OnDirectoryResultReturned(CodecDirectory result) + private void OnDirectoryResultReturned(CodecDirectory result) { CurrentDirectoryResultIsNotDirectoryRoot.FireUpdate(); @@ -1515,19 +2062,27 @@ void OnDirectoryResultReturned(CodecDirectory result) PrintDirectory(result); } - private string UpdateLayoutsXSig(List layouts) + private string UpdateLayoutsXSig(ICollection layoutList) { + var layouts = layoutList; var layoutIndex = 1; var tokenArray = new XSigToken[layouts.Count]; + if (layouts.Count == 0) + { + var clearBytes = XSigHelpers.ClearOutputs(); + return Encoding.GetEncoding(XSigEncoding).GetString(clearBytes, 0, clearBytes.Length); + } + foreach (var layout in layouts) { var arrayIndex = layoutIndex - 1; - Debug.Console(2, this, "Layout Name : {0}", layout.Label); + Debug.Console(0, this, "Layout Name : {0}", layout.Label); tokenArray[arrayIndex] = new XSigSerialToken(layoutIndex, layout.Label); layoutIndex++; } + return GetXSigString(tokenArray); } @@ -1549,16 +2104,22 @@ private static string GetXSigString(XSigToken[] tokenArray) return returnString; } + public void CodecPollLayouts() + { + EnqueueCommand("xStatus Video Layout CurrentLayouts"); + } + /// /// Evaluates an event received from the codec /// /// - void EvalutateDisconnectEvent(CiscoCodecEvents.RootObject eventReceived) + private void EvalutateDisconnectEvent(CiscoCodecEvents.RootObject eventReceived) { if (eventReceived.Event.CallDisconnect != null) { - var tempActiveCall = ActiveCalls.FirstOrDefault(c => c.Id.Equals(eventReceived.Event.CallDisconnect.CallId.Value)); + var tempActiveCall = + ActiveCalls.FirstOrDefault(c => c.Id.Equals(eventReceived.Event.CallDisconnect.CallId.Value)); // Remove the call from the Active calls list if (tempActiveCall == null) return; @@ -1648,7 +2209,8 @@ public void CheckCurrentHour(object o) { if (DateTime.Now.Hour == 2) { - Debug.Console(1, this, "Checking hour to see if phonebook should be downloaded. Current hour is {0}", DateTime.Now.Hour); + Debug.Console(1, this, "Checking hour to see if phonebook should be downloaded. Current hour is {0}", + DateTime.Now.Hour); GetPhonebook(null); PhonebookRefreshTimer.Reset(3600000, 3600000); @@ -1671,13 +2233,16 @@ public void GetPhonebook(string command) private void GetPhonebookFolders() { // Get Phonebook Folders (determine local/corporate from config, and set results limit) - EnqueueCommand(string.Format("xCommand Phonebook Search PhonebookType: {0} ContactType: Folder", _phonebookMode)); + EnqueueCommand(string.Format("xCommand Phonebook Search PhonebookType: {0} ContactType: Folder", + _phonebookMode)); } private void GetPhonebookContacts() { // Get Phonebook Folders (determine local/corporate from config, and set results limit) - EnqueueCommand(string.Format("xCommand Phonebook Search PhonebookType: {0} ContactType: Contact Limit: {1}", _phonebookMode, _phonebookResultsLimit)); + EnqueueCommand(string.Format( + "xCommand Phonebook Search PhonebookType: {0} ContactType: Contact Limit: {1}", _phonebookMode, + _phonebookResultsLimit)); } /// @@ -1686,16 +2251,30 @@ private void GetPhonebookContacts() /// public void SearchDirectory(string searchString) { - EnqueueCommand(string.Format("xCommand Phonebook Search SearchString: \"{0}\" PhonebookType: {1} ContactType: Contact Limit: {2}", searchString, _phonebookMode, _phonebookResultsLimit)); + Debug.Console(0, this, + "_phonebookAutoPopulate = {0}, searchString = {1}, _lastSeached = {2}, _phonebookInitialSearch = {3}", + _phonebookAutoPopulate ? "true" : "false", searchString, _lastSearched, + _phonebookInitialSearch ? "true" : "false"); + + if (!_phonebookAutoPopulate && searchString == _lastSearched && !_phonebookInitialSearch) return; + EnqueueCommand( + string.Format( + "xCommand Phonebook Search SearchString: \"{0}\" PhonebookType: {1} ContactType: Contact Limit: {2}", + searchString, _phonebookMode, _phonebookResultsLimit)); + _lastSearched = searchString; + _phonebookInitialSearch = false; } + /// /// // Get contents of a specific folder in the phonebook /// /// public void GetDirectoryFolderContents(string folderId) { - EnqueueCommand(string.Format("xCommand Phonebook Search FolderId: {0} PhonebookType: {1} ContactType: Any Limit: {2}", folderId, _phonebookMode, _phonebookResultsLimit)); + EnqueueCommand( + string.Format("xCommand Phonebook Search FolderId: {0} PhonebookType: {1} ContactType: Any Limit: {2}", + folderId, _phonebookMode, _phonebookResultsLimit)); } /// @@ -1738,7 +2317,7 @@ public void SetCurrentDirectoryToRoot() /// Prints the directory to console /// /// - void PrintDirectory(CodecDirectory directory) + private void PrintDirectory(CodecDirectory directory) { if (Debug.Level > 0) { @@ -1755,7 +2334,8 @@ void PrintDirectory(CodecDirectory directory) Debug.Console(1, this, "{0}", item.Name); } } - Debug.Console(1, this, "Directory is on Root Level: {0}", !CurrentDirectoryResultIsNotDirectoryRoot.BoolValue); + Debug.Console(1, this, "Directory is on Root Level: {0}", + !CurrentDirectoryResultIsNotDirectoryRoot.BoolValue); } } @@ -1767,6 +2347,7 @@ void PrintDirectory(CodecDirectory directory) public override void Dial(string number) { EnqueueCommand(string.Format("xCommand Dial Number: \"{0}\"", number)); + DirectoryClearSelection(); } /// @@ -1779,6 +2360,7 @@ public override void Dial(Meeting meeting) { Dial(c.Number, c.Protocol, c.CallRate, c.CallType, meeting.Id); } + DirectoryClearSelection(); } /// @@ -1791,13 +2373,16 @@ public override void Dial(Meeting meeting) /// public void Dial(string number, string protocol, string callRate, string callType, string meetingId) { - EnqueueCommand(string.Format("xCommand Dial Number: \"{0}\" Protocol: {1} CallRate: {2} CallType: {3} BookingId: {4}", number, protocol, callRate, callType, meetingId)); + EnqueueCommand( + string.Format("xCommand Dial Number: \"{0}\" Protocol: {1} CallRate: {2} CallType: {3} BookingId: {4}", + number, protocol, callRate, callType, meetingId)); + DirectoryClearSelection(); } public override void EndCall(CodecActiveCallItem activeCall) { - EnqueueCommand(string.Format("xCommand Call Disconnect CallId: {0}", activeCall.Id)); + EnqueueCommand(string.Format("xCommand CiscoCall Disconnect CallId: {0}", activeCall.Id)); PresentationStates = eCodecPresentationStates.LocalOnly; } @@ -1805,31 +2390,42 @@ public override void EndAllCalls() { foreach (CodecActiveCallItem activeCall in ActiveCalls) { - EnqueueCommand(string.Format("xCommand Call Disconnect CallId: {0}", activeCall.Id)); + EnqueueCommand(string.Format("xCommand CiscoCall Disconnect CallId: {0}", activeCall.Id)); } PresentationStates = eCodecPresentationStates.LocalOnly; } public override void AcceptCall(CodecActiveCallItem item) { - EnqueueCommand("xCommand Call Accept"); + EnqueueCommand("xCommand CiscoCall Accept"); } public override void RejectCall(CodecActiveCallItem item) { - EnqueueCommand("xCommand Call Reject"); + EnqueueCommand("xCommand CiscoCall Reject"); } #region IHasCallHold Members public void HoldCall(CodecActiveCallItem activeCall) { - EnqueueCommand(string.Format("xCommand Call Hold CallId: {0}", activeCall.Id)); + EnqueueCommand(string.Format("xCommand CiscoCall Hold CallId: {0}", activeCall.Id)); } public void ResumeCall(CodecActiveCallItem activeCall) { - EnqueueCommand(string.Format("xCommand Call Resume CallId: {0}", activeCall.Id)); + EnqueueCommand(string.Format("xCommand CiscoCall Resume CallId: {0}", activeCall.Id)); + } + + /// + /// Resumes all held calls + /// + public void ResumeAllCalls() + { + foreach (var codecActiveCallItem in ActiveCalls.Where(codecActiveCallItem => codecActiveCallItem.IsOnHold)) + { + ResumeCall(codecActiveCallItem); + } } #endregion @@ -1838,7 +2434,7 @@ public void ResumeCall(CodecActiveCallItem activeCall) public void JoinCall(CodecActiveCallItem activeCall) { - EnqueueCommand(string.Format("xCommand Call Join CallId: {0}", activeCall.Id)); + EnqueueCommand(string.Format("xCommand CiscoCall Join CallId: {0}", activeCall.Id)); } public void JoinAllCalls() @@ -1855,7 +2451,7 @@ public void JoinAllCalls() if (ids.Length > 0) { - EnqueueCommand(string.Format("xCommand Call Join {0}", ids.ToString())); + EnqueueCommand(string.Format("xCommand CiscoCall Join {0}", ids.ToString())); } } @@ -1867,7 +2463,7 @@ public void JoinAllCalls() /// public override void SendDtmf(string s) { - EnqueueCommand(string.Format("xCommand Call DTMFSend CallId: {0} DTMFString: \"{1}\"", GetCallId(), s)); + EnqueueCommand(string.Format("xCommand CiscoCall DTMFSend CallId: {0} DTMFString: \"{1}\"", GetCallId(), s)); } /// @@ -1877,7 +2473,7 @@ public override void SendDtmf(string s) /// public override void SendDtmf(string s, CodecActiveCallItem activeCall) { - EnqueueCommand(string.Format("xCommand Call DTMFSend CallId: {0} DTMFString: \"{1}\"", activeCall.Id, s)); + EnqueueCommand(string.Format("xCommand CiscoCall DTMFSend CallId: {0} DTMFString: \"{1}\"", activeCall.Id, s)); } public void SelectPresentationSource(int source) @@ -1899,9 +2495,10 @@ public void SetRingtoneVolume(int volume) return; } - if (volume % 5 != 0) + if (volume%5 != 0) { - Debug.Console(0, this, "Cannot set ringtone volume to '{0}'. Value must be between 0 - 100 and a multiple of 5", volume); + Debug.Console(0, this, + "Cannot set ringtone volume to '{0}'. Value must be between 0 - 100 and a multiple of 5", volume); return; } @@ -1932,7 +2529,8 @@ public void SelectPresentationSource2() public override void StartSharing() { if (_desiredPresentationSource > 0) - EnqueueCommand(string.Format("xCommand Presentation Start PresentationSource: {0} SendingMode: {1}", _desiredPresentationSource, PresentationStates.ToString())); + EnqueueCommand(string.Format("xCommand Presentation Start PresentationSource: {0} SendingMode: {1}", + _desiredPresentationSource, PresentationStates.ToString())); } /// @@ -2045,7 +2643,7 @@ public override void LinkToApi(BasicTriList trilist, uint joinStart, string join bridge.AddJoinMap(Key, joinMap); } - LinkVideoCodecToApi(this, trilist, joinStart, joinMapKey, bridge); + LinkVideoCodecToApi(this, trilist, joinMap); LinkCiscoCodecToApi(trilist, joinMap); } @@ -2059,27 +2657,178 @@ public void LinkCiscoCodecToApi(BasicTriList trilist, CiscoCodecJoinMap joinMap) var dndCodec = this as IHasDoNotDisturbMode; if (dndCodec != null) { - dndCodec.DoNotDisturbModeIsOnFeedback.LinkInputSig(trilist.BooleanInput[joinMap.ActivateDoNotDisturbMode.JoinNumber]); - dndCodec.DoNotDisturbModeIsOnFeedback.LinkComplementInputSig(trilist.BooleanInput[joinMap.DeactivateDoNotDisturbMode.JoinNumber]); + dndCodec.DoNotDisturbModeIsOnFeedback.LinkInputSig( + trilist.BooleanInput[joinMap.ActivateDoNotDisturbMode.JoinNumber]); + dndCodec.DoNotDisturbModeIsOnFeedback.LinkComplementInputSig( + trilist.BooleanInput[joinMap.DeactivateDoNotDisturbMode.JoinNumber]); + + trilist.SetSigFalseAction(joinMap.ActivateDoNotDisturbMode.JoinNumber, + () => dndCodec.ActivateDoNotDisturbMode()); + trilist.SetSigFalseAction(joinMap.DeactivateDoNotDisturbMode.JoinNumber, + () => dndCodec.DeactivateDoNotDisturbMode()); + trilist.SetSigFalseAction(joinMap.ToggleDoNotDisturbMode.JoinNumber, + () => dndCodec.ToggleDoNotDisturbMode()); + } + + var scheduleCodec = this as IHasScheduleAwareness; + if (scheduleCodec != null) + { + trilist.SetSigFalseAction(joinMap.DialMeeting4.JoinNumber, () => + { + var mtg = 4; + var index = mtg - 1; + Debug.Console(1, this, + "Meeting {0} Selected (EISC dig-o{1}) > _currentMeetings[{2}].Id: {3}, Title: {4}", + mtg, joinMap.DialMeeting4.JoinNumber, index, _currentMeetings[index].Id, + _currentMeetings[index].Title); + if (_currentMeetings[index] != null) + Dial(_currentMeetings[index]); + }); + + trilist.SetSigFalseAction(joinMap.DialMeeting5.JoinNumber, () => + { + var mtg = 5; + var index = mtg - 1; + Debug.Console(1, this, + "Meeting {0} Selected (EISC dig-o{1}) > _currentMeetings[{2}].Id: {3}, Title: {4}", + mtg, joinMap.DialMeeting5.JoinNumber, index, _currentMeetings[index].Id, + _currentMeetings[index].Title); + if (_currentMeetings[index] != null) + Dial(_currentMeetings[index]); + }); + trilist.SetSigFalseAction(joinMap.DialActiveMeeting.JoinNumber, () => + { + if (_currentMeeting == null) return; + Debug.Console(1, this, "Active Meeting Selected > _Id: {0}, Title: {1}", + _currentMeeting.Id, _currentMeeting.Title); + Dial(_currentMeeting); + }); + + + - trilist.SetSigFalseAction(joinMap.ActivateDoNotDisturbMode.JoinNumber, () => dndCodec.ActivateDoNotDisturbMode()); - trilist.SetSigFalseAction(joinMap.DeactivateDoNotDisturbMode.JoinNumber, () => dndCodec.DeactivateDoNotDisturbMode()); - trilist.SetSigFalseAction(joinMap.ToggleDoNotDisturbMode.JoinNumber, () => dndCodec.ToggleDoNotDisturbMode()); } var halfwakeCodec = this as IHasHalfWakeMode; if (halfwakeCodec != null) { halfwakeCodec.StandbyIsOnFeedback.LinkInputSig(trilist.BooleanInput[joinMap.ActivateStandby.JoinNumber]); - halfwakeCodec.StandbyIsOnFeedback.LinkComplementInputSig(trilist.BooleanInput[joinMap.DeactivateStandby.JoinNumber]); - halfwakeCodec.HalfWakeModeIsOnFeedback.LinkInputSig(trilist.BooleanInput[joinMap.ActivateHalfWakeMode.JoinNumber]); - halfwakeCodec.EnteringStandbyModeFeedback.LinkInputSig(trilist.BooleanInput[joinMap.EnteringStandbyMode.JoinNumber]); + halfwakeCodec.StandbyIsOnFeedback.LinkComplementInputSig( + trilist.BooleanInput[joinMap.DeactivateStandby.JoinNumber]); + halfwakeCodec.HalfWakeModeIsOnFeedback.LinkInputSig( + trilist.BooleanInput[joinMap.ActivateHalfWakeMode.JoinNumber]); + halfwakeCodec.EnteringStandbyModeFeedback.LinkInputSig( + trilist.BooleanInput[joinMap.EnteringStandbyMode.JoinNumber]); - trilist.SetSigFalseAction(joinMap.ActivateStandby.JoinNumber, () => halfwakeCodec.StandbyActivate()); - trilist.SetSigFalseAction(joinMap.DeactivateStandby.JoinNumber, () => halfwakeCodec.StandbyDeactivate()); - trilist.SetSigFalseAction(joinMap.ActivateHalfWakeMode.JoinNumber, () => halfwakeCodec.HalfwakeActivate()); + trilist.SetSigFalseAction(joinMap.ActivateStandby.JoinNumber, halfwakeCodec.StandbyActivate); + trilist.SetSigFalseAction(joinMap.DeactivateStandby.JoinNumber, halfwakeCodec.StandbyDeactivate); + trilist.SetSigFalseAction(joinMap.ActivateHalfWakeMode.JoinNumber, + halfwakeCodec.HalfwakeActivate); } + CameraTrackingCapabilitiesChanged += (sender, args) => + { + + switch (CameraTrackingCapabilities) + { + case eCameraTrackingCapabilities.None: + { + trilist.SetBool(joinMap.SpeakerTrackAvailable.JoinNumber, false); + trilist.SetBool(joinMap.PresenterTrackAvailable.JoinNumber, false); + trilist.SetBool(joinMap.CameraSupportsAutoMode.JoinNumber, false); + break; + } + case eCameraTrackingCapabilities.PresenterTrack: + { + trilist.SetBool(joinMap.SpeakerTrackAvailable.JoinNumber, false); + trilist.SetBool(joinMap.PresenterTrackAvailable.JoinNumber, true); + trilist.SetBool(joinMap.CameraSupportsAutoMode.JoinNumber, true); + break; + } + case eCameraTrackingCapabilities.SpeakerTrack: + { + trilist.SetBool(joinMap.SpeakerTrackAvailable.JoinNumber, true); + trilist.SetBool(joinMap.PresenterTrackAvailable.JoinNumber, false); + trilist.SetBool(joinMap.CameraSupportsAutoMode.JoinNumber, true); + break; + } + case eCameraTrackingCapabilities.Both: + { + trilist.SetBool(joinMap.SpeakerTrackAvailable.JoinNumber, true); + trilist.SetBool(joinMap.PresenterTrackAvailable.JoinNumber, true); + trilist.SetBool(joinMap.CameraSupportsAutoMode.JoinNumber, true); + break; + } + + } + }; + + + + AvailableLayoutsChanged += (sender, args) => + { + Debug.Console(2, this, "AvailableLayoutsChanged Event"); + var layouts = args.AvailableLayouts; + + Debug.Console(2, this, "There are {0} layouts", layouts.Count); + + + var clearBytes = XSigHelpers.ClearOutputs(); + + trilist.SetString(joinMap.AvailableLayoutsFb.JoinNumber, + Encoding.GetEncoding(XSigEncoding).GetString(clearBytes, 0, clearBytes.Length)); + + var availableLayoutsXSig = UpdateLayoutsXSig(layouts); + + Debug.Console(2, this, "LayoutXsig = {0}", availableLayoutsXSig); + + trilist.SetString(joinMap.AvailableLayoutsFb.JoinNumber, availableLayoutsXSig); + }; + + CurrentLayoutChanged += (sender, args) => + { + var currentLayout = args.CurrentLayout; + + Debug.Console(2, this, "CurrentLayout == {0}", currentLayout == String.Empty ? "None" : currentLayout); + + trilist.SetString(joinMap.CurrentLayoutStringFb.JoinNumber, currentLayout); + + }; + + CodecInfoChanged += (sender, args) => + { + if (args.InfoChangeType == eCodecInfoChangeType.Unknown) return; + switch (args.InfoChangeType) + { + case eCodecInfoChangeType.Network: + trilist.SetString(joinMap.DeviceIpAddresss.JoinNumber, args.IpAddress); + break; + case eCodecInfoChangeType.Sip: + trilist.SetString(joinMap.SipPhoneNumber.JoinNumber, args.SipPhoneNumber); + trilist.SetString(joinMap.SipUri.JoinNumber, args.SipUri); + break; + case eCodecInfoChangeType.H323: + trilist.SetString(joinMap.E164Alias.JoinNumber, args.E164Alias); + trilist.SetString(joinMap.H323Id.JoinNumber, args.H323Id); + break; + case eCodecInfoChangeType.Multisite: + trilist.SetBool(joinMap.MultiSiteOptionIsEnabled.JoinNumber, args.MultiSiteOptionIsEnabled); + break; + case eCodecInfoChangeType.AutoAnswer: + trilist.SetBool(joinMap.AutoAnswerEnabled.JoinNumber, args.AutoAnswerEnabled); + break; + } + }; + + + AvailableLayoutsFeedback.LinkInputSig(trilist.StringInput[joinMap.AvailableLayoutsFb.JoinNumber]); + + trilist.SetStringSigAction(joinMap.SelectLayout.JoinNumber, LayoutSet); + + + + trilist.SetSigTrueAction(joinMap.ResumeAllCalls.JoinNumber, ResumeAllCalls); + // Ringtone volume trilist.SetUShortSigAction(joinMap.RingtoneVolume.JoinNumber, (u) => SetRingtoneVolume(u)); RingtoneVolumeFeedback.LinkInputSig(trilist.UShortInput[joinMap.RingtoneVolume.JoinNumber]); @@ -2092,76 +2841,153 @@ public void LinkCiscoCodecToApi(BasicTriList trilist, CiscoCodecJoinMap joinMap) trilist.SetSigTrueAction(joinMap.PresentationLocalRemote.JoinNumber, SetPresentationLocalRemote); trilist.SetSigTrueAction(joinMap.PresentationLocalRemoteToggle.JoinNumber, SetPresentationLocalRemoteToggle); - PresentationViewDefaultFeedback.LinkInputSig(trilist.BooleanInput[joinMap.PresentationViewDefault.JoinNumber]); - PresentationViewMinimizedFeedback.LinkInputSig(trilist.BooleanInput[joinMap.PresentationViewMinimized.JoinNumber]); - PresentationViewMaximizedFeedback.LinkInputSig(trilist.BooleanInput[joinMap.PresentationViewMinimized.JoinNumber]); + PresentationViewDefaultFeedback.LinkInputSig( + trilist.BooleanInput[joinMap.PresentationViewDefault.JoinNumber]); + PresentationViewMinimizedFeedback.LinkInputSig( + trilist.BooleanInput[joinMap.PresentationViewMinimized.JoinNumber]); + PresentationViewMaximizedFeedback.LinkInputSig( + trilist.BooleanInput[joinMap.PresentationViewMaximized.JoinNumber]); trilist.SetSigTrueAction(joinMap.PresentationViewDefault.JoinNumber, PresentationViewDefaultSet); trilist.SetSigTrueAction(joinMap.PresentationViewMinimized.JoinNumber, PresentationViewMinimizedzedSet); trilist.SetSigTrueAction(joinMap.PresentationViewMaximized.JoinNumber, PresentationViewMaximizedSet); - PresentationSendingLocalOnlyFeedback.LinkInputSig(trilist.BooleanInput[joinMap.PresentationLocalOnly.JoinNumber]); - PresentationSendingLocalRemoteFeedback.LinkInputSig(trilist.BooleanInput[joinMap.PresentationLocalRemote.JoinNumber]); + PresentationSendingLocalOnlyFeedback.LinkInputSig( + trilist.BooleanInput[joinMap.PresentationLocalOnly.JoinNumber]); + PresentationSendingLocalRemoteFeedback.LinkInputSig( + trilist.BooleanInput[joinMap.PresentationLocalRemote.JoinNumber]); - PresenterTrackEnabledFeedback.LinkInputSig(trilist.BooleanInput[joinMap.PresenterTrackEnabled.JoinNumber]); + //PresenterTrackAvailableFeedback.LinkInputSig(trilist.BooleanInput[joinMap.PresenterTrackEnabled.JoinNumber]); PresenterTrackStatusOffFeedback.LinkInputSig(trilist.BooleanInput[joinMap.PresenterTrackOff.JoinNumber]); - PresenterTrackStatusFollowFeedback.LinkInputSig(trilist.BooleanInput[joinMap.PresenterTrackFollow.JoinNumber]); - PresenterTrackStatusBackgroundFeedback.LinkInputSig(trilist.BooleanInput[joinMap.PresenterTrackBackground.JoinNumber]); - PresenterTrackStatusPersistentFeedback.LinkInputSig(trilist.BooleanInput[joinMap.PresenterTrackPersistent.JoinNumber]); + PresenterTrackStatusFollowFeedback.LinkInputSig( + trilist.BooleanInput[joinMap.PresenterTrackFollow.JoinNumber]); + PresenterTrackStatusBackgroundFeedback.LinkInputSig( + trilist.BooleanInput[joinMap.PresenterTrackBackground.JoinNumber]); + PresenterTrackStatusPersistentFeedback.LinkInputSig( + trilist.BooleanInput[joinMap.PresenterTrackPersistent.JoinNumber]); trilist.SetSigTrueAction(joinMap.PresenterTrackOff.JoinNumber, PresenterTrackOff); trilist.SetSigTrueAction(joinMap.PresenterTrackFollow.JoinNumber, PresenterTrackFollow); trilist.SetSigTrueAction(joinMap.PresenterTrackBackground.JoinNumber, PresenterTrackBackground); trilist.SetSigTrueAction(joinMap.PresenterTrackPersistent.JoinNumber, PresenterTrackPersistent); + PresentationActiveFeedback.LinkInputSig(trilist.BooleanInput[joinMap.PresentationActive.JoinNumber]); + CodecSchedule.MeetingEventChange += (sender, args) => { - if (args.ChangeType == eMeetingEventChangeType.MeetingStartWarning) + if (_scheduleCheckTimer == null) _scheduleCheckTimer = new CTimer(ScheduleTimeCheck, null, 0, 15000); + + if (args.ChangeType != eMeetingEventChangeType.Unknown) ; { UpdateMeetingsListEnhanced(this, trilist, joinMap); } }; + + MinuteChanged += (sender, args) => + { + if (args.EventTime == DateTime.MinValue) return; + _scheduleCheckLast = args.EventTime; + UpdateMeetingsListEnhanced(this, trilist, joinMap); + }; } - private static void UpdateMeetingsListEnhanced(IHasScheduleAwareness codec, BasicTriList trilist, + + private void UpdateMeetingsListEnhanced(IHasScheduleAwareness codec, BasicTriList trilist, CiscoCodecJoinMap joinMap) { var currentTime = DateTime.Now; + const string boilerplate1 = "Available for "; + const string boilerplate2 = "Next meeting in "; - List currentMeetings = codec.CodecSchedule.Meetings.Where(m => m.StartTime >= currentTime || m.EndTime >= currentTime).ToList(); - if (currentMeetings.Count == 0) + + _currentMeetings = + codec.CodecSchedule.Meetings.Where(m => m.StartTime >= currentTime || m.EndTime >= currentTime).ToList(); + + if (_currentMeetings.Count == 0) { trilist.SetBool(joinMap.CodecAvailable.JoinNumber, true); trilist.SetBool(joinMap.CodecMeetingBannerActive.JoinNumber, false); trilist.SetBool(joinMap.CodecMeetingBannerWarning.JoinNumber, false); + trilist.SetString(joinMap.AvailableTimeRemaining.JoinNumber, boilerplate1 + "the rest of the day."); + trilist.SetString(joinMap.TimeToNextMeeting.JoinNumber, "No Meetings Scheduled"); + trilist.SetString(joinMap.ActiveMeetingDataXSig.JoinNumber, UpdateActiveMeetingXSig(null)); + trilist.SetUshort(joinMap.TotalMinutesUntilMeeting.JoinNumber, 0); + trilist.SetUshort(joinMap.HoursUntilMeeting.JoinNumber, 0); + trilist.SetUshort(joinMap.MinutesUntilMeeting.JoinNumber, 0); return; } - var upcomingMeeting = - currentMeetings.FirstOrDefault(x => x.StartTime >= currentTime && x.EndTime >= currentTime); - var currentMeeting = - currentMeetings.FirstOrDefault(x => x.StartTime <= currentTime && x.EndTime >= currentTime); + var upcomingMeeting = + _currentMeetings.FirstOrDefault(x => x.StartTime >= currentTime && x.EndTime >= currentTime); + var currentMeeting = + _currentMeetings.FirstOrDefault( + x => x.StartTime - x.MeetingWarningMinutes <= currentTime && x.EndTime >= currentTime); + var warningBanner = upcomingMeeting != null && + upcomingMeeting.StartTime - currentTime <= upcomingMeeting.MeetingWarningMinutes; + + - var warningBanner = upcomingMeeting != null && - upcomingMeeting.StartTime - currentTime <= upcomingMeeting.MeetingWarningMinutes; + _currentMeeting = currentMeeting; + trilist.SetBool(joinMap.CodecAvailable.JoinNumber, currentMeeting == null); + trilist.SetBool(joinMap.CodecMeetingBannerActive.JoinNumber, currentMeeting != null); + trilist.SetBool(joinMap.CodecMeetingBannerWarning.JoinNumber, warningBanner); + string availabilityMessage; + string nextMeetingMessage; + + if (upcomingMeeting == null) return; + var timeRemainingAvailable = upcomingMeeting.StartTime - currentTime; + var hoursRemainingAvailable = timeRemainingAvailable.Hours; + var minutesRemainingAvailable = timeRemainingAvailable.Minutes; + var totalMinutesRemainingAvailable = timeRemainingAvailable.TotalMinutes; + var hoursPlural = hoursRemainingAvailable > 1; + var hoursPresent = hoursRemainingAvailable > 0; + var minutesPlural = minutesRemainingAvailable > 1; + var minutesPresent = minutesRemainingAvailable > 0; + var hourString = String.Format("{0} {1}", hoursRemainingAvailable, + hoursPlural ? "hours" : "hour"); + var minuteString = String.Format("{0}{1} {2}", hoursPresent ? " and " : String.Empty, + minutesRemainingAvailable, + minutesPlural ? "minutes" : "minute"); + var messageBase = String.Format("{0}{1}", hoursPresent ? hourString : String.Empty, + minutesPresent ? minuteString : String.Empty); + + + if (totalMinutesRemainingAvailable > 0) + { + availabilityMessage = String.Format("{0}{1}.", boilerplate1, messageBase); + nextMeetingMessage = String.Format("{0}{1}.", boilerplate2, messageBase); - trilist.SetBool(joinMap.CodecAvailable.JoinNumber, currentMeeting == null); - trilist.SetBool(joinMap.CodecMeetingBannerActive.JoinNumber, currentMeeting != null); - trilist.SetBool(joinMap.CodecMeetingBannerWarning.JoinNumber, warningBanner); + } + else + { + availabilityMessage = "Unavailable"; + nextMeetingMessage = "Next meeting starts soon."; + } + + trilist.SetString(joinMap.ActiveMeetingDataXSig.JoinNumber, UpdateActiveMeetingXSig(currentMeeting)); + trilist.SetUshort(joinMap.TotalMinutesUntilMeeting.JoinNumber, (ushort) totalMinutesRemainingAvailable); + trilist.SetUshort(joinMap.HoursUntilMeeting.JoinNumber, (ushort) hoursRemainingAvailable); + trilist.SetUshort(joinMap.MinutesUntilMeeting.JoinNumber, (ushort) minutesRemainingAvailable); + trilist.SetString(joinMap.AvailableTimeRemaining.JoinNumber, availabilityMessage); + trilist.SetString(joinMap.TimeToNextMeeting.JoinNumber, nextMeetingMessage); } + + + + public void SetPresentationLocalOnly() { PresentationStates = eCodecPresentationStates.LocalOnly; - if(CodecStatus.Status.Conference.Presentation.Mode.BoolValue) StartSharing(); + StartSharing(); } public void SetPresentationLocalRemote() { PresentationStates = eCodecPresentationStates.LocalRemote; - if (CodecStatus.Status.Conference.Presentation.Mode.BoolValue) StartSharing(); + StartSharing(); } public void SetPresentationLocalRemoteToggle() @@ -2185,7 +3011,7 @@ public void Reboot() /// /// Sets SelfView Mode based on config /// - void SetSelfViewMode() + private void SetSelfViewMode() { if (!IsInCall) { @@ -2200,16 +3026,38 @@ void SetSelfViewMode() } } - private void OnAvailableLayoutsChanged() + private void OnAvailableLayoutsChanged(List availableLayouts) { + if (availableLayouts == null) return; var handler = AvailableLayoutsChanged; if (handler == null) return; - handler(this, new AvailableLayoutChangedEventArgs() + handler(this, new AvailableLayoutsChangedEventArgs() { - AvailableLayouts = AvailableLocalLayouts + AvailableLayouts = availableLayouts }); } + private void OnCameraTrackingCapabilitiesChanged() + { + var handler = CameraTrackingCapabilitiesChanged; + if (handler == null) return; + handler(this, + new CameraTrackingCapabilitiesArgs(SpeakerTrackAvailableFeedbackFunc, + PresenterTrackAvailableFeedbackFunc)); + } + + private void OnCurrentLayoutChanged(string currentLayout) + { + if (String.IsNullOrEmpty(currentLayout)) return; + var handler = CurrentLayoutChanged; + if (handler == null) return; + handler(this, new CurrentLayoutChangedEventArgs() + { + CurrentLayout = currentLayout + }); + } + + /// /// Turns on Selfview Mode /// @@ -2259,7 +3107,8 @@ public void SelfviewPipPositionToggle() { var nextPipPositionIndex = SelfviewPipPositions.IndexOf(_currentSelfviewPipPosition) + 1; - if (nextPipPositionIndex >= SelfviewPipPositions.Count) // Check if we need to loop back to the first item in the list + if (nextPipPositionIndex >= SelfviewPipPositions.Count) + // Check if we need to loop back to the first item in the list nextPipPositionIndex = 0; SelfviewPipPositionSet(SelfviewPipPositions[nextPipPositionIndex]); @@ -2270,28 +3119,28 @@ public void SelfviewPipPositionToggle() /// Sets a specific local layout /// /// - public void LocalLayoutSet(CodecCommandWithLabel layout) + public void LayoutSet(CodecCommandWithLabel layout) { if (layout == null) { Debug.Console(0, this, "Unable to Recall Layout - Null CodecCommandWithLabel Object Sent"); return; } - EnqueueCommand(string.Format("xCommand Video Layout SetLayout LayoutName: {0}", layout.Command)); + EnqueueCommand(string.Format("xCommand Video Layout SetLayout LayoutName: \"{0}\"", layout.Command)); } /// /// Sets a specific local layout /// /// - public void LocalLayoutSet(string layout) + public void LayoutSet(string layout) { if (String.IsNullOrEmpty(layout)) { Debug.Console(0, this, "Unable to Recall Layout - Null string Sent"); return; } - EnqueueCommand(string.Format("xCommand Video Layout SetLayout LayoutName: {0}", layout)); + EnqueueCommand(string.Format("xCommand Video Layout SetLayout LayoutName: \"{0}\"", layout)); } @@ -2302,12 +3151,14 @@ public void LocalLayoutToggle() { if (_currentLayout != null) { - var nextLocalLayoutIndex = AvailableLocalLayouts.IndexOf(AvailableLocalLayouts.FirstOrDefault(l => l.Label.Equals(_currentLayout))) + 1; + var nextLocalLayoutIndex = + AvailableLayouts.IndexOf(AvailableLayouts.FirstOrDefault(l => l.Label.Equals(_currentLayout))) + 1; - if (nextLocalLayoutIndex >= AvailableLocalLayouts.Count) // Check if we need to loop back to the first item in the list + if (nextLocalLayoutIndex >= AvailableLayouts.Count) + // Check if we need to loop back to the first item in the list nextLocalLayoutIndex = 0; - if (AvailableLocalLayouts[nextLocalLayoutIndex] == null) return; - LocalLayoutSet(AvailableLocalLayouts[nextLocalLayoutIndex]); + if (AvailableLayouts[nextLocalLayoutIndex] == null) return; + LayoutSet(AvailableLayouts[nextLocalLayoutIndex]); } } @@ -2318,9 +3169,9 @@ public void LocalLayoutToggleSingleProminent() { if (String.IsNullOrEmpty(_currentLayout)) return; if (_currentLayout != "Prominent") - LocalLayoutSet(AvailableLocalLayouts.FirstOrDefault(l => l.Label.Equals("Prominent"))); + LayoutSet(AvailableLayouts.FirstOrDefault(l => l.Label.Equals("Prominent"))); else - LocalLayoutSet(AvailableLocalLayouts.FirstOrDefault(l => l.Label.Equals("Single"))); + LayoutSet(AvailableLayouts.FirstOrDefault(l => l.Label.Equals("Single"))); } /// @@ -2341,7 +3192,8 @@ public void PresentationViewDefaultSet() _currentPresentationView = "Default"; EnqueueCommand(string.Format("xCommand Video PresentationView Set View: {0}", _currentPresentationView)); - PresentationViewMaximizedFeedback.FireUpdate(); + PresentationViewFeedbackGroup.FireUpdate(); + //PresentationViewMaximizedFeedback.FireUpdate(); } public void PresentationViewMinimizedzedSet() @@ -2349,7 +3201,7 @@ public void PresentationViewMinimizedzedSet() _currentPresentationView = "Minimized"; EnqueueCommand(string.Format("xCommand Video PresentationView Set View: {0}", _currentPresentationView)); - PresentationViewMaximizedFeedback.FireUpdate(); + PresentationViewFeedbackGroup.FireUpdate(); } @@ -2358,16 +3210,17 @@ public void PresentationViewMaximizedSet() _currentPresentationView = "Maximized"; EnqueueCommand(string.Format("xCommand Video PresentationView Set View: {0}", _currentPresentationView)); - PresentationViewMaximizedFeedback.FireUpdate(); - + PresentationViewFeedbackGroup.FireUpdate(); } /// /// Calculates the current selfview PIP position /// - void ComputeSelfviewPipStatus() + private void ComputeSelfviewPipStatus() { - _currentSelfviewPipPosition = SelfviewPipPositions.FirstOrDefault(p => p.Command.ToLower().Equals(CodecStatus.Status.Video.Selfview.PIPPosition.Value.ToLower())); + _currentSelfviewPipPosition = + SelfviewPipPositions.FirstOrDefault( + p => p.Command.ToLower().Equals(CodecStatus.Status.Video.Selfview.PIPPosition.Value.ToLower())); if (_currentSelfviewPipPosition != null) SelfviewIsOnFeedback.FireUpdate(); @@ -2388,7 +3241,10 @@ void ComputeLocalLayout() public void RemoveCallHistoryEntry(CodecCallHistory.CallHistoryEntry entry) { - EnqueueCommand(string.Format("xCommand CallHistory DeleteEntry CallHistoryId: {0} AcknowledgeConsecutiveDuplicates: True", entry.OccurrenceHistoryId)); + EnqueueCommand( + string.Format( + "xCommand CallHistory DeleteEntry CallHistoryId: {0} AcknowledgeConsecutiveDuplicates: True", + entry.OccurrenceHistoryId)); } #region IHasCameraSpeakerTrack @@ -2405,7 +3261,71 @@ public void CameraAutoModeToggle() public void CameraAutoModeOn() { - if (!CodecStatus.Status.Cameras.SpeakerTrack.Availability.BoolValue) return; + switch (CameraTrackingCapabilities) + { + case eCameraTrackingCapabilities.None: + { + Debug.Console(0, this, "Camera Auto Mode Unavailable"); + break; + } + case eCameraTrackingCapabilities.PresenterTrack: + { + PresenterTrackFollow(); + break; + } + case eCameraTrackingCapabilities.SpeakerTrack: + { + SpeakerTrackOn(); + break; + } + case eCameraTrackingCapabilities.Both: + { + if (_preferredTrackingMode == eCameraTrackingCapabilities.SpeakerTrack) + { + SpeakerTrackOn(); + break; + } + PresenterTrackFollow(); + break; + } + } + } + + public void CameraAutoModeOff() + { + switch (CameraTrackingCapabilities) + { + case eCameraTrackingCapabilities.None: + { + Debug.Console(0, this, "Camera Auto Mode Unavailable"); + break; + } + case eCameraTrackingCapabilities.PresenterTrack: + { + PresenterTrackOff(); + break; + } + case eCameraTrackingCapabilities.SpeakerTrack: + { + SpeakerTrackOff(); + break; + } + case eCameraTrackingCapabilities.Both: + { + if (_preferredTrackingMode == eCameraTrackingCapabilities.SpeakerTrack) + { + SpeakerTrackOff(); + break; + } + PresenterTrackOff(); + break; + } + } + + } + + public void SpeakerTrackOn() + { if (CameraIsOffFeedback.BoolValue) { CameraMuteOff(); @@ -2414,7 +3334,7 @@ public void CameraAutoModeOn() EnqueueCommand("xCommand Cameras SpeakerTrack Activate"); } - public void CameraAutoModeOff() + public void SpeakerTrackOff() { if (CameraIsOffFeedback.BoolValue) { @@ -2422,13 +3342,20 @@ public void CameraAutoModeOff() } EnqueueCommand("xCommand Cameras SpeakerTrack Deactivate"); + } + + #endregion public void PresenterTrackOff() { - if (!CodecStatus.Status.Cameras.PresenterTrack.Availability.BoolValue) return; + if (!CodecStatus.Status.Cameras.PresenterTrack.Availability.BoolValue) + { + Debug.Console(0, this, "Presenter Track is Unavailable on this Codec"); + return; + } if (CameraIsOffFeedback.BoolValue) { CameraMuteOff(); @@ -2439,7 +3366,11 @@ public void PresenterTrackOff() public void PresenterTrackFollow() { - if (!CodecStatus.Status.Cameras.PresenterTrack.Availability.BoolValue) return; + if (!CodecStatus.Status.Cameras.PresenterTrack.Availability.BoolValue) + { + Debug.Console(0, this, "Presenter Track is Unavailable on this Codec"); + return; + } if (CameraIsOffFeedback.BoolValue) { CameraMuteOff(); @@ -2450,7 +3381,11 @@ public void PresenterTrackFollow() public void PresenterTrackBackground() { - if (!CodecStatus.Status.Cameras.PresenterTrack.Availability.BoolValue) return; + if (!CodecStatus.Status.Cameras.PresenterTrack.Availability.BoolValue) + { + Debug.Console(0, this, "Presenter Track is Unavailable on this Codec"); + return; + } if (CameraIsOffFeedback.BoolValue) { @@ -2462,7 +3397,11 @@ public void PresenterTrackBackground() public void PresenterTrackPersistent() { - if (!CodecStatus.Status.Cameras.PresenterTrack.Availability.BoolValue) return; + if (!CodecStatus.Status.Cameras.PresenterTrack.Availability.BoolValue) + { + Debug.Console(0, this, "Presenter Track is Unavailable on this Codec"); + return; + } if (CameraIsOffFeedback.BoolValue) { CameraMuteOff(); @@ -2477,7 +3416,7 @@ public void PresenterTrackPersistent() /// /// Builds the cameras List. Could later be modified to build from config data /// - void SetUpCameras(List cameraInfo) + private void SetUpCameras(List cameraInfo) { // Add the internal camera Cameras = new List(); @@ -2492,7 +3431,8 @@ void SetUpCameras(List cameraInfo) if (camCount > 0) { // Try to get the capabilities from the codec - if (CodecStatus.Status.Cameras.Camera[0] != null && CodecStatus.Status.Cameras.Camera[0].Capabilities != null) + if (CodecStatus.Status.Cameras.Camera[0] != null && + CodecStatus.Status.Cameras.Camera[0].Capabilities != null) { internalCamera.SetCapabilites(CodecStatus.Status.Cameras.Camera[0].Capabilities.Options.Value); } @@ -2508,14 +3448,14 @@ void SetUpCameras(List cameraInfo) { var cam = CodecStatus.Status.Cameras.Camera[i]; - var id = (uint)i; + var id = (uint) i; var name = string.Format("Camera {0}", id); // Check for a config object that matches the camera number var camInfo = cameraInfo.FirstOrDefault(c => c.CameraNumber == i + 1); if (camInfo != null) { - id = (uint)camInfo.SourceId; + id = (uint) camInfo.SourceId; name = camInfo.Name; } @@ -2550,7 +3490,8 @@ void SetUpCameras(List cameraInfo) FarEndRoomPresets.Add(new CodecRoomPreset(i, label, true, false)); } - SelectedCamera = Cameras[0]; ; // call the method to select the camera and ensure the feedbacks get updated. + SelectedCamera = Cameras[0]; + ; // call the method to select the camera and ensure the feedbacks get updated. } @@ -2569,10 +3510,7 @@ void SetUpCameras(List cameraInfo) /// public CameraBase SelectedCamera { - get - { - return _selectedCamera; - } + get { return _selectedCamera; } private set { _selectedCamera = value; @@ -2613,135 +3551,6 @@ public void SelectCamera(string key) #endregion - /// - /// - /// - public class CiscoCodecInfo : VideoCodecInfo - { - public CiscoCodecStatus.RootObject CodecStatus { get; private set; } - - public CiscoCodecConfiguration.RootObject CodecConfiguration { get; private set; } - - public override bool MultiSiteOptionIsEnabled - { - get - { - if (!string.IsNullOrEmpty(CodecStatus.Status.SystemUnit.Software.OptionKeys.MultiSite.Value) && CodecStatus.Status.SystemUnit.Software.OptionKeys.MultiSite.Value.ToLower() == "true") - return true; - else - return false; - } - - } - public override string IpAddress - { - get - { - var address = string.Empty; - if (CodecConfiguration.Configuration.Network.Count > 0) - { - if (!string.IsNullOrEmpty(CodecConfiguration.Configuration.Network[0].IPv4.Address.Value)) - address = CodecConfiguration.Configuration.Network[0].IPv4.Address.Value; - } - - if (string.IsNullOrEmpty(address) && CodecStatus.Status.Network.Count > 0) - { - if (!string.IsNullOrEmpty(CodecStatus.Status.Network[0].IPv4.Address.Value)) - address = CodecStatus.Status.Network[0].IPv4.Address.Value; - } - return address; - } - } - public override string E164Alias - { - get - { - if (CodecConfiguration.Configuration.H323 != null && CodecConfiguration.Configuration.H323.H323Alias.E164 != null) - { - return CodecConfiguration.Configuration.H323.H323Alias.E164.Value; - } - else - { - return string.Empty; - } - } - } - public override string H323Id - { - get - { - if (CodecConfiguration.Configuration.H323 != null && CodecConfiguration.Configuration.H323.H323Alias != null - && CodecConfiguration.Configuration.H323.H323Alias.ID != null) - { - return CodecConfiguration.Configuration.H323.H323Alias.ID.Value; - } - else - { - return string.Empty; - } - } - } - public override string SipPhoneNumber - { - get - { - if (CodecStatus.Status.SIP != null && CodecStatus.Status.SIP.Registration.Count > 0) - { - var match = Regex.Match(CodecStatus.Status.SIP.Registration[0].URI.Value, @"(\d+)"); // extract numbers only - if (match.Success) - { - Debug.Console(1, "Extracted phone number as '{0}' from string '{1}'", match.Groups[1].Value, CodecStatus.Status.SIP.Registration[0].URI.Value); - return match.Groups[1].Value; - } - else - { - Debug.Console(1, "Unable to extract phone number from string: '{0}'", CodecStatus.Status.SIP.Registration[0].URI.Value); - return string.Empty; - } - } - else - { - Debug.Console(1, "Unable to extract phone number. No SIP Registration items found"); - return string.Empty; - } - } - } - - public override string SipUri - { - get - { - if (CodecStatus.Status.SIP != null && CodecStatus.Status.SIP.AlternateURI.Primary.URI.Value != null) - { - return CodecStatus.Status.SIP.AlternateURI.Primary.URI.Value; - } - else if (CodecStatus.Status.UserInterface != null && - CodecStatus.Status.UserInterface.ContactInfo.ContactMethod[0].Number.Value != null) - { - return CodecStatus.Status.UserInterface.ContactInfo.ContactMethod[0].Number.Value; - } - else - return string.Empty; - } - } - - public override bool AutoAnswerEnabled - { - get - { - if (CodecConfiguration.Configuration.Conference.AutoAnswer.Mode.Value == null) return false; - return CodecConfiguration.Configuration.Conference.AutoAnswer.Mode.Value.ToLower() == "on"; - } - } - - public CiscoCodecInfo(CiscoCodecStatus.RootObject status, CiscoCodecConfiguration.RootObject configuration) - { - CodecStatus = status; - CodecConfiguration = configuration; - } - } - - #region IHasCameraPresets Members public event EventHandler CodecRoomPresetsListHasChanged; @@ -2761,14 +3570,17 @@ public void CodecRoomPresetSelect(int preset) public void CodecRoomPresetStore(int preset, string description) { - EnqueueCommand(string.Format("xCommand RoomPreset Store PresetId: {0} Description: \"{1}\" Type: All", preset, description)); + EnqueueCommand(string.Format("xCommand RoomPreset Store PresetId: {0} Description: \"{1}\" Type: All", + preset, description)); } #endregion public void SelectFarEndPreset(int preset) { - EnqueueCommand(string.Format("xCommand Call FarEndControl RoomPreset Activate CallId: {0} PresetId: {1}", GetCallId(), preset)); + EnqueueCommand( + string.Format("xCommand CiscoCall FarEndControl RoomPreset Activate CallId: {0} PresetId: {1}", + GetCallId(), preset)); } @@ -2777,11 +3589,7 @@ public void SelectFarEndPreset(int preset) /// /// Wheather the Cisco supports External Source Lists or not /// - public bool ExternalSourceListEnabled - { - get; - private set; - } + public bool ExternalSourceListEnabled { get; private set; } /// /// The name of the RoutingInputPort to which the upstream external switcher is connected @@ -2814,7 +3622,8 @@ public bool ExternalSourceListEnabled } * */ - public void AddExternalSource(string connectorId, string key, string name, PepperDash.Essentials.Devices.Common.VideoCodec.Cisco.eExternalSourceType type) + public void AddExternalSource(string connectorId, string key, string name, + PepperDash.Essentials.Devices.Common.VideoCodec.Cisco.eExternalSourceType type) { int id = 2; if (connectorId.ToLower() == "hdmiin3") @@ -2836,9 +3645,13 @@ public void AddExternalSource(string connectorId, string key, string name, Peppe /// /// /// - public void SetExternalSourceState(string key, PepperDash.Essentials.Devices.Common.VideoCodec.Cisco.eExternalSourceMode mode) + public void SetExternalSourceState(string key, + PepperDash.Essentials.Devices.Common.VideoCodec.Cisco.eExternalSourceMode mode) { - EnqueueCommand(string.Format("xCommand UserInterface Presentation ExternalSource State Set SourceIdentifier: \"{0}\" State: {1}", key, mode.ToString())); + EnqueueCommand( + string.Format( + "xCommand UserInterface Presentation ExternalSource State Set SourceIdentifier: \"{0}\" State: {1}", + key, mode.ToString())); } @@ -2856,7 +3669,8 @@ public void ClearExternalSources() /// public void SetSelectedSource(string key) { - EnqueueCommand(string.Format("xCommand UserInterface Presentation ExternalSource Select SourceIdentifier: {0}", key)); + EnqueueCommand( + string.Format("xCommand UserInterface Presentation ExternalSource Select SourceIdentifier: {0}", key)); _externalSourceChangeRequested = true; } @@ -2871,6 +3685,7 @@ public void SetSelectedSource(string key) #endregion + #region ExternalDevices @@ -2974,11 +3789,220 @@ public void UpdateDeviceInfo() raiseEvent(this, args); } } + + public void OnCodecInfoChanged(CodecInfoChangedEventArgs args) + { + var handler = CodecInfoChanged; + if (handler != null) + { + handler(this, args); + } + } + + } + + public class CodecInfoChangedEventArgs : EventArgs + { + public bool MultiSiteOptionIsEnabled { get; set; } + public string IpAddress { get; set; } + public string SipPhoneNumber { get; set; } + public string E164Alias { get; set; } + public string H323Id { get; set; } + public string SipUri { get; set; } + public bool AutoAnswerEnabled { get; set; } + + public eCodecInfoChangeType InfoChangeType; + + public CodecInfoChangedEventArgs() + { + InfoChangeType = eCodecInfoChangeType.Unknown; + } + + public CodecInfoChangedEventArgs(eCodecInfoChangeType changeType) + { + InfoChangeType = changeType; + } + + + } + + public enum eCodecInfoChangeType + { + AutoAnswer, + Network, + Sip, + H323, + Multisite, + Unknown + } + + + public class FeedbackGroup + { + private readonly FeedbackCollection _feedbacks; + + public FeedbackGroup(IEnumerable feedbacks) + { + _feedbacks = new FeedbackCollection(); + _feedbacks.AddRange(feedbacks); + } + + public void FireUpdate() + { + foreach (var f in _feedbacks) + { + var feedback = f; + feedback.FireUpdate(); + } + } + } + + public class MinuteChangedEventArgs : EventArgs + { + public DateTime EventTime { get; private set; } + + public MinuteChangedEventArgs(DateTime eventTime) + { + EventTime = eventTime; + } + + public MinuteChangedEventArgs() + { + EventTime = DateTime.Now; + } + } + + public class CameraTrackingCapabilitiesArgs : EventArgs + { + public eCameraTrackingCapabilities CameraTrackingCapabilites { get; set; } + + public CameraTrackingCapabilitiesArgs(bool speakerTrack, bool presenterTrack) + { + CameraTrackingCapabilites = SetCameraTrackingCapabilities(speakerTrack, presenterTrack); + } + + public CameraTrackingCapabilitiesArgs(Func speakerTrack, Func presenterTrack) + { + CameraTrackingCapabilites = SetCameraTrackingCapabilities(speakerTrack(), presenterTrack()); + } + + private eCameraTrackingCapabilities SetCameraTrackingCapabilities(bool speakerTrack, bool presenterTrack) + { + var trackingType = eCameraTrackingCapabilities.None; + + if (speakerTrack && presenterTrack) + { + trackingType = eCameraTrackingCapabilities.Both; + return trackingType; + } + if (!speakerTrack && presenterTrack) + { + trackingType = eCameraTrackingCapabilities.PresenterTrack; + return trackingType; + } + if (speakerTrack && !presenterTrack) + { + trackingType = eCameraTrackingCapabilities.SpeakerTrack; + return trackingType; + } + return trackingType; + + } + + + + } + public class CiscoCodecInfo : VideoCodecInfo + { + private readonly CiscoCodec _codec; + + private bool _multiSiteOptionIsEnabled; + public override bool MultiSiteOptionIsEnabled + { + get { return _multiSiteOptionIsEnabled; } + } + + private string _ipAddress; + + public override string IpAddress + { + get { return _ipAddress; } + } + + private string _sipPhoneNumber; + + public override string SipPhoneNumber + { + get { return _sipPhoneNumber; } + } + + private string _e164Alias; + + public override string E164Alias + { + get { return _e164Alias; } + } + + private string _h323Id; + + public override string H323Id + { + get { return _h323Id; } + } + + private string _sipUri; + + public override string SipUri + { + get { return _sipUri; } + } + + private bool _autoAnswerEnabled; + + public override bool AutoAnswerEnabled + { + get { return _autoAnswerEnabled; } + } + + public CiscoCodecInfo(CiscoCodec codec) + { + _codec = codec; + _codec.CodecInfoChanged += (sender, args) => + { + if (args.InfoChangeType == eCodecInfoChangeType.Unknown) return; + switch (args.InfoChangeType) + { + case eCodecInfoChangeType.Network: + _ipAddress = args.IpAddress; + break; + case eCodecInfoChangeType.Sip: + _sipPhoneNumber = args.SipPhoneNumber; + _sipUri = args.SipUri; + break; + case eCodecInfoChangeType.H323: + _h323Id = args.H323Id; + _e164Alias = args.E164Alias; + break; + case eCodecInfoChangeType.Multisite: + _multiSiteOptionIsEnabled = args.MultiSiteOptionIsEnabled; + break; + case eCodecInfoChangeType.AutoAnswer: + _autoAnswerEnabled = args.AutoAnswerEnabled; + break; + + } + }; + } + + } + + +} + -} \ No newline at end of file diff --git a/epi-videoCodec-ciscoExtended/IHasCiscoCodecLayouts.cs b/epi-videoCodec-ciscoExtended/IHasCiscoCodecLayouts.cs new file mode 100644 index 0000000..53013e0 --- /dev/null +++ b/epi-videoCodec-ciscoExtended/IHasCiscoCodecLayouts.cs @@ -0,0 +1,33 @@ +using System; +using System.Collections.Generic; +using PepperDash.Essentials.Core; +using PepperDash.Essentials.Devices.Common.VideoCodec; + +namespace epi_videoCodec_ciscoExtended +{ + /// + /// Defines the required elements for layout control with direct layout selection + /// + public interface IHasCodecLayoutsAvailable : IHasCodecLayouts + { + + event EventHandler AvailableLayoutsChanged; + event EventHandler CurrentLayoutChanged; + + StringFeedback AvailableLayoutsFeedback { get; } + List AvailableLayouts { get; } + void LayoutSet(string layout); + void LayoutSet(CodecCommandWithLabel layout); + + } + + public class AvailableLayoutsChangedEventArgs : EventArgs + { + public List AvailableLayouts { get; set; } + } + + public class CurrentLayoutChangedEventArgs : EventArgs + { + public string CurrentLayout { get; set; } + } +} diff --git a/epi-videoCodec-ciscoExtended/epi-videoCodec-ciscoExtended.csproj b/epi-videoCodec-ciscoExtended/epi-videoCodec-ciscoExtended.csproj index b1d7543..fd7f129 100644 --- a/epi-videoCodec-ciscoExtended/epi-videoCodec-ciscoExtended.csproj +++ b/epi-videoCodec-ciscoExtended/epi-videoCodec-ciscoExtended.csproj @@ -54,12 +54,12 @@ False ..\..\..\..\..\ProgramData\Crestron\SDK\SSPDevices\Crestron.SimplSharpPro.GeneralIO.dll - + False ..\packages\PepperDashEssentials\lib\net35\Essentials Devices Common.dll - + False ..\packages\PepperDashEssentials\lib\net35\PepperDashEssentials.dll @@ -113,6 +113,7 @@ + diff --git a/epi-videoCodec-ciscoExtended/xStatus.cs b/epi-videoCodec-ciscoExtended/xStatus.cs index 304e34c..65ed8e5 100644 --- a/epi-videoCodec-ciscoExtended/xStatus.cs +++ b/epi-videoCodec-ciscoExtended/xStatus.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.Runtime.InteropServices; using PepperDash.Core; using PepperDash.Essentials.Devices.Common.VideoCodec; using PepperDash.Essentials.Core.Presets; @@ -311,7 +312,7 @@ public string Value { // If the incoming value is "Available" it sets the BoolValue true, otherwise sets it false _Value = value; - BoolValue = value == "Available"; + BoolValue = value != "Unavailable"; OnValueChanged(); } } @@ -339,10 +340,13 @@ public string Value } } - public class Status2 : ValueProperty + public class SpeakerTrackStatus : ValueProperty { string _Value; public bool BoolValue { get; private set; } + public string StringValue { get; private set; } + + public List SpeakerTrackStatusValues { get; private set; } public string Value @@ -355,20 +359,26 @@ public string Value { // If the incoming value is "Active" it sets the BoolValue true, otherwise sets it false _Value = value; - BoolValue = value == "Active"; + BoolValue = value.ToLower() == "active"; + StringValue = value; OnValueChanged(); } } + + public SpeakerTrackStatus() + { + SpeakerTrackStatusValues = new List() { "active", "inactive" }; + } } public class SpeakerTrack { public Availability Availability { get; set; } - public Status2 Status { get; set; } + public SpeakerTrackStatus Status { get; set; } public SpeakerTrack() { - Status = new Status2(); + Status = new SpeakerTrackStatus(); Availability = new Availability(); } } @@ -376,19 +386,23 @@ public SpeakerTrack() public class PresenterTrack { public Availability Availability { get; set; } - public Status11 Status { get; set; } + public PresenterTrackStatus Status { get; set; } public PresenterTrack() { - Status = new Status11(); + Status = new PresenterTrackStatus(); Availability = new Availability(); } } - public class Status11 : ValueProperty + public class PresenterTrackStatus : ValueProperty { string _Value; + public string StringValue { get; private set; } + public bool BoolValue { get; private set; } + public List PresenterTrackStatusValues { get; private set; } + public string Value { get @@ -399,9 +413,16 @@ public string Value { // If the incoming value is "Active" it sets the BoolValue true, otherwise sets it false _Value = value; + StringValue = value; + BoolValue = value.ToLower() != "off"; OnValueChanged(); } } + + public PresenterTrackStatus() + { + PresenterTrackStatusValues = new List(){"off", "follow", "diagnostic", "background", "setup", "persistent"}; + } } public class Cameras @@ -410,13 +431,58 @@ public class Cameras public List Camera { get; set; } public SpeakerTrack SpeakerTrack { get; set; } public PresenterTrack PresenterTrack { get; set; } + //public CameraTrackingCapability CameraCapability { get; set; } public Cameras() { Camera = new List(); SpeakerTrack = new SpeakerTrack(); PresenterTrack = new PresenterTrack(); + //CameraCapability = new CameraTrackingCapability(SpeakerTrack, PresenterTrack); + } + } + + public class CameraTrackingCapability : ValueProperty + { + public eCameraTrackingCapabilities CameraTrackingCapabilities { get; private set; } + private readonly SpeakerTrack _speakerTrack; + private readonly PresenterTrack _presenterTrack; + + + public CameraTrackingCapability(SpeakerTrack speakerTrack, PresenterTrack presenterTrack) + { + _speakerTrack = speakerTrack; + _presenterTrack = presenterTrack; + } + + protected Func CameraTrackingFeedbackFunc + { + get + { + return () => + { + var trackingType = eCameraTrackingCapabilities.None; + + if (_speakerTrack.Availability.BoolValue && _presenterTrack.Availability.BoolValue) + { + trackingType = eCameraTrackingCapabilities.Both; + return trackingType; + } + if (!_speakerTrack.Availability.BoolValue && _presenterTrack.Availability.BoolValue) + { + trackingType = eCameraTrackingCapabilities.PresenterTrack; + return trackingType; + } + if (_speakerTrack.Availability.BoolValue && !_presenterTrack.Availability.BoolValue) + { + trackingType = eCameraTrackingCapabilities.SpeakerTrack; + return trackingType; + } + return trackingType; + }; + } } + } //public class CameraConverter : JsonConverter @@ -658,6 +724,7 @@ public bool LocalOnly if (string.IsNullOrEmpty(_Value)) return false; + return _Value.ToLower() == "localonly"; } } @@ -672,6 +739,17 @@ public bool LocalRemote return _Value.ToLower() == "localremote"; } } + + public bool Off + { + get + { + if (string.IsNullOrEmpty(_Value)) + return false; + + return _Value.ToLower() == "off"; + } + } } public class LocalInstance @@ -2275,7 +2353,7 @@ public class Status public Proximity Proximity { get; set; } public RoomAnalytics RoomAnalytics { get; set; } - public List RoomPreset { get; set; } + public List RoomPreset { get; set; } public SIP SIP { get; set; } public Security Security { get; set; } @@ -2292,7 +2370,7 @@ public Status() Standby = new Standby(); Cameras = new Cameras(); RoomAnalytics = new RoomAnalytics(); - RoomPreset = new List(); + RoomPreset = new List(); Conference = new Conference2(); SystemUnit = new SystemUnit(); Video = new Video(); @@ -2301,7 +2379,7 @@ public Status() } } - public class RoomPreset : IConvertiblePreset + public class RoomPreset : ConvertiblePreset { public string id { get; set; } public Defined Defined { get; set; } @@ -2315,13 +2393,13 @@ public RoomPreset() Type = new Type5(); } - public PresetBase ConvertCodecPreset() + public override PresetBase ConvertCodecPreset() { try { var preset = new CodecRoomPreset(UInt16.Parse(id), Description.Value, Defined.BoolValue, true); - Debug.Console(2, "Preset ID {0} Converted from Cisco Codec Preset to Essentials Preset"); + Debug.Console(2, "Preset ID {0} Converted from Cisco Codec Preset to Essentials Preset", id); return preset; } From 1e49fbe86a71312dfb41f4ea4e2f2054423a81eb Mon Sep 17 00:00:00 2001 From: Trevor Payne Date: Tue, 6 Sep 2022 00:28:42 -0500 Subject: [PATCH 6/8] test: Testing in Lab --- epi-videoCodec-ciscoExtended/CiscoCodecFactory.cs | 6 +++--- .../epi-videoCodec-ciscoExtended.nuspec | 2 +- packages.config | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/epi-videoCodec-ciscoExtended/CiscoCodecFactory.cs b/epi-videoCodec-ciscoExtended/CiscoCodecFactory.cs index 960ed44..d5945a8 100644 --- a/epi-videoCodec-ciscoExtended/CiscoCodecFactory.cs +++ b/epi-videoCodec-ciscoExtended/CiscoCodecFactory.cs @@ -10,7 +10,7 @@ public class CiscoCodecFactory : EssentialsPluginDeviceFactory { public CiscoCodecFactory() { - MinimumEssentialsFrameworkVersion = "1.10.6"; + MinimumEssentialsFrameworkVersion = "1.10.9"; TypeNames = new List() { "ciscoRoomOS" }; } @@ -28,9 +28,9 @@ public class CiscoCodecDevelopmentFactory : EssentialsPluginDevelopmentDeviceFac { public CiscoCodecDevelopmentFactory() { - MinimumEssentialsFrameworkVersion = "1.10.6"; + MinimumEssentialsFrameworkVersion = "1.10.9"; - DevelopmentEssentialsFrameworkVersions = new List() {"1.10.6-alpha-1897"}; + DevelopmentEssentialsFrameworkVersions = new List() {"1.10.9-alpha-1928"}; TypeNames = new List() { "ciscoRoomOS-development" }; } diff --git a/epi-videoCodec-ciscoExtended/epi-videoCodec-ciscoExtended.nuspec b/epi-videoCodec-ciscoExtended/epi-videoCodec-ciscoExtended.nuspec index bd42211..39112b4 100644 --- a/epi-videoCodec-ciscoExtended/epi-videoCodec-ciscoExtended.nuspec +++ b/epi-videoCodec-ciscoExtended/epi-videoCodec-ciscoExtended.nuspec @@ -11,7 +11,7 @@ https://github.com/PepperDash/epi-videoCodec-ciscoExtended Copyright 2022 This software is a plugin designed to work as a part of PepperDash Essentials for Crestron control processors. This plugin allows for control of a Cisco RoomOs Video Codec using SSH - crestron 3series 4series samsung + crestron 3series 4series samsung cisco webex webexpro vtc videocodec codec diff --git a/packages.config b/packages.config index b3a5914..39d91f5 100644 --- a/packages.config +++ b/packages.config @@ -1,3 +1,3 @@ - + \ No newline at end of file From 3e360ab612bb4273e5f693b17316b18174a74df8 Mon Sep 17 00:00:00 2001 From: Trevor Payne Date: Wed, 7 Sep 2022 21:10:43 -0500 Subject: [PATCH 7/8] ci: updated workflows build: updated packages.conf for proper build version build: referenced newest rc build of essentials --- .../essentialsplugins-betabuilds.yml | 24 +++++--- .../essentialsplugins-releasebuilds.yml | 24 +++++--- packages.config | 2 +- .../BookingsDataClasses.cs | 0 .../CallHistoryDataClasses.cs | 0 .../CiscoCamera.cs | 0 .../CiscoCodecConfig.cs | 0 .../CiscoCodecFactory.cs | 6 +- .../CiscoCodecJoinMap.cs | 14 ----- .../CiscoCodecPhonebookDataClasses.cs | 0 .../CiscoRoomOsCodec.cs | 58 +++++++++++++------ .../CodecSyncState.cs | 0 .../HttpApiServerExtended.cs | 0 .../IHasCiscoCodecLayouts.cs | 0 .../Properties/AssemblyInfo.cs | 0 .../Properties/ControlSystem.cfg | 0 .../epi-videoCodec-ciscoExtended.csproj | 0 .../epi-videoCodec-ciscoExtended.nuspec | 2 + .../epi-videoCodec-ciscoExtended.sln | 0 .../xConfiguration.cs | 0 .../xEvent.cs | 0 .../xStatus.cs | 0 .../xStatusSparkPlus.cs | 0 23 files changed, 79 insertions(+), 51 deletions(-) rename {epi-videoCodec-ciscoExtended => src}/BookingsDataClasses.cs (100%) rename {epi-videoCodec-ciscoExtended => src}/CallHistoryDataClasses.cs (100%) rename {epi-videoCodec-ciscoExtended => src}/CiscoCamera.cs (100%) rename {epi-videoCodec-ciscoExtended => src}/CiscoCodecConfig.cs (100%) rename {epi-videoCodec-ciscoExtended => src}/CiscoCodecFactory.cs (89%) rename {epi-videoCodec-ciscoExtended => src}/CiscoCodecJoinMap.cs (97%) rename {epi-videoCodec-ciscoExtended => src}/CiscoCodecPhonebookDataClasses.cs (100%) rename {epi-videoCodec-ciscoExtended => src}/CiscoRoomOsCodec.cs (98%) rename {epi-videoCodec-ciscoExtended => src}/CodecSyncState.cs (100%) rename {epi-videoCodec-ciscoExtended => src}/HttpApiServerExtended.cs (100%) rename {epi-videoCodec-ciscoExtended => src}/IHasCiscoCodecLayouts.cs (100%) rename {epi-videoCodec-ciscoExtended => src}/Properties/AssemblyInfo.cs (100%) rename {epi-videoCodec-ciscoExtended => src}/Properties/ControlSystem.cfg (100%) rename {epi-videoCodec-ciscoExtended => src}/epi-videoCodec-ciscoExtended.csproj (100%) rename {epi-videoCodec-ciscoExtended => src}/epi-videoCodec-ciscoExtended.nuspec (92%) rename {epi-videoCodec-ciscoExtended => src}/epi-videoCodec-ciscoExtended.sln (100%) rename {epi-videoCodec-ciscoExtended => src}/xConfiguration.cs (100%) rename {epi-videoCodec-ciscoExtended => src}/xEvent.cs (100%) rename {epi-videoCodec-ciscoExtended => src}/xStatus.cs (100%) rename {epi-videoCodec-ciscoExtended => src}/xStatusSparkPlus.cs (100%) diff --git a/.github/workflows/essentialsplugins-betabuilds.yml b/.github/workflows/essentialsplugins-betabuilds.yml index ad34045..d6e6780 100644 --- a/.github/workflows/essentialsplugins-betabuilds.yml +++ b/.github/workflows/essentialsplugins-betabuilds.yml @@ -153,7 +153,7 @@ jobs: $exclusions = "packages" # Trying to get any .json schema files (not currently working) # Gets any files with the listed extensions. - Get-ChildItem -recurse -Path "$($Env:GITHUB_WORKSPACE)" -include "*.clz", "*.cpz", "*.cplz", "*.nuspec" | ForEach-Object { + Get-ChildItem -recurse -Path "$($Env:GITHUB_WORKSPACE)" -include "*.clz", "*.cpz", "*.cplz", "*.nuspec", "*.md" | ForEach-Object { $allowed = $true; # Exclude any files in submodules foreach ($exclude in $exclusions) { @@ -253,19 +253,27 @@ jobs: - name: Get nuget File shell: powershell run: | - $nuspec_file = Get-ChildItem *.nuspec -recurse - echo "NUSPEC_FILE=$($nuspec_file.BaseName)"| Out-File -FilePath $env:GITHUB_ENV -Encoding utf8 -Append + $nuspec_file = (Get-ChildItem *.nuspec -recurse).BaseName + echo "NUSPEC_FILE=$($nuspec_file)" | Out-File -FilePath $env:GITHUB_ENV -Encoding utf8 -Append + # Pulls the nuget builder packages - name: Add nuget.exe + if: "!contains(env.NUSPEC_FILE, 'EssentialsPluginTemplate')" uses: nuget/setup-nuget@v1 + # Creating nuget Packages - name: Add Github Packages source + if: "!contains(env.NUSPEC_FILE, 'EssentialsPluginTemplate')" run: nuget sources add -name github -source https://nuget.pkg.github.com/pepperdash/index.json -username Pepperdash -password ${{ secrets.GITHUB_TOKEN }} - # Pushes to nuget, not needed unless publishing publicly - - name: Add nuget.org API Key - run: nuget setApiKey ${{ secrets.NUGET_API_KEY }} - name: Create nuget package + if: "!contains(env.NUSPEC_FILE, 'EssentialsPluginTemplate')" run: nuget pack "./${{ env.NUSPEC_FILE}}.nuspec" -version ${{ env.VERSION }} + # Pushes to internal github registry - name: Publish nuget package to Github registry + if: "!contains(env.NUSPEC_FILE, 'EssentialsPluginTemplate')" run: nuget push **/*.nupkg -source github - # Pushes to nuget, not needed unless publishing publicly >> this pushes package to nuget.org + # Pushes to nuget gallery + - name: Add nuget.org API Key + if: github.repository_owner == 'PepperDash' && github.repository_visibility == 'public' && !contains(env.NUSPEC_FILE, 'EssentialsPluginTemplate') + run: nuget setApiKey ${{ secrets.NUGET_API_KEY }} - name: Publish nuget package to nuget.org - run: nuget push **/*.nupkg -Source https://api.nuget.org/v3/index.json + if: github.repository_owner == 'PepperDash' && github.repository_visibility == 'public' && !contains(env.NUSPEC_FILE, 'EssentialsPluginTemplate') + run: nuget push **/*.nupkg -Source https://api.nuget.org/v3/index.json \ No newline at end of file diff --git a/.github/workflows/essentialsplugins-releasebuilds.yml b/.github/workflows/essentialsplugins-releasebuilds.yml index 3e169ce..2aa5af3 100644 --- a/.github/workflows/essentialsplugins-releasebuilds.yml +++ b/.github/workflows/essentialsplugins-releasebuilds.yml @@ -111,7 +111,7 @@ jobs: $exclusions = "packages" # Trying to get any .json schema files (not currently working) # Gets any files with the listed extensions. - Get-ChildItem -recurse -Path "$($Env:GITHUB_WORKSPACE)" -include "*.clz", "*.cpz", "*.cplz", "*.nuspec" | ForEach-Object { + Get-ChildItem -recurse -Path "$($Env:GITHUB_WORKSPACE)" -include "*.clz", "*.cpz", "*.cplz", "*.nuspec", "*.md" | ForEach-Object { $allowed = $true; # Exclude any files in submodules foreach ($exclude in $exclusions) { @@ -201,19 +201,27 @@ jobs: - name: Get nuget File shell: powershell run: | - $nuspec_file = Get-ChildItem *.nuspec -recurse - echo "NUSPEC_FILE=$($nuspec_file.BaseName)"| Out-File -FilePath $env:GITHUB_ENV -Encoding utf8 -Append + $nuspec_file = (Get-ChildItem *.nuspec -recurse).BaseName + echo "NUSPEC_FILE=$($nuspec_file)" | Out-File -FilePath $env:GITHUB_ENV -Encoding utf8 -Append + # Pulls the nuget builder packages - name: Add nuget.exe + if: "!contains(env.NUSPEC_FILE, 'EssentialsPluginTemplate')" uses: nuget/setup-nuget@v1 + # Creating nuget Packages - name: Add Github Packages source + if: "!contains(env.NUSPEC_FILE, 'EssentialsPluginTemplate')" run: nuget sources add -name github -source https://nuget.pkg.github.com/pepperdash/index.json -username Pepperdash -password ${{ secrets.GITHUB_TOKEN }} - # Pushes to nuget, not needed unless publishing publicly - - name: Add nuget.org API Key - run: nuget setApiKey ${{ secrets.NUGET_API_KEY }} - name: Create nuget package + if: "!contains(env.NUSPEC_FILE, 'EssentialsPluginTemplate')" run: nuget pack "./${{ env.NUSPEC_FILE}}.nuspec" -version ${{ env.VERSION }} + # Pushes to internal github registry - name: Publish nuget package to Github registry + if: "!contains(env.NUSPEC_FILE, 'EssentialsPluginTemplate')" run: nuget push **/*.nupkg -source github - # Pushes to nuget, not needed unless publishing publicly >> this pushes package to nuget.org + # Pushes to nuget gallery + - name: Add nuget.org API Key + if: github.repository_owner == 'PepperDash' && github.repository_visibility == 'public' && !contains(env.NUSPEC_FILE, 'EssentialsPluginTemplate') + run: nuget setApiKey ${{ secrets.NUGET_API_KEY }} - name: Publish nuget package to nuget.org - run: nuget push **/*.nupkg -Source https://api.nuget.org/v3/index.json + if: github.repository_owner == 'PepperDash' && github.repository_visibility == 'public' && !contains(env.NUSPEC_FILE, 'EssentialsPluginTemplate') + run: nuget push **/*.nupkg -Source https://api.nuget.org/v3/index.json \ No newline at end of file diff --git a/packages.config b/packages.config index 39d91f5..9f60f85 100644 --- a/packages.config +++ b/packages.config @@ -1,3 +1,3 @@ - + \ No newline at end of file diff --git a/epi-videoCodec-ciscoExtended/BookingsDataClasses.cs b/src/BookingsDataClasses.cs similarity index 100% rename from epi-videoCodec-ciscoExtended/BookingsDataClasses.cs rename to src/BookingsDataClasses.cs diff --git a/epi-videoCodec-ciscoExtended/CallHistoryDataClasses.cs b/src/CallHistoryDataClasses.cs similarity index 100% rename from epi-videoCodec-ciscoExtended/CallHistoryDataClasses.cs rename to src/CallHistoryDataClasses.cs diff --git a/epi-videoCodec-ciscoExtended/CiscoCamera.cs b/src/CiscoCamera.cs similarity index 100% rename from epi-videoCodec-ciscoExtended/CiscoCamera.cs rename to src/CiscoCamera.cs diff --git a/epi-videoCodec-ciscoExtended/CiscoCodecConfig.cs b/src/CiscoCodecConfig.cs similarity index 100% rename from epi-videoCodec-ciscoExtended/CiscoCodecConfig.cs rename to src/CiscoCodecConfig.cs diff --git a/epi-videoCodec-ciscoExtended/CiscoCodecFactory.cs b/src/CiscoCodecFactory.cs similarity index 89% rename from epi-videoCodec-ciscoExtended/CiscoCodecFactory.cs rename to src/CiscoCodecFactory.cs index d5945a8..4c3d763 100644 --- a/epi-videoCodec-ciscoExtended/CiscoCodecFactory.cs +++ b/src/CiscoCodecFactory.cs @@ -10,7 +10,7 @@ public class CiscoCodecFactory : EssentialsPluginDeviceFactory { public CiscoCodecFactory() { - MinimumEssentialsFrameworkVersion = "1.10.9"; + MinimumEssentialsFrameworkVersion = "1.11.0"; TypeNames = new List() { "ciscoRoomOS" }; } @@ -28,9 +28,9 @@ public class CiscoCodecDevelopmentFactory : EssentialsPluginDevelopmentDeviceFac { public CiscoCodecDevelopmentFactory() { - MinimumEssentialsFrameworkVersion = "1.10.9"; + MinimumEssentialsFrameworkVersion = "1.11.0"; - DevelopmentEssentialsFrameworkVersions = new List() {"1.10.9-alpha-1928"}; + DevelopmentEssentialsFrameworkVersions = new List() {"1.11.0-rc-1935"}; TypeNames = new List() { "ciscoRoomOS-development" }; } diff --git a/epi-videoCodec-ciscoExtended/CiscoCodecJoinMap.cs b/src/CiscoCodecJoinMap.cs similarity index 97% rename from epi-videoCodec-ciscoExtended/CiscoCodecJoinMap.cs rename to src/CiscoCodecJoinMap.cs index b61c7c8..1073541 100644 --- a/epi-videoCodec-ciscoExtended/CiscoCodecJoinMap.cs +++ b/src/CiscoCodecJoinMap.cs @@ -7,21 +7,7 @@ namespace epi_videoCodec_ciscoExtended { public class CiscoCodecJoinMap : VideoCodecControllerJoinMap { - #region Digital - [JoinName("PhoneBookClearSelected")] - public JoinDataComplete PhoneBookClearSelected = new JoinDataComplete( - new JoinData - { - JoinNumber = 110, - JoinSpan = 1 - }, - new JoinMetadata - { - Description = "Clear Selected Entry and String from Search", - JoinCapabilities = eJoinCapabilities.FromSIMPL, - JoinType = eJoinType.Digital - }); [JoinName("PresenterTrackOff")] diff --git a/epi-videoCodec-ciscoExtended/CiscoCodecPhonebookDataClasses.cs b/src/CiscoCodecPhonebookDataClasses.cs similarity index 100% rename from epi-videoCodec-ciscoExtended/CiscoCodecPhonebookDataClasses.cs rename to src/CiscoCodecPhonebookDataClasses.cs diff --git a/epi-videoCodec-ciscoExtended/CiscoRoomOsCodec.cs b/src/CiscoRoomOsCodec.cs similarity index 98% rename from epi-videoCodec-ciscoExtended/CiscoRoomOsCodec.cs rename to src/CiscoRoomOsCodec.cs index 5348a76..cda6bf3 100644 --- a/epi-videoCodec-ciscoExtended/CiscoRoomOsCodec.cs +++ b/src/CiscoRoomOsCodec.cs @@ -72,7 +72,7 @@ public enum eCameraTrackingCapabilities } - public class CiscoCodec : VideoCodecBase, IHasCallHistory, IHasCallFavorites, IHasDirectoryClearSelection, + public class CiscoCodec : VideoCodecBase, IHasCallHistory, IHasCallFavorites, IHasDirectory, IHasScheduleAwareness, IOccupancyStatusProvider, IHasCodecLayoutsAvailable, IHasCodecSelfView, ICommunicationMonitor, IRouting, IHasCodecCameras, IHasCameraAutoMode, IHasCodecRoomPresets, IHasExternalSourceSwitching, IHasBranding, IHasCameraOff, IHasCameraMute, IHasDoNotDisturbMode, @@ -98,6 +98,8 @@ public class CiscoCodec : VideoCodecBase, IHasCallHistory, IHasCallFavorites, IH private const int XSigEncoding = 28591; + private List _currentMeetings; + private const string TestedCodecFirmware = "10.11.5.2"; private Meeting _currentMeeting; @@ -144,8 +146,6 @@ public class CiscoCodec : VideoCodecBase, IHasCallHistory, IHasCallFavorites, IH public IntFeedback PeopleCountFeedback { get; private set; } - private List _currentMeetings = new List(); - public BoolFeedback SelfviewIsOnFeedback { get; private set; } public StringFeedback SelfviewPipPositionFeedback { get; private set; } @@ -737,11 +737,6 @@ private void CiscoCodec_CallStatusChange(object sender, CodecCallStatusItemChang OnCurrentLayoutChanged(String.Empty); } - public void DirectoryClearSelection() - { - DirectoryClearSelectionBase(); - } - private string UpdateActiveMeetingXSig(Meeting currentMeeting) { // TODO [ ] hotfix/videocodecbase-max-meeting-xsig-set @@ -2347,7 +2342,6 @@ private void PrintDirectory(CodecDirectory directory) public override void Dial(string number) { EnqueueCommand(string.Format("xCommand Dial Number: \"{0}\"", number)); - DirectoryClearSelection(); } /// @@ -2360,7 +2354,6 @@ public override void Dial(Meeting meeting) { Dial(c.Number, c.Protocol, c.CallRate, c.CallType, meeting.Id); } - DirectoryClearSelection(); } /// @@ -2376,7 +2369,6 @@ public void Dial(string number, string protocol, string callRate, string callTyp EnqueueCommand( string.Format("xCommand Dial Number: \"{0}\" Protocol: {1} CallRate: {2} CallType: {3} BookingId: {4}", number, protocol, callRate, callType, meetingId)); - DirectoryClearSelection(); } @@ -2651,8 +2643,7 @@ public override void LinkToApi(BasicTriList trilist, uint joinStart, string join public void LinkCiscoCodecToApi(BasicTriList trilist, CiscoCodecJoinMap joinMap) { // Custom commands to codec - trilist.SetStringSigAction(joinMap.CommandToDevice.JoinNumber, (s) => this.EnqueueCommand(s)); - + trilist.SetStringSigAction(joinMap.CommandToDevice.JoinNumber, EnqueueCommand); var dndCodec = this as IHasDoNotDisturbMode; if (dndCodec != null) @@ -2673,10 +2664,43 @@ public void LinkCiscoCodecToApi(BasicTriList trilist, CiscoCodecJoinMap joinMap) var scheduleCodec = this as IHasScheduleAwareness; if (scheduleCodec != null) { + trilist.SetSigFalseAction(joinMap.DialMeeting1.JoinNumber, () => + { + const int mtg = 1; + const int index = mtg - 1; + Debug.Console(1, this, + "Meeting {0} Selected (EISC dig-o{1}) > _currentMeetings[{2}].Id: {3}, Title: {4}", + mtg, joinMap.DialMeeting1.JoinNumber, index, _currentMeetings[index].Id, + _currentMeetings[index].Title); + if (_currentMeetings[index] != null) + Dial(_currentMeetings[index]); + }); + trilist.SetSigFalseAction(joinMap.DialMeeting2.JoinNumber, () => + { + const int mtg = 2; + const int index = mtg - 1; + Debug.Console(1, this, + "Meeting {0} Selected (EISC dig-o{1}) > _currentMeetings[{2}].Id: {3}, Title: {4}", + mtg, joinMap.DialMeeting2.JoinNumber, index, _currentMeetings[index].Id, + _currentMeetings[index].Title); + if (_currentMeetings[index] != null) + Dial(_currentMeetings[index]); + }); + trilist.SetSigFalseAction(joinMap.DialMeeting3.JoinNumber, () => + { + const int mtg = 3; + const int index = mtg - 1; + Debug.Console(1, this, + "Meeting {0} Selected (EISC dig-o{1}) > _currentMeetings[{2}].Id: {3}, Title: {4}", + mtg, joinMap.DialMeeting3.JoinNumber, index, _currentMeetings[index].Id, + _currentMeetings[index].Title); + if (_currentMeetings[index] != null) + Dial(_currentMeetings[index]); + }); trilist.SetSigFalseAction(joinMap.DialMeeting4.JoinNumber, () => { - var mtg = 4; - var index = mtg - 1; + const int mtg = 4; + const int index = mtg - 1; Debug.Console(1, this, "Meeting {0} Selected (EISC dig-o{1}) > _currentMeetings[{2}].Id: {3}, Title: {4}", mtg, joinMap.DialMeeting4.JoinNumber, index, _currentMeetings[index].Id, @@ -2687,8 +2711,8 @@ public void LinkCiscoCodecToApi(BasicTriList trilist, CiscoCodecJoinMap joinMap) trilist.SetSigFalseAction(joinMap.DialMeeting5.JoinNumber, () => { - var mtg = 5; - var index = mtg - 1; + const int mtg = 5; + const int index = mtg - 1; Debug.Console(1, this, "Meeting {0} Selected (EISC dig-o{1}) > _currentMeetings[{2}].Id: {3}, Title: {4}", mtg, joinMap.DialMeeting5.JoinNumber, index, _currentMeetings[index].Id, diff --git a/epi-videoCodec-ciscoExtended/CodecSyncState.cs b/src/CodecSyncState.cs similarity index 100% rename from epi-videoCodec-ciscoExtended/CodecSyncState.cs rename to src/CodecSyncState.cs diff --git a/epi-videoCodec-ciscoExtended/HttpApiServerExtended.cs b/src/HttpApiServerExtended.cs similarity index 100% rename from epi-videoCodec-ciscoExtended/HttpApiServerExtended.cs rename to src/HttpApiServerExtended.cs diff --git a/epi-videoCodec-ciscoExtended/IHasCiscoCodecLayouts.cs b/src/IHasCiscoCodecLayouts.cs similarity index 100% rename from epi-videoCodec-ciscoExtended/IHasCiscoCodecLayouts.cs rename to src/IHasCiscoCodecLayouts.cs diff --git a/epi-videoCodec-ciscoExtended/Properties/AssemblyInfo.cs b/src/Properties/AssemblyInfo.cs similarity index 100% rename from epi-videoCodec-ciscoExtended/Properties/AssemblyInfo.cs rename to src/Properties/AssemblyInfo.cs diff --git a/epi-videoCodec-ciscoExtended/Properties/ControlSystem.cfg b/src/Properties/ControlSystem.cfg similarity index 100% rename from epi-videoCodec-ciscoExtended/Properties/ControlSystem.cfg rename to src/Properties/ControlSystem.cfg diff --git a/epi-videoCodec-ciscoExtended/epi-videoCodec-ciscoExtended.csproj b/src/epi-videoCodec-ciscoExtended.csproj similarity index 100% rename from epi-videoCodec-ciscoExtended/epi-videoCodec-ciscoExtended.csproj rename to src/epi-videoCodec-ciscoExtended.csproj diff --git a/epi-videoCodec-ciscoExtended/epi-videoCodec-ciscoExtended.nuspec b/src/epi-videoCodec-ciscoExtended.nuspec similarity index 92% rename from epi-videoCodec-ciscoExtended/epi-videoCodec-ciscoExtended.nuspec rename to src/epi-videoCodec-ciscoExtended.nuspec index 39112b4..de688c6 100644 --- a/epi-videoCodec-ciscoExtended/epi-videoCodec-ciscoExtended.nuspec +++ b/src/epi-videoCodec-ciscoExtended.nuspec @@ -2,6 +2,7 @@ PepperDash.Essentials.Plugin.CiscoRoomOsCodec + docs\README.md 2.0.2 Cisco RoomOs Codec Essentials Plugin PepperDash Technologies @@ -17,5 +18,6 @@ + \ No newline at end of file diff --git a/epi-videoCodec-ciscoExtended/epi-videoCodec-ciscoExtended.sln b/src/epi-videoCodec-ciscoExtended.sln similarity index 100% rename from epi-videoCodec-ciscoExtended/epi-videoCodec-ciscoExtended.sln rename to src/epi-videoCodec-ciscoExtended.sln diff --git a/epi-videoCodec-ciscoExtended/xConfiguration.cs b/src/xConfiguration.cs similarity index 100% rename from epi-videoCodec-ciscoExtended/xConfiguration.cs rename to src/xConfiguration.cs diff --git a/epi-videoCodec-ciscoExtended/xEvent.cs b/src/xEvent.cs similarity index 100% rename from epi-videoCodec-ciscoExtended/xEvent.cs rename to src/xEvent.cs diff --git a/epi-videoCodec-ciscoExtended/xStatus.cs b/src/xStatus.cs similarity index 100% rename from epi-videoCodec-ciscoExtended/xStatus.cs rename to src/xStatus.cs diff --git a/epi-videoCodec-ciscoExtended/xStatusSparkPlus.cs b/src/xStatusSparkPlus.cs similarity index 100% rename from epi-videoCodec-ciscoExtended/xStatusSparkPlus.cs rename to src/xStatusSparkPlus.cs From e6bb1c6bb34c5ab173c0e4558929d2bae8b00c4e Mon Sep 17 00:00:00 2001 From: Trevor Payne Date: Thu, 8 Sep 2022 13:43:50 -0500 Subject: [PATCH 8/8] build: fix essentials references --- src/epi-videoCodec-ciscoExtended.csproj | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/epi-videoCodec-ciscoExtended.csproj b/src/epi-videoCodec-ciscoExtended.csproj index fd7f129..21ebe44 100644 --- a/src/epi-videoCodec-ciscoExtended.csproj +++ b/src/epi-videoCodec-ciscoExtended.csproj @@ -54,12 +54,12 @@ False ..\..\..\..\..\ProgramData\Crestron\SDK\SSPDevices\Crestron.SimplSharpPro.GeneralIO.dll - + False ..\packages\PepperDashEssentials\lib\net35\Essentials Devices Common.dll - + False ..\packages\PepperDashEssentials\lib\net35\PepperDashEssentials.dll @@ -67,11 +67,11 @@ False ..\packages\PepperDashEssentials\lib\net35\PepperDash_Core.dll - + False ..\packages\PepperDashEssentials\lib\net35\PepperDash_Essentials_Core.dll - + False ..\packages\PepperDashEssentials\lib\net35\PepperDash_Essentials_DM.dll