diff --git a/src/PepperDash.Core/Comm/GenericUdpServer.cs b/src/PepperDash.Core/Comm/GenericUdpServer.cs index 61bebf8d..52ac627a 100644 --- a/src/PepperDash.Core/Comm/GenericUdpServer.cs +++ b/src/PepperDash.Core/Comm/GenericUdpServer.cs @@ -131,14 +131,14 @@ namespace PepperDash.Core /// /// /// - /// - public GenericUdpServer(string key, string address, int port, int buffefSize) + /// + public GenericUdpServer(string key, string address, int port, int bufferSize) : base(key) { StreamDebugging = new CommunicationStreamDebugging(key); Hostname = address; Port = port; - BufferSize = buffefSize; + BufferSize = bufferSize; CrestronEnvironment.ProgramStatusEventHandler += new ProgramStatusEventHandler(CrestronEnvironment_ProgramStatusEventHandler); CrestronEnvironment.EthernetEventHandler += new EthernetEventHandler(CrestronEnvironment_EthernetEventHandler); @@ -194,7 +194,21 @@ namespace PepperDash.Core { if (Server == null) { - Server = new UDPServer(); + try + { + var address = IPAddress.Parse(Hostname); + + Server = new UDPServer(address, Port, BufferSize); + + } + catch (Exception ex) + { + this.LogError("Error parsing IP Address '{ipAddress}': message: {message}", Hostname, ex.Message); + this.LogInformation("Creating UDPServer with default buffersize"); + + Server = new UDPServer(); + } + } if (string.IsNullOrEmpty(Hostname)) diff --git a/src/PepperDash.Essentials.Devices.Common/Cameras/CameraControl.cs b/src/PepperDash.Essentials.Devices.Common/Cameras/CameraControl.cs deleted file mode 100644 index e2120638..00000000 --- a/src/PepperDash.Essentials.Devices.Common/Cameras/CameraControl.cs +++ /dev/null @@ -1,323 +0,0 @@ -using System; -using System.Collections.Generic; -using PepperDash.Core; -using PepperDash.Essentials.Core; - -namespace PepperDash.Essentials.Devices.Common.Cameras -{ - /// - /// Enum for camera control modes - /// - public enum eCameraControlMode - { - /// - /// Manual control mode, where the camera is controlled directly by the user or system - /// - Manual = 0, - /// - /// Off control mode, where the camera is turned off or disabled - /// - Off, - /// - /// Auto control mode, where the camera automatically adjusts settings based on the environment or conditions - /// - Auto - } - - - /// - /// Interface for devices that have cameras - /// - public interface IHasCameras : IKeyName - { - /// - /// Event that is raised when a camera is selected - /// - event EventHandler CameraSelected; - - /// - /// List of cameras on the device. This should be a list of CameraBase objects - /// - List Cameras { get; } - - /// - /// The currently selected camera. This should be a CameraBase object - /// - CameraBase SelectedCamera { get; } - - /// - /// Feedback that indicates the currently selected camera - /// - StringFeedback SelectedCameraFeedback { get; } - - /// - /// Selects a camera from the list of available cameras based on the provided key. - /// - /// The unique identifier or name of the camera to select. - void SelectCamera(string key); - } - - /// - /// Defines the contract for IHasCodecCameras - /// - public interface IHasCodecCameras : IHasCameras, IHasFarEndCameraControl - { - - } - - /// - /// To be implmented on codecs that can disable their camera(s) to blank the near end video - /// - public interface IHasCameraOff - { - /// - /// Feedback that indicates whether the camera is off - /// - BoolFeedback CameraIsOffFeedback { get; } - - /// - /// Turns the camera off, blanking the near end video - /// - void CameraOff(); - } - - /// - /// Describes the ability to mute and unmute camera video - /// - public interface IHasCameraMute - { - /// - /// Feedback that indicates whether the camera is muted - /// - BoolFeedback CameraIsMutedFeedback { get; } - - /// - /// Mutes the camera video, preventing it from being sent to the far end - /// - void CameraMuteOn(); - - /// - /// Unmutes the camera video, allowing it to be sent to the far end - /// - void CameraMuteOff(); - - /// - /// Toggles the camera mute state. If the camera is muted, it will be unmuted, and vice versa. - /// - void CameraMuteToggle(); - } - - /// - /// Interface for devices that can mute and unmute their camera video, with an event for unmute requests - /// - public interface IHasCameraMuteWithUnmuteReqeust : IHasCameraMute - { - /// - /// Event that is raised when a video unmute is requested, typically by the far end - /// - event EventHandler VideoUnmuteRequested; - } - - /// - /// Event arguments for the CameraSelected event - /// - public class CameraSelectedEventArgs : EventArgs - { - /// - /// Gets or sets the SelectedCamera - /// - public CameraBase SelectedCamera { get; private set; } - - /// - /// Constructor for CameraSelectedEventArgs - /// - /// - public CameraSelectedEventArgs(CameraBase camera) - { - SelectedCamera = camera; - } - } - - /// - /// Interface for devices that have a far end camera control - /// - public interface IHasFarEndCameraControl - { - /// - /// Gets the far end camera, which is typically a CameraBase object that represents the camera at the far end of a call - /// - CameraBase FarEndCamera { get; } - - /// - /// Feedback that indicates whether the far end camera is being controlled - /// - BoolFeedback ControllingFarEndCameraFeedback { get; } - - } - - /// - /// Defines the contract for IAmFarEndCamera - /// - public interface IAmFarEndCamera - { - - } - - /// - /// Interface for devices that have camera controls - /// - public interface IHasCameraControls - { - } - - /// - /// Defines the contract for IHasCameraPtzControl - /// - public interface IHasCameraPtzControl : IHasCameraPanControl, IHasCameraTiltControl, IHasCameraZoomControl - { - /// - /// Resets the camera position - /// - void PositionHome(); - } - - /// - /// Interface for camera pan control - /// - public interface IHasCameraPanControl : IHasCameraControls - { - /// - /// Pans the camera left - /// - void PanLeft(); - - /// - /// Pans the camera right - /// - void PanRight(); - - /// - /// Stops the camera pan movement - /// - void PanStop(); - } - - /// - /// Defines the contract for IHasCameraTiltControl - /// - public interface IHasCameraTiltControl : IHasCameraControls - { - /// - /// Tilts the camera down - /// - void TiltDown(); - - /// - /// Tilts the camera up - /// - void TiltUp(); - - /// - /// Stops the camera tilt movement - /// - void TiltStop(); - } - - /// - /// Defines the contract for IHasCameraZoomControl - /// - public interface IHasCameraZoomControl : IHasCameraControls - { - /// - /// Zooms the camera in - /// - void ZoomIn(); - - /// - /// Zooms the camera out - /// - void ZoomOut(); - - /// - /// Stops the camera zoom movement - /// - void ZoomStop(); - } - - /// - /// Defines the contract for IHasCameraFocusControl - /// - public interface IHasCameraFocusControl : IHasCameraControls - { - /// - /// Focuses the camera near - /// - void FocusNear(); - - /// - /// Focuses the camera far - /// - void FocusFar(); - - /// - /// Stops the camera focus movement - /// - void FocusStop(); - - /// - /// Triggers the camera's auto focus functionality, if available. - /// - void TriggerAutoFocus(); - } - - /// - /// Interface for devices that have auto focus mode control - /// - public interface IHasAutoFocusMode - { - /// - /// Sets the focus mode to auto or manual, or toggles between them. - /// - void SetFocusModeAuto(); - - /// - /// Sets the focus mode to manual, allowing for manual focus adjustments. - /// - void SetFocusModeManual(); - - /// - /// Toggles the focus mode between auto and manual. - /// - void ToggleFocusMode(); - } - - /// - /// Interface for devices that have camera auto mode control - /// - public interface IHasCameraAutoMode : IHasCameraControls - { - /// - /// Enables or disables the camera's auto mode, which may include automatic adjustments for focus, exposure, and other settings. - /// - void CameraAutoModeOn(); - - /// - /// Disables the camera's auto mode, allowing for manual control of camera settings. - /// - void CameraAutoModeOff(); - - /// - /// Toggles the camera's auto mode state. If the camera is in auto mode, it will switch to manual mode, and vice versa. - /// - void CameraAutoModeToggle(); - - /// - /// Feedback that indicates whether the camera's auto mode is currently enabled. - /// - BoolFeedback CameraAutoModeIsOnFeedback { get; } - } - - - - -} \ No newline at end of file diff --git a/src/PepperDash.Essentials.Devices.Common/Cameras/Interfaces/CameraSelectedEventArgs.cs b/src/PepperDash.Essentials.Devices.Common/Cameras/Interfaces/CameraSelectedEventArgs.cs new file mode 100644 index 00000000..bb2a85a2 --- /dev/null +++ b/src/PepperDash.Essentials.Devices.Common/Cameras/Interfaces/CameraSelectedEventArgs.cs @@ -0,0 +1,49 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace PepperDash.Essentials.Devices.Common.Cameras +{ + /// + /// Event arguments for the CameraSelected event + /// + [Obsolete("Use CameraSelectedEventArgs instead. This class will be removed in a future version")] + public class CameraSelectedEventArgs : EventArgs + { + /// Gets or sets the SelectedCamera + /// + public CameraBase SelectedCamera { get; private set; } + + /// + /// Constructor for CameraSelectedEventArgs + /// + /// + public CameraSelectedEventArgs(CameraBase camera) + { + SelectedCamera = camera; + } + } + + /// + /// Event arguments for the CameraSelected event + /// + /// + public class CameraSelectedEventArgs : EventArgs + { + /// + /// Gets or sets the SelectedCamera + /// + public T SelectedCamera { get; private set; } + + /// + /// Constructor for CameraSelectedEventArgs + /// + /// + public CameraSelectedEventArgs(T camera) + { + SelectedCamera = camera; + } + } +} diff --git a/src/PepperDash.Essentials.Devices.Common/Cameras/Interfaces/IAmFarEndCamera.cs b/src/PepperDash.Essentials.Devices.Common/Cameras/Interfaces/IAmFarEndCamera.cs new file mode 100644 index 00000000..a8e96664 --- /dev/null +++ b/src/PepperDash.Essentials.Devices.Common/Cameras/Interfaces/IAmFarEndCamera.cs @@ -0,0 +1,12 @@ +using PepperDash.Core; + +namespace PepperDash.Essentials.Devices.Common.Cameras +{ + /// + /// Defines the contract for IAmFarEndCamera + /// + public interface IAmFarEndCamera : IKeyName + { + + } +} diff --git a/src/PepperDash.Essentials.Devices.Common/Cameras/Interfaces/ICameraCapabilities.cs b/src/PepperDash.Essentials.Devices.Common/Cameras/Interfaces/ICameraCapabilities.cs new file mode 100644 index 00000000..cf39a95c --- /dev/null +++ b/src/PepperDash.Essentials.Devices.Common/Cameras/Interfaces/ICameraCapabilities.cs @@ -0,0 +1,86 @@ +using Newtonsoft.Json; +using PepperDash.Core; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace PepperDash.Essentials.Devices.Common.Cameras +{ + /// + /// Interface for camera capabilities + /// + public interface ICameraCapabilities: IKeyName + { + /// + /// Indicates whether the camera can pan + /// + [JsonProperty("canPan", NullValueHandling = NullValueHandling.Ignore)] + bool CanPan { get; } + + /// + /// Indicates whether the camera can tilt + /// + [JsonProperty("canTilt", NullValueHandling = NullValueHandling.Ignore)] + bool CanTilt { get; } + + /// + /// Indicates whether the camera can zoom + /// + [JsonProperty("canZoom", NullValueHandling = NullValueHandling.Ignore)] + bool CanZoom { get; } + + + /// + /// Indicates whether the camera can focus + /// + [JsonProperty("canFocus", NullValueHandling = NullValueHandling.Ignore)] + bool CanFocus { get; } + } + + /// + /// Indicates the capabilities of a camera + /// + public class CameraCapabilities : ICameraCapabilities + { + + /// + /// Unique Key + /// + [JsonProperty("key", NullValueHandling = NullValueHandling.Ignore)] + public string Key { get; set; } + + /// + /// Isn't it obvious :) + /// + [JsonProperty("name", NullValueHandling = NullValueHandling.Ignore)] + public string Name { get; set; } + + + /// + /// Indicates whether the camera can pan + /// + [JsonProperty("canPan", NullValueHandling = NullValueHandling.Ignore)] + public bool CanPan { get; set; } + + /// + /// Indicates whether the camera can tilt + /// + [JsonProperty("canTilt", NullValueHandling = NullValueHandling.Ignore)] + public bool CanTilt { get; set; } + + /// + /// Indicates whether the camera can zoom + /// + [JsonProperty("canZoom", NullValueHandling = NullValueHandling.Ignore)] + public bool CanZoom { get; set; } + + + /// + /// Indicates whether the camera can focus + /// + [JsonProperty("canFocus", NullValueHandling = NullValueHandling.Ignore)] + public bool CanFocus { get; set; } + } +} diff --git a/src/PepperDash.Essentials.Devices.Common/Cameras/Interfaces/IHasAutoFocusMode.cs b/src/PepperDash.Essentials.Devices.Common/Cameras/Interfaces/IHasAutoFocusMode.cs new file mode 100644 index 00000000..0dbd5f52 --- /dev/null +++ b/src/PepperDash.Essentials.Devices.Common/Cameras/Interfaces/IHasAutoFocusMode.cs @@ -0,0 +1,24 @@ + +namespace PepperDash.Essentials.Devices.Common.Cameras +{ + /// + /// Interface for devices that have auto focus mode control + /// + public interface IHasAutoFocusMode : IHasCameraControls + { + /// + /// Sets the focus mode to auto or manual, or toggles between them. + /// + void SetFocusModeAuto(); + + /// + /// Sets the focus mode to manual, allowing for manual focus adjustments. + /// + void SetFocusModeManual(); + + /// + /// Toggles the focus mode between auto and manual. + /// + void ToggleFocusMode(); + } +} diff --git a/src/PepperDash.Essentials.Devices.Common/Cameras/Interfaces/IHasCameraAutoMode.cs b/src/PepperDash.Essentials.Devices.Common/Cameras/Interfaces/IHasCameraAutoMode.cs new file mode 100644 index 00000000..9eeb1f40 --- /dev/null +++ b/src/PepperDash.Essentials.Devices.Common/Cameras/Interfaces/IHasCameraAutoMode.cs @@ -0,0 +1,31 @@ +using PepperDash.Essentials.Core; + +namespace PepperDash.Essentials.Devices.Common.Cameras +{ + + /// + /// Interface for devices that have camera auto mode control + /// + public interface IHasCameraAutoMode : IHasCameraControls + { + /// + /// Enables or disables the camera's auto mode, which may include automatic adjustments for focus, exposure, and other settings. + /// + void CameraAutoModeOn(); + + /// + /// Disables the camera's auto mode, allowing for manual control of camera settings. + /// + void CameraAutoModeOff(); + + /// + /// Toggles the camera's auto mode state. If the camera is in auto mode, it will switch to manual mode, and vice versa. + /// + void CameraAutoModeToggle(); + + /// + /// Feedback that indicates whether the camera's auto mode is currently enabled. + /// + BoolFeedback CameraAutoModeIsOnFeedback { get; } + } +} diff --git a/src/PepperDash.Essentials.Devices.Common/Cameras/Interfaces/IHasCameraControls.cs b/src/PepperDash.Essentials.Devices.Common/Cameras/Interfaces/IHasCameraControls.cs new file mode 100644 index 00000000..a4ed5937 --- /dev/null +++ b/src/PepperDash.Essentials.Devices.Common/Cameras/Interfaces/IHasCameraControls.cs @@ -0,0 +1,13 @@ +using PepperDash.Core; + + +namespace PepperDash.Essentials.Devices.Common.Cameras +{ + + /// + /// Interface for devices that have camera controls + /// + public interface IHasCameraControls : IKeyName + { + } +} diff --git a/src/PepperDash.Essentials.Devices.Common/Cameras/Interfaces/IHasCameraFocusControl.cs b/src/PepperDash.Essentials.Devices.Common/Cameras/Interfaces/IHasCameraFocusControl.cs new file mode 100644 index 00000000..bf266d56 --- /dev/null +++ b/src/PepperDash.Essentials.Devices.Common/Cameras/Interfaces/IHasCameraFocusControl.cs @@ -0,0 +1,29 @@ + +namespace PepperDash.Essentials.Devices.Common.Cameras +{ + /// + /// Defines the contract for IHasCameraFocusControl + /// + public interface IHasCameraFocusControl : IHasCameraControls + { + /// + /// Focuses the camera near + /// + void FocusNear(); + + /// + /// Focuses the camera far + /// + void FocusFar(); + + /// + /// Stops the camera focus movement + /// + void FocusStop(); + + /// + /// Triggers the camera's auto focus functionality, if available. + /// + void TriggerAutoFocus(); + } +} diff --git a/src/PepperDash.Essentials.Devices.Common/Cameras/Interfaces/IHasCameraMute.cs b/src/PepperDash.Essentials.Devices.Common/Cameras/Interfaces/IHasCameraMute.cs new file mode 100644 index 00000000..cae6f5ef --- /dev/null +++ b/src/PepperDash.Essentials.Devices.Common/Cameras/Interfaces/IHasCameraMute.cs @@ -0,0 +1,31 @@ +using PepperDash.Core; +using PepperDash.Essentials.Core; + +namespace PepperDash.Essentials.Devices.Common.Cameras +{ + /// + /// Describes the ability to mute and unmute camera video + /// + public interface IHasCameraMute : IKeyName + { + /// + /// Feedback that indicates whether the camera is muted + /// + BoolFeedback CameraIsMutedFeedback { get; } + + /// + /// Mutes the camera video, preventing it from being sent to the far end + /// + void CameraMuteOn(); + + /// + /// Unmutes the camera video, allowing it to be sent to the far end + /// + void CameraMuteOff(); + + /// + /// Toggles the camera mute state. If the camera is muted, it will be unmuted, and vice versa. + /// + void CameraMuteToggle(); + } +} diff --git a/src/PepperDash.Essentials.Devices.Common/Cameras/Interfaces/IHasCameraMuteWithUnmuteRequest.cs b/src/PepperDash.Essentials.Devices.Common/Cameras/Interfaces/IHasCameraMuteWithUnmuteRequest.cs new file mode 100644 index 00000000..5426ea2b --- /dev/null +++ b/src/PepperDash.Essentials.Devices.Common/Cameras/Interfaces/IHasCameraMuteWithUnmuteRequest.cs @@ -0,0 +1,16 @@ +using System; + + +namespace PepperDash.Essentials.Devices.Common.Cameras +{ + /// + /// Interface for devices that can mute and unmute their camera video, with an event for unmute requests + /// + public interface IHasCameraMuteWithUnmuteReqeust : IHasCameraMute + { + /// + /// Event that is raised when a video unmute is requested, typically by the far end + /// + event EventHandler VideoUnmuteRequested; + } +} diff --git a/src/PepperDash.Essentials.Devices.Common/Cameras/Interfaces/IHasCameraOff.cs b/src/PepperDash.Essentials.Devices.Common/Cameras/Interfaces/IHasCameraOff.cs new file mode 100644 index 00000000..6dc451c1 --- /dev/null +++ b/src/PepperDash.Essentials.Devices.Common/Cameras/Interfaces/IHasCameraOff.cs @@ -0,0 +1,27 @@ +using PepperDash.Essentials.Core; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace PepperDash.Essentials.Devices.Common.Cameras +{ + + + /// + /// To be implmented on codecs that can disable their camera(s) to blank the near end video + /// + public interface IHasCameraOff : IHasCameraControls + { + /// + /// Feedback that indicates whether the camera is off + /// + BoolFeedback CameraIsOffFeedback { get; } + + /// + /// Turns the camera off, blanking the near end video + /// + void CameraOff(); + } +} diff --git a/src/PepperDash.Essentials.Devices.Common/Cameras/Interfaces/IHasCameraPanControl.cs b/src/PepperDash.Essentials.Devices.Common/Cameras/Interfaces/IHasCameraPanControl.cs new file mode 100644 index 00000000..507dc555 --- /dev/null +++ b/src/PepperDash.Essentials.Devices.Common/Cameras/Interfaces/IHasCameraPanControl.cs @@ -0,0 +1,24 @@ + +namespace PepperDash.Essentials.Devices.Common.Cameras +{ + /// + /// Interface for camera pan control + /// + public interface IHasCameraPanControl : IHasCameraControls + { + /// + /// Pans the camera left + /// + void PanLeft(); + + /// + /// Pans the camera right + /// + void PanRight(); + + /// + /// Stops the camera pan movement + /// + void PanStop(); + } +} diff --git a/src/PepperDash.Essentials.Devices.Common/Cameras/Interfaces/IHasCameraPtzControl.cs b/src/PepperDash.Essentials.Devices.Common/Cameras/Interfaces/IHasCameraPtzControl.cs new file mode 100644 index 00000000..de2b52dd --- /dev/null +++ b/src/PepperDash.Essentials.Devices.Common/Cameras/Interfaces/IHasCameraPtzControl.cs @@ -0,0 +1,14 @@ + +namespace PepperDash.Essentials.Devices.Common.Cameras +{ + /// + /// Defines the contract for IHasCameraPtzControl + /// + public interface IHasCameraPtzControl : IHasCameraPanControl, IHasCameraTiltControl, IHasCameraZoomControl + { + /// + /// Resets the camera position + /// + void PositionHome(); + } +} diff --git a/src/PepperDash.Essentials.Devices.Common/Cameras/Interfaces/IHasCameraTiltControl.cs b/src/PepperDash.Essentials.Devices.Common/Cameras/Interfaces/IHasCameraTiltControl.cs new file mode 100644 index 00000000..87dc1751 --- /dev/null +++ b/src/PepperDash.Essentials.Devices.Common/Cameras/Interfaces/IHasCameraTiltControl.cs @@ -0,0 +1,24 @@ + +namespace PepperDash.Essentials.Devices.Common.Cameras +{ + /// + /// Defines the contract for IHasCameraTiltControl + /// + public interface IHasCameraTiltControl : IHasCameraControls + { + /// + /// Tilts the camera down + /// + void TiltDown(); + + /// + /// Tilts the camera up + /// + void TiltUp(); + + /// + /// Stops the camera tilt movement + /// + void TiltStop(); + } +} diff --git a/src/PepperDash.Essentials.Devices.Common/Cameras/Interfaces/IHasCameraZoomControl.cs b/src/PepperDash.Essentials.Devices.Common/Cameras/Interfaces/IHasCameraZoomControl.cs new file mode 100644 index 00000000..72bf16c4 --- /dev/null +++ b/src/PepperDash.Essentials.Devices.Common/Cameras/Interfaces/IHasCameraZoomControl.cs @@ -0,0 +1,24 @@ + +namespace PepperDash.Essentials.Devices.Common.Cameras +{ + /// + /// Defines the contract for IHasCameraZoomControl + /// + public interface IHasCameraZoomControl : IHasCameraControls + { + /// + /// Zooms the camera in + /// + void ZoomIn(); + + /// + /// Zooms the camera out + /// + void ZoomOut(); + + /// + /// Stops the camera zoom movement + /// + void ZoomStop(); + } +} diff --git a/src/PepperDash.Essentials.Devices.Common/Cameras/Interfaces/IHasCameras.cs b/src/PepperDash.Essentials.Devices.Common/Cameras/Interfaces/IHasCameras.cs new file mode 100644 index 00000000..5a5962f8 --- /dev/null +++ b/src/PepperDash.Essentials.Devices.Common/Cameras/Interfaces/IHasCameras.cs @@ -0,0 +1,41 @@ +using Newtonsoft.Json; +using PepperDash.Core; +using PepperDash.Essentials.Core; +using System; +using System.Collections.Generic; + +namespace PepperDash.Essentials.Devices.Common.Cameras +{ + /// + /// Interface for devices that have cameras + /// + [Obsolete("Use IHasCamerasWithControls instead. This interface will be removed in a future version")] + public interface IHasCameras : IKeyName + { + /// + /// Event that is raised when a camera is selected + /// + event EventHandler CameraSelected; + + /// + /// List of cameras on the device. This should be a list of CameraBase objects + /// + List Cameras { get; } + + /// + /// The currently selected camera. This should be a CameraBase object + /// + CameraBase SelectedCamera { get; } + + /// + /// Feedback that indicates the currently selected camera + /// + StringFeedback SelectedCameraFeedback { get; } + + /// + /// Selects a camera from the list of available cameras based on the provided key. + /// + /// The unique identifier or name of the camera to select. + void SelectCamera(string key); + } +} diff --git a/src/PepperDash.Essentials.Devices.Common/Cameras/Interfaces/IHasCamerasWithControls.cs b/src/PepperDash.Essentials.Devices.Common/Cameras/Interfaces/IHasCamerasWithControls.cs new file mode 100644 index 00000000..f7aff6d2 --- /dev/null +++ b/src/PepperDash.Essentials.Devices.Common/Cameras/Interfaces/IHasCamerasWithControls.cs @@ -0,0 +1,40 @@ +using PepperDash.Core; +using PepperDash.Essentials.Core; +using System; +using System.Collections.Generic; + +namespace PepperDash.Essentials.Devices.Common.Cameras +{ + /// + /// Interface for devices that have cameras with controls + /// + public interface IHasCamerasWithControls : IKeyName, IKeyed + { + /// + /// List of cameras on the device. This should be a list of IHasCameraControls objects + /// + + List Cameras { get; } + + /// + /// The currently selected camera. This should be an IHasCameraControls object + /// + IHasCameraControls SelectedCamera { get; } + + /// + /// Feedback that indicates the currently selected camera + /// + StringFeedback SelectedCameraFeedback { get; } + + /// + /// Event that is raised when a camera is selected + /// + event EventHandler> CameraSelected; + + /// + /// Selects a camera from the list of available cameras based on the provided key. + /// + /// + void SelectCamera(string key); + } +} diff --git a/src/PepperDash.Essentials.Devices.Common/Cameras/Interfaces/IHasCodecCameras.cs b/src/PepperDash.Essentials.Devices.Common/Cameras/Interfaces/IHasCodecCameras.cs new file mode 100644 index 00000000..01cdf24e --- /dev/null +++ b/src/PepperDash.Essentials.Devices.Common/Cameras/Interfaces/IHasCodecCameras.cs @@ -0,0 +1,13 @@ + +namespace PepperDash.Essentials.Devices.Common.Cameras +{ + + /// + /// Defines the contract for IHasCodecCameras + /// + public interface IHasCodecCameras : IHasCameras, IHasFarEndCameraControl + { + + } + +} diff --git a/src/PepperDash.Essentials.Devices.Common/Cameras/Interfaces/IHasFarEndCameraControl.cs b/src/PepperDash.Essentials.Devices.Common/Cameras/Interfaces/IHasFarEndCameraControl.cs new file mode 100644 index 00000000..10a4ba69 --- /dev/null +++ b/src/PepperDash.Essentials.Devices.Common/Cameras/Interfaces/IHasFarEndCameraControl.cs @@ -0,0 +1,23 @@ +using PepperDash.Core; +using PepperDash.Essentials.Core; + + +namespace PepperDash.Essentials.Devices.Common.Cameras +{ + /// + /// Interface for devices that have a far end camera control + /// + public interface IHasFarEndCameraControl : IKeyName + { + /// + /// Gets the far end camera, which is typically a CameraBase object that represents the camera at the far end of a call + /// + CameraBase FarEndCamera { get; } + + /// + /// Feedback that indicates whether the far end camera is being controlled + /// + BoolFeedback ControllingFarEndCameraFeedback { get; } + + } +} diff --git a/src/PepperDash.Essentials.Devices.Common/Cameras/Interfaces/eCameraControlMode.cs b/src/PepperDash.Essentials.Devices.Common/Cameras/Interfaces/eCameraControlMode.cs new file mode 100644 index 00000000..c966ac41 --- /dev/null +++ b/src/PepperDash.Essentials.Devices.Common/Cameras/Interfaces/eCameraControlMode.cs @@ -0,0 +1,24 @@ + + +namespace PepperDash.Essentials.Devices.Common.Cameras +{ + /// + /// Enum for camera control modes + /// + public enum eCameraControlMode + { + /// + /// Manual control mode, where the camera is controlled directly by the user or system + /// + Manual = 0, + /// + /// Off control mode, where the camera is turned off or disabled + /// + Off, + /// + /// Auto control mode, where the camera automatically adjusts settings based on the environment or conditions + /// + Auto + } + +} diff --git a/src/PepperDash.Essentials.MobileControl.Messengers/Messengers/CameraBaseMessenger.cs b/src/PepperDash.Essentials.MobileControl.Messengers/Messengers/CameraBaseMessenger.cs index 7650b430..8c9f0451 100644 --- a/src/PepperDash.Essentials.MobileControl.Messengers/Messengers/CameraBaseMessenger.cs +++ b/src/PepperDash.Essentials.MobileControl.Messengers/Messengers/CameraBaseMessenger.cs @@ -1,6 +1,8 @@ using System; using System.Collections.Generic; +using Newtonsoft.Json; using Newtonsoft.Json.Linq; +using PepperDash.Core; using PepperDash.Essentials.Core; using PepperDash.Essentials.Devices.Common.Cameras; @@ -9,12 +11,12 @@ namespace PepperDash.Essentials.AppServer.Messengers /// /// Messenger for a CameraBase device /// - public class CameraBaseMessenger : MessengerBase + public class CameraBaseMessenger : MessengerBase where T : IKeyed { /// /// Gets or sets the Camera /// - public CameraBase Camera { get; set; } + public T Camera { get; set; } /// /// Constructor @@ -22,10 +24,13 @@ namespace PepperDash.Essentials.AppServer.Messengers /// /// /// - public CameraBaseMessenger(string key, CameraBase camera, string messagePath) - : base(key, messagePath, camera) + public CameraBaseMessenger(string key, T camera, string messagePath) + : base(key, messagePath, camera as IKeyName) { - Camera = camera ?? throw new ArgumentNullException("camera"); + if (camera == null) + throw new ArgumentNullException(nameof(camera)); + + Camera = camera; if (Camera is IHasCameraPresets presetsCamera) @@ -178,19 +183,44 @@ namespace PepperDash.Essentials.AppServer.Messengers private void SendCameraFullMessageObject(string id = null) { var presetList = new List(); + CameraCapabilities capabilities = null; if (Camera is IHasCameraPresets presetsCamera) presetList = presetsCamera.Presets; - PostStatusMessage(JToken.FromObject(new + if (Camera is ICameraCapabilities cameraCapabilities) + capabilities = new CameraCapabilities + { + CanPan = cameraCapabilities.CanPan, + CanTilt = cameraCapabilities.CanTilt, + CanZoom = cameraCapabilities.CanZoom, + CanFocus = cameraCapabilities.CanFocus + + }; + + if (Camera is CameraBase cameraBase) + capabilities = new CameraCapabilities + { + CanPan = cameraBase.CanPan, + CanTilt = cameraBase.CanTilt, + CanZoom = cameraBase.CanZoom, + CanFocus = cameraBase.CanFocus + + }; + + var message = new CameraStateMessage { - cameraManualSupported = Camera is IHasCameraControls, - cameraAutoSupported = Camera is IHasCameraAutoMode, - cameraOffSupported = Camera is IHasCameraOff, - cameraMode = GetCameraMode(), - hasPresets = Camera is IHasCameraPresets, - presets = presetList - }), id + CameraManualSupported = Camera is IHasCameraControls, + CameraAutoSupported = Camera is IHasCameraAutoMode, + CameraOffSupported = Camera is IHasCameraOff, + CameraMode = (eCameraControlMode)Enum.Parse(typeof(eCameraControlMode), GetCameraMode(), true), + HasPresets = Camera is IHasCameraPresets, + Presets = presetList, + Capabilities = capabilities, + IsFarEnd = Camera is IAmFarEndCamera + }; + + PostStatusMessage(message, id ); } @@ -210,4 +240,59 @@ namespace PepperDash.Essentials.AppServer.Messengers return m; } } + + /// + /// State message for a camera device + /// + public class CameraStateMessage : DeviceStateMessageBase + { + /// + /// Indicates whether the camera supports manual control + /// + [JsonProperty("cameraManualSupported", NullValueHandling = NullValueHandling.Ignore)] + public bool CameraManualSupported { get; set; } + + /// + /// Indicates whether the camera supports auto control + /// + [JsonProperty("cameraAutoSupported", NullValueHandling = NullValueHandling.Ignore)] + public bool CameraAutoSupported { get; set; } + + /// + /// Indicates whether the camera supports off control + /// + [JsonProperty("cameraOffSupported", NullValueHandling = NullValueHandling.Ignore)] + public bool CameraOffSupported { get; set; } + + /// + /// Indicates the current camera control mode + /// + [JsonProperty("cameraMode", NullValueHandling = NullValueHandling.Ignore)] + [JsonConverter(typeof(Newtonsoft.Json.Converters.StringEnumConverter))] + public eCameraControlMode CameraMode { get; set; } + + /// + /// Indicates whether the camera has presets + /// + [JsonProperty("hasPresets", NullValueHandling = NullValueHandling.Ignore)] + public bool HasPresets { get; set; } + + /// + /// List of presets if the camera supports them + /// + [JsonProperty("presets", NullValueHandling = NullValueHandling.Ignore)] + public List Presets { get; set; } + + /// + /// Indicates the capabilities of the camera + /// + [JsonProperty("capabilities", NullValueHandling = NullValueHandling.Ignore)] + public CameraCapabilities Capabilities { get; set; } + + /// + /// Indicates whether the camera is a far end camera + /// + [JsonProperty("isFarEnd", NullValueHandling = NullValueHandling.Ignore)] + public bool IsFarEnd { get; set; } + } } \ No newline at end of file diff --git a/src/PepperDash.Essentials.MobileControl.Messengers/Messengers/IHasCamerasMessenger.cs b/src/PepperDash.Essentials.MobileControl.Messengers/Messengers/IHasCamerasMessenger.cs index 7099e52c..00c2c2fe 100644 --- a/src/PepperDash.Essentials.MobileControl.Messengers/Messengers/IHasCamerasMessenger.cs +++ b/src/PepperDash.Essentials.MobileControl.Messengers/Messengers/IHasCamerasMessenger.cs @@ -1,17 +1,14 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using Newtonsoft.Json; -using Newtonsoft.Json.Linq; +using Newtonsoft.Json; using PepperDash.Essentials.Devices.Common.Cameras; +using System; +using System.Collections.Generic; namespace PepperDash.Essentials.AppServer.Messengers { /// /// Messenger for devices that implement the IHasCameras interface. /// + [Obsolete("Use IHasCamerasWithControlsMessenger instead. This class will be removed in a future version")] public class IHasCamerasMessenger : MessengerBase { /// diff --git a/src/PepperDash.Essentials.MobileControl.Messengers/Messengers/IHasCamerasWithControlMessenger.cs b/src/PepperDash.Essentials.MobileControl.Messengers/Messengers/IHasCamerasWithControlMessenger.cs new file mode 100644 index 00000000..cce07dcd --- /dev/null +++ b/src/PepperDash.Essentials.MobileControl.Messengers/Messengers/IHasCamerasWithControlMessenger.cs @@ -0,0 +1,137 @@ +using Newtonsoft.Json; +using PepperDash.Core; +using PepperDash.Core.Logging; +using PepperDash.Essentials.Core; +using PepperDash.Essentials.Devices.Common.Cameras; +using System; +using System.Collections.Generic; +using System.Linq; + +namespace PepperDash.Essentials.AppServer.Messengers +{ + /// + /// Messenger for devices that implement the IHasCameras interface. + /// + public class IHasCamerasWithControlMessenger : MessengerBase + { + /// + /// Device being bridged that implements IHasCameras interface. + /// + public IHasCamerasWithControls CameraController { get; private set; } + + /// + /// Messenger for devices that implement IHasCameras interface. + /// + /// + /// + /// + /// + public IHasCamerasWithControlMessenger(string key, string messagePath, IHasCamerasWithControls cameraController) + : base(key, messagePath, cameraController) + { + CameraController = cameraController ?? throw new ArgumentNullException("cameraController"); + CameraController.CameraSelected += CameraController_CameraSelected; + } + + private void CameraController_CameraSelected(object sender, CameraSelectedEventArgs e) + { + var selectedCamera = new KeyName + { + Key = e.SelectedCamera.Key, + Name = e.SelectedCamera.Name + }; + + PostStatusMessage(new IHasCamerasWithControlsStateMessage + { + SelectedCamera = selectedCamera + }); + } + + /// + /// Registers the actions for this messenger. + /// + /// + 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(); + + 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 cameraList = new List(); + KeyName selectedCamera = null; + + foreach (var cam in CameraController.Cameras) + { + cameraList.Add(new KeyName{ + Key = cam.Key, + Name = cam.Name + }); + } + + if (CameraController.SelectedCamera != null) + { + selectedCamera = new KeyName + { + Key = CameraController.SelectedCamera.Key, + Name = CameraController.SelectedCamera.Name + }; + } + + var state = new IHasCamerasWithControlsStateMessage + { + CameraList = cameraList, + SelectedCamera = selectedCamera + }; + + PostStatusMessage(state, clientId); + } + } + + /// + /// State message for devices that implement the IHasCameras interface. + /// + public class IHasCamerasWithControlsStateMessage : DeviceStateMessageBase + { + /// + /// List of cameras available in the device. + /// + [JsonProperty("cameraList", NullValueHandling = NullValueHandling.Ignore)] + public List CameraList { get; set; } + + /// + /// The currently selected camera on the device. + /// + [JsonProperty("selectedCamera", NullValueHandling = NullValueHandling.Ignore)] + public IKeyName SelectedCamera { get; set; } + } + + class KeyName : IKeyName + { + public string Key { get; set; } + public string Name { get; set; } + public KeyName() + { + Key = ""; + Name = ""; + } + } +} diff --git a/src/PepperDash.Essentials.MobileControl.Messengers/Messengers/ISelectableItemsMessenger.cs b/src/PepperDash.Essentials.MobileControl.Messengers/Messengers/ISelectableItemsMessenger.cs index 36d73a3e..8e2f8f3e 100644 --- a/src/PepperDash.Essentials.MobileControl.Messengers/Messengers/ISelectableItemsMessenger.cs +++ b/src/PepperDash.Essentials.MobileControl.Messengers/Messengers/ISelectableItemsMessenger.cs @@ -16,6 +16,8 @@ namespace PepperDash.Essentials.AppServer.Messengers private readonly string _propName; + private List _itemKeys = new List(); + /// /// Constructs a messenger for a device that implements ISelectableItems /// @@ -39,9 +41,35 @@ namespace PepperDash.Essentials.AppServer.Messengers AddAction("/itemsStatus", (id, content) => SendFullStatus(id)); + AddAction("/selectItem", (id, content) => + { + try + { + var key = content.ToObject(); + + if (key == null) + { + this.LogError("No key specified to select"); + return; + } + if (itemDevice.Items.ContainsKey((TKey)Convert.ChangeType(key, typeof(TKey)))) + { + itemDevice.Items[(TKey)Convert.ChangeType(key, typeof(TKey))].Select(); + } + else + { + this.LogError("Key {0} not found in items", key); + } + } + catch (Exception e) + { + this.LogError("Error selecting item: {0}", e.Message); + } + }); + itemDevice.ItemsUpdated += (sender, args) => { - SendFullStatus(); + SetItems(); }; itemDevice.CurrentItemChanged += (sender, args) => @@ -49,23 +77,47 @@ namespace PepperDash.Essentials.AppServer.Messengers SendFullStatus(); }; - foreach (var input in itemDevice.Items) + SetItems(); + } + + /// + /// Sets the items and registers their update events + /// + private void SetItems() + { + if (_itemKeys != null && _itemKeys.Count > 0) { - var key = input.Key; - var localItem = input.Value; + /// Clear out any existing item actions + foreach (var item in _itemKeys) + { + RemoveAction($"/{item}"); + } + + _itemKeys.Clear(); + } + + foreach (var item in itemDevice.Items) + { + var key = item.Key; + var localItem = item.Value; AddAction($"/{key}", (id, content) => { localItem.Select(); }); - localItem.ItemUpdated += (sender, args) => - { - SendFullStatus(); - }; + _itemKeys.Add(key.ToString()); + + localItem.ItemUpdated -= LocalItem_ItemUpdated; + localItem.ItemUpdated += LocalItem_ItemUpdated; } } + private void LocalItem_ItemUpdated(object sender, EventArgs e) + { + SendFullStatus(); + } + private void SendFullStatus(string id = null) { try diff --git a/src/PepperDash.Essentials.MobileControl/MobileControlSystemController.cs b/src/PepperDash.Essentials.MobileControl/MobileControlSystemController.cs index 0579c1f6..d6a40ede 100644 --- a/src/PepperDash.Essentials.MobileControl/MobileControlSystemController.cs +++ b/src/PepperDash.Essentials.MobileControl/MobileControlSystemController.cs @@ -405,14 +405,15 @@ namespace PepperDash.Essentials messengerAdded = true; } - if (device is CameraBase cameraDevice) + // Default to IHasCameraControls if CameraBase and IHasCameraControls + if (device is CameraBase cameraDevice && !(device is IHasCameraControls)) { this.LogVerbose( "Adding CameraBaseMessenger for {deviceKey}", device.Key ); - var cameraMessenger = new CameraBaseMessenger( + var cameraMessenger = new CameraBaseMessenger( $"{device.Key}-cameraBase-{Key}", cameraDevice, $"/device/{device.Key}" @@ -423,6 +424,21 @@ namespace PepperDash.Essentials messengerAdded = true; } + if (device is IHasCameraControls cameraControlDev) + { + this.LogVerbose( + "Adding IHasCamerasWithControlMessenger for {deviceKey}", + device.Key + ); + var cameraControlMessenger = new CameraBaseMessenger( + $"{device.Key}-hasCamerasWithControls-{Key}", + cameraControlDev, + $"/device/{device.Key}" + ); + AddDefaultDeviceMessenger(cameraControlMessenger); + messengerAdded = true; + } + if (device is BlueJeansPc) { this.LogVerbose( @@ -975,6 +991,19 @@ namespace PepperDash.Essentials messengerAdded = true; } + if (device is IHasCamerasWithControls cameras2) + { + this.LogVerbose("Adding IHasCamerasWithControlsMessenger for {deviceKey}", device.Key + ); + var messenger = new IHasCamerasWithControlMessenger( + $"{device.Key}-cameras-{Key}", + $"/device/{device.Key}", + cameras2 + ); + AddDefaultDeviceMessenger(messenger); + messengerAdded = true; + } + this.LogVerbose("Trying to cast to generic device for device: {key}", device.Key); if (device is EssentialsDevice)