From 6dd882b1a0d56f57f9229f5e958501a378809442 Mon Sep 17 00:00:00 2001 From: Neil Dorin Date: Wed, 10 Nov 2021 13:49:43 -0700 Subject: [PATCH 01/59] feat(essentials): Adds hold/resume/duration features to call status --- .../Codec/CodecActiveCallItem.cs | 20 ++++++---- .../Codec/IHasCallHold.cs | 23 +++++++++++ .../Essentials Devices Common.csproj | 1 + .../VideoCodec/CiscoCodec/CiscoSparkCodec.cs | 36 +++++++++++++++-- .../VideoCodec/CiscoCodec/xStatus.cs | 40 +++++++++++++++++-- 5 files changed, 106 insertions(+), 14 deletions(-) create mode 100644 essentials-framework/Essentials Devices Common/Essentials Devices Common/Codec/IHasCallHold.cs diff --git a/essentials-framework/Essentials Devices Common/Essentials Devices Common/Codec/CodecActiveCallItem.cs b/essentials-framework/Essentials Devices Common/Essentials Devices Common/Codec/CodecActiveCallItem.cs index 75c4fc1a..d1dbdf5f 100644 --- a/essentials-framework/Essentials Devices Common/Essentials Devices Common/Codec/CodecActiveCallItem.cs +++ b/essentials-framework/Essentials Devices Common/Essentials Devices Common/Codec/CodecActiveCallItem.cs @@ -12,34 +12,40 @@ namespace PepperDash.Essentials.Devices.Common.Codec { public class CodecActiveCallItem { - [JsonProperty("name")] + [JsonProperty("name", NullValueHandling = NullValueHandling.Ignore)] public string Name { get; set; } - [JsonProperty("number")] + [JsonProperty("number", NullValueHandling = NullValueHandling.Ignore)] public string Number { get; set; } - [JsonProperty("type")] + [JsonProperty("type", NullValueHandling = NullValueHandling.Ignore)] [JsonConverter(typeof(StringEnumConverter))] public eCodecCallType Type { get; set; } - [JsonProperty("status")] + [JsonProperty("status", NullValueHandling = NullValueHandling.Ignore)] [JsonConverter(typeof(StringEnumConverter))] public eCodecCallStatus Status { get; set; } - [JsonProperty("direction")] + [JsonProperty("direction", NullValueHandling = NullValueHandling.Ignore)] [JsonConverter(typeof(StringEnumConverter))] public eCodecCallDirection Direction { get; set; } - [JsonProperty("id")] + [JsonProperty("id", NullValueHandling = NullValueHandling.Ignore)] public string Id { get; set; } + [JsonProperty("isOnHold", NullValueHandling = NullValueHandling.Ignore)] + public bool IsOnHold { get; set; } + + [JsonProperty("duration", NullValueHandling = NullValueHandling.Ignore)] + public TimeSpan Duration { get; set; } + //public object CallMetaData { get; set; } /// /// Returns true when this call is any status other than /// Unknown, Disconnected, Disconnecting /// - [JsonProperty("isActiveCall")] + [JsonProperty("isActiveCall", NullValueHandling = NullValueHandling.Ignore)] public bool IsActiveCall { get diff --git a/essentials-framework/Essentials Devices Common/Essentials Devices Common/Codec/IHasCallHold.cs b/essentials-framework/Essentials Devices Common/Essentials Devices Common/Codec/IHasCallHold.cs new file mode 100644 index 00000000..78211841 --- /dev/null +++ b/essentials-framework/Essentials Devices Common/Essentials Devices Common/Codec/IHasCallHold.cs @@ -0,0 +1,23 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using Crestron.SimplSharp; + +namespace PepperDash.Essentials.Devices.Common.Codec +{ + public interface IHasCallHold + { + /// + /// Put the specified call on hold + /// + /// + void HoldCall(CodecActiveCallItem activeCall); + + /// + /// Resume the specified call + /// + /// + void ResumeCall(CodecActiveCallItem activeCall); + } +} \ No newline at end of file diff --git a/essentials-framework/Essentials Devices Common/Essentials Devices Common/Essentials Devices Common.csproj b/essentials-framework/Essentials Devices Common/Essentials Devices Common/Essentials Devices Common.csproj index 1fcffff2..b3f78d0e 100644 --- a/essentials-framework/Essentials Devices Common/Essentials Devices Common/Essentials Devices Common.csproj +++ b/essentials-framework/Essentials Devices Common/Essentials Devices Common/Essentials Devices Common.csproj @@ -108,6 +108,7 @@ + diff --git a/essentials-framework/Essentials Devices Common/Essentials Devices Common/VideoCodec/CiscoCodec/CiscoSparkCodec.cs b/essentials-framework/Essentials Devices Common/Essentials Devices Common/VideoCodec/CiscoCodec/CiscoSparkCodec.cs index 2d3645f0..99021350 100644 --- a/essentials-framework/Essentials Devices Common/Essentials Devices Common/VideoCodec/CiscoCodec/CiscoSparkCodec.cs +++ b/essentials-framework/Essentials Devices Common/Essentials Devices Common/VideoCodec/CiscoCodec/CiscoSparkCodec.cs @@ -30,7 +30,7 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.Cisco IHasScheduleAwareness, IOccupancyStatusProvider, IHasCodecLayouts, IHasCodecSelfView, ICommunicationMonitor, IRouting, IHasCodecCameras, IHasCameraAutoMode, IHasCodecRoomPresets, IHasExternalSourceSwitching, IHasBranding, IHasCameraOff, IHasCameraMute, IHasDoNotDisturbMode, - IHasHalfWakeMode + IHasHalfWakeMode, IHasCallHold { private bool _externalSourceChangeRequested; @@ -847,6 +847,19 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.Cisco changeDetected = true; } } + if(call.Duration != null) + { + if(!string.IsNullOrEmpty(call.Duration.Value)) + { + tempActiveCall.Duration = call.Duration.DurationValue; + changeDetected = true; + } + } + if(call.PlacedOnHold != null) + { + tempActiveCall.IsOnHold = call.PlacedOnHold.BoolValue; + changeDetected = true; + } if (changeDetected) { @@ -865,7 +878,9 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.Cisco Name = call.DisplayName.Value, Number = call.RemoteNumber.Value, Type = CodecCallType.ConvertToTypeEnum(call.CallType.Value), - Direction = CodecCallDirection.ConvertToDirectionEnum(call.Direction.Value) + Direction = CodecCallDirection.ConvertToDirectionEnum(call.Direction.Value), + Duration = call.Duration.DurationValue, + IsOnHold = call.PlacedOnHold.BoolValue, }; // Add it to the ActiveCalls List @@ -1348,7 +1363,8 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.Cisco { SendText(string.Format("xCommand Dial Number: \"{0}\" Protocol: {1} CallRate: {2} CallType: {3} BookingId: {4}", number, protocol, callRate, callType, meetingId)); } - + + public override void EndCall(CodecActiveCallItem activeCall) { SendText(string.Format("xCommand Call Disconnect CallId: {0}", activeCall.Id)); @@ -1372,6 +1388,20 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.Cisco SendText("xCommand Call Reject"); } + #region IHasCallHold Members + + public void HoldCall(CodecActiveCallItem activeCall) + { + SendText(string.Format("xCommand Call Hold CallId: {0}", activeCall.Id)); + } + + public void ResumeCall(CodecActiveCallItem activeCall) + { + SendText(string.Format("xCommand Call Resume CallId: {0}", activeCall.Id)); + } + + #endregion + public override void SendDtmf(string s) { SendText(string.Format("xCommand Call DTMFSend CallId: {0} DTMFString: \"{1}\"", GetCallId(), s)); diff --git a/essentials-framework/Essentials Devices Common/Essentials Devices Common/VideoCodec/CiscoCodec/xStatus.cs b/essentials-framework/Essentials Devices Common/Essentials Devices Common/VideoCodec/CiscoCodec/xStatus.cs index 29b9f260..eadc4c32 100644 --- a/essentials-framework/Essentials Devices Common/Essentials Devices Common/VideoCodec/CiscoCodec/xStatus.cs +++ b/essentials-framework/Essentials Devices Common/Essentials Devices Common/VideoCodec/CiscoCodec/xStatus.cs @@ -1949,9 +1949,30 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.Cisco public string Value { get; set; } } - public class Duration + public class Duration : ValueProperty { - public string Value { get; set; } + private string _Value; + + public string Value + { + get + { + return _Value; + } + set + { + _Value = value; + OnValueChanged(); + } + } + + public TimeSpan DurationValue + { + get + { + return new TimeSpan(0, 0, Int32.Parse(_Value)); + } + } } public class FacilityServiceId @@ -1964,9 +1985,19 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.Cisco public string Value { get; set; } } - public class PlacedOnHold + public class PlacedOnHold : ValueProperty { - public string Value { get; set; } + public bool BoolValue { get; private set; } + + public string Value + { + set + { + // If the incoming value is "True" it sets the BoolValue true, otherwise sets it false + BoolValue = value == "True"; + OnValueChanged(); + } + } } public class Protocol @@ -2014,6 +2045,7 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.Cisco { CallType = new CallType(); Status = new Status2(); + Duration = new Duration(); } } From dc53ce42e71cd40f81352573387a0aa61a0e7913 Mon Sep 17 00:00:00 2001 From: Neil Dorin Date: Wed, 10 Nov 2021 14:08:12 -0700 Subject: [PATCH 02/59] feat(essentials): Adds interface and implementation to join calls --- .../Essentials Devices Common.csproj | 1 + .../VideoCodec/CiscoCodec/CiscoSparkCodec.cs | 19 ++++++++++++++++++- .../VideoCodec/Interfaces/IJoinCalls.cs | 16 ++++++++++++++++ 3 files changed, 35 insertions(+), 1 deletion(-) create mode 100644 essentials-framework/Essentials Devices Common/Essentials Devices Common/VideoCodec/Interfaces/IJoinCalls.cs diff --git a/essentials-framework/Essentials Devices Common/Essentials Devices Common/Essentials Devices Common.csproj b/essentials-framework/Essentials Devices Common/Essentials Devices Common/Essentials Devices Common.csproj index b3f78d0e..3689bf61 100644 --- a/essentials-framework/Essentials Devices Common/Essentials Devices Common/Essentials Devices Common.csproj +++ b/essentials-framework/Essentials Devices Common/Essentials Devices Common/Essentials Devices Common.csproj @@ -130,6 +130,7 @@ + diff --git a/essentials-framework/Essentials Devices Common/Essentials Devices Common/VideoCodec/CiscoCodec/CiscoSparkCodec.cs b/essentials-framework/Essentials Devices Common/Essentials Devices Common/VideoCodec/CiscoCodec/CiscoSparkCodec.cs index 99021350..779fd310 100644 --- a/essentials-framework/Essentials Devices Common/Essentials Devices Common/VideoCodec/CiscoCodec/CiscoSparkCodec.cs +++ b/essentials-framework/Essentials Devices Common/Essentials Devices Common/VideoCodec/CiscoCodec/CiscoSparkCodec.cs @@ -30,7 +30,7 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.Cisco IHasScheduleAwareness, IOccupancyStatusProvider, IHasCodecLayouts, IHasCodecSelfView, ICommunicationMonitor, IRouting, IHasCodecCameras, IHasCameraAutoMode, IHasCodecRoomPresets, IHasExternalSourceSwitching, IHasBranding, IHasCameraOff, IHasCameraMute, IHasDoNotDisturbMode, - IHasHalfWakeMode, IHasCallHold + IHasHalfWakeMode, IHasCallHold, IJoinCalls { private bool _externalSourceChangeRequested; @@ -1400,6 +1400,23 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.Cisco SendText(string.Format("xCommand Call Resume CallId: {0}", activeCall.Id)); } + #endregion + #region IJoinCalls + + public void JoinCall(CodecActiveCallItem activeCall) + { + SendText(string.Format("xCommand Call Join CallId: {0}", activeCall.Id)); + } + + public void JoinAllCalls() + { + foreach (var call in ActiveCalls) + { + if(call.IsActiveCall) + JoinCall(call); + } + } + #endregion public override void SendDtmf(string s) diff --git a/essentials-framework/Essentials Devices Common/Essentials Devices Common/VideoCodec/Interfaces/IJoinCalls.cs b/essentials-framework/Essentials Devices Common/Essentials Devices Common/VideoCodec/Interfaces/IJoinCalls.cs new file mode 100644 index 00000000..b84db1e9 --- /dev/null +++ b/essentials-framework/Essentials Devices Common/Essentials Devices Common/VideoCodec/Interfaces/IJoinCalls.cs @@ -0,0 +1,16 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using Crestron.SimplSharp; + +using PepperDash.Essentials.Devices.Common.Codec; + +namespace PepperDash.Essentials.Devices.Common.VideoCodec +{ + public interface IJoinCalls + { + void JoinCall(CodecActiveCallItem activeCall); + void JoinAllCalls(); + } +} \ No newline at end of file From a043309bb1ec07d63c351296fb1fb228c406eaa8 Mon Sep 17 00:00:00 2001 From: Neil Dorin Date: Wed, 10 Nov 2021 18:02:23 -0700 Subject: [PATCH 03/59] feat(essentials): More updates to add ringtone volume and focus near/far to bridge --- .../JoinMaps/VideoCodecControllerJoinMap.cs | 42 +++++++++++++++++ .../VideoCodec/CiscoCodec/CiscoSparkCodec.cs | 35 +++++++++++++++ .../VideoCodec/CiscoCodec/xConfiguration.cs | 45 ++++++++++++++++++- .../VideoCodec/CiscoCodec/xStatus.cs | 34 +++++++------- .../VideoCodec/VideoCodecBase.cs | 33 ++++++++++++++ 5 files changed, 170 insertions(+), 19 deletions(-) diff --git a/essentials-framework/Essentials Core/PepperDashEssentialsBase/Bridges/JoinMaps/VideoCodecControllerJoinMap.cs b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Bridges/JoinMaps/VideoCodecControllerJoinMap.cs index dcb66a2e..c83f6332 100644 --- a/essentials-framework/Essentials Core/PepperDashEssentialsBase/Bridges/JoinMaps/VideoCodecControllerJoinMap.cs +++ b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Bridges/JoinMaps/VideoCodecControllerJoinMap.cs @@ -525,6 +525,48 @@ namespace PepperDash.Essentials.Core.Bridges.JoinMaps JoinType = eJoinType.Digital }); + [JoinName("CameraFocusNear")] + public JoinDataComplete CameraFocusNear = new JoinDataComplete( + new JoinData + { + JoinNumber = 117, + JoinSpan = 1 + }, + new JoinMetadata + { + Description = "Camera Focus Near", + JoinCapabilities = eJoinCapabilities.FromSIMPL, + JoinType = eJoinType.Digital + }); + + [JoinName("CameraFocusFar")] + public JoinDataComplete CameraFocusFar = new JoinDataComplete( + new JoinData + { + JoinNumber = 118, + JoinSpan = 1 + }, + new JoinMetadata + { + Description = "Camera Focus Far", + JoinCapabilities = eJoinCapabilities.FromSIMPL, + JoinType = eJoinType.Digital + }); + + [JoinName("CameraFocusAuto")] + public JoinDataComplete CameraFocusAuto = new JoinDataComplete( + new JoinData + { + JoinNumber = 119, + JoinSpan = 1 + }, + new JoinMetadata + { + Description = "Camera Auto Focus Trigger", + JoinCapabilities = eJoinCapabilities.FromSIMPL, + JoinType = eJoinType.Digital + }); + [JoinName("CameraPresetSave")] public JoinDataComplete CameraPresetSave = new JoinDataComplete( new JoinData diff --git a/essentials-framework/Essentials Devices Common/Essentials Devices Common/VideoCodec/CiscoCodec/CiscoSparkCodec.cs b/essentials-framework/Essentials Devices Common/Essentials Devices Common/VideoCodec/CiscoCodec/CiscoSparkCodec.cs index 779fd310..172c186c 100644 --- a/essentials-framework/Essentials Devices Common/Essentials Devices Common/VideoCodec/CiscoCodec/CiscoSparkCodec.cs +++ b/essentials-framework/Essentials Devices Common/Essentials Devices Common/VideoCodec/CiscoCodec/CiscoSparkCodec.cs @@ -64,6 +64,8 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.Cisco public BoolFeedback FarEndIsSharingContentFeedback { get; private set; } + public IntFeedback RingtoneVolumeFeedback { get; private set; } + private CodecCommandWithLabel CurrentSelfviewPipPosition; private CodecCommandWithLabel CurrentLocalLayout; @@ -324,6 +326,8 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.Cisco PresentationViewMaximizedFeedback = new BoolFeedback(() => CurrentPresentationView == "Maximized"); + RingtoneVolumeFeedback = new IntFeedback(() => CodecConfiguration.Configuration.Audio.SoundsAndAlerts.RingVolume.Volume); + Communication = comm; if (props.CommunicationMonitorProperties != null) @@ -436,6 +440,8 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.Cisco CodecStatus.Status.Conference.Presentation.Mode.ValueChangedAction = 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; @@ -1419,11 +1425,25 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.Cisco #endregion + /// + /// Sends tones to the last connected call + /// + /// public override void SendDtmf(string s) { SendText(string.Format("xCommand Call DTMFSend CallId: {0} DTMFString: \"{1}\"", GetCallId(), s)); } + /// + /// Sends tones to a specific call + /// + /// + /// + public void SendDtmf(string s, CodecActiveCallItem activeCall) + { + SendText(string.Format("xCommand Call DTMFSend CallId: {0} DTMFString: \"{1}\"", activeCall.Id, s)); + } + public void SelectPresentationSource(int source) { PresentationSource = source; @@ -1431,6 +1451,15 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.Cisco StartSharing(); } + /// + /// Sets the ringtone volume level + /// + /// level from 0 - 100 in increments of 5 + public void SetRingtoneVolume(int volume) + { + SendText(string.Format("xConfiguration Audio SoundsAndAlerts RingVolume: [0]", volume)); + } + /// /// Select source 1 as the presetnation source /// @@ -1447,6 +1476,8 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.Cisco SelectPresentationSource(3); } + + /// /// Starts presentation sharing /// @@ -1473,6 +1504,8 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.Cisco SendText("xCommand Presentation Stop"); } + + public override void PrivacyModeOn() { SendText("xCommand Audio Microphones Mute"); @@ -1601,6 +1634,8 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.Cisco trilist.SetSigFalseAction(joinMap.DeactivateStandby.JoinNumber, () => halfwakeCodec.StandbyDeactivate()); trilist.SetSigFalseAction(joinMap.ActivateHalfWakeMode.JoinNumber, () => halfwakeCodec.HalfwakeActivate()); } + + // TODO: Add mechanism to select a call instance to be able to direct DTMF tones to... } /// diff --git a/essentials-framework/Essentials Devices Common/Essentials Devices Common/VideoCodec/CiscoCodec/xConfiguration.cs b/essentials-framework/Essentials Devices Common/Essentials Devices Common/VideoCodec/CiscoCodec/xConfiguration.cs index 8ae9e643..e6ee8e4d 100644 --- a/essentials-framework/Essentials Devices Common/Essentials Devices Common/VideoCodec/CiscoCodec/xConfiguration.cs +++ b/essentials-framework/Essentials Devices Common/Essentials Devices Common/VideoCodec/CiscoCodec/xConfiguration.cs @@ -112,16 +112,46 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.Cisco public string Value { get; set; } } - public class RingVolume + public class RingVolume : ValueProperty { public string valueSpaceRef { get; set; } - public string Value { get; set; } + + string _Value; + + /// + /// Sets Value and triggers the action when set + /// + public string Value + { + get + { + return _Value; + } + set + { + _Value = value; + OnValueChanged(); + } + } + + public int Volume + { + get + { + return Int32.Parse(_Value); + } + } } public class SoundsAndAlerts { public RingTone RingTone { get; set; } public RingVolume RingVolume { get; set; } + + public SoundsAndAlerts() + { + RingVolume = new RingVolume(); + } } public class Audio @@ -131,6 +161,12 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.Cisco public Microphones Microphones { get; set; } public Output Output { get; set; } public SoundsAndAlerts SoundsAndAlerts { get; set; } + + + public Audio() + { + SoundsAndAlerts = new SoundsAndAlerts(); + } } public class DefaultMode @@ -1797,6 +1833,11 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.Cisco public UserInterface UserInterface { get; set; } public UserManagement UserManagement { get; set; } public Video2 Video { get; set; } + + public Configuration() + { + Audio = new Audio(); + } } public class RootObject diff --git a/essentials-framework/Essentials Devices Common/Essentials Devices Common/VideoCodec/CiscoCodec/xStatus.cs b/essentials-framework/Essentials Devices Common/Essentials Devices Common/VideoCodec/CiscoCodec/xStatus.cs index eadc4c32..ca98c1fc 100644 --- a/essentials-framework/Essentials Devices Common/Essentials Devices Common/VideoCodec/CiscoCodec/xStatus.cs +++ b/essentials-framework/Essentials Devices Common/Essentials Devices Common/VideoCodec/CiscoCodec/xStatus.cs @@ -12,28 +12,28 @@ using PepperDash.Essentials.Devices.Common.VideoCodec.CiscoCodec; namespace PepperDash.Essentials.Devices.Common.VideoCodec.Cisco { + // Helper Classes for Proerties + public abstract class ValueProperty + { + /// + /// Triggered when Value is set + /// + public Action ValueChangedAction { get; set; } + + protected void OnValueChanged() + { + var a = ValueChangedAction; + if (a != null) + a(); + } + + } + /// /// This class exists to capture serialized data sent back by a Cisco codec in JSON output mode /// public class CiscoCodecStatus { - // Helper Classes for Proerties - public abstract class ValueProperty - { - /// - /// Triggered when Value is set - /// - public Action ValueChangedAction { get; set; } - - protected void OnValueChanged() - { - var a = ValueChangedAction; - if (a != null) - a(); - } - - } - public class ConnectionStatus { diff --git a/essentials-framework/Essentials Devices Common/Essentials Devices Common/VideoCodec/VideoCodecBase.cs b/essentials-framework/Essentials Devices Common/Essentials Devices Common/VideoCodec/VideoCodecBase.cs index 2549bea0..84900293 100644 --- a/essentials-framework/Essentials Devices Common/Essentials Devices Common/VideoCodec/VideoCodecBase.cs +++ b/essentials-framework/Essentials Devices Common/Essentials Devices Common/VideoCodec/VideoCodecBase.cs @@ -1201,6 +1201,39 @@ ScreenIndexIsPinnedTo: {8} (a{17}) else camera.ZoomStop(); }); + + trilist.SetBoolSigAction(joinMap.CameraFocusNear.JoinNumber, (b) => + { + if (codec.SelectedCamera == null) return; + var camera = codec.SelectedCamera as IHasCameraFocusControl; + + if (camera == null) return; + + if (b) camera.FocusNear(); + else camera.FocusStop(); + }); + + trilist.SetBoolSigAction(joinMap.CameraFocusFar.JoinNumber, (b) => + { + if (codec.SelectedCamera == null) return; + var camera = codec.SelectedCamera as IHasCameraFocusControl; + + if (camera == null) return; + + if (b) camera.FocusFar(); + else camera.FocusStop(); + }); + + trilist.SetSigFalseAction(joinMap.CameraFocusAuto.JoinNumber, () => + { + if (codec.SelectedCamera == null) return; + var camera = codec.SelectedCamera as IHasCameraFocusControl; + + if (camera == null) return; + + camera.TriggerAutoFocus(); + }); + //Camera Select trilist.SetUShortSigAction(joinMap.CameraNumberSelect.JoinNumber, (i) => { From 8aae23db9e2a70d36c16d12b7a3953629fcd64f9 Mon Sep 17 00:00:00 2001 From: Neil Dorin Date: Thu, 11 Nov 2021 16:54:03 -0700 Subject: [PATCH 04/59] feat(essentials): #865 Updates to Bridging Adds ability to end individual calls, report connected call count, report call duration and hold status, send DTMF tones to individual call index and select far end presets --- .../JoinMaps/VideoCodecControllerJoinMap.cs | 80 +++++++++++++- .../VideoCodec/CiscoCodec/CiscoSparkCodec.cs | 14 ++- .../VideoCodec/CiscoCodec/RoomPresets.cs | 2 + .../VideoCodec/MockVC/MockVC.cs | 5 + .../VideoCodec/VideoCodecBase.cs | 102 +++++++++++++++--- 5 files changed, 179 insertions(+), 24 deletions(-) diff --git a/essentials-framework/Essentials Core/PepperDashEssentialsBase/Bridges/JoinMaps/VideoCodecControllerJoinMap.cs b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Bridges/JoinMaps/VideoCodecControllerJoinMap.cs index c83f6332..d8610047 100644 --- a/essentials-framework/Essentials Core/PepperDashEssentialsBase/Bridges/JoinMaps/VideoCodecControllerJoinMap.cs +++ b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Bridges/JoinMaps/VideoCodecControllerJoinMap.cs @@ -20,6 +20,20 @@ namespace PepperDash.Essentials.Core.Bridges.JoinMaps JoinType = eJoinType.Digital }); + [JoinName("SendDtmfToSpecificCallIndex")] + public JoinDataComplete SendDtmfToSpecificCallIndex = new JoinDataComplete( + new JoinData + { + JoinNumber = 10, + JoinSpan = 1 + }, + new JoinMetadata + { + Description = "If High, will send DTMF tones to the call set by SelectCall analog. If low sends DTMF tones to last connected call.", + JoinCapabilities = eJoinCapabilities.FromSIMPL, + JoinType = eJoinType.Digital + }); + [JoinName("1")] public JoinDataComplete Dtmf1 = new JoinDataComplete( new JoinData @@ -188,8 +202,8 @@ namespace PepperDash.Essentials.Core.Bridges.JoinMaps JoinType = eJoinType.Digital }); - [JoinName("EndCall")] - public JoinDataComplete EndCall = new JoinDataComplete( + [JoinName("EndAllCalls")] + public JoinDataComplete EndAllCalls = new JoinDataComplete( new JoinData { JoinNumber = 24, @@ -197,7 +211,7 @@ namespace PepperDash.Essentials.Core.Bridges.JoinMaps }, new JoinMetadata { - Description = "Hang Up", + Description = "End All Calls", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); @@ -576,7 +590,7 @@ namespace PepperDash.Essentials.Core.Bridges.JoinMaps }, new JoinMetadata { - Description = "Save Selected Preset", + Description = "Pulse to save selected preset. FB will pulse for 3s when preset saved.", JoinCapabilities = eJoinCapabilities.ToFromSIMPL, JoinType = eJoinType.Digital }); @@ -966,6 +980,48 @@ namespace PepperDash.Essentials.Core.Bridges.JoinMaps #region Analog + [JoinName("SelectCall")] + public JoinDataComplete SelectCall = new JoinDataComplete( + new JoinData + { + JoinNumber = 24, + JoinSpan = 1 + }, + new JoinMetadata + { + Description = "Sets the selected Call. Valid values 1-8", + JoinCapabilities = eJoinCapabilities.FromSIMPL, + JoinType = eJoinType.Analog + }); + + [JoinName("EndCall")] + public JoinDataComplete EndCall = new JoinDataComplete( + new JoinData + { + JoinNumber = 24, + JoinSpan = 1 + }, + new JoinMetadata + { + Description = "End a specific call by call index. Valid values 1-8", + JoinCapabilities = eJoinCapabilities.FromSIMPL, + JoinType = eJoinType.Analog + }); + + [JoinName("ConnectedCallCount")] + public JoinDataComplete ConnectedCallCount = new JoinDataComplete( + new JoinData + { + JoinNumber = 25, + JoinSpan = 1 + }, + new JoinMetadata + { + Description = "Reports the number of currently connected calls", + JoinCapabilities = eJoinCapabilities.ToSIMPL, + JoinType = eJoinType.Analog + }); + [JoinName("MinutesBeforeMeetingStart")] public JoinDataComplete MinutesBeforeMeetingStart = new JoinDataComplete( new JoinData @@ -1032,10 +1088,24 @@ namespace PepperDash.Essentials.Core.Bridges.JoinMaps new JoinMetadata { Description = "Camera Preset Select", - JoinCapabilities = eJoinCapabilities.ToFromSIMPL, + JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Analog }); + [JoinName("FarEndPresetSelect")] + public JoinDataComplete FarEndPresetSelect = new JoinDataComplete( + new JoinData + { + JoinNumber = 122, + JoinSpan = 1 + }, + new JoinMetadata + { + Description = "Far End Preset Preset Select", + JoinCapabilities = eJoinCapabilities.ToSIMPL, + JoinType = eJoinType.Analog + }); + [JoinName("ParticipantCount")] public JoinDataComplete ParticipantCount = new JoinDataComplete( new JoinData diff --git a/essentials-framework/Essentials Devices Common/Essentials Devices Common/VideoCodec/CiscoCodec/CiscoSparkCodec.cs b/essentials-framework/Essentials Devices Common/Essentials Devices Common/VideoCodec/CiscoCodec/CiscoSparkCodec.cs index 172c186c..7b44b47a 100644 --- a/essentials-framework/Essentials Devices Common/Essentials Devices Common/VideoCodec/CiscoCodec/CiscoSparkCodec.cs +++ b/essentials-framework/Essentials Devices Common/Essentials Devices Common/VideoCodec/CiscoCodec/CiscoSparkCodec.cs @@ -1407,6 +1407,7 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.Cisco } #endregion + #region IJoinCalls public void JoinCall(CodecActiveCallItem activeCall) @@ -1416,10 +1417,19 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.Cisco public void JoinAllCalls() { + StringBuilder ids = new StringBuilder(); + foreach (var call in ActiveCalls) { - if(call.IsActiveCall) - JoinCall(call); + if (call.IsActiveCall) + { + ids.Append(string.Format(" CallId: {0}", call.Id)); + } + } + + if (ids.Length > 0) + { + SendText(string.Format("xCommand Call Join {0}", ids.ToString())); } } diff --git a/essentials-framework/Essentials Devices Common/Essentials Devices Common/VideoCodec/CiscoCodec/RoomPresets.cs b/essentials-framework/Essentials Devices Common/Essentials Devices Common/VideoCodec/CiscoCodec/RoomPresets.cs index 1b456774..b6327d52 100644 --- a/essentials-framework/Essentials Devices Common/Essentials Devices Common/VideoCodec/CiscoCodec/RoomPresets.cs +++ b/essentials-framework/Essentials Devices Common/Essentials Devices Common/VideoCodec/CiscoCodec/RoomPresets.cs @@ -26,6 +26,8 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec void CodecRoomPresetSelect(int preset); void CodecRoomPresetStore(int preset, string description); + + void SelectFarEndPreset(int preset); } public static class RoomPresets diff --git a/essentials-framework/Essentials Devices Common/Essentials Devices Common/VideoCodec/MockVC/MockVC.cs b/essentials-framework/Essentials Devices Common/Essentials Devices Common/VideoCodec/MockVC/MockVC.cs index 78302fcc..c47870ab 100644 --- a/essentials-framework/Essentials Devices Common/Essentials Devices Common/VideoCodec/MockVC/MockVC.cs +++ b/essentials-framework/Essentials Devices Common/Essentials Devices Common/VideoCodec/MockVC/MockVC.cs @@ -751,6 +751,11 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec SetConfig(Config); } + public void SelectFarEndPreset(int i) + { + Debug.Console(1, this, "Selecting Far End Preset: {0}", i); + } + #endregion protected override void CustomSetConfig(DeviceConfig config) diff --git a/essentials-framework/Essentials Devices Common/Essentials Devices Common/VideoCodec/VideoCodecBase.cs b/essentials-framework/Essentials Devices Common/Essentials Devices Common/VideoCodec/VideoCodecBase.cs index 84900293..5771d868 100644 --- a/essentials-framework/Essentials Devices Common/Essentials Devices Common/VideoCodec/VideoCodecBase.cs +++ b/essentials-framework/Essentials Devices Common/Essentials Devices Common/VideoCodec/VideoCodecBase.cs @@ -149,6 +149,7 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec public abstract void AcceptCall(CodecActiveCallItem call); public abstract void RejectCall(CodecActiveCallItem call); public abstract void SendDtmf(string s); + public virtual void SendDtmf(string s, CodecActiveCallItem call) { } #endregion @@ -978,8 +979,21 @@ ScreenIndexIsPinnedTo: {8} (a{17}) trilist.SetSigFalseAction(joinMap.ManualDial.JoinNumber, () => Dial(trilist.StringOutput[joinMap.CurrentDialString.JoinNumber].StringValue)); - //End All calls for now - trilist.SetSigFalseAction(joinMap.EndCall.JoinNumber, EndAllCalls); + //End All calls + trilist.SetSigFalseAction(joinMap.EndAllCalls.JoinNumber, EndAllCalls); + + //End a specific call, specified by index + trilist.SetUShortSigAction(joinMap.EndCall.JoinNumber, (i) => + { + if (i > 0 && i <= 8) + { + var call = ActiveCalls[i - 1]; + if (call != null) + { + EndCall(call); + } + } + }); trilist.SetBool(joinMap.HookState.JoinNumber, IsInCall); @@ -998,6 +1012,8 @@ ScreenIndexIsPinnedTo: {8} (a{17}) } trilist.SetString(joinMap.CurrentCallData.JoinNumber, UpdateCallStatusXSig()); + + trilist.SetUshort(joinMap.ConnectedCallCount.JoinNumber, (ushort)ActiveCalls.Count); }; } @@ -1018,6 +1034,7 @@ ScreenIndexIsPinnedTo: {8} (a{17}) break; //digitals tokenArray[arrayIndex] = new XSigDigitalToken(digitalIndex + 1, call.IsActiveCall); + tokenArray[arrayIndex + 1] = new XSigDigitalToken(digitalIndex + 2, call.IsOnHold); //serials tokenArray[arrayIndex + 1] = new XSigSerialToken(stringIndex + 1, call.Name ?? String.Empty); @@ -1025,6 +1042,12 @@ ScreenIndexIsPinnedTo: {8} (a{17}) tokenArray[arrayIndex + 3] = new XSigSerialToken(stringIndex + 3, call.Direction.ToString()); tokenArray[arrayIndex + 4] = new XSigSerialToken(stringIndex + 4, call.Type.ToString()); tokenArray[arrayIndex + 5] = new XSigSerialToken(stringIndex + 5, call.Status.ToString()); + if(call.Duration != null) + { + // May need to verify correct string format here + var dur = string.Format("{0:c}", call.Duration); + tokenArray[arrayIndex + 6] = new XSigSerialToken(stringIndex + 6, dur); + } arrayIndex += offset; stringIndex += maxStrings; @@ -1034,13 +1057,16 @@ ScreenIndexIsPinnedTo: {8} (a{17}) { //digitals tokenArray[arrayIndex] = new XSigDigitalToken(digitalIndex + 1, false); + tokenArray[arrayIndex + 1] = new XSigDigitalToken(digitalIndex + 2, false); - //serials + + //serials tokenArray[arrayIndex + 1] = new XSigSerialToken(stringIndex + 1, String.Empty); tokenArray[arrayIndex + 2] = new XSigSerialToken(stringIndex + 2, String.Empty); tokenArray[arrayIndex + 3] = new XSigSerialToken(stringIndex + 3, String.Empty); tokenArray[arrayIndex + 4] = new XSigSerialToken(stringIndex + 4, String.Empty); tokenArray[arrayIndex + 5] = new XSigSerialToken(stringIndex + 5, String.Empty); + tokenArray[arrayIndex + 6] = new XSigSerialToken(stringIndex + 6, String.Empty); arrayIndex += offset; stringIndex += maxStrings; @@ -1052,20 +1078,56 @@ ScreenIndexIsPinnedTo: {8} (a{17}) private void LinkVideoCodecDtmfToApi(BasicTriList trilist, VideoCodecControllerJoinMap joinMap) { - trilist.SetSigFalseAction(joinMap.Dtmf0.JoinNumber, () => SendDtmf("0")); - trilist.SetSigFalseAction(joinMap.Dtmf1.JoinNumber, () => SendDtmf("1")); - trilist.SetSigFalseAction(joinMap.Dtmf2.JoinNumber, () => SendDtmf("2")); - trilist.SetSigFalseAction(joinMap.Dtmf3.JoinNumber, () => SendDtmf("3")); - trilist.SetSigFalseAction(joinMap.Dtmf4.JoinNumber, () => SendDtmf("4")); - trilist.SetSigFalseAction(joinMap.Dtmf5.JoinNumber, () => SendDtmf("5")); - trilist.SetSigFalseAction(joinMap.Dtmf6.JoinNumber, () => SendDtmf("6")); - trilist.SetSigFalseAction(joinMap.Dtmf7.JoinNumber, () => SendDtmf("7")); - trilist.SetSigFalseAction(joinMap.Dtmf8.JoinNumber, () => SendDtmf("8")); - trilist.SetSigFalseAction(joinMap.Dtmf9.JoinNumber, () => SendDtmf("9")); - trilist.SetSigFalseAction(joinMap.DtmfStar.JoinNumber, () => SendDtmf("*")); - trilist.SetSigFalseAction(joinMap.DtmfPound.JoinNumber, () => SendDtmf("#")); + trilist.SetSigFalseAction(joinMap.Dtmf0.JoinNumber, () => SendDtmfAction("0", trilist, joinMap)); + trilist.SetSigFalseAction(joinMap.Dtmf1.JoinNumber, () => SendDtmfAction("1", trilist, joinMap)); + trilist.SetSigFalseAction(joinMap.Dtmf2.JoinNumber, () => SendDtmfAction("2", trilist, joinMap)); + trilist.SetSigFalseAction(joinMap.Dtmf3.JoinNumber, () => SendDtmfAction("3", trilist, joinMap)); + trilist.SetSigFalseAction(joinMap.Dtmf4.JoinNumber, () => SendDtmfAction("4", trilist, joinMap)); + trilist.SetSigFalseAction(joinMap.Dtmf5.JoinNumber, () => SendDtmfAction("5", trilist, joinMap)); + trilist.SetSigFalseAction(joinMap.Dtmf6.JoinNumber, () => SendDtmfAction("6", trilist, joinMap)); + trilist.SetSigFalseAction(joinMap.Dtmf7.JoinNumber, () => SendDtmfAction("7", trilist, joinMap)); + trilist.SetSigFalseAction(joinMap.Dtmf8.JoinNumber, () => SendDtmfAction("8", trilist, joinMap)); + trilist.SetSigFalseAction(joinMap.Dtmf9.JoinNumber, () => SendDtmfAction("9", trilist, joinMap)); + trilist.SetSigFalseAction(joinMap.DtmfStar.JoinNumber, () => SendDtmfAction("*", trilist, joinMap)); + trilist.SetSigFalseAction(joinMap.DtmfPound.JoinNumber, () => SendDtmfAction("#", trilist, joinMap)); } + /// + /// Sends the specified string as a DTMF command. + /// Reads the value of the SendDtmfToSpecificCallInstance digital join and SelectCall analog join to determine + /// Whther to send to a specific call index or to the last connected call + /// + /// + /// + /// + private void SendDtmfAction(string s, BasicTriList trilist, VideoCodecControllerJoinMap joinMap) + { + if (!trilist.GetBool(joinMap.SendDtmfToSpecificCallIndex.JoinNumber)) + { + SendDtmf(s); + } + else + { + var callIndex = trilist.GetUshort(joinMap.SelectCall.JoinNumber); + if (callIndex > 0 && callIndex <= 8) + { + var call = ActiveCalls[callIndex - 1]; + if (call != null && call.IsActiveCall) + { + SendDtmf(s, call); + } + else + { + Debug.Console(0, this, "Warning: No call found at index {0} or call is not active.", callIndex); + } + } + else + { + Debug.Console(0, this, "Warning: Invalid call index specified. Please use a value of 1-8."); + } + } + } + private void LinkVideoCodecCameraLayoutsToApi(IHasCodecLayouts codec, BasicTriList trilist, VideoCodecControllerJoinMap joinMap) { trilist.SetSigFalseAction(joinMap.CameraLayout.JoinNumber, codec.LocalLayoutToggle); @@ -1288,10 +1350,16 @@ ScreenIndexIsPinnedTo: {8} (a{17}) trilist.SetUShortSigAction(joinMap.CameraPresetSelect.JoinNumber, (i) => { presetCodec.CodecRoomPresetSelect(i); - - trilist.SetUshort(joinMap.CameraPresetSelect.JoinNumber, i); }); + + // Far End Presets + trilist.SetUShortSigAction(joinMap.FarEndPresetSelect.JoinNumber, (i) => + { + presetCodec.SelectFarEndPreset(i); + }); + + trilist.SetSigFalseAction(joinMap.CameraPresetSave.JoinNumber, () => { From 0ff29695e73f388c685879ffa8b2407eb5dc9b3a Mon Sep 17 00:00:00 2001 From: Neil Dorin Date: Thu, 11 Nov 2021 21:05:57 -0700 Subject: [PATCH 05/59] feat(essentials): #865 Updates join map and bridge for new features Adds control and feedback for presentation source Updates camera setup, selection and feedback Adds ringtone volume control/feedback Adds call hold/resume/join control to bridge Adds new config properties for camera info --- .../JoinMaps/VideoCodecControllerJoinMap.cs | 115 +++++++- .../VideoCodec/CiscoCodec/CiscoCamera.cs | 2 +- .../CiscoCodec/CiscoCodecJoinMap.cs | 56 ++++ .../VideoCodec/CiscoCodec/CiscoSparkCodec.cs | 270 ++++++++++++------ .../CiscoSparkCodecPropertiesConfig.cs | 20 +- .../VideoCodec/CiscoCodec/xStatus.cs | 37 ++- .../VideoCodec/VideoCodecBase.cs | 108 ++++++- 7 files changed, 490 insertions(+), 118 deletions(-) diff --git a/essentials-framework/Essentials Core/PepperDashEssentialsBase/Bridges/JoinMaps/VideoCodecControllerJoinMap.cs b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Bridges/JoinMaps/VideoCodecControllerJoinMap.cs index d8610047..a0729352 100644 --- a/essentials-framework/Essentials Core/PepperDashEssentialsBase/Bridges/JoinMaps/VideoCodecControllerJoinMap.cs +++ b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Bridges/JoinMaps/VideoCodecControllerJoinMap.cs @@ -342,6 +342,48 @@ namespace PepperDash.Essentials.Core.Bridges.JoinMaps JoinType = eJoinType.Digital }); + [JoinName("EndCallStart")] + public JoinDataComplete EndCallStart = new JoinDataComplete( + new JoinData + { + JoinNumber = 81, + JoinSpan = 8 + }, + new JoinMetadata + { + Description = "End a specific call by call index. ", + JoinCapabilities = eJoinCapabilities.FromSIMPL, + JoinType = eJoinType.Digital + }); + + [JoinName("JoinAllCalls")] + public JoinDataComplete JoinAllCalls = new JoinDataComplete( + new JoinData + { + JoinNumber = 90, + JoinSpan = 8 + }, + new JoinMetadata + { + Description = "End a specific call by call index. ", + JoinCapabilities = eJoinCapabilities.FromSIMPL, + JoinType = eJoinType.Digital + }); + + [JoinName("JoinCallStart")] + public JoinDataComplete JoinCallStart = new JoinDataComplete( + new JoinData + { + JoinNumber = 91, + JoinSpan = 8 + }, + new JoinMetadata + { + Description = "End a specific call by call index. ", + JoinCapabilities = eJoinCapabilities.FromSIMPL, + JoinType = eJoinType.Digital + }); + [JoinName("DirectorySearchBusy")] public JoinDataComplete DirectorySearchBusy = new JoinDataComplete( new JoinData @@ -931,6 +973,34 @@ namespace PepperDash.Essentials.Core.Bridges.JoinMaps JoinType = eJoinType.Digital }); + [JoinName("HoldCallsStart")] + public JoinDataComplete HoldCallsStart = new JoinDataComplete( + new JoinData + { + JoinNumber = 221, + JoinSpan = 8 + }, + new JoinMetadata + { + Description = "Holds Call at specified index", + JoinCapabilities = eJoinCapabilities.FromSIMPL, + JoinType = eJoinType.Digital + }); + + [JoinName("ResumeCallsStart")] + public JoinDataComplete ResumeCallsStart = new JoinDataComplete( + new JoinData + { + JoinNumber = 231, + JoinSpan = 8 + }, + new JoinMetadata + { + Description = "Resume Call at specified index", + JoinCapabilities = eJoinCapabilities.FromSIMPL, + JoinType = eJoinType.Digital + }); + [JoinName("ParticipantAudioMuteToggleStart")] public JoinDataComplete ParticipantAudioMuteToggleStart = new JoinDataComplete( new JoinData @@ -989,24 +1059,11 @@ namespace PepperDash.Essentials.Core.Bridges.JoinMaps }, new JoinMetadata { - Description = "Sets the selected Call. Valid values 1-8", + Description = "Sets the selected Call for DTMF commands. Valid values 1-8", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Analog }); - [JoinName("EndCall")] - public JoinDataComplete EndCall = new JoinDataComplete( - new JoinData - { - JoinNumber = 24, - JoinSpan = 1 - }, - new JoinMetadata - { - Description = "End a specific call by call index. Valid values 1-8", - JoinCapabilities = eJoinCapabilities.FromSIMPL, - JoinType = eJoinType.Analog - }); [JoinName("ConnectedCallCount")] public JoinDataComplete ConnectedCallCount = new JoinDataComplete( @@ -1045,11 +1102,25 @@ namespace PepperDash.Essentials.Core.Bridges.JoinMaps }, new JoinMetadata { - Description = "Camera Number Select/FB", + Description = "Camera Number Select/FB. 1 based index. Valid range is 1 to the value reported by CameraCount.", JoinCapabilities = eJoinCapabilities.ToFromSIMPL, JoinType = eJoinType.Analog }); + [JoinName("CameraCount")] + public JoinDataComplete CameraCount = new JoinDataComplete( + new JoinData + { + JoinNumber = 61, + JoinSpan = 1 + }, + new JoinMetadata + { + Description = "Reports the number of cameras", + JoinCapabilities = eJoinCapabilities.ToSIMPL, + JoinType = eJoinType.Analog + }); + [JoinName("DirectoryRowCount")] public JoinDataComplete DirectoryRowCount = new JoinDataComplete( new JoinData @@ -1323,6 +1394,20 @@ namespace PepperDash.Essentials.Core.Bridges.JoinMaps JoinType = eJoinType.Serial }); + [JoinName("CameraNamesFb")] + public JoinDataComplete CameraNamesFb = new JoinDataComplete( + new JoinData + { + JoinNumber = 161, + JoinSpan = 10 + }, + new JoinMetadata + { + Description = "Camera Name Fb", + JoinCapabilities = eJoinCapabilities.ToSIMPL, + JoinType = eJoinType.Serial + }); + [JoinName("CurrentSource")] public JoinDataComplete CurrentSource = new JoinDataComplete( new JoinData diff --git a/essentials-framework/Essentials Devices Common/Essentials Devices Common/VideoCodec/CiscoCodec/CiscoCamera.cs b/essentials-framework/Essentials Devices Common/Essentials Devices Common/VideoCodec/CiscoCodec/CiscoCamera.cs index 6f68b369..67312df8 100644 --- a/essentials-framework/Essentials Devices Common/Essentials Devices Common/VideoCodec/CiscoCodec/CiscoCamera.cs +++ b/essentials-framework/Essentials Devices Common/Essentials Devices Common/VideoCodec/CiscoCodec/CiscoCamera.cs @@ -116,7 +116,7 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.Cisco /// /// The ID of the camera on the codec /// - protected uint CameraId { get; private set; } + public uint CameraId { get; private set; } /// /// Valid range 1-15 diff --git a/essentials-framework/Essentials Devices Common/Essentials Devices Common/VideoCodec/CiscoCodec/CiscoCodecJoinMap.cs b/essentials-framework/Essentials Devices Common/Essentials Devices Common/VideoCodec/CiscoCodec/CiscoCodecJoinMap.cs index e4945ce8..44256ca4 100644 --- a/essentials-framework/Essentials Devices Common/Essentials Devices Common/VideoCodec/CiscoCodec/CiscoCodecJoinMap.cs +++ b/essentials-framework/Essentials Devices Common/Essentials Devices Common/VideoCodec/CiscoCodec/CiscoCodecJoinMap.cs @@ -9,6 +9,34 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.Cisco { #region Digital + [JoinName("PresentationLocalOnly")] + public JoinDataComplete PresentationLocalOnly = new JoinDataComplete( + new JoinData + { + JoinNumber = 205, + JoinSpan = 1 + }, + new JoinMetadata + { + Description = "Presentation Local Only Feedback", + JoinCapabilities = eJoinCapabilities.ToSIMPL, + JoinType = eJoinType.Digital + }); + + [JoinName("PresentationLocalRemote")] + public JoinDataComplete PresentationLocalRemote = new JoinDataComplete( + new JoinData + { + JoinNumber = 206, + JoinSpan = 1 + }, + new JoinMetadata + { + Description = "Presentation Local Only Feedback", + JoinCapabilities = eJoinCapabilities.ToSIMPL, + JoinType = eJoinType.Digital + }); + [JoinName("ActivateDoNotDisturbMode")] public JoinDataComplete ActivateDoNotDisturbMode = new JoinDataComplete( new JoinData @@ -112,6 +140,34 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.Cisco #region Analog + [JoinName("RingtoneVolume")] + public JoinDataComplete RingtoneVolume = new JoinDataComplete( + new JoinData + { + JoinNumber = 21, + JoinSpan = 1 + }, + new JoinMetadata + { + Description = "Ringtone volume set/FB. Valid values are 0 - 100 in increments of 5 (5, 10, 15, 20, etc.)", + JoinCapabilities = eJoinCapabilities.ToFromSIMPL, + JoinType = eJoinType.Analog + }); + + [JoinName("PresentationSource")] + public JoinDataComplete PresentationSource = new JoinDataComplete( + new JoinData + { + JoinNumber = 201, + JoinSpan = 1 + }, + new JoinMetadata + { + Description = "Presentation set/FB. Valid values are 0 - 6 depending on the codec model.", + JoinCapabilities = eJoinCapabilities.ToFromSIMPL, + JoinType = eJoinType.Analog + }); + #endregion diff --git a/essentials-framework/Essentials Devices Common/Essentials Devices Common/VideoCodec/CiscoCodec/CiscoSparkCodec.cs b/essentials-framework/Essentials Devices Common/Essentials Devices Common/VideoCodec/CiscoCodec/CiscoSparkCodec.cs index 7b44b47a..4c842f22 100644 --- a/essentials-framework/Essentials Devices Common/Essentials Devices Common/VideoCodec/CiscoCodec/CiscoSparkCodec.cs +++ b/essentials-framework/Essentials Devices Common/Essentials Devices Common/VideoCodec/CiscoCodec/CiscoSparkCodec.cs @@ -42,11 +42,11 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.Cisco public StatusMonitorBase CommunicationMonitor { get; private set; } - private GenericQueue ReceiveQueue; + private GenericQueue _receiveQueue; public BoolFeedback PresentationViewMaximizedFeedback { get; private set; } - string CurrentPresentationView; + private string _currentPresentationView; public BoolFeedback RoomIsOccupiedFeedback { get; private set; } @@ -66,9 +66,9 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.Cisco public IntFeedback RingtoneVolumeFeedback { get; private set; } - private CodecCommandWithLabel CurrentSelfviewPipPosition; + private CodecCommandWithLabel _currentSelfviewPipPosition; - private CodecCommandWithLabel CurrentLocalLayout; + private CodecCommandWithLabel _currentLocalLayout; /// /// List the available positions for the selfview PIP window @@ -167,7 +167,7 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.Cisco { get { - return () => PresentationSourceKey; + return () => _presentationSourceKey; } } @@ -231,7 +231,7 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.Cisco { get { - return () => CurrentSelfviewPipPosition.Label; + return () => _currentSelfviewPipPosition.Label; } } @@ -239,7 +239,7 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.Cisco { get { - return () => CurrentLocalLayout.Label; + return () => _currentLocalLayout.Label; } } @@ -247,43 +247,58 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.Cisco { get { - return () => CurrentLocalLayout.Label == "Prominent"; + return () => _currentLocalLayout.Label == "Prominent"; } } - private string CliFeedbackRegistrationExpression; + private string _cliFeedbackRegistrationExpression; - private CodecSyncState SyncState; + private CodecSyncState _syncState; public CodecPhonebookSyncState PhonebookSyncState { get; private set; } - private StringBuilder JsonMessage; + private StringBuilder _jsonMessage; - private bool JsonFeedbackMessageIsIncoming; + private bool _jsonFeedbackMessageIsIncoming; public bool CommDebuggingIsOn; string Delimiter = "\r\n"; + public IntFeedback PresentationSourceFeedback { get; private set; } + + public BoolFeedback PresentationSendingLocalOnlyFeedback { get; private set; } + + public BoolFeedback PresentationSendingLocalRemoteFeedback { get; private set; } + /// /// Used to track the current connector used for the presentation source /// - int PresentationSource; + private int _presentationSource; - string PresentationSourceKey; + /// + /// Used to track the connector that is desired to be the current presentation source (until the command is send) + /// + private int _desiredPresentationSource; - string PhonebookMode = "Local"; // Default to Local + private string _presentationSourceKey; - uint PhonebookResultsLimit = 255; // Could be set later by config. + private bool _presentationLocalOnly; - CTimer LoginMessageReceivedTimer; - CTimer RetryConnectionTimer; + private bool _presentationLocalRemote; + + private string _phonebookMode = "Local"; // Default to Local + + private uint _phonebookResultsLimit = 255; // Could be set later by config. + + private CTimer _loginMessageReceivedTimer; + private CTimer _retryConnectionTimer; // **___________________________________________________________________** // Timers to be moved to the global system timer at a later point.... - CTimer BookingsRefreshTimer; - CTimer PhonebookRefreshTimer; + private CTimer BookingsRefreshTimer; + private CTimer PhonebookRefreshTimer; // **___________________________________________________________________** public RoutingInputPort CodecOsdIn { get; private set; } @@ -302,11 +317,11 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.Cisco // Use the configured phonebook results limit if present if (props.PhonebookResultsLimit > 0) { - PhonebookResultsLimit = props.PhonebookResultsLimit; + _phonebookResultsLimit = props.PhonebookResultsLimit; } // The queue that will collect the repsonses in the order they are received - ReceiveQueue = new GenericQueue(this.Key + "-rxQueue", 25); + _receiveQueue = new GenericQueue(this.Key + "-rxQueue", 25); RoomIsOccupiedFeedback = new BoolFeedback(RoomIsOccupiedFeedbackFunc); PeopleCountFeedback = new IntFeedback(PeopleCountFeedbackFunc); @@ -324,10 +339,14 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.Cisco 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"); + PresentationViewMaximizedFeedback = new BoolFeedback(() => _currentPresentationView == "Maximized"); RingtoneVolumeFeedback = new IntFeedback(() => CodecConfiguration.Configuration.Audio.SoundsAndAlerts.RingVolume.Volume); + PresentationSourceFeedback = new IntFeedback(() => _presentationSource); + PresentationSendingLocalOnlyFeedback = new BoolFeedback(() => _presentationLocalOnly); + PresentationSendingLocalRemoteFeedback = new BoolFeedback(() => _presentationLocalRemote); + Communication = comm; if (props.CommunicationMonitorProperties != null) @@ -346,13 +365,13 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.Cisco DeviceManager.AddDevice(CommunicationMonitor); - PhonebookMode = props.PhonebookMode; + _phonebookMode = props.PhonebookMode; - SyncState = new CodecSyncState(Key + "--Sync"); + _syncState = new CodecSyncState(Key + "--Sync"); PhonebookSyncState = new CodecPhonebookSyncState(Key + "--PhonebookSync"); - SyncState.InitialSyncCompleted += new EventHandler(SyncState_InitialSyncCompleted); + _syncState.InitialSyncCompleted += new EventHandler(SyncState_InitialSyncCompleted); PortGather = new CommunicationGather(Communication, Delimiter); PortGather.IncludeDelimiter = true; @@ -399,7 +418,7 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.Cisco InputPorts.Add(HdmiIn3); OutputPorts.Add(HdmiOut1); - SetUpCameras(); + SetUpCameras(props.CameraInfo); CreateOsdSource(); @@ -589,7 +608,7 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.Cisco const string prefix = "xFeedback register "; - CliFeedbackRegistrationExpression = + _cliFeedbackRegistrationExpression = prefix + "/Configuration" + Delimiter + prefix + "/Status/Audio" + Delimiter + prefix + "/Status/Call" + Delimiter + @@ -651,12 +670,12 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.Cisco Debug.Console(1, this, "Socket status change {0}", e.Client.ClientStatus); if (e.Client.IsConnected) { - if(!SyncState.LoginMessageWasReceived) - LoginMessageReceivedTimer = new CTimer(o => DisconnectClientAndReconnect(), 5000); + if(!_syncState.LoginMessageWasReceived) + _loginMessageReceivedTimer = new CTimer(o => DisconnectClientAndReconnect(), 5000); } else { - SyncState.CodecDisconnected(); + _syncState.CodecDisconnected(); PhonebookSyncState.CodecDisconnected(); if (PhonebookRefreshTimer != null) @@ -679,7 +698,7 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.Cisco Communication.Disconnect(); - RetryConnectionTimer = new CTimer(o => Communication.Connect(), 2000); + _retryConnectionTimer = new CTimer(o => Communication.Connect(), 2000); //CrestronEnvironment.Sleep(2000); @@ -696,66 +715,66 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.Cisco { if (CommDebuggingIsOn) { - if (!JsonFeedbackMessageIsIncoming) + if (!_jsonFeedbackMessageIsIncoming) Debug.Console(1, this, "RX: '{0}'", args.Text); } if (args.Text == "{" + Delimiter) // Check for the beginning of a new JSON message { - JsonFeedbackMessageIsIncoming = true; + _jsonFeedbackMessageIsIncoming = true; if (CommDebuggingIsOn) Debug.Console(1, this, "Incoming JSON message..."); - JsonMessage = new StringBuilder(); + _jsonMessage = new StringBuilder(); } else if (args.Text == "}" + Delimiter) // Check for the end of a JSON message { - JsonFeedbackMessageIsIncoming = false; + _jsonFeedbackMessageIsIncoming = false; - JsonMessage.Append(args.Text); + _jsonMessage.Append(args.Text); if (CommDebuggingIsOn) - Debug.Console(1, this, "Complete JSON Received:\n{0}", JsonMessage.ToString()); + Debug.Console(1, this, "Complete JSON Received:\n{0}", _jsonMessage.ToString()); // Enqueue the complete message to be deserialized - ReceiveQueue.Enqueue(new ProcessStringMessage(JsonMessage.ToString(), DeserializeResponse)); + _receiveQueue.Enqueue(new ProcessStringMessage(_jsonMessage.ToString(), DeserializeResponse)); return; } - if(JsonFeedbackMessageIsIncoming) + if(_jsonFeedbackMessageIsIncoming) { - JsonMessage.Append(args.Text); + _jsonMessage.Append(args.Text); //Debug.Console(1, this, "Building JSON:\n{0}", JsonMessage.ToString()); return; } - if (!SyncState.InitialSyncComplete) + if (!_syncState.InitialSyncComplete) { 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("xPreferences outputmode json"); break; } case "xpreferences outputmode json": { - if (!SyncState.InitialStatusMessageWasReceived) + if (!_syncState.InitialStatusMessageWasReceived) SendText("xStatus"); break; } case "xfeedback register /event/calldisconnect": { - SyncState.FeedbackRegistered(); + _syncState.FeedbackRegistered(); break; } } @@ -801,11 +820,18 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.Cisco if (conference.Presentation.LocalInstance.Count > 0) { if (!string.IsNullOrEmpty(conference.Presentation.LocalInstance[0].ghost)) - PresentationSource = 0; + _presentationSource = 0; else if (conference.Presentation.LocalInstance[0].Source != null) { - PresentationSource = conference.Presentation.LocalInstance[0].Source.IntValue; + _presentationSource = conference.Presentation.LocalInstance[0].Source.IntValue; } + + _presentationLocalOnly = conference.Presentation.LocalInstance.Any((i) => i.SendingMode.LocalOnly); + _presentationLocalRemote = conference.Presentation.LocalInstance.Any((i) => i.SendingMode.LocalRemote); + + PresentationSourceFeedback.FireUpdate(); + PresentationSendingLocalOnlyFeedback.FireUpdate(); + PresentationSendingLocalRemoteFeedback.FireUpdate(); } // Check to see if this is a call status message received after the initial status message @@ -966,11 +992,11 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.Cisco JsonConvert.PopulateObject(response, CodecStatus); } - if (!SyncState.InitialStatusMessageWasReceived) + if (!_syncState.InitialStatusMessageWasReceived) { - SyncState.InitialStatusMessageReceived(); + _syncState.InitialStatusMessageReceived(); - if (!SyncState.InitialConfigurationMessageWasReceived) + if (!_syncState.InitialConfigurationMessageWasReceived) SendText("xConfiguration"); } } @@ -980,12 +1006,12 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.Cisco JsonConvert.PopulateObject(response, CodecConfiguration); - if (!SyncState.InitialConfigurationMessageWasReceived) + if (!_syncState.InitialConfigurationMessageWasReceived) { - SyncState.InitialConfigurationMessageReceived(); - if (!SyncState.FeedbackWasRegistered) + _syncState.InitialConfigurationMessageReceived(); + if (!_syncState.FeedbackWasRegistered) { - SendText(CliFeedbackRegistrationExpression); + SendText(_cliFeedbackRegistrationExpression); } } @@ -1158,7 +1184,7 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.Cisco public override void ExecuteSwitch(object selector) { (selector as Action)(); - PresentationSourceKey = selector.ToString(); + _presentationSourceKey = selector.ToString(); } /// @@ -1168,7 +1194,7 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.Cisco public void ExecuteSwitch(object inputSelector, object outputSelector, eRoutingSignalType signalType) { ExecuteSwitch(inputSelector); - PresentationSourceKey = inputSelector.ToString(); + _presentationSourceKey = inputSelector.ToString(); } @@ -1247,13 +1273,13 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.Cisco private void GetPhonebookFolders() { // Get Phonebook Folders (determine local/corporate from config, and set results limit) - SendText(string.Format("xCommand Phonebook Search PhonebookType: {0} ContactType: Folder", PhonebookMode)); + SendText(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) - SendText(string.Format("xCommand Phonebook Search PhonebookType: {0} ContactType: Contact Limit: {1}", PhonebookMode, PhonebookResultsLimit)); + SendText(string.Format("xCommand Phonebook Search PhonebookType: {0} ContactType: Contact Limit: {1}", _phonebookMode, _phonebookResultsLimit)); } /// @@ -1262,7 +1288,7 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.Cisco /// public void SearchDirectory(string searchString) { - SendText(string.Format("xCommand Phonebook Search SearchString: \"{0}\" PhonebookType: {1} ContactType: Contact Limit: {2}", searchString, PhonebookMode, PhonebookResultsLimit)); + SendText(string.Format("xCommand Phonebook Search SearchString: \"{0}\" PhonebookType: {1} ContactType: Contact Limit: {2}", searchString, _phonebookMode, _phonebookResultsLimit)); } /// @@ -1271,7 +1297,7 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.Cisco /// public void GetDirectoryFolderContents(string folderId) { - SendText(string.Format("xCommand Phonebook Search FolderId: {0} PhonebookType: {1} ContactType: Any Limit: {2}", folderId, PhonebookMode, PhonebookResultsLimit)); + SendText(string.Format("xCommand Phonebook Search FolderId: {0} PhonebookType: {1} ContactType: Any Limit: {2}", folderId, _phonebookMode, _phonebookResultsLimit)); } /// @@ -1449,14 +1475,14 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.Cisco /// /// /// - public void SendDtmf(string s, CodecActiveCallItem activeCall) + public override void SendDtmf(string s, CodecActiveCallItem activeCall) { SendText(string.Format("xCommand Call DTMFSend CallId: {0} DTMFString: \"{1}\"", activeCall.Id, s)); } public void SelectPresentationSource(int source) { - PresentationSource = source; + _desiredPresentationSource = source; StartSharing(); } @@ -1467,6 +1493,18 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.Cisco /// level from 0 - 100 in increments of 5 public void SetRingtoneVolume(int volume) { + if (volume < 0 || volume > 100) + { + Debug.Console(0, this, "Cannot set ringtone volume to '{0}'. Value must be between 0 - 100", volume); + return; + } + + 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); + return; + } + SendText(string.Format("xConfiguration Audio SoundsAndAlerts RingVolume: [0]", volume)); } @@ -1500,8 +1538,8 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.Cisco else sendingMode = "LocalOnly"; - if(PresentationSource > 0) - SendText(string.Format("xCommand Presentation Start PresentationSource: {0} SendingMode: {1}", PresentationSource, sendingMode)); + if (_desiredPresentationSource > 0) + SendText(string.Format("xCommand Presentation Start PresentationSource: {0} SendingMode: {1}", _desiredPresentationSource, sendingMode)); } /// @@ -1509,7 +1547,7 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.Cisco /// public override void StopSharing() { - PresentationSource = 0; + _desiredPresentationSource = 0; SendText("xCommand Presentation Stop"); } @@ -1645,7 +1683,16 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.Cisco trilist.SetSigFalseAction(joinMap.ActivateHalfWakeMode.JoinNumber, () => halfwakeCodec.HalfwakeActivate()); } - // TODO: Add mechanism to select a call instance to be able to direct DTMF tones to... + // Ringtone volume + trilist.SetUShortSigAction(joinMap.RingtoneVolume.JoinNumber, (u) => SetRingtoneVolume(u)); + RingtoneVolumeFeedback.LinkInputSig(trilist.UShortInput[joinMap.RingtoneVolume.JoinNumber]); + + // Presentation Source + trilist.SetUShortSigAction(joinMap.PresentationSource.JoinNumber, (u) => SelectPresentationSource(u)); + PresentationSourceFeedback.LinkInputSig(trilist.UShortInput[joinMap.PresentationSource.JoinNumber]); + + PresentationSendingLocalOnlyFeedback.LinkInputSig(trilist.BooleanInput[joinMap.PresentationLocalOnly.JoinNumber]); + PresentationSendingLocalRemoteFeedback.LinkInputSig(trilist.BooleanInput[joinMap.PresentationLocalRemote.JoinNumber]); } /// @@ -1719,9 +1766,9 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.Cisco /// public void SelfviewPipPositionToggle() { - if (CurrentSelfviewPipPosition != null) + if (_currentSelfviewPipPosition != null) { - var nextPipPositionIndex = SelfviewPipPositions.IndexOf(CurrentSelfviewPipPosition) + 1; + var nextPipPositionIndex = SelfviewPipPositions.IndexOf(_currentSelfviewPipPosition) + 1; if (nextPipPositionIndex >= SelfviewPipPositions.Count) // Check if we need to loop back to the first item in the list nextPipPositionIndex = 0; @@ -1744,9 +1791,9 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.Cisco /// public void LocalLayoutToggle() { - if(CurrentLocalLayout != null) + if(_currentLocalLayout != null) { - var nextLocalLayoutIndex = LocalLayouts.IndexOf(CurrentLocalLayout) + 1; + var nextLocalLayoutIndex = LocalLayouts.IndexOf(_currentLocalLayout) + 1; if (nextLocalLayoutIndex >= LocalLayouts.Count) // Check if we need to loop back to the first item in the list nextLocalLayoutIndex = 0; @@ -1760,9 +1807,9 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.Cisco /// public void LocalLayoutToggleSingleProminent() { - if (CurrentLocalLayout != null) + if (_currentLocalLayout != null) { - if (CurrentLocalLayout.Label != "Prominent") + if (_currentLocalLayout.Label != "Prominent") LocalLayoutSet(LocalLayouts.FirstOrDefault(l => l.Label.Equals("Prominent"))); else LocalLayoutSet(LocalLayouts.FirstOrDefault(l => l.Label.Equals("Single"))); @@ -1776,11 +1823,11 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.Cisco public void MinMaxLayoutToggle() { if (PresentationViewMaximizedFeedback.BoolValue) - CurrentPresentationView = "Minimized"; + _currentPresentationView = "Minimized"; else - CurrentPresentationView = "Maximized"; + _currentPresentationView = "Maximized"; - SendText(string.Format("xCommand Video PresentationView Set View: {0}", CurrentPresentationView)); + SendText(string.Format("xCommand Video PresentationView Set View: {0}", _currentPresentationView)); PresentationViewMaximizedFeedback.FireUpdate(); } @@ -1789,9 +1836,9 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.Cisco /// 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) + if(_currentSelfviewPipPosition != null) SelfviewIsOnFeedback.FireUpdate(); } @@ -1800,9 +1847,9 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.Cisco /// void ComputeLocalLayout() { - CurrentLocalLayout = LocalLayouts.FirstOrDefault(l => l.Command.ToLower().Equals(CodecStatus.Status.Video.Layout.LayoutFamily.Local.Value.ToLower())); + _currentLocalLayout = LocalLayouts.FirstOrDefault(l => l.Command.ToLower().Equals(CodecStatus.Status.Video.Layout.LayoutFamily.Local.Value.ToLower())); - if (CurrentLocalLayout != null) + if (_currentLocalLayout != null) LocalLayoutFeedback.FireUpdate(); } @@ -1850,19 +1897,59 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.Cisco /// /// Builds the cameras List. Could later be modified to build from config data /// - void SetUpCameras() + void SetUpCameras(List cameraInfo) { // Add the internal camera Cameras = new List(); - var internalCamera = new CiscoSparkCamera(Key + "-camera1", "Near End", this, 1); + var camCount = CodecStatus.Status.Cameras.Camera.Count; - if(CodecStatus.Status.Cameras.Camera.Count > 0) - internalCamera.SetCapabilites(CodecStatus.Status.Cameras.Camera[0].Capabilities.Options.Value); + Debug.Console(0, this, "Codec reports {0} cameras", camCount); + + + // Deal with the case of 1 or no reported cameras + if (camCount <= 1) + { + var internalCamera = new CiscoSparkCamera(Key + "-camera1", "Near End", this, 1); + + if (CodecStatus.Status.Cameras.Camera[0] != null && CodecStatus.Status.Cameras.Camera[0].Capabilities != null) + { + internalCamera.SetCapabilites(CodecStatus.Status.Cameras.Camera[0].Capabilities.Options.Value); + } + + Cameras.Add(internalCamera); + DeviceManager.AddDevice(internalCamera); + } else - // Somehow subscribe to the event on the Options.Value property and update when it changes. + { + // Setup all the cameras + for (int i = 0; i < camCount; i++) + { + var cam = CodecStatus.Status.Cameras.Camera[i]; - Cameras.Add(internalCamera); + 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; + name = camInfo.Name; + } + + var key = string.Format("{0}-camera{1}", Key, id); + var camera = new CiscoSparkCamera(key, name, this, id); + + if (cam.Capabilities != null) + { + camera.SetCapabilites(cam.Capabilities.Options.Value); + } + + Cameras.Add(camera); + DeviceManager.AddDevice(camera); + } + } // Add the far end camera var farEndCamera = new CiscoFarEndCamera(Key + "-cameraFar", "Far End", this); @@ -1872,7 +1959,6 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.Cisco ControllingFarEndCameraFeedback = new BoolFeedback(() => SelectedCamera is IAmFarEndCamera); - DeviceManager.AddDevice(internalCamera); DeviceManager.AddDevice(farEndCamera); NearEndPresets = new List(15); @@ -1886,7 +1972,7 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.Cisco FarEndRoomPresets.Add(new CodecRoomPreset(i, label, true, false)); } - SelectedCamera = internalCamera; ; // 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. } #region IHasCodecCameras Members @@ -1934,6 +2020,12 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.Cisco } else Debug.Console(2, this, "Unable to select camera with key: '{0}'", key); + + var ciscoCam = camera as CiscoSparkCamera; + if (ciscoCam != null) + { + SendText(string.Format("xCommand Video Input SetMainVideoSource SourceId: {0}", ciscoCam.CameraId)); + } } public CameraBase FarEndCamera { get; private set; } diff --git a/essentials-framework/Essentials Devices Common/Essentials Devices Common/VideoCodec/CiscoCodec/CiscoSparkCodecPropertiesConfig.cs b/essentials-framework/Essentials Devices Common/Essentials Devices Common/VideoCodec/CiscoCodec/CiscoSparkCodecPropertiesConfig.cs index 1836bafb..7f36b0bf 100644 --- a/essentials-framework/Essentials Devices Common/Essentials Devices Common/VideoCodec/CiscoCodec/CiscoSparkCodecPropertiesConfig.cs +++ b/essentials-framework/Essentials Devices Common/Essentials Devices Common/VideoCodec/CiscoCodec/CiscoSparkCodecPropertiesConfig.cs @@ -50,8 +50,16 @@ namespace PepperDash.Essentials.Devices.Common.Codec public uint PhonebookResultsLimit { get; set; } [JsonProperty("UiBranding")] - public BrandingLogoProperties UiBranding { get; set; } + public BrandingLogoProperties UiBranding { get; set; } + [JsonProperty("cameraInfo")] + public List CameraInfo { get; set; } + + + public CiscoSparkCodecPropertiesConfig() + { + CameraInfo = new List(); + } } public class SharingProperties @@ -68,4 +76,14 @@ namespace PepperDash.Essentials.Devices.Common.Codec [JsonProperty("brandingUrl")] public string BrandingUrl { get; set; } } + + /// + /// Describes configuration information for the near end cameras + /// + public class CameraInfo + { + public int CameraNumber { get; set; } + public string Name { get; set; } + public int SourceId { get; set; } + } } \ No newline at end of file diff --git a/essentials-framework/Essentials Devices Common/Essentials Devices Common/VideoCodec/CiscoCodec/xStatus.cs b/essentials-framework/Essentials Devices Common/Essentials Devices Common/VideoCodec/CiscoCodec/xStatus.cs index ca98c1fc..6db3c2e3 100644 --- a/essentials-framework/Essentials Devices Common/Essentials Devices Common/VideoCodec/CiscoCodec/xStatus.cs +++ b/essentials-framework/Essentials Devices Common/Essentials Devices Common/VideoCodec/CiscoCodec/xStatus.cs @@ -558,9 +558,41 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.Cisco } } - public class SendingMode + public class SendingMode : ValueProperty { - public string Value { get; set; } + string _Value; + + /// + /// Sets Value and triggers the action when set + /// + public string Value + { + get + { + return _Value; + } + set + { + _Value = value; + OnValueChanged(); + } + } + + public bool LocalOnly + { + get + { + return _Value.ToLower() == "localonly"; + } + } + + public bool LocalRemote + { + get + { + return _Value.ToLower() == "localremote"; + } + } } public class LocalInstance @@ -573,6 +605,7 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.Cisco public LocalInstance() { Source = new Source2(); + SendingMode = new SendingMode(); } } diff --git a/essentials-framework/Essentials Devices Common/Essentials Devices Common/VideoCodec/VideoCodecBase.cs b/essentials-framework/Essentials Devices Common/Essentials Devices Common/VideoCodec/VideoCodecBase.cs index 5771d868..b87e47f6 100644 --- a/essentials-framework/Essentials Devices Common/Essentials Devices Common/VideoCodec/VideoCodecBase.cs +++ b/essentials-framework/Essentials Devices Common/Essentials Devices Common/VideoCodec/VideoCodecBase.cs @@ -982,18 +982,22 @@ ScreenIndexIsPinnedTo: {8} (a{17}) //End All calls trilist.SetSigFalseAction(joinMap.EndAllCalls.JoinNumber, EndAllCalls); - //End a specific call, specified by index - trilist.SetUShortSigAction(joinMap.EndCall.JoinNumber, (i) => - { - if (i > 0 && i <= 8) + //End a specific call, specified by index. Maximum 8 calls supported + for (int i = 0; i < joinMap.EndCallStart.JoinSpan; i++) + { + trilist.SetSigFalseAction((uint)(joinMap.EndCallStart.JoinNumber + i), () => { - var call = ActiveCalls[i - 1]; + var call = ActiveCalls[i]; if (call != null) { EndCall(call); } - } - }); + else + { + Debug.Console(0, this, "[End Call] Unable to find call at index '{0}'", i); + } + }); + } trilist.SetBool(joinMap.HookState.JoinNumber, IsInCall); @@ -1015,6 +1019,61 @@ ScreenIndexIsPinnedTo: {8} (a{17}) trilist.SetUshort(joinMap.ConnectedCallCount.JoinNumber, (ushort)ActiveCalls.Count); }; + + var joinCodec = this as IJoinCalls; + if (joinCodec != null) + { + trilist.SetSigFalseAction(joinMap.JoinAllCalls.JoinNumber, () => joinCodec.JoinAllCalls()); + + for (int i = 0; i < joinMap.JoinCallStart.JoinSpan; i++) + { + trilist.SetSigFalseAction((uint)(joinMap.JoinCallStart.JoinNumber + i), () => + { + var call = ActiveCalls[i]; + if (call != null) + { + joinCodec.JoinCall(call); + } + else + { + Debug.Console(0, this, "[Join Call] Unable to find call at index '{0}'", i); + } + }); + } + } + + var holdCodec = this as IHasCallHold; + if (holdCodec != null) + { + for (int i = 0; i < joinMap.JoinCallStart.JoinSpan; i++) + { + trilist.SetSigFalseAction((uint)(joinMap.HoldCallsStart.JoinNumber + i), () => + { + var call = ActiveCalls[i]; + if (call != null) + { + holdCodec.HoldCall(call); + } + else + { + Debug.Console(0, this, "[Hold Call] Unable to find call at index '{0}'", i); + } + }); + + trilist.SetSigFalseAction((uint)(joinMap.ResumeCallsStart.JoinNumber + i), () => + { + var call = ActiveCalls[i]; + if (call != null) + { + holdCodec.ResumeCall(call); + } + else + { + Debug.Console(0, this, "[Resume Call] Unable to find call at index '{0}'", i); + } + }); + } + } } private string UpdateCallStatusXSig() @@ -1296,18 +1355,47 @@ ScreenIndexIsPinnedTo: {8} (a{17}) camera.TriggerAutoFocus(); }); + // Camera count + trilist.SetUshort(joinMap.CameraCount.JoinNumber, (ushort)codec.Cameras.Count); + + // Camera names + for (uint i = 0; i < joinMap.CameraNamesFb.JoinSpan; i++) + { + if (codec.Cameras[(int)i] != null) + { + trilist.SetString(joinMap.CameraNamesFb.JoinNumber + i, codec.Cameras[(int)i].Name); + } + else + { + trilist.SetString(joinMap.CameraNamesFb.JoinNumber + i, ""); + } + } + //Camera Select trilist.SetUShortSigAction(joinMap.CameraNumberSelect.JoinNumber, (i) => { - if (codec.SelectedCamera == null) return; - - codec.SelectCamera(codec.Cameras[i].Key); + if (i > 0 && i <= codec.Cameras.Count) + { + codec.SelectCamera(codec.Cameras[i - 1].Key); + } + else + { + Debug.Console(0, this, "Unable to select. No camera found at index {0}", i); + } }); + // Set initial selected camera feedback + if (codec.SelectedCamera != null) + { + trilist.SetUshort(joinMap.CameraNumberSelect.JoinNumber, (ushort)codec.Cameras.FindIndex((c) => c.Key == codec.SelectedCamera.Key)); + } + codec.CameraSelected += (sender, args) => { var i = (ushort)codec.Cameras.FindIndex((c) => c.Key == args.SelectedCamera.Key); + trilist.SetUshort(joinMap.CameraNumberSelect.JoinNumber, (ushort)(i + 1)); + if (codec is IHasCodecRoomPresets) { return; From d8aef1a0dad0211611a4b48630a054b15918d7a9 Mon Sep 17 00:00:00 2001 From: Neil Dorin Date: Fri, 12 Nov 2021 22:07:11 -0700 Subject: [PATCH 06/59] feat(essentials): #865 More updates Adds ability to disable auto dialing behavior of selected directory contact. Adds XSig to send contact method info across bridge Adds XSig to send call history data across bridge and also joins to manipulate --- .../JoinMaps/VideoCodecControllerJoinMap.cs | 125 +++++++++++++ .../Codec/iHasCallHistory.cs | 6 +- .../VideoCodec/VideoCodecBase.cs | 172 ++++++++++++++++-- 3 files changed, 287 insertions(+), 16 deletions(-) diff --git a/essentials-framework/Essentials Core/PepperDashEssentialsBase/Bridges/JoinMaps/VideoCodecControllerJoinMap.cs b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Bridges/JoinMaps/VideoCodecControllerJoinMap.cs index a0729352..a32dcc88 100644 --- a/essentials-framework/Essentials Core/PepperDashEssentialsBase/Bridges/JoinMaps/VideoCodecControllerJoinMap.cs +++ b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Bridges/JoinMaps/VideoCodecControllerJoinMap.cs @@ -496,6 +496,19 @@ namespace PepperDash.Essentials.Core.Bridges.JoinMaps JoinType = eJoinType.Digital }); + [JoinName("DirectoryDisableAutoDialSelectedLine")] + public JoinDataComplete DirectoryDisableAutoDialSelectedLine = new JoinDataComplete( + new JoinData + { + JoinNumber = 107, + JoinSpan = 1 + }, + new JoinMetadata + { + Description = "Set high to disable automatic dialing of a contact when selected", + JoinCapabilities = eJoinCapabilities.FromSIMPL, + JoinType = eJoinType.Digital + }); [JoinName("CameraTiltUp")] public JoinDataComplete CameraTiltUp = new JoinDataComplete( @@ -903,6 +916,20 @@ namespace PepperDash.Essentials.Core.Bridges.JoinMaps JoinType = eJoinType.Digital }); + [JoinName("RemoveSelectedRecentCallItem")] + public JoinDataComplete RemoveSelectedRecentCallItem = new JoinDataComplete( + new JoinData + { + JoinNumber = 181, + JoinSpan = 1 + }, + new JoinMetadata + { + Description = "Removes the selected recent call item", + JoinCapabilities = eJoinCapabilities.ToSIMPL, + JoinType = eJoinType.Digital + }); + [JoinName("SourceShareStart")] public JoinDataComplete SourceShareStart = new JoinDataComplete( new JoinData @@ -1219,6 +1246,34 @@ namespace PepperDash.Essentials.Core.Bridges.JoinMaps JoinType = eJoinType.Analog }); + [JoinName("SelectRecentCallItem")] + public JoinDataComplete SelectRecentCallItem = new JoinDataComplete( + new JoinData + { + JoinNumber = 180, + JoinSpan = 1 + }, + new JoinMetadata + { + Description = "Select/FB for Recent Call Item. Valid values 1 - 10", + JoinCapabilities = eJoinCapabilities.ToFromSIMPL, + JoinType = eJoinType.Analog + }); + + [JoinName("RecentCallOccurrenceType")] + public JoinDataComplete RecentCallOccurrenceType = new JoinDataComplete( + new JoinData + { + JoinNumber = 181, + JoinSpan = 10 + }, + new JoinMetadata + { + Description = "Recent Call Occurrence Type. [0-3] 0 = Unknown, 1 = Placed, 2 = Received, 3 = NoAnswer", + JoinCapabilities = eJoinCapabilities.ToSIMPL, + JoinType = eJoinType.Analog + }); + #endregion @@ -1352,6 +1407,20 @@ namespace PepperDash.Essentials.Core.Bridges.JoinMaps JoinType = eJoinType.Serial }); + [JoinName("ContactMethods")] + public JoinDataComplete ContactMethods = new JoinDataComplete( + new JoinData + { + JoinNumber = 103, + JoinSpan = 1 + }, + new JoinMetadata + { + Description = "Contact Methods - XSig, 10 entries", + JoinCapabilities = eJoinCapabilities.ToSIMPL, + JoinType = eJoinType.Serial + }); + [JoinName("CameraPresetNames")] public JoinDataComplete CameraPresetNames = new JoinDataComplete( new JoinData @@ -1408,6 +1477,62 @@ namespace PepperDash.Essentials.Core.Bridges.JoinMaps JoinType = eJoinType.Serial }); + [JoinName("SelectedRecentCallName")] + public JoinDataComplete SelectedRecentCallName = new JoinDataComplete( + new JoinData + { + JoinNumber = 171, + JoinSpan = 1 + }, + new JoinMetadata + { + Description = "Selected Recent Call Name", + JoinCapabilities = eJoinCapabilities.ToSIMPL, + JoinType = eJoinType.Serial + }); + + [JoinName("SelectedRecentCallNumber")] + public JoinDataComplete SelectedRecentCallNumber = new JoinDataComplete( + new JoinData + { + JoinNumber = 172, + JoinSpan = 1 + }, + new JoinMetadata + { + Description = "Selected Recent Call Number", + JoinCapabilities = eJoinCapabilities.ToSIMPL, + JoinType = eJoinType.Serial + }); + + [JoinName("RecentCallNamesStart")] + public JoinDataComplete RecentCallNamesStart = new JoinDataComplete( + new JoinData + { + JoinNumber = 181, + JoinSpan = 10 + }, + new JoinMetadata + { + Description = "Recent Call Names", + JoinCapabilities = eJoinCapabilities.ToSIMPL, + JoinType = eJoinType.Serial + }); + + [JoinName("RecentCallTimesStart")] + public JoinDataComplete RecentCallTimesStart = new JoinDataComplete( + new JoinData + { + JoinNumber = 191, + JoinSpan = 10 + }, + new JoinMetadata + { + Description = "Recent Calls Times", + JoinCapabilities = eJoinCapabilities.ToSIMPL, + JoinType = eJoinType.Serial + }); + [JoinName("CurrentSource")] public JoinDataComplete CurrentSource = new JoinDataComplete( new JoinData diff --git a/essentials-framework/Essentials Devices Common/Essentials Devices Common/Codec/iHasCallHistory.cs b/essentials-framework/Essentials Devices Common/Essentials Devices Common/Codec/iHasCallHistory.cs index 256938d1..83a74022 100644 --- a/essentials-framework/Essentials Devices Common/Essentials Devices Common/Codec/iHasCallHistory.cs +++ b/essentials-framework/Essentials Devices Common/Essentials Devices Common/Codec/iHasCallHistory.cs @@ -23,9 +23,9 @@ namespace PepperDash.Essentials.Devices.Common.Codec public enum eCodecOccurrenceType { Unknown = 0, - Placed, - Received, - NoAnswer + Placed = 1, + Received = 2, + NoAnswer = 3, } /// diff --git a/essentials-framework/Essentials Devices Common/Essentials Devices Common/VideoCodec/VideoCodecBase.cs b/essentials-framework/Essentials Devices Common/Essentials Devices Common/VideoCodec/VideoCodecBase.cs index b87e47f6..114c1cf7 100644 --- a/essentials-framework/Essentials Devices Common/Essentials Devices Common/VideoCodec/VideoCodecBase.cs +++ b/essentials-framework/Essentials Devices Common/Essentials Devices Common/VideoCodec/VideoCodecBase.cs @@ -390,6 +390,11 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec LinkVideoCodecPhoneToApi(codec as IHasPhoneDialing, trilist, joinMap); } + if (codec is IHasCallHistory) + { + LinkVideoCodecCallHistoryToApi(codec as IHasCallHistory, trilist, joinMap); + } + trilist.OnlineStatusChange += (device, args) => { if (!args.DeviceOnLine) return; @@ -436,6 +441,11 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec (codec as IHasPhoneDialing).PhoneOffHookFeedback.FireUpdate(); } + if (codec is IHasCallHistory) + { + UpdateCallHistory((codec as IHasCallHistory), trilist, joinMap); + } + SharingContentIsOnFeedback.FireUpdate(); trilist.SetBool(joinMap.HookState.JoinNumber, IsInCall); @@ -901,7 +911,9 @@ ScreenIndexIsPinnedTo: {8} (a{17}) trilist.SetStringSigAction(joinMap.DirectorySearchString.JoinNumber, codec.SearchDirectory); - trilist.SetUShortSigAction(joinMap.DirectorySelectRow.JoinNumber, (i) => SelectDirectoryEntry(codec, i)); + trilist.SetUShortSigAction(joinMap.DirectorySelectRow.JoinNumber, (i) => SelectDirectoryEntry(codec, i, trilist, joinMap)); + + // Report feedback for number of contact methods for selected contact trilist.SetSigFalseAction(joinMap.DirectoryRoot.JoinNumber, codec.SetCurrentDirectoryToRoot); @@ -921,7 +933,7 @@ ScreenIndexIsPinnedTo: {8} (a{17}) }; } - private void SelectDirectoryEntry(IHasDirectory codec, ushort i) + private void SelectDirectoryEntry(IHasDirectory codec, ushort i, BasicTriList trilist, VideoCodecControllerJoinMap joinMap) { var entry = codec.CurrentDirectoryResult.CurrentDirectoryResults[i - 1]; @@ -931,21 +943,87 @@ ScreenIndexIsPinnedTo: {8} (a{17}) return; } - var dialableEntry = entry as IInvitableContact; + // Allow auto dial of selected line + if (!trilist.GetBool(joinMap.DirectoryDisableAutoDialSelectedLine.JoinNumber)) + { + var dialableEntry = entry as IInvitableContact; - if (dialableEntry != null) - { - Dial(dialableEntry); - return; - } + if (dialableEntry != null) + { + Dial(dialableEntry); + return; + } - var entryToDial = entry as DirectoryContact; + var entryToDial = entry as DirectoryContact; - if (entryToDial == null) return; + if (entryToDial == null) return; + + Dial(entryToDial.ContactMethods[0].Number); + return; + } + else + { + // If auto dial is disabled... + var entryToDial = entry as DirectoryContact; + + if (entryToDial == null) return; + + trilist.SetSigFalseAction(joinMap.DirectoryDialSelectedLine.JoinNumber, () => Dial(entryToDial.ContactMethods[0].Number)); + + var clearBytes = XSigHelpers.ClearOutputs(); + + trilist.SetString(joinMap.ContactMethods.JoinNumber, + Encoding.GetEncoding(XSigEncoding).GetString(clearBytes, 0, clearBytes.Length)); + var contactMethodsXSig = UpdateContactMethodsXSig(entryToDial); + + trilist.SetString(joinMap.ContactMethods.JoinNumber, contactMethodsXSig); + } - Dial(entryToDial.ContactMethods[0].Number); } + /// + /// Generates the XSig data representing the available contact methods for the selected DirectoryContact + /// + /// + /// + private string UpdateContactMethodsXSig(DirectoryContact contact) + { + const int maxMethods = 10; + const int maxStrings = 3; + const int offset = maxStrings; + var stringIndex = 0; + var arrayIndex = 0; + var tokenArray = new XSigToken[contact.ContactMethods.Count]; + + // TODO: Add code to generate XSig data + + foreach (var method in contact.ContactMethods) + { + if (arrayIndex >= maxMethods * offset) + break; + + //serials + tokenArray[arrayIndex + 1] = new XSigSerialToken(stringIndex + 1, method.Number); + tokenArray[arrayIndex + 2] = new XSigSerialToken(stringIndex + 2, method.ContactMethodId.ToString()); + tokenArray[arrayIndex + 3] = new XSigSerialToken(stringIndex + 3, method.Device.ToString()); + + arrayIndex += offset; + stringIndex += maxStrings; + } + + while (arrayIndex < maxMethods) + { + tokenArray[arrayIndex + 1] = new XSigSerialToken(stringIndex + 1, String.Empty); + tokenArray[arrayIndex + 2] = new XSigSerialToken(stringIndex + 2, String.Empty); + tokenArray[arrayIndex + 3] = new XSigSerialToken(stringIndex + 3, String.Empty); + + arrayIndex += offset; + stringIndex += maxStrings; + } + + return GetXSigString(tokenArray); + } + private string UpdateDirectoryXSig(CodecDirectory directory, bool isRoot) { var contactIndex = 1; @@ -1079,7 +1157,7 @@ ScreenIndexIsPinnedTo: {8} (a{17}) private string UpdateCallStatusXSig() { const int maxCalls = 8; - const int maxStrings = 5; + const int maxStrings = 6; const int offset = 6; var stringIndex = 0; var digitalIndex = maxStrings * maxCalls; @@ -1457,7 +1535,75 @@ ScreenIndexIsPinnedTo: {8} (a{17}) }); } - private string SetCameraPresetNames(IEnumerable presets) + // Following fields only used for Bridging + private int _selectedRecentCallItemIndex; + private CodecCallHistory.CallHistoryEntry _selectedRecentCallItem; + + private void LinkVideoCodecCallHistoryToApi(IHasCallHistory codec, BasicTriList trilist, VideoCodecControllerJoinMap joinMap) + { + codec.CallHistory.RecentCallsListHasChanged += (o, a) => + { + UpdateCallHistory(codec, trilist, joinMap); + }; + + // Selected item action and feedback + trilist.SetUShortSigAction(joinMap.SelectRecentCallItem.JoinNumber, (u) => + { + _selectedRecentCallItemIndex = (int)(u - 1); + trilist.SetUshort(joinMap.SelectRecentCallItem.JoinNumber, u); + + var _selectedRecentCallItem = codec.CallHistory.RecentCalls[_selectedRecentCallItemIndex]; + + if (_selectedRecentCallItem != null) + { + trilist.SetString(joinMap.SelectedRecentCallName.JoinNumber, _selectedRecentCallItem.Name); + trilist.SetString(joinMap.SelectedRecentCallNumber.JoinNumber, _selectedRecentCallItem.Number); + trilist.SetSigFalseAction(joinMap.RemoveSelectedRecentCallItem.JoinNumber, () => codec.RemoveCallHistoryEntry(_selectedRecentCallItem)); + } + else + { + trilist.SetString(joinMap.SelectedRecentCallName.JoinNumber, string.Empty); + trilist.SetString(joinMap.SelectedRecentCallNumber.JoinNumber, string.Empty); + trilist.ClearBoolSigAction(joinMap.RemoveSelectedRecentCallItem.JoinNumber); + } + }); + } + + + + private void UpdateCallHistory(IHasCallHistory codec, BasicTriList trilist, VideoCodecControllerJoinMap joinMap) + { + // Clear out selected item + _selectedRecentCallItemIndex = 0; + _selectedRecentCallItem = null; + trilist.SetUshort(joinMap.SelectRecentCallItem.JoinNumber, 0); + trilist.SetString(joinMap.SelectedRecentCallName.JoinNumber, string.Empty); + trilist.SetString(joinMap.SelectedRecentCallNumber.JoinNumber, string.Empty); + trilist.ClearBoolSigAction(joinMap.RemoveSelectedRecentCallItem.JoinNumber); + // + + + // Update the call history joins + var maxItems = joinMap.RecentCallNamesStart.JoinSpan; + + uint i = 0; + foreach(var item in codec.CallHistory.RecentCalls) + { + trilist.SetString(joinMap.RecentCallNamesStart.JoinNumber + i, item.Name); + trilist.SetString(joinMap.RecentCallTimesStart.JoinNumber + i, item.StartTime.ToShortTimeString()); + trilist.SetUshort(joinMap.RecentCallOccurrenceType.JoinNumber + i, (ushort)item.OccurrenceType); + i++; + } + + for (uint index = i; i < maxItems; index++) + { + trilist.SetString(joinMap.RecentCallNamesStart.JoinNumber + index, string.Empty); + trilist.SetString(joinMap.RecentCallTimesStart.JoinNumber + index, string.Empty); + trilist.SetUshort(joinMap.RecentCallOccurrenceType.JoinNumber + index, 0); + } + } + + private string SetCameraPresetNames(IEnumerable presets) { return SetCameraPresetNames(presets.Select(p => p.Description).ToList()); } From cdafaf1bcbc8b8ce4bf531a6f7f9c2a0abb62831 Mon Sep 17 00:00:00 2001 From: Neil Dorin Date: Wed, 17 Nov 2021 11:37:29 -0700 Subject: [PATCH 07/59] fix(essentials): Adds missing constructor for Configuration RootObject --- .../VideoCodec/CiscoCodec/xConfiguration.cs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/essentials-framework/Essentials Devices Common/Essentials Devices Common/VideoCodec/CiscoCodec/xConfiguration.cs b/essentials-framework/Essentials Devices Common/Essentials Devices Common/VideoCodec/CiscoCodec/xConfiguration.cs index e6ee8e4d..86e700b9 100644 --- a/essentials-framework/Essentials Devices Common/Essentials Devices Common/VideoCodec/CiscoCodec/xConfiguration.cs +++ b/essentials-framework/Essentials Devices Common/Essentials Devices Common/VideoCodec/CiscoCodec/xConfiguration.cs @@ -1843,6 +1843,11 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.Cisco public class RootObject { public Configuration Configuration { get; set; } + + public RootObject() + { + Configuration = new Configuration(); + } } } } \ No newline at end of file From c685608f6747f580aca97f7f422813a9d8069f79 Mon Sep 17 00:00:00 2001 From: Neil Dorin Date: Wed, 17 Nov 2021 12:24:58 -0700 Subject: [PATCH 08/59] fix(essentials): reworks logic for setting up cameras to wait until codec communication sync has finished --- .../VideoCodec/CiscoCodec/CiscoSparkCodec.cs | 17 ++++++++++++----- .../VideoCodec/VideoCodecBase.cs | 13 +++++++++---- 2 files changed, 21 insertions(+), 9 deletions(-) diff --git a/essentials-framework/Essentials Devices Common/Essentials Devices Common/VideoCodec/CiscoCodec/CiscoSparkCodec.cs b/essentials-framework/Essentials Devices Common/Essentials Devices Common/VideoCodec/CiscoCodec/CiscoSparkCodec.cs index 4c842f22..bce9d153 100644 --- a/essentials-framework/Essentials Devices Common/Essentials Devices Common/VideoCodec/CiscoCodec/CiscoSparkCodec.cs +++ b/essentials-framework/Essentials Devices Common/Essentials Devices Common/VideoCodec/CiscoCodec/CiscoSparkCodec.cs @@ -32,6 +32,8 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.Cisco IHasExternalSourceSwitching, IHasBranding, IHasCameraOff, IHasCameraMute, IHasDoNotDisturbMode, IHasHalfWakeMode, IHasCallHold, IJoinCalls { + private CiscoSparkCodecPropertiesConfig _config; + private bool _externalSourceChangeRequested; public event EventHandler DirectoryResultReturned; @@ -314,6 +316,8 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.Cisco { var props = JsonConvert.DeserializeObject(config.Properties.ToString()); + _config = props; + // Use the configured phonebook results limit if present if (props.PhonebookResultsLimit > 0) { @@ -417,9 +421,6 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.Cisco InputPorts.Add(HdmiIn2); InputPorts.Add(HdmiIn3); OutputPorts.Add(HdmiOut1); - - SetUpCameras(props.CameraInfo); - CreateOsdSource(); ExternalSourceListEnabled = props.ExternalSourceListEnabled; @@ -638,6 +639,8 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.Cisco /// void SyncState_InitialSyncCompleted(object sender, EventArgs e) { + SetUpCameras(_config.CameraInfo); + // Fire the ready event SetIsReady(); //CommDebuggingIsOn = false; @@ -1912,9 +1915,13 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.Cisco { var internalCamera = new CiscoSparkCamera(Key + "-camera1", "Near End", this, 1); - if (CodecStatus.Status.Cameras.Camera[0] != null && CodecStatus.Status.Cameras.Camera[0].Capabilities != null) + if (camCount > 0) { - internalCamera.SetCapabilites(CodecStatus.Status.Cameras.Camera[0].Capabilities.Options.Value); + // Try to get the capabilities from the codec + if (CodecStatus.Status.Cameras.Camera[0] != null && CodecStatus.Status.Cameras.Camera[0].Capabilities != null) + { + internalCamera.SetCapabilites(CodecStatus.Status.Cameras.Camera[0].Capabilities.Options.Value); + } } Cameras.Add(internalCamera); diff --git a/essentials-framework/Essentials Devices Common/Essentials Devices Common/VideoCodec/VideoCodecBase.cs b/essentials-framework/Essentials Devices Common/Essentials Devices Common/VideoCodec/VideoCodecBase.cs index 114c1cf7..789723d7 100644 --- a/essentials-framework/Essentials Devices Common/Essentials Devices Common/VideoCodec/VideoCodecBase.cs +++ b/essentials-framework/Essentials Devices Common/Essentials Devices Common/VideoCodec/VideoCodecBase.cs @@ -328,15 +328,20 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec LinkVideoCodecVolumeToApi(trilist, joinMap); + // Register for this event to link any functions that require the codec to be ready first + codec.IsReadyChange += (o, a) => + { + if (codec is IHasCodecCameras) + { + LinkVideoCodecCameraToApi(codec as IHasCodecCameras, trilist, joinMap); + } + }; + if (codec is ICommunicationMonitor) { LinkVideoCodecCommMonitorToApi(codec as ICommunicationMonitor, trilist, joinMap); } - if (codec is IHasCodecCameras) - { - LinkVideoCodecCameraToApi(codec as IHasCodecCameras, trilist, joinMap); - } if (codec is IHasCodecSelfView) { From 4552a15cbb2acf6df52158aaf2eccfe4965b0990 Mon Sep 17 00:00:00 2001 From: Neil Dorin Date: Tue, 7 Dec 2021 16:22:15 -0700 Subject: [PATCH 09/59] fix(essentials): #865 Updates to join map and bridging based on feedback from testing --- .../JoinMaps/VideoCodecControllerJoinMap.cs | 164 ++++++++++++++---- .../CiscoCodec/CiscoCodecJoinMap.cs | 31 +++- .../VideoCodec/CiscoCodec/CiscoSparkCodec.cs | 4 + .../VideoCodec/VideoCodecBase.cs | 29 +++- 4 files changed, 186 insertions(+), 42 deletions(-) diff --git a/essentials-framework/Essentials Core/PepperDashEssentialsBase/Bridges/JoinMaps/VideoCodecControllerJoinMap.cs b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Bridges/JoinMaps/VideoCodecControllerJoinMap.cs index a32dcc88..08281109 100644 --- a/essentials-framework/Essentials Core/PepperDashEssentialsBase/Bridges/JoinMaps/VideoCodecControllerJoinMap.cs +++ b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Bridges/JoinMaps/VideoCodecControllerJoinMap.cs @@ -34,7 +34,7 @@ namespace PepperDash.Essentials.Core.Bridges.JoinMaps JoinType = eJoinType.Digital }); - [JoinName("1")] + [JoinName("Dtmf1")] public JoinDataComplete Dtmf1 = new JoinDataComplete( new JoinData { @@ -48,7 +48,7 @@ namespace PepperDash.Essentials.Core.Bridges.JoinMaps JoinType = eJoinType.Digital }); - [JoinName("2")] + [JoinName("Dtmf2")] public JoinDataComplete Dtmf2 = new JoinDataComplete( new JoinData { @@ -62,7 +62,7 @@ namespace PepperDash.Essentials.Core.Bridges.JoinMaps JoinType = eJoinType.Digital }); - [JoinName("3")] + [JoinName("Dtmf3")] public JoinDataComplete Dtmf3 = new JoinDataComplete( new JoinData { @@ -76,7 +76,7 @@ namespace PepperDash.Essentials.Core.Bridges.JoinMaps JoinType = eJoinType.Digital }); - [JoinName("4")] + [JoinName("Dtmf4")] public JoinDataComplete Dtmf4 = new JoinDataComplete( new JoinData { @@ -90,7 +90,7 @@ namespace PepperDash.Essentials.Core.Bridges.JoinMaps JoinType = eJoinType.Digital }); - [JoinName("5")] + [JoinName("Dtmf5")] public JoinDataComplete Dtmf5 = new JoinDataComplete( new JoinData { @@ -104,7 +104,7 @@ namespace PepperDash.Essentials.Core.Bridges.JoinMaps JoinType = eJoinType.Digital }); - [JoinName("6")] + [JoinName("Dtmf6")] public JoinDataComplete Dtmf6 = new JoinDataComplete( new JoinData { @@ -118,7 +118,7 @@ namespace PepperDash.Essentials.Core.Bridges.JoinMaps JoinType = eJoinType.Digital }); - [JoinName("7")] + [JoinName("Dtmf7")] public JoinDataComplete Dtmf7 = new JoinDataComplete( new JoinData { @@ -132,7 +132,7 @@ namespace PepperDash.Essentials.Core.Bridges.JoinMaps JoinType = eJoinType.Digital }); - [JoinName("8")] + [JoinName("Dtmf8")] public JoinDataComplete Dtmf8 = new JoinDataComplete( new JoinData { @@ -146,7 +146,7 @@ namespace PepperDash.Essentials.Core.Bridges.JoinMaps JoinType = eJoinType.Digital }); - [JoinName("9")] + [JoinName("Dtmf9")] public JoinDataComplete Dtmf9 = new JoinDataComplete( new JoinData { @@ -160,7 +160,7 @@ namespace PepperDash.Essentials.Core.Bridges.JoinMaps JoinType = eJoinType.Digital }); - [JoinName("0")] + [JoinName("Dtmf0")] public JoinDataComplete Dtmf0 = new JoinDataComplete( new JoinData { @@ -174,7 +174,7 @@ namespace PepperDash.Essentials.Core.Bridges.JoinMaps JoinType = eJoinType.Digital }); - [JoinName("*")] + [JoinName("DtmfStar")] public JoinDataComplete DtmfStar = new JoinDataComplete( new JoinData { @@ -188,7 +188,7 @@ namespace PepperDash.Essentials.Core.Bridges.JoinMaps JoinType = eJoinType.Digital }); - [JoinName("#")] + [JoinName("DtmfPound")] public JoinDataComplete DtmfPound = new JoinDataComplete( new JoinData { @@ -295,12 +295,12 @@ namespace PepperDash.Essentials.Core.Bridges.JoinMaps }, new JoinMetadata { - Description = "Dial manual string", + Description = "Dial manual string specified by CurrentDialString serial join", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); - [JoinName("DialPhoneCall")] + [JoinName("DialPhone")] public JoinDataComplete DialPhone = new JoinDataComplete( new JoinData { @@ -328,7 +328,7 @@ namespace PepperDash.Essentials.Core.Bridges.JoinMaps JoinType = eJoinType.Digital }); - [JoinName("EndPhoneCall")] + [JoinName("HangUpPhone")] public JoinDataComplete HangUpPhone = new JoinDataComplete( new JoinData { @@ -337,7 +337,7 @@ namespace PepperDash.Essentials.Core.Bridges.JoinMaps }, new JoinMetadata { - Description = "Hang Up PHone", + Description = "Hang Up Phone", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); @@ -361,11 +361,11 @@ namespace PepperDash.Essentials.Core.Bridges.JoinMaps new JoinData { JoinNumber = 90, - JoinSpan = 8 + JoinSpan = 1 }, new JoinMetadata { - Description = "End a specific call by call index. ", + Description = "Join all calls", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); @@ -379,7 +379,7 @@ namespace PepperDash.Essentials.Core.Bridges.JoinMaps }, new JoinMetadata { - Description = "End a specific call by call index. ", + Description = "Join a specific call by call index. ", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); @@ -645,7 +645,7 @@ namespace PepperDash.Essentials.Core.Bridges.JoinMaps }, new JoinMetadata { - Description = "Pulse to save selected preset. FB will pulse for 3s when preset saved.", + Description = "Pulse to save selected preset spcified by CameraPresetSelect analog join. FB will pulse for 3s when preset saved.", JoinCapabilities = eJoinCapabilities.ToFromSIMPL, JoinType = eJoinType.Digital }); @@ -659,7 +659,7 @@ namespace PepperDash.Essentials.Core.Bridges.JoinMaps }, new JoinMetadata { - Description = "Camera Mode Auto", + Description = "Camera Mode Auto. Enables camera auto tracking mode, with feedback", JoinCapabilities = eJoinCapabilities.ToFromSIMPL, JoinType = eJoinType.Digital }); @@ -673,7 +673,7 @@ namespace PepperDash.Essentials.Core.Bridges.JoinMaps }, new JoinMetadata { - Description = "Camera Mode Manual", + Description = "Camera Mode Manual. Disables camera auto tracking mode, with feedback", JoinCapabilities = eJoinCapabilities.ToFromSIMPL, JoinType = eJoinType.Digital }); @@ -687,7 +687,7 @@ namespace PepperDash.Essentials.Core.Bridges.JoinMaps }, new JoinMetadata { - Description = "Camera Mode Off", + Description = "Camera Mode Off. Disables camera video, with feedback. Works like video mute.", JoinCapabilities = eJoinCapabilities.ToFromSIMPL, JoinType = eJoinType.Digital }); @@ -925,7 +925,7 @@ namespace PepperDash.Essentials.Core.Bridges.JoinMaps }, new JoinMetadata { - Description = "Removes the selected recent call item", + Description = "Removes the selected recent call item specified by the SelectRecentCallItem analog join", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); @@ -995,7 +995,7 @@ namespace PepperDash.Essentials.Core.Bridges.JoinMaps }, new JoinMetadata { - Description = "advance selfview position", + Description = "Toggles selfview position", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); @@ -1010,7 +1010,7 @@ namespace PepperDash.Essentials.Core.Bridges.JoinMaps new JoinMetadata { Description = "Holds Call at specified index", - JoinCapabilities = eJoinCapabilities.FromSIMPL, + JoinCapabilities = eJoinCapabilities.ToFromSIMPL, JoinType = eJoinType.Digital }); @@ -1028,6 +1028,34 @@ namespace PepperDash.Essentials.Core.Bridges.JoinMaps JoinType = eJoinType.Digital }); + [JoinName("MultiSiteOptionIsEnabled")] + public JoinDataComplete MultiSiteOptionIsEnabled = new JoinDataComplete( + new JoinData + { + JoinNumber = 301, + JoinSpan = 1 + }, + new JoinMetadata + { + Description = "Multi site option is enabled FB", + JoinCapabilities = eJoinCapabilities.ToSIMPL, + JoinType = eJoinType.Digital + }); + + [JoinName("AutoAnswerEnabled")] + public JoinDataComplete AutoAnswerEnabled = new JoinDataComplete( + new JoinData + { + JoinNumber = 302, + JoinSpan = 1 + }, + new JoinMetadata + { + Description = "Auto Answer is enabled FB", + JoinCapabilities = eJoinCapabilities.ToSIMPL, + JoinType = eJoinType.Digital + }); + [JoinName("ParticipantAudioMuteToggleStart")] public JoinDataComplete ParticipantAudioMuteToggleStart = new JoinDataComplete( new JoinData @@ -1289,12 +1317,12 @@ namespace PepperDash.Essentials.Core.Bridges.JoinMaps }, new JoinMetadata { - Description = "Current Dial String", - JoinCapabilities = eJoinCapabilities.ToFromSIMPL, + Description = "Value to dial when ManualDial digital join is pulsed", + JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Serial }); - [JoinName("PhoneString")] + [JoinName("PhoneDialString")] public JoinDataComplete PhoneDialString = new JoinDataComplete( new JoinData { @@ -1308,7 +1336,7 @@ namespace PepperDash.Essentials.Core.Bridges.JoinMaps JoinType = eJoinType.Serial }); - [JoinName("CurrentCallName")] + [JoinName("CurrentCallData")] public JoinDataComplete CurrentCallData = new JoinDataComplete( new JoinData { @@ -1435,8 +1463,8 @@ namespace PepperDash.Essentials.Core.Bridges.JoinMaps JoinType = eJoinType.Serial }); - [JoinName("CameraLayoutStringFb")] - public JoinDataComplete CameraLayoutStringFb = new JoinDataComplete( + [JoinName("CurrentLayoutStringFb")] + public JoinDataComplete CurrentLayoutStringFb = new JoinDataComplete( new JoinData { JoinNumber = 141, @@ -1559,7 +1587,77 @@ namespace PepperDash.Essentials.Core.Bridges.JoinMaps Description = "advance selfview position", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Serial - }); + }); + + [JoinName("DeviceIpAddresss")] + public JoinDataComplete DeviceIpAddresss = new JoinDataComplete( + new JoinData + { + JoinNumber = 301, + JoinSpan = 1 + }, + new JoinMetadata + { + Description = "IP Address of device", + JoinCapabilities = eJoinCapabilities.ToSIMPL, + JoinType = eJoinType.Serial + }); + + [JoinName("SipPhoneNumber")] + public JoinDataComplete SipPhoneNumber = new JoinDataComplete( + new JoinData + { + JoinNumber = 302, + JoinSpan = 1 + }, + new JoinMetadata + { + Description = "SIP phone number of device", + JoinCapabilities = eJoinCapabilities.ToSIMPL, + JoinType = eJoinType.Serial + }); + + [JoinName("E164Alias")] + public JoinDataComplete E164Alias = new JoinDataComplete( + new JoinData + { + JoinNumber = 303, + JoinSpan = 1 + }, + new JoinMetadata + { + Description = "E164 alias of device", + JoinCapabilities = eJoinCapabilities.ToSIMPL, + JoinType = eJoinType.Serial + }); + + [JoinName("H323Id")] + public JoinDataComplete H323Id = new JoinDataComplete( + new JoinData + { + JoinNumber = 304, + JoinSpan = 1 + }, + new JoinMetadata + { + Description = "H323 ID of device", + JoinCapabilities = eJoinCapabilities.ToSIMPL, + JoinType = eJoinType.Serial + }); + + [JoinName("SipUri")] + public JoinDataComplete SipUri = new JoinDataComplete( + new JoinData + { + JoinNumber = 305, + JoinSpan = 1 + }, + new JoinMetadata + { + Description = "SIP URI of device", + JoinCapabilities = eJoinCapabilities.ToSIMPL, + JoinType = eJoinType.Serial + }); [JoinName("DirectoryEntrySelectedName")] public JoinDataComplete DirectoryEntrySelectedName = new JoinDataComplete( diff --git a/essentials-framework/Essentials Devices Common/Essentials Devices Common/VideoCodec/CiscoCodec/CiscoCodecJoinMap.cs b/essentials-framework/Essentials Devices Common/Essentials Devices Common/VideoCodec/CiscoCodec/CiscoCodecJoinMap.cs index 44256ca4..2396afdc 100644 --- a/essentials-framework/Essentials Devices Common/Essentials Devices Common/VideoCodec/CiscoCodec/CiscoCodecJoinMap.cs +++ b/essentials-framework/Essentials Devices Common/Essentials Devices Common/VideoCodec/CiscoCodec/CiscoCodecJoinMap.cs @@ -32,7 +32,7 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.Cisco }, new JoinMetadata { - Description = "Presentation Local Only Feedback", + Description = "Presentation Local and Remote Feedback", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); @@ -41,7 +41,7 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.Cisco public JoinDataComplete ActivateDoNotDisturbMode = new JoinDataComplete( new JoinData { - JoinNumber = 221, + JoinNumber = 241, JoinSpan = 1 }, new JoinMetadata @@ -55,7 +55,7 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.Cisco public JoinDataComplete DeactivateDoNotDisturbMode = new JoinDataComplete( new JoinData { - JoinNumber = 222, + JoinNumber = 242, JoinSpan = 1 }, new JoinMetadata @@ -69,7 +69,7 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.Cisco public JoinDataComplete ToggleDoNotDisturbMode = new JoinDataComplete( new JoinData { - JoinNumber = 223, + JoinNumber = 243, JoinSpan = 1 }, new JoinMetadata @@ -83,7 +83,7 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.Cisco public JoinDataComplete ActivateStandby = new JoinDataComplete( new JoinData { - JoinNumber = 226, + JoinNumber = 246, JoinSpan = 1 }, new JoinMetadata @@ -97,7 +97,7 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.Cisco public JoinDataComplete DeactivateStandby = new JoinDataComplete( new JoinData { - JoinNumber = 227, + JoinNumber = 247, JoinSpan = 1 }, new JoinMetadata @@ -111,7 +111,7 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.Cisco public JoinDataComplete ActivateHalfWakeMode = new JoinDataComplete( new JoinData { - JoinNumber = 228, + JoinNumber = 248, JoinSpan = 1 }, new JoinMetadata @@ -125,7 +125,7 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.Cisco public JoinDataComplete EnteringStandbyMode = new JoinDataComplete( new JoinData { - JoinNumber = 229, + JoinNumber = 249, JoinSpan = 1 }, new JoinMetadata @@ -174,6 +174,21 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.Cisco #region Serials + [JoinName("CommandToDevice")] + public JoinDataComplete CommandToDevice = new JoinDataComplete( + new JoinData + { + JoinNumber = 5, + JoinSpan = 1 + }, + new JoinMetadata + { + Description = "Sends a serial command to the device. Do not include the delimiter, it will be added automatically.", + JoinCapabilities = eJoinCapabilities.FromSIMPL, + JoinType = eJoinType.Serial + }); + + #endregion diff --git a/essentials-framework/Essentials Devices Common/Essentials Devices Common/VideoCodec/CiscoCodec/CiscoSparkCodec.cs b/essentials-framework/Essentials Devices Common/Essentials Devices Common/VideoCodec/CiscoCodec/CiscoSparkCodec.cs index bce9d153..3ed2dae1 100644 --- a/essentials-framework/Essentials Devices Common/Essentials Devices Common/VideoCodec/CiscoCodec/CiscoSparkCodec.cs +++ b/essentials-framework/Essentials Devices Common/Essentials Devices Common/VideoCodec/CiscoCodec/CiscoSparkCodec.cs @@ -1662,6 +1662,10 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.Cisco public void LinkCiscoCodecToApi(BasicTriList trilist, CiscoCodecJoinMap joinMap) { + // Custom commands to codec + trilist.SetStringSigAction(joinMap.CommandToDevice.JoinNumber, (s) => this.SendText(s)); + + var dndCodec = this as IHasDoNotDisturbMode; if (dndCodec != null) { diff --git a/essentials-framework/Essentials Devices Common/Essentials Devices Common/VideoCodec/VideoCodecBase.cs b/essentials-framework/Essentials Devices Common/Essentials Devices Common/VideoCodec/VideoCodecBase.cs index 789723d7..45fc67ee 100644 --- a/essentials-framework/Essentials Devices Common/Essentials Devices Common/VideoCodec/VideoCodecBase.cs +++ b/essentials-framework/Essentials Devices Common/Essentials Devices Common/VideoCodec/VideoCodecBase.cs @@ -328,6 +328,8 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec LinkVideoCodecVolumeToApi(trilist, joinMap); + LinkVideoCodecInfoToApi(trilist, joinMap); + // Register for this event to link any functions that require the codec to be ready first codec.IsReadyChange += (o, a) => { @@ -459,6 +461,31 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec }; } + private void LinkVideoCodecInfoToApi(BasicTriList trilist, VideoCodecControllerJoinMap joinMap) + { + trilist.SetBool(joinMap.MultiSiteOptionIsEnabled.JoinNumber, this.CodecInfo.MultiSiteOptionIsEnabled); + trilist.SetBool(joinMap.AutoAnswerEnabled.JoinNumber, this.CodecInfo.AutoAnswerEnabled); + trilist.SetString(joinMap.DeviceIpAddresss.JoinNumber, this.CodecInfo.IpAddress); + trilist.SetString(joinMap.SipPhoneNumber.JoinNumber, this.CodecInfo.SipPhoneNumber); + trilist.SetString(joinMap.E164Alias.JoinNumber, this.CodecInfo.E164Alias); + trilist.SetString(joinMap.H323Id.JoinNumber, this.CodecInfo.H323Id); + trilist.SetString(joinMap.SipUri.JoinNumber, this.CodecInfo.SipUri); + + trilist.OnlineStatusChange += (o, a) => + { + if (a.DeviceOnLine) + { + trilist.SetBool(joinMap.MultiSiteOptionIsEnabled.JoinNumber, this.CodecInfo.MultiSiteOptionIsEnabled); + trilist.SetBool(joinMap.AutoAnswerEnabled.JoinNumber, this.CodecInfo.AutoAnswerEnabled); + trilist.SetString(joinMap.DeviceIpAddresss.JoinNumber, this.CodecInfo.IpAddress); + trilist.SetString(joinMap.SipPhoneNumber.JoinNumber, this.CodecInfo.SipPhoneNumber); + trilist.SetString(joinMap.E164Alias.JoinNumber, this.CodecInfo.E164Alias); + trilist.SetString(joinMap.H323Id.JoinNumber, this.CodecInfo.H323Id); + trilist.SetString(joinMap.SipUri.JoinNumber, this.CodecInfo.SipUri); + } + }; + } + private void LinkVideoCodecPhoneToApi(IHasPhoneDialing codec, BasicTriList trilist, VideoCodecControllerJoinMap joinMap) { codec.PhoneOffHookFeedback.LinkInputSig(trilist.BooleanInput[joinMap.PhoneHookState.JoinNumber]); @@ -1274,7 +1301,7 @@ ScreenIndexIsPinnedTo: {8} (a{17}) { trilist.SetSigFalseAction(joinMap.CameraLayout.JoinNumber, codec.LocalLayoutToggle); - codec.LocalLayoutFeedback.LinkInputSig(trilist.StringInput[joinMap.CameraLayoutStringFb.JoinNumber]); + codec.LocalLayoutFeedback.LinkInputSig(trilist.StringInput[joinMap.CurrentLayoutStringFb.JoinNumber]); } private void LinkVideoCodecCameraModeToApi(IHasCameraAutoMode codec, BasicTriList trilist, VideoCodecControllerJoinMap joinMap) From 90e22e9136f96c4d8eec05ee5ae4292ea83310ab Mon Sep 17 00:00:00 2001 From: Neil Dorin Date: Tue, 7 Dec 2021 16:45:14 -0700 Subject: [PATCH 10/59] fix(essentials): #865 Adds SelectedContactMethodCount join to report the number of methods for the selected contact --- .../JoinMaps/VideoCodecControllerJoinMap.cs | 14 ++++++++++++++ .../VideoCodec/VideoCodecBase.cs | 9 ++++++++- 2 files changed, 22 insertions(+), 1 deletion(-) diff --git a/essentials-framework/Essentials Core/PepperDashEssentialsBase/Bridges/JoinMaps/VideoCodecControllerJoinMap.cs b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Bridges/JoinMaps/VideoCodecControllerJoinMap.cs index 08281109..205c4e09 100644 --- a/essentials-framework/Essentials Core/PepperDashEssentialsBase/Bridges/JoinMaps/VideoCodecControllerJoinMap.cs +++ b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Bridges/JoinMaps/VideoCodecControllerJoinMap.cs @@ -1204,6 +1204,20 @@ namespace PepperDash.Essentials.Core.Bridges.JoinMaps JoinType = eJoinType.Analog }); + [JoinName("SelectedContactMethodCount")] + public JoinDataComplete SelectedContactMethodCount = new JoinDataComplete( + new JoinData + { + JoinNumber = 102, + JoinSpan = 1 + }, + new JoinMetadata + { + Description = "Reports the number of contact methods for the selected contact", + JoinCapabilities = eJoinCapabilities.FromSIMPL, + JoinType = eJoinType.Analog + }); + [JoinName("CameraPresetSelect")] public JoinDataComplete CameraPresetSelect = new JoinDataComplete( new JoinData diff --git a/essentials-framework/Essentials Devices Common/Essentials Devices Common/VideoCodec/VideoCodecBase.cs b/essentials-framework/Essentials Devices Common/Essentials Devices Common/VideoCodec/VideoCodecBase.cs index 45fc67ee..9714d04c 100644 --- a/essentials-framework/Essentials Devices Common/Essentials Devices Common/VideoCodec/VideoCodecBase.cs +++ b/essentials-framework/Essentials Devices Common/Essentials Devices Common/VideoCodec/VideoCodecBase.cs @@ -972,6 +972,7 @@ ScreenIndexIsPinnedTo: {8} (a{17}) if (entry is DirectoryFolder) { codec.GetDirectoryFolderContents(entry.FolderId); + trilist.SetUshort(joinMap.SelectedContactMethodCount.JoinNumber, 0); return; } @@ -998,10 +999,16 @@ ScreenIndexIsPinnedTo: {8} (a{17}) // If auto dial is disabled... var entryToDial = entry as DirectoryContact; - if (entryToDial == null) return; + if (entryToDial == null) + { + trilist.SetUshort(joinMap.SelectedContactMethodCount.JoinNumber, 0); + return; + } trilist.SetSigFalseAction(joinMap.DirectoryDialSelectedLine.JoinNumber, () => Dial(entryToDial.ContactMethods[0].Number)); + trilist.SetUshort(joinMap.SelectedContactMethodCount.JoinNumber, (ushort)entryToDial.ContactMethods.Count); + var clearBytes = XSigHelpers.ClearOutputs(); trilist.SetString(joinMap.ContactMethods.JoinNumber, From 611f0bec2eff7a243dfac02e98b63797944da508 Mon Sep 17 00:00:00 2001 From: Neil Dorin Date: Tue, 7 Dec 2021 19:40:03 -0700 Subject: [PATCH 11/59] fix(essentials): #865 Adds DialselectedRecentCallItem join --- .../JoinMaps/VideoCodecControllerJoinMap.cs | 16 +++++++++++++++- .../VideoCodec/VideoCodecBase.cs | 2 ++ 2 files changed, 17 insertions(+), 1 deletion(-) diff --git a/essentials-framework/Essentials Core/PepperDashEssentialsBase/Bridges/JoinMaps/VideoCodecControllerJoinMap.cs b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Bridges/JoinMaps/VideoCodecControllerJoinMap.cs index 205c4e09..862e1b2a 100644 --- a/essentials-framework/Essentials Core/PepperDashEssentialsBase/Bridges/JoinMaps/VideoCodecControllerJoinMap.cs +++ b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Bridges/JoinMaps/VideoCodecControllerJoinMap.cs @@ -925,7 +925,21 @@ namespace PepperDash.Essentials.Core.Bridges.JoinMaps }, new JoinMetadata { - Description = "Removes the selected recent call item specified by the SelectRecentCallItem analog join", + Description = "Pulse to remove the selected recent call item specified by the SelectRecentCallItem analog join", + JoinCapabilities = eJoinCapabilities.ToSIMPL, + JoinType = eJoinType.Digital + }); + + [JoinName("DialSelectedRecentCallItem")] + public JoinDataComplete DialSelectedRecentCallItem = new JoinDataComplete( + new JoinData + { + JoinNumber = 182, + JoinSpan = 1 + }, + new JoinMetadata + { + Description = "Pulse to dial the selected recent call item specified by the SelectRecentCallItem analog join", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); diff --git a/essentials-framework/Essentials Devices Common/Essentials Devices Common/VideoCodec/VideoCodecBase.cs b/essentials-framework/Essentials Devices Common/Essentials Devices Common/VideoCodec/VideoCodecBase.cs index 9714d04c..51376b51 100644 --- a/essentials-framework/Essentials Devices Common/Essentials Devices Common/VideoCodec/VideoCodecBase.cs +++ b/essentials-framework/Essentials Devices Common/Essentials Devices Common/VideoCodec/VideoCodecBase.cs @@ -1598,12 +1598,14 @@ ScreenIndexIsPinnedTo: {8} (a{17}) trilist.SetString(joinMap.SelectedRecentCallName.JoinNumber, _selectedRecentCallItem.Name); trilist.SetString(joinMap.SelectedRecentCallNumber.JoinNumber, _selectedRecentCallItem.Number); trilist.SetSigFalseAction(joinMap.RemoveSelectedRecentCallItem.JoinNumber, () => codec.RemoveCallHistoryEntry(_selectedRecentCallItem)); + trilist.SetSigFalseAction(joinMap.DialSelectedRecentCallItem.JoinNumber, () => this.Dial(_selectedRecentCallItem.Number)); } else { trilist.SetString(joinMap.SelectedRecentCallName.JoinNumber, string.Empty); trilist.SetString(joinMap.SelectedRecentCallNumber.JoinNumber, string.Empty); trilist.ClearBoolSigAction(joinMap.RemoveSelectedRecentCallItem.JoinNumber); + trilist.ClearBoolSigAction(joinMap.DialSelectedRecentCallItem.JoinNumber); } }); } From abdd1b38f8c6a57773c264e8bc0f36056a525a5d Mon Sep 17 00:00:00 2001 From: Andrew Welker Date: Wed, 2 Feb 2022 09:22:13 -0700 Subject: [PATCH 12/59] feat (Core): #898 Add name to `GenericQueue` Thread This name will show up in console using the `SSPTASKS` command and allow for easier troubleshooting. --- .../PepperDashEssentialsBase/Queues/GenericQueue.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/essentials-framework/Essentials Core/PepperDashEssentialsBase/Queues/GenericQueue.cs b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Queues/GenericQueue.cs index a1cef30d..f6b0794c 100644 --- a/essentials-framework/Essentials Core/PepperDashEssentialsBase/Queues/GenericQueue.cs +++ b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Queues/GenericQueue.cs @@ -139,7 +139,8 @@ namespace PepperDash.Essentials.Core.Queues _queue = new CrestronQueue(cap); _worker = new Thread(ProcessQueue, null, Thread.eThreadStartOptions.Running) { - Priority = priority + Priority = priority, + Name = _key }; SetDelayValues(pacing); From 742ff4bc1b7ff5633f0e0f2ac18f1744ae2f36ed Mon Sep 17 00:00:00 2001 From: Neil Dorin Date: Wed, 2 Feb 2022 10:18:04 -0700 Subject: [PATCH 13/59] fix(essentials): Updates config type for Vtc1 type rooms --- .../Room/Types/EssentialsCombinedHuddleVtc1Room.cs | 6 +++--- PepperDashEssentials/Room/Types/EssentialsHuddleVtc1Room.cs | 2 +- .../Room/Types/Interfaces/IEssentialsHuddleVtc1Room.cs | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/PepperDashEssentials/Room/Types/EssentialsCombinedHuddleVtc1Room.cs b/PepperDashEssentials/Room/Types/EssentialsCombinedHuddleVtc1Room.cs index 9dec21f2..50186d0b 100644 --- a/PepperDashEssentials/Room/Types/EssentialsCombinedHuddleVtc1Room.cs +++ b/PepperDashEssentials/Room/Types/EssentialsCombinedHuddleVtc1Room.cs @@ -89,7 +89,7 @@ namespace PepperDash.Essentials } } - public EssentialsConferenceRoomPropertiesConfig PropertiesConfig { get; private set; } + public EssentialsHuddleVtc1PropertiesConfig PropertiesConfig { get; private set; } private List Displays; @@ -199,7 +199,7 @@ namespace PepperDash.Essentials { try { - PropertiesConfig = JsonConvert.DeserializeObject + PropertiesConfig = JsonConvert.DeserializeObject (config.Properties.ToString()); VideoCodec = DeviceManager.GetDeviceForKey(PropertiesConfig.VideoCodecKey) as @@ -361,7 +361,7 @@ namespace PepperDash.Essentials protected override void CustomSetConfig(DeviceConfig config) { - var newPropertiesConfig = JsonConvert.DeserializeObject(config.Properties.ToString()); + var newPropertiesConfig = JsonConvert.DeserializeObject(config.Properties.ToString()); if (newPropertiesConfig != null) PropertiesConfig = newPropertiesConfig; diff --git a/PepperDashEssentials/Room/Types/EssentialsHuddleVtc1Room.cs b/PepperDashEssentials/Room/Types/EssentialsHuddleVtc1Room.cs index f429b8c8..ba4567dc 100644 --- a/PepperDashEssentials/Room/Types/EssentialsHuddleVtc1Room.cs +++ b/PepperDashEssentials/Room/Types/EssentialsHuddleVtc1Room.cs @@ -101,7 +101,7 @@ namespace PepperDash.Essentials } } - public EssentialsConferenceRoomPropertiesConfig PropertiesConfig { get; private set; } + public EssentialsHuddleVtc1PropertiesConfig PropertiesConfig { get; private set; } public IRoutingSinkWithSwitching DefaultDisplay { get; private set; } public IBasicVolumeControls DefaultAudioDevice { get; private set; } diff --git a/PepperDashEssentials/Room/Types/Interfaces/IEssentialsHuddleVtc1Room.cs b/PepperDashEssentials/Room/Types/Interfaces/IEssentialsHuddleVtc1Room.cs index 4b13145c..03f7340b 100644 --- a/PepperDashEssentials/Room/Types/Interfaces/IEssentialsHuddleVtc1Room.cs +++ b/PepperDashEssentials/Room/Types/Interfaces/IEssentialsHuddleVtc1Room.cs @@ -10,7 +10,7 @@ namespace PepperDash.Essentials public interface IEssentialsHuddleVtc1Room : IEssentialsRoom, IHasCurrentSourceInfoChange, IPrivacy, IHasCurrentVolumeControls, IRunRouteAction, IRunDefaultCallRoute, IHasVideoCodec, IHasAudioCodec, IHasDefaultDisplay, IHasInCallFeedback { - EssentialsConferenceRoomPropertiesConfig PropertiesConfig { get; } + EssentialsHuddleVtc1PropertiesConfig PropertiesConfig { get; } bool ExcludeFromGlobalFunctions { get; } From c6023ad7005071121e1f1f965b28adb0add10aba Mon Sep 17 00:00:00 2001 From: Neil Dorin Date: Fri, 4 Feb 2022 15:51:29 -0700 Subject: [PATCH 14/59] fix(essentials): Adds missing help message property to tech room config and exposes config --- .../Room/Config/EssentialsTechRoomConfig.cs | 3 ++ .../Room/Types/EssentialsTechRoom.cs | 42 +++++++++---------- 2 files changed, 24 insertions(+), 21 deletions(-) diff --git a/PepperDashEssentials/Room/Config/EssentialsTechRoomConfig.cs b/PepperDashEssentials/Room/Config/EssentialsTechRoomConfig.cs index 9ff3a2d2..2944b854 100644 --- a/PepperDashEssentials/Room/Config/EssentialsTechRoomConfig.cs +++ b/PepperDashEssentials/Room/Config/EssentialsTechRoomConfig.cs @@ -56,6 +56,9 @@ namespace PepperDash.Essentials.Room.Config [JsonProperty("mirroredTuners")] public Dictionary MirroredTuners { get; set; } + [JsonProperty("helpMessage")] + public string HelpMessage { get; set; } + /// /// Indicates the room /// diff --git a/PepperDashEssentials/Room/Types/EssentialsTechRoom.cs b/PepperDashEssentials/Room/Types/EssentialsTechRoom.cs index c2b08f89..b97ef9c4 100644 --- a/PepperDashEssentials/Room/Types/EssentialsTechRoom.cs +++ b/PepperDashEssentials/Room/Types/EssentialsTechRoom.cs @@ -19,7 +19,7 @@ namespace PepperDash.Essentials { public class EssentialsTechRoom : EssentialsRoomBase, ITvPresetsProvider, IBridgeAdvanced, IRunDirectRouteAction { - private readonly EssentialsTechRoomConfig _config; + public EssentialsTechRoomConfig PropertiesConfig { get; private set; } private readonly Dictionary _displays; private readonly DevicePresetsModel _tunerPresets; @@ -57,16 +57,16 @@ namespace PepperDash.Essentials public EssentialsTechRoom(DeviceConfig config) : base(config) { - _config = config.Properties.ToObject(); + PropertiesConfig = config.Properties.ToObject(); - _tunerPresets = new DevicePresetsModel(String.Format("{0}-presets", config.Key), _config.PresetsFileName); + _tunerPresets = new DevicePresetsModel(String.Format("{0}-presets", config.Key), PropertiesConfig.PresetsFileName); - _tunerPresets.SetFileName(_config.PresetsFileName); + _tunerPresets.SetFileName(PropertiesConfig.PresetsFileName); _tunerPresets.PresetRecalled += TunerPresetsOnPresetRecalled; - _tuners = GetDevices(_config.Tuners); - _displays = GetDevices(_config.Displays); + _tuners = GetDevices(PropertiesConfig.Tuners); + _displays = GetDevices(PropertiesConfig.Displays); RoomPowerIsOnFeedback = new BoolFeedback(() => RoomPowerIsOn); @@ -153,7 +153,7 @@ namespace PepperDash.Essentials private void CreateOrUpdateScheduledEvents() { - var eventsConfig = _config.ScheduledEvents; + var eventsConfig = PropertiesConfig.ScheduledEvents; GetOrCreateScheduleGroup(); @@ -207,21 +207,21 @@ namespace PepperDash.Essentials { //update config based on key of scheduleEvent GetOrCreateScheduleGroup(); - var existingEventIndex = _config.ScheduledEvents.FindIndex((e) => e.Key == scheduledEvent.Key); + var existingEventIndex = PropertiesConfig.ScheduledEvents.FindIndex((e) => e.Key == scheduledEvent.Key); if (existingEventIndex < 0) { - _config.ScheduledEvents.Add(scheduledEvent); + PropertiesConfig.ScheduledEvents.Add(scheduledEvent); } else { - _config.ScheduledEvents[existingEventIndex] = scheduledEvent; + PropertiesConfig.ScheduledEvents[existingEventIndex] = scheduledEvent; } //create or update event based on config CreateOrUpdateSingleEvent(scheduledEvent); //save config - Config.Properties = JToken.FromObject(_config); + Config.Properties = JToken.FromObject(PropertiesConfig); CustomSetConfig(Config); //Fire Event @@ -230,7 +230,7 @@ namespace PepperDash.Essentials public List GetScheduledEvents() { - return _config.ScheduledEvents ?? new List(); + return PropertiesConfig.ScheduledEvents ?? new List(); } private void OnScheduledEventUpdate() @@ -242,14 +242,14 @@ namespace PepperDash.Essentials return; } - handler(this, new ScheduledEventEventArgs {ScheduledEvents = _config.ScheduledEvents}); + handler(this, new ScheduledEventEventArgs {ScheduledEvents = PropertiesConfig.ScheduledEvents}); } public event EventHandler ScheduledEventsChanged; private void HandleScheduledEvent(ScheduledEvent schevent, ScheduledEventCommon.eCallbackReason type) { - var eventConfig = _config.ScheduledEvents.FirstOrDefault(e => e.Key == schevent.Name); + var eventConfig = PropertiesConfig.ScheduledEvents.FirstOrDefault(e => e.Key == schevent.Name); if (eventConfig == null) { @@ -286,11 +286,11 @@ Params: {2}" { Debug.Console(2, this, "Room Powering On"); - var dummySource = DeviceManager.GetDeviceForKey(_config.DummySourceKey) as IRoutingOutputs; + var dummySource = DeviceManager.GetDeviceForKey(PropertiesConfig.DummySourceKey) as IRoutingOutputs; if (dummySource == null) { - Debug.Console(1, this, "Unable to get source with key: {0}", _config.DummySourceKey); + Debug.Console(1, this, "Unable to get source with key: {0}", PropertiesConfig.DummySourceKey); return; } @@ -376,12 +376,12 @@ Params: {2}" bridge.AddJoinMap(Key, joinMap); } - if (_config.IsPrimary) + if (PropertiesConfig.IsPrimary) { Debug.Console(1, this, "Linking Primary system Tuner Preset Mirroring"); - if (_config.MirroredTuners != null && _config.MirroredTuners.Count > 0) + if (PropertiesConfig.MirroredTuners != null && PropertiesConfig.MirroredTuners.Count > 0) { - foreach (var tuner in _config.MirroredTuners) + foreach (var tuner in PropertiesConfig.MirroredTuners) { var f = CurrentPresetsFeedbacks[tuner.Value]; @@ -423,9 +423,9 @@ Params: {2}" { Debug.Console(1, this, "Linking Secondary system Tuner Preset Mirroring"); - if (_config.MirroredTuners != null && _config.MirroredTuners.Count > 0) + if (PropertiesConfig.MirroredTuners != null && PropertiesConfig.MirroredTuners.Count > 0) { - foreach (var tuner in _config.MirroredTuners) + foreach (var tuner in PropertiesConfig.MirroredTuners) { var t = _tuners[tuner.Value]; From bc826c9e1712655cc8ef79e7c35243c234de1d42 Mon Sep 17 00:00:00 2001 From: Neil Dorin Date: Fri, 4 Feb 2022 16:41:57 -0700 Subject: [PATCH 15/59] fix(essentials): updates action workflows to specify windows-2019 instead of latest --- .github/workflows/docker.yml | 2 +- .github/workflows/main.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/docker.yml b/.github/workflows/docker.yml index 94c45937..cdcc925b 100644 --- a/.github/workflows/docker.yml +++ b/.github/workflows/docker.yml @@ -22,7 +22,7 @@ env: RELEASE_BRANCH: main jobs: Build_Project: - runs-on: windows-latest + runs-on: windows-2019 steps: # First we checkout the source repo - name: Checkout repo diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index dc219ce3..ef43152b 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -19,7 +19,7 @@ env: RELEASE_BRANCH: main jobs: Build_Project: - runs-on: windows-latest + runs-on: windows-2019 steps: # First we checkout the source repo - name: Checkout repo From d9181c780fcfc77a8a9f99505454d1270a139a6e Mon Sep 17 00:00:00 2001 From: Jason DeVito Date: Mon, 7 Feb 2022 16:45:08 -0600 Subject: [PATCH 16/59] fix: Updated _receiveQueue capacity from 512 to 2048 to help with processing large amounts of push data received from zoom. --- .../Essentials Devices Common/VideoCodec/ZoomRoom/ZoomRoom.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/essentials-framework/Essentials Devices Common/Essentials Devices Common/VideoCodec/ZoomRoom/ZoomRoom.cs b/essentials-framework/Essentials Devices Common/Essentials Devices Common/VideoCodec/ZoomRoom/ZoomRoom.cs index 8fc40f29..5eba02ed 100644 --- a/essentials-framework/Essentials Devices Common/Essentials Devices Common/VideoCodec/ZoomRoom/ZoomRoom.cs +++ b/essentials-framework/Essentials Devices Common/Essentials Devices Common/VideoCodec/ZoomRoom/ZoomRoom.cs @@ -59,7 +59,7 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.ZoomRoom _props = JsonConvert.DeserializeObject(config.Properties.ToString()); - _receiveQueue = new GenericQueue(Key + "-rxQueue", Thread.eThreadPriority.MediumPriority, 512); + _receiveQueue = new GenericQueue(Key + "-rxQueue", Thread.eThreadPriority.MediumPriority, 2048); Communication = comm; From 7b2498ac6b9f031e716592090e19f62960ab0298 Mon Sep 17 00:00:00 2001 From: Jason DeVito Date: Mon, 7 Feb 2022 16:50:35 -0600 Subject: [PATCH 17/59] fix: added JSON property decorator to configuration properties. --- .../ZoomRoom/ZoomRoomPropertiesConfig.cs | 34 ++++++++++++------- 1 file changed, 22 insertions(+), 12 deletions(-) diff --git a/essentials-framework/Essentials Devices Common/Essentials Devices Common/VideoCodec/ZoomRoom/ZoomRoomPropertiesConfig.cs b/essentials-framework/Essentials Devices Common/Essentials Devices Common/VideoCodec/ZoomRoom/ZoomRoomPropertiesConfig.cs index 4c9b08c2..3f752f43 100644 --- a/essentials-framework/Essentials Devices Common/Essentials Devices Common/VideoCodec/ZoomRoom/ZoomRoomPropertiesConfig.cs +++ b/essentials-framework/Essentials Devices Common/Essentials Devices Common/VideoCodec/ZoomRoom/ZoomRoomPropertiesConfig.cs @@ -2,30 +2,40 @@ using System.Collections.Generic; using System.Linq; using System.Text; -using Crestron.SimplSharp; - +using Crestron.SimplSharp; +using Newtonsoft.Json; using PepperDash.Core; using PepperDash.Essentials.Core; namespace PepperDash.Essentials.Devices.Common.VideoCodec.ZoomRoom { public class ZoomRoomPropertiesConfig - { - public CommunicationMonitorConfig CommunicationMonitorProperties { get; set; } - - public bool DisablePhonebookAutoDownload { get; set; } - public bool SupportsCameraAutoMode { get; set; } + { + [JsonProperty("communicationMonitorProperties")] + public CommunicationMonitorConfig CommunicationMonitorProperties { get; set; } + + [JsonProperty("disablePhonebookAutoDownload")] + public bool DisablePhonebookAutoDownload { get; set; } + + [JsonProperty("supportsCameraAutoMode")] + public bool SupportsCameraAutoMode { get; set; } + + [JsonProperty("supportsCameraOff")] public bool SupportsCameraOff { get; set; } - //if true, the layouts will be set automatically when sharing starts/ends or a call is joined + //if true, the layouts will be set automatically when sharing starts/ends or a call is joined + [JsonProperty("autoDefaultLayouts")] public bool AutoDefaultLayouts { get; set; } - /* This layout will be selected when Sharing starts (either from Far end or locally)*/ + /* This layout will be selected when Sharing starts (either from Far end or locally)*/ + [JsonProperty("defaultSharingLayout")] public string DefaultSharingLayout { get; set; } - //This layout will be selected when a call is connected and no content is being shared - public string DefaultCallLayout { get; set; } - + //This layout will be selected when a call is connected and no content is being shared + [JsonProperty("defaultCallLayout")] + public string DefaultCallLayout { get; set; } + + [JsonProperty("minutesBeforeMeetingStart")] public int MinutesBeforeMeetingStart { get; set; } } } \ No newline at end of file From e19b0ba530b859fd16b1357ff800a3fb1b462ea6 Mon Sep 17 00:00:00 2001 From: Jason DeVito Date: Mon, 7 Feb 2022 16:58:24 -0600 Subject: [PATCH 18/59] fix: updated yaml files to point to windows-2019 to resolve action failures. --- .github/workflows/docker.yml | 4 ++-- .github/workflows/main.yml | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/docker.yml b/.github/workflows/docker.yml index 94c45937..e654fa68 100644 --- a/.github/workflows/docker.yml +++ b/.github/workflows/docker.yml @@ -22,7 +22,7 @@ env: RELEASE_BRANCH: main jobs: Build_Project: - runs-on: windows-latest + runs-on: windows-2019 steps: # First we checkout the source repo - name: Checkout repo @@ -98,7 +98,7 @@ jobs: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} Push_Nuget_Package: needs: Build_Project - runs-on: windows-latest + runs-on: windows-2019 steps: - name: Download Build Version Info uses: actions/download-artifact@v1 diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index dc219ce3..abcc8419 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -19,7 +19,7 @@ env: RELEASE_BRANCH: main jobs: Build_Project: - runs-on: windows-latest + runs-on: windows-2019 steps: # First we checkout the source repo - name: Checkout repo @@ -82,7 +82,7 @@ jobs: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} Push_Nuget_Package: needs: Build_Project - runs-on: windows-latest + runs-on: windows-2019 steps: - name: Download Build Version Info uses: actions/download-artifact@v1 From 6cd1a03ee0a8ff925732210a00baed2662adfcb8 Mon Sep 17 00:00:00 2001 From: Jason DeVito Date: Tue, 8 Feb 2022 09:38:40 -0600 Subject: [PATCH 19/59] fix: Updated LinkVideoCodecToApi trilist.onlinestatus change to fix CameraSupportsAudioMode passing true rather than property. --- .../Essentials Devices Common/VideoCodec/VideoCodecBase.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/essentials-framework/Essentials Devices Common/Essentials Devices Common/VideoCodec/VideoCodecBase.cs b/essentials-framework/Essentials Devices Common/Essentials Devices Common/VideoCodec/VideoCodecBase.cs index cd70119f..438d6c56 100644 --- a/essentials-framework/Essentials Devices Common/Essentials Devices Common/VideoCodec/VideoCodecBase.cs +++ b/essentials-framework/Essentials Devices Common/Essentials Devices Common/VideoCodec/VideoCodecBase.cs @@ -411,7 +411,7 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec if (codec is IHasCameraAutoMode) { - trilist.SetBool(joinMap.CameraSupportsAutoMode.JoinNumber, true); + trilist.SetBool(joinMap.CameraSupportsAutoMode.JoinNumber, SupportsCameraAutoMode); (codec as IHasCameraAutoMode).CameraAutoModeIsOnFeedback.FireUpdate(); } From b5589364ff90afb4c26234a4015043c068c93545 Mon Sep 17 00:00:00 2001 From: Jonathan Arndt Date: Tue, 8 Feb 2022 12:15:29 -0800 Subject: [PATCH 20/59] Instantiate xConfiguration members of Configuration, AutoAnswer, and Conference classes --- .github/workflows/docker.yml | 4 ++-- .github/workflows/main.yml | 4 ++-- .../VideoCodec/CiscoCodec/CiscoSparkCodec.cs | 8 ++++++++ .../VideoCodec/CiscoCodec/xConfiguration.cs | 13 +++++++++++++ 4 files changed, 25 insertions(+), 4 deletions(-) diff --git a/.github/workflows/docker.yml b/.github/workflows/docker.yml index 94c45937..e654fa68 100644 --- a/.github/workflows/docker.yml +++ b/.github/workflows/docker.yml @@ -22,7 +22,7 @@ env: RELEASE_BRANCH: main jobs: Build_Project: - runs-on: windows-latest + runs-on: windows-2019 steps: # First we checkout the source repo - name: Checkout repo @@ -98,7 +98,7 @@ jobs: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} Push_Nuget_Package: needs: Build_Project - runs-on: windows-latest + runs-on: windows-2019 steps: - name: Download Build Version Info uses: actions/download-artifact@v1 diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index dc219ce3..abcc8419 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -19,7 +19,7 @@ env: RELEASE_BRANCH: main jobs: Build_Project: - runs-on: windows-latest + runs-on: windows-2019 steps: # First we checkout the source repo - name: Checkout repo @@ -82,7 +82,7 @@ jobs: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} Push_Nuget_Package: needs: Build_Project - runs-on: windows-latest + runs-on: windows-2019 steps: - name: Download Build Version Info uses: actions/download-artifact@v1 diff --git a/essentials-framework/Essentials Devices Common/Essentials Devices Common/VideoCodec/CiscoCodec/CiscoSparkCodec.cs b/essentials-framework/Essentials Devices Common/Essentials Devices Common/VideoCodec/CiscoCodec/CiscoSparkCodec.cs index 3ed2dae1..eee9a887 100644 --- a/essentials-framework/Essentials Devices Common/Essentials Devices Common/VideoCodec/CiscoCodec/CiscoSparkCodec.cs +++ b/essentials-framework/Essentials Devices Common/Essentials Devices Common/VideoCodec/CiscoCodec/CiscoSparkCodec.cs @@ -2154,6 +2154,14 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.Cisco { get { + CrestronConsole.PrintLine("CiscoSparkCodec AutoAnswerEnabled << Get >>"); + if (CodecConfiguration == null) CrestronConsole.PrintLine("CiscoSparkCodec > CodecConfiguration == Null"); + if (CodecConfiguration.Configuration == null) CrestronConsole.PrintLine("CiscoSparkCodec > CodecConfiguration.Configuration == Null"); + if (CodecConfiguration.Configuration.Conference == null) CrestronConsole.PrintLine("CiscoSparkCodec > CodecConfiguration.Configuration.Conference == Null"); + if (CodecConfiguration.Configuration.Conference.AutoAnswer == null) CrestronConsole.PrintLine("CiscoSparkCodec > CodecConfiguration.Configuration.Conference.AutoAnswer == Null"); + if (CodecConfiguration.Configuration.Conference.AutoAnswer.Mode == null) CrestronConsole.PrintLine("CiscoSparkCodec > CodecConfiguration.Configuration.Conference.AutoAnswer.Mode == Null"); + if (CodecConfiguration.Configuration.Conference.AutoAnswer.Mode.Value == null) CrestronConsole.PrintLine("CiscoSparkCodec > CodecConfiguration.Configuration.Conference.AutoAnswer.Mode.Value == Null"); + if (CodecConfiguration.Configuration.Conference.AutoAnswer.Mode.Value.ToLower() == "on") return true; else diff --git a/essentials-framework/Essentials Devices Common/Essentials Devices Common/VideoCodec/CiscoCodec/xConfiguration.cs b/essentials-framework/Essentials Devices Common/Essentials Devices Common/VideoCodec/CiscoCodec/xConfiguration.cs index 86e700b9..3a8c6252 100644 --- a/essentials-framework/Essentials Devices Common/Essentials Devices Common/VideoCodec/CiscoCodec/xConfiguration.cs +++ b/essentials-framework/Essentials Devices Common/Essentials Devices Common/VideoCodec/CiscoCodec/xConfiguration.cs @@ -376,6 +376,13 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.Cisco public Delay Delay { get; set; } public Mode9 Mode { get; set; } public Mute2 Mute { get; set; } + + public AutoAnswer() + { + Mode = new Mode9(); + Delay = new Delay(); + Mute = new Mute2(); + } } public class Protocol @@ -476,6 +483,11 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.Cisco public MaxTotalTransmitCallRate MaxTotalTransmitCallRate { get; set; } public MaxTransmitCallRate MaxTransmitCallRate { get; set; } public MultiStream MultiStream { get; set; } + + public Conference() + { + AutoAnswer = new AutoAnswer(); + } } public class LoginName @@ -1837,6 +1849,7 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.Cisco public Configuration() { Audio = new Audio(); + Conference = new Conference(); } } From 64352811c5036d7c1e33536fd5adb8e0d2218d06 Mon Sep 17 00:00:00 2001 From: Jonathan Arndt Date: Tue, 8 Feb 2022 13:31:13 -0800 Subject: [PATCH 21/59] Update VideoCodecBase.LinkVideoCodecCameraToApi FOR loop checking camera names to first check camera count --- .../VideoCodec/CiscoCodec/CiscoSparkCodec.cs | 14 ++------------ .../VideoCodec/VideoCodecBase.cs | 3 ++- 2 files changed, 4 insertions(+), 13 deletions(-) diff --git a/essentials-framework/Essentials Devices Common/Essentials Devices Common/VideoCodec/CiscoCodec/CiscoSparkCodec.cs b/essentials-framework/Essentials Devices Common/Essentials Devices Common/VideoCodec/CiscoCodec/CiscoSparkCodec.cs index eee9a887..c981c8f0 100644 --- a/essentials-framework/Essentials Devices Common/Essentials Devices Common/VideoCodec/CiscoCodec/CiscoSparkCodec.cs +++ b/essentials-framework/Essentials Devices Common/Essentials Devices Common/VideoCodec/CiscoCodec/CiscoSparkCodec.cs @@ -2154,18 +2154,8 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.Cisco { get { - CrestronConsole.PrintLine("CiscoSparkCodec AutoAnswerEnabled << Get >>"); - if (CodecConfiguration == null) CrestronConsole.PrintLine("CiscoSparkCodec > CodecConfiguration == Null"); - if (CodecConfiguration.Configuration == null) CrestronConsole.PrintLine("CiscoSparkCodec > CodecConfiguration.Configuration == Null"); - if (CodecConfiguration.Configuration.Conference == null) CrestronConsole.PrintLine("CiscoSparkCodec > CodecConfiguration.Configuration.Conference == Null"); - if (CodecConfiguration.Configuration.Conference.AutoAnswer == null) CrestronConsole.PrintLine("CiscoSparkCodec > CodecConfiguration.Configuration.Conference.AutoAnswer == Null"); - if (CodecConfiguration.Configuration.Conference.AutoAnswer.Mode == null) CrestronConsole.PrintLine("CiscoSparkCodec > CodecConfiguration.Configuration.Conference.AutoAnswer.Mode == Null"); - if (CodecConfiguration.Configuration.Conference.AutoAnswer.Mode.Value == null) CrestronConsole.PrintLine("CiscoSparkCodec > CodecConfiguration.Configuration.Conference.AutoAnswer.Mode.Value == Null"); - - if (CodecConfiguration.Configuration.Conference.AutoAnswer.Mode.Value.ToLower() == "on") - return true; - else - return false; + if (CodecConfiguration.Configuration.Conference.AutoAnswer.Mode.Value == null) return false; + return CodecConfiguration.Configuration.Conference.AutoAnswer.Mode.Value.ToLower() == "on"; } } diff --git a/essentials-framework/Essentials Devices Common/Essentials Devices Common/VideoCodec/VideoCodecBase.cs b/essentials-framework/Essentials Devices Common/Essentials Devices Common/VideoCodec/VideoCodecBase.cs index 51376b51..9860d1c3 100644 --- a/essentials-framework/Essentials Devices Common/Essentials Devices Common/VideoCodec/VideoCodecBase.cs +++ b/essentials-framework/Essentials Devices Common/Essentials Devices Common/VideoCodec/VideoCodecBase.cs @@ -1478,7 +1478,8 @@ ScreenIndexIsPinnedTo: {8} (a{17}) // Camera names for (uint i = 0; i < joinMap.CameraNamesFb.JoinSpan; i++) { - if (codec.Cameras[(int)i] != null) + //Check the count first + if (i < codec.Cameras.Count && codec.Cameras[(int)i] != null) { trilist.SetString(joinMap.CameraNamesFb.JoinNumber + i, codec.Cameras[(int)i].Name); } From 93bfcc7baa708bef2407c74283e14bfff80d9ea5 Mon Sep 17 00:00:00 2001 From: Jonathan Arndt Date: Tue, 8 Feb 2022 16:24:54 -0800 Subject: [PATCH 22/59] Add logic to subscribe to PhoneBookSyncState during the CustomActivate method within CiscoSparkCodec class --- .../JoinMaps/VideoCodecControllerJoinMap.cs | 2 +- .../VideoCodec/CiscoCodec/CiscoSparkCodec.cs | 8 +++ .../VideoCodec/VideoCodecBase.cs | 64 +++++++++++++++---- 3 files changed, 59 insertions(+), 15 deletions(-) diff --git a/essentials-framework/Essentials Core/PepperDashEssentialsBase/Bridges/JoinMaps/VideoCodecControllerJoinMap.cs b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Bridges/JoinMaps/VideoCodecControllerJoinMap.cs index 862e1b2a..368a547f 100644 --- a/essentials-framework/Essentials Core/PepperDashEssentialsBase/Bridges/JoinMaps/VideoCodecControllerJoinMap.cs +++ b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Bridges/JoinMaps/VideoCodecControllerJoinMap.cs @@ -464,7 +464,7 @@ namespace PepperDash.Essentials.Core.Bridges.JoinMaps new JoinMetadata { Description = "Go to Directory Root", - JoinCapabilities = eJoinCapabilities.ToSIMPL, + JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); diff --git a/essentials-framework/Essentials Devices Common/Essentials Devices Common/VideoCodec/CiscoCodec/CiscoSparkCodec.cs b/essentials-framework/Essentials Devices Common/Essentials Devices Common/VideoCodec/CiscoCodec/CiscoSparkCodec.cs index c981c8f0..efe1914d 100644 --- a/essentials-framework/Essentials Devices Common/Essentials Devices Common/VideoCodec/CiscoCodec/CiscoSparkCodec.cs +++ b/essentials-framework/Essentials Devices Common/Essentials Devices Common/VideoCodec/CiscoCodec/CiscoSparkCodec.cs @@ -590,9 +590,16 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.Cisco 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 += new EventHandler(PhonebookSyncState_InitialSyncCompleted); + return base.CustomActivate(); } + void PhonebookSyncState_InitialSyncCompleted(object sender, EventArgs e) + { + OnDirectoryResultReturned(DirectoryRoot); + } + #region Overrides of Device public override void Initialize() @@ -1144,6 +1151,7 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.Cisco var handler = DirectoryResultReturned; if (handler != null) { + Debug.Console(2, this, "Directory result returned"); handler(this, new DirectoryEventArgs() { Directory = result, diff --git a/essentials-framework/Essentials Devices Common/Essentials Devices Common/VideoCodec/VideoCodecBase.cs b/essentials-framework/Essentials Devices Common/Essentials Devices Common/VideoCodec/VideoCodecBase.cs index 9860d1c3..f60ece74 100644 --- a/essentials-framework/Essentials Devices Common/Essentials Devices Common/VideoCodec/VideoCodecBase.cs +++ b/essentials-framework/Essentials Devices Common/Essentials Devices Common/VideoCodec/VideoCodecBase.cs @@ -937,9 +937,7 @@ ScreenIndexIsPinnedTo: {8} (a{17}) private void LinkVideoCodecDirectoryToApi(IHasDirectory codec, BasicTriList trilist, VideoCodecControllerJoinMap joinMap) { codec.CurrentDirectoryResultIsNotDirectoryRoot.LinkComplementInputSig( - trilist.BooleanInput[joinMap.DirectoryIsRoot.JoinNumber]); - - trilist.SetSigFalseAction(joinMap.DirectoryRoot.JoinNumber, codec.SetCurrentDirectoryToRoot); + trilist.BooleanInput[joinMap.DirectoryIsRoot.JoinNumber]); trilist.SetStringSigAction(joinMap.DirectorySearchString.JoinNumber, codec.SearchDirectory); @@ -951,8 +949,25 @@ ScreenIndexIsPinnedTo: {8} (a{17}) trilist.SetSigFalseAction(joinMap.DirectoryFolderBack.JoinNumber, codec.GetDirectoryParentFolderContents); + if (codec.DirectoryRoot != null) + { + trilist.SetUshort(joinMap.DirectoryRowCount.JoinNumber, (ushort)codec.DirectoryRoot.CurrentDirectoryResults.Count); + + var clearBytes = XSigHelpers.ClearOutputs(); + + trilist.SetString(joinMap.DirectoryEntries.JoinNumber, + Encoding.GetEncoding(XSigEncoding).GetString(clearBytes, 0, clearBytes.Length)); + var directoryXSig = UpdateDirectoryXSig(codec.DirectoryRoot, !codec.CurrentDirectoryResultIsNotDirectoryRoot.BoolValue); + + Debug.Console(2, this, "Directory XSig Length: {0}", directoryXSig.Length); + + trilist.SetString(joinMap.DirectoryEntries.JoinNumber, directoryXSig); + } + codec.DirectoryResultReturned += (sender, args) => { + Debug.Console(2, this, "CiscoLinkToApi > DirectoryResultReturnedHandler"); + trilist.SetUshort(joinMap.DirectoryRowCount.JoinNumber, (ushort)args.Directory.CurrentDirectoryResults.Count); var clearBytes = XSigHelpers.ClearOutputs(); @@ -961,6 +976,8 @@ ScreenIndexIsPinnedTo: {8} (a{17}) Encoding.GetEncoding(XSigEncoding).GetString(clearBytes, 0, clearBytes.Length)); var directoryXSig = UpdateDirectoryXSig(args.Directory, !codec.CurrentDirectoryResultIsNotDirectoryRoot.BoolValue); + Debug.Console(2, this, "Directory XSig Length: {0}", directoryXSig.Length); + trilist.SetString(joinMap.DirectoryEntries.JoinNumber, directoryXSig); }; } @@ -1068,10 +1085,14 @@ ScreenIndexIsPinnedTo: {8} (a{17}) var contactIndex = 1; var tokenArray = new XSigToken[directory.CurrentDirectoryResults.Count]; + Debug.Console(2, this, "Is root {0} Directory Count: {1}", isRoot, directory.CurrentDirectoryResults.Count); + foreach (var entry in directory.CurrentDirectoryResults) { var arrayIndex = contactIndex - 1; + Debug.Console(2, this, "Entry Name: {0}, Folder ID: {1}", entry.Name, entry.FolderId); + if (entry is DirectoryFolder && entry.ParentFolderId == "root") { tokenArray[arrayIndex] = new XSigSerialToken(contactIndex, String.Format("[+] {0}", entry.Name)); @@ -1081,7 +1102,11 @@ ScreenIndexIsPinnedTo: {8} (a{17}) continue; } - if (isRoot && String.IsNullOrEmpty(entry.FolderId)) continue; + //if (isRoot && String.IsNullOrEmpty(entry.FolderId)) { continue; } + //else + //{ + // Debug.Console(2, this, "Skipping Entry"); + //} tokenArray[arrayIndex] = new XSigSerialToken(contactIndex, entry.Name); @@ -1628,20 +1653,31 @@ ScreenIndexIsPinnedTo: {8} (a{17}) // Update the call history joins var maxItems = joinMap.RecentCallNamesStart.JoinSpan; - uint i = 0; - foreach(var item in codec.CallHistory.RecentCalls) + // Create history + uint index = 0; + for (uint i = 0; i < maxItems && i < codec.CallHistory.RecentCalls.Count; i++) { - trilist.SetString(joinMap.RecentCallNamesStart.JoinNumber + i, item.Name); - trilist.SetString(joinMap.RecentCallTimesStart.JoinNumber + i, item.StartTime.ToShortTimeString()); - trilist.SetUshort(joinMap.RecentCallOccurrenceType.JoinNumber + i, (ushort)item.OccurrenceType); - i++; + trilist.SetString(joinMap.RecentCallNamesStart.JoinNumber + i, codec.CallHistory.RecentCalls[(int)i].Name); + trilist.SetString(joinMap.RecentCallTimesStart.JoinNumber + i, codec.CallHistory.RecentCalls[(int)i].StartTime.ToShortTimeString()); + trilist.SetUshort(joinMap.RecentCallOccurrenceType.JoinNumber + i, (ushort)codec.CallHistory.RecentCalls[(int)i].OccurrenceType); + //i++; + index = i; } + + //foreach(var item in codec.CallHistory.RecentCalls) + //{ + // trilist.SetString(joinMap.RecentCallNamesStart.JoinNumber + i, item.Name); + // trilist.SetString(joinMap.RecentCallTimesStart.JoinNumber + i, item.StartTime.ToShortTimeString()); + // trilist.SetUshort(joinMap.RecentCallOccurrenceType.JoinNumber + i, (ushort)item.OccurrenceType); + // i++; + //} - for (uint index = i; i < maxItems; index++) + // Clears existing items + for (uint j = index; j < maxItems; j++) { - trilist.SetString(joinMap.RecentCallNamesStart.JoinNumber + index, string.Empty); - trilist.SetString(joinMap.RecentCallTimesStart.JoinNumber + index, string.Empty); - trilist.SetUshort(joinMap.RecentCallOccurrenceType.JoinNumber + index, 0); + trilist.SetString(joinMap.RecentCallNamesStart.JoinNumber + j, string.Empty); + trilist.SetString(joinMap.RecentCallTimesStart.JoinNumber + j, string.Empty); + trilist.SetUshort(joinMap.RecentCallOccurrenceType.JoinNumber + j, 0); } } From 84b39a959edb5ac5571a3878bfccb31403ba79d6 Mon Sep 17 00:00:00 2001 From: Jonathan Arndt Date: Tue, 8 Feb 2022 16:31:18 -0800 Subject: [PATCH 23/59] Update VideoCodecBase class UpdateDirectoryXSig method removing the check if the FolderId is null or empty as that check would be device specific --- .../VideoCodec/VideoCodecBase.cs | 8 -------- 1 file changed, 8 deletions(-) diff --git a/essentials-framework/Essentials Devices Common/Essentials Devices Common/VideoCodec/VideoCodecBase.cs b/essentials-framework/Essentials Devices Common/Essentials Devices Common/VideoCodec/VideoCodecBase.cs index f60ece74..fd24c8ec 100644 --- a/essentials-framework/Essentials Devices Common/Essentials Devices Common/VideoCodec/VideoCodecBase.cs +++ b/essentials-framework/Essentials Devices Common/Essentials Devices Common/VideoCodec/VideoCodecBase.cs @@ -966,8 +966,6 @@ ScreenIndexIsPinnedTo: {8} (a{17}) codec.DirectoryResultReturned += (sender, args) => { - Debug.Console(2, this, "CiscoLinkToApi > DirectoryResultReturnedHandler"); - trilist.SetUshort(joinMap.DirectoryRowCount.JoinNumber, (ushort)args.Directory.CurrentDirectoryResults.Count); var clearBytes = XSigHelpers.ClearOutputs(); @@ -1102,12 +1100,6 @@ ScreenIndexIsPinnedTo: {8} (a{17}) continue; } - //if (isRoot && String.IsNullOrEmpty(entry.FolderId)) { continue; } - //else - //{ - // Debug.Console(2, this, "Skipping Entry"); - //} - tokenArray[arrayIndex] = new XSigSerialToken(contactIndex, entry.Name); contactIndex++; From 402754b69e199dd1c219dddebe47f737e83896a2 Mon Sep 17 00:00:00 2001 From: Jonathan Arndt Date: Tue, 8 Feb 2022 16:31:26 -0800 Subject: [PATCH 24/59] Update VideoCodecBase class UpdateDirectoryXSig method removing the check if the FolderId is null or empty as that check would be device specific --- .../Essentials Devices Common/VideoCodec/VideoCodecBase.cs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/essentials-framework/Essentials Devices Common/Essentials Devices Common/VideoCodec/VideoCodecBase.cs b/essentials-framework/Essentials Devices Common/Essentials Devices Common/VideoCodec/VideoCodecBase.cs index fd24c8ec..490d5abb 100644 --- a/essentials-framework/Essentials Devices Common/Essentials Devices Common/VideoCodec/VideoCodecBase.cs +++ b/essentials-framework/Essentials Devices Common/Essentials Devices Common/VideoCodec/VideoCodecBase.cs @@ -1100,6 +1100,12 @@ ScreenIndexIsPinnedTo: {8} (a{17}) continue; } + //if (isRoot && String.IsNullOrEmpty(entry.FolderId)) { continue; } + //else + //{ + // Debug.Console(2, this, "Skipping Entry"); + //} + tokenArray[arrayIndex] = new XSigSerialToken(contactIndex, entry.Name); contactIndex++; From faabdde3f78c5901e2cfe8341b2bc4cff052e91e Mon Sep 17 00:00:00 2001 From: Jonathan Arndt Date: Tue, 8 Feb 2022 16:31:45 -0800 Subject: [PATCH 25/59] Update VideoCodecBase class UpdateDirectoryXSig method removing the check if the FolderId is null or empty as that check would be device specific --- .../Essentials Devices Common/VideoCodec/VideoCodecBase.cs | 6 ------ 1 file changed, 6 deletions(-) diff --git a/essentials-framework/Essentials Devices Common/Essentials Devices Common/VideoCodec/VideoCodecBase.cs b/essentials-framework/Essentials Devices Common/Essentials Devices Common/VideoCodec/VideoCodecBase.cs index 490d5abb..fd24c8ec 100644 --- a/essentials-framework/Essentials Devices Common/Essentials Devices Common/VideoCodec/VideoCodecBase.cs +++ b/essentials-framework/Essentials Devices Common/Essentials Devices Common/VideoCodec/VideoCodecBase.cs @@ -1100,12 +1100,6 @@ ScreenIndexIsPinnedTo: {8} (a{17}) continue; } - //if (isRoot && String.IsNullOrEmpty(entry.FolderId)) { continue; } - //else - //{ - // Debug.Console(2, this, "Skipping Entry"); - //} - tokenArray[arrayIndex] = new XSigSerialToken(contactIndex, entry.Name); contactIndex++; From c84525ddefed71d2ba65571dfa8b614d8af6f5ac Mon Sep 17 00:00:00 2001 From: Jonathan Arndt Date: Wed, 9 Feb 2022 11:39:35 -0800 Subject: [PATCH 26/59] Update recent call history and call method to protect for zero value from SIMPL --- .../VideoCodec/CiscoCodec/CiscoSparkCodec.cs | 2 +- .../VideoCodec/VideoCodecBase.cs | 18 ++++++++++++++---- 2 files changed, 15 insertions(+), 5 deletions(-) diff --git a/essentials-framework/Essentials Devices Common/Essentials Devices Common/VideoCodec/CiscoCodec/CiscoSparkCodec.cs b/essentials-framework/Essentials Devices Common/Essentials Devices Common/VideoCodec/CiscoCodec/CiscoSparkCodec.cs index efe1914d..74f4b919 100644 --- a/essentials-framework/Essentials Devices Common/Essentials Devices Common/VideoCodec/CiscoCodec/CiscoSparkCodec.cs +++ b/essentials-framework/Essentials Devices Common/Essentials Devices Common/VideoCodec/CiscoCodec/CiscoSparkCodec.cs @@ -1516,7 +1516,7 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.Cisco return; } - SendText(string.Format("xConfiguration Audio SoundsAndAlerts RingVolume: [0]", volume)); + SendText(string.Format("xConfiguration Audio SoundsAndAlerts RingVolume: {0}", volume)); } /// diff --git a/essentials-framework/Essentials Devices Common/Essentials Devices Common/VideoCodec/VideoCodecBase.cs b/essentials-framework/Essentials Devices Common/Essentials Devices Common/VideoCodec/VideoCodecBase.cs index fd24c8ec..fcdcc127 100644 --- a/essentials-framework/Essentials Devices Common/Essentials Devices Common/VideoCodec/VideoCodecBase.cs +++ b/essentials-framework/Essentials Devices Common/Essentials Devices Common/VideoCodec/VideoCodecBase.cs @@ -982,6 +982,8 @@ ScreenIndexIsPinnedTo: {8} (a{17}) private void SelectDirectoryEntry(IHasDirectory codec, ushort i, BasicTriList trilist, VideoCodecControllerJoinMap joinMap) { + if (i < 1 || i > codec.CurrentDirectoryResult.CurrentDirectoryResults.Count) return; + var entry = codec.CurrentDirectoryResult.CurrentDirectoryResults[i - 1]; if (entry is DirectoryFolder) @@ -1047,10 +1049,12 @@ ScreenIndexIsPinnedTo: {8} (a{17}) const int offset = maxStrings; var stringIndex = 0; var arrayIndex = 0; - var tokenArray = new XSigToken[contact.ContactMethods.Count]; + // Create a new token array and set the size to the number of methods times the total number of signals + var tokenArray = new XSigToken[maxMethods * offset]; + + Debug.Console(2, this, "Creating XSIG token array with size {0}", maxMethods * offset); // TODO: Add code to generate XSig data - foreach (var method in contact.ContactMethods) { if (arrayIndex >= maxMethods * offset) @@ -1606,11 +1610,17 @@ ScreenIndexIsPinnedTo: {8} (a{17}) // Selected item action and feedback trilist.SetUShortSigAction(joinMap.SelectRecentCallItem.JoinNumber, (u) => { + if (u == 0 || u > codec.CallHistory.RecentCalls.Count) + { + Debug.Console(2, this, "Recent Call History index out of range"); + return; + } + _selectedRecentCallItemIndex = (int)(u - 1); - trilist.SetUshort(joinMap.SelectRecentCallItem.JoinNumber, u); + trilist.SetUshort(joinMap.SelectRecentCallItem.JoinNumber, u); var _selectedRecentCallItem = codec.CallHistory.RecentCalls[_selectedRecentCallItemIndex]; - + if (_selectedRecentCallItem != null) { trilist.SetString(joinMap.SelectedRecentCallName.JoinNumber, _selectedRecentCallItem.Name); From db982f449095cb337057043bacc6b3ef6e96075e Mon Sep 17 00:00:00 2001 From: Neil Dorin Date: Wed, 9 Feb 2022 14:00:49 -0700 Subject: [PATCH 27/59] feat(essentials): Adds ability to select and dial contact methods for directory contacts via SIMPL bridge --- .../JoinMaps/VideoCodecControllerJoinMap.cs | 28 ++++++++ .../VideoCodec/VideoCodecBase.cs | 70 ++++++++++++++----- 2 files changed, 80 insertions(+), 18 deletions(-) diff --git a/essentials-framework/Essentials Core/PepperDashEssentialsBase/Bridges/JoinMaps/VideoCodecControllerJoinMap.cs b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Bridges/JoinMaps/VideoCodecControllerJoinMap.cs index 368a547f..51b30c6a 100644 --- a/essentials-framework/Essentials Core/PepperDashEssentialsBase/Bridges/JoinMaps/VideoCodecControllerJoinMap.cs +++ b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Bridges/JoinMaps/VideoCodecControllerJoinMap.cs @@ -510,6 +510,20 @@ namespace PepperDash.Essentials.Core.Bridges.JoinMaps JoinType = eJoinType.Digital }); + [JoinName("DirectoryDialSelectedContactMethod")] + public JoinDataComplete DirectoryDialSelectedContactMethod = new JoinDataComplete( + new JoinData + { + JoinNumber = 108, + JoinSpan = 1 + }, + new JoinMetadata + { + Description = "Pulse to dial the selected contact method", + JoinCapabilities = eJoinCapabilities.FromSIMPL, + JoinType = eJoinType.Digital + }); + [JoinName("CameraTiltUp")] public JoinDataComplete CameraTiltUp = new JoinDataComplete( new JoinData @@ -1232,6 +1246,20 @@ namespace PepperDash.Essentials.Core.Bridges.JoinMaps JoinType = eJoinType.Analog }); + [JoinName("SelectContactMethod")] + public JoinDataComplete SelectContactMethod = new JoinDataComplete( + new JoinData + { + JoinNumber = 103, + JoinSpan = 1 + }, + new JoinMetadata + { + Description = "Selects a contact method by index", + JoinCapabilities = eJoinCapabilities.FromSIMPL, + JoinType = eJoinType.Analog + }); + [JoinName("CameraPresetSelect")] public JoinDataComplete CameraPresetSelect = new JoinDataComplete( new JoinData diff --git a/essentials-framework/Essentials Devices Common/Essentials Devices Common/VideoCodec/VideoCodecBase.cs b/essentials-framework/Essentials Devices Common/Essentials Devices Common/VideoCodec/VideoCodecBase.cs index fcdcc127..55063eab 100644 --- a/essentials-framework/Essentials Devices Common/Essentials Devices Common/VideoCodec/VideoCodecBase.cs +++ b/essentials-framework/Essentials Devices Common/Essentials Devices Common/VideoCodec/VideoCodecBase.cs @@ -980,52 +980,86 @@ ScreenIndexIsPinnedTo: {8} (a{17}) }; } + + private void SelectDirectoryEntry(IHasDirectory codec, ushort i, BasicTriList trilist, VideoCodecControllerJoinMap joinMap) { if (i < 1 || i > codec.CurrentDirectoryResult.CurrentDirectoryResults.Count) return; - var entry = codec.CurrentDirectoryResult.CurrentDirectoryResults[i - 1]; + _selectedDirectoryItem = codec.CurrentDirectoryResult.CurrentDirectoryResults[i - 1]; - if (entry is DirectoryFolder) + + if (_selectedDirectoryItem is DirectoryFolder) { - codec.GetDirectoryFolderContents(entry.FolderId); + codec.GetDirectoryFolderContents(_selectedDirectoryItem.FolderId); trilist.SetUshort(joinMap.SelectedContactMethodCount.JoinNumber, 0); - return; + trilist.SetString(joinMap.DirectorySelectedFolderName.JoinNumber, _selectedDirectoryItem.Name); + trilist.SetString(joinMap.DirectoryEntrySelectedName.JoinNumber, string.Empty); + trilist.ClearUShortSigAction(joinMap.SelectContactMethod.JoinNumber); + trilist.ClearBoolSigAction(joinMap.DirectoryDialSelectedLine.JoinNumber); + trilist.ClearBoolSigAction(joinMap.DirectoryDialSelectedContactMethod.JoinNumber); + return; } - // Allow auto dial of selected line + // not a folder. Clear this value + trilist.SetString(joinMap.DirectorySelectedFolderName.JoinNumber, string.Empty); + + var selectedContact = _selectedDirectoryItem as DirectoryContact; + if (selectedContact != null) + { + trilist.SetString(joinMap.DirectoryEntrySelectedName.JoinNumber, selectedContact.Name); + + } + + // Allow auto dial of selected line. Always dials first contact method if (!trilist.GetBool(joinMap.DirectoryDisableAutoDialSelectedLine.JoinNumber)) { - var dialableEntry = entry as IInvitableContact; + var invitableEntry = _selectedDirectoryItem as IInvitableContact; - if (dialableEntry != null) - { - Dial(dialableEntry); - return; - } + if (invitableEntry != null) + { + Dial(invitableEntry); + return; + } - var entryToDial = entry as DirectoryContact; + var entryToDial = _selectedDirectoryItem as DirectoryContact; - if (entryToDial == null) return; + trilist.SetString(joinMap.DirectoryEntrySelectedNumber.JoinNumber, selectedContact.ContactMethods[0].Number); - Dial(entryToDial.ContactMethods[0].Number); + if (entryToDial == null) return; + + Dial(entryToDial.ContactMethods[0].Number); return; } else { // If auto dial is disabled... - var entryToDial = entry as DirectoryContact; + var entryToDial = _selectedDirectoryItem as DirectoryContact; if (entryToDial == null) { + // Clear out values and actions from last selected item trilist.SetUshort(joinMap.SelectedContactMethodCount.JoinNumber, 0); + trilist.SetString(joinMap.DirectoryEntrySelectedName.JoinNumber, string.Empty); + trilist.ClearUShortSigAction(joinMap.SelectContactMethod.JoinNumber); + trilist.ClearBoolSigAction(joinMap.DirectoryDialSelectedLine.JoinNumber); + trilist.ClearBoolSigAction(joinMap.DirectoryDialSelectedContactMethod.JoinNumber); return; } - trilist.SetSigFalseAction(joinMap.DirectoryDialSelectedLine.JoinNumber, () => Dial(entryToDial.ContactMethods[0].Number)); - trilist.SetUshort(joinMap.SelectedContactMethodCount.JoinNumber, (ushort)entryToDial.ContactMethods.Count); + // Update the action to dial the selected contact method + trilist.SetUShortSigAction(joinMap.SelectContactMethod.JoinNumber, (u) => + { + if (u < 1 || u > entryToDial.ContactMethods.Count) return; + + trilist.SetSigFalseAction(joinMap.DirectoryDialSelectedContactMethod.JoinNumber, () => Dial(entryToDial.ContactMethods[u].Number)); + }); + + // Sets DirectoryDialSelectedLine join action to dial first contact method + trilist.SetSigFalseAction(joinMap.DirectoryDialSelectedLine.JoinNumber, () => Dial(entryToDial.ContactMethods[0].Number)); + var clearBytes = XSigHelpers.ClearOutputs(); trilist.SetString(joinMap.ContactMethods.JoinNumber, @@ -1034,7 +1068,6 @@ ScreenIndexIsPinnedTo: {8} (a{17}) trilist.SetString(joinMap.ContactMethods.JoinNumber, contactMethodsXSig); } - } /// @@ -1599,6 +1632,7 @@ ScreenIndexIsPinnedTo: {8} (a{17}) // Following fields only used for Bridging private int _selectedRecentCallItemIndex; private CodecCallHistory.CallHistoryEntry _selectedRecentCallItem; + private DirectoryItem _selectedDirectoryItem; private void LinkVideoCodecCallHistoryToApi(IHasCallHistory codec, BasicTriList trilist, VideoCodecControllerJoinMap joinMap) { From db526cdd40d1cffd7cd2741c0711f46c50f7c320 Mon Sep 17 00:00:00 2001 From: Neil Dorin Date: Wed, 9 Feb 2022 14:09:54 -0700 Subject: [PATCH 28/59] fix(essentials): fixes exception when parsing presentation local instance ghosted response --- .../VideoCodec/CiscoCodec/CiscoSparkCodec.cs | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/essentials-framework/Essentials Devices Common/Essentials Devices Common/VideoCodec/CiscoCodec/CiscoSparkCodec.cs b/essentials-framework/Essentials Devices Common/Essentials Devices Common/VideoCodec/CiscoCodec/CiscoSparkCodec.cs index 74f4b919..36192f7d 100644 --- a/essentials-framework/Essentials Devices Common/Essentials Devices Common/VideoCodec/CiscoCodec/CiscoSparkCodec.cs +++ b/essentials-framework/Essentials Devices Common/Essentials Devices Common/VideoCodec/CiscoCodec/CiscoSparkCodec.cs @@ -830,15 +830,18 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.Cisco if (conference.Presentation.LocalInstance.Count > 0) { if (!string.IsNullOrEmpty(conference.Presentation.LocalInstance[0].ghost)) + { _presentationSource = 0; + _presentationLocalOnly = false; + _presentationLocalRemote = false; + } else if (conference.Presentation.LocalInstance[0].Source != null) { _presentationSource = conference.Presentation.LocalInstance[0].Source.IntValue; + _presentationLocalOnly = conference.Presentation.LocalInstance.Any((i) => i.SendingMode.LocalOnly); + _presentationLocalRemote = conference.Presentation.LocalInstance.Any((i) => i.SendingMode.LocalRemote); } - _presentationLocalOnly = conference.Presentation.LocalInstance.Any((i) => i.SendingMode.LocalOnly); - _presentationLocalRemote = conference.Presentation.LocalInstance.Any((i) => i.SendingMode.LocalRemote); - PresentationSourceFeedback.FireUpdate(); PresentationSendingLocalOnlyFeedback.FireUpdate(); PresentationSendingLocalRemoteFeedback.FireUpdate(); From b97783603b28a403ce5072992145ab3fbbe9d69d Mon Sep 17 00:00:00 2001 From: Neil Dorin Date: Wed, 9 Feb 2022 14:14:44 -0700 Subject: [PATCH 29/59] feat(essentials): Adds analog fb join for recent calls count to VideoCodecControllerJoinMap and bridge --- .../JoinMaps/VideoCodecControllerJoinMap.cs | 14 ++++++++++++++ .../VideoCodec/VideoCodecBase.cs | 1 + 2 files changed, 15 insertions(+) diff --git a/essentials-framework/Essentials Core/PepperDashEssentialsBase/Bridges/JoinMaps/VideoCodecControllerJoinMap.cs b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Bridges/JoinMaps/VideoCodecControllerJoinMap.cs index 51b30c6a..03d0c4b5 100644 --- a/essentials-framework/Essentials Core/PepperDashEssentialsBase/Bridges/JoinMaps/VideoCodecControllerJoinMap.cs +++ b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Bridges/JoinMaps/VideoCodecControllerJoinMap.cs @@ -1358,6 +1358,20 @@ namespace PepperDash.Essentials.Core.Bridges.JoinMaps JoinType = eJoinType.Analog }); + [JoinName("RecentCallCount")] + public JoinDataComplete RecentCallCount = new JoinDataComplete( + new JoinData + { + JoinNumber = 191, + JoinSpan = 1 + }, + new JoinMetadata + { + Description = "Recent Call Count", + JoinCapabilities = eJoinCapabilities.ToSIMPL, + JoinType = eJoinType.Analog + }); + #endregion diff --git a/essentials-framework/Essentials Devices Common/Essentials Devices Common/VideoCodec/VideoCodecBase.cs b/essentials-framework/Essentials Devices Common/Essentials Devices Common/VideoCodec/VideoCodecBase.cs index 55063eab..c32643ba 100644 --- a/essentials-framework/Essentials Devices Common/Essentials Devices Common/VideoCodec/VideoCodecBase.cs +++ b/essentials-framework/Essentials Devices Common/Essentials Devices Common/VideoCodec/VideoCodecBase.cs @@ -1685,6 +1685,7 @@ ScreenIndexIsPinnedTo: {8} (a{17}) trilist.ClearBoolSigAction(joinMap.RemoveSelectedRecentCallItem.JoinNumber); // + trilist.SetUshort(joinMap.RecentCallCount.JoinNumber, (ushort)codec.CallHistory.RecentCalls.Count); // Update the call history joins var maxItems = joinMap.RecentCallNamesStart.JoinSpan; From adbce916baa322f83fbb5a2ce36d4d8157cc5b10 Mon Sep 17 00:00:00 2001 From: Neil Dorin Date: Wed, 9 Feb 2022 14:34:25 -0700 Subject: [PATCH 30/59] feat(essentials): Adds ability to read camera info from codec rather than just from config --- .../VideoCodec/CiscoCodec/CiscoSparkCodec.cs | 26 ++++++++++++++++++- .../VideoCodec/CiscoCodec/xStatus.cs | 14 ++++++++++ 2 files changed, 39 insertions(+), 1 deletion(-) diff --git a/essentials-framework/Essentials Devices Common/Essentials Devices Common/VideoCodec/CiscoCodec/CiscoSparkCodec.cs b/essentials-framework/Essentials Devices Common/Essentials Devices Common/VideoCodec/CiscoCodec/CiscoSparkCodec.cs index 36192f7d..213a8d7c 100644 --- a/essentials-framework/Essentials Devices Common/Essentials Devices Common/VideoCodec/CiscoCodec/CiscoSparkCodec.cs +++ b/essentials-framework/Essentials Devices Common/Essentials Devices Common/VideoCodec/CiscoCodec/CiscoSparkCodec.cs @@ -646,7 +646,31 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.Cisco /// void SyncState_InitialSyncCompleted(object sender, EventArgs e) { - SetUpCameras(_config.CameraInfo); + // Check for camera config info first + if (_config.CameraInfo.Count > 0) + { + SetUpCameras(_config.CameraInfo); + } + else + { + try + { + var cameraInfo = new List(); + + foreach (var camera in CodecStatus.Status.Cameras.Camera) + { + var id = Convert.ToUInt16(camera.id); + var info = new CameraInfo() { CameraNumber = id, Name = string.Format("{0} {1}", camera.Manufacturer, camera.Model), SourceId = camera.DetectedConnector.ConnectorId }; + cameraInfo.Add(info); + } + } + catch (Exception ex) + { + Debug.Console(2, this, "Error generating camera info from codec status data: {0}", ex); + } + } + + // Fire the ready event SetIsReady(); diff --git a/essentials-framework/Essentials Devices Common/Essentials Devices Common/VideoCodec/CiscoCodec/xStatus.cs b/essentials-framework/Essentials Devices Common/Essentials Devices Common/VideoCodec/CiscoCodec/xStatus.cs index 6db3c2e3..e7f418eb 100644 --- a/essentials-framework/Essentials Devices Common/Essentials Devices Common/VideoCodec/CiscoCodec/xStatus.cs +++ b/essentials-framework/Essentials Devices Common/Essentials Devices Common/VideoCodec/CiscoCodec/xStatus.cs @@ -262,11 +262,25 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.Cisco public string Value { get; set; } } + public class DectectedConnector + { + public string Value { get; set; } + + public int ConnectorId + { + get + { + return Convert.ToUInt16(Value); + } + } + } + public class Camera { public string id { get; set; } public Capabilities Capabilities { get; set; } public Connected Connected { get; set; } + public DectectedConnector DetectedConnector { get; set; } public Flip Flip { get; set; } public HardwareID HardwareID { get; set; } public MacAddress MacAddress { get; set; } From 90023621dc7929db042a0ae50cc2a96603013e09 Mon Sep 17 00:00:00 2001 From: Neil Dorin Date: Wed, 9 Feb 2022 14:48:45 -0700 Subject: [PATCH 31/59] fix(essentials): Adds some better console log comments and calls SetUpCameras() after reading data from codec. --- .../VideoCodec/CiscoCodec/CiscoSparkCodec.cs | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/essentials-framework/Essentials Devices Common/Essentials Devices Common/VideoCodec/CiscoCodec/CiscoSparkCodec.cs b/essentials-framework/Essentials Devices Common/Essentials Devices Common/VideoCodec/CiscoCodec/CiscoSparkCodec.cs index 213a8d7c..39b3e167 100644 --- a/essentials-framework/Essentials Devices Common/Essentials Devices Common/VideoCodec/CiscoCodec/CiscoSparkCodec.cs +++ b/essentials-framework/Essentials Devices Common/Essentials Devices Common/VideoCodec/CiscoCodec/CiscoSparkCodec.cs @@ -649,10 +649,12 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.Cisco // Check for camera config info first if (_config.CameraInfo.Count > 0) { + Debug.Console(0, this, "Reading codec cameraInfo from config properties."); SetUpCameras(_config.CameraInfo); } else { + 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(); @@ -663,6 +665,10 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.Cisco var info = new CameraInfo() { CameraNumber = id, Name = string.Format("{0} {1}", camera.Manufacturer, camera.Model), SourceId = camera.DetectedConnector.ConnectorId }; cameraInfo.Add(info); } + + Debug.Console(0, this, "Successfully got cameraInfo for {0} cameras from codec.", cameraInfo.Count); + + SetUpCameras(cameraInfo); } catch (Exception ex) { @@ -670,10 +676,6 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.Cisco } } - - - // Fire the ready event - SetIsReady(); //CommDebuggingIsOn = false; GetCallHistory(); @@ -683,6 +685,9 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.Cisco BookingsRefreshTimer = new CTimer(GetBookings, 900000, 900000); // 15 minute timer to check for new booking info GetBookings(null); + + // Fire the ready event + SetIsReady(); } public void SetCommDebug(string s) @@ -2003,6 +2008,8 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.Cisco SelectedCameraFeedback = new StringFeedback(() => SelectedCamera.Key); + SelectedCamera = Cameras[0]; ; // call the method to select the camera and ensure the feedbacks get updated. + ControllingFarEndCameraFeedback = new BoolFeedback(() => SelectedCamera is IAmFarEndCamera); DeviceManager.AddDevice(farEndCamera); @@ -2018,7 +2025,6 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.Cisco FarEndRoomPresets.Add(new CodecRoomPreset(i, label, true, false)); } - SelectedCamera = Cameras[0]; ; // call the method to select the camera and ensure the feedbacks get updated. } #region IHasCodecCameras Members From 89a7f2aa800c18a2657a4b543224412ad3a12055 Mon Sep 17 00:00:00 2001 From: Neil Dorin Date: Wed, 9 Feb 2022 14:54:19 -0700 Subject: [PATCH 32/59] fix(essentials): Add a condition to check for an empty configuration.presentation object response and return to avoid null ref ex --- .../VideoCodec/CiscoCodec/CiscoSparkCodec.cs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/essentials-framework/Essentials Devices Common/Essentials Devices Common/VideoCodec/CiscoCodec/CiscoSparkCodec.cs b/essentials-framework/Essentials Devices Common/Essentials Devices Common/VideoCodec/CiscoCodec/CiscoSparkCodec.cs index 39b3e167..d9baa070 100644 --- a/essentials-framework/Essentials Devices Common/Essentials Devices Common/VideoCodec/CiscoCodec/CiscoSparkCodec.cs +++ b/essentials-framework/Essentials Devices Common/Essentials Devices Common/VideoCodec/CiscoCodec/CiscoSparkCodec.cs @@ -856,6 +856,12 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.Cisco // Check to see if the message contains /Status/Conference/Presentation/LocalInstance and extract source value var conference = tempCodecStatus.Status.Conference; + if (conference.Presentation != null && conference.Presentation.LocalInstance == null) + { + // Handles an empty presentation object response + return; + } + if (conference.Presentation.LocalInstance.Count > 0) { if (!string.IsNullOrEmpty(conference.Presentation.LocalInstance[0].ghost)) From 70c5df90400de3675d55683734a89ed182b8ef5e Mon Sep 17 00:00:00 2001 From: Jonathan Arndt Date: Wed, 9 Feb 2022 14:09:07 -0800 Subject: [PATCH 33/59] Removed add camera to device manager --- .../VideoCodec/CiscoCodec/CiscoSparkCodec.cs | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/essentials-framework/Essentials Devices Common/Essentials Devices Common/VideoCodec/CiscoCodec/CiscoSparkCodec.cs b/essentials-framework/Essentials Devices Common/Essentials Devices Common/VideoCodec/CiscoCodec/CiscoSparkCodec.cs index d9baa070..0140142d 100644 --- a/essentials-framework/Essentials Devices Common/Essentials Devices Common/VideoCodec/CiscoCodec/CiscoSparkCodec.cs +++ b/essentials-framework/Essentials Devices Common/Essentials Devices Common/VideoCodec/CiscoCodec/CiscoSparkCodec.cs @@ -2003,8 +2003,7 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.Cisco camera.SetCapabilites(cam.Capabilities.Options.Value); } - Cameras.Add(camera); - DeviceManager.AddDevice(camera); + Cameras.Add(camera); } } @@ -2012,13 +2011,9 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.Cisco var farEndCamera = new CiscoFarEndCamera(Key + "-cameraFar", "Far End", this); Cameras.Add(farEndCamera); - SelectedCameraFeedback = new StringFeedback(() => SelectedCamera.Key); + SelectedCameraFeedback = new StringFeedback(() => SelectedCamera.Key); - SelectedCamera = Cameras[0]; ; // call the method to select the camera and ensure the feedbacks get updated. - - ControllingFarEndCameraFeedback = new BoolFeedback(() => SelectedCamera is IAmFarEndCamera); - - DeviceManager.AddDevice(farEndCamera); + ControllingFarEndCameraFeedback = new BoolFeedback(() => SelectedCamera is IAmFarEndCamera); NearEndPresets = new List(15); @@ -2031,6 +2026,8 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.Cisco FarEndRoomPresets.Add(new CodecRoomPreset(i, label, true, false)); } + SelectedCamera = Cameras[0]; ; // call the method to select the camera and ensure the feedbacks get updated. + } #region IHasCodecCameras Members From 9d80954214181b55fd84e2a21709b614f8c14d28 Mon Sep 17 00:00:00 2001 From: Neil Dorin Date: Wed, 9 Feb 2022 15:10:39 -0700 Subject: [PATCH 34/59] fix(essentials): Adds check for SendingMode property value before attempting to set fb --- .../VideoCodec/CiscoCodec/CiscoSparkCodec.cs | 9 +++++++-- .../VideoCodec/CiscoCodec/xStatus.cs | 6 ++++++ 2 files changed, 13 insertions(+), 2 deletions(-) diff --git a/essentials-framework/Essentials Devices Common/Essentials Devices Common/VideoCodec/CiscoCodec/CiscoSparkCodec.cs b/essentials-framework/Essentials Devices Common/Essentials Devices Common/VideoCodec/CiscoCodec/CiscoSparkCodec.cs index 0140142d..51141051 100644 --- a/essentials-framework/Essentials Devices Common/Essentials Devices Common/VideoCodec/CiscoCodec/CiscoSparkCodec.cs +++ b/essentials-framework/Essentials Devices Common/Essentials Devices Common/VideoCodec/CiscoCodec/CiscoSparkCodec.cs @@ -873,8 +873,13 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.Cisco else if (conference.Presentation.LocalInstance[0].Source != null) { _presentationSource = conference.Presentation.LocalInstance[0].Source.IntValue; - _presentationLocalOnly = conference.Presentation.LocalInstance.Any((i) => i.SendingMode.LocalOnly); - _presentationLocalRemote = conference.Presentation.LocalInstance.Any((i) => i.SendingMode.LocalRemote); + + // Check for any values in the SendingMode property + if (conference.Presentation.LocalInstance.Any((i) => !string.IsNullOrEmpty(i.SendingMode.Value))) + { + _presentationLocalOnly = conference.Presentation.LocalInstance.Any((i) => i.SendingMode.LocalOnly); + _presentationLocalRemote = conference.Presentation.LocalInstance.Any((i) => i.SendingMode.LocalRemote); + } } PresentationSourceFeedback.FireUpdate(); diff --git a/essentials-framework/Essentials Devices Common/Essentials Devices Common/VideoCodec/CiscoCodec/xStatus.cs b/essentials-framework/Essentials Devices Common/Essentials Devices Common/VideoCodec/CiscoCodec/xStatus.cs index e7f418eb..19208c73 100644 --- a/essentials-framework/Essentials Devices Common/Essentials Devices Common/VideoCodec/CiscoCodec/xStatus.cs +++ b/essentials-framework/Essentials Devices Common/Essentials Devices Common/VideoCodec/CiscoCodec/xStatus.cs @@ -596,6 +596,9 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.Cisco { get { + if(string.IsNullOrEmpty(_Value)) + return false; + return _Value.ToLower() == "localonly"; } } @@ -604,6 +607,9 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.Cisco { get { + if(string.IsNullOrEmpty(_Value)) + return false; + return _Value.ToLower() == "localremote"; } } From e24965eb54afd3124f7b3b4a1d58bcf5b54d6a2d Mon Sep 17 00:00:00 2001 From: Neil Dorin Date: Wed, 9 Feb 2022 15:37:55 -0700 Subject: [PATCH 35/59] fix(essentials): fixes ValueChagnedAction to run both feedback updates instead of one --- .../VideoCodec/CiscoCodec/CiscoSparkCodec.cs | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/essentials-framework/Essentials Devices Common/Essentials Devices Common/VideoCodec/CiscoCodec/CiscoSparkCodec.cs b/essentials-framework/Essentials Devices Common/Essentials Devices Common/VideoCodec/CiscoCodec/CiscoSparkCodec.cs index 51141051..53776000 100644 --- a/essentials-framework/Essentials Devices Common/Essentials Devices Common/VideoCodec/CiscoCodec/CiscoSparkCodec.cs +++ b/essentials-framework/Essentials Devices Common/Essentials Devices Common/VideoCodec/CiscoCodec/CiscoSparkCodec.cs @@ -456,8 +456,11 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.Cisco CodecStatus.Status.Video.Selfview.Mode.ValueChangedAction = SelfviewIsOnFeedback.FireUpdate; CodecStatus.Status.Video.Selfview.PIPPosition.ValueChangedAction = ComputeSelfviewPipStatus; CodecStatus.Status.Video.Layout.LayoutFamily.Local.ValueChangedAction = ComputeLocalLayout; - CodecStatus.Status.Conference.Presentation.Mode.ValueChangedAction = SharingContentIsOnFeedback.FireUpdate; - CodecStatus.Status.Conference.Presentation.Mode.ValueChangedAction = FarEndIsSharingContentFeedback.FireUpdate; + 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; From 7dd6b3a9b643d57bba2355bb01a6760a06928afa Mon Sep 17 00:00:00 2001 From: Neil Dorin Date: Wed, 9 Feb 2022 16:31:31 -0700 Subject: [PATCH 36/59] fix(essentials): fixes index off by 1 error and updates call status to check for "OnHold" as status value --- .../Bridges/JoinMaps/VideoCodecControllerJoinMap.cs | 10 +++++----- .../VideoCodec/CiscoCodec/CiscoSparkCodec.cs | 1 + .../VideoCodec/CiscoCodec/xStatus.cs | 4 ++++ .../VideoCodec/VideoCodecBase.cs | 7 +++++-- 4 files changed, 15 insertions(+), 7 deletions(-) diff --git a/essentials-framework/Essentials Core/PepperDashEssentialsBase/Bridges/JoinMaps/VideoCodecControllerJoinMap.cs b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Bridges/JoinMaps/VideoCodecControllerJoinMap.cs index 03d0c4b5..1d6657ca 100644 --- a/essentials-framework/Essentials Core/PepperDashEssentialsBase/Bridges/JoinMaps/VideoCodecControllerJoinMap.cs +++ b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Bridges/JoinMaps/VideoCodecControllerJoinMap.cs @@ -240,7 +240,7 @@ namespace PepperDash.Essentials.Core.Bridges.JoinMaps new JoinMetadata { Description = "Speed Dial", - JoinCapabilities = eJoinCapabilities.ToSIMPL, + JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); @@ -940,7 +940,7 @@ namespace PepperDash.Essentials.Core.Bridges.JoinMaps new JoinMetadata { Description = "Pulse to remove the selected recent call item specified by the SelectRecentCallItem analog join", - JoinCapabilities = eJoinCapabilities.ToSIMPL, + JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); @@ -954,7 +954,7 @@ namespace PepperDash.Essentials.Core.Bridges.JoinMaps new JoinMetadata { Description = "Pulse to dial the selected recent call item specified by the SelectRecentCallItem analog join", - JoinCapabilities = eJoinCapabilities.ToSIMPL, + JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); @@ -1037,8 +1037,8 @@ namespace PepperDash.Essentials.Core.Bridges.JoinMaps }, new JoinMetadata { - Description = "Holds Call at specified index", - JoinCapabilities = eJoinCapabilities.ToFromSIMPL, + Description = "Holds Call at specified index. FB reported on Call Status XSIG", + JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); diff --git a/essentials-framework/Essentials Devices Common/Essentials Devices Common/VideoCodec/CiscoCodec/CiscoSparkCodec.cs b/essentials-framework/Essentials Devices Common/Essentials Devices Common/VideoCodec/CiscoCodec/CiscoSparkCodec.cs index 53776000..2d4ec0d6 100644 --- a/essentials-framework/Essentials Devices Common/Essentials Devices Common/VideoCodec/CiscoCodec/CiscoSparkCodec.cs +++ b/essentials-framework/Essentials Devices Common/Essentials Devices Common/VideoCodec/CiscoCodec/CiscoSparkCodec.cs @@ -909,6 +909,7 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.Cisco if (!string.IsNullOrEmpty(call.Status.Value)) { tempActiveCall.Status = CodecCallStatus.ConvertToStatusEnum(call.Status.Value); + tempActiveCall.IsOnHold = call.Status.OnHold; if (newStatus == eCodecCallStatus.Connected) GetCallHistory(); diff --git a/essentials-framework/Essentials Devices Common/Essentials Devices Common/VideoCodec/CiscoCodec/xStatus.cs b/essentials-framework/Essentials Devices Common/Essentials Devices Common/VideoCodec/CiscoCodec/xStatus.cs index 19208c73..d6de0d4b 100644 --- a/essentials-framework/Essentials Devices Common/Essentials Devices Common/VideoCodec/CiscoCodec/xStatus.cs +++ b/essentials-framework/Essentials Devices Common/Essentials Devices Common/VideoCodec/CiscoCodec/xStatus.cs @@ -317,6 +317,8 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.Cisco string _Value; public bool BoolValue { get; private set; } + public bool OnHold { get; private set; } + public string Value { get @@ -328,6 +330,7 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.Cisco // If the incoming value is "Active" it sets the BoolValue true, otherwise sets it false _Value = value; BoolValue = value == "Active"; + OnHold = value == "OnHold"; OnValueChanged(); } } @@ -2099,6 +2102,7 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.Cisco CallType = new CallType(); Status = new Status2(); Duration = new Duration(); + PlacedOnHold = new PlacedOnHold(); } } diff --git a/essentials-framework/Essentials Devices Common/Essentials Devices Common/VideoCodec/VideoCodecBase.cs b/essentials-framework/Essentials Devices Common/Essentials Devices Common/VideoCodec/VideoCodecBase.cs index c32643ba..670111e9 100644 --- a/essentials-framework/Essentials Devices Common/Essentials Devices Common/VideoCodec/VideoCodecBase.cs +++ b/essentials-framework/Essentials Devices Common/Essentials Devices Common/VideoCodec/VideoCodecBase.cs @@ -1054,7 +1054,7 @@ ScreenIndexIsPinnedTo: {8} (a{17}) { if (u < 1 || u > entryToDial.ContactMethods.Count) return; - trilist.SetSigFalseAction(joinMap.DirectoryDialSelectedContactMethod.JoinNumber, () => Dial(entryToDial.ContactMethods[u].Number)); + trilist.SetSigFalseAction(joinMap.DirectoryDialSelectedContactMethod.JoinNumber, () => Dial(entryToDial.ContactMethods[u - 1].Number)); }); // Sets DirectoryDialSelectedLine join action to dial first contact method @@ -1216,7 +1216,7 @@ ScreenIndexIsPinnedTo: {8} (a{17}) var holdCodec = this as IHasCallHold; if (holdCodec != null) { - for (int i = 0; i < joinMap.JoinCallStart.JoinSpan; i++) + for (int i = 0; i < joinMap.HoldCallsStart.JoinSpan; i++) { trilist.SetSigFalseAction((uint)(joinMap.HoldCallsStart.JoinNumber + i), () => { @@ -1245,6 +1245,9 @@ ScreenIndexIsPinnedTo: {8} (a{17}) }); } } + + + } private string UpdateCallStatusXSig() From 102ae3ad4f44da8fcb3dbb5bd143ca0488a625a6 Mon Sep 17 00:00:00 2001 From: Neil Dorin Date: Wed, 9 Feb 2022 16:41:37 -0700 Subject: [PATCH 37/59] fix(essentials): second attempt to get on hold fb working --- .../VideoCodec/CiscoCodec/CiscoSparkCodec.cs | 2 +- .../VideoCodec/CiscoCodec/xStatus.cs | 28 ++++++++++++++++--- 2 files changed, 25 insertions(+), 5 deletions(-) diff --git a/essentials-framework/Essentials Devices Common/Essentials Devices Common/VideoCodec/CiscoCodec/CiscoSparkCodec.cs b/essentials-framework/Essentials Devices Common/Essentials Devices Common/VideoCodec/CiscoCodec/CiscoSparkCodec.cs index 2d4ec0d6..bf067570 100644 --- a/essentials-framework/Essentials Devices Common/Essentials Devices Common/VideoCodec/CiscoCodec/CiscoSparkCodec.cs +++ b/essentials-framework/Essentials Devices Common/Essentials Devices Common/VideoCodec/CiscoCodec/CiscoSparkCodec.cs @@ -909,7 +909,7 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.Cisco if (!string.IsNullOrEmpty(call.Status.Value)) { tempActiveCall.Status = CodecCallStatus.ConvertToStatusEnum(call.Status.Value); - tempActiveCall.IsOnHold = call.Status.OnHold; + tempActiveCall.IsOnHold = tempActiveCall.Status == eCodecCallStatus.OnHold; if (newStatus == eCodecCallStatus.Connected) GetCallHistory(); diff --git a/essentials-framework/Essentials Devices Common/Essentials Devices Common/VideoCodec/CiscoCodec/xStatus.cs b/essentials-framework/Essentials Devices Common/Essentials Devices Common/VideoCodec/CiscoCodec/xStatus.cs index d6de0d4b..9b45d3ce 100644 --- a/essentials-framework/Essentials Devices Common/Essentials Devices Common/VideoCodec/CiscoCodec/xStatus.cs +++ b/essentials-framework/Essentials Devices Common/Essentials Devices Common/VideoCodec/CiscoCodec/xStatus.cs @@ -312,12 +312,33 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.Cisco } } + public class CallStatus : ValueProperty + { + string _Value; + public bool BoolValue { get; private set; } + + + public string Value + { + get + { + return _Value; + } + set + { + // If the incoming value is "Active" it sets the BoolValue true, otherwise sets it false + _Value = value; + BoolValue = value == "Connected"; + OnValueChanged(); + } + } + } + public class Status2 : ValueProperty { string _Value; public bool BoolValue { get; private set; } - public bool OnHold { get; private set; } public string Value { @@ -330,7 +351,6 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.Cisco // If the incoming value is "Active" it sets the BoolValue true, otherwise sets it false _Value = value; BoolValue = value == "Active"; - OnHold = value == "OnHold"; OnValueChanged(); } } @@ -2094,13 +2114,13 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.Cisco public Protocol Protocol { get; set; } public ReceiveCallRate ReceiveCallRate { get; set; } public RemoteNumber RemoteNumber { get; set; } - public Status2 Status { get; set; } + public CallStatus Status { get; set; } public TransmitCallRate TransmitCallRate { get; set; } public Call() { CallType = new CallType(); - Status = new Status2(); + Status = new CallStatus(); Duration = new Duration(); PlacedOnHold = new PlacedOnHold(); } From db67f97a1f5ae8b618c387df6eba2b7d737ffa2a Mon Sep 17 00:00:00 2001 From: Neil Dorin Date: Wed, 9 Feb 2022 16:46:19 -0700 Subject: [PATCH 38/59] fix(essentials): add local scope variable for indexer in hold/resume call loop --- .../VideoCodec/VideoCodecBase.cs | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/essentials-framework/Essentials Devices Common/Essentials Devices Common/VideoCodec/VideoCodecBase.cs b/essentials-framework/Essentials Devices Common/Essentials Devices Common/VideoCodec/VideoCodecBase.cs index 670111e9..37cbebd4 100644 --- a/essentials-framework/Essentials Devices Common/Essentials Devices Common/VideoCodec/VideoCodecBase.cs +++ b/essentials-framework/Essentials Devices Common/Essentials Devices Common/VideoCodec/VideoCodecBase.cs @@ -1218,9 +1218,13 @@ ScreenIndexIsPinnedTo: {8} (a{17}) { for (int i = 0; i < joinMap.HoldCallsStart.JoinSpan; i++) { - trilist.SetSigFalseAction((uint)(joinMap.HoldCallsStart.JoinNumber + i), () => + var index = i; + + trilist.SetSigFalseAction((uint)(joinMap.HoldCallsStart.JoinNumber + index), () => { - var call = ActiveCalls[i]; + if (index < 0 || index >= ActiveCalls.Count) return; + + var call = ActiveCalls[index]; if (call != null) { holdCodec.HoldCall(call); @@ -1231,9 +1235,11 @@ ScreenIndexIsPinnedTo: {8} (a{17}) } }); - trilist.SetSigFalseAction((uint)(joinMap.ResumeCallsStart.JoinNumber + i), () => + trilist.SetSigFalseAction((uint)(joinMap.ResumeCallsStart.JoinNumber + index), () => { - var call = ActiveCalls[i]; + if (index < 0 || index >= ActiveCalls.Count) return; + + var call = ActiveCalls[index]; if (call != null) { holdCodec.ResumeCall(call); From 7a2e99f145f388ea739e2d1b83d17ddf888a9080 Mon Sep 17 00:00:00 2001 From: Neil Dorin Date: Wed, 9 Feb 2022 16:50:06 -0700 Subject: [PATCH 39/59] feat(essentials): Adds HoldAllCalls join and action --- .../JoinMaps/VideoCodecControllerJoinMap.cs | 14 ++++++++++++++ .../VideoCodec/VideoCodecBase.cs | 8 ++++++++ 2 files changed, 22 insertions(+) diff --git a/essentials-framework/Essentials Core/PepperDashEssentialsBase/Bridges/JoinMaps/VideoCodecControllerJoinMap.cs b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Bridges/JoinMaps/VideoCodecControllerJoinMap.cs index 1d6657ca..8f7e8188 100644 --- a/essentials-framework/Essentials Core/PepperDashEssentialsBase/Bridges/JoinMaps/VideoCodecControllerJoinMap.cs +++ b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Bridges/JoinMaps/VideoCodecControllerJoinMap.cs @@ -1028,6 +1028,20 @@ namespace PepperDash.Essentials.Core.Bridges.JoinMaps JoinType = eJoinType.Digital }); + [JoinName("HoldAllCalls")] + public JoinDataComplete HoldAllCalls = new JoinDataComplete( + new JoinData + { + JoinNumber = 220, + JoinSpan = 1 + }, + new JoinMetadata + { + Description = "Holds all calls", + JoinCapabilities = eJoinCapabilities.FromSIMPL, + JoinType = eJoinType.Digital + }); + [JoinName("HoldCallsStart")] public JoinDataComplete HoldCallsStart = new JoinDataComplete( new JoinData diff --git a/essentials-framework/Essentials Devices Common/Essentials Devices Common/VideoCodec/VideoCodecBase.cs b/essentials-framework/Essentials Devices Common/Essentials Devices Common/VideoCodec/VideoCodecBase.cs index 37cbebd4..821a46d5 100644 --- a/essentials-framework/Essentials Devices Common/Essentials Devices Common/VideoCodec/VideoCodecBase.cs +++ b/essentials-framework/Essentials Devices Common/Essentials Devices Common/VideoCodec/VideoCodecBase.cs @@ -1216,6 +1216,14 @@ ScreenIndexIsPinnedTo: {8} (a{17}) var holdCodec = this as IHasCallHold; if (holdCodec != null) { + trilist.SetSigFalseAction(joinMap.HoldAllCalls.JoinNumber, () => + { + foreach (var call in ActiveCalls) + { + holdCodec.HoldCall(call); + } + }); + for (int i = 0; i < joinMap.HoldCallsStart.JoinSpan; i++) { var index = i; From bfdc882eb61cecbb7ff7f7df9fe822ff2e5ec3f0 Mon Sep 17 00:00:00 2001 From: Neil Dorin Date: Wed, 9 Feb 2022 17:07:18 -0700 Subject: [PATCH 40/59] fix(essentials): Adds logic to recover from malformed json response on initial communication. Adds better formatting for active calls list print to console --- .../VideoCodec/CiscoCodec/CiscoSparkCodec.cs | 10 ++++++++++ .../VideoCodec/VideoCodecBase.cs | 4 +++- 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/essentials-framework/Essentials Devices Common/Essentials Devices Common/VideoCodec/CiscoCodec/CiscoSparkCodec.cs b/essentials-framework/Essentials Devices Common/Essentials Devices Common/VideoCodec/CiscoCodec/CiscoSparkCodec.cs index bf067570..567d49dc 100644 --- a/essentials-framework/Essentials Devices Common/Essentials Devices Common/VideoCodec/CiscoCodec/CiscoSparkCodec.cs +++ b/essentials-framework/Essentials Devices Common/Essentials Devices Common/VideoCodec/CiscoCodec/CiscoSparkCodec.cs @@ -1182,6 +1182,16 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.Cisco } catch (Exception ex) { + if (ex is Newtonsoft.Json.JsonReaderException) + { + Debug.Console(1, this, "Received malformed response from codec. Unable to serialize. Disconnecting and attmpting to recconnect"); + + Communication.Disconnect(); + + Initialize(); + } + + Debug.Console(1, this, "Error Deserializing feedback from codec: {0}", ex); } } diff --git a/essentials-framework/Essentials Devices Common/Essentials Devices Common/VideoCodec/VideoCodecBase.cs b/essentials-framework/Essentials Devices Common/Essentials Devices Common/VideoCodec/VideoCodecBase.cs index 821a46d5..0d1df28f 100644 --- a/essentials-framework/Essentials Devices Common/Essentials Devices Common/VideoCodec/VideoCodecBase.cs +++ b/essentials-framework/Essentials Devices Common/Essentials Devices Common/VideoCodec/VideoCodecBase.cs @@ -257,10 +257,12 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec /// public virtual void ListCalls() { + Debug.Console(1, this, "Active Calls:"); + var sb = new StringBuilder(); foreach (var c in ActiveCalls) { - sb.AppendFormat("{0} {1} -- {2} {3}\n", c.Id, c.Number, c.Name, c.Status); + sb.AppendFormat("id: {0} number: {1} -- name: {2} status: {3} onHold: {4}\r\n", c.Id, c.Number, c.Name, c.Status, c.IsOnHold); } Debug.Console(1, this, "\n{0}\n", sb.ToString()); } From b0288951eb24954e4043bac781926cb08968a8cd Mon Sep 17 00:00:00 2001 From: Neil Dorin Date: Wed, 9 Feb 2022 17:15:58 -0700 Subject: [PATCH 41/59] fix(essentials): removes logic to disconnect and reinitialize on malformed json response --- .../VideoCodec/CiscoCodec/CiscoSparkCodec.cs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/essentials-framework/Essentials Devices Common/Essentials Devices Common/VideoCodec/CiscoCodec/CiscoSparkCodec.cs b/essentials-framework/Essentials Devices Common/Essentials Devices Common/VideoCodec/CiscoCodec/CiscoSparkCodec.cs index 567d49dc..fce15e76 100644 --- a/essentials-framework/Essentials Devices Common/Essentials Devices Common/VideoCodec/CiscoCodec/CiscoSparkCodec.cs +++ b/essentials-framework/Essentials Devices Common/Essentials Devices Common/VideoCodec/CiscoCodec/CiscoSparkCodec.cs @@ -1182,17 +1182,17 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.Cisco } catch (Exception ex) { + Debug.Console(1, this, "Error Deserializing feedback from codec: {0}", ex); + if (ex is Newtonsoft.Json.JsonReaderException) { - Debug.Console(1, this, "Received malformed response from codec. Unable to serialize. Disconnecting and attmpting to recconnect"); + Debug.Console(1, this, "Received malformed response from codec. Unable to deserialize. Disconnecting and attmpting to recconnect"); - Communication.Disconnect(); + //Communication.Disconnect(); - Initialize(); + //Initialize(); } - - Debug.Console(1, this, "Error Deserializing feedback from codec: {0}", ex); } } From e4a4564bbc49f76b605c797f9ea70db21c0e126e Mon Sep 17 00:00:00 2001 From: Neil Dorin Date: Wed, 9 Feb 2022 17:21:19 -0700 Subject: [PATCH 42/59] fix(essentials): Attempts to set OnHold an alternative way --- .../VideoCodec/CiscoCodec/CiscoSparkCodec.cs | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/essentials-framework/Essentials Devices Common/Essentials Devices Common/VideoCodec/CiscoCodec/CiscoSparkCodec.cs b/essentials-framework/Essentials Devices Common/Essentials Devices Common/VideoCodec/CiscoCodec/CiscoSparkCodec.cs index fce15e76..9d6ddc71 100644 --- a/essentials-framework/Essentials Devices Common/Essentials Devices Common/VideoCodec/CiscoCodec/CiscoSparkCodec.cs +++ b/essentials-framework/Essentials Devices Common/Essentials Devices Common/VideoCodec/CiscoCodec/CiscoSparkCodec.cs @@ -909,7 +909,10 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.Cisco if (!string.IsNullOrEmpty(call.Status.Value)) { tempActiveCall.Status = CodecCallStatus.ConvertToStatusEnum(call.Status.Value); - tempActiveCall.IsOnHold = tempActiveCall.Status == eCodecCallStatus.OnHold; + if (tempActiveCall.Status == eCodecCallStatus.OnHold) + { + tempActiveCall.IsOnHold = true; + } if (newStatus == eCodecCallStatus.Connected) GetCallHistory(); @@ -1186,7 +1189,7 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.Cisco if (ex is Newtonsoft.Json.JsonReaderException) { - Debug.Console(1, this, "Received malformed response from codec. Unable to deserialize. Disconnecting and attmpting to recconnect"); + Debug.Console(1, this, "Received malformed response from codec."); //Communication.Disconnect(); From 0bb4b6edd4938e2f399aef5183c102baad3b90fe Mon Sep 17 00:00:00 2001 From: Neil Dorin Date: Wed, 9 Feb 2022 17:30:26 -0700 Subject: [PATCH 43/59] fix(essentials): doh! fixes issue where IsOnHold would get set to false if response contains no PlacedOhHold object --- .../Essentials Devices Common/VideoCodec/CiscoCodec/xStatus.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/essentials-framework/Essentials Devices Common/Essentials Devices Common/VideoCodec/CiscoCodec/xStatus.cs b/essentials-framework/Essentials Devices Common/Essentials Devices Common/VideoCodec/CiscoCodec/xStatus.cs index 9b45d3ce..daaf8709 100644 --- a/essentials-framework/Essentials Devices Common/Essentials Devices Common/VideoCodec/CiscoCodec/xStatus.cs +++ b/essentials-framework/Essentials Devices Common/Essentials Devices Common/VideoCodec/CiscoCodec/xStatus.cs @@ -2122,7 +2122,6 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.Cisco CallType = new CallType(); Status = new CallStatus(); Duration = new Duration(); - PlacedOnHold = new PlacedOnHold(); } } From cb3c80ff8ffd6b829c239f41f22ee1eb4d386901 Mon Sep 17 00:00:00 2001 From: Neil Dorin Date: Wed, 9 Feb 2022 17:44:53 -0700 Subject: [PATCH 44/59] fix(essentials): fixes to on hold feedback and call status xsig --- .../VideoCodec/CiscoCodec/CiscoSparkCodec.cs | 7 ++----- .../VideoCodec/VideoCodecBase.cs | 11 ++++++----- 2 files changed, 8 insertions(+), 10 deletions(-) diff --git a/essentials-framework/Essentials Devices Common/Essentials Devices Common/VideoCodec/CiscoCodec/CiscoSparkCodec.cs b/essentials-framework/Essentials Devices Common/Essentials Devices Common/VideoCodec/CiscoCodec/CiscoSparkCodec.cs index 9d6ddc71..32aaaa21 100644 --- a/essentials-framework/Essentials Devices Common/Essentials Devices Common/VideoCodec/CiscoCodec/CiscoSparkCodec.cs +++ b/essentials-framework/Essentials Devices Common/Essentials Devices Common/VideoCodec/CiscoCodec/CiscoSparkCodec.cs @@ -909,11 +909,8 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.Cisco if (!string.IsNullOrEmpty(call.Status.Value)) { tempActiveCall.Status = CodecCallStatus.ConvertToStatusEnum(call.Status.Value); - if (tempActiveCall.Status == eCodecCallStatus.OnHold) - { - tempActiveCall.IsOnHold = true; - } - + tempActiveCall.IsOnHold = tempActiveCall.Status == eCodecCallStatus.OnHold; + if (newStatus == eCodecCallStatus.Connected) GetCallHistory(); diff --git a/essentials-framework/Essentials Devices Common/Essentials Devices Common/VideoCodec/VideoCodecBase.cs b/essentials-framework/Essentials Devices Common/Essentials Devices Common/VideoCodec/VideoCodecBase.cs index 0d1df28f..07c62144 100644 --- a/essentials-framework/Essentials Devices Common/Essentials Devices Common/VideoCodec/VideoCodecBase.cs +++ b/essentials-framework/Essentials Devices Common/Essentials Devices Common/VideoCodec/VideoCodecBase.cs @@ -1270,7 +1270,8 @@ ScreenIndexIsPinnedTo: {8} (a{17}) { const int maxCalls = 8; const int maxStrings = 6; - const int offset = 6; + const int maxDigitals = 2; + const int offset = maxStrings + maxDigitals; var stringIndex = 0; var digitalIndex = maxStrings * maxCalls; var arrayIndex = 0; @@ -1282,8 +1283,8 @@ ScreenIndexIsPinnedTo: {8} (a{17}) if (arrayIndex >= maxCalls * offset) break; //digitals - tokenArray[arrayIndex] = new XSigDigitalToken(digitalIndex + 1, call.IsActiveCall); - tokenArray[arrayIndex + 1] = new XSigDigitalToken(digitalIndex + 2, call.IsOnHold); + tokenArray[digitalIndex] = new XSigDigitalToken(digitalIndex + 1, call.IsActiveCall); + tokenArray[digitalIndex + 1] = new XSigDigitalToken(digitalIndex + 2, call.IsOnHold); //serials tokenArray[arrayIndex + 1] = new XSigSerialToken(stringIndex + 1, call.Name ?? String.Empty); @@ -1305,8 +1306,8 @@ ScreenIndexIsPinnedTo: {8} (a{17}) while (digitalIndex < maxCalls) { //digitals - tokenArray[arrayIndex] = new XSigDigitalToken(digitalIndex + 1, false); - tokenArray[arrayIndex + 1] = new XSigDigitalToken(digitalIndex + 2, false); + tokenArray[digitalIndex] = new XSigDigitalToken(digitalIndex + 1, false); + tokenArray[digitalIndex + 1] = new XSigDigitalToken(digitalIndex + 2, false); //serials From 79a3a8ed7ef6efb81a8c490db8e4ad23185e6984 Mon Sep 17 00:00:00 2001 From: Neil Dorin Date: Thu, 10 Feb 2022 15:49:53 -0700 Subject: [PATCH 45/59] fix(essentials): #901 Overhaul's feedback processing for efficiency Updates to address changes to ZRAAPI v1.1 and ZoomRooms 5.9.4 --- .../VideoCodec/ZoomRoom/ZoomRoom.cs | 174 +++++++++++++++--- packages.config | 2 +- 2 files changed, 152 insertions(+), 24 deletions(-) diff --git a/essentials-framework/Essentials Devices Common/Essentials Devices Common/VideoCodec/ZoomRoom/ZoomRoom.cs b/essentials-framework/Essentials Devices Common/Essentials Devices Common/VideoCodec/ZoomRoom/ZoomRoom.cs index ef3b59cb..adc2e79d 100644 --- a/essentials-framework/Essentials Devices Common/Essentials Devices Common/VideoCodec/ZoomRoom/ZoomRoom.cs +++ b/essentials-framework/Essentials Devices Common/Essentials Devices Common/VideoCodec/ZoomRoom/ZoomRoom.cs @@ -32,8 +32,20 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.ZoomRoom private const long MeetingRefreshTimer = 60000; public uint DefaultMeetingDurationMin { get; private set; } - private const string Delimiter = "\x0D\x0A"; + /// + /// CR LF + /// + private const string EchoDelimiter = "\x0D\x0A\x0D\x0A"; + private const string SendDelimiter = "\x0D"; + + /// + /// CR LF } CR LF + /// + private const string JsonDelimiter = "\x0D\x0A\x7D\x0D\x0A"; + + private string[] Delimiters = new string[] { EchoDelimiter, JsonDelimiter, "OK\x0D\x0A", "end\x0D\x0A" }; + //"echo off\x0D\x0A\x0A\x0D\x0A" private readonly GenericQueue _receiveQueue; //private readonly CrestronQueue _receiveQueue; @@ -71,7 +83,7 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.ZoomRoom else { CommunicationMonitor = new GenericCommunicationMonitor(this, Communication, 30000, 120000, 300000, - "zStatus SystemUnit\r"); + "zStatus SystemUnit" + SendDelimiter); } DeviceManager.AddDevice(CommunicationMonitor); @@ -86,9 +98,11 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.ZoomRoom _syncState.InitialSyncCompleted += SyncState_InitialSyncCompleted; + _syncState.FirstJsonResponseReceived += (o, a) => SetUpSyncQueries(); + PhonebookSyncState = new CodecPhonebookSyncState(Key + "--PhonebookSync"); - PortGather = new CommunicationGather(Communication, "\x0A") {IncludeDelimiter = true}; + PortGather = new CommunicationGather(Communication, Delimiters) {IncludeDelimiter = true}; PortGather.LineReceived += Port_LineReceived; CodecOsdIn = new RoutingInputPort(RoutingPortNames.CodecOsd, @@ -904,7 +918,7 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.ZoomRoom Debug.Console(1, this, "Sending: '{0}'", command); } - Communication.SendText(command + Delimiter); + Communication.SendText(command + SendDelimiter); } /// @@ -914,13 +928,28 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.ZoomRoom /// private void Port_LineReceived(object dev, GenericCommMethodReceiveTextArgs args) { - //if (CommDebuggingIsOn) - // Debug.Console(1, this, "Gathered: '{0}'", args.Text); + //Debug.Console(0, this, "Port_LineReceived"); - _receiveQueue.Enqueue(new ProcessStringMessage(args.Text, ProcessMessage)); + if (args.Delimiter != JsonDelimiter) + { +// Debug.Console(0, this, +//@"Non JSON response: +//Delimiter: {0} +//{1}", ComTextHelper.GetDebugText(args.Delimiter), args.Text); + ProcessNonJsonResponse(args.Text); + return; + } + else + { +// Debug.Console(0, this, +//@"JSON response: +//Delimiter: {0} +//{1}", ComTextHelper.GetDebugText(args.Delimiter), args.Text); + _receiveQueue.Enqueue(new ProcessStringMessage(args.Text, DeserializeResponse)); + //_receiveQueue.Enqueue(new ProcessStringMessage(args.Text, ProcessMessage)); + } } - /// /// Queues the initial queries to be sent upon connection /// @@ -979,6 +1008,84 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.ZoomRoom _syncState.StartSync(); } + private void SetupSession() + { + // disable echo of commands + SendText("echo off"); + // switch to json format + // set feedback exclusions + // Currently the feedback exclusions don't work when using the API in JSON response mode + // But leave these here in case the API gets updated in the future + // These may work as of 5.9.4 + if (_props.DisablePhonebookAutoDownload) + { + SendText("zFeedback Register Op: ex Path: /Event/Phonebook/AddedContact"); + } + SendText("zFeedback Register Op: ex Path: /Event/InfoResult/Info/callin_country_list"); + SendText("zFeedback Register Op: ex Path: /Event/InfoResult/Info/callout_country_list"); + SendText("zFeedback Register Op: ex Path: /Event/InfoResult/Info/toll_free_callinLlist"); + + SendText("zStatus SystemUnit"); + } + + /// + /// Processes non-JSON responses as their are received + /// + /// + private void ProcessNonJsonResponse(string response) + { + if (response.Contains("client_loop: send disconnect: Broken pipe")) + { + Debug.Console(1, this, Debug.ErrorLogLevel.Error, + "Zoom Room Controller or App connected. Essentials will NOT control the Zoom Room until it is disconnected."); + + return; + } + + if (!_syncState.InitialSyncComplete) + { + if(response.ToLower().Contains("*r login successful")) + { + _syncState.LoginResponseReceived(); + + SendText("format json"); + + SetupSession(); + } + + //switch (response.Trim().ToLower()) // remove the whitespace + //{ + // case "*r login successful": + // { + // _syncState.LoginMessageReceived(); + + // //// Fire up a thread to send the intial commands. + // //CrestronInvoke.BeginInvoke(o => + // //{ + // // disable echo of commands + // SendText("echo off"); + // // switch to json format + // SendText("format json"); + // // set feedback exclusions + // // Currently the feedback exclusions don't work when using the API in JSON response mode + // // But leave these here in case the API gets updated in the future + // // These may work as of 5.9.4 + // if (_props.DisablePhonebookAutoDownload) + // { + // SendText("zFeedback Register Op: ex Path: /Event/Phonebook/AddedContact"); + // } + // SendText("zFeedback Register Op: ex Path: /Event/InfoResult/Info/callin_country_list"); + // SendText("zFeedback Register Op: ex Path: /Event/InfoResult/Info/callout_country_list"); + // SendText("zFeedback Register Op: ex Path: /Event/InfoResult/Info/toll_free_callinLlist"); + + // //}); + + // break; + // } + //} + } + } + /// /// Processes messages as they are dequeued /// @@ -1006,7 +1113,7 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.ZoomRoom //Debug.Console(2, this, "JSON Curly Brace Count: {0}", _jsonCurlyBraceCounter); - if (!_jsonFeedbackMessageIsIncoming && message.Trim('\x20') == "{" + Delimiter) + if (!_jsonFeedbackMessageIsIncoming && message.Trim('\x20') == "{" + EchoDelimiter) // Check for the beginning of a new JSON message { _jsonFeedbackMessageIsIncoming = true; @@ -1023,7 +1130,7 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.ZoomRoom return; } - if (_jsonFeedbackMessageIsIncoming && message.Trim('\x20') == "}" + Delimiter) + if (_jsonFeedbackMessageIsIncoming && message.Trim('\x20') == "}" + EchoDelimiter) // Check for the end of a JSON message { _jsonMessage.Append(message); @@ -1068,7 +1175,7 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.ZoomRoom { case "*r login successful": { - _syncState.LoginMessageReceived(); + _syncState.LoginResponseReceived(); // Fire up a thread to send the intial commands. @@ -1121,6 +1228,11 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.ZoomRoom var message = JObject.Parse(trimmedResponse); + if (!_syncState.FirstJsonResponseWasReceived) + { + _syncState.ReceivedFirstJsonResponse(); + } + var eType = (eZoomRoomResponseType) Enum.Parse(typeof (eZoomRoomResponseType), message["type"].Value(), true); @@ -1642,19 +1754,17 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.ZoomRoom { case "login": { - _syncState.LoginMessageReceived(); + _syncState.LoginResponseReceived(); - if (!_syncState.InitialQueryMessagesWereSent) - { - SetUpSyncQueries(); - } + SetupSession(); JsonConvert.PopulateObject(responseObj.ToString(), Status.Login); break; } case "systemunit": - { + { + JsonConvert.PopulateObject(responseObj.ToString(), Status.SystemUnit); break; @@ -3437,7 +3547,9 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.ZoomRoom } } - public bool LoginMessageWasReceived { get; private set; } + public bool LoginResponseWasReceived { get; private set; } + + public bool FirstJsonResponseWasReceived { get; private set; } public bool InitialQueryMessagesWereSent { get; private set; } @@ -3453,6 +3565,8 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.ZoomRoom public event EventHandler InitialSyncCompleted; + public event EventHandler FirstJsonResponseReceived; + public void StartSync() { DequeueQueries(); @@ -3475,13 +3589,26 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.ZoomRoom _syncQueries.Enqueue(query); } - public void LoginMessageReceived() + public void LoginResponseReceived() { - LoginMessageWasReceived = true; - Debug.Console(1, this, "Login Message Received."); + LoginResponseWasReceived = true; + Debug.Console(1, this, "Login Rsponse Received."); CheckSyncStatus(); } + public void ReceivedFirstJsonResponse() + { + FirstJsonResponseWasReceived = true; + Debug.Console(1, this, "First JSON Response Received."); + + var handler = FirstJsonResponseReceived; + if (handler != null) + { + handler(this, null); + } + CheckSyncStatus(); + } + public void InitialQueryMessagesSent() { InitialQueryMessagesWereSent = true; @@ -3506,7 +3633,8 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.ZoomRoom public void CodecDisconnected() { _syncQueries.Clear(); - LoginMessageWasReceived = false; + LoginResponseWasReceived = false; + FirstJsonResponseWasReceived = false; InitialQueryMessagesWereSent = false; LastQueryResponseWasReceived = false; CamerasHaveBeenSetUp = false; @@ -3515,7 +3643,7 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.ZoomRoom private void CheckSyncStatus() { - if (LoginMessageWasReceived && InitialQueryMessagesWereSent && LastQueryResponseWasReceived && + if (LoginResponseWasReceived && FirstJsonResponseWasReceived && InitialQueryMessagesWereSent && LastQueryResponseWasReceived && CamerasHaveBeenSetUp) { InitialSyncComplete = true; diff --git a/packages.config b/packages.config index 10124bbd..41f858a6 100644 --- a/packages.config +++ b/packages.config @@ -1,3 +1,3 @@ - + \ No newline at end of file From 348981d8cbc294d0cf426c7ea6db7b546cbb6572 Mon Sep 17 00:00:00 2001 From: Neil Dorin Date: Thu, 10 Feb 2022 17:33:06 -0700 Subject: [PATCH 46/59] fix(essntials): Fixes exception in OnLayoutChanged and fixes debug JSON formatting for Zoom responses --- .../Essentials Devices Common/VideoCodec/ZoomRoom/ZoomRoom.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/essentials-framework/Essentials Devices Common/Essentials Devices Common/VideoCodec/ZoomRoom/ZoomRoom.cs b/essentials-framework/Essentials Devices Common/Essentials Devices Common/VideoCodec/ZoomRoom/ZoomRoom.cs index 01c53ab7..f3891dde 100644 --- a/essentials-framework/Essentials Devices Common/Essentials Devices Common/VideoCodec/ZoomRoom/ZoomRoom.cs +++ b/essentials-framework/Essentials Devices Common/Essentials Devices Common/VideoCodec/ZoomRoom/ZoomRoom.cs @@ -1241,7 +1241,7 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.ZoomRoom var responseObj = message[topKey]; - Debug.Console(1, "{0} Response Received. topKey: '{1}'\n{2}", eType, topKey, responseObj.ToString()); + Debug.Console(1, this, "{0} Response Received. topKey: '{1}'\n{2}", eType, topKey, responseObj.ToString().Replace("\n", CrestronEnvironment.NewLine)); switch (eType) { @@ -3170,7 +3170,7 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.ZoomRoom handler(this, new LayoutInfoChangedEventArgs() { AvailableLayouts = AvailableLayouts, - CurrentSelectedLayout = (zConfiguration.eLayoutStyle)Enum.Parse(typeof(zConfiguration.eLayoutStyle),LocalLayoutFeedback.StringValue, true), + CurrentSelectedLayout = (zConfiguration.eLayoutStyle)Enum.Parse(typeof(zConfiguration.eLayoutStyle),string.IsNullOrEmpty(LocalLayoutFeedback.StringValue) ? "None" : LocalLayoutFeedback.StringValue , true), LayoutViewIsOnFirstPage = LayoutViewIsOnFirstPageFeedback.BoolValue, LayoutViewIsOnLastPage = LayoutViewIsOnLastPageFeedback.BoolValue, CanSwapContentWithThumbnail = CanSwapContentWithThumbnailFeedback.BoolValue, From 0e5cecbfc3e885c6797deb6a2aafbca7f8f97e2c Mon Sep 17 00:00:00 2001 From: Neil Dorin Date: Fri, 11 Feb 2022 14:16:40 -0700 Subject: [PATCH 47/59] fix(essentials): #901 Refines initial synchronization sequence Makes sure that the AddedContact feedback subscription is excluded right away, but later included after the phonebook is retrieved. This should ensure we get the initial phonebook and all subsequent additions at runtime while also minimizing initial data volume. --- .../VideoCodec/ZoomRoom/ZoomRoom.cs | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) diff --git a/essentials-framework/Essentials Devices Common/Essentials Devices Common/VideoCodec/ZoomRoom/ZoomRoom.cs b/essentials-framework/Essentials Devices Common/Essentials Devices Common/VideoCodec/ZoomRoom/ZoomRoom.cs index f3891dde..1db04f0c 100644 --- a/essentials-framework/Essentials Devices Common/Essentials Devices Common/VideoCodec/ZoomRoom/ZoomRoom.cs +++ b/essentials-framework/Essentials Devices Common/Essentials Devices Common/VideoCodec/ZoomRoom/ZoomRoom.cs @@ -102,6 +102,8 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.ZoomRoom PhonebookSyncState = new CodecPhonebookSyncState(Key + "--PhonebookSync"); + PhonebookSyncState.InitialSyncCompleted += (o, a) => ResubscribeForAddedContacts(); + PortGather = new CommunicationGather(Communication, Delimiters) {IncludeDelimiter = true}; PortGather.LineReceived += Port_LineReceived; @@ -1017,10 +1019,11 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.ZoomRoom // Currently the feedback exclusions don't work when using the API in JSON response mode // But leave these here in case the API gets updated in the future // These may work as of 5.9.4 - if (_props.DisablePhonebookAutoDownload) - { - SendText("zFeedback Register Op: ex Path: /Event/Phonebook/AddedContact"); - } + + // In 5.9.4 we're getting sent an AddedContact message for every contact in the phonebook on connect, which is redunant and way too much data + // We want to exclude these messages right away until after we've retrieved the entire phonebook and then we can re-enable them + SendText("zFeedback Register Op: ex Path: /Event/Phonebook/AddedContact"); + SendText("zFeedback Register Op: ex Path: /Event/InfoResult/Info/callin_country_list"); SendText("zFeedback Register Op: ex Path: /Event/InfoResult/Info/callout_country_list"); SendText("zFeedback Register Op: ex Path: /Event/InfoResult/Info/toll_free_callinLlist"); @@ -1028,6 +1031,14 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.ZoomRoom SendText("zStatus SystemUnit"); } + /// + /// Removes the feedback exclusion for added contacts + /// + private void ResubscribeForAddedContacts() + { + SendText("zFeedback Register Op: in Path: /Event/Phonebook/AddedContact"); + } + /// /// Processes non-JSON responses as their are received /// From b0e3fddec78aefee57713b5a8f46f1efa5767c9e Mon Sep 17 00:00:00 2001 From: Neil Dorin Date: Fri, 11 Feb 2022 15:50:09 -0700 Subject: [PATCH 48/59] fix(essentials): fixes issue with local var scope when assigning actions for ending individual calls Fixes Incoming call name/number feedback in bridge --- .../VideoCodec/VideoCodecBase.cs | 84 +++++++++++-------- 1 file changed, 47 insertions(+), 37 deletions(-) diff --git a/essentials-framework/Essentials Devices Common/Essentials Devices Common/VideoCodec/VideoCodecBase.cs b/essentials-framework/Essentials Devices Common/Essentials Devices Common/VideoCodec/VideoCodecBase.cs index 07c62144..a96de4f9 100644 --- a/essentials-framework/Essentials Devices Common/Essentials Devices Common/VideoCodec/VideoCodecBase.cs +++ b/essentials-framework/Essentials Devices Common/Essentials Devices Common/VideoCodec/VideoCodecBase.cs @@ -680,37 +680,37 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec { if (meetingIndex >= maxParticipants * offset) break; - Debug.Console(2, this, -@"Updating Participant on xsig: -Name: {0} (s{9}) -AudioMute: {1} (d{10}) -VideoMute: {2} (d{11}) -CanMuteVideo: {3} (d{12}) -CanUMuteVideo: {4} (d{13}) -IsHost: {5} (d{14}) -HandIsRaised: {6} (d{15}) -IsPinned: {7} (d{16}) -ScreenIndexIsPinnedTo: {8} (a{17}) -", - participant.Name, - participant.AudioMuteFb, - participant.VideoMuteFb, - participant.CanMuteVideo, - participant.CanUnmuteVideo, - participant.IsHost, - participant.HandIsRaisedFb, - participant.IsPinnedFb, - participant.ScreenIndexIsPinnedToFb, - stringIndex + 1, - digitalIndex + 1, - digitalIndex + 2, - digitalIndex + 3, - digitalIndex + 4, - digitalIndex + 5, - digitalIndex + 6, - digitalIndex + 7, - analogIndex + 1 - ); +// Debug.Console(2, this, +//@"Updating Participant on xsig: +//Name: {0} (s{9}) +//AudioMute: {1} (d{10}) +//VideoMute: {2} (d{11}) +//CanMuteVideo: {3} (d{12}) +//CanUMuteVideo: {4} (d{13}) +//IsHost: {5} (d{14}) +//HandIsRaised: {6} (d{15}) +//IsPinned: {7} (d{16}) +//ScreenIndexIsPinnedTo: {8} (a{17}) +//", +// participant.Name, +// participant.AudioMuteFb, +// participant.VideoMuteFb, +// participant.CanMuteVideo, +// participant.CanUnmuteVideo, +// participant.IsHost, +// participant.HandIsRaisedFb, +// participant.IsPinnedFb, +// participant.ScreenIndexIsPinnedToFb, +// stringIndex + 1, +// digitalIndex + 1, +// digitalIndex + 2, +// digitalIndex + 3, +// digitalIndex + 4, +// digitalIndex + 5, +// digitalIndex + 6, +// digitalIndex + 7, +// analogIndex + 1 +// ); //digitals @@ -1160,7 +1160,9 @@ ScreenIndexIsPinnedTo: {8} (a{17}) { trilist.SetSigFalseAction((uint)(joinMap.EndCallStart.JoinNumber + i), () => { - var call = ActiveCalls[i]; + var callIndex = i; + + var call = ActiveCalls[callIndex]; if (call != null) { EndCall(call); @@ -1182,11 +1184,19 @@ ScreenIndexIsPinnedTo: {8} (a{17}) Debug.Console(1, this, "Call is incoming: {0}", args.CallItem.Direction == eCodecCallDirection.Incoming); trilist.SetBool(joinMap.IncomingCall.JoinNumber, args.CallItem.Direction == eCodecCallDirection.Incoming && args.CallItem.Status == eCodecCallStatus.Ringing); - if (args.CallItem.Direction == eCodecCallDirection.Incoming) - { - trilist.SetSigFalseAction(joinMap.IncomingAnswer.JoinNumber, () => AcceptCall(args.CallItem)); - trilist.SetSigFalseAction(joinMap.IncomingReject.JoinNumber, () => RejectCall(args.CallItem)); - } + if (args.CallItem.Direction == eCodecCallDirection.Incoming) + { + trilist.SetSigFalseAction(joinMap.IncomingAnswer.JoinNumber, () => AcceptCall(args.CallItem)); + trilist.SetSigFalseAction(joinMap.IncomingReject.JoinNumber, () => RejectCall(args.CallItem)); + trilist.SetString(joinMap.IncomingCallName.JoinNumber, args.CallItem.Name); + trilist.SetString(joinMap.IncomingCallNumber.JoinNumber, args.CallItem.Number); + } + else + { + trilist.SetString(joinMap.IncomingCallName.JoinNumber, string.Empty); + trilist.SetString(joinMap.IncomingCallNumber.JoinNumber, string.Empty); + } + trilist.SetString(joinMap.CurrentCallData.JoinNumber, UpdateCallStatusXSig()); From d88a454499c5213d47febceb558d28448889297b Mon Sep 17 00:00:00 2001 From: Jonathan Arndt Date: Fri, 11 Feb 2022 16:39:47 -0800 Subject: [PATCH 49/59] fix(essentials): various bug fixes for hold FB, individual call end, incoming name-number fb, ipv4 address fb --- .../VideoCodec/CiscoCodec/CiscoSparkCodec.cs | 27 ++++++++++++++----- .../VideoCodec/CiscoCodec/xConfiguration.cs | 11 ++++++++ .../VideoCodec/CiscoCodec/xStatus.cs | 25 ++++++++++++++++- .../VideoCodec/VideoCodecBase.cs | 9 ++++++- 4 files changed, 64 insertions(+), 8 deletions(-) diff --git a/essentials-framework/Essentials Devices Common/Essentials Devices Common/VideoCodec/CiscoCodec/CiscoSparkCodec.cs b/essentials-framework/Essentials Devices Common/Essentials Devices Common/VideoCodec/CiscoCodec/CiscoSparkCodec.cs index 32aaaa21..e42386c8 100644 --- a/essentials-framework/Essentials Devices Common/Essentials Devices Common/VideoCodec/CiscoCodec/CiscoSparkCodec.cs +++ b/essentials-framework/Essentials Devices Common/Essentials Devices Common/VideoCodec/CiscoCodec/CiscoSparkCodec.cs @@ -664,8 +664,16 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.Cisco foreach (var camera in CodecStatus.Status.Cameras.Camera) { + Debug.Console(0, this, +@"Camera id: {0} +Name: {1} +ConnectorID: {2}" +, 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, camera.Model), 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); } @@ -1994,7 +2002,7 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.Cisco } Cameras.Add(internalCamera); - DeviceManager.AddDevice(internalCamera); + //DeviceManager.AddDevice(internalCamera); } else { @@ -2132,12 +2140,19 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.Cisco { get { - if (CodecConfiguration.Configuration.Network != null) + var address = string.Empty; + if (CodecConfiguration.Configuration.Network.Count > 0) { - if (CodecConfiguration.Configuration.Network.Count > 0) - return CodecConfiguration.Configuration.Network[0].IPv4.Address.Value; + if(!string.IsNullOrEmpty(CodecConfiguration.Configuration.Network[0].IPv4.Address.Value)) + address = CodecConfiguration.Configuration.Network[0].IPv4.Address.Value; } - return string.Empty; + + 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 diff --git a/essentials-framework/Essentials Devices Common/Essentials Devices Common/VideoCodec/CiscoCodec/xConfiguration.cs b/essentials-framework/Essentials Devices Common/Essentials Devices Common/VideoCodec/CiscoCodec/xConfiguration.cs index 3a8c6252..05c07378 100644 --- a/essentials-framework/Essentials Devices Common/Essentials Devices Common/VideoCodec/CiscoCodec/xConfiguration.cs +++ b/essentials-framework/Essentials Devices Common/Essentials Devices Common/VideoCodec/CiscoCodec/xConfiguration.cs @@ -738,6 +738,11 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.Cisco public Assignment Assignment { get; set; } public Gateway Gateway { get; set; } public SubnetMask SubnetMask { get; set; } + + public IPv4() + { + Address = new Address4(); + } } public class Address5 @@ -889,6 +894,11 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.Cisco public RemoteAccess RemoteAccess { get; set; } public Speed Speed { get; set; } public VLAN VLAN { get; set; } + + public Network() + { + IPv4 = new IPv4(); + } } public class Mode19 @@ -1850,6 +1860,7 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.Cisco { Audio = new Audio(); Conference = new Conference(); + Network = new List(); } } diff --git a/essentials-framework/Essentials Devices Common/Essentials Devices Common/VideoCodec/CiscoCodec/xStatus.cs b/essentials-framework/Essentials Devices Common/Essentials Devices Common/VideoCodec/CiscoCodec/xStatus.cs index daaf8709..5bde30ff 100644 --- a/essentials-framework/Essentials Devices Common/Essentials Devices Common/VideoCodec/CiscoCodec/xStatus.cs +++ b/essentials-framework/Essentials Devices Common/Essentials Devices Common/VideoCodec/CiscoCodec/xStatus.cs @@ -270,7 +270,12 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.Cisco { get { - return Convert.ToUInt16(Value); + if(!string.IsNullOrEmpty(Value)) + { + return Convert.ToUInt16(Value); + } + else + return -1; } } } @@ -289,6 +294,13 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.Cisco public Position Position { get; set; } public SerialNumber SerialNumber { get; set; } public SoftwareID SoftwareID { get; set; } + + public Camera() + { + Manufacturer = new Manufacturer(); + Model = new Model(); + DetectedConnector = new DectectedConnector(); + } } public class Availability : ValueProperty @@ -957,6 +969,11 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.Cisco public Address4 Address { get; set; } public Gateway Gateway { get; set; } public SubnetMask SubnetMask { get; set; } + + public IPv4() + { + Address = new Address4(); + } } public class Address5 @@ -999,6 +1016,11 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.Cisco public IPv4 IPv4 { get; set; } public IPv6 IPv6 { get; set; } public VLAN VLAN { get; set; } + + public Network() + { + IPv4 = new IPv4(); + } } public class CurrentAddress @@ -2222,6 +2244,7 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.Cisco SystemUnit = new SystemUnit(); Video = new Video(); Conference = new Conference2(); + Network = new List(); } } diff --git a/essentials-framework/Essentials Devices Common/Essentials Devices Common/VideoCodec/VideoCodecBase.cs b/essentials-framework/Essentials Devices Common/Essentials Devices Common/VideoCodec/VideoCodecBase.cs index a96de4f9..73390b06 100644 --- a/essentials-framework/Essentials Devices Common/Essentials Devices Common/VideoCodec/VideoCodecBase.cs +++ b/essentials-framework/Essentials Devices Common/Essentials Devices Common/VideoCodec/VideoCodecBase.cs @@ -1158,9 +1158,16 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec //End a specific call, specified by index. Maximum 8 calls supported for (int i = 0; i < joinMap.EndCallStart.JoinSpan; i++) { + var callIndex = i; + trilist.SetSigFalseAction((uint)(joinMap.EndCallStart.JoinNumber + i), () => { - var callIndex = i; + + if (callIndex < 0 || callIndex >= ActiveCalls.Count) + { + Debug.Console(2, this, "Cannot end call. No call found at index: {0}", callIndex); + return; + } var call = ActiveCalls[callIndex]; if (call != null) From e39c76001ac27a57dbde1e1f62133a3e384e23ab Mon Sep 17 00:00:00 2001 From: Neil Dorin Date: Mon, 14 Feb 2022 16:16:58 -0700 Subject: [PATCH 50/59] feat(essentials): Updates to initial sync mechanism Adds queue for all outgoing commands to codec that blocks until sync is established --- .../VideoCodec/CiscoCodec/CiscoCamera.cs | 40 ++-- .../VideoCodec/CiscoCodec/CiscoSparkCodec.cs | 198 +++++++++++------- .../VideoCodec/ZoomRoom/ZoomRoom.cs | 2 +- 3 files changed, 147 insertions(+), 93 deletions(-) diff --git a/essentials-framework/Essentials Devices Common/Essentials Devices Common/VideoCodec/CiscoCodec/CiscoCamera.cs b/essentials-framework/Essentials Devices Common/Essentials Devices Common/VideoCodec/CiscoCodec/CiscoCamera.cs index 67312df8..9e8b0554 100644 --- a/essentials-framework/Essentials Devices Common/Essentials Devices Common/VideoCodec/CiscoCodec/CiscoCamera.cs +++ b/essentials-framework/Essentials Devices Common/Essentials Devices Common/VideoCodec/CiscoCodec/CiscoCamera.cs @@ -41,12 +41,12 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.Cisco public void PanLeft() { - ParentCodec.SendText(string.Format("xCommand Call FarEndControl Camera Move Value: Left CallId: {0}", CallId)); + ParentCodec.EnqueueCommand(string.Format("xCommand Call FarEndControl Camera Move Value: Left CallId: {0}", CallId)); } public void PanRight() { - ParentCodec.SendText(string.Format("xCommand Call FarEndControl Camera Move Value: Right CallId: {0}", CallId)); + ParentCodec.EnqueueCommand(string.Format("xCommand Call FarEndControl Camera Move Value: Right CallId: {0}", CallId)); } public void PanStop() @@ -60,12 +60,12 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.Cisco public void TiltDown() { - ParentCodec.SendText(string.Format("xCommand Call FarEndControl Camera Move Value: Down CallId: {0}", CallId)); + ParentCodec.EnqueueCommand(string.Format("xCommand Call FarEndControl Camera Move Value: Down CallId: {0}", CallId)); } public void TiltUp() { - ParentCodec.SendText(string.Format("xCommand Call FarEndControl Camera Move Value: Up CallId: {0}", CallId)); + ParentCodec.EnqueueCommand(string.Format("xCommand Call FarEndControl Camera Move Value: Up CallId: {0}", CallId)); } public void TiltStop() @@ -79,12 +79,12 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.Cisco public void ZoomIn() { - ParentCodec.SendText(string.Format("xCommand Call FarEndControl Camera Move Value: ZoomIn CallId: {0}", CallId)); + ParentCodec.EnqueueCommand(string.Format("xCommand Call FarEndControl Camera Move Value: ZoomIn CallId: {0}", CallId)); } public void ZoomOut() { - ParentCodec.SendText(string.Format("xCommand Call FarEndControl Camera Move Value: ZoomOut CallId: {0}", CallId)); + ParentCodec.EnqueueCommand(string.Format("xCommand Call FarEndControl Camera Move Value: ZoomOut CallId: {0}", CallId)); } public void ZoomStop() @@ -97,7 +97,7 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.Cisco void Stop() { - ParentCodec.SendText(string.Format("xCommand Call FarEndControl Camera Stop CallId: {0}", CallId)); + ParentCodec.EnqueueCommand(string.Format("xCommand Call FarEndControl Camera Stop CallId: {0}", CallId)); } public void LinkToApi(BasicTriList trilist, uint joinStart, string joinMapKey, EiscApiAdvanced bridge) @@ -202,7 +202,7 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.Cisco { if (!isMoving) { - ParentCodec.SendText(string.Format("xCommand Camera Ramp CameraId: {0} Pan: Left PanSpeed: {1}", CameraId, PanSpeed)); + ParentCodec.EnqueueCommand(string.Format("xCommand Camera Ramp CameraId: {0} Pan: Left PanSpeed: {1}", CameraId, PanSpeed)); isPanning = true; } } @@ -211,14 +211,14 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.Cisco { if (!isMoving) { - ParentCodec.SendText(string.Format("xCommand Camera Ramp CameraId: {0} Pan: Right PanSpeed: {1}", CameraId, PanSpeed)); + ParentCodec.EnqueueCommand(string.Format("xCommand Camera Ramp CameraId: {0} Pan: Right PanSpeed: {1}", CameraId, PanSpeed)); isPanning = true; } } public void PanStop() { - ParentCodec.SendText(string.Format("xCommand Camera Ramp CameraId: {0} Pan: Stop", CameraId)); + ParentCodec.EnqueueCommand(string.Format("xCommand Camera Ramp CameraId: {0} Pan: Stop", CameraId)); isPanning = false; } @@ -232,7 +232,7 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.Cisco { if (!isMoving) { - ParentCodec.SendText(string.Format("xCommand Camera Ramp CameraId: {0} Tilt: Down TiltSpeed: {1}", CameraId, TiltSpeed)); + ParentCodec.EnqueueCommand(string.Format("xCommand Camera Ramp CameraId: {0} Tilt: Down TiltSpeed: {1}", CameraId, TiltSpeed)); isTilting = true; } } @@ -241,14 +241,14 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.Cisco { if (!isMoving) { - ParentCodec.SendText(string.Format("xCommand Camera Ramp CameraId: {0} Tilt: Up TiltSpeed: {1}", CameraId, TiltSpeed)); + ParentCodec.EnqueueCommand(string.Format("xCommand Camera Ramp CameraId: {0} Tilt: Up TiltSpeed: {1}", CameraId, TiltSpeed)); isTilting = true; } } public void TiltStop() { - ParentCodec.SendText(string.Format("xCommand Camera Ramp CameraId: {0} Tilt: Stop", CameraId)); + ParentCodec.EnqueueCommand(string.Format("xCommand Camera Ramp CameraId: {0} Tilt: Stop", CameraId)); isTilting = false; } @@ -260,7 +260,7 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.Cisco { if (!isMoving) { - ParentCodec.SendText(string.Format("xCommand Camera Ramp CameraId: {0} Zoom: In ZoomSpeed: {1}", CameraId, ZoomSpeed)); + ParentCodec.EnqueueCommand(string.Format("xCommand Camera Ramp CameraId: {0} Zoom: In ZoomSpeed: {1}", CameraId, ZoomSpeed)); isZooming = true; } } @@ -269,14 +269,14 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.Cisco { if (!isMoving) { - ParentCodec.SendText(string.Format("xCommand Camera Ramp CameraId: {0} Zoom: Out ZoomSpeed: {1}", CameraId, ZoomSpeed)); + ParentCodec.EnqueueCommand(string.Format("xCommand Camera Ramp CameraId: {0} Zoom: Out ZoomSpeed: {1}", CameraId, ZoomSpeed)); isZooming = true; } } public void ZoomStop() { - ParentCodec.SendText(string.Format("xCommand Camera Ramp CameraId: {0} Zoom: Stop", CameraId)); + ParentCodec.EnqueueCommand(string.Format("xCommand Camera Ramp CameraId: {0} Zoom: Stop", CameraId)); isZooming = false; } @@ -288,7 +288,7 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.Cisco { if (!isMoving) { - ParentCodec.SendText(string.Format("xCommand Camera Ramp CameraId: {0} Focus: Near", CameraId)); + ParentCodec.EnqueueCommand(string.Format("xCommand Camera Ramp CameraId: {0} Focus: Near", CameraId)); isFocusing = true; } } @@ -297,20 +297,20 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.Cisco { if (!isMoving) { - ParentCodec.SendText(string.Format("xCommand Camera Ramp CameraId: {0} Focus: Far", CameraId)); + ParentCodec.EnqueueCommand(string.Format("xCommand Camera Ramp CameraId: {0} Focus: Far", CameraId)); isFocusing = true; } } public void FocusStop() { - ParentCodec.SendText(string.Format("xCommand Camera Ramp CameraId: {0} Focus: Stop", CameraId)); + ParentCodec.EnqueueCommand(string.Format("xCommand Camera Ramp CameraId: {0} Focus: Stop", CameraId)); isFocusing = false; } public void TriggerAutoFocus() { - ParentCodec.SendText(string.Format("xCommand Camera TriggerAutofocus CameraId: {0}", CameraId)); + ParentCodec.EnqueueCommand(string.Format("xCommand Camera TriggerAutofocus CameraId: {0}", CameraId)); } #endregion diff --git a/essentials-framework/Essentials Devices Common/Essentials Devices Common/VideoCodec/CiscoCodec/CiscoSparkCodec.cs b/essentials-framework/Essentials Devices Common/Essentials Devices Common/VideoCodec/CiscoCodec/CiscoSparkCodec.cs index e42386c8..b6f59dac 100644 --- a/essentials-framework/Essentials Devices Common/Essentials Devices Common/VideoCodec/CiscoCodec/CiscoSparkCodec.cs +++ b/essentials-framework/Essentials Devices Common/Essentials Devices Common/VideoCodec/CiscoCodec/CiscoSparkCodec.cs @@ -371,7 +371,7 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.Cisco _phonebookMode = props.PhonebookMode; - _syncState = new CodecSyncState(Key + "--Sync"); + _syncState = new CodecSyncState(Key + "--Sync", this); PhonebookSyncState = new CodecPhonebookSyncState(Key + "--PhonebookSync"); @@ -547,7 +547,7 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.Cisco /// Mobile Control user code private void DisplayUserCode(string code) { - SendText(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) @@ -559,17 +559,17 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.Cisco Debug.Console(1, this, "Sending url: {0}", mcBridge.QrCodeUrl); - SendText("xconfiguration userinterface custommessage: \"Scan the QR code with a mobile phone to get started\""); - SendText("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) : String.Empty; - SendText(String.Format( + EnqueueCommand(String.Format( "xcommand userinterface branding fetch {1}type: branding url: {0}", mcBridge.QrCodeUrl, checksum)); - SendText(String.Format( + EnqueueCommand(String.Format( "xcommand userinterface branding fetch {1}type: halfwakebranding url: {0}", mcBridge.QrCodeUrl, checksum)); } @@ -578,9 +578,9 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.Cisco { Debug.Console(1, this, "Sending url: {0}", _brandingUrl); - SendText(String.Format("xcommand userinterface branding fetch type: branding url: {0}", + EnqueueCommand(String.Format("xcommand userinterface branding fetch type: branding url: {0}", _brandingUrl)); - SendText(String.Format("xcommand userinterface branding fetch type: halfwakebranding url: {0}", + EnqueueCommand(String.Format("xcommand userinterface branding fetch type: halfwakebranding url: {0}", _brandingUrl)); } /// @@ -769,6 +769,12 @@ ConnectorID: {2}" Debug.Console(1, this, "RX: '{0}'", args.Text); } + if(args.Text.Contains("xCommand")) + { + Debug.Console(2, this, "Received command echo response. Ignoring"); + return; + } + if (args.Text == "{" + Delimiter) // Check for the beginning of a new JSON message { _jsonFeedbackMessageIsIncoming = true; @@ -813,6 +819,7 @@ ConnectorID: {2}" if(_loginMessageReceivedTimer != null) _loginMessageReceivedTimer.Stop(); + SendText("echo off"); SendText("xPreferences outputmode json"); break; } @@ -829,12 +836,21 @@ ConnectorID: {2}" } } } - - } /// - /// Appends the delimiter and send the command to the codec + /// Enqueues a command to be sent to the codec. + /// + /// + public void EnqueueCommand(string command) + { + _syncState.AddCommandToQueue(command + Delimiter); + } + + /// + /// Appends the delimiter and send the command to the codec. + /// Should not be used for sending general commands to the codec. Use EnqueueCommand instead. + /// Should be used to get initial Status and Configuration as well as set up Feedback Registration /// /// public void SendText(string command) @@ -1062,7 +1078,9 @@ ConnectorID: {2}" _syncState.InitialStatusMessageReceived(); if (!_syncState.InitialConfigurationMessageWasReceived) + { SendText("xConfiguration"); + } } } else if (response.IndexOf("\"Configuration\":{") > -1 || response.IndexOf("\"Configuration\": {") > -1) @@ -1296,7 +1314,7 @@ ConnectorID: {2}" public void GetCallHistory() { - SendText("xCommand CallHistory Recents Limit: 20 Order: OccurrenceTime"); + EnqueueCommand("xCommand CallHistory Recents Limit: 20 Order: OccurrenceTime"); } /// @@ -1315,7 +1333,7 @@ ConnectorID: {2}" { Debug.Console(1, this, "Retrieving Booking Info from Codec. Current Time: {0}", DateTime.Now.ToLocalTime()); - SendText("xCommand Bookings List Days: 1 DayOffset: 0"); + EnqueueCommand("xCommand Bookings List Days: 1 DayOffset: 0"); } /// @@ -1349,13 +1367,13 @@ ConnectorID: {2}" private void GetPhonebookFolders() { // Get Phonebook Folders (determine local/corporate from config, and set results limit) - SendText(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) - SendText(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)); } /// @@ -1364,7 +1382,7 @@ ConnectorID: {2}" /// public void SearchDirectory(string searchString) { - SendText(string.Format("xCommand Phonebook Search SearchString: \"{0}\" PhonebookType: {1} ContactType: Contact Limit: {2}", searchString, _phonebookMode, _phonebookResultsLimit)); + EnqueueCommand(string.Format("xCommand Phonebook Search SearchString: \"{0}\" PhonebookType: {1} ContactType: Contact Limit: {2}", searchString, _phonebookMode, _phonebookResultsLimit)); } /// @@ -1373,7 +1391,7 @@ ConnectorID: {2}" /// public void GetDirectoryFolderContents(string folderId) { - SendText(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)); } /// @@ -1444,7 +1462,7 @@ ConnectorID: {2}" /// public override void Dial(string number) { - SendText(string.Format("xCommand Dial Number: \"{0}\"", number)); + EnqueueCommand(string.Format("xCommand Dial Number: \"{0}\"", number)); } /// @@ -1469,43 +1487,43 @@ ConnectorID: {2}" /// public void Dial(string number, string protocol, string callRate, string callType, string meetingId) { - SendText(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)); } public override void EndCall(CodecActiveCallItem activeCall) { - SendText(string.Format("xCommand Call Disconnect CallId: {0}", activeCall.Id)); + EnqueueCommand(string.Format("xCommand Call Disconnect CallId: {0}", activeCall.Id)); } public override void EndAllCalls() { foreach (CodecActiveCallItem activeCall in ActiveCalls) { - SendText(string.Format("xCommand Call Disconnect CallId: {0}", activeCall.Id)); + EnqueueCommand(string.Format("xCommand Call Disconnect CallId: {0}", activeCall.Id)); } } public override void AcceptCall(CodecActiveCallItem item) { - SendText("xCommand Call Accept"); + EnqueueCommand("xCommand Call Accept"); } public override void RejectCall(CodecActiveCallItem item) { - SendText("xCommand Call Reject"); + EnqueueCommand("xCommand Call Reject"); } #region IHasCallHold Members public void HoldCall(CodecActiveCallItem activeCall) { - SendText(string.Format("xCommand Call Hold CallId: {0}", activeCall.Id)); + EnqueueCommand(string.Format("xCommand Call Hold CallId: {0}", activeCall.Id)); } public void ResumeCall(CodecActiveCallItem activeCall) { - SendText(string.Format("xCommand Call Resume CallId: {0}", activeCall.Id)); + EnqueueCommand(string.Format("xCommand Call Resume CallId: {0}", activeCall.Id)); } #endregion @@ -1514,7 +1532,7 @@ ConnectorID: {2}" public void JoinCall(CodecActiveCallItem activeCall) { - SendText(string.Format("xCommand Call Join CallId: {0}", activeCall.Id)); + EnqueueCommand(string.Format("xCommand Call Join CallId: {0}", activeCall.Id)); } public void JoinAllCalls() @@ -1531,7 +1549,7 @@ ConnectorID: {2}" if (ids.Length > 0) { - SendText(string.Format("xCommand Call Join {0}", ids.ToString())); + EnqueueCommand(string.Format("xCommand Call Join {0}", ids.ToString())); } } @@ -1543,7 +1561,7 @@ ConnectorID: {2}" /// public override void SendDtmf(string s) { - SendText(string.Format("xCommand Call DTMFSend CallId: {0} DTMFString: \"{1}\"", GetCallId(), s)); + EnqueueCommand(string.Format("xCommand Call DTMFSend CallId: {0} DTMFString: \"{1}\"", GetCallId(), s)); } /// @@ -1553,7 +1571,7 @@ ConnectorID: {2}" /// public override void SendDtmf(string s, CodecActiveCallItem activeCall) { - SendText(string.Format("xCommand Call DTMFSend CallId: {0} DTMFString: \"{1}\"", activeCall.Id, s)); + EnqueueCommand(string.Format("xCommand Call DTMFSend CallId: {0} DTMFString: \"{1}\"", activeCall.Id, s)); } public void SelectPresentationSource(int source) @@ -1581,7 +1599,7 @@ ConnectorID: {2}" return; } - SendText(string.Format("xConfiguration Audio SoundsAndAlerts RingVolume: {0}", volume)); + EnqueueCommand(string.Format("xConfiguration Audio SoundsAndAlerts RingVolume: {0}", volume)); } /// @@ -1615,7 +1633,7 @@ ConnectorID: {2}" sendingMode = "LocalOnly"; if (_desiredPresentationSource > 0) - SendText(string.Format("xCommand Presentation Start PresentationSource: {0} SendingMode: {1}", _desiredPresentationSource, sendingMode)); + EnqueueCommand(string.Format("xCommand Presentation Start PresentationSource: {0} SendingMode: {1}", _desiredPresentationSource, sendingMode)); } /// @@ -1625,39 +1643,39 @@ ConnectorID: {2}" { _desiredPresentationSource = 0; - SendText("xCommand Presentation Stop"); + EnqueueCommand("xCommand Presentation Stop"); } public override void PrivacyModeOn() { - SendText("xCommand Audio Microphones Mute"); + EnqueueCommand("xCommand Audio Microphones Mute"); } public override void PrivacyModeOff() { - SendText("xCommand Audio Microphones Unmute"); + EnqueueCommand("xCommand Audio Microphones Unmute"); } public override void PrivacyModeToggle() { - SendText("xCommand Audio Microphones ToggleMute"); + EnqueueCommand("xCommand Audio Microphones ToggleMute"); } public override void MuteOff() { - SendText("xCommand Audio Volume Unmute"); + EnqueueCommand("xCommand Audio Volume Unmute"); } public override void MuteOn() { - SendText("xCommand Audio Volume Mute"); + EnqueueCommand("xCommand Audio Volume Mute"); } public override void MuteToggle() { - SendText("xCommand Audio Volume ToggleMute"); + EnqueueCommand("xCommand Audio Volume ToggleMute"); } /// @@ -1666,7 +1684,7 @@ ConnectorID: {2}" /// public override void VolumeUp(bool pressRelease) { - SendText("xCommand Audio Volume Increase"); + EnqueueCommand("xCommand Audio Volume Increase"); } /// @@ -1675,7 +1693,7 @@ ConnectorID: {2}" /// public override void VolumeDown(bool pressRelease) { - SendText("xCommand Audio Volume Decrease"); + EnqueueCommand("xCommand Audio Volume Decrease"); } /// @@ -1685,7 +1703,7 @@ ConnectorID: {2}" public override void SetVolume(ushort level) { var scaledLevel = CrestronEnvironment.ScaleWithLimits(level, 65535, 0, 100, 0); - SendText(string.Format("xCommand Audio Volume Set Level: {0}", scaledLevel)); + EnqueueCommand(string.Format("xCommand Audio Volume Set Level: {0}", scaledLevel)); } /// @@ -1693,7 +1711,7 @@ ConnectorID: {2}" /// public void VolumeSetToDefault() { - SendText("xCommand Audio Volume SetToDefault"); + EnqueueCommand("xCommand Audio Volume SetToDefault"); } /// @@ -1701,7 +1719,7 @@ ConnectorID: {2}" /// public override void StandbyActivate() { - SendText("xCommand Standby Activate"); + EnqueueCommand("xCommand Standby Activate"); } /// @@ -1709,7 +1727,7 @@ ConnectorID: {2}" /// public override void StandbyDeactivate() { - SendText("xCommand Standby Deactivate"); + EnqueueCommand("xCommand Standby Deactivate"); } public override void LinkToApi(BasicTriList trilist, uint joinStart, string joinMapKey, EiscApiAdvanced bridge) @@ -1736,7 +1754,7 @@ ConnectorID: {2}" public void LinkCiscoCodecToApi(BasicTriList trilist, CiscoCodecJoinMap joinMap) { // Custom commands to codec - trilist.SetStringSigAction(joinMap.CommandToDevice.JoinNumber, (s) => this.SendText(s)); + trilist.SetStringSigAction(joinMap.CommandToDevice.JoinNumber, (s) => this.EnqueueCommand(s)); var dndCodec = this as IHasDoNotDisturbMode; @@ -1780,7 +1798,7 @@ ConnectorID: {2}" /// public void Reboot() { - SendText("xCommand SystemUnit Boot Action: Restart"); + EnqueueCommand("xCommand SystemUnit Boot Action: Restart"); } /// @@ -1806,7 +1824,7 @@ ConnectorID: {2}" /// public void SelfViewModeOn() { - SendText("xCommand Video Selfview Set Mode: On"); + EnqueueCommand("xCommand Video Selfview Set Mode: On"); } /// @@ -1814,7 +1832,7 @@ ConnectorID: {2}" /// public void SelfViewModeOff() { - SendText("xCommand Video Selfview Set Mode: Off"); + EnqueueCommand("xCommand Video Selfview Set Mode: Off"); } /// @@ -1829,7 +1847,7 @@ ConnectorID: {2}" else mode = "On"; - SendText(string.Format("xCommand Video Selfview Set Mode: {0}", mode)); + EnqueueCommand(string.Format("xCommand Video Selfview Set Mode: {0}", mode)); } /// @@ -1838,7 +1856,7 @@ ConnectorID: {2}" /// public void SelfviewPipPositionSet(CodecCommandWithLabel position) { - SendText(string.Format("xCommand Video Selfview Set Mode: On PIPPosition: {0}", position.Command)); + EnqueueCommand(string.Format("xCommand Video Selfview Set Mode: On PIPPosition: {0}", position.Command)); } /// @@ -1863,7 +1881,7 @@ ConnectorID: {2}" /// public void LocalLayoutSet(CodecCommandWithLabel layout) { - SendText(string.Format("xCommand Video Layout LayoutFamily Set Target: local LayoutFamily: {0}", layout.Command)); + EnqueueCommand(string.Format("xCommand Video Layout LayoutFamily Set Target: local LayoutFamily: {0}", layout.Command)); } /// @@ -1907,7 +1925,7 @@ ConnectorID: {2}" else _currentPresentationView = "Maximized"; - SendText(string.Format("xCommand Video PresentationView Set View: {0}", _currentPresentationView)); + EnqueueCommand(string.Format("xCommand Video PresentationView Set View: {0}", _currentPresentationView)); PresentationViewMaximizedFeedback.FireUpdate(); } @@ -1935,7 +1953,7 @@ ConnectorID: {2}" public void RemoveCallHistoryEntry(CodecCallHistory.CallHistoryEntry entry) { - SendText(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 @@ -1944,11 +1962,11 @@ ConnectorID: {2}" { if (!CameraAutoModeIsOnFeedback.BoolValue) { - SendText("xCommand Cameras SpeakerTrack Activate"); + EnqueueCommand("xCommand Cameras SpeakerTrack Activate"); } else { - SendText("xCommand Cameras SpeakerTrack Deactivate"); + EnqueueCommand("xCommand Cameras SpeakerTrack Deactivate"); } } @@ -1959,7 +1977,7 @@ ConnectorID: {2}" CameraMuteOff(); } - SendText("xCommand Cameras SpeakerTrack Activate"); + EnqueueCommand("xCommand Cameras SpeakerTrack Activate"); } public void CameraAutoModeOff() @@ -1969,7 +1987,7 @@ ConnectorID: {2}" CameraMuteOff(); } - SendText("xCommand Cameras SpeakerTrack Deactivate"); + EnqueueCommand("xCommand Cameras SpeakerTrack Deactivate"); } #endregion @@ -2106,7 +2124,7 @@ ConnectorID: {2}" var ciscoCam = camera as CiscoSparkCamera; if (ciscoCam != null) { - SendText(string.Format("xCommand Video Input SetMainVideoSource SourceId: {0}", ciscoCam.CameraId)); + EnqueueCommand(string.Format("xCommand Video Input SetMainVideoSource SourceId: {0}", ciscoCam.CameraId)); } } @@ -2259,19 +2277,19 @@ ConnectorID: {2}" if (SelectedCamera is IAmFarEndCamera) SelectFarEndPreset(preset); else - SendText(string.Format("xCommand RoomPreset Activate PresetId: {0}", preset)); + EnqueueCommand(string.Format("xCommand RoomPreset Activate PresetId: {0}", preset)); } public void CodecRoomPresetStore(int preset, string description) { - SendText(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) { - SendText(string.Format("xCommand Call FarEndControl RoomPreset Activate CallId: {0} PresetId: {1}", GetCallId(), preset)); + EnqueueCommand(string.Format("xCommand Call FarEndControl RoomPreset Activate CallId: {0} PresetId: {1}", GetCallId(), preset)); } @@ -2308,7 +2326,7 @@ ConnectorID: {2}" { id = 3; } - SendText(string.Format("xCommand UserInterface Presentation ExternalSource Add ConnectorId: {0} SourceIdentifier: \"{1}\" Name: \"{2}\" Type: {3}", id, key, name, type.ToString())); + EnqueueCommand(string.Format("xCommand UserInterface Presentation ExternalSource Add ConnectorId: {0} SourceIdentifier: \"{1}\" Name: \"{2}\" Type: {3}", id, key, name, type.ToString())); // SendText(string.Format("xCommand UserInterface Presentation ExternalSource State Set SourceIdentifier: \"{0}\" State: Ready", key)); Debug.Console(2, this, "Adding ExternalSource {0} {1}", connectorId, name); @@ -2322,14 +2340,14 @@ ConnectorID: {2}" /// public void SetExternalSourceState(string key, eExternalSourceMode mode) { - SendText(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())); } /// /// Clears all external sources on the codec /// public void ClearExternalSources() { - SendText("xCommand UserInterface Presentation ExternalSource RemoveAll"); + EnqueueCommand("xCommand UserInterface Presentation ExternalSource RemoveAll"); } @@ -2338,7 +2356,7 @@ ConnectorID: {2}" /// public void SetSelectedSource(string key) { - SendText(string.Format("xCommand UserInterface Presentation ExternalSource Select SourceIdentifier: {0}", key)); + EnqueueCommand(string.Format("xCommand UserInterface Presentation ExternalSource Select SourceIdentifier: {0}", key)); _externalSourceChangeRequested = true; } @@ -2377,7 +2395,7 @@ ConnectorID: {2}" /// public void CameraMuteOn() { - SendText("xCommand Video Input MainVideo Mute"); + EnqueueCommand("xCommand Video Input MainVideo Mute"); } /// @@ -2385,7 +2403,7 @@ ConnectorID: {2}" /// public void CameraMuteOff() { - SendText("xCommand Video Input MainVideo Unmute"); + EnqueueCommand("xCommand Video Input MainVideo Unmute"); } /// @@ -2405,12 +2423,12 @@ ConnectorID: {2}" public void ActivateDoNotDisturbMode() { - SendText("xCommand Conference DoNotDisturb Activate"); + EnqueueCommand("xCommand Conference DoNotDisturb Activate"); } public void DeactivateDoNotDisturbMode() { - SendText("xCommand Conference DoNotDisturb Deactivate"); + EnqueueCommand("xCommand Conference DoNotDisturb Deactivate"); } public void ToggleDoNotDisturbMode() @@ -2435,7 +2453,7 @@ ConnectorID: {2}" public void HalfwakeActivate() { - SendText("xCommand Standby Halfwake"); + EnqueueCommand("xCommand Standby Halfwake"); } #endregion @@ -2463,8 +2481,10 @@ ConnectorID: {2}" public class CodecSyncState : IKeyed { bool _InitialSyncComplete; + private readonly CiscoSparkCodec _parent; public event EventHandler InitialSyncCompleted; + private readonly CrestronQueue _commandQueue; public string Key { get; private set; } @@ -2491,10 +2511,43 @@ ConnectorID: {2}" public bool FeedbackWasRegistered { get; private set; } - public CodecSyncState(string key) + public CodecSyncState(string key, CiscoSparkCodec parent) { Key = key; + _parent = parent; + _commandQueue = new CrestronQueue(25); CodecDisconnected(); + + + while (InitialSyncComplete && !_commandQueue.IsEmpty) + { + var query = _commandQueue.Dequeue(); + + _parent.SendText(query); + } + } + + //public void StartSync() + //{ + // DequeueQueries(); + //} + + //private void DequeueQueries() + //{ + + // while (!_commandQueue.IsEmpty) + // { + // var query = _commandQueue.Dequeue(); + + // _parent.SendText(query); + // } + + // InitialQueryMessagesSent(); + //} + + public void AddCommandToQueue(string query) + { + _commandQueue.Enqueue(query); } public void LoginMessageReceived() @@ -2527,6 +2580,7 @@ ConnectorID: {2}" public void CodecDisconnected() { + _commandQueue.Clear(); LoginMessageWasReceived = false; InitialConfigurationMessageWasReceived = false; InitialStatusMessageWasReceived = false; @@ -2536,7 +2590,7 @@ ConnectorID: {2}" void CheckSyncStatus() { - if (LoginMessageWasReceived && InitialConfigurationMessageWasReceived && InitialStatusMessageWasReceived && FeedbackWasRegistered) + if (LoginMessageWasReceived && InitialConfigurationMessageWasReceived && InitialStatusMessageWasReceived && FeedbackWasRegistered) { InitialSyncComplete = true; Debug.Console(1, this, "Initial Codec Sync Complete!"); diff --git a/essentials-framework/Essentials Devices Common/Essentials Devices Common/VideoCodec/ZoomRoom/ZoomRoom.cs b/essentials-framework/Essentials Devices Common/Essentials Devices Common/VideoCodec/ZoomRoom/ZoomRoom.cs index a43ea79c..1fa58ffb 100644 --- a/essentials-framework/Essentials Devices Common/Essentials Devices Common/VideoCodec/ZoomRoom/ZoomRoom.cs +++ b/essentials-framework/Essentials Devices Common/Essentials Devices Common/VideoCodec/ZoomRoom/ZoomRoom.cs @@ -3200,7 +3200,7 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.ZoomRoom CheckSyncStatus(); } - public void InitialQueryMessagesSent() + private void InitialQueryMessagesSent() { InitialQueryMessagesWereSent = true; Debug.Console(1, this, "Query Messages Sent."); From 6df594dd7fe21d93c2f8c3764ad3b090b807e60e Mon Sep 17 00:00:00 2001 From: Jonathan Arndt Date: Mon, 14 Feb 2022 17:21:15 -0800 Subject: [PATCH 51/59] Updates to CiscoSparkCodec queue --- .../VideoCodec/CiscoCodec/CiscoSparkCodec.cs | 75 ++++++++++--------- 1 file changed, 39 insertions(+), 36 deletions(-) diff --git a/essentials-framework/Essentials Devices Common/Essentials Devices Common/VideoCodec/CiscoCodec/CiscoSparkCodec.cs b/essentials-framework/Essentials Devices Common/Essentials Devices Common/VideoCodec/CiscoCodec/CiscoSparkCodec.cs index b6f59dac..1a9dec0e 100644 --- a/essentials-framework/Essentials Devices Common/Essentials Devices Common/VideoCodec/CiscoCodec/CiscoSparkCodec.cs +++ b/essentials-framework/Essentials Devices Common/Essentials Devices Common/VideoCodec/CiscoCodec/CiscoSparkCodec.cs @@ -359,7 +359,7 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.Cisco } else { - CommunicationMonitor = new GenericCommunicationMonitor(this, Communication, 30000, 120000, 300000, "xStatus SystemUnit Software Version\r"); + CommunicationMonitor = new GenericCommunicationMonitor(this, Communication, 30000, 120000, 300000, "xStatus SystemUnit Software Version\r\n"); } if (props.Sharing != null) @@ -662,6 +662,8 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.Cisco { var cameraInfo = new List(); + Debug.Console(0, this, "Codec reports {0} cameras", CodecStatus.Status.Cameras.Camera.Count); + foreach (var camera in CodecStatus.Status.Cameras.Camera) { Debug.Console(0, this, @@ -766,12 +768,12 @@ ConnectorID: {2}" if (CommDebuggingIsOn) { if (!_jsonFeedbackMessageIsIncoming) - Debug.Console(1, this, "RX: '{0}'", args.Text); + Debug.Console(1, this, "RX: '{0}'", ComTextHelper.GetDebugText(args.Text)); } - if(args.Text.Contains("xCommand")) + if(args.Text.ToLower().Contains("xcommand")) { - Debug.Console(2, this, "Received command echo response. Ignoring"); + Debug.Console(1, this, "Received command echo response. Ignoring"); return; } @@ -819,12 +821,17 @@ ConnectorID: {2}" if(_loginMessageReceivedTimer != null) _loginMessageReceivedTimer.Stop(); - SendText("echo off"); + //SendText("echo off"); SendText("xPreferences outputmode json"); break; } case "xpreferences outputmode json": { + if (_syncState.JsonResponseModeSet) + return; + + _syncState.JsonResponseModeMessageReceived(); + if (!_syncState.InitialStatusMessageWasReceived) SendText("xStatus"); break; @@ -844,7 +851,7 @@ ConnectorID: {2}" /// public void EnqueueCommand(string command) { - _syncState.AddCommandToQueue(command + Delimiter); + _syncState.AddCommandToQueue(command); } /// @@ -856,7 +863,7 @@ ConnectorID: {2}" public void SendText(string command) { if (CommDebuggingIsOn) - Debug.Console(1, this, "Sending: '{0}'", command); + Debug.Console(1, this, "Sending: '{0}'", ComTextHelper.GetDebugText(command + Delimiter)); Communication.SendText(command + Delimiter); } @@ -2002,9 +2009,6 @@ ConnectorID: {2}" var camCount = CodecStatus.Status.Cameras.Camera.Count; - Debug.Console(0, this, "Codec reports {0} cameras", camCount); - - // Deal with the case of 1 or no reported cameras if (camCount <= 1) { @@ -2505,6 +2509,8 @@ ConnectorID: {2}" public bool LoginMessageWasReceived { get; private set; } + public bool JsonResponseModeSet { get; private set; } + public bool InitialStatusMessageWasReceived { get; private set; } public bool InitialConfigurationMessageWasReceived { get; private set; } @@ -2515,35 +2521,22 @@ ConnectorID: {2}" { Key = key; _parent = parent; - _commandQueue = new CrestronQueue(25); + _commandQueue = new CrestronQueue(50); CodecDisconnected(); - - - while (InitialSyncComplete && !_commandQueue.IsEmpty) - { - var query = _commandQueue.Dequeue(); - - _parent.SendText(query); - } } - //public void StartSync() - //{ - // DequeueQueries(); - //} + private void ProcessQueuedCommands() + { + while (InitialSyncComplete) + { + if (!_commandQueue.IsEmpty) + { + var query = _commandQueue.Dequeue(); - //private void DequeueQueries() - //{ - - // while (!_commandQueue.IsEmpty) - // { - // var query = _commandQueue.Dequeue(); - - // _parent.SendText(query); - // } - - // InitialQueryMessagesSent(); - //} + _parent.SendText(query); + } + } + } public void AddCommandToQueue(string query) { @@ -2557,6 +2550,13 @@ ConnectorID: {2}" CheckSyncStatus(); } + public void JsonResponseModeMessageReceived() + { + JsonResponseModeSet = true; + Debug.Console(1, this, "Json Response Mode Message Received."); + CheckSyncStatus(); + } + public void InitialStatusMessageReceived() { InitialStatusMessageWasReceived = true; @@ -2582,6 +2582,7 @@ ConnectorID: {2}" { _commandQueue.Clear(); LoginMessageWasReceived = false; + JsonResponseModeSet = false; InitialConfigurationMessageWasReceived = false; InitialStatusMessageWasReceived = false; FeedbackWasRegistered = false; @@ -2590,10 +2591,12 @@ ConnectorID: {2}" void CheckSyncStatus() { - if (LoginMessageWasReceived && InitialConfigurationMessageWasReceived && InitialStatusMessageWasReceived && FeedbackWasRegistered) + if (LoginMessageWasReceived && JsonResponseModeSet && InitialConfigurationMessageWasReceived && InitialStatusMessageWasReceived && FeedbackWasRegistered) { InitialSyncComplete = true; Debug.Console(1, this, "Initial Codec Sync Complete!"); + Debug.Console(1, this, "{0} Command queued. Processing now...", _commandQueue.Count); + ProcessQueuedCommands(); } else InitialSyncComplete = false; From 80b5fb6c7f1090a6c095e6418c491faa338fcf5a Mon Sep 17 00:00:00 2001 From: Jonathan Arndt Date: Tue, 15 Feb 2022 11:27:37 -0800 Subject: [PATCH 52/59] CiscoSparkCodec > Removed inner IF of processQueuedCommands and added CrestronInvoke to CheckSyncStatus --- .../PepperDashEssentialsBase/Queues/GenericQueue.cs | 2 +- .../VideoCodec/CiscoCodec/CiscoSparkCodec.cs | 13 +++++++------ 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/essentials-framework/Essentials Core/PepperDashEssentialsBase/Queues/GenericQueue.cs b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Queues/GenericQueue.cs index a1cef30d..8dca9803 100644 --- a/essentials-framework/Essentials Core/PepperDashEssentialsBase/Queues/GenericQueue.cs +++ b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Queues/GenericQueue.cs @@ -118,7 +118,7 @@ namespace PepperDash.Essentials.Core.Queues /// public GenericQueue(string key, int pacing, Thread.eThreadPriority priority, int capacity) : this(key, priority, capacity, pacing) - { + { } /// diff --git a/essentials-framework/Essentials Devices Common/Essentials Devices Common/VideoCodec/CiscoCodec/CiscoSparkCodec.cs b/essentials-framework/Essentials Devices Common/Essentials Devices Common/VideoCodec/CiscoCodec/CiscoSparkCodec.cs index 1a9dec0e..edcc61ec 100644 --- a/essentials-framework/Essentials Devices Common/Essentials Devices Common/VideoCodec/CiscoCodec/CiscoSparkCodec.cs +++ b/essentials-framework/Essentials Devices Common/Essentials Devices Common/VideoCodec/CiscoCodec/CiscoSparkCodec.cs @@ -2529,12 +2529,9 @@ ConnectorID: {2}" { while (InitialSyncComplete) { - if (!_commandQueue.IsEmpty) - { - var query = _commandQueue.Dequeue(); + var query = _commandQueue.Dequeue(); - _parent.SendText(query); - } + _parent.SendText(query); } } @@ -2596,7 +2593,11 @@ ConnectorID: {2}" InitialSyncComplete = true; Debug.Console(1, this, "Initial Codec Sync Complete!"); Debug.Console(1, this, "{0} Command queued. Processing now...", _commandQueue.Count); - ProcessQueuedCommands(); + + // Invoke a thread for the queue + CrestronInvoke.BeginInvoke((o) => { + ProcessQueuedCommands(); + }); } else InitialSyncComplete = false; From a06652ee61345df7726b4338a74e460d18361758 Mon Sep 17 00:00:00 2001 From: Neil Dorin Date: Mon, 21 Feb 2022 12:06:09 -0700 Subject: [PATCH 53/59] chore(essentials): Cleans up some debug statements no longer needed --- .../EssentialsHuddleVtc1PanelAvFunctionsDriver.cs | 8 ++++---- PepperDashEssentials/UIDrivers/JoinedSigInterlock.cs | 10 +++++----- .../UIDrivers/ScreenSaverController.cs | 12 ++++++------ .../VideoCodec/ZoomRoom/ZoomRoom.cs | 4 ++-- 4 files changed, 17 insertions(+), 17 deletions(-) diff --git a/PepperDashEssentials/UIDrivers/EssentialsHuddleVTC/EssentialsHuddleVtc1PanelAvFunctionsDriver.cs b/PepperDashEssentials/UIDrivers/EssentialsHuddleVTC/EssentialsHuddleVtc1PanelAvFunctionsDriver.cs index 44091362..80fb0ba8 100644 --- a/PepperDashEssentials/UIDrivers/EssentialsHuddleVTC/EssentialsHuddleVtc1PanelAvFunctionsDriver.cs +++ b/PepperDashEssentials/UIDrivers/EssentialsHuddleVTC/EssentialsHuddleVtc1PanelAvFunctionsDriver.cs @@ -493,10 +493,10 @@ namespace PepperDash.Essentials // and the LastMeetingDismissed != this meeting var lastMeetingDismissed = meetings.FirstOrDefault(m => m.Id == LastMeetingDismissedId); - Debug.Console(0, "*#* Room on: {0}, lastMeetingDismissedId: {1} {2} *#*", - CurrentRoom.OnFeedback.BoolValue, - LastMeetingDismissedId, - lastMeetingDismissed != null ? lastMeetingDismissed.StartTime.ToString("t", Global.Culture) : ""); + //Debug.Console(0, "*#* Room on: {0}, lastMeetingDismissedId: {1} {2} *#*", + // CurrentRoom.OnFeedback.BoolValue, + // LastMeetingDismissedId, + // lastMeetingDismissed != null ? lastMeetingDismissed.StartTime.ToString("t", Global.Culture) : ""); var meeting = meetings.LastOrDefault(m => m.Joinable); if (CurrentRoom.OnFeedback.BoolValue diff --git a/PepperDashEssentials/UIDrivers/JoinedSigInterlock.cs b/PepperDashEssentials/UIDrivers/JoinedSigInterlock.cs index 04e01eb0..a7dba246 100644 --- a/PepperDashEssentials/UIDrivers/JoinedSigInterlock.cs +++ b/PepperDashEssentials/UIDrivers/JoinedSigInterlock.cs @@ -52,7 +52,7 @@ namespace PepperDash.Essentials { var prevJoin = CurrentJoin; var wasShown = _IsShown; - Debug.Console(2, "Trilist {0:X2}, interlock swapping {1} for {2}", TriList.ID, CurrentJoin, join); + //Debug.Console(2, "Trilist {0:X2}, interlock swapping {1} for {2}", TriList.ID, CurrentJoin, join); if (CurrentJoin == join && TriList.BooleanInput[join].BoolValue) return; SetButDontShow(join); @@ -71,7 +71,7 @@ namespace PepperDash.Essentials var prevJoin = CurrentJoin; var wasShown = IsShown; - Debug.Console(2, "Trilist {0:X2}, interlock swapping {1} for {2}", TriList.ID, CurrentJoin, join); + //Debug.Console(2, "Trilist {0:X2}, interlock swapping {1} for {2}", TriList.ID, CurrentJoin, join); if (CurrentJoin == join) HideAndClear(); else @@ -92,7 +92,7 @@ namespace PepperDash.Essentials { var prevJoin = CurrentJoin; var wasShown = IsShown; - Debug.Console(2, "Trilist {0:X2}, interlock hiding {1}", TriList.ID, CurrentJoin); + //Debug.Console(2, "Trilist {0:X2}, interlock hiding {1}", TriList.ID, CurrentJoin); Hide(); CurrentJoin = 0; @@ -108,7 +108,7 @@ namespace PepperDash.Essentials var prevJoin = CurrentJoin; var wasShown = IsShown; - Debug.Console(2, "Trilist {0:X2}, interlock hiding {1}", TriList.ID, CurrentJoin); + //Debug.Console(2, "Trilist {0:X2}, interlock hiding {1}", TriList.ID, CurrentJoin); if (CurrentJoin > 0) { TriList.BooleanInput[CurrentJoin].BoolValue = false; @@ -125,7 +125,7 @@ namespace PepperDash.Essentials var prevJoin = CurrentJoin; var wasShown = IsShown; - Debug.Console(2, "Trilist {0:X2}, interlock showing {1}", TriList.ID, CurrentJoin); + //Debug.Console(2, "Trilist {0:X2}, interlock showing {1}", TriList.ID, CurrentJoin); if (CurrentJoin > 0) { TriList.BooleanInput[CurrentJoin].BoolValue = true; diff --git a/PepperDashEssentials/UIDrivers/ScreenSaverController.cs b/PepperDashEssentials/UIDrivers/ScreenSaverController.cs index 0f75e2a2..11ce587a 100644 --- a/PepperDashEssentials/UIDrivers/ScreenSaverController.cs +++ b/PepperDashEssentials/UIDrivers/ScreenSaverController.cs @@ -51,7 +51,7 @@ namespace PepperDash.Essentials public override void Show() { - Debug.Console(2, "Showing ScreenSaverController: {0:X2}", TriList.ID); + //Debug.Console(2, "Showing ScreenSaverController: {0:X2}", TriList.ID); if (_parent.AvDriver != null) { @@ -67,11 +67,11 @@ namespace PepperDash.Essentials public override void Hide() { - Debug.Console(2, "Hiding ScreenSaverController: {0:X2}", TriList.ID); + //Debug.Console(2, "Hiding ScreenSaverController: {0:X2}", TriList.ID); if (PositionTimer != null) { - Debug.Console(2, "Stopping PositionTimer: {0:X2}", TriList.ID); + //Debug.Console(2, "Stopping PositionTimer: {0:X2}", TriList.ID); PositionTimer.Stop(); PositionTimer.Dispose(); PositionTimer = null; @@ -89,7 +89,7 @@ namespace PepperDash.Essentials void StartPositionTimer() { - Debug.Console(2, "Starting Position Timer: {0:X2}", TriList.ID); + //Debug.Console(2, "Starting Position Timer: {0:X2}", TriList.ID); if (PositionTimer == null) { @@ -122,7 +122,7 @@ namespace PepperDash.Essentials CurrentPositionIndex = 0; } - Debug.Console(2, "ScreenSaver Position Timer Expired: Setting new position: {0} ID: {1:X2}", CurrentPositionIndex, TriList.ID); + //Debug.Console(2, "ScreenSaver Position Timer Expired: Setting new position: {0} ID: {1:X2}", CurrentPositionIndex, TriList.ID); } // @@ -134,7 +134,7 @@ namespace PepperDash.Essentials void ClearAllPositions() { - Debug.Console(2, "Hiding all screensaver positions: {0:X2}", TriList.ID); + //Debug.Console(2, "Hiding all screensaver positions: {0:X2}", TriList.ID); PositionInterlock.HideAndClear(); } diff --git a/essentials-framework/Essentials Devices Common/Essentials Devices Common/VideoCodec/ZoomRoom/ZoomRoom.cs b/essentials-framework/Essentials Devices Common/Essentials Devices Common/VideoCodec/ZoomRoom/ZoomRoom.cs index 6ea90c80..e2c06eee 100644 --- a/essentials-framework/Essentials Devices Common/Essentials Devices Common/VideoCodec/ZoomRoom/ZoomRoom.cs +++ b/essentials-framework/Essentials Devices Common/Essentials Devices Common/VideoCodec/ZoomRoom/ZoomRoom.cs @@ -33,14 +33,14 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.ZoomRoom public uint DefaultMeetingDurationMin { get; private set; } /// - /// CR LF + /// CR LF CR LF Delimits an echoed response to a command /// private const string EchoDelimiter = "\x0D\x0A\x0D\x0A"; private const string SendDelimiter = "\x0D"; /// - /// CR LF } CR LF + /// CR LF } CR LF Delimits a JSON response /// private const string JsonDelimiter = "\x0D\x0A\x7D\x0D\x0A"; From 55ab593d7379ff437f8bb1d07dc78f98d3ac6892 Mon Sep 17 00:00:00 2001 From: Neil Dorin Date: Thu, 24 Feb 2022 14:34:38 -0700 Subject: [PATCH 54/59] feat(essentails): #911 swaps cisco comm monitor poll string --- .../VideoCodec/CiscoCodec/CiscoSparkCodec.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/essentials-framework/Essentials Devices Common/Essentials Devices Common/VideoCodec/CiscoCodec/CiscoSparkCodec.cs b/essentials-framework/Essentials Devices Common/Essentials Devices Common/VideoCodec/CiscoCodec/CiscoSparkCodec.cs index edcc61ec..c9e584d3 100644 --- a/essentials-framework/Essentials Devices Common/Essentials Devices Common/VideoCodec/CiscoCodec/CiscoSparkCodec.cs +++ b/essentials-framework/Essentials Devices Common/Essentials Devices Common/VideoCodec/CiscoCodec/CiscoSparkCodec.cs @@ -359,7 +359,8 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.Cisco } else { - CommunicationMonitor = new GenericCommunicationMonitor(this, Communication, 30000, 120000, 300000, "xStatus SystemUnit Software Version\r\n"); + 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); } if (props.Sharing != null) From b3f75684695db0174781e422b4ca211f81e1c4d0 Mon Sep 17 00:00:00 2001 From: Neil Dorin Date: Thu, 24 Feb 2022 22:03:03 -0700 Subject: [PATCH 55/59] fix(essentials): updates to IHasDirectory and ZoomRoom Prevents serialization of CurrentDirectoryResults object. Modified OnDirectoryResultsReturne helper method for ZoomRoom to fix stripping of contacts --- .../Codec/iHasDirectory.cs | 3 +- .../VideoCodec/ZoomRoom/ZoomRoom.cs | 48 +++++++++---------- 2 files changed, 26 insertions(+), 25 deletions(-) diff --git a/essentials-framework/Essentials Devices Common/Essentials Devices Common/Codec/iHasDirectory.cs b/essentials-framework/Essentials Devices Common/Essentials Devices Common/Codec/iHasDirectory.cs index 642f03d0..57dbbd6b 100644 --- a/essentials-framework/Essentials Devices Common/Essentials Devices Common/Codec/iHasDirectory.cs +++ b/essentials-framework/Essentials Devices Common/Essentials Devices Common/Codec/iHasDirectory.cs @@ -65,8 +65,9 @@ namespace PepperDash.Essentials.Devices.Common.Codec { /// /// Represents the contents of the directory + /// We don't want to serialize this for messages to MobileControl. MC can combine Contacts and Folders to get the same data /// - [JsonProperty("directoryResults")] + [JsonIgnore] public List CurrentDirectoryResults { get; private set; } [JsonProperty("contacts")] diff --git a/essentials-framework/Essentials Devices Common/Essentials Devices Common/VideoCodec/ZoomRoom/ZoomRoom.cs b/essentials-framework/Essentials Devices Common/Essentials Devices Common/VideoCodec/ZoomRoom/ZoomRoom.cs index e2c06eee..ffab3ea5 100644 --- a/essentials-framework/Essentials Devices Common/Essentials Devices Common/VideoCodec/ZoomRoom/ZoomRoom.cs +++ b/essentials-framework/Essentials Devices Common/Essentials Devices Common/VideoCodec/ZoomRoom/ZoomRoom.cs @@ -400,10 +400,8 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.ZoomRoom { _currentDirectoryResult = value; - Debug.Console(2, this, "CurrentDirectoryResult Updated. ResultsFolderId: {0}", - _currentDirectoryResult.ResultsFolderId); - - CurrentDirectoryResultIsNotDirectoryRoot.FireUpdate(); + Debug.Console(2, this, "CurrentDirectoryResult Updated. ResultsFolderId: {0} Contact Count: {1}", + _currentDirectoryResult.ResultsFolderId, _currentDirectoryResult.CurrentDirectoryResults.Count); OnDirectoryResultReturned(_currentDirectoryResult); } @@ -1305,6 +1303,9 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.ZoomRoom // This result will always be the complete contents of the directory and never // A subset of the results via a search + // Clear out any existing data + Status.Phonebook = new zStatus.Phonebook(); + JsonConvert.PopulateObject(responseObj.ToString(), Status.Phonebook); var directoryResults = @@ -1318,10 +1319,7 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.ZoomRoom PhonebookSyncState.SetNumberOfContacts(Status.Phonebook.Contacts.Count); } - if (directoryResults.ResultsFolderId != "root") - { - directoryResults.ResultsFolderId = "root"; - } + directoryResults.ResultsFolderId = "root"; DirectoryRoot = directoryResults; @@ -2696,27 +2694,27 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.ZoomRoom { try { - Debug.Console(2, this, "OnDirectoryResultReturned"); + Debug.Console(2, this, "OnDirectoryResultReturned. Result has {0} contacts", result.Contacts.Count); - var directoryResult = new CodecDirectory(); + var directoryResult = result; // If result is Root, create a copy and filter out contacts whose parent folder is not root - if (!CurrentDirectoryResultIsNotDirectoryRoot.BoolValue) - { - Debug.Console(2, this, "Filtering DirectoryRoot to remove contacts for display"); + //if (!CurrentDirectoryResultIsNotDirectoryRoot.BoolValue) + //{ + // Debug.Console(2, this, "Filtering DirectoryRoot to remove contacts for display"); - directoryResult.ResultsFolderId = result.ResultsFolderId; - directoryResult.AddFoldersToDirectory(result.Folders); - directoryResult.AddContactsToDirectory( - result.Contacts.Where((c) => c.ParentFolderId == result.ResultsFolderId).ToList()); - } - else - { - directoryResult = result; - } + // directoryResult.ResultsFolderId = result.ResultsFolderId; + // directoryResult.AddFoldersToDirectory(result.Folders); + // directoryResult.AddContactsToDirectory( + // result.Contacts.Where((c) => c.ParentFolderId == result.ResultsFolderId).ToList()); + //} + //else + //{ + // directoryResult = result; + //} - Debug.Console(2, this, "Updating directoryResult. IsOnRoot: {0}", - !CurrentDirectoryResultIsNotDirectoryRoot.BoolValue); + Debug.Console(2, this, "Updating directoryResult. IsOnRoot: {0} Contact Count: {1}", + !CurrentDirectoryResultIsNotDirectoryRoot.BoolValue, directoryResult.Contacts.Count); // This will return the latest results to all UIs. Multiple indendent UI Directory browsing will require a different methodology var handler = DirectoryResultReturned; @@ -2728,6 +2726,8 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.ZoomRoom DirectoryIsOnRoot = !CurrentDirectoryResultIsNotDirectoryRoot.BoolValue }); } + + CurrentDirectoryResultIsNotDirectoryRoot.FireUpdate(); } catch (Exception e) { From 06fdee313a55f5e6415715a94ea08cb68c856fed Mon Sep 17 00:00:00 2001 From: Neil Dorin Date: Fri, 25 Feb 2022 21:10:44 -0700 Subject: [PATCH 56/59] fix(essentials): adds missing property decorators and unmutes video on camera select --- .../Essentials Devices Common/Cameras/CameraBase.cs | 8 +++++--- .../VideoCodec/ZoomRoom/ZoomRoom.cs | 5 +++++ .../VideoCodec/ZoomRoom/ZoomRoomCamera.cs | 5 ++++- 3 files changed, 14 insertions(+), 4 deletions(-) diff --git a/essentials-framework/Essentials Devices Common/Essentials Devices Common/Cameras/CameraBase.cs b/essentials-framework/Essentials Devices Common/Essentials Devices Common/Cameras/CameraBase.cs index 18a1ad36..1ef679ba 100644 --- a/essentials-framework/Essentials Devices Common/Essentials Devices Common/Cameras/CameraBase.cs +++ b/essentials-framework/Essentials Devices Common/Essentials Devices Common/Cameras/CameraBase.cs @@ -29,6 +29,7 @@ namespace PepperDash.Essentials.Devices.Common.Cameras public abstract class CameraBase : ReconfigurableDevice, IRoutingOutputs { + [JsonProperty("controlMode", NullValueHandling = NullValueHandling.Ignore)] public eCameraControlMode ControlMode { get; protected set; } #region IRoutingOutputs Members @@ -37,6 +38,7 @@ namespace PepperDash.Essentials.Devices.Common.Cameras #endregion + [JsonProperty("canPan", NullValueHandling = NullValueHandling.Ignore)] public bool CanPan { get @@ -44,7 +46,7 @@ namespace PepperDash.Essentials.Devices.Common.Cameras return (Capabilities & eCameraCapabilities.Pan) == eCameraCapabilities.Pan; } } - + [JsonProperty("canTilt", NullValueHandling = NullValueHandling.Ignore)] public bool CanTilt { get @@ -52,7 +54,7 @@ namespace PepperDash.Essentials.Devices.Common.Cameras return (Capabilities & eCameraCapabilities.Tilt) == eCameraCapabilities.Tilt; } } - + [JsonProperty("canZoom", NullValueHandling = NullValueHandling.Ignore)] public bool CanZoom { get @@ -60,7 +62,7 @@ namespace PepperDash.Essentials.Devices.Common.Cameras return (Capabilities & eCameraCapabilities.Zoom) == eCameraCapabilities.Zoom; } } - + [JsonProperty("canFocus", NullValueHandling = NullValueHandling.Ignore)] public bool CanFocus { get diff --git a/essentials-framework/Essentials Devices Common/Essentials Devices Common/VideoCodec/ZoomRoom/ZoomRoom.cs b/essentials-framework/Essentials Devices Common/Essentials Devices Common/VideoCodec/ZoomRoom/ZoomRoom.cs index ffab3ea5..7542594d 100644 --- a/essentials-framework/Essentials Devices Common/Essentials Devices Common/VideoCodec/ZoomRoom/ZoomRoom.cs +++ b/essentials-framework/Essentials Devices Common/Essentials Devices Common/VideoCodec/ZoomRoom/ZoomRoom.cs @@ -342,6 +342,11 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.ZoomRoom { Debug.Console(1, this, "Selected Camera with key: '{0}'", camera.Key); SelectedCamera = camera; + + if (CameraIsMutedFeedback.BoolValue) + { + CameraMuteOff(); + } } else { diff --git a/essentials-framework/Essentials Devices Common/Essentials Devices Common/VideoCodec/ZoomRoom/ZoomRoomCamera.cs b/essentials-framework/Essentials Devices Common/Essentials Devices Common/VideoCodec/ZoomRoom/ZoomRoomCamera.cs index b0fc52fe..4b723ec8 100644 --- a/essentials-framework/Essentials Devices Common/Essentials Devices Common/VideoCodec/ZoomRoom/ZoomRoomCamera.cs +++ b/essentials-framework/Essentials Devices Common/Essentials Devices Common/VideoCodec/ZoomRoom/ZoomRoomCamera.cs @@ -7,6 +7,8 @@ using Crestron.SimplSharpPro.DeviceSupport; using PepperDash.Essentials.Core.Bridges; using PepperDash.Essentials.Devices.Common.Cameras; +using Newtonsoft.Json; + namespace PepperDash.Essentials.Devices.Common.VideoCodec.ZoomRoom { public enum eZoomRoomCameraState @@ -34,7 +36,8 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.ZoomRoom { protected ZoomRoom ParentCodec { get; private set; } - public int Id = 0; // ID of near end selected camara is always 0 + [JsonProperty("id", NullValueHandling = NullValueHandling.Ignore)] + public int? Id = 0; // ID of near end selected camara is always 0 private int ContinueTime = 10; // number of milliseconds between issuing continue commands From 97b9ed5016f9855cd4b0b03f2cd2e19d2244c9f3 Mon Sep 17 00:00:00 2001 From: Neil Dorin Date: Mon, 28 Feb 2022 19:21:27 -0700 Subject: [PATCH 57/59] fix(essentials): Fixes SetupCameras to not add duplicate cameras to the list --- .../VideoCodec/ZoomRoom/ZoomRoom.cs | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/essentials-framework/Essentials Devices Common/Essentials Devices Common/VideoCodec/ZoomRoom/ZoomRoom.cs b/essentials-framework/Essentials Devices Common/Essentials Devices Common/VideoCodec/ZoomRoom/ZoomRoom.cs index 7542594d..f21d2068 100644 --- a/essentials-framework/Essentials Devices Common/Essentials Devices Common/VideoCodec/ZoomRoom/ZoomRoom.cs +++ b/essentials-framework/Essentials Devices Common/Essentials Devices Common/VideoCodec/ZoomRoom/ZoomRoom.cs @@ -1844,6 +1844,8 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.ZoomRoom } case "video camera line": { + Status.Cameras.Clear(); + JsonConvert.PopulateObject(responseObj.ToString(), Status.Cameras); if (!_syncState.CamerasHaveBeenSetUp) @@ -2763,14 +2765,19 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.ZoomRoom continue; } - var camera = new ZoomRoomCamera(cam.id, cam.Name, this); + var existingCam = Cameras.FirstOrDefault((c) => c.Key.Equals(cam.id)); - Cameras.Add(camera); + if (existingCam == null) + { + var camera = new ZoomRoomCamera(cam.id, cam.Name, this); - if (cam.Selected) - { - SelectedCamera = camera; - } + Cameras.Add(camera); + + if (cam.Selected) + { + SelectedCamera = camera; + } + } } if (IsInCall) From 787c8eb954f616a7553a4ad435df5f779140eab5 Mon Sep 17 00:00:00 2001 From: Neil Dorin Date: Tue, 1 Mar 2022 21:43:38 -0700 Subject: [PATCH 58/59] feat(essentials): Adds new interface and event to notify if video unmute is requested --- .../Cameras/CameraControl.cs | 5 +++++ .../VideoCodec/ZoomRoom/ZoomRoom.cs | 12 ++++++++++-- 2 files changed, 15 insertions(+), 2 deletions(-) diff --git a/essentials-framework/Essentials Devices Common/Essentials Devices Common/Cameras/CameraControl.cs b/essentials-framework/Essentials Devices Common/Essentials Devices Common/Cameras/CameraControl.cs index 208b38de..cbf53476 100644 --- a/essentials-framework/Essentials Devices Common/Essentials Devices Common/Cameras/CameraControl.cs +++ b/essentials-framework/Essentials Devices Common/Essentials Devices Common/Cameras/CameraControl.cs @@ -57,6 +57,11 @@ namespace PepperDash.Essentials.Devices.Common.Cameras void CameraMuteToggle(); } + public interface IHasCameraMuteWithUnmuteReqeust : IHasCameraMute + { + event EventHandler VideoUnmuteRequested; + } + public class CameraSelectedEventArgs : EventArgs { public CameraBase SelectedCamera { get; private set; } diff --git a/essentials-framework/Essentials Devices Common/Essentials Devices Common/VideoCodec/ZoomRoom/ZoomRoom.cs b/essentials-framework/Essentials Devices Common/Essentials Devices Common/VideoCodec/ZoomRoom/ZoomRoom.cs index f21d2068..ee3cdc0f 100644 --- a/essentials-framework/Essentials Devices Common/Essentials Devices Common/VideoCodec/ZoomRoom/ZoomRoom.cs +++ b/essentials-framework/Essentials Devices Common/Essentials Devices Common/VideoCodec/ZoomRoom/ZoomRoom.cs @@ -24,11 +24,13 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.ZoomRoom { public class ZoomRoom : VideoCodecBase, IHasCodecSelfView, IHasDirectoryHistoryStack, ICommunicationMonitor, IRouting, - IHasScheduleAwareness, IHasCodecCameras, IHasParticipants, IHasCameraOff, IHasCameraMute, IHasCameraAutoMode, + IHasScheduleAwareness, IHasCodecCameras, IHasParticipants, IHasCameraOff, IHasCameraMuteWithUnmuteReqeust, IHasCameraAutoMode, IHasFarEndContentStatus, IHasSelfviewPosition, IHasPhoneDialing, IHasZoomRoomLayouts, IHasParticipantPinUnpin, IHasParticipantAudioMute, IHasSelfviewSize, IPasswordPrompt, IHasStartMeeting, IHasMeetingInfo, IHasPresentationOnlyMeeting, IHasMeetingLock, IHasMeetingRecording { + public event EventHandler VideoUnmuteRequested; + private const long MeetingRefreshTimer = 60000; public uint DefaultMeetingDurationMin { get; private set; } @@ -1611,7 +1613,13 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.ZoomRoom } case "videounmuterequest": { - // TODO: notify room of a request to unmute video + var handler = VideoUnmuteRequested; + + if (handler != null) + { + handler(this, null); + } + break; } case "meetingneedspassword": From 89dd098ea6ca995861fdc4a0015f5d6fce3a93c0 Mon Sep 17 00:00:00 2001 From: Neil Dorin Date: Thu, 3 Mar 2022 14:39:54 -0700 Subject: [PATCH 59/59] feat(essentials): #912 Updates to GenericCommunicationMonitor to better monitor socket status --- .../Monitoring/GenericCommunicationMonitor.cs | 154 +++++++++++++++--- .../Display/SamsungMDCDisplay.cs | 2 +- 2 files changed, 131 insertions(+), 25 deletions(-) diff --git a/essentials-framework/Essentials Core/PepperDashEssentialsBase/Monitoring/GenericCommunicationMonitor.cs b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Monitoring/GenericCommunicationMonitor.cs index 0d19762f..edb4c31b 100644 --- a/essentials-framework/Essentials Core/PepperDashEssentialsBase/Monitoring/GenericCommunicationMonitor.cs +++ b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Monitoring/GenericCommunicationMonitor.cs @@ -16,11 +16,28 @@ namespace PepperDash.Essentials.Core /// /// Used for monitoring comms that are IBasicCommunication. Will send a poll string and provide an event when /// statuses change. + /// Default monitoring uses TextReceived event on Client. /// public class GenericCommunicationMonitor : StatusMonitorBase { public IBasicCommunication Client { get; private set; } + /// + /// Will monitor Client.BytesReceived if set to true. Otherwise the default is to monitor Client.TextReceived + /// + public bool MonitorBytesReceived { get; private set; } + + /// + /// Return true if the Client is ISocketStatus + /// + public bool IsSocket + { + get + { + return Client is ISocketStatus; + } + } + long PollTime; CTimer PollTimer; string PollString; @@ -46,8 +63,20 @@ namespace PepperDash.Essentials.Core Client = client; PollTime = pollTime; PollString = pollString; + + if (IsSocket) + { + (Client as ISocketStatus).ConnectionChange += new EventHandler(socket_ConnectionChange); + } } + public GenericCommunicationMonitor(IKeyed parent, IBasicCommunication client, long pollTime, + long warningTime, long errorTime, string pollString, bool monitorBytesReceived) : + this(parent, client, pollTime, warningTime, errorTime, pollString) + { + SetMonitorBytesReceived(monitorBytesReceived); + } + /// /// Poll is a provided action instead of string /// @@ -69,6 +98,19 @@ namespace PepperDash.Essentials.Core Client = client; PollTime = pollTime; PollAction = pollAction; + + if (IsSocket) + { + (Client as ISocketStatus).ConnectionChange += new EventHandler(socket_ConnectionChange); + } + + } + + public GenericCommunicationMonitor(IKeyed parent, IBasicCommunication client, long pollTime, + long warningTime, long errorTime, Action pollAction, bool monitorBytesReceived) : + this(parent, client, pollTime, warningTime, errorTime, pollAction) + { + SetMonitorBytesReceived(monitorBytesReceived); } @@ -79,23 +121,96 @@ namespace PepperDash.Essentials.Core CommunicationMonitorConfig props) : this(parent, client, props.PollInterval, props.TimeToWarning, props.TimeToError, props.PollString) { + if (IsSocket) + { + (Client as ISocketStatus).ConnectionChange += new EventHandler(socket_ConnectionChange); + } } + /// + /// Builds the monitor from a config object and takes a bool to specify whether to monitor BytesReceived + /// Default is to monitor TextReceived + /// + /// + /// + /// + /// + public GenericCommunicationMonitor(IKeyed parent, IBasicCommunication client, CommunicationMonitorConfig props, bool monitorBytesReceived) : + this(parent, client, props.PollInterval, props.TimeToWarning, props.TimeToError, props.PollString) + { + SetMonitorBytesReceived(monitorBytesReceived); + } + + void SetMonitorBytesReceived(bool monitorBytesReceived) + { + MonitorBytesReceived = monitorBytesReceived; + } + public override void Start() { - Client.BytesReceived += Client_BytesReceived; - Poll(); - PollTimer = new CTimer(o => Poll(), null, PollTime, PollTime); + if (MonitorBytesReceived) + { + Client.BytesReceived += Client_BytesReceived; + } + else + { + Client.TextReceived += Client_TextReceived; + } + + if (!IsSocket) + { + BeginPolling(); + } } + void socket_ConnectionChange(object sender, GenericSocketStatusChageEventArgs e) + { + if (!e.Client.IsConnected) + { + // Immediately stop polling and notify that device is offline + Stop(); + Status = MonitorStatus.InError; + ResetErrorTimers(); + } + else + { + // Start polling and set status to unknow and let poll result update the status to IsOk when a response is received + Status = MonitorStatus.StatusUnknown; + Start(); + BeginPolling(); + } + } + + void BeginPolling() + { + Poll(); + PollTimer = new CTimer(o => Poll(), null, PollTime, PollTime); + } + public override void Stop() { - Client.BytesReceived -= this.Client_BytesReceived; - PollTimer.Stop(); - PollTimer = null; - StopErrorTimers(); + if(MonitorBytesReceived) + { + Client.BytesReceived -= this.Client_BytesReceived; + } + else + { + Client.TextReceived -= Client_TextReceived; + } + + if (PollTimer != null) + { + PollTimer.Stop(); + PollTimer = null; + StopErrorTimers(); + } } + void Client_TextReceived(object sender, GenericCommMethodReceiveTextArgs e) + { + DataReceived(); + } + /// /// Upon any receipt of data, set everything to ok! /// @@ -103,10 +218,14 @@ namespace PepperDash.Essentials.Core /// void Client_BytesReceived(object sender, GenericCommMethodReceiveBytesArgs e) { - Status = MonitorStatus.IsOk; - ResetErrorTimers(); - // - } + DataReceived(); + } + + void DataReceived() + { + Status = MonitorStatus.IsOk; + ResetErrorTimers(); + } void Poll() { @@ -124,19 +243,6 @@ namespace PepperDash.Essentials.Core Debug.Console(2, this, "Comm not connected"); } } - - /// - /// When the client connects, and we're waiting for it, respond and disconect from event - /// - void OneTimeConnectHandler(object o, EventArgs a) - { - if (Client.IsConnected) - { - //Client.IsConnected -= OneTimeConnectHandler; - Debug.Console(2, this, "Comm connected"); - Poll(); - } - } } diff --git a/essentials-framework/Essentials Devices Common/Essentials Devices Common/Display/SamsungMDCDisplay.cs b/essentials-framework/Essentials Devices Common/Essentials Devices Common/Display/SamsungMDCDisplay.cs index 65e38408..9fcb7295 100644 --- a/essentials-framework/Essentials Devices Common/Essentials Devices Common/Display/SamsungMDCDisplay.cs +++ b/essentials-framework/Essentials Devices Common/Essentials Devices Common/Display/SamsungMDCDisplay.cs @@ -99,7 +99,7 @@ namespace PepperDash.Essentials.Devices.Displays WarmupTime = 10000; CooldownTime = 8000; - CommunicationMonitor = new GenericCommunicationMonitor(this, Communication, 2000, 120000, 300000, StatusGet); + CommunicationMonitor = new GenericCommunicationMonitor(this, Communication, 2000, 120000, 300000, StatusGet, true); DeviceManager.AddDevice(CommunicationMonitor); VolumeIncrementer = new ActionIncrementer(655, 0, 65535, 800, 80,