From 6dd882b1a0d56f57f9229f5e958501a378809442 Mon Sep 17 00:00:00 2001 From: Neil Dorin Date: Wed, 10 Nov 2021 13:49:43 -0700 Subject: [PATCH 01/41] 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/41] 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/41] 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/41] 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/41] 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/41] 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/41] 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/41] 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/41] 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/41] 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/41] 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 b5589364ff90afb4c26234a4015043c068c93545 Mon Sep 17 00:00:00 2001 From: Jonathan Arndt Date: Tue, 8 Feb 2022 12:15:29 -0800 Subject: [PATCH 12/41] 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 13/41] 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 14/41] 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 15/41] 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 16/41] 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 17/41] 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 18/41] 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 19/41] 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 20/41] 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 21/41] 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 22/41] 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 23/41] 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 24/41] 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 25/41] 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 26/41] 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 27/41] 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 28/41] 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 29/41] 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 30/41] 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 31/41] 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 32/41] 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 33/41] 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 34/41] 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 35/41] 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 36/41] 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 b0e3fddec78aefee57713b5a8f46f1efa5767c9e Mon Sep 17 00:00:00 2001 From: Neil Dorin Date: Fri, 11 Feb 2022 15:50:09 -0700 Subject: [PATCH 37/41] 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 38/41] 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 39/41] 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 40/41] 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 41/41] 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;