diff --git a/Essentials Devices Common/Essentials Devices Common/Codec/eMeetingPrivacy.cs b/Essentials Devices Common/Essentials Devices Common/Codec/eMeetingPrivacy.cs new file mode 100644 index 00000000..2381d569 --- /dev/null +++ b/Essentials Devices Common/Essentials Devices Common/Codec/eMeetingPrivacy.cs @@ -0,0 +1,42 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using Crestron.SimplSharp; + +namespace PepperDash.Essentials.Devices.Common.Codec +{ + public enum eMeetingPrivacy + { + Unknown = 0, + Public, + Private + } + + public class CodecCallPrivacy + { + /// + /// Takes the Cisco privacy type and converts to the matching enum + /// + /// + /// + public static eMeetingPrivacy ConvertToDirectionEnum(string s) + { + switch (s.ToLower()) + { + case "public": + { + return eMeetingPrivacy.Public; + } + case "private": + { + return eMeetingPrivacy.Private; + } + default: + return eMeetingPrivacy.Unknown; + } + + } + + } +} \ No newline at end of file diff --git a/Essentials Devices Common/Essentials Devices Common/Codec/iHasScheduleAwareness.cs b/Essentials Devices Common/Essentials Devices Common/Codec/iHasScheduleAwareness.cs new file mode 100644 index 00000000..7edbec1c --- /dev/null +++ b/Essentials Devices Common/Essentials Devices Common/Codec/iHasScheduleAwareness.cs @@ -0,0 +1,61 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using Crestron.SimplSharp; + +namespace PepperDash.Essentials.Devices.Common.Codec +{ + public interface IHasScheduleAwareness + { + CodecScheduleAwareness CodecSchedule { get; } + } + + public class CodecScheduleAwareness + { + public List Meetings { get; set; } + + public CodecScheduleAwareness() + { + Meetings = new List(); + } + } + + /// + /// Generic class to represent a meeting (Cisco or Polycom OBTP or Fusion) + /// + public class Meeting + { + public string Id { get; set; } + public string Organizer { get; set; } + public string Title { get; set; } + public string Agenda { get; set; } + public DateTime StartTime { get; set; } + public DateTime EndTime { get; set; } + public TimeSpan Duration + { + get + { + return EndTime - StartTime; + } + } + public eMeetingPrivacy Privacy { get; set; } + public bool Joinable + { + get + { + var timeToMeetingStart = StartTime - DateTime.Now; + + var timetoMeetingEnd = DateTime.Now - EndTime; + + // Meeting is joinable from 5 minutes before start until 5 minutes before end + if (timeToMeetingStart.Minutes <= 5 && timetoMeetingEnd.Minutes >= 5) + return true; + else + return false; + } + } + public string ConferenceNumberToDial { get; set; } + public string ConferencePassword { get; set; } + } +} \ No newline at end of file diff --git a/Essentials Devices Common/Essentials Devices Common/Essentials Devices Common.csproj b/Essentials Devices Common/Essentials Devices Common/Essentials Devices Common.csproj index c6efdea9..348bbe0d 100644 --- a/Essentials Devices Common/Essentials Devices Common/Essentials Devices Common.csproj +++ b/Essentials Devices Common/Essentials Devices Common/Essentials Devices Common.csproj @@ -106,12 +106,14 @@ + + diff --git a/Essentials Devices Common/Essentials Devices Common/VideoCodec/CiscoCodec/BookingsDataClasses.cs b/Essentials Devices Common/Essentials Devices Common/VideoCodec/CiscoCodec/BookingsDataClasses.cs index 429119b6..19c54028 100644 --- a/Essentials Devices Common/Essentials Devices Common/VideoCodec/CiscoCodec/BookingsDataClasses.cs +++ b/Essentials Devices Common/Essentials Devices Common/VideoCodec/CiscoCodec/BookingsDataClasses.cs @@ -4,6 +4,9 @@ using System.Linq; using System.Text; using Crestron.SimplSharp; +using PepperDash.Core; +using PepperDash.Essentials.Devices.Common.Codec; + namespace PepperDash.Essentials.Devices.Common.VideoCodec { public class CiscoCodecBookings @@ -69,6 +72,13 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec public LastName LastName { get; set; } public Email Email { get; set; } public Id2 Id { get; set; } + + public Organizer() + { + FirstName = new FirstName(); + LastName = new LastName(); + Email = new Email(); + } } public class StartTime @@ -97,6 +107,12 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec public StartTimeBuffer StartTimeBuffer { get; set; } public EndTime EndTime { get; set; } public EndTimeBuffer EndTimeBuffer { get; set; } + + public Time() + { + StartTime = new StartTime(); + EndTime = new EndTime(); + } } public class MaximumMeetingExtension @@ -206,6 +222,16 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec public Role Role { get; set; } public Recording Recording { get; set; } public DialInfo DialInfo { get; set; } + + public Booking() + { + Time = new Time(); + Id = new Id(); + Organizer = new Organizer(); + Title = new Title(); + Agenda = new Agenda(); + Privacy = new Privacy(); + } } public class BookingsListResult @@ -225,5 +251,46 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec { public CommandResponse CommandResponse { get; set; } } + + /// + /// Extracts the necessary meeting values from the Cisco bookings response ans converts them to the generic class + /// + /// + /// + public static List GetGenericMeetingsFromBookingResult(List bookings) + { + var meetings = new List(); + + if (Debug.Level > 0) + { + Debug.Console(1, "Meetings List:\n"); + } + + foreach(Booking b in bookings) + { + var meeting = new Meeting(); + + meeting.Id = b.Id.Value; + meeting.Organizer = string.Format("{0}, {1}", b.Organizer.LastName.Value, b.Organizer.FirstName.Value); + meeting.Title = b.Title.Value; + meeting.Agenda = b.Agenda.Value; + meeting.StartTime = b.Time.StartTime.Value; + meeting.EndTime = b.Time.EndTime.Value; + meeting.Privacy = CodecCallPrivacy.ConvertToDirectionEnum(b.Privacy.Value); + + if(Debug.Level > 0) + { + Debug.Console(1, "Title: {0}, ID: {1}, Organizer: {2}, Agenda: {3}", meeting.Title, meeting.Id, meeting.Organizer, meeting.Agenda); + Debug.Console(1, " Start Time: {0}, End Time: {1}, Duration: {2}", meeting.StartTime, meeting.EndTime, meeting.Duration); + Debug.Console(1, " Joinable: {0}", meeting.Joinable); + } + } + + meetings.OrderBy(m => m.StartTime); + + + + return meetings; + } } } \ No newline at end of file diff --git a/Essentials Devices Common/Essentials Devices Common/VideoCodec/CiscoCodec/CiscoCodec.cs b/Essentials Devices Common/Essentials Devices Common/VideoCodec/CiscoCodec/CiscoCodec.cs index 926a30d2..c770bad4 100644 --- a/Essentials Devices Common/Essentials Devices Common/VideoCodec/CiscoCodec/CiscoCodec.cs +++ b/Essentials Devices Common/Essentials Devices Common/VideoCodec/CiscoCodec/CiscoCodec.cs @@ -20,7 +20,7 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.Cisco { enum eCommandType { SessionStart, SessionEnd, Command, GetStatus, GetConfiguration }; - public class CiscoCodec : VideoCodecBase, IHasCallHistory, iHasCallFavorites, iHasDirectory + public class CiscoCodec : VideoCodecBase, IHasCallHistory, iHasCallFavorites, iHasDirectory, IHasScheduleAwareness { public event EventHandler UpcomingMeetingWarning; @@ -56,6 +56,8 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.Cisco public CodecDirectory DirectoryRoot { get; private set; } + public CodecScheduleAwareness CodecSchedule { get; private set; } + /// /// Gets and returns the scaled volume of the codec /// @@ -88,10 +90,10 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.Cisco /// protected override Func SharingSourceFeedbackFunc { -#warning figure out how to return the key of the shared source somehow +#warning verify that source feedback to room works from codec get { - return () => "todo"; + return () => PresentationSourceKey; } } @@ -160,12 +162,19 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.Cisco int PresentationSource; + string PresentationSourceKey; + string PhonebookMode = "Local"; // Default to Local int PhonebookResultsLimit = 255; // Could be set later by config. CTimer LoginMessageReceived; + public RoutingInputPort CodecOsdIn { get; private set; } + public RoutingInputPort HdmiIn1 { get; private set; } + public RoutingInputPort HdmiIn2 { get; private set; } + public RoutingOutputPort HdmiOut { get; private set; } + // Constructor for IBasicCommunication public CiscoCodec(string key, string name, IBasicCommunication comm, CiscoCodecPropertiesConfig props ) : base(key, name) @@ -217,6 +226,8 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.Cisco CallFavorites.Favorites = props.Favorites; DirectoryRoot = new CodecDirectory(); + + CodecSchedule = new CodecScheduleAwareness(); //Set Feedback Actions CodecStatus.Status.Audio.Volume.ValueChangedAction = VolumeLevelFeedback.FireUpdate; @@ -235,8 +246,9 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.Cisco public override bool CustomActivate() { CrestronConsole.AddNewConsoleCommand(SendText, "send" + Key, "", ConsoleAccessLevelEnum.AccessOperator); - CrestronConsole.AddNewConsoleCommand(SetCommDebug, "SetCiscoCommDebug", "0 for Off, 1 for on", ConsoleAccessLevelEnum.AccessOperator); + CrestronConsole.AddNewConsoleCommand(SetCommDebug, "SetCodecCommDebug", "0 for Off, 1 for on", ConsoleAccessLevelEnum.AccessOperator); CrestronConsole.AddNewConsoleCommand(GetPhonebook, "GetCodecPhonebook", "Triggers a refresh of the codec phonebook", ConsoleAccessLevelEnum.AccessOperator); + CrestronConsole.AddNewConsoleCommand(GetBookings, "GetCodecBookings", "Triggers a refresh of the booking data for today", ConsoleAccessLevelEnum.AccessOperator); //CommDebuggingIsOn = true; Communication.Connect(); @@ -248,8 +260,17 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.Cisco CommunicationMonitor.Start(); - InputPorts.Add(new RoutingInputPort(RoutingPortNames.HdmiIn1, eRoutingSignalType.AudioVideo, eRoutingPortConnectionType.Hdmi, new Action(SelectPresentationSource1), this)); - InputPorts.Add(new RoutingInputPort(RoutingPortNames.HdmiIn2, eRoutingSignalType.AudioVideo, eRoutingPortConnectionType.Hdmi, new Action(SelectPresentationSource2), this)); + CodecOsdIn = new RoutingInputPort(RoutingPortNames.CodecOsd, eRoutingSignalType.AudioVideo, eRoutingPortConnectionType.Hdmi, new Action(StopSharing), this); + HdmiIn1 = new RoutingInputPort(RoutingPortNames.HdmiIn1, eRoutingSignalType.AudioVideo, eRoutingPortConnectionType.Hdmi, new Action(SelectPresentationSource1), this); + HdmiIn2 = new RoutingInputPort(RoutingPortNames.HdmiIn2, eRoutingSignalType.AudioVideo, eRoutingPortConnectionType.Hdmi, new Action(SelectPresentationSource2), this); + + HdmiOut = new RoutingOutputPort(RoutingPortNames.HdmiOut, eRoutingSignalType.AudioVideo, eRoutingPortConnectionType.Hdmi, null, this); + + InputPorts.Add(CodecOsdIn); + InputPorts.Add(HdmiIn1); + InputPorts.Add(HdmiIn2); + OutputPorts.Add(HdmiOut); + string prefix = "xFeedback register "; @@ -281,10 +302,9 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.Cisco GetCallHistory(); - // Get bookings for the day - //SendText("xCommand Bookings List Days: 1 DayOffset: 0"); - GetPhonebook(null); + + GetBookings(null); } public void SetCommDebug(string s) @@ -609,7 +629,7 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.Cisco JsonConvert.PopulateObject(response, codecBookings); - // Do something with this data.... + CodecSchedule.Meetings = CiscoCodecBookings.GetGenericMeetingsFromBookingResult(codecBookings.CommandResponse.BookingsListResult.Booking); } } @@ -649,6 +669,7 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.Cisco public override void ExecuteSwitch(object selector) { (selector as Action)(); + PresentationSourceKey = selector.ToString(); } protected override Func IncomingCallFeedbackFunc { get { return () => false; } } @@ -677,6 +698,15 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.Cisco SendText("xCommand CallHistory Recents Limit: 20 Order: OccurrenceTime"); } + /// + /// Gets the bookings for today + /// + /// + public void GetBookings(string command) + { + SendText("xCommand Bookings List Days: 1 DayOffset: 0"); + } + /// /// Triggers a refresh of the codec phonebook ///