diff --git a/PepperDashEssentials/UIDrivers/EssentialsHuddleVTC/EssentialsHuddleVtc1PanelAvFunctionsDriver.cs b/PepperDashEssentials/UIDrivers/EssentialsHuddleVTC/EssentialsHuddleVtc1PanelAvFunctionsDriver.cs index 44091362..80fb0ba8 100644 --- a/PepperDashEssentials/UIDrivers/EssentialsHuddleVTC/EssentialsHuddleVtc1PanelAvFunctionsDriver.cs +++ b/PepperDashEssentials/UIDrivers/EssentialsHuddleVTC/EssentialsHuddleVtc1PanelAvFunctionsDriver.cs @@ -493,10 +493,10 @@ namespace PepperDash.Essentials // and the LastMeetingDismissed != this meeting var lastMeetingDismissed = meetings.FirstOrDefault(m => m.Id == LastMeetingDismissedId); - Debug.Console(0, "*#* Room on: {0}, lastMeetingDismissedId: {1} {2} *#*", - CurrentRoom.OnFeedback.BoolValue, - LastMeetingDismissedId, - lastMeetingDismissed != null ? lastMeetingDismissed.StartTime.ToString("t", Global.Culture) : ""); + //Debug.Console(0, "*#* Room on: {0}, lastMeetingDismissedId: {1} {2} *#*", + // CurrentRoom.OnFeedback.BoolValue, + // LastMeetingDismissedId, + // lastMeetingDismissed != null ? lastMeetingDismissed.StartTime.ToString("t", Global.Culture) : ""); var meeting = meetings.LastOrDefault(m => m.Joinable); if (CurrentRoom.OnFeedback.BoolValue diff --git a/PepperDashEssentials/UIDrivers/JoinedSigInterlock.cs b/PepperDashEssentials/UIDrivers/JoinedSigInterlock.cs index 04e01eb0..a7dba246 100644 --- a/PepperDashEssentials/UIDrivers/JoinedSigInterlock.cs +++ b/PepperDashEssentials/UIDrivers/JoinedSigInterlock.cs @@ -52,7 +52,7 @@ namespace PepperDash.Essentials { var prevJoin = CurrentJoin; var wasShown = _IsShown; - Debug.Console(2, "Trilist {0:X2}, interlock swapping {1} for {2}", TriList.ID, CurrentJoin, join); + //Debug.Console(2, "Trilist {0:X2}, interlock swapping {1} for {2}", TriList.ID, CurrentJoin, join); if (CurrentJoin == join && TriList.BooleanInput[join].BoolValue) return; SetButDontShow(join); @@ -71,7 +71,7 @@ namespace PepperDash.Essentials var prevJoin = CurrentJoin; var wasShown = IsShown; - Debug.Console(2, "Trilist {0:X2}, interlock swapping {1} for {2}", TriList.ID, CurrentJoin, join); + //Debug.Console(2, "Trilist {0:X2}, interlock swapping {1} for {2}", TriList.ID, CurrentJoin, join); if (CurrentJoin == join) HideAndClear(); else @@ -92,7 +92,7 @@ namespace PepperDash.Essentials { var prevJoin = CurrentJoin; var wasShown = IsShown; - Debug.Console(2, "Trilist {0:X2}, interlock hiding {1}", TriList.ID, CurrentJoin); + //Debug.Console(2, "Trilist {0:X2}, interlock hiding {1}", TriList.ID, CurrentJoin); Hide(); CurrentJoin = 0; @@ -108,7 +108,7 @@ namespace PepperDash.Essentials var prevJoin = CurrentJoin; var wasShown = IsShown; - Debug.Console(2, "Trilist {0:X2}, interlock hiding {1}", TriList.ID, CurrentJoin); + //Debug.Console(2, "Trilist {0:X2}, interlock hiding {1}", TriList.ID, CurrentJoin); if (CurrentJoin > 0) { TriList.BooleanInput[CurrentJoin].BoolValue = false; @@ -125,7 +125,7 @@ namespace PepperDash.Essentials var prevJoin = CurrentJoin; var wasShown = IsShown; - Debug.Console(2, "Trilist {0:X2}, interlock showing {1}", TriList.ID, CurrentJoin); + //Debug.Console(2, "Trilist {0:X2}, interlock showing {1}", TriList.ID, CurrentJoin); if (CurrentJoin > 0) { TriList.BooleanInput[CurrentJoin].BoolValue = true; diff --git a/PepperDashEssentials/UIDrivers/ScreenSaverController.cs b/PepperDashEssentials/UIDrivers/ScreenSaverController.cs index 0f75e2a2..11ce587a 100644 --- a/PepperDashEssentials/UIDrivers/ScreenSaverController.cs +++ b/PepperDashEssentials/UIDrivers/ScreenSaverController.cs @@ -51,7 +51,7 @@ namespace PepperDash.Essentials public override void Show() { - Debug.Console(2, "Showing ScreenSaverController: {0:X2}", TriList.ID); + //Debug.Console(2, "Showing ScreenSaverController: {0:X2}", TriList.ID); if (_parent.AvDriver != null) { @@ -67,11 +67,11 @@ namespace PepperDash.Essentials public override void Hide() { - Debug.Console(2, "Hiding ScreenSaverController: {0:X2}", TriList.ID); + //Debug.Console(2, "Hiding ScreenSaverController: {0:X2}", TriList.ID); if (PositionTimer != null) { - Debug.Console(2, "Stopping PositionTimer: {0:X2}", TriList.ID); + //Debug.Console(2, "Stopping PositionTimer: {0:X2}", TriList.ID); PositionTimer.Stop(); PositionTimer.Dispose(); PositionTimer = null; @@ -89,7 +89,7 @@ namespace PepperDash.Essentials void StartPositionTimer() { - Debug.Console(2, "Starting Position Timer: {0:X2}", TriList.ID); + //Debug.Console(2, "Starting Position Timer: {0:X2}", TriList.ID); if (PositionTimer == null) { @@ -122,7 +122,7 @@ namespace PepperDash.Essentials CurrentPositionIndex = 0; } - Debug.Console(2, "ScreenSaver Position Timer Expired: Setting new position: {0} ID: {1:X2}", CurrentPositionIndex, TriList.ID); + //Debug.Console(2, "ScreenSaver Position Timer Expired: Setting new position: {0} ID: {1:X2}", CurrentPositionIndex, TriList.ID); } // @@ -134,7 +134,7 @@ namespace PepperDash.Essentials void ClearAllPositions() { - Debug.Console(2, "Hiding all screensaver positions: {0:X2}", TriList.ID); + //Debug.Console(2, "Hiding all screensaver positions: {0:X2}", TriList.ID); PositionInterlock.HideAndClear(); } diff --git a/essentials-framework/Essentials Core/PepperDashEssentialsBase/Monitoring/GenericCommunicationMonitor.cs b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Monitoring/GenericCommunicationMonitor.cs index 0d19762f..edb4c31b 100644 --- a/essentials-framework/Essentials Core/PepperDashEssentialsBase/Monitoring/GenericCommunicationMonitor.cs +++ b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Monitoring/GenericCommunicationMonitor.cs @@ -16,11 +16,28 @@ namespace PepperDash.Essentials.Core /// /// Used for monitoring comms that are IBasicCommunication. Will send a poll string and provide an event when /// statuses change. + /// Default monitoring uses TextReceived event on Client. /// public class GenericCommunicationMonitor : StatusMonitorBase { public IBasicCommunication Client { get; private set; } + /// + /// Will monitor Client.BytesReceived if set to true. Otherwise the default is to monitor Client.TextReceived + /// + public bool MonitorBytesReceived { get; private set; } + + /// + /// Return true if the Client is ISocketStatus + /// + public bool IsSocket + { + get + { + return Client is ISocketStatus; + } + } + long PollTime; CTimer PollTimer; string PollString; @@ -46,8 +63,20 @@ namespace PepperDash.Essentials.Core Client = client; PollTime = pollTime; PollString = pollString; + + if (IsSocket) + { + (Client as ISocketStatus).ConnectionChange += new EventHandler(socket_ConnectionChange); + } } + public GenericCommunicationMonitor(IKeyed parent, IBasicCommunication client, long pollTime, + long warningTime, long errorTime, string pollString, bool monitorBytesReceived) : + this(parent, client, pollTime, warningTime, errorTime, pollString) + { + SetMonitorBytesReceived(monitorBytesReceived); + } + /// /// Poll is a provided action instead of string /// @@ -69,6 +98,19 @@ namespace PepperDash.Essentials.Core Client = client; PollTime = pollTime; PollAction = pollAction; + + if (IsSocket) + { + (Client as ISocketStatus).ConnectionChange += new EventHandler(socket_ConnectionChange); + } + + } + + public GenericCommunicationMonitor(IKeyed parent, IBasicCommunication client, long pollTime, + long warningTime, long errorTime, Action pollAction, bool monitorBytesReceived) : + this(parent, client, pollTime, warningTime, errorTime, pollAction) + { + SetMonitorBytesReceived(monitorBytesReceived); } @@ -79,23 +121,96 @@ namespace PepperDash.Essentials.Core CommunicationMonitorConfig props) : this(parent, client, props.PollInterval, props.TimeToWarning, props.TimeToError, props.PollString) { + if (IsSocket) + { + (Client as ISocketStatus).ConnectionChange += new EventHandler(socket_ConnectionChange); + } } + /// + /// Builds the monitor from a config object and takes a bool to specify whether to monitor BytesReceived + /// Default is to monitor TextReceived + /// + /// + /// + /// + /// + public GenericCommunicationMonitor(IKeyed parent, IBasicCommunication client, CommunicationMonitorConfig props, bool monitorBytesReceived) : + this(parent, client, props.PollInterval, props.TimeToWarning, props.TimeToError, props.PollString) + { + SetMonitorBytesReceived(monitorBytesReceived); + } + + void SetMonitorBytesReceived(bool monitorBytesReceived) + { + MonitorBytesReceived = monitorBytesReceived; + } + public override void Start() { - Client.BytesReceived += Client_BytesReceived; - Poll(); - PollTimer = new CTimer(o => Poll(), null, PollTime, PollTime); + if (MonitorBytesReceived) + { + Client.BytesReceived += Client_BytesReceived; + } + else + { + Client.TextReceived += Client_TextReceived; + } + + if (!IsSocket) + { + BeginPolling(); + } } + void socket_ConnectionChange(object sender, GenericSocketStatusChageEventArgs e) + { + if (!e.Client.IsConnected) + { + // Immediately stop polling and notify that device is offline + Stop(); + Status = MonitorStatus.InError; + ResetErrorTimers(); + } + else + { + // Start polling and set status to unknow and let poll result update the status to IsOk when a response is received + Status = MonitorStatus.StatusUnknown; + Start(); + BeginPolling(); + } + } + + void BeginPolling() + { + Poll(); + PollTimer = new CTimer(o => Poll(), null, PollTime, PollTime); + } + public override void Stop() { - Client.BytesReceived -= this.Client_BytesReceived; - PollTimer.Stop(); - PollTimer = null; - StopErrorTimers(); + if(MonitorBytesReceived) + { + Client.BytesReceived -= this.Client_BytesReceived; + } + else + { + Client.TextReceived -= Client_TextReceived; + } + + if (PollTimer != null) + { + PollTimer.Stop(); + PollTimer = null; + StopErrorTimers(); + } } + void Client_TextReceived(object sender, GenericCommMethodReceiveTextArgs e) + { + DataReceived(); + } + /// /// Upon any receipt of data, set everything to ok! /// @@ -103,10 +218,14 @@ namespace PepperDash.Essentials.Core /// void Client_BytesReceived(object sender, GenericCommMethodReceiveBytesArgs e) { - Status = MonitorStatus.IsOk; - ResetErrorTimers(); - // - } + DataReceived(); + } + + void DataReceived() + { + Status = MonitorStatus.IsOk; + ResetErrorTimers(); + } void Poll() { @@ -124,19 +243,6 @@ namespace PepperDash.Essentials.Core Debug.Console(2, this, "Comm not connected"); } } - - /// - /// When the client connects, and we're waiting for it, respond and disconect from event - /// - void OneTimeConnectHandler(object o, EventArgs a) - { - if (Client.IsConnected) - { - //Client.IsConnected -= OneTimeConnectHandler; - Debug.Console(2, this, "Comm connected"); - Poll(); - } - } } diff --git a/essentials-framework/Essentials Devices Common/Essentials Devices Common/Cameras/CameraBase.cs b/essentials-framework/Essentials Devices Common/Essentials Devices Common/Cameras/CameraBase.cs index 18a1ad36..1ef679ba 100644 --- a/essentials-framework/Essentials Devices Common/Essentials Devices Common/Cameras/CameraBase.cs +++ b/essentials-framework/Essentials Devices Common/Essentials Devices Common/Cameras/CameraBase.cs @@ -29,6 +29,7 @@ namespace PepperDash.Essentials.Devices.Common.Cameras public abstract class CameraBase : ReconfigurableDevice, IRoutingOutputs { + [JsonProperty("controlMode", NullValueHandling = NullValueHandling.Ignore)] public eCameraControlMode ControlMode { get; protected set; } #region IRoutingOutputs Members @@ -37,6 +38,7 @@ namespace PepperDash.Essentials.Devices.Common.Cameras #endregion + [JsonProperty("canPan", NullValueHandling = NullValueHandling.Ignore)] public bool CanPan { get @@ -44,7 +46,7 @@ namespace PepperDash.Essentials.Devices.Common.Cameras return (Capabilities & eCameraCapabilities.Pan) == eCameraCapabilities.Pan; } } - + [JsonProperty("canTilt", NullValueHandling = NullValueHandling.Ignore)] public bool CanTilt { get @@ -52,7 +54,7 @@ namespace PepperDash.Essentials.Devices.Common.Cameras return (Capabilities & eCameraCapabilities.Tilt) == eCameraCapabilities.Tilt; } } - + [JsonProperty("canZoom", NullValueHandling = NullValueHandling.Ignore)] public bool CanZoom { get @@ -60,7 +62,7 @@ namespace PepperDash.Essentials.Devices.Common.Cameras return (Capabilities & eCameraCapabilities.Zoom) == eCameraCapabilities.Zoom; } } - + [JsonProperty("canFocus", NullValueHandling = NullValueHandling.Ignore)] public bool CanFocus { get diff --git a/essentials-framework/Essentials Devices Common/Essentials Devices Common/Cameras/CameraControl.cs b/essentials-framework/Essentials Devices Common/Essentials Devices Common/Cameras/CameraControl.cs index 208b38de..cbf53476 100644 --- a/essentials-framework/Essentials Devices Common/Essentials Devices Common/Cameras/CameraControl.cs +++ b/essentials-framework/Essentials Devices Common/Essentials Devices Common/Cameras/CameraControl.cs @@ -57,6 +57,11 @@ namespace PepperDash.Essentials.Devices.Common.Cameras void CameraMuteToggle(); } + public interface IHasCameraMuteWithUnmuteReqeust : IHasCameraMute + { + event EventHandler VideoUnmuteRequested; + } + public class CameraSelectedEventArgs : EventArgs { public CameraBase SelectedCamera { get; private set; } diff --git a/essentials-framework/Essentials Devices Common/Essentials Devices Common/Codec/iHasDirectory.cs b/essentials-framework/Essentials Devices Common/Essentials Devices Common/Codec/iHasDirectory.cs index 642f03d0..57dbbd6b 100644 --- a/essentials-framework/Essentials Devices Common/Essentials Devices Common/Codec/iHasDirectory.cs +++ b/essentials-framework/Essentials Devices Common/Essentials Devices Common/Codec/iHasDirectory.cs @@ -65,8 +65,9 @@ namespace PepperDash.Essentials.Devices.Common.Codec { /// /// Represents the contents of the directory + /// We don't want to serialize this for messages to MobileControl. MC can combine Contacts and Folders to get the same data /// - [JsonProperty("directoryResults")] + [JsonIgnore] public List CurrentDirectoryResults { get; private set; } [JsonProperty("contacts")] diff --git a/essentials-framework/Essentials Devices Common/Essentials Devices Common/Display/SamsungMDCDisplay.cs b/essentials-framework/Essentials Devices Common/Essentials Devices Common/Display/SamsungMDCDisplay.cs index 65e38408..9fcb7295 100644 --- a/essentials-framework/Essentials Devices Common/Essentials Devices Common/Display/SamsungMDCDisplay.cs +++ b/essentials-framework/Essentials Devices Common/Essentials Devices Common/Display/SamsungMDCDisplay.cs @@ -99,7 +99,7 @@ namespace PepperDash.Essentials.Devices.Displays WarmupTime = 10000; CooldownTime = 8000; - CommunicationMonitor = new GenericCommunicationMonitor(this, Communication, 2000, 120000, 300000, StatusGet); + CommunicationMonitor = new GenericCommunicationMonitor(this, Communication, 2000, 120000, 300000, StatusGet, true); DeviceManager.AddDevice(CommunicationMonitor); VolumeIncrementer = new ActionIncrementer(655, 0, 65535, 800, 80, diff --git a/essentials-framework/Essentials Devices Common/Essentials Devices Common/VideoCodec/CiscoCodec/CiscoSparkCodec.cs b/essentials-framework/Essentials Devices Common/Essentials Devices Common/VideoCodec/CiscoCodec/CiscoSparkCodec.cs index edcc61ec..c9e584d3 100644 --- a/essentials-framework/Essentials Devices Common/Essentials Devices Common/VideoCodec/CiscoCodec/CiscoSparkCodec.cs +++ b/essentials-framework/Essentials Devices Common/Essentials Devices Common/VideoCodec/CiscoCodec/CiscoSparkCodec.cs @@ -359,7 +359,8 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.Cisco } else { - CommunicationMonitor = new GenericCommunicationMonitor(this, Communication, 30000, 120000, 300000, "xStatus SystemUnit Software Version\r\n"); + var command = string.Format("xCommand Peripherals HeartBeat ID: {0}{1}", CrestronEthernetHelper.ETHERNET_PARAMETER_TO_GET.GET_MAC_ADDRESS, Delimiter); + CommunicationMonitor = new GenericCommunicationMonitor(this, Communication, 30000, 120000, 300000, command); } if (props.Sharing != null) diff --git a/essentials-framework/Essentials Devices Common/Essentials Devices Common/VideoCodec/ZoomRoom/ZoomRoom.cs b/essentials-framework/Essentials Devices Common/Essentials Devices Common/VideoCodec/ZoomRoom/ZoomRoom.cs index 6ea90c80..ee3cdc0f 100644 --- a/essentials-framework/Essentials Devices Common/Essentials Devices Common/VideoCodec/ZoomRoom/ZoomRoom.cs +++ b/essentials-framework/Essentials Devices Common/Essentials Devices Common/VideoCodec/ZoomRoom/ZoomRoom.cs @@ -24,23 +24,25 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.ZoomRoom { public class ZoomRoom : VideoCodecBase, IHasCodecSelfView, IHasDirectoryHistoryStack, ICommunicationMonitor, IRouting, - IHasScheduleAwareness, IHasCodecCameras, IHasParticipants, IHasCameraOff, IHasCameraMute, IHasCameraAutoMode, + IHasScheduleAwareness, IHasCodecCameras, IHasParticipants, IHasCameraOff, IHasCameraMuteWithUnmuteReqeust, IHasCameraAutoMode, IHasFarEndContentStatus, IHasSelfviewPosition, IHasPhoneDialing, IHasZoomRoomLayouts, IHasParticipantPinUnpin, IHasParticipantAudioMute, IHasSelfviewSize, IPasswordPrompt, IHasStartMeeting, IHasMeetingInfo, IHasPresentationOnlyMeeting, IHasMeetingLock, IHasMeetingRecording { + public event EventHandler VideoUnmuteRequested; + private const long MeetingRefreshTimer = 60000; public uint DefaultMeetingDurationMin { get; private set; } /// - /// CR LF + /// CR LF CR LF Delimits an echoed response to a command /// private const string EchoDelimiter = "\x0D\x0A\x0D\x0A"; private const string SendDelimiter = "\x0D"; /// - /// CR LF } CR LF + /// CR LF } CR LF Delimits a JSON response /// private const string JsonDelimiter = "\x0D\x0A\x7D\x0D\x0A"; @@ -342,6 +344,11 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.ZoomRoom { Debug.Console(1, this, "Selected Camera with key: '{0}'", camera.Key); SelectedCamera = camera; + + if (CameraIsMutedFeedback.BoolValue) + { + CameraMuteOff(); + } } else { @@ -400,10 +407,8 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.ZoomRoom { _currentDirectoryResult = value; - Debug.Console(2, this, "CurrentDirectoryResult Updated. ResultsFolderId: {0}", - _currentDirectoryResult.ResultsFolderId); - - CurrentDirectoryResultIsNotDirectoryRoot.FireUpdate(); + Debug.Console(2, this, "CurrentDirectoryResult Updated. ResultsFolderId: {0} Contact Count: {1}", + _currentDirectoryResult.ResultsFolderId, _currentDirectoryResult.CurrentDirectoryResults.Count); OnDirectoryResultReturned(_currentDirectoryResult); } @@ -1305,6 +1310,9 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.ZoomRoom // This result will always be the complete contents of the directory and never // A subset of the results via a search + // Clear out any existing data + Status.Phonebook = new zStatus.Phonebook(); + JsonConvert.PopulateObject(responseObj.ToString(), Status.Phonebook); var directoryResults = @@ -1318,10 +1326,7 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.ZoomRoom PhonebookSyncState.SetNumberOfContacts(Status.Phonebook.Contacts.Count); } - if (directoryResults.ResultsFolderId != "root") - { - directoryResults.ResultsFolderId = "root"; - } + directoryResults.ResultsFolderId = "root"; DirectoryRoot = directoryResults; @@ -1608,7 +1613,13 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.ZoomRoom } case "videounmuterequest": { - // TODO: notify room of a request to unmute video + var handler = VideoUnmuteRequested; + + if (handler != null) + { + handler(this, null); + } + break; } case "meetingneedspassword": @@ -1841,6 +1852,8 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.ZoomRoom } case "video camera line": { + Status.Cameras.Clear(); + JsonConvert.PopulateObject(responseObj.ToString(), Status.Cameras); if (!_syncState.CamerasHaveBeenSetUp) @@ -2696,27 +2709,27 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.ZoomRoom { try { - Debug.Console(2, this, "OnDirectoryResultReturned"); + Debug.Console(2, this, "OnDirectoryResultReturned. Result has {0} contacts", result.Contacts.Count); - var directoryResult = new CodecDirectory(); + var directoryResult = result; // If result is Root, create a copy and filter out contacts whose parent folder is not root - if (!CurrentDirectoryResultIsNotDirectoryRoot.BoolValue) - { - Debug.Console(2, this, "Filtering DirectoryRoot to remove contacts for display"); + //if (!CurrentDirectoryResultIsNotDirectoryRoot.BoolValue) + //{ + // Debug.Console(2, this, "Filtering DirectoryRoot to remove contacts for display"); - directoryResult.ResultsFolderId = result.ResultsFolderId; - directoryResult.AddFoldersToDirectory(result.Folders); - directoryResult.AddContactsToDirectory( - result.Contacts.Where((c) => c.ParentFolderId == result.ResultsFolderId).ToList()); - } - else - { - directoryResult = result; - } + // directoryResult.ResultsFolderId = result.ResultsFolderId; + // directoryResult.AddFoldersToDirectory(result.Folders); + // directoryResult.AddContactsToDirectory( + // result.Contacts.Where((c) => c.ParentFolderId == result.ResultsFolderId).ToList()); + //} + //else + //{ + // directoryResult = result; + //} - Debug.Console(2, this, "Updating directoryResult. IsOnRoot: {0}", - !CurrentDirectoryResultIsNotDirectoryRoot.BoolValue); + Debug.Console(2, this, "Updating directoryResult. IsOnRoot: {0} Contact Count: {1}", + !CurrentDirectoryResultIsNotDirectoryRoot.BoolValue, directoryResult.Contacts.Count); // This will return the latest results to all UIs. Multiple indendent UI Directory browsing will require a different methodology var handler = DirectoryResultReturned; @@ -2728,6 +2741,8 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.ZoomRoom DirectoryIsOnRoot = !CurrentDirectoryResultIsNotDirectoryRoot.BoolValue }); } + + CurrentDirectoryResultIsNotDirectoryRoot.FireUpdate(); } catch (Exception e) { @@ -2758,14 +2773,19 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.ZoomRoom continue; } - var camera = new ZoomRoomCamera(cam.id, cam.Name, this); + var existingCam = Cameras.FirstOrDefault((c) => c.Key.Equals(cam.id)); - Cameras.Add(camera); + if (existingCam == null) + { + var camera = new ZoomRoomCamera(cam.id, cam.Name, this); - if (cam.Selected) - { - SelectedCamera = camera; - } + Cameras.Add(camera); + + if (cam.Selected) + { + SelectedCamera = camera; + } + } } if (IsInCall) diff --git a/essentials-framework/Essentials Devices Common/Essentials Devices Common/VideoCodec/ZoomRoom/ZoomRoomCamera.cs b/essentials-framework/Essentials Devices Common/Essentials Devices Common/VideoCodec/ZoomRoom/ZoomRoomCamera.cs index b0fc52fe..4b723ec8 100644 --- a/essentials-framework/Essentials Devices Common/Essentials Devices Common/VideoCodec/ZoomRoom/ZoomRoomCamera.cs +++ b/essentials-framework/Essentials Devices Common/Essentials Devices Common/VideoCodec/ZoomRoom/ZoomRoomCamera.cs @@ -7,6 +7,8 @@ using Crestron.SimplSharpPro.DeviceSupport; using PepperDash.Essentials.Core.Bridges; using PepperDash.Essentials.Devices.Common.Cameras; +using Newtonsoft.Json; + namespace PepperDash.Essentials.Devices.Common.VideoCodec.ZoomRoom { public enum eZoomRoomCameraState @@ -34,7 +36,8 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.ZoomRoom { protected ZoomRoom ParentCodec { get; private set; } - public int Id = 0; // ID of near end selected camara is always 0 + [JsonProperty("id", NullValueHandling = NullValueHandling.Ignore)] + public int? Id = 0; // ID of near end selected camara is always 0 private int ContinueTime = 10; // number of milliseconds between issuing continue commands