Refator: Refactor timer implementation across multiple classes to use System.Timers.Timer instead of CTimer for improved consistency and performance.

- Updated RelayControlledShade to utilize Timer for output pulsing.
- Refactored MockVC to replace CTimer with Timer for call status simulation.
- Modified VideoCodecBase to enhance documentation and improve feedback handling.
- Removed obsolete IHasCamerasMessenger and updated related classes to use IHasCamerasWithControls.
- Adjusted PressAndHoldHandler to implement Timer for button hold actions.
- Enhanced logging throughout MobileControl and RoomBridges for better debugging and information tracking.
- Cleaned up unnecessary comments and improved exception handling in various classes.
This commit is contained in:
Neil Dorin 2026-03-30 11:44:15 -06:00
parent b4d53dbe0e
commit 7076eafc21
56 changed files with 1343 additions and 2197 deletions

View file

@ -1,100 +0,0 @@
using Newtonsoft.Json;
using PepperDash.Essentials.Devices.Common.Cameras;
using System;
using System.Collections.Generic;
namespace PepperDash.Essentials.AppServer.Messengers
{
/// <summary>
/// Messenger for devices that implement the IHasCameras interface.
/// </summary>
[Obsolete("Use IHasCamerasWithControlsMessenger instead. This class will be removed in a future version")]
public class IHasCamerasMessenger : MessengerBase
{
/// <summary>
/// Device being bridged that implements IHasCameras interface.
/// </summary>
public IHasCameras CameraController { get; private set; }
/// <summary>
/// Messenger for devices that implement IHasCameras interface.
/// </summary>
/// <param name="key"></param>
/// <param name="cameraController"></param>
/// <param name="messagePath"></param>
/// <exception cref="ArgumentNullException"></exception>
public IHasCamerasMessenger(string key, string messagePath, IHasCameras cameraController)
: base(key, messagePath, cameraController)
{
CameraController = cameraController ?? throw new ArgumentNullException("cameraController");
CameraController.CameraSelected += CameraController_CameraSelected;
}
private void CameraController_CameraSelected(object sender, CameraSelectedEventArgs e)
{
PostStatusMessage(new IHasCamerasStateMessage
{
SelectedCamera = e.SelectedCamera
});
}
/// <summary>
/// Registers the actions for this messenger.
/// </summary>
/// <exception cref="ArgumentException"></exception>
protected override void RegisterActions()
{
base.RegisterActions();
AddAction("/fullStatus", (id, context) => SendFullStatus(id));
AddAction("/cameraListStatus", (id, content) => SendFullStatus(id));
AddAction("/selectCamera", (id, content) =>
{
var cameraKey = content?.ToObject<string>();
if (!string.IsNullOrEmpty(cameraKey))
{
CameraController.SelectCamera(cameraKey);
}
else
{
throw new ArgumentException("Content must be a string representing the camera key");
}
});
}
private void SendFullStatus(string clientId)
{
var state = new IHasCamerasStateMessage
{
CameraList = CameraController.Cameras,
SelectedCamera = CameraController.SelectedCamera
};
PostStatusMessage(state, clientId);
}
}
/// <summary>
/// State message for devices that implement the IHasCameras interface.
/// </summary>
public class IHasCamerasStateMessage : DeviceStateMessageBase
{
/// <summary>
/// List of cameras available in the device.
/// </summary>
[JsonProperty("cameraList", NullValueHandling = NullValueHandling.Ignore)]
public List<CameraBase> CameraList { get; set; }
/// <summary>
/// The currently selected camera on the device.
/// </summary>
[JsonProperty("selectedCamera", NullValueHandling = NullValueHandling.Ignore)]
public CameraBase SelectedCamera { get; set; }
}
}

View file

@ -285,7 +285,6 @@ namespace PepperDash.Essentials.AppServer.Messengers
{
try
{
//Debug.Console(2, this, "*********************Setting DeviceStateMessageProperties on MobileControlResponseMessage");
deviceState.SetInterfaces(_deviceInterfaces);
deviceState.Key = _device.Key;

View file

@ -1,6 +1,6 @@
using System;
using System.Collections.Generic;
using Crestron.SimplSharp;
using System.Timers;
using Newtonsoft.Json.Linq;
using PepperDash.Core;
@ -13,7 +13,7 @@ namespace PepperDash.Essentials.AppServer.Messengers
{
private const long ButtonHeartbeatInterval = 1000;
private static readonly Dictionary<string, CTimer> _pushedActions = new Dictionary<string, CTimer>();
private static readonly Dictionary<string, Timer> _pushedActions = new Dictionary<string, Timer>();
private static readonly Dictionary<string, Action<string, Action<bool>>> _pushedActionHandlers;
@ -31,7 +31,7 @@ namespace PepperDash.Essentials.AppServer.Messengers
{
Debug.LogDebug("Attempting to add timer for {deviceKey}", deviceKey);
if (_pushedActions.TryGetValue(deviceKey, out CTimer cancelTimer))
if (_pushedActions.TryGetValue(deviceKey, out Timer cancelTimer))
{
Debug.LogDebug("Timer for {deviceKey} already exists", deviceKey);
return;
@ -41,14 +41,16 @@ namespace PepperDash.Essentials.AppServer.Messengers
action(true);
cancelTimer = new CTimer(o =>
cancelTimer = new Timer(ButtonHeartbeatInterval) { AutoReset = false };
cancelTimer.Elapsed += (s, e) =>
{
Debug.LogDebug("Timer expired for {deviceKey}", deviceKey);
action(false);
_pushedActions.Remove(deviceKey);
}, ButtonHeartbeatInterval);
};
cancelTimer.Start();
_pushedActions.Add(deviceKey, cancelTimer);
}
@ -57,7 +59,7 @@ namespace PepperDash.Essentials.AppServer.Messengers
{
Debug.LogDebug("Attempting to reset timer for {deviceKey}", deviceKey);
if (!_pushedActions.TryGetValue(deviceKey, out CTimer cancelTimer))
if (!_pushedActions.TryGetValue(deviceKey, out Timer cancelTimer))
{
Debug.LogDebug("Timer for {deviceKey} not found", deviceKey);
return;
@ -65,14 +67,16 @@ namespace PepperDash.Essentials.AppServer.Messengers
Debug.LogDebug("Resetting timer for {deviceKey} with due time {dueTime}", deviceKey, ButtonHeartbeatInterval);
cancelTimer.Reset(ButtonHeartbeatInterval);
cancelTimer.Stop();
cancelTimer.Interval = ButtonHeartbeatInterval;
cancelTimer.Start();
}
private static void StopTimer(string deviceKey, Action<bool> action)
{
Debug.LogDebug("Attempting to stop timer for {deviceKey}", deviceKey);
if (!_pushedActions.TryGetValue(deviceKey, out CTimer cancelTimer))
if (!_pushedActions.TryGetValue(deviceKey, out Timer cancelTimer))
{
Debug.LogDebug("Timer for {deviceKey} not found", deviceKey);
return;
@ -85,6 +89,11 @@ namespace PepperDash.Essentials.AppServer.Messengers
_pushedActions.Remove(deviceKey);
}
/// <summary>
/// Gets the handler for a given press and hold message type
/// </summary>
/// <param name="value">The press and hold message type.</param>
/// <returns>The handler for the specified message type.</returns>
public static Action<string, Action<bool>> GetPressAndHoldHandler(string value)
{
Debug.LogDebug("Getting press and hold handler for {value}", value);

View file

@ -33,7 +33,7 @@ namespace PepperDash.Essentials.AppServer.Messengers
protected override void RegisterActions()
{
Debug.Console(2, "********** Direct Route Messenger CustomRegisterWithAppServer **********");
this.LogDebug("Direct Route Messenger CustomRegisterWithAppServer **********");
//Audio source
@ -81,7 +81,7 @@ namespace PepperDash.Essentials.AppServer.Messengers
{
var b = content.ToObject<MobileControlSimpleContent<bool>>();
Debug.Console(1, "Current Sharing Mode: {2}\r\nadvanced sharing mode: {0} join number: {1}", b.Value,
this.LogDebug("Current Sharing Mode: {2}\r\nadvanced sharing mode: {0} join number: {1}", b.Value,
JoinMap.AdvancedSharingModeOn.JoinNumber,
_eisc.BooleanOutput[JoinMap.AdvancedSharingModeOn.JoinNumber].BoolValue);

View file

@ -255,10 +255,10 @@ namespace PepperDash.Essentials.AppServer.Messengers
_eisc.SetUshort(JoinMap.DirectorySelectRow.JoinNumber, u);
_eisc.PulseBool(JoinMap.DirectoryLineSelected.JoinNumber);
}
catch (Exception)
catch (Exception e)
{
Debug.Console(1, this, Debug.ErrorLogLevel.Warning,
"/directoryById request contains non-numeric ID incompatible with SIMPL bridge");
this.LogException(e,"directoryById request contains non-numeric ID incompatible with SIMPL bridge: {0}", e.Message);
this.LogVerbose("Stack Trace:\r{0}", e.StackTrace);
}
});
AddAction("/directorySelectContact", (id, content) =>
@ -270,9 +270,10 @@ namespace PepperDash.Essentials.AppServer.Messengers
_eisc.SetUshort(JoinMap.DirectorySelectRow.JoinNumber, u);
_eisc.PulseBool(JoinMap.DirectoryLineSelected.JoinNumber);
}
catch
catch (Exception e)
{
Debug.Console(2, this, "Error parsing contact from {0} for path /directorySelectContact", s);
this.LogException(e, "Error parsing contact from {0} for path /directorySelectContact", s.Value);
this.LogVerbose("Stack Trace:\r{0}", e.StackTrace);
}
});
AddAction("/directoryDialContact",

View file

@ -40,7 +40,6 @@ namespace PepperDash.Essentials.AppServer.Messengers
{
if (e.ProgramInfo != null)
{
//Debug.Console(1, "Posting Status Message: {0}", e.ProgramInfo.ToString());
PostStatusMessage(JToken.FromObject(e.ProgramInfo)
);
}

View file

@ -431,7 +431,7 @@ namespace PepperDash.Essentials.AppServer.Messengers
}
private void CameraCodec_CameraSelected(object sender, CameraSelectedEventArgs e)
private void CameraCodec_CameraSelected(object sender, CameraSelectedEventArgs<IHasCameraControls> e)
{
try
{
@ -449,7 +449,7 @@ namespace PepperDash.Essentials.AppServer.Messengers
/// </summary>
private void MapCameraActions()
{
if (Codec is IHasCameras cameraCodec && cameraCodec.SelectedCamera != null)
if (Codec is IHasCamerasWithControls cameraCodec && cameraCodec.SelectedCamera != null)
{
RemoveAction("/cameraUp");
RemoveAction("/cameraDown");
@ -764,7 +764,7 @@ namespace PepperDash.Essentials.AppServer.Messengers
status.ShowSelfViewByDefault = Codec.ShowSelfViewByDefault;
status.SupportsAdHocMeeting = Codec is IHasStartMeeting;
status.HasRecents = Codec is IHasCallHistory;
status.HasCameras = Codec is IHasCameras;
status.HasCameras = Codec is IHasCamerasWithControls;
status.Presets = GetCurrentPresets();
status.IsZoomRoom = codecType.GetInterface("IHasZoomRoomLayouts") != null;
status.ReceivingContent = Codec is IHasFarEndContentStatus && (Codec as IHasFarEndContentStatus).ReceivingContent.BoolValue;
@ -899,12 +899,15 @@ namespace PepperDash.Essentials.AppServer.Messengers
{
camera.Name = camerasCodec.SelectedCamera.Name;
camera.Capabilities = new CameraCapabilities()
if(camerasCodec.SelectedCamera is IHasCameraPtzControl cameraControls)
{
CanPan = camerasCodec.SelectedCamera.CanPan,
CanTilt = camerasCodec.SelectedCamera.CanTilt,
CanZoom = camerasCodec.SelectedCamera.CanZoom,
CanFocus = camerasCodec.SelectedCamera.CanFocus,
camera.Capabilities = new CameraCapabilities()
{
CanPan = cameraControls is IHasCameraPanControl,
CanTilt = cameraControls is IHasCameraTiltControl,
CanZoom = cameraControls is IHasCameraZoomControl,
CanFocus = cameraControls is IHasCameraFocusControl,
};
};
}
@ -1084,7 +1087,7 @@ namespace PepperDash.Essentials.AppServer.Messengers
/// Gets or sets the Cameras
/// </summary>
[JsonProperty("cameraList", NullValueHandling = NullValueHandling.Ignore)]
public List<CameraBase> Cameras { get; set; }
public List<IHasCameraControls> Cameras { get; set; }
/// <summary>