docs: XML comments for Devices.Common

This commit is contained in:
Andrew Welker
2025-10-09 13:18:36 -05:00
parent a5d409e93a
commit f9d9df9d5c
115 changed files with 5772 additions and 4292 deletions

View File

@@ -0,0 +1,26 @@
namespace PepperDash.Essentials.Devices.Common.Codec
{
/// <summary>
/// Represents a Call
/// </summary>
public class Call
{
/// <summary>
/// Gets or sets the Number
/// </summary>
public string Number { get; set; }
/// <summary>
/// Gets or sets the Protocol
/// </summary>
public string Protocol { get; set; }
/// <summary>
/// Gets or sets the CallRate
/// </summary>
public string CallRate { get; set; }
/// <summary>
/// Gets or sets the CallType
/// </summary>
public string CallType { get; set; }
}
}

View File

@@ -1,10 +1,5 @@
using PepperDash.Core;
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.Codec.Cisco
{

View File

@@ -1,10 +1,5 @@
using PepperDash.Core;
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.Codec.Cisco
{

View File

@@ -1,10 +1,6 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Crestron.SimplSharp;
using Newtonsoft.Json;
using Newtonsoft.Json.Converters;
@@ -17,55 +13,55 @@ namespace PepperDash.Essentials.Devices.Common.Codec
/// </summary>
public class CodecActiveCallItem
{
[JsonProperty("name", NullValueHandling = NullValueHandling.Ignore)]
/// <summary>
/// Gets or sets the Name
/// </summary>
[JsonProperty("name", NullValueHandling = NullValueHandling.Ignore)]
public string Name { get; set; }
[JsonProperty("number", NullValueHandling = NullValueHandling.Ignore)]
/// <summary>
/// Gets or sets the Number
/// </summary>
[JsonProperty("number", NullValueHandling = NullValueHandling.Ignore)]
public string Number { get; set; }
[JsonProperty("type", NullValueHandling = NullValueHandling.Ignore)]
[JsonConverter(typeof(StringEnumConverter))]
/// <summary>
/// Gets or sets the Type
/// </summary>
[JsonProperty("type", NullValueHandling = NullValueHandling.Ignore)]
[JsonConverter(typeof(StringEnumConverter))]
public eCodecCallType Type { get; set; }
[JsonProperty("status", NullValueHandling = NullValueHandling.Ignore)]
[JsonConverter(typeof(StringEnumConverter))]
/// <summary>
/// Gets or sets the Status
/// </summary>
[JsonProperty("status", NullValueHandling = NullValueHandling.Ignore)]
[JsonConverter(typeof(StringEnumConverter))]
public eCodecCallStatus Status { get; set; }
[JsonProperty("direction", NullValueHandling = NullValueHandling.Ignore)]
[JsonConverter(typeof(StringEnumConverter))]
/// <summary>
/// Gets or sets the Direction
/// </summary>
[JsonProperty("direction", NullValueHandling = NullValueHandling.Ignore)]
[JsonConverter(typeof(StringEnumConverter))]
public eCodecCallDirection Direction { get; set; }
[JsonProperty("id", NullValueHandling = NullValueHandling.Ignore)]
/// <summary>
/// Gets or sets the Id
/// </summary>
[JsonProperty("id", NullValueHandling = NullValueHandling.Ignore)]
public string Id { get; set; }
[JsonProperty("isOnHold", NullValueHandling = NullValueHandling.Ignore)]
/// <summary>
/// Gets or sets the IsOnHold
/// </summary>
[JsonProperty("isOnHold", NullValueHandling = NullValueHandling.Ignore)]
public bool IsOnHold { get; set; }
[JsonProperty("duration", NullValueHandling = NullValueHandling.Ignore)]
/// <summary>
/// Gets or sets the Duration
/// </summary>
[JsonProperty("duration", NullValueHandling = NullValueHandling.Ignore)]
public TimeSpan Duration { get; set; }
//public object CallMetaData { get; set; }
@@ -81,7 +77,7 @@ namespace PepperDash.Essentials.Devices.Common.Codec
{
return !(Status == eCodecCallStatus.Disconnected
|| Status == eCodecCallStatus.Disconnecting
|| Status == eCodecCallStatus.Idle
|| Status == eCodecCallStatus.Idle
|| Status == eCodecCallStatus.Unknown);
}
}
@@ -97,6 +93,10 @@ namespace PepperDash.Essentials.Devices.Common.Codec
/// </summary>
public CodecActiveCallItem CallItem { get; private set; }
/// <summary>
/// Initializes a new instance of the CodecCallStatusItemChangeEventArgs class
/// </summary>
/// <param name="item">The call item that changed</param>
public CodecCallStatusItemChangeEventArgs(CodecActiveCallItem item)
{
CallItem = item;

View File

@@ -0,0 +1,121 @@
using System;
using System.Collections.Generic;
using System.Linq;
using Newtonsoft.Json;
namespace PepperDash.Essentials.Devices.Common.Codec
{
/// <summary>
/// Represents a codec directory
/// </summary>
public class CodecDirectory
{
/// <summary>
/// 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
/// </summary>
[JsonIgnore]
public List<DirectoryItem> CurrentDirectoryResults { get; private set; }
/// <summary>
/// Gets the Contacts in the CurrentDirectoryResults
/// </summary>
[JsonProperty("contacts")]
public List<DirectoryItem> Contacts
{
get
{
return CurrentDirectoryResults.OfType<DirectoryContact>().Cast<DirectoryItem>().ToList();
}
}
/// <summary>
/// Gets the Folders in the CurrentDirectoryResults
/// </summary>
[JsonProperty("folders")]
public List<DirectoryItem> Folders
{
get
{
return CurrentDirectoryResults.OfType<DirectoryFolder>().Cast<DirectoryItem>().ToList();
}
}
/// <summary>
/// Used to store the ID of the current folder for CurrentDirectoryResults
/// Gets or sets the ResultsFolderId
/// </summary>
[JsonProperty("resultsFolderId")]
public string ResultsFolderId { get; set; }
/// <summary>
/// Constructor for <see cref="CodecDirectory"/>
/// </summary>
public CodecDirectory()
{
CurrentDirectoryResults = new List<DirectoryItem>();
}
/// <summary>
/// Adds folders to the directory
/// </summary>
/// <param name="folders"></param>
public void AddFoldersToDirectory(List<DirectoryItem> folders)
{
if (folders != null)
CurrentDirectoryResults.AddRange(folders);
SortDirectory();
}
/// <summary>
/// Adds contacts to the directory
/// </summary>
/// <param name="contacts"></param>
public void AddContactsToDirectory(List<DirectoryItem> contacts)
{
if (contacts != null)
CurrentDirectoryResults.AddRange(contacts);
SortDirectory();
}
/// <summary>
/// Filters the CurrentDirectoryResults by the predicate
/// </summary>
/// <param name="predicate"></param>
public void FilterContacts(Func<DirectoryItem, bool> predicate)
{
CurrentDirectoryResults = CurrentDirectoryResults.Where(predicate).ToList();
}
/// <summary>
/// Sorts the DirectoryResults list to display all folders alphabetically, then all contacts alphabetically
/// </summary>
private void SortDirectory()
{
var sortedFolders = new List<DirectoryItem>();
sortedFolders.AddRange(CurrentDirectoryResults.Where(f => f is DirectoryFolder));
sortedFolders.OrderBy(f => f.Name);
var sortedContacts = new List<DirectoryItem>();
sortedContacts.AddRange(CurrentDirectoryResults.Where(c => c is DirectoryContact));
sortedFolders.OrderBy(c => c.Name);
CurrentDirectoryResults.Clear();
CurrentDirectoryResults.AddRange(sortedFolders);
CurrentDirectoryResults.AddRange(sortedContacts);
}
}
}

View File

@@ -0,0 +1,146 @@
using System;
using System.Collections.Generic;
using Crestron.SimplSharp;
using PepperDash.Core;
using Serilog.Events;
namespace PepperDash.Essentials.Devices.Common.Codec
{
/// <summary>
/// Represents a CodecScheduleAwareness
/// </summary>
public class CodecScheduleAwareness
{
List<Meeting> _meetings;
/// <summary>
/// Event that is raised when a meeting event changes
/// </summary>
public event EventHandler<MeetingEventArgs> MeetingEventChange;
/// <summary>
/// Event that is raised when the meetings list has changed
/// </summary>
public event EventHandler<EventArgs> MeetingsListHasChanged;
private int _meetingWarningMinutes = 5;
//private Meeting _previousChangedMeeting;
//private eMeetingEventChangeType _previousChangeType = eMeetingEventChangeType.Unknown;
/// <summary>
/// Gets or sets the number of minutes before a meeting to issue a warning
/// </summary>
public int MeetingWarningMinutes
{
get { return _meetingWarningMinutes; }
set { _meetingWarningMinutes = value; }
}
/// <summary>
/// Setter triggers MeetingsListHasChanged event
/// </summary>
public List<Meeting> Meetings
{
get
{
return _meetings;
}
set
{
_meetings = value;
MeetingsListHasChanged?.Invoke(this, new EventArgs());
}
}
private readonly CTimer _scheduleChecker;
/// <summary>
/// Initializes a new instance of the CodecScheduleAwareness class with default poll time
/// </summary>
public CodecScheduleAwareness()
{
Meetings = new List<Meeting>();
_scheduleChecker = new CTimer(CheckSchedule, null, 1000, 1000);
}
/// <summary>
/// Initializes a new instance of the CodecScheduleAwareness class with specified poll time
/// </summary>
/// <param name="pollTime">The poll time in milliseconds for checking schedule changes</param>
public CodecScheduleAwareness(long pollTime)
{
Meetings = new List<Meeting>();
_scheduleChecker = new CTimer(CheckSchedule, null, pollTime, pollTime);
}
/// <summary>
/// Helper method to fire MeetingEventChange. Should only fire once for each changeType on each meeting
/// </summary>
/// <param name="changeType"></param>
/// <param name="meeting"></param>
private void OnMeetingChange(eMeetingEventChangeType changeType, Meeting meeting)
{
Debug.LogMessage(LogEventLevel.Verbose, "*****************OnMeetingChange. id: {0} changeType: {1}**********************", meeting.Id, changeType);
if (changeType != (changeType & meeting.NotifiedChangeTypes))
{
// Add this change type to the NotifiedChangeTypes
meeting.NotifiedChangeTypes |= changeType;
MeetingEventChange?.Invoke(this, new MeetingEventArgs() { ChangeType = changeType, Meeting = meeting });
}
else
{
Debug.LogMessage(LogEventLevel.Verbose, "Meeting: {0} already notified of changeType: {1}", meeting.Id, changeType);
}
}
/// <summary>
/// Checks the schedule to see if any MeetingEventChange updates should be fired
/// </summary>
/// <param name="o"></param>
private void CheckSchedule(object o)
{
// Iterate the meeting list and check if any meeting need to do anything
const double meetingTimeEpsilon = 0.05;
foreach (var m in Meetings)
{
var changeType = eMeetingEventChangeType.Unknown;
if (eMeetingEventChangeType.MeetingStartWarning != (m.NotifiedChangeTypes & eMeetingEventChangeType.MeetingStartWarning) && m.TimeToMeetingStart.TotalMinutes <= m.MeetingWarningMinutes.TotalMinutes && m.TimeToMeetingStart.Seconds > 0) // Meeting is about to start
{
Debug.LogMessage(LogEventLevel.Verbose, "********************* MeetingStartWarning. TotalMinutes: {0} Seconds: {1}", m.TimeToMeetingStart.TotalMinutes, m.TimeToMeetingStart.Seconds);
changeType = eMeetingEventChangeType.MeetingStartWarning;
}
else if (eMeetingEventChangeType.MeetingStart != (m.NotifiedChangeTypes & eMeetingEventChangeType.MeetingStart) && Math.Abs(m.TimeToMeetingStart.TotalMinutes) < meetingTimeEpsilon) // Meeting Start
{
Debug.LogMessage(LogEventLevel.Verbose, "********************* MeetingStart");
changeType = eMeetingEventChangeType.MeetingStart;
}
else if (eMeetingEventChangeType.MeetingEndWarning != (m.NotifiedChangeTypes & eMeetingEventChangeType.MeetingEndWarning) && m.TimeToMeetingEnd.TotalMinutes <= m.MeetingWarningMinutes.TotalMinutes && m.TimeToMeetingEnd.Seconds > 0) // Meeting is about to end
{
Debug.LogMessage(LogEventLevel.Verbose, "********************* MeetingEndWarning. TotalMinutes: {0} Seconds: {1}", m.TimeToMeetingEnd.TotalMinutes, m.TimeToMeetingEnd.Seconds);
changeType = eMeetingEventChangeType.MeetingEndWarning;
}
else if (eMeetingEventChangeType.MeetingEnd != (m.NotifiedChangeTypes & eMeetingEventChangeType.MeetingEnd) && Math.Abs(m.TimeToMeetingEnd.TotalMinutes) < meetingTimeEpsilon) // Meeting has ended
{
Debug.LogMessage(LogEventLevel.Verbose, "********************* MeetingEnd");
changeType = eMeetingEventChangeType.MeetingEnd;
}
if (changeType != eMeetingEventChangeType.Unknown)
{
OnMeetingChange(changeType, m);
}
}
}
}
}

View File

@@ -0,0 +1,37 @@
using Newtonsoft.Json;
using Newtonsoft.Json.Converters;
namespace PepperDash.Essentials.Devices.Common.Codec
{
/// <summary>
/// Represents a ContactMethod
/// </summary>
public class ContactMethod
{
/// <summary>
/// Gets or sets the ContactMethodId
/// </summary>
[JsonProperty("contactMethodId")]
public string ContactMethodId { get; set; }
/// <summary>
/// Gets or sets the Number
/// </summary>
[JsonProperty("number")]
public string Number { get; set; }
/// <summary>
/// Gets or sets the Device
/// </summary>
[JsonProperty("device")]
[JsonConverter(typeof(StringEnumConverter))]
public eContactMethodDevice Device { get; set; }
/// <summary>
/// Gets or sets the CallType
/// </summary>
[JsonProperty("callType")]
[JsonConverter(typeof(StringEnumConverter))]
public eContactMethodCallType CallType { get; set; }
}
}

View File

@@ -0,0 +1,39 @@
using System.Collections.Generic;
using Newtonsoft.Json;
namespace PepperDash.Essentials.Devices.Common.Codec
{
/// <summary>
/// Represents a DirectoryContact
/// </summary>
public class DirectoryContact : DirectoryItem
{
/// <summary>
/// Gets or sets the ContactId
/// </summary>
[JsonProperty("contactId")]
public string ContactId { get; set; }
/// <summary>
/// Gets or sets the Title
/// </summary>
[JsonProperty("title")]
public string Title { get; set; }
/// <summary>
/// Gets or sets the ContactMethods
/// </summary>
[JsonProperty("contactMethods")]
public List<ContactMethod> ContactMethods { get; set; }
/// <summary>
/// Constructor for <see cref="DirectoryContact"/>
/// </summary>
public DirectoryContact()
{
ContactMethods = new List<ContactMethod>();
}
}
}

View File

@@ -0,0 +1,21 @@
using System;
namespace PepperDash.Essentials.Devices.Common.Codec
{
/// <summary>
/// Represents a DirectoryEventArgs
/// </summary>
public class DirectoryEventArgs : EventArgs
{
/// <summary>
/// Gets or sets the Directory
/// </summary>
public CodecDirectory Directory { get; set; }
/// <summary>
/// Gets or sets the DirectoryIsOnRoot
/// </summary>
public bool DirectoryIsOnRoot { get; set; }
}
}

View File

@@ -0,0 +1,27 @@
using System.Collections.Generic;
using Newtonsoft.Json;
namespace PepperDash.Essentials.Devices.Common.Codec
{
/// <summary>
/// Represents a DirectoryFolder
/// </summary>
public class DirectoryFolder : DirectoryItem
{
/// <summary>
/// Gets or sets the Contacts
/// </summary>
[JsonProperty("contacts")]
public List<DirectoryContact> Contacts { get; set; }
/// <summary>
/// Constructor for <see cref="DirectoryFolder"/>
/// </summary>
public DirectoryFolder()
{
Contacts = new List<DirectoryContact>();
}
}
}

View File

@@ -0,0 +1,41 @@
using System;
using Newtonsoft.Json;
namespace PepperDash.Essentials.Devices.Common.Codec
{
/// <summary>
/// Represents a DirectoryItem
/// </summary>
public class DirectoryItem : ICloneable
{
/// <summary>
/// Clone method
/// </summary>
public object Clone()
{
return MemberwiseClone();
}
/// <summary>
/// Gets or sets the FolderId
/// </summary>
[JsonProperty("folderId")]
public string FolderId { get; set; }
/// <summary>
/// Gets or sets the Name
/// </summary>
[JsonProperty("name")]
public string Name { get; set; }
/// <summary>
/// Gets or sets the ParentFolderId
/// </summary>
[JsonProperty("parentFolderId")]
public string ParentFolderId { get; set; }
}
}

View File

@@ -1,31 +1,65 @@
using Crestron.SimplSharpPro;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace PepperDash.Essentials.Devices.Common.Codec
{
namespace PepperDash.Essentials.Devices.Common.Codec
{
/// <summary>
/// Describes a cisco codec device that can allow configuration of cameras
/// </summary>
public interface ICiscoCodecCameraConfig
{
/// <summary>
/// Sets the assigned serial number for the specified camera
/// </summary>
/// <param name="cameraId">The camera identifier</param>
/// <param name="serialNumber">The serial number to assign</param>
void SetCameraAssignedSerialNumber(uint cameraId, string serialNumber);
/// <summary>
/// Sets the name for the camera on the specified video connector
/// </summary>
/// <param name="videoConnectorId">The video connector identifier</param>
/// <param name="name">The name to assign</param>
void SetCameraName(uint videoConnectorId, string name);
/// <summary>
/// Sets the input source type for the specified video connector
/// </summary>
/// <param name="videoConnectorId">The video connector identifier</param>
/// <param name="sourceType">The source type to set</param>
void SetInputSourceType(uint videoConnectorId, eCiscoCodecInputSourceType sourceType);
}
/// <summary>
/// Enumeration of Cisco codec input source types
/// </summary>
public enum eCiscoCodecInputSourceType
{
/// <summary>
/// PC source type
/// </summary>
PC,
/// <summary>
/// Camera source type
/// </summary>
camera,
/// <summary>
/// Document camera source type
/// </summary>
document_camera,
/// <summary>
/// Media player source type
/// </summary>
mediaplayer,
/// <summary>
/// Other source type
/// </summary>
other,
/// <summary>
/// Whiteboard source type
/// </summary>
whiteboard
}
}

View File

@@ -1,10 +1,4 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Crestron.SimplSharp;
namespace PepperDash.Essentials.Devices.Common.Codec
namespace PepperDash.Essentials.Devices.Common.Codec
{
/// <summary>
/// Defines the contract for IHasCallHold

View File

@@ -0,0 +1,14 @@
using System.Collections.Generic;
using PepperDash.Essentials.Devices.Common.Codec;
/// <summary>
/// Defines the contract for IHasDirectoryHistoryStack
/// </summary>
public interface IHasDirectoryHistoryStack : IHasDirectory
{
/// <summary>
/// Gets the DirectoryBrowseHistoryStack
/// </summary>
Stack<CodecDirectory> DirectoryBrowseHistoryStack { get; }
}

View File

@@ -1,10 +1,4 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Crestron.SimplSharp;
using PepperDash.Essentials.Core;
using PepperDash.Essentials.Core;
namespace PepperDash.Essentials.Devices.Common.Codec
{
@@ -34,6 +28,9 @@ namespace PepperDash.Essentials.Devices.Common.Codec
void ToggleDoNotDisturbMode();
}
/// <summary>
/// Defines the contract for devices that support Do Not Disturb mode with timeout functionality
/// </summary>
public interface IHasDoNotDisturbModeWithTimeout : IHasDoNotDisturbMode
{
/// <summary>

View File

@@ -1,25 +1,54 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Crestron.SimplSharp;
using PepperDash.Essentials.Core;
using PepperDash.Essentials.Devices.Common.VideoCodec.Cisco;
namespace PepperDash.Essentials.Devices.Common.Codec
{
/// <summary>
/// Defines the contract for IHasExternalSourceSwitching
/// </summary>
/// <summary>
/// Defines the contract for IHasExternalSourceSwitching
/// </summary>
public interface IHasExternalSourceSwitching
{
/// <summary>
/// Gets a value indicating whether the external source list is enabled
/// </summary>
bool ExternalSourceListEnabled { get; }
string ExternalSourceInputPort { get; }
/// <summary>
/// Gets the external source input port identifier
/// </summary>
string ExternalSourceInputPort { get; }
/// <summary>
/// Adds an external source to the available sources
/// </summary>
/// <param name="connectorId">The connector identifier</param>
/// <param name="key">The unique key for the source</param>
/// <param name="name">The display name for the source</param>
/// <param name="type">The type of external source</param>
void AddExternalSource(string connectorId, string key, string name, eExternalSourceType type);
/// <summary>
/// Sets the state of the specified external source
/// </summary>
/// <param name="key">The unique key of the external source</param>
/// <param name="mode">The mode to set for the source</param>
void SetExternalSourceState(string key, eExternalSourceMode mode);
/// <summary>
/// Clears all external sources from the list
/// </summary>
void ClearExternalSources();
void SetSelectedSource(string key);
Action<string, string> RunRouteAction { set;}
/// <summary>
/// Sets the selected source by its key
/// </summary>
/// <param name="key">The unique key of the source to select</param>
void SetSelectedSource(string key);
/// <summary>
/// Sets the action to run when routing between sources
/// </summary>
Action<string, string> RunRouteAction { set; }
}
}

View File

@@ -0,0 +1,13 @@
namespace PepperDash.Essentials.Devices.Common.Codec
{
/// <summary>
/// Defines the contract for IInvitableContact
/// </summary>
public interface IInvitableContact
{
/// <summary>
/// Gets a value indicating whether this contact is invitable
/// </summary>
bool IsInvitableContact { get; }
}
}

View File

@@ -0,0 +1,22 @@
using Newtonsoft.Json;
namespace PepperDash.Essentials.Devices.Common.Codec
{
/// <summary>
/// Represents an InvitableDirectoryContact
/// </summary>
public class InvitableDirectoryContact : DirectoryContact, IInvitableContact
{
/// <summary>
/// Gets a value indicating whether this contact is invitable
/// </summary>
[JsonProperty("isInvitableContact")]
public bool IsInvitableContact
{
get
{
return this is IInvitableContact;
}
}
}
}

View File

@@ -0,0 +1,182 @@
using System;
using System.Collections.Generic;
using Newtonsoft.Json;
namespace PepperDash.Essentials.Devices.Common.Codec
{
/// <summary>
/// Represents a Meeting
/// </summary>
public class Meeting
{
/// <summary>
/// Minutes before the meeting to show warning
/// </summary>
[JsonProperty("minutesBeforeMeeting")]
public int MinutesBeforeMeeting;
/// <summary>
/// Gets or sets the meeting ID
/// </summary>
[JsonProperty("id")]
public string Id { get; set; }
/// <summary>
/// Gets or sets the meeting organizer
/// </summary>
[JsonProperty("organizer")]
public string Organizer { get; set; }
/// <summary>
/// Gets or sets the Title
/// </summary>
[JsonProperty("title")]
public string Title { get; set; }
/// <summary>
/// Gets or sets the Agenda
/// </summary>
[JsonProperty("agenda")]
public string Agenda { get; set; }
/// <summary>
/// Gets the meeting warning time span in minutes before the meeting starts
/// </summary>
[JsonProperty("meetingWarningMinutes")]
public TimeSpan MeetingWarningMinutes
{
get { return TimeSpan.FromMinutes(MinutesBeforeMeeting); }
}
/// <summary>
/// Gets the time remaining until the meeting starts
/// </summary>
[JsonProperty("timeToMeetingStart")]
public TimeSpan TimeToMeetingStart
{
get
{
return StartTime - DateTime.Now;
}
}
/// <summary>
/// Gets the time remaining until the meeting ends
/// </summary>
[JsonProperty("timeToMeetingEnd")]
public TimeSpan TimeToMeetingEnd
{
get
{
return EndTime - DateTime.Now;
}
}
/// <summary>
/// Gets or sets the StartTime
/// </summary>
[JsonProperty("startTime")]
public DateTime StartTime { get; set; }
/// <summary>
/// Gets or sets the EndTime
/// </summary>
[JsonProperty("endTime")]
public DateTime EndTime { get; set; }
/// <summary>
/// Gets the duration of the meeting
/// </summary>
[JsonProperty("duration")]
public TimeSpan Duration
{
get
{
return EndTime - StartTime;
}
}
/// <summary>
/// Gets or sets the Privacy
/// </summary>
[JsonProperty("privacy")]
public eMeetingPrivacy Privacy { get; set; }
/// <summary>
/// Gets a value indicating whether the meeting can be joined
/// </summary>
[JsonProperty("joinable")]
public bool Joinable
{
get
{
var joinable = StartTime.AddMinutes(-MinutesBeforeMeeting) <= DateTime.Now
&& DateTime.Now <= EndTime.AddSeconds(-_joinableCooldownSeconds);
//Debug.LogMessage(LogEventLevel.Verbose, "Meeting Id: {0} joinable: {1}", Id, joinable);
return joinable;
}
}
/// <summary>
/// Gets or sets the Dialable
/// </summary>
[JsonProperty("dialable")]
public bool Dialable { get; set; }
//public string ConferenceNumberToDial { get; set; }
/// <summary>
/// Gets or sets the ConferencePassword
/// </summary>
[JsonProperty("conferencePassword")]
public string ConferencePassword { get; set; }
/// <summary>
/// Gets or sets the IsOneButtonToPushMeeting
/// </summary>
[JsonProperty("isOneButtonToPushMeeting")]
public bool IsOneButtonToPushMeeting { get; set; }
/// <summary>
/// Gets or sets the Calls
/// </summary>
[JsonProperty("calls")]
public List<Call> Calls { get; private set; }
/// <summary>
/// Tracks the change types that have already been notified for
/// Gets or sets the NotifiedChangeTypes
/// </summary>
[JsonIgnore]
public eMeetingEventChangeType NotifiedChangeTypes { get; set; }
[JsonIgnore] private readonly int _joinableCooldownSeconds;
/// <summary>
/// Constructor for Meeting <see cref="Meeting"/>
/// </summary>
public Meeting()
{
Calls = new List<Call>();
_joinableCooldownSeconds = 300;
}
/// <summary>
/// Constructor for Meeting <see cref="Meeting"/>
/// </summary>
/// <param name="joinableCooldownSeconds">Number of seconds after meeting start when it is no longer joinable</param>
public Meeting(int joinableCooldownSeconds)
{
Calls = new List<Call>();
_joinableCooldownSeconds = joinableCooldownSeconds;
}
#region Overrides of Object
/// <summary>
/// ToString method
/// </summary>
/// <inheritdoc />
public override string ToString()
{
return string.Format("{0}:{1}: {2}-{3}", Title, Agenda, StartTime, EndTime);
}
#endregion
}
}

View File

@@ -0,0 +1,22 @@
using System;
namespace PepperDash.Essentials.Devices.Common.Codec
{
/// <summary>
/// Represents a MeetingEventArgs
/// </summary>
public class MeetingEventArgs : EventArgs
{
/// <summary>
/// Gets or sets the ChangeType
/// </summary>
public eMeetingEventChangeType ChangeType { get; set; }
/// <summary>
/// Gets or sets the Meeting
/// </summary>
public Meeting Meeting { get; set; }
}
}

View File

@@ -1,10 +1,4 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Crestron.SimplSharp;
namespace PepperDash.Essentials.Devices.Common.Codec
namespace PepperDash.Essentials.Devices.Common.Codec
{
/// <summary>
@@ -12,7 +6,20 @@ namespace PepperDash.Essentials.Devices.Common.Codec
/// </summary>
public enum eCodecCallDirection
{
Unknown = 0, Incoming, Outgoing
/// <summary>
/// Unknown call direction
/// </summary>
Unknown = 0,
/// <summary>
/// Incoming call direction
/// </summary>
Incoming,
/// <summary>
/// Outgoing call direction
/// </summary>
Outgoing
}
/// <summary>

View File

@@ -1,27 +1,68 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Crestron.SimplSharp;
namespace PepperDash.Essentials.Devices.Common.Codec
namespace PepperDash.Essentials.Devices.Common.Codec
{
/// <summary>
/// Enumeration of eCodecCallStatus values
/// </summary>
public enum eCodecCallStatus
{
/// <summary>
/// Unknown call status
/// </summary>
Unknown = 0,
Connected,
Connecting,
Dialing,
/// <summary>
/// Call is connected
/// </summary>
Connected,
/// <summary>
/// Call is connecting
/// </summary>
Connecting,
/// <summary>
/// Call is dialing
/// </summary>
Dialing,
/// <summary>
/// Call is disconnected
/// </summary>
Disconnected,
Disconnecting,
EarlyMedia,
/// <summary>
/// Call is disconnecting
/// </summary>
Disconnecting,
/// <summary>
/// Early media is being sent/received
/// </summary>
EarlyMedia,
/// <summary>
/// Call is idle
/// </summary>
Idle,
OnHold,
Ringing,
Preserved,
/// <summary>
/// Call is on hold
/// </summary>
OnHold,
/// <summary>
/// Call is ringing
/// </summary>
Ringing,
/// <summary>
/// Call is preserved
/// </summary>
Preserved,
/// <summary>
/// Call is remote preserved
/// </summary>
RemotePreserved,
}

View File

@@ -1,10 +1,4 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Crestron.SimplSharp;
namespace PepperDash.Essentials.Devices.Common.Codec
namespace PepperDash.Essentials.Devices.Common.Codec
{
/// <summary>
@@ -12,10 +6,29 @@ namespace PepperDash.Essentials.Devices.Common.Codec
/// </summary>
public enum eCodecCallType
{
Unknown = 0,
Audio,
Video,
AudioCanEscalate,
/// <summary>
/// Unknown call type
/// </summary>
Unknown = 0,
/// <summary>
/// Audio-only call type
/// </summary>
Audio,
/// <summary>
/// Video call type
/// </summary>
Video,
/// <summary>
/// Audio call that can be escalated to video
/// </summary>
AudioCanEscalate,
/// <summary>
/// Forward all call type
/// </summary>
ForwardAllCall
}

View File

@@ -0,0 +1,21 @@
namespace PepperDash.Essentials.Devices.Common.Codec
{
/// <summary>
/// Enumeration of eContactMethodCallType values
/// </summary>
public enum eContactMethodCallType
{
/// <summary>
/// Unknown call type
/// </summary>
Unknown = 0,
/// <summary>
/// Audio call type
/// </summary>
Audio,
/// <summary>
/// Video call type
/// </summary>
Video
}
}

View File

@@ -0,0 +1,29 @@
namespace PepperDash.Essentials.Devices.Common.Codec
{
/// <summary>
/// Enumeration of eContactMethodDevice values
/// </summary>
public enum eContactMethodDevice
{
/// <summary>
/// Unknown contact method
/// </summary>
Unknown = 0,
/// <summary>
/// Mobile contact method
/// </summary>
Mobile,
/// <summary>
/// Other contact method
/// </summary>
Other,
/// <summary>
/// Telephone contact method
/// </summary>
Telephone,
/// <summary>
/// Video contact method
/// </summary>
Video
}
}

View File

@@ -0,0 +1,35 @@
using System;
namespace PepperDash.Essentials.Devices.Common.Codec
{
/// <summary>
/// Enumeration of eMeetingEventChangeType values
/// </summary>
[Flags]
public enum eMeetingEventChangeType
{
/// <summary>
/// Unknown change type
/// </summary>
Unknown = 0,
/// <summary>
/// Meeting start warning
/// </summary>
MeetingStartWarning = 1,
/// <summary>
/// Meeting start
/// </summary>
MeetingStart = 2,
/// <summary>
/// Meeting end warning
/// </summary>
MeetingEndWarning = 4,
/// <summary>
/// Meeting end
/// </summary>
MeetingEnd = 8
}
}

View File

@@ -1,18 +1,23 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Crestron.SimplSharp;
namespace PepperDash.Essentials.Devices.Common.Codec
namespace PepperDash.Essentials.Devices.Common.Codec
{
/// <summary>
/// Enumeration of eMeetingPrivacy values
/// </summary>
public enum eMeetingPrivacy
{
/// <summary>
/// Unknown meeting privacy level
/// </summary>
Unknown = 0,
/// <summary>
/// Public meeting
/// </summary>
Public,
/// <summary>
/// Private meeting
/// </summary>
Private
}

View File

@@ -1,10 +1,4 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Crestron.SimplSharp;
using PepperDash.Essentials.Core;
using PepperDash.Essentials.Core;
namespace PepperDash.Essentials.Devices.Common.Codec
{

View File

@@ -1,8 +1,4 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Crestron.SimplSharp;
using System.Collections.Generic;
namespace PepperDash.Essentials.Devices.Common.Codec
{
@@ -11,6 +7,9 @@ namespace PepperDash.Essentials.Devices.Common.Codec
/// </summary>
public interface IHasCallFavorites
{
/// <summary>
/// Gets the call favorites for this device
/// </summary>
CodecCallFavorites CallFavorites { get; }
}
@@ -24,6 +23,9 @@ namespace PepperDash.Essentials.Devices.Common.Codec
/// </summary>
public List<CodecActiveCallItem> Favorites { get; set; }
/// <summary>
/// Initializes a new instance of the CodecCallFavorites class
/// </summary>
public CodecCallFavorites()
{
Favorites = new List<CodecActiveCallItem>();

View File

@@ -2,10 +2,9 @@
using System;
using System.Collections.Generic;
using PepperDash.Essentials.Devices.Common.VideoCodec;
using Newtonsoft.Json;
using Newtonsoft.Json.Converters;
using PepperDash.Essentials.Devices.Common.VideoCodec;
namespace PepperDash.Essentials.Devices.Common.Codec
{
@@ -15,8 +14,15 @@ namespace PepperDash.Essentials.Devices.Common.Codec
/// </summary>
public interface IHasCallHistory
{
/// <summary>
/// Gets the call history for this device
/// </summary>
CodecCallHistory CallHistory { get; }
/// <summary>
/// Removes the specified call history entry
/// </summary>
/// <param name="entry">The call history entry to remove</param>
void RemoveCallHistoryEntry(CodecCallHistory.CallHistoryEntry entry);
}
@@ -25,9 +31,24 @@ namespace PepperDash.Essentials.Devices.Common.Codec
/// </summary>
public enum eCodecOccurrenceType
{
/// <summary>
/// Unknown occurrence type
/// </summary>
Unknown = 0,
/// <summary>
/// Call was placed (outgoing)
/// </summary>
Placed = 1,
/// <summary>
/// Call was received (incoming)
/// </summary>
Received = 2,
/// <summary>
/// Call received no answer
/// </summary>
NoAnswer = 3,
}
@@ -36,6 +57,9 @@ namespace PepperDash.Essentials.Devices.Common.Codec
/// </summary>
public class CodecCallHistory
{
/// <summary>
/// Event that is raised when the recent calls list has changed
/// </summary>
public event EventHandler<EventArgs> RecentCallsListHasChanged;
/// <summary>
@@ -48,6 +72,9 @@ namespace PepperDash.Essentials.Devices.Common.Codec
/// </summary>
CallHistoryEntry ListEmptyEntry;
/// <summary>
/// Initializes a new instance of the CodecCallHistory class
/// </summary>
public CodecCallHistory()
{
ListEmptyEntry = new CallHistoryEntry() { Name = "No Recent Calls" };
@@ -80,15 +107,22 @@ namespace PepperDash.Essentials.Devices.Common.Codec
/// </summary>
public class CallHistoryEntry : CodecActiveCallItem
{
[JsonConverter(typeof(IsoDateTimeConverter))]
[JsonProperty("startTime")]
/// <summary>
/// Gets or sets the StartTime
/// </summary>
[JsonConverter(typeof(IsoDateTimeConverter))]
[JsonProperty("startTime")]
public DateTime StartTime { get; set; }
/// <summary>
/// Gets or sets the occurrence type for this call history entry
/// </summary>
[JsonConverter(typeof(StringEnumConverter))]
[JsonProperty("occurrenceType")]
public eCodecOccurrenceType OccurrenceType { get; set; }
/// <summary>
/// Gets or sets the occurrence history identifier
/// </summary>
[JsonProperty("occurrenceHistoryId")]
public string OccurrenceHistoryId { get; set; }
}
@@ -119,7 +153,7 @@ namespace PepperDash.Essentials.Devices.Common.Codec
}
// Check if list is empty and if so, add an item to display No Recent Calls
if(genericEntries.Count == 0)
if (genericEntries.Count == 0)
genericEntries.Add(ListEmptyEntry);
RecentCalls = genericEntries;

View File

@@ -1,11 +1,4 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Crestron.SimplSharp;
using PepperDash.Core;
using PepperDash.Essentials.Core;
using PepperDash.Essentials.Core;
namespace PepperDash.Essentials.Devices.Common.Codec
@@ -15,12 +8,29 @@ namespace PepperDash.Essentials.Devices.Common.Codec
/// </summary>
public interface IHasContentSharing
{
/// <summary>
/// Gets feedback indicating whether content sharing is currently active
/// </summary>
BoolFeedback SharingContentIsOnFeedback { get; }
/// <summary>
/// Gets feedback about the current sharing source
/// </summary>
StringFeedback SharingSourceFeedback { get; }
/// <summary>
/// Gets a value indicating whether content should be automatically shared while in a call
/// </summary>
bool AutoShareContentWhileInCall { get; }
/// <summary>
/// Starts content sharing
/// </summary>
void StartSharing();
/// <summary>
/// Stops content sharing
/// </summary>
void StopSharing();
}

View File

@@ -1,10 +1,4 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Crestron.SimplSharp;
using PepperDash.Essentials.Core;
namespace PepperDash.Essentials.Devices.Common.Codec
{
@@ -15,15 +9,49 @@ namespace PepperDash.Essentials.Devices.Common.Codec
{
// Add requirements for Dialer functionality
/// <summary>
/// Event that is raised when call status changes
/// </summary>
event EventHandler<CodecCallStatusItemChangeEventArgs> CallStatusChange;
/// <summary>
/// Dials the specified number
/// </summary>
/// <param name="number">The number to dial</param>
void Dial(string number);
/// <summary>
/// Ends the specified active call
/// </summary>
/// <param name="activeCall">The active call to end</param>
void EndCall(CodecActiveCallItem activeCall);
/// <summary>
/// Ends all active calls
/// </summary>
void EndAllCalls();
/// <summary>
/// Accepts the specified incoming call
/// </summary>
/// <param name="item">The call item to accept</param>
void AcceptCall(CodecActiveCallItem item);
/// <summary>
/// Rejects the specified incoming call
/// </summary>
/// <param name="item">The call item to reject</param>
void RejectCall(CodecActiveCallItem item);
/// <summary>
/// Sends DTMF digits during a call
/// </summary>
/// <param name="digit">The DTMF digit(s) to send</param>
void SendDtmf(string digit);
/// <summary>
/// Gets a value indicating whether the device is currently in a call
/// </summary>
bool IsInCall { get; }
}

View File

@@ -1,319 +1,59 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Crestron.SimplSharp;
using Newtonsoft.Json;
using Newtonsoft.Json.Converters;
using PepperDash.Core;
using PepperDash.Essentials.Core;
using PepperDash.Essentials.Devices.Common.VideoCodec;
namespace PepperDash.Essentials.Devices.Common.Codec
{
/// <summary>
/// Defines the API for codecs with a directory
/// </summary>
/// <summary>
/// Defines the API for codecs with a directory
/// </summary>
public interface IHasDirectory
{
/// <summary>
/// Event that fires when a directory result is returned from the codec
/// </summary>
event EventHandler<DirectoryEventArgs> DirectoryResultReturned;
/// <summary>
/// Gets the DirectoryRoot
/// </summary>
CodecDirectory DirectoryRoot { get; }
/// <summary>
/// Gets the CurrentDirectoryResult
/// </summary>
CodecDirectory CurrentDirectoryResult { get; }
/// <summary>
/// Gets the PhonebookSyncState
/// </summary>
CodecPhonebookSyncState PhonebookSyncState { get; }
/// <summary>
/// Method to initiate a search of the directory on the server
/// </summary>
void SearchDirectory(string searchString);
/// <summary>
/// Method to get the contents of a specific folder in the directory on the server
/// </summary>
void GetDirectoryFolderContents(string folderId);
/// <summary>
/// Method to set the current directory to the root folder
/// </summary>
void SetCurrentDirectoryToRoot();
/// <summary>
/// Method to get the contents of the parent folder in the directory on the server
/// </summary>
void GetDirectoryParentFolderContents();
/// <summary>
/// Gets the CurrentDirectoryResultIsNotDirectoryRoot
/// </summary>
BoolFeedback CurrentDirectoryResultIsNotDirectoryRoot { get; }
}
/// <summary>
/// Defines the contract for IHasDirectoryHistoryStack
/// </summary>
public interface IHasDirectoryHistoryStack : IHasDirectory
{
Stack<CodecDirectory> DirectoryBrowseHistoryStack { get; }
}
/// <summary>
/// Represents a DirectoryEventArgs
/// </summary>
public class DirectoryEventArgs : EventArgs
{
/// <summary>
/// Gets or sets the Directory
/// </summary>
public CodecDirectory Directory { get; set; }
/// <summary>
/// Gets or sets the DirectoryIsOnRoot
/// </summary>
public bool DirectoryIsOnRoot { get; set; }
}
/// <summary>
/// Represents a codec directory
/// </summary>
public class CodecDirectory
{
/// <summary>
/// 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
/// </summary>
[JsonIgnore]
public List<DirectoryItem> CurrentDirectoryResults { get; private set; }
[JsonProperty("contacts")]
public List<DirectoryItem> Contacts
{
get
{
return CurrentDirectoryResults.OfType<DirectoryContact>().Cast<DirectoryItem>().ToList();
}
}
[JsonProperty("folders")]
public List<DirectoryItem> Folders
{
get
{
return CurrentDirectoryResults.OfType<DirectoryFolder>().Cast<DirectoryItem>().ToList();
}
}
/// <summary>
/// Used to store the ID of the current folder for CurrentDirectoryResults
/// </summary>
[JsonProperty("resultsFolderId")]
/// <summary>
/// Gets or sets the ResultsFolderId
/// </summary>
public string ResultsFolderId { get; set; }
public CodecDirectory()
{
CurrentDirectoryResults = new List<DirectoryItem>();
}
/// <summary>
/// Adds folders to the directory
/// </summary>
/// <param name="folders"></param>
/// <summary>
/// AddFoldersToDirectory method
/// </summary>
public void AddFoldersToDirectory(List<DirectoryItem> folders)
{
if(folders != null)
CurrentDirectoryResults.AddRange(folders);
SortDirectory();
}
/// <summary>
/// Adds contacts to the directory
/// </summary>
/// <param name="contacts"></param>
/// <summary>
/// AddContactsToDirectory method
/// </summary>
public void AddContactsToDirectory(List<DirectoryItem> contacts)
{
if(contacts != null)
CurrentDirectoryResults.AddRange(contacts);
SortDirectory();
}
/// <summary>
/// Filters the CurrentDirectoryResults by the predicate
/// </summary>
/// <param name="predicate"></param>
/// <summary>
/// FilterContacts method
/// </summary>
public void FilterContacts(Func<DirectoryItem, bool> predicate)
{
CurrentDirectoryResults = CurrentDirectoryResults.Where(predicate).ToList();
}
/// <summary>
/// Sorts the DirectoryResults list to display all folders alphabetically, then all contacts alphabetically
/// </summary>
private void SortDirectory()
{
var sortedFolders = new List<DirectoryItem>();
sortedFolders.AddRange(CurrentDirectoryResults.Where(f => f is DirectoryFolder));
sortedFolders.OrderBy(f => f.Name);
var sortedContacts = new List<DirectoryItem>();
sortedContacts.AddRange(CurrentDirectoryResults.Where(c => c is DirectoryContact));
sortedFolders.OrderBy(c => c.Name);
CurrentDirectoryResults.Clear();
CurrentDirectoryResults.AddRange(sortedFolders);
CurrentDirectoryResults.AddRange(sortedContacts);
}
}
/// <summary>
/// Defines the contract for IInvitableContact
/// </summary>
public interface IInvitableContact
{
bool IsInvitableContact { get; }
}
public class InvitableDirectoryContact : DirectoryContact, IInvitableContact
{
[JsonProperty("isInvitableContact")]
public bool IsInvitableContact
{
get
{
return this is IInvitableContact;
}
}
}
/// <summary>
/// Represents a DirectoryItem
/// </summary>
public class DirectoryItem : ICloneable
{
/// <summary>
/// Clone method
/// </summary>
public object Clone()
{
return this.MemberwiseClone();
}
[JsonProperty("folderId")]
public string FolderId { get; set; }
[JsonProperty("name")]
/// <summary>
/// Gets or sets the Name
/// </summary>
public string Name { get; set; }
[JsonProperty("parentFolderId")]
/// <summary>
/// Gets or sets the ParentFolderId
/// </summary>
public string ParentFolderId { get; set; }
}
/// <summary>
/// Represents a DirectoryFolder
/// </summary>
public class DirectoryFolder : DirectoryItem
{
[JsonProperty("contacts")]
/// <summary>
/// Gets or sets the Contacts
/// </summary>
public List<DirectoryContact> Contacts { get; set; }
public DirectoryFolder()
{
Contacts = new List<DirectoryContact>();
}
}
/// <summary>
/// Represents a DirectoryContact
/// </summary>
public class DirectoryContact : DirectoryItem
{
[JsonProperty("contactId")]
/// <summary>
/// Gets or sets the ContactId
/// </summary>
public string ContactId { get; set; }
[JsonProperty("title")]
public string Title { get; set; }
[JsonProperty("contactMethods")]
public List<ContactMethod> ContactMethods { get; set; }
public DirectoryContact()
{
ContactMethods = new List<ContactMethod>();
}
}
/// <summary>
/// Represents a ContactMethod
/// </summary>
public class ContactMethod
{
[JsonProperty("contactMethodId")]
/// <summary>
/// Gets or sets the ContactMethodId
/// </summary>
public string ContactMethodId { get; set; }
[JsonProperty("number")]
public string Number { get; set; }
[JsonProperty("device")]
[JsonConverter(typeof(StringEnumConverter))]
/// <summary>
/// Gets or sets the Device
/// </summary>
public eContactMethodDevice Device { get; set; }
[JsonProperty("callType")]
[JsonConverter(typeof(StringEnumConverter))]
/// <summary>
/// Gets or sets the CallType
/// </summary>
public eContactMethodCallType CallType { get; set; }
}
/// <summary>
/// Enumeration of eContactMethodDevice values
/// </summary>
public enum eContactMethodDevice
{
Unknown = 0,
Mobile,
Other,
Telephone,
Video
}
/// <summary>
/// Enumeration of eContactMethodCallType values
/// </summary>
public enum eContactMethodCallType
{
Unknown = 0,
Audio,
Video
}
}

View File

@@ -1,339 +1,20 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Crestron.SimplSharp;
using PepperDash.Core;
using Newtonsoft.Json;
using Serilog.Events;
namespace PepperDash.Essentials.Devices.Common.Codec
namespace PepperDash.Essentials.Devices.Common.Codec
{
[Flags]
/// <summary>
/// Enumeration of eMeetingEventChangeType values
/// </summary>
public enum eMeetingEventChangeType
{
Unknown = 0,
MeetingStartWarning = 1,
MeetingStart = 2,
MeetingEndWarning = 4,
MeetingEnd = 8
}
/// <summary>
/// Defines the contract for IHasScheduleAwareness
/// </summary>
public interface IHasScheduleAwareness
{
/// <summary>
/// Gets the CodecScheduleAwareness instance
/// </summary>
CodecScheduleAwareness CodecSchedule { get; }
/// <summary>
/// Method to initiate getting the schedule from the server
/// </summary>
void GetSchedule();
}
/// <summary>
/// Represents a CodecScheduleAwareness
/// </summary>
public class CodecScheduleAwareness
{
List<Meeting> _meetings;
public event EventHandler<MeetingEventArgs> MeetingEventChange;
public event EventHandler<EventArgs> MeetingsListHasChanged;
private int _meetingWarningMinutes = 5;
//private Meeting _previousChangedMeeting;
//private eMeetingEventChangeType _previousChangeType = eMeetingEventChangeType.Unknown;
public int MeetingWarningMinutes
{
get { return _meetingWarningMinutes; }
set { _meetingWarningMinutes = value; }
}
/// <summary>
/// Setter triggers MeetingsListHasChanged event
/// </summary>
public List<Meeting> Meetings
{
get
{
return _meetings;
}
set
{
_meetings = value;
MeetingsListHasChanged?.Invoke(this, new EventArgs());
}
}
private readonly CTimer _scheduleChecker;
public CodecScheduleAwareness()
{
Meetings = new List<Meeting>();
_scheduleChecker = new CTimer(CheckSchedule, null, 1000, 1000);
}
public CodecScheduleAwareness(long pollTime)
{
Meetings = new List<Meeting>();
_scheduleChecker = new CTimer(CheckSchedule, null, pollTime, pollTime);
}
/// <summary>
/// Helper method to fire MeetingEventChange. Should only fire once for each changeType on each meeting
/// </summary>
/// <param name="changeType"></param>
/// <param name="meeting"></param>
private void OnMeetingChange(eMeetingEventChangeType changeType, Meeting meeting)
{
Debug.LogMessage(LogEventLevel.Verbose, "*****************OnMeetingChange. id: {0} changeType: {1}**********************", meeting.Id, changeType);
if (changeType != (changeType & meeting.NotifiedChangeTypes))
{
// Add this change type to the NotifiedChangeTypes
meeting.NotifiedChangeTypes |= changeType;
MeetingEventChange?.Invoke(this, new MeetingEventArgs() { ChangeType = changeType, Meeting = meeting });
}
else
{
Debug.LogMessage(LogEventLevel.Verbose, "Meeting: {0} already notified of changeType: {1}", meeting.Id, changeType);
}
}
/// <summary>
/// Checks the schedule to see if any MeetingEventChange updates should be fired
/// </summary>
/// <param name="o"></param>
private void CheckSchedule(object o)
{
// Iterate the meeting list and check if any meeting need to do anything
const double meetingTimeEpsilon = 0.05;
foreach (var m in Meetings)
{
var changeType = eMeetingEventChangeType.Unknown;
if (eMeetingEventChangeType.MeetingStartWarning != (m.NotifiedChangeTypes & eMeetingEventChangeType.MeetingStartWarning) && m.TimeToMeetingStart.TotalMinutes <= m.MeetingWarningMinutes.TotalMinutes && m.TimeToMeetingStart.Seconds > 0) // Meeting is about to start
{
Debug.LogMessage(LogEventLevel.Verbose, "********************* MeetingStartWarning. TotalMinutes: {0} Seconds: {1}", m.TimeToMeetingStart.TotalMinutes, m.TimeToMeetingStart.Seconds);
changeType = eMeetingEventChangeType.MeetingStartWarning;
}
else if (eMeetingEventChangeType.MeetingStart != (m.NotifiedChangeTypes & eMeetingEventChangeType.MeetingStart) && Math.Abs(m.TimeToMeetingStart.TotalMinutes) < meetingTimeEpsilon) // Meeting Start
{
Debug.LogMessage(LogEventLevel.Verbose, "********************* MeetingStart");
changeType = eMeetingEventChangeType.MeetingStart;
}
else if (eMeetingEventChangeType.MeetingEndWarning != (m.NotifiedChangeTypes & eMeetingEventChangeType.MeetingEndWarning) && m.TimeToMeetingEnd.TotalMinutes <= m.MeetingWarningMinutes.TotalMinutes && m.TimeToMeetingEnd.Seconds > 0) // Meeting is about to end
{
Debug.LogMessage(LogEventLevel.Verbose, "********************* MeetingEndWarning. TotalMinutes: {0} Seconds: {1}", m.TimeToMeetingEnd.TotalMinutes, m.TimeToMeetingEnd.Seconds);
changeType = eMeetingEventChangeType.MeetingEndWarning;
}
else if (eMeetingEventChangeType.MeetingEnd != (m.NotifiedChangeTypes & eMeetingEventChangeType.MeetingEnd) && Math.Abs(m.TimeToMeetingEnd.TotalMinutes) < meetingTimeEpsilon) // Meeting has ended
{
Debug.LogMessage(LogEventLevel.Verbose, "********************* MeetingEnd");
changeType = eMeetingEventChangeType.MeetingEnd;
}
if (changeType != eMeetingEventChangeType.Unknown)
{
OnMeetingChange(changeType, m);
}
}
}
}
/// <summary>
/// Represents a Meeting
/// </summary>
public class Meeting
{
[JsonProperty("minutesBeforeMeeting")]
public int MinutesBeforeMeeting;
[JsonProperty("id")]
public string Id { get; set; }
[JsonProperty("organizer")]
public string Organizer { get; set; }
[JsonProperty("title")]
/// <summary>
/// Gets or sets the Title
/// </summary>
public string Title { get; set; }
[JsonProperty("agenda")]
/// <summary>
/// Gets or sets the Agenda
/// </summary>
public string Agenda { get; set; }
[JsonProperty("meetingWarningMinutes")]
public TimeSpan MeetingWarningMinutes
{
get { return TimeSpan.FromMinutes(MinutesBeforeMeeting); }
}
[JsonProperty("timeToMeetingStart")]
public TimeSpan TimeToMeetingStart
{
get
{
return StartTime - DateTime.Now;
}
}
[JsonProperty("timeToMeetingEnd")]
public TimeSpan TimeToMeetingEnd
{
get
{
return EndTime - DateTime.Now;
}
}
[JsonProperty("startTime")]
/// <summary>
/// Gets or sets the StartTime
/// </summary>
public DateTime StartTime { get; set; }
[JsonProperty("endTime")]
/// <summary>
/// Gets or sets the EndTime
/// </summary>
public DateTime EndTime { get; set; }
[JsonProperty("duration")]
public TimeSpan Duration
{
get
{
return EndTime - StartTime;
}
}
[JsonProperty("privacy")]
/// <summary>
/// Gets or sets the Privacy
/// </summary>
public eMeetingPrivacy Privacy { get; set; }
[JsonProperty("joinable")]
public bool Joinable
{
get
{
var joinable = StartTime.AddMinutes(-MinutesBeforeMeeting) <= DateTime.Now
&& DateTime.Now <= EndTime.AddSeconds(-_joinableCooldownSeconds);
//Debug.LogMessage(LogEventLevel.Verbose, "Meeting Id: {0} joinable: {1}", Id, joinable);
return joinable;
}
}
[JsonProperty("dialable")]
/// <summary>
/// Gets or sets the Dialable
/// </summary>
public bool Dialable { get; set; }
//public string ConferenceNumberToDial { get; set; }
[JsonProperty("conferencePassword")]
/// <summary>
/// Gets or sets the ConferencePassword
/// </summary>
public string ConferencePassword { get; set; }
[JsonProperty("isOneButtonToPushMeeting")]
/// <summary>
/// Gets or sets the IsOneButtonToPushMeeting
/// </summary>
public bool IsOneButtonToPushMeeting { get; set; }
[JsonProperty("calls")]
/// <summary>
/// Gets or sets the Calls
/// </summary>
public List<Call> Calls { get; private set; }
/// <summary>
/// Tracks the change types that have already been notified for
/// </summary>
[JsonIgnore]
/// <summary>
/// Gets or sets the NotifiedChangeTypes
/// </summary>
public eMeetingEventChangeType NotifiedChangeTypes { get; set; }
[JsonIgnore] private readonly int _joinableCooldownSeconds;
public Meeting()
{
Calls = new List<Call>();
_joinableCooldownSeconds = 300;
}
public Meeting(int joinableCooldownSeconds)
{
Calls = new List<Call>();
_joinableCooldownSeconds = joinableCooldownSeconds;
}
#region Overrides of Object
/// <summary>
/// ToString method
/// </summary>
/// <inheritdoc />
public override string ToString()
{
return String.Format("{0}:{1}: {2}-{3}", Title, Agenda, StartTime, EndTime);
}
#endregion
}
/// <summary>
/// Represents a Call
/// </summary>
public class Call
{
/// <summary>
/// Gets or sets the Number
/// </summary>
public string Number { get; set; }
/// <summary>
/// Gets or sets the Protocol
/// </summary>
public string Protocol { get; set; }
/// <summary>
/// Gets or sets the CallRate
/// </summary>
public string CallRate { get; set; }
/// <summary>
/// Gets or sets the CallType
/// </summary>
public string CallType { get; set; }
}
/// <summary>
/// Represents a MeetingEventArgs
/// </summary>
public class MeetingEventArgs : EventArgs
{
/// <summary>
/// Gets or sets the ChangeType
/// </summary>
public eMeetingEventChangeType ChangeType { get; set; }
/// <summary>
/// Gets or sets the Meeting
/// </summary>
public Meeting Meeting { get; set; }
}
}