From 72197e547f0aacf7b55506c0530af238523c506d Mon Sep 17 00:00:00 2001 From: jkdevito Date: Wed, 6 Jan 2021 16:22:54 -0600 Subject: [PATCH] Updated VideoCodecBase.cs and ZoomRooms.cs to resolve an issue with dialing the currently scheduled meetings. VideoCodecBase.cs changes: 1. Moved the trilist.SetSigFalseActions for DialMeeting 1-3 from the UpdateMeetinsgList mehtod to the LinkVideoCodecScheduleToApi method. - This was necessary to resolve an issue with dialing current meetings. - When the SetSigFalseActions where located in the UpdateMeetingsList, they were using the codec.CodecSchedule.Meetings to dial, which was not updated based on the time of day. 2. Turned the local var currentMeetings into a private list, _currentMeetings, that can be updated by UpdateMeetingsList and then used in LinkVideoCodecScheduleToApi when the trilist actions are executed. 3. Added debug statements to help narrow down the issue and verify the data. ZoomRoom.cs changes: 1. Added debug statement to Dial(Meeting meeting) method to confirm the data passed from LinkVideoCodecScheduleToApi was matching the _currentMeetings list data. --- .../VideoCodec/VideoCodecBase.cs | 2528 +++++++++-------- .../VideoCodec/ZoomRoom/ZoomRoom.cs | 1 + 2 files changed, 1276 insertions(+), 1253 deletions(-) diff --git a/essentials-framework/Essentials Devices Common/Essentials Devices Common/VideoCodec/VideoCodecBase.cs b/essentials-framework/Essentials Devices Common/Essentials Devices Common/VideoCodec/VideoCodecBase.cs index 0977dea2..6b6d5891 100644 --- a/essentials-framework/Essentials Devices Common/Essentials Devices Common/VideoCodec/VideoCodecBase.cs +++ b/essentials-framework/Essentials Devices Common/Essentials Devices Common/VideoCodec/VideoCodecBase.cs @@ -1,1257 +1,1279 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using Crestron.SimplSharp.CrestronIO; -using Crestron.SimplSharp.Ssh; -using Crestron.SimplSharpPro.DeviceSupport; -using Crestron.SimplSharp; -using PepperDash.Core; -using PepperDash.Core.Intersystem; -using PepperDash.Core.Intersystem.Tokens; -using PepperDash.Core.WebApi.Presets; -using PepperDash.Essentials.Core; -using PepperDash.Essentials.Core.Bridges; -using PepperDash.Essentials.Core.Config; -using PepperDash.Essentials.Core.Devices; -using PepperDash.Essentials.Core.DeviceTypeInterfaces; -using PepperDash.Essentials.Core.Routing; -using PepperDash.Essentials.Devices.Common.Cameras; -using PepperDash.Essentials.Devices.Common.Codec; -using PepperDash.Essentials.Devices.Common.VideoCodec.Interfaces; -using PepperDash_Essentials_Core.Bridges.JoinMaps; -using PepperDash_Essentials_Core.DeviceTypeInterfaces; -using Feedback = PepperDash.Essentials.Core.Feedback; - -namespace PepperDash.Essentials.Devices.Common.VideoCodec -{ - public abstract class VideoCodecBase : ReconfigurableDevice, IRoutingInputsOutputs, - IUsageTracking, IHasDialer, IHasContentSharing, ICodecAudio, iVideoCodecInfo, IBridgeAdvanced - { - private const int XSigEncoding = 28591; - private readonly byte[] _clearBytes = XSigHelpers.ClearOutputs(); - protected VideoCodecBase(DeviceConfig config) - : base(config) - { - - StandbyIsOnFeedback = new BoolFeedback(StandbyIsOnFeedbackFunc); - PrivacyModeIsOnFeedback = new BoolFeedback(PrivacyModeIsOnFeedbackFunc); - VolumeLevelFeedback = new IntFeedback(VolumeLevelFeedbackFunc); - MuteFeedback = new BoolFeedback(MuteFeedbackFunc); - SharingSourceFeedback = new StringFeedback(SharingSourceFeedbackFunc); - SharingContentIsOnFeedback = new BoolFeedback(SharingContentIsOnFeedbackFunc); - - InputPorts = new RoutingPortCollection(); - OutputPorts = new RoutingPortCollection(); - - ActiveCalls = new List(); - } - - public IBasicCommunication Communication { get; protected set; } - - /// - /// An internal pseudo-source that is routable and connected to the osd input - /// - public DummyRoutingInputsDevice OsdSource { get; protected set; } - - public BoolFeedback StandbyIsOnFeedback { get; private set; } - - protected abstract Func PrivacyModeIsOnFeedbackFunc { get; } - protected abstract Func VolumeLevelFeedbackFunc { get; } - protected abstract Func MuteFeedbackFunc { get; } - protected abstract Func StandbyIsOnFeedbackFunc { get; } - - public List ActiveCalls { get; set; } - - public bool ShowSelfViewByDefault { get; protected set; } - - protected bool SupportsCameraOff; - protected bool SupportsCameraAutoMode; - - public bool IsReady { get; protected set; } - - public virtual List Feedbacks - { - get - { - return new List +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using Crestron.SimplSharp.CrestronIO; +using Crestron.SimplSharp.Ssh; +using Crestron.SimplSharpPro.DeviceSupport; +using Crestron.SimplSharp; +using PepperDash.Core; +using PepperDash.Core.Intersystem; +using PepperDash.Core.Intersystem.Tokens; +using PepperDash.Core.WebApi.Presets; +using PepperDash.Essentials.Core; +using PepperDash.Essentials.Core.Bridges; +using PepperDash.Essentials.Core.Config; +using PepperDash.Essentials.Core.Devices; +using PepperDash.Essentials.Core.DeviceTypeInterfaces; +using PepperDash.Essentials.Core.Routing; +using PepperDash.Essentials.Devices.Common.Cameras; +using PepperDash.Essentials.Devices.Common.Codec; +using PepperDash.Essentials.Devices.Common.VideoCodec.Interfaces; +using PepperDash_Essentials_Core.Bridges.JoinMaps; +using PepperDash_Essentials_Core.DeviceTypeInterfaces; +using Feedback = PepperDash.Essentials.Core.Feedback; + +namespace PepperDash.Essentials.Devices.Common.VideoCodec +{ + public abstract class VideoCodecBase : ReconfigurableDevice, IRoutingInputsOutputs, + IUsageTracking, IHasDialer, IHasContentSharing, ICodecAudio, iVideoCodecInfo, IBridgeAdvanced + { + private const int XSigEncoding = 28591; + private readonly byte[] _clearBytes = XSigHelpers.ClearOutputs(); + protected VideoCodecBase(DeviceConfig config) + : base(config) + { + + StandbyIsOnFeedback = new BoolFeedback(StandbyIsOnFeedbackFunc); + PrivacyModeIsOnFeedback = new BoolFeedback(PrivacyModeIsOnFeedbackFunc); + VolumeLevelFeedback = new IntFeedback(VolumeLevelFeedbackFunc); + MuteFeedback = new BoolFeedback(MuteFeedbackFunc); + SharingSourceFeedback = new StringFeedback(SharingSourceFeedbackFunc); + SharingContentIsOnFeedback = new BoolFeedback(SharingContentIsOnFeedbackFunc); + + InputPorts = new RoutingPortCollection(); + OutputPorts = new RoutingPortCollection(); + + ActiveCalls = new List(); + } + + public IBasicCommunication Communication { get; protected set; } + + /// + /// An internal pseudo-source that is routable and connected to the osd input + /// + public DummyRoutingInputsDevice OsdSource { get; protected set; } + + public BoolFeedback StandbyIsOnFeedback { get; private set; } + + protected abstract Func PrivacyModeIsOnFeedbackFunc { get; } + protected abstract Func VolumeLevelFeedbackFunc { get; } + protected abstract Func MuteFeedbackFunc { get; } + protected abstract Func StandbyIsOnFeedbackFunc { get; } + + public List ActiveCalls { get; set; } + + public bool ShowSelfViewByDefault { get; protected set; } + + protected bool SupportsCameraOff; + protected bool SupportsCameraAutoMode; + + public bool IsReady { get; protected set; } + + public virtual List Feedbacks + { + get + { + return new List { PrivacyModeIsOnFeedback, SharingSourceFeedback - }; - } - } - - protected abstract Func SharingSourceFeedbackFunc { get; } - protected abstract Func SharingContentIsOnFeedbackFunc { get; } - - #region ICodecAudio Members - - public abstract void PrivacyModeOn(); - public abstract void PrivacyModeOff(); - public abstract void PrivacyModeToggle(); - public BoolFeedback PrivacyModeIsOnFeedback { get; private set; } - - - public BoolFeedback MuteFeedback { get; private set; } - - public abstract void MuteOff(); - - public abstract void MuteOn(); - - public abstract void SetVolume(ushort level); - - public IntFeedback VolumeLevelFeedback { get; private set; } - - public abstract void MuteToggle(); - - public abstract void VolumeDown(bool pressRelease); - - - public abstract void VolumeUp(bool pressRelease); - - #endregion - - #region IHasContentSharing Members - - public abstract void StartSharing(); - public abstract void StopSharing(); - - public bool AutoShareContentWhileInCall { get; protected set; } - - public StringFeedback SharingSourceFeedback { get; private set; } - public BoolFeedback SharingContentIsOnFeedback { get; private set; } - - #endregion - - #region IHasDialer Members - - /// - /// Fires when the status of any active, dialing, or incoming call changes or is new - /// - public event EventHandler CallStatusChange; - - /// - /// Returns true when any call is not in state Unknown, Disconnecting, Disconnected - /// - public bool IsInCall - { - get - { - var value = ActiveCalls != null && ActiveCalls.Any(c => c.IsActiveCall); - return value; - } - } - - public abstract void Dial(string number); - public abstract void EndCall(CodecActiveCallItem call); - public abstract void EndAllCalls(); - public abstract void AcceptCall(CodecActiveCallItem call); - public abstract void RejectCall(CodecActiveCallItem call); - public abstract void SendDtmf(string s); - - #endregion - - #region IRoutingInputsOutputs Members - - public RoutingPortCollection InputPorts { get; private set; } - - public RoutingPortCollection OutputPorts { get; private set; } - - #endregion - - #region IUsageTracking Members - - /// - /// This object can be added by outside users of this class to provide usage tracking - /// for various services - /// - public UsageTracking UsageTracker { get; set; } - - #endregion - - #region iVideoCodecInfo Members - - public VideoCodecInfo CodecInfo { get; protected set; } - - #endregion - - public event EventHandler IsReadyChange; - public abstract void Dial(Meeting meeting); - - public virtual void Dial(IInvitableContact contact) - { - } - - public abstract void ExecuteSwitch(object selector); - - /// - /// Helper method to fire CallStatusChange event with old and new status - /// - protected void SetNewCallStatusAndFireCallStatusChange(eCodecCallStatus newStatus, CodecActiveCallItem call) - { - call.Status = newStatus; - - OnCallStatusChange(call); - } - - /// - /// - /// - /// - /// - /// - protected virtual void OnCallStatusChange(CodecActiveCallItem item) - { - var handler = CallStatusChange; - if (handler != null) - { - handler(this, new CodecCallStatusItemChangeEventArgs(item)); - } - - if (AutoShareContentWhileInCall) - { - StartSharing(); - } - - if (UsageTracker != null) - { - if (IsInCall && !UsageTracker.UsageTrackingStarted) - { - UsageTracker.StartDeviceUsage(); - } - else if (UsageTracker.UsageTrackingStarted && !IsInCall) - { - UsageTracker.EndDeviceUsage(); - } - } - } - - /// - /// Sets IsReady property and fires the event. Used for dependent classes to sync up their data. - /// - protected void SetIsReady() - { - CrestronInvoke.BeginInvoke( (o) => - { - try - { - IsReady = true; - var h = IsReadyChange; - if (h != null) - { - h(this, new EventArgs()); - } - } - catch (Exception e) - { - Debug.Console(2, this, "Error in SetIsReady() : {0}", e); - } - }); - } - - // **** DEBUGGING THINGS **** - /// - /// - /// - public virtual void ListCalls() - { - var sb = new StringBuilder(); - foreach (var c in ActiveCalls) - { - sb.AppendFormat("{0} {1} -- {2} {3}\n", c.Id, c.Number, c.Name, c.Status); - } - Debug.Console(1, this, "\n{0}\n", sb.ToString()); - } - - public abstract void StandbyActivate(); - - public abstract void StandbyDeactivate(); - - #region Implementation of IBridgeAdvanced - - public abstract void LinkToApi(BasicTriList trilist, uint joinStart, string joinMapKey, EiscApiAdvanced bridge); - - protected void LinkVideoCodecToApi(VideoCodecBase codec, BasicTriList trilist, uint joinStart, string joinMapKey, - EiscApiAdvanced bridge) - { - var joinMap = new VideoCodecControllerJoinMap(joinStart); - - var customJoins = JoinMapHelper.TryGetJoinMapAdvancedForDevice(joinMapKey); - - if (customJoins != null) - { - joinMap.SetCustomJoinData(customJoins); - } - - if (bridge != null) - { - bridge.AddJoinMap(Key, joinMap); - } - - Debug.Console(1, this, "Linking to Trilist {0}", trilist.ID.ToString("X")); - - - - LinkVideoCodecDtmfToApi(trilist, joinMap); - - LinkVideoCodecCallControlsToApi(trilist, joinMap); - - LinkVideoCodecContentSharingToApi(trilist, joinMap); - - LinkVideoCodecPrivacyToApi(trilist, joinMap); - - LinkVideoCodecVolumeToApi(trilist, joinMap); - - if (codec is ICommunicationMonitor) - { - LinkVideoCodecCommMonitorToApi(codec as ICommunicationMonitor, trilist, joinMap); - } - - if (codec is IHasCodecCameras) - { - LinkVideoCodecCameraToApi(codec as IHasCodecCameras, trilist, joinMap); - } - - if (codec is IHasCodecSelfView) - { - LinkVideoCodecSelfviewToApi(codec as IHasCodecSelfView, trilist, joinMap); - } - - if (codec is IHasCameraAutoMode) - { - trilist.SetBool(joinMap.CameraSupportsAutoMode.JoinNumber, SupportsCameraAutoMode); - LinkVideoCodecCameraModeToApi(codec as IHasCameraAutoMode, trilist, joinMap); - } - - if (codec is IHasCameraOff) - { - trilist.SetBool(joinMap.CameraSupportsOffMode.JoinNumber, SupportsCameraOff); - LinkVideoCodecCameraOffToApi(codec as IHasCameraOff, trilist, joinMap); - } - - if (codec is IHasCodecLayouts) - { - LinkVideoCodecCameraLayoutsToApi(codec as IHasCodecLayouts, trilist, joinMap); - } - - if (codec is IHasSelfviewPosition) - { - LinkVideoCodecSelfviewPositionToApi(codec as IHasSelfviewPosition, trilist, joinMap); - } - - if (codec is IHasDirectory) - { - LinkVideoCodecDirectoryToApi(codec as IHasDirectory, trilist, joinMap); - } - - if (codec is IHasScheduleAwareness) - { - LinkVideoCodecScheduleToApi(codec as IHasScheduleAwareness, trilist, joinMap); - } - - if (codec is IHasParticipants) - { - LinkVideoCodecParticipantsToApi(codec as IHasParticipants, trilist, joinMap); - } - - if (codec is IHasFarEndContentStatus) - { - (codec as IHasFarEndContentStatus).ReceivingContent.LinkInputSig(trilist.BooleanInput[joinMap.RecievingContent.JoinNumber]); - } - - if (codec is IHasPhoneDialing) - { - LinkVideoCodecPhoneToApi(codec as IHasPhoneDialing, trilist, joinMap); - } - - trilist.OnlineStatusChange += (device, args) => - { - if (!args.DeviceOnLine) return; - - if (codec is IHasDirectory) - { - (codec as IHasDirectory).SetCurrentDirectoryToRoot(); - } - - if (codec is IHasScheduleAwareness) - { - (codec as IHasScheduleAwareness).GetSchedule(); - } - - if (codec is IHasParticipants) - { - UpdateParticipantsXSig((codec as IHasParticipants).Participants.CurrentParticipants); - } - - if (codec is IHasCameraAutoMode) - { - trilist.SetBool(joinMap.CameraSupportsAutoMode.JoinNumber, true); - - (codec as IHasCameraAutoMode).CameraAutoModeIsOnFeedback.FireUpdate(); - } - - if (codec is IHasCodecSelfView) - { - (codec as IHasCodecSelfView).SelfviewIsOnFeedback.FireUpdate(); - } - - if (codec is IHasCameraAutoMode) - { - (codec as IHasCameraAutoMode).CameraAutoModeIsOnFeedback.FireUpdate(); - } - - if (codec is IHasCameraOff) - { - (codec as IHasCameraOff).CameraIsOffFeedback.FireUpdate(); - } - - if (codec is IHasPhoneDialing) - { - (codec as IHasPhoneDialing).PhoneOffHookFeedback.FireUpdate(); - } - - SharingContentIsOnFeedback.FireUpdate(); - - trilist.SetBool(joinMap.HookState.JoinNumber, IsInCall); - - trilist.SetString(joinMap.CurrentCallData.JoinNumber, UpdateCallStatusXSig()); - }; - } - - private void LinkVideoCodecPhoneToApi(IHasPhoneDialing codec, BasicTriList trilist, VideoCodecControllerJoinMap joinMap) - { - codec.PhoneOffHookFeedback.LinkInputSig(trilist.BooleanInput[joinMap.PhoneHookState.JoinNumber]); - - trilist.SetSigFalseAction(joinMap.DialPhone.JoinNumber, - () => codec.DialPhoneCall(trilist.StringOutput[joinMap.PhoneDialString.JoinNumber].StringValue)); - - trilist.SetSigFalseAction(joinMap.HangUpPhone.JoinNumber, codec.EndPhoneCall); - } - - private void LinkVideoCodecSelfviewPositionToApi(IHasSelfviewPosition codec, BasicTriList trilist, VideoCodecControllerJoinMap joinMap) - { - trilist.SetSigFalseAction(joinMap.SelfviewPosition.JoinNumber, codec.SelfviewPipPositionToggle); - - codec.SelfviewPipPositionFeedback.LinkInputSig(trilist.StringInput[joinMap.SelfviewPositionFb.JoinNumber]); - } - - private void LinkVideoCodecCameraOffToApi(IHasCameraOff codec, BasicTriList trilist, VideoCodecControllerJoinMap joinMap) - { - trilist.SetSigFalseAction(joinMap.CameraModeOff.JoinNumber, codec.CameraOff); - - codec.CameraIsOffFeedback.OutputChange += (o, a) => - { - if (a.BoolValue) - { - trilist.SetBool(joinMap.CameraModeOff.JoinNumber, true); - trilist.SetBool(joinMap.CameraModeManual.JoinNumber, false); - trilist.SetBool(joinMap.CameraModeAuto.JoinNumber, false); - return; - } - - trilist.SetBool(joinMap.CameraModeOff.JoinNumber, false); - - var autoCodec = codec as IHasCameraAutoMode; - - if (autoCodec == null) return; - - trilist.SetBool(joinMap.CameraModeAuto.JoinNumber, autoCodec.CameraAutoModeIsOnFeedback.BoolValue); - trilist.SetBool(joinMap.CameraModeManual.JoinNumber, !autoCodec.CameraAutoModeIsOnFeedback.BoolValue); - }; - - if (codec.CameraIsOffFeedback.BoolValue) - { - trilist.SetBool(joinMap.CameraModeOff.JoinNumber, true); - trilist.SetBool(joinMap.CameraModeManual.JoinNumber, false); - trilist.SetBool(joinMap.CameraModeAuto.JoinNumber, false); - return; - } - - trilist.SetBool(joinMap.CameraModeOff.JoinNumber, false); - - var autoModeCodec = codec as IHasCameraAutoMode; - - if (autoModeCodec == null) return; - - trilist.SetBool(joinMap.CameraModeAuto.JoinNumber, autoModeCodec.CameraAutoModeIsOnFeedback.BoolValue); - trilist.SetBool(joinMap.CameraModeManual.JoinNumber, !autoModeCodec.CameraAutoModeIsOnFeedback.BoolValue); - } - - private void LinkVideoCodecVolumeToApi(BasicTriList trilist, VideoCodecControllerJoinMap joinMap) - { - MuteFeedback.LinkInputSig(trilist.BooleanInput[joinMap.VolumeMuteOn.JoinNumber]); - MuteFeedback.LinkComplementInputSig(trilist.BooleanInput[joinMap.VolumeMuteOff.JoinNumber]); - - trilist.SetSigFalseAction(joinMap.VolumeMuteOn.JoinNumber, MuteOn); - trilist.SetSigFalseAction(joinMap.VolumeMuteOff.JoinNumber, MuteOff); - trilist.SetSigFalseAction(joinMap.VolumeMuteToggle.JoinNumber, MuteToggle); - - VolumeLevelFeedback.LinkInputSig(trilist.UShortInput[joinMap.VolumeLevel.JoinNumber]); - - trilist.SetBoolSigAction(joinMap.VolumeUp.JoinNumber, VolumeUp); - trilist.SetBoolSigAction(joinMap.VolumeDown.JoinNumber, VolumeDown); - - trilist.SetUShortSigAction(joinMap.VolumeLevel.JoinNumber, SetVolume); - - } - - private void LinkVideoCodecPrivacyToApi(BasicTriList trilist, VideoCodecControllerJoinMap joinMap) - { - PrivacyModeIsOnFeedback.LinkInputSig(trilist.BooleanInput[joinMap.MicMuteOn.JoinNumber]); - PrivacyModeIsOnFeedback.LinkComplementInputSig(trilist.BooleanInput[joinMap.MicMuteOff.JoinNumber]); - - trilist.SetSigFalseAction(joinMap.MicMuteOn.JoinNumber, PrivacyModeOn); - trilist.SetSigFalseAction(joinMap.MicMuteOff.JoinNumber, PrivacyModeOff); - trilist.SetSigFalseAction(joinMap.MicMuteToggle.JoinNumber, PrivacyModeToggle); - } - - private void LinkVideoCodecCommMonitorToApi(ICommunicationMonitor codec, BasicTriList trilist, VideoCodecControllerJoinMap joinMap) - { - codec.CommunicationMonitor.IsOnlineFeedback.LinkInputSig(trilist.BooleanInput[joinMap.IsOnline.JoinNumber]); - } - - private void LinkVideoCodecParticipantsToApi(IHasParticipants codec, BasicTriList trilist, VideoCodecControllerJoinMap joinMap) - { - codec.Participants.ParticipantsListHasChanged += (sender, args) => - { - string participantsXSig; - - if (codec.Participants.CurrentParticipants.Count == 0) - { - participantsXSig = Encoding.GetEncoding(XSigEncoding).GetString(_clearBytes, 0, _clearBytes.Length); - trilist.SetString(joinMap.CurrentParticipants.JoinNumber, participantsXSig); - trilist.SetUshort(joinMap.ParticipantCount.JoinNumber, (ushort)codec.Participants.CurrentParticipants.Count); - return; - } - - participantsXSig = UpdateParticipantsXSig(codec.Participants.CurrentParticipants); - - trilist.SetString(joinMap.CurrentParticipants.JoinNumber, participantsXSig); - - trilist.SetUshort(joinMap.ParticipantCount.JoinNumber, (ushort) codec.Participants.CurrentParticipants.Count); - }; - } - - private string UpdateParticipantsXSig(List currentParticipants) - { - const int maxParticipants = 50; - const int maxDigitals = 5; - const int maxStrings = 1; - const int offset = maxDigitals + maxStrings; - var digitalIndex = maxStrings * maxParticipants; //15 - var stringIndex = 0; - var meetingIndex = 0; - - var tokenArray = new XSigToken[maxParticipants * offset]; - - foreach (var participant in currentParticipants) - { - if (meetingIndex >= maxParticipants * offset) break; - - //digitals - tokenArray[digitalIndex] = new XSigDigitalToken(digitalIndex + 1, participant.AudioMuteFb); - tokenArray[digitalIndex + 1] = new XSigDigitalToken(digitalIndex + 2, participant.VideoMuteFb); - tokenArray[digitalIndex + 2] = new XSigDigitalToken(digitalIndex + 3, participant.CanMuteVideo); - tokenArray[digitalIndex + 3] = new XSigDigitalToken(digitalIndex + 4, participant.CanUnmuteVideo); - tokenArray[digitalIndex + 4] = new XSigDigitalToken(digitalIndex + 5, participant.IsHost); - - //serials - tokenArray[stringIndex] = new XSigSerialToken(stringIndex + 1, participant.Name); - - digitalIndex += maxDigitals; - meetingIndex += offset; - stringIndex += maxStrings; - } - - while (meetingIndex < maxParticipants*offset) - { - tokenArray[digitalIndex] = new XSigDigitalToken(digitalIndex + 1, false); - tokenArray[digitalIndex + 1] = new XSigDigitalToken(digitalIndex + 2, false); - tokenArray[digitalIndex + 2] = new XSigDigitalToken(digitalIndex + 3, false); - tokenArray[digitalIndex + 3] = new XSigDigitalToken(digitalIndex + 4, false); - tokenArray[digitalIndex + 4] = new XSigDigitalToken(digitalIndex + 5, false); - - //serials - tokenArray[stringIndex] = new XSigSerialToken(stringIndex + 1, String.Empty); - - digitalIndex += maxDigitals; - meetingIndex += offset; - stringIndex += maxStrings; - } - - return GetXSigString(tokenArray); - } - - private void LinkVideoCodecContentSharingToApi(BasicTriList trilist, VideoCodecControllerJoinMap joinMap) - { - SharingContentIsOnFeedback.LinkInputSig(trilist.BooleanInput[joinMap.SourceShareStart.JoinNumber]); - SharingContentIsOnFeedback.LinkComplementInputSig(trilist.BooleanInput[joinMap.SourceShareEnd.JoinNumber]); - - SharingSourceFeedback.LinkInputSig(trilist.StringInput[joinMap.CurrentSource.JoinNumber]); - - trilist.SetSigFalseAction(joinMap.SourceShareStart.JoinNumber, StartSharing); - trilist.SetSigFalseAction(joinMap.SourceShareEnd.JoinNumber, StopSharing); - - trilist.SetBoolSigAction(joinMap.SourceShareAutoStart.JoinNumber, (b) => AutoShareContentWhileInCall = b); - } - - private void LinkVideoCodecScheduleToApi(IHasScheduleAwareness codec, BasicTriList trilist, VideoCodecControllerJoinMap joinMap) - { - trilist.SetSigFalseAction(joinMap.UpdateMeetings.JoinNumber, codec.GetSchedule); - - trilist.SetUShortSigAction(joinMap.MinutesBeforeMeetingStart.JoinNumber, (i) => - { - codec.CodecSchedule.MeetingWarningMinutes = i; - }); - - codec.CodecSchedule.MeetingsListHasChanged += (sender, args) => UpdateMeetingsList(codec, trilist, joinMap); - - codec.CodecSchedule.MeetingEventChange += - (sender, args) => - { - if (args.ChangeType == eMeetingEventChangeType.MeetingStartWarning) - { - UpdateMeetingsList(codec, trilist, joinMap); - } - }; - } - - private void UpdateMeetingsList(IHasScheduleAwareness codec, BasicTriList trilist, VideoCodecControllerJoinMap joinMap) - { - var currentTime = DateTime.Now; - var currentMeetings = - codec.CodecSchedule.Meetings.Where(m => m.StartTime >= currentTime || m.EndTime >= currentTime).ToList(); - - var meetingsData = UpdateMeetingsListXSig(currentMeetings); - - trilist.SetString(joinMap.Schedule.JoinNumber, meetingsData); - - trilist.SetSigFalseAction(joinMap.DialMeeting1.JoinNumber, () => - { - if(codec.CodecSchedule.Meetings[0] != null) - Dial(codec.CodecSchedule.Meetings[0]); - }); - trilist.SetSigFalseAction(joinMap.DialMeeting2.JoinNumber, () => - { - if (codec.CodecSchedule.Meetings[1] != null) - Dial(codec.CodecSchedule.Meetings[1]); - }); - trilist.SetSigFalseAction(joinMap.DialMeeting3.JoinNumber, () => - { - if (codec.CodecSchedule.Meetings[2] != null) - Dial(codec.CodecSchedule.Meetings[2]); - }); - - trilist.SetUshort(joinMap.MeetingCount.JoinNumber, (ushort)currentMeetings.Count); - } - - private string UpdateMeetingsListXSig(List meetings) - { - const int maxMeetings = 3; - const int maxDigitals = 2; - const int maxStrings = 7; - const int offset = maxDigitals + maxStrings; - var digitalIndex = maxStrings*maxMeetings; //15 - var stringIndex = 0; - var meetingIndex = 0; - - var tokenArray = new XSigToken[maxMeetings*offset]; - /* - * Digitals - * IsJoinable - 1 - * IsDialable - 2 - * - * Serials - * Organizer - 1 - * Title - 2 - * Start Date - 3 - * Start Time - 4 - * End Date - 5 - * End Time - 6 - */ - - - foreach(var meeting in meetings) - { - var currentTime = DateTime.Now; - - if(meeting.StartTime < currentTime && meeting.EndTime < currentTime) continue; - - if (meetingIndex >= maxMeetings*offset) - { - Debug.Console(2, this, "Max Meetings reached"); - break;} - - //digitals - tokenArray[digitalIndex] = new XSigDigitalToken(digitalIndex + 1, meeting.Joinable); - tokenArray[digitalIndex + 1] = new XSigDigitalToken(digitalIndex + 2, meeting.Id != "0"); - - //serials - tokenArray[stringIndex] = new XSigSerialToken(stringIndex + 1, meeting.Organizer); - tokenArray[stringIndex + 1] = new XSigSerialToken(stringIndex + 2, meeting.Title); - tokenArray[stringIndex + 2] = new XSigSerialToken(stringIndex + 3, meeting.StartTime.ToShortDateString()); - tokenArray[stringIndex + 3] = new XSigSerialToken(stringIndex + 4, meeting.StartTime.ToShortTimeString()); - tokenArray[stringIndex + 4] = new XSigSerialToken(stringIndex + 5, meeting.EndTime.ToShortDateString()); - tokenArray[stringIndex + 5] = new XSigSerialToken(stringIndex + 6, meeting.EndTime.ToShortTimeString()); - tokenArray[stringIndex + 6] = new XSigSerialToken(stringIndex + 7, meeting.Id); - - - digitalIndex += maxDigitals; - meetingIndex += offset; - stringIndex += maxStrings; - } - - while (meetingIndex < maxMeetings*offset) - { - Debug.Console(2, this, "Clearing unused data. Meeting Index: {0} MaxMeetings * Offset: {1}", - meetingIndex, maxMeetings*offset); - - //digitals - tokenArray[digitalIndex] = new XSigDigitalToken(digitalIndex + 1, false); - tokenArray[digitalIndex + 1] = new XSigDigitalToken(digitalIndex + 2, false); - - //serials - tokenArray[stringIndex] = new XSigSerialToken(stringIndex + 1, String.Empty); - tokenArray[stringIndex + 1] = new XSigSerialToken(stringIndex + 2, String.Empty); - tokenArray[stringIndex + 2] = new XSigSerialToken(stringIndex + 3, String.Empty); - tokenArray[stringIndex + 3] = new XSigSerialToken(stringIndex + 4, String.Empty); - tokenArray[stringIndex + 4] = new XSigSerialToken(stringIndex + 5, String.Empty); - tokenArray[stringIndex + 5] = new XSigSerialToken(stringIndex + 6, String.Empty); - tokenArray[stringIndex + 6] = new XSigSerialToken(stringIndex + 7, String.Empty); - - digitalIndex += maxDigitals; - meetingIndex += offset; - stringIndex += maxStrings; - } - - return GetXSigString(tokenArray); - } - - private void LinkVideoCodecDirectoryToApi(IHasDirectory codec, BasicTriList trilist, VideoCodecControllerJoinMap joinMap) - { - codec.CurrentDirectoryResultIsNotDirectoryRoot.LinkComplementInputSig( - trilist.BooleanInput[joinMap.DirectoryIsRoot.JoinNumber]); - - trilist.SetSigFalseAction(joinMap.DirectoryRoot.JoinNumber, codec.SetCurrentDirectoryToRoot); - - trilist.SetStringSigAction(joinMap.DirectorySearchString.JoinNumber, codec.SearchDirectory); - - trilist.SetUShortSigAction(joinMap.DirectorySelectRow.JoinNumber, (i) => SelectDirectoryEntry(codec, i)); - - trilist.SetSigFalseAction(joinMap.DirectoryRoot.JoinNumber, codec.SetCurrentDirectoryToRoot); - - trilist.SetSigFalseAction(joinMap.DirectoryFolderBack.JoinNumber, codec.GetDirectoryParentFolderContents); - - codec.DirectoryResultReturned += (sender, args) => - { - trilist.SetUshort(joinMap.DirectoryRowCount.JoinNumber, (ushort) args.Directory.CurrentDirectoryResults.Count); - - var clearBytes = XSigHelpers.ClearOutputs(); - - trilist.SetString(joinMap.DirectoryEntries.JoinNumber, - Encoding.GetEncoding(XSigEncoding).GetString(clearBytes, 0, clearBytes.Length)); - var directoryXSig = UpdateDirectoryXSig(args.Directory, !codec.CurrentDirectoryResultIsNotDirectoryRoot.BoolValue); - - trilist.SetString(joinMap.DirectoryEntries.JoinNumber, directoryXSig); - }; - } - - private void SelectDirectoryEntry(IHasDirectory codec, ushort i) - { - var entry = codec.CurrentDirectoryResult.CurrentDirectoryResults[i - 1]; - - if (entry is DirectoryFolder) - { - codec.GetDirectoryFolderContents(entry.FolderId); - return; - } - - var dialableEntry = entry as IInvitableContact; - - if (dialableEntry != null) - { - Dial(dialableEntry); - return; - } - - var entryToDial = entry as DirectoryContact; - - if (entryToDial == null) return; - - Dial(entryToDial.ContactMethods[0].Number); - } - - private string UpdateDirectoryXSig(CodecDirectory directory, bool isRoot) - { - var contactIndex = 1; - var tokenArray = new XSigToken[directory.CurrentDirectoryResults.Count]; - - foreach(var entry in directory.CurrentDirectoryResults) - { - var arrayIndex = contactIndex - 1; - - if (entry is DirectoryFolder && entry.ParentFolderId == "root") - { - tokenArray[arrayIndex] = new XSigSerialToken(contactIndex, String.Format("[+] {0}", entry.Name)); - - contactIndex++; - - continue; - } - - if(isRoot && String.IsNullOrEmpty(entry.FolderId)) continue; - - tokenArray[arrayIndex] = new XSigSerialToken(contactIndex, entry.Name); - - contactIndex++; - } - - return GetXSigString(tokenArray); - } - - private void LinkVideoCodecCallControlsToApi(BasicTriList trilist, VideoCodecControllerJoinMap joinMap) - { - trilist.SetSigFalseAction(joinMap.ManualDial.JoinNumber, - () => Dial(trilist.StringOutput[joinMap.CurrentDialString.JoinNumber].StringValue)); - - //End All calls for now - trilist.SetSigFalseAction(joinMap.EndCall.JoinNumber, EndAllCalls); - - trilist.SetBool(joinMap.HookState.JoinNumber, IsInCall); - - CallStatusChange += (sender, args) => - { - trilist.SetBool(joinMap.HookState.JoinNumber, IsInCall); - - Debug.Console(1, this, "Call Direction: {0}", args.CallItem.Direction); - Debug.Console(1, this, "Call is incoming: {0}", args.CallItem.Direction == eCodecCallDirection.Incoming); - trilist.SetBool(joinMap.IncomingCall.JoinNumber, args.CallItem.Direction == eCodecCallDirection.Incoming && args.CallItem.Status != eCodecCallStatus.Disconnected); - - if (args.CallItem.Direction == eCodecCallDirection.Incoming) - { - trilist.SetSigFalseAction(joinMap.IncomingAnswer.JoinNumber, () => AcceptCall(args.CallItem)); - trilist.SetSigFalseAction(joinMap.IncomingReject.JoinNumber, () => RejectCall(args.CallItem)); - } - - trilist.SetString(joinMap.CurrentCallData.JoinNumber, UpdateCallStatusXSig()); - }; - } - - private string UpdateCallStatusXSig() - { - const int maxCalls = 8; - const int maxStrings = 5; - const int offset = 6; - var stringIndex = 0; - var digitalIndex = maxStrings * maxCalls; - var arrayIndex = 0; - - var tokenArray = new XSigToken[maxCalls*offset]; //set array size for number of calls * pieces of info - - foreach (var call in ActiveCalls) - { - if (arrayIndex >= maxCalls * offset) - break; - //digitals - tokenArray[arrayIndex] = new XSigDigitalToken(digitalIndex + 1, call.IsActiveCall); - - //serials - tokenArray[arrayIndex + 1] = new XSigSerialToken(stringIndex + 1, call.Name ?? String.Empty); - tokenArray[arrayIndex + 2] = new XSigSerialToken(stringIndex + 2, call.Number ?? String.Empty); - tokenArray[arrayIndex + 3] = new XSigSerialToken(stringIndex + 3, call.Direction.ToString()); - tokenArray[arrayIndex + 4] = new XSigSerialToken(stringIndex + 4, call.Type.ToString()); - tokenArray[arrayIndex + 5] = new XSigSerialToken(stringIndex + 5, call.Status.ToString()); - - arrayIndex += offset; - stringIndex += maxStrings; - digitalIndex++; - } - while (digitalIndex < maxCalls) - { - //digitals - tokenArray[arrayIndex] = new XSigDigitalToken(digitalIndex + 1, false); - - //serials - tokenArray[arrayIndex + 1] = new XSigSerialToken(stringIndex + 1, String.Empty); - tokenArray[arrayIndex + 2] = new XSigSerialToken(stringIndex + 2, String.Empty); - tokenArray[arrayIndex + 3] = new XSigSerialToken(stringIndex + 3, String.Empty); - tokenArray[arrayIndex + 4] = new XSigSerialToken(stringIndex + 4, String.Empty); - tokenArray[arrayIndex + 5] = new XSigSerialToken(stringIndex + 5, String.Empty); - - arrayIndex += offset; - stringIndex += maxStrings; - digitalIndex++; - } - - return GetXSigString(tokenArray); - } - - private void LinkVideoCodecDtmfToApi(BasicTriList trilist, VideoCodecControllerJoinMap joinMap) - { - trilist.SetSigFalseAction(joinMap.Dtmf0.JoinNumber, () => SendDtmf("0")); - trilist.SetSigFalseAction(joinMap.Dtmf1.JoinNumber, () => SendDtmf("1")); - trilist.SetSigFalseAction(joinMap.Dtmf2.JoinNumber, () => SendDtmf("2")); - trilist.SetSigFalseAction(joinMap.Dtmf3.JoinNumber, () => SendDtmf("3")); - trilist.SetSigFalseAction(joinMap.Dtmf4.JoinNumber, () => SendDtmf("4")); - trilist.SetSigFalseAction(joinMap.Dtmf5.JoinNumber, () => SendDtmf("5")); - trilist.SetSigFalseAction(joinMap.Dtmf6.JoinNumber, () => SendDtmf("6")); - trilist.SetSigFalseAction(joinMap.Dtmf7.JoinNumber, () => SendDtmf("7")); - trilist.SetSigFalseAction(joinMap.Dtmf8.JoinNumber, () => SendDtmf("8")); - trilist.SetSigFalseAction(joinMap.Dtmf9.JoinNumber, () => SendDtmf("9")); - trilist.SetSigFalseAction(joinMap.DtmfStar.JoinNumber, () => SendDtmf("*")); - trilist.SetSigFalseAction(joinMap.DtmfPound.JoinNumber, () => SendDtmf("#")); - } - - private void LinkVideoCodecCameraLayoutsToApi(IHasCodecLayouts codec, BasicTriList trilist, VideoCodecControllerJoinMap joinMap) - { - trilist.SetSigFalseAction(joinMap.CameraLayout.JoinNumber, codec.LocalLayoutToggle); - - codec.LocalLayoutFeedback.LinkInputSig(trilist.StringInput[joinMap.CameraLayoutStringFb.JoinNumber]); - } - - private void LinkVideoCodecCameraModeToApi(IHasCameraAutoMode codec, BasicTriList trilist, VideoCodecControllerJoinMap joinMap) - { - trilist.SetSigFalseAction(joinMap.CameraModeAuto.JoinNumber, codec.CameraAutoModeOn); - trilist.SetSigFalseAction(joinMap.CameraModeManual.JoinNumber, codec.CameraAutoModeOff); - - codec.CameraAutoModeIsOnFeedback.OutputChange += (o, a) => - { - var offCodec = codec as IHasCameraOff; - - if (offCodec != null) - { - if (offCodec.CameraIsOffFeedback.BoolValue) - { - trilist.SetBool(joinMap.CameraModeAuto.JoinNumber, false); - trilist.SetBool(joinMap.CameraModeManual.JoinNumber, false); - trilist.SetBool(joinMap.CameraModeOff.JoinNumber, true); - return; - } - - trilist.SetBool(joinMap.CameraModeAuto.JoinNumber, a.BoolValue); - trilist.SetBool(joinMap.CameraModeManual.JoinNumber, !a.BoolValue); - trilist.SetBool(joinMap.CameraModeOff.JoinNumber, false); - return; - } - - trilist.SetBool(joinMap.CameraModeAuto.JoinNumber, a.BoolValue); - trilist.SetBool(joinMap.CameraModeManual.JoinNumber, !a.BoolValue); - trilist.SetBool(joinMap.CameraModeOff.JoinNumber, false); - }; - - var offModeCodec = codec as IHasCameraOff; - - if (offModeCodec != null) - { - if (offModeCodec.CameraIsOffFeedback.BoolValue) - { - trilist.SetBool(joinMap.CameraModeAuto.JoinNumber, false); - trilist.SetBool(joinMap.CameraModeManual.JoinNumber, false); - trilist.SetBool(joinMap.CameraModeOff.JoinNumber, true); - return; - } - - trilist.SetBool(joinMap.CameraModeAuto.JoinNumber, codec.CameraAutoModeIsOnFeedback.BoolValue); - trilist.SetBool(joinMap.CameraModeManual.JoinNumber, !codec.CameraAutoModeIsOnFeedback.BoolValue); - trilist.SetBool(joinMap.CameraModeOff.JoinNumber, false); - return; - } - - trilist.SetBool(joinMap.CameraModeAuto.JoinNumber, codec.CameraAutoModeIsOnFeedback.BoolValue); - trilist.SetBool(joinMap.CameraModeManual.JoinNumber, !codec.CameraAutoModeIsOnFeedback.BoolValue); - trilist.SetBool(joinMap.CameraModeOff.JoinNumber, false); - } - - private void LinkVideoCodecSelfviewToApi(IHasCodecSelfView codec, BasicTriList trilist, - VideoCodecControllerJoinMap joinMap) - { - trilist.SetSigFalseAction(joinMap.CameraSelfView.JoinNumber, codec.SelfViewModeToggle); - - codec.SelfviewIsOnFeedback.LinkInputSig(trilist.BooleanInput[joinMap.CameraSelfView.JoinNumber]); - } - - private void LinkVideoCodecCameraToApi(IHasCodecCameras codec, BasicTriList trilist, VideoCodecControllerJoinMap joinMap) - { - //Camera PTZ - trilist.SetBoolSigAction(joinMap.CameraTiltUp.JoinNumber, (b) => - { - if (codec.SelectedCamera == null) return; - var camera = codec.SelectedCamera as IHasCameraPtzControl; - - if (camera == null) return; - - if (b) camera.TiltUp(); - else camera.TiltStop(); - }); - - trilist.SetBoolSigAction(joinMap.CameraTiltDown.JoinNumber, (b) => - { - if (codec.SelectedCamera == null) return; - var camera = codec.SelectedCamera as IHasCameraPtzControl; - - if (camera == null) return; - - if (b) camera.TiltDown(); - else camera.TiltStop(); - }); - trilist.SetBoolSigAction(joinMap.CameraPanLeft.JoinNumber, (b) => - { - if (codec.SelectedCamera == null) return; - var camera = codec.SelectedCamera as IHasCameraPtzControl; - - if (camera == null) return; - - if (b) camera.PanLeft(); - else camera.PanStop(); - }); - trilist.SetBoolSigAction(joinMap.CameraPanRight.JoinNumber, (b) => - { - if (codec.SelectedCamera == null) return; - var camera = codec.SelectedCamera as IHasCameraPtzControl; - - if (camera == null) return; - - if (b) camera.PanRight(); - else camera.PanStop(); - }); - - trilist.SetBoolSigAction(joinMap.CameraZoomIn.JoinNumber, (b) => - { - if (codec.SelectedCamera == null) return; - var camera = codec.SelectedCamera as IHasCameraPtzControl; - - if (camera == null) return; - - if (b) camera.ZoomIn(); - else camera.ZoomStop(); - }); - - trilist.SetBoolSigAction(joinMap.CameraZoomOut.JoinNumber, (b) => - { - if (codec.SelectedCamera == null) return; - var camera = codec.SelectedCamera as IHasCameraPtzControl; - - if (camera == null) return; - - if (b) camera.ZoomOut(); - else camera.ZoomStop(); - }); - - //Camera Select - trilist.SetUShortSigAction(joinMap.CameraNumberSelect.JoinNumber, (i) => - { - if (codec.SelectedCamera == null) return; - - codec.SelectCamera(codec.Cameras[i].Key); - }); - - codec.CameraSelected += (sender, args) => - { - var i = (ushort) codec.Cameras.FindIndex((c) => c.Key == args.SelectedCamera.Key); - - if (codec is IHasCodecRoomPresets) - { - return; - } - - if (!(args.SelectedCamera is IHasCameraPresets)) - { - return; - } - - var cam = args.SelectedCamera as IHasCameraPresets; - SetCameraPresetNames(cam.Presets); - - (args.SelectedCamera as IHasCameraPresets).PresetsListHasChanged += (o, eventArgs) => SetCameraPresetNames(cam.Presets); - - trilist.SetUShortSigAction(joinMap.CameraPresetSelect.JoinNumber, - (a) => - { - cam.PresetSelect(a); - trilist.SetUshort(joinMap.CameraPresetSelect.JoinNumber, a); - }); - - trilist.SetSigFalseAction(joinMap.CameraPresetSave.JoinNumber, - () => - { - cam.PresetStore(trilist.UShortOutput[joinMap.CameraPresetSelect.JoinNumber].UShortValue, - String.Empty); - trilist.PulseBool(joinMap.CameraPresetSave.JoinNumber, 3000); - }); - }; - - if (!(codec is IHasCodecRoomPresets)) return; - - var presetCodec = codec as IHasCodecRoomPresets; - - presetCodec.CodecRoomPresetsListHasChanged += - (sender, args) => SetCameraPresetNames(presetCodec.NearEndPresets); - - //Camera Presets - trilist.SetUShortSigAction(joinMap.CameraPresetSelect.JoinNumber, (i) => - { - presetCodec.CodecRoomPresetSelect(i); - - trilist.SetUshort(joinMap.CameraPresetSelect.JoinNumber, i); - }); - - trilist.SetSigFalseAction(joinMap.CameraPresetSave.JoinNumber, - () => - { - presetCodec.CodecRoomPresetStore( - trilist.UShortOutput[joinMap.CameraPresetSelect.JoinNumber].UShortValue, String.Empty); - trilist.PulseBool(joinMap.CameraPresetSave.JoinNumber, 3000); - }); - } - - private string SetCameraPresetNames(IEnumerable presets) - { - return SetCameraPresetNames(presets.Select(p => p.Description).ToList()); - } - - private string SetCameraPresetNames(IEnumerable presets) - { - return SetCameraPresetNames(presets.Select(p => p.Description).ToList()); - } - - private string SetCameraPresetNames(ICollection presets) - { - var i = 1; //start index for xsig; - - var tokenArray = new XSigToken[presets.Count]; - - foreach (var preset in presets) - { - var cameraPreset = new XSigSerialToken(i, preset); - tokenArray[i - 1] = cameraPreset; - i++; - } - - return GetXSigString(tokenArray); - } - - private string GetXSigString(XSigToken[] tokenArray) - { - string returnString; - using (var s = new MemoryStream()) - { - using (var tw = new XSigTokenStreamWriter(s, true)) - { - tw.WriteXSigData(tokenArray); - } - - var xSig = s.ToArray(); - - returnString = Encoding.GetEncoding(XSigEncoding).GetString(xSig, 0, xSig.Length); - } - - return returnString; - } - - #endregion - } - - - /// - /// Used to track the status of syncronizing the phonebook values when connecting to a codec or refreshing the phonebook info - /// - public class CodecPhonebookSyncState : IKeyed - { - private bool _InitialSyncComplete; - - public CodecPhonebookSyncState(string key) - { - Key = key; - - CodecDisconnected(); - } - - public bool InitialSyncComplete - { - get { return _InitialSyncComplete; } - private set - { - if (value == true) - { - var handler = InitialSyncCompleted; - if (handler != null) - { - handler(this, new EventArgs()); - } - } - _InitialSyncComplete = value; - } - } - - public bool InitialPhonebookFoldersWasReceived { get; private set; } - - public bool NumberOfContactsWasReceived { get; private set; } - - public bool PhonebookRootEntriesWasRecieved { get; private set; } - - public bool PhonebookHasFolders { get; private set; } - - public int NumberOfContacts { get; private set; } - - #region IKeyed Members - - public string Key { get; private set; } - - #endregion - - public event EventHandler InitialSyncCompleted; - - public void InitialPhonebookFoldersReceived() - { - InitialPhonebookFoldersWasReceived = true; - - CheckSyncStatus(); - } - - public void PhonebookRootEntriesReceived() - { - PhonebookRootEntriesWasRecieved = true; - - CheckSyncStatus(); - } - - public void SetPhonebookHasFolders(bool value) - { - PhonebookHasFolders = value; - - Debug.Console(1, this, "Phonebook has folders: {0}", PhonebookHasFolders); - } - - public void SetNumberOfContacts(int contacts) - { - NumberOfContacts = contacts; - NumberOfContactsWasReceived = true; - - Debug.Console(1, this, "Phonebook contains {0} contacts.", NumberOfContacts); - - CheckSyncStatus(); - } - - public void CodecDisconnected() - { - InitialPhonebookFoldersWasReceived = false; - PhonebookHasFolders = false; - NumberOfContacts = 0; - NumberOfContactsWasReceived = false; - } - - private void CheckSyncStatus() - { - if (InitialPhonebookFoldersWasReceived && NumberOfContactsWasReceived && PhonebookRootEntriesWasRecieved) - { - InitialSyncComplete = true; - Debug.Console(1, this, "Initial Phonebook Sync Complete!"); - } - else - { - InitialSyncComplete = false; - } - } - } + }; + } + } + + protected abstract Func SharingSourceFeedbackFunc { get; } + protected abstract Func SharingContentIsOnFeedbackFunc { get; } + + #region ICodecAudio Members + + public abstract void PrivacyModeOn(); + public abstract void PrivacyModeOff(); + public abstract void PrivacyModeToggle(); + public BoolFeedback PrivacyModeIsOnFeedback { get; private set; } + + + public BoolFeedback MuteFeedback { get; private set; } + + public abstract void MuteOff(); + + public abstract void MuteOn(); + + public abstract void SetVolume(ushort level); + + public IntFeedback VolumeLevelFeedback { get; private set; } + + public abstract void MuteToggle(); + + public abstract void VolumeDown(bool pressRelease); + + + public abstract void VolumeUp(bool pressRelease); + + #endregion + + #region IHasContentSharing Members + + public abstract void StartSharing(); + public abstract void StopSharing(); + + public bool AutoShareContentWhileInCall { get; protected set; } + + public StringFeedback SharingSourceFeedback { get; private set; } + public BoolFeedback SharingContentIsOnFeedback { get; private set; } + + #endregion + + #region IHasDialer Members + + /// + /// Fires when the status of any active, dialing, or incoming call changes or is new + /// + public event EventHandler CallStatusChange; + + /// + /// Returns true when any call is not in state Unknown, Disconnecting, Disconnected + /// + public bool IsInCall + { + get + { + var value = ActiveCalls != null && ActiveCalls.Any(c => c.IsActiveCall); + return value; + } + } + + public abstract void Dial(string number); + public abstract void EndCall(CodecActiveCallItem call); + public abstract void EndAllCalls(); + public abstract void AcceptCall(CodecActiveCallItem call); + public abstract void RejectCall(CodecActiveCallItem call); + public abstract void SendDtmf(string s); + + #endregion + + #region IRoutingInputsOutputs Members + + public RoutingPortCollection InputPorts { get; private set; } + + public RoutingPortCollection OutputPorts { get; private set; } + + #endregion + + #region IUsageTracking Members + + /// + /// This object can be added by outside users of this class to provide usage tracking + /// for various services + /// + public UsageTracking UsageTracker { get; set; } + + #endregion + + #region iVideoCodecInfo Members + + public VideoCodecInfo CodecInfo { get; protected set; } + + #endregion + + public event EventHandler IsReadyChange; + public abstract void Dial(Meeting meeting); + + public virtual void Dial(IInvitableContact contact) + { + } + + public abstract void ExecuteSwitch(object selector); + + /// + /// Helper method to fire CallStatusChange event with old and new status + /// + protected void SetNewCallStatusAndFireCallStatusChange(eCodecCallStatus newStatus, CodecActiveCallItem call) + { + call.Status = newStatus; + + OnCallStatusChange(call); + } + + /// + /// + /// + /// + /// + /// + protected virtual void OnCallStatusChange(CodecActiveCallItem item) + { + var handler = CallStatusChange; + if (handler != null) + { + handler(this, new CodecCallStatusItemChangeEventArgs(item)); + } + + if (AutoShareContentWhileInCall) + { + StartSharing(); + } + + if (UsageTracker != null) + { + if (IsInCall && !UsageTracker.UsageTrackingStarted) + { + UsageTracker.StartDeviceUsage(); + } + else if (UsageTracker.UsageTrackingStarted && !IsInCall) + { + UsageTracker.EndDeviceUsage(); + } + } + } + + /// + /// Sets IsReady property and fires the event. Used for dependent classes to sync up their data. + /// + protected void SetIsReady() + { + CrestronInvoke.BeginInvoke((o) => + { + try + { + IsReady = true; + var h = IsReadyChange; + if (h != null) + { + h(this, new EventArgs()); + } + } + catch (Exception e) + { + Debug.Console(2, this, "Error in SetIsReady() : {0}", e); + } + }); + } + + // **** DEBUGGING THINGS **** + /// + /// + /// + public virtual void ListCalls() + { + var sb = new StringBuilder(); + foreach (var c in ActiveCalls) + { + sb.AppendFormat("{0} {1} -- {2} {3}\n", c.Id, c.Number, c.Name, c.Status); + } + Debug.Console(1, this, "\n{0}\n", sb.ToString()); + } + + public abstract void StandbyActivate(); + + public abstract void StandbyDeactivate(); + + #region Implementation of IBridgeAdvanced + + public abstract void LinkToApi(BasicTriList trilist, uint joinStart, string joinMapKey, EiscApiAdvanced bridge); + + protected void LinkVideoCodecToApi(VideoCodecBase codec, BasicTriList trilist, uint joinStart, string joinMapKey, + EiscApiAdvanced bridge) + { + var joinMap = new VideoCodecControllerJoinMap(joinStart); + + var customJoins = JoinMapHelper.TryGetJoinMapAdvancedForDevice(joinMapKey); + + if (customJoins != null) + { + joinMap.SetCustomJoinData(customJoins); + } + + if (bridge != null) + { + bridge.AddJoinMap(Key, joinMap); + } + + Debug.Console(1, this, "Linking to Trilist {0}", trilist.ID.ToString("X")); + + + + LinkVideoCodecDtmfToApi(trilist, joinMap); + + LinkVideoCodecCallControlsToApi(trilist, joinMap); + + LinkVideoCodecContentSharingToApi(trilist, joinMap); + + LinkVideoCodecPrivacyToApi(trilist, joinMap); + + LinkVideoCodecVolumeToApi(trilist, joinMap); + + if (codec is ICommunicationMonitor) + { + LinkVideoCodecCommMonitorToApi(codec as ICommunicationMonitor, trilist, joinMap); + } + + if (codec is IHasCodecCameras) + { + LinkVideoCodecCameraToApi(codec as IHasCodecCameras, trilist, joinMap); + } + + if (codec is IHasCodecSelfView) + { + LinkVideoCodecSelfviewToApi(codec as IHasCodecSelfView, trilist, joinMap); + } + + if (codec is IHasCameraAutoMode) + { + trilist.SetBool(joinMap.CameraSupportsAutoMode.JoinNumber, SupportsCameraAutoMode); + LinkVideoCodecCameraModeToApi(codec as IHasCameraAutoMode, trilist, joinMap); + } + + if (codec is IHasCameraOff) + { + trilist.SetBool(joinMap.CameraSupportsOffMode.JoinNumber, SupportsCameraOff); + LinkVideoCodecCameraOffToApi(codec as IHasCameraOff, trilist, joinMap); + } + + if (codec is IHasCodecLayouts) + { + LinkVideoCodecCameraLayoutsToApi(codec as IHasCodecLayouts, trilist, joinMap); + } + + if (codec is IHasSelfviewPosition) + { + LinkVideoCodecSelfviewPositionToApi(codec as IHasSelfviewPosition, trilist, joinMap); + } + + if (codec is IHasDirectory) + { + LinkVideoCodecDirectoryToApi(codec as IHasDirectory, trilist, joinMap); + } + + if (codec is IHasScheduleAwareness) + { + LinkVideoCodecScheduleToApi(codec as IHasScheduleAwareness, trilist, joinMap); + } + + if (codec is IHasParticipants) + { + LinkVideoCodecParticipantsToApi(codec as IHasParticipants, trilist, joinMap); + } + + if (codec is IHasFarEndContentStatus) + { + (codec as IHasFarEndContentStatus).ReceivingContent.LinkInputSig(trilist.BooleanInput[joinMap.RecievingContent.JoinNumber]); + } + + if (codec is IHasPhoneDialing) + { + LinkVideoCodecPhoneToApi(codec as IHasPhoneDialing, trilist, joinMap); + } + + trilist.OnlineStatusChange += (device, args) => + { + if (!args.DeviceOnLine) return; + + if (codec is IHasDirectory) + { + (codec as IHasDirectory).SetCurrentDirectoryToRoot(); + } + + if (codec is IHasScheduleAwareness) + { + (codec as IHasScheduleAwareness).GetSchedule(); + } + + if (codec is IHasParticipants) + { + UpdateParticipantsXSig((codec as IHasParticipants).Participants.CurrentParticipants); + } + + if (codec is IHasCameraAutoMode) + { + trilist.SetBool(joinMap.CameraSupportsAutoMode.JoinNumber, true); + + (codec as IHasCameraAutoMode).CameraAutoModeIsOnFeedback.FireUpdate(); + } + + if (codec is IHasCodecSelfView) + { + (codec as IHasCodecSelfView).SelfviewIsOnFeedback.FireUpdate(); + } + + if (codec is IHasCameraAutoMode) + { + (codec as IHasCameraAutoMode).CameraAutoModeIsOnFeedback.FireUpdate(); + } + + if (codec is IHasCameraOff) + { + (codec as IHasCameraOff).CameraIsOffFeedback.FireUpdate(); + } + + if (codec is IHasPhoneDialing) + { + (codec as IHasPhoneDialing).PhoneOffHookFeedback.FireUpdate(); + } + + SharingContentIsOnFeedback.FireUpdate(); + + trilist.SetBool(joinMap.HookState.JoinNumber, IsInCall); + + trilist.SetString(joinMap.CurrentCallData.JoinNumber, UpdateCallStatusXSig()); + }; + } + + private void LinkVideoCodecPhoneToApi(IHasPhoneDialing codec, BasicTriList trilist, VideoCodecControllerJoinMap joinMap) + { + codec.PhoneOffHookFeedback.LinkInputSig(trilist.BooleanInput[joinMap.PhoneHookState.JoinNumber]); + + trilist.SetSigFalseAction(joinMap.DialPhone.JoinNumber, + () => codec.DialPhoneCall(trilist.StringOutput[joinMap.PhoneDialString.JoinNumber].StringValue)); + + trilist.SetSigFalseAction(joinMap.HangUpPhone.JoinNumber, codec.EndPhoneCall); + } + + private void LinkVideoCodecSelfviewPositionToApi(IHasSelfviewPosition codec, BasicTriList trilist, VideoCodecControllerJoinMap joinMap) + { + trilist.SetSigFalseAction(joinMap.SelfviewPosition.JoinNumber, codec.SelfviewPipPositionToggle); + + codec.SelfviewPipPositionFeedback.LinkInputSig(trilist.StringInput[joinMap.SelfviewPositionFb.JoinNumber]); + } + + private void LinkVideoCodecCameraOffToApi(IHasCameraOff codec, BasicTriList trilist, VideoCodecControllerJoinMap joinMap) + { + trilist.SetSigFalseAction(joinMap.CameraModeOff.JoinNumber, codec.CameraOff); + + codec.CameraIsOffFeedback.OutputChange += (o, a) => + { + if (a.BoolValue) + { + trilist.SetBool(joinMap.CameraModeOff.JoinNumber, true); + trilist.SetBool(joinMap.CameraModeManual.JoinNumber, false); + trilist.SetBool(joinMap.CameraModeAuto.JoinNumber, false); + return; + } + + trilist.SetBool(joinMap.CameraModeOff.JoinNumber, false); + + var autoCodec = codec as IHasCameraAutoMode; + + if (autoCodec == null) return; + + trilist.SetBool(joinMap.CameraModeAuto.JoinNumber, autoCodec.CameraAutoModeIsOnFeedback.BoolValue); + trilist.SetBool(joinMap.CameraModeManual.JoinNumber, !autoCodec.CameraAutoModeIsOnFeedback.BoolValue); + }; + + if (codec.CameraIsOffFeedback.BoolValue) + { + trilist.SetBool(joinMap.CameraModeOff.JoinNumber, true); + trilist.SetBool(joinMap.CameraModeManual.JoinNumber, false); + trilist.SetBool(joinMap.CameraModeAuto.JoinNumber, false); + return; + } + + trilist.SetBool(joinMap.CameraModeOff.JoinNumber, false); + + var autoModeCodec = codec as IHasCameraAutoMode; + + if (autoModeCodec == null) return; + + trilist.SetBool(joinMap.CameraModeAuto.JoinNumber, autoModeCodec.CameraAutoModeIsOnFeedback.BoolValue); + trilist.SetBool(joinMap.CameraModeManual.JoinNumber, !autoModeCodec.CameraAutoModeIsOnFeedback.BoolValue); + } + + private void LinkVideoCodecVolumeToApi(BasicTriList trilist, VideoCodecControllerJoinMap joinMap) + { + MuteFeedback.LinkInputSig(trilist.BooleanInput[joinMap.VolumeMuteOn.JoinNumber]); + MuteFeedback.LinkComplementInputSig(trilist.BooleanInput[joinMap.VolumeMuteOff.JoinNumber]); + + trilist.SetSigFalseAction(joinMap.VolumeMuteOn.JoinNumber, MuteOn); + trilist.SetSigFalseAction(joinMap.VolumeMuteOff.JoinNumber, MuteOff); + trilist.SetSigFalseAction(joinMap.VolumeMuteToggle.JoinNumber, MuteToggle); + + VolumeLevelFeedback.LinkInputSig(trilist.UShortInput[joinMap.VolumeLevel.JoinNumber]); + + trilist.SetBoolSigAction(joinMap.VolumeUp.JoinNumber, VolumeUp); + trilist.SetBoolSigAction(joinMap.VolumeDown.JoinNumber, VolumeDown); + + trilist.SetUShortSigAction(joinMap.VolumeLevel.JoinNumber, SetVolume); + + } + + private void LinkVideoCodecPrivacyToApi(BasicTriList trilist, VideoCodecControllerJoinMap joinMap) + { + PrivacyModeIsOnFeedback.LinkInputSig(trilist.BooleanInput[joinMap.MicMuteOn.JoinNumber]); + PrivacyModeIsOnFeedback.LinkComplementInputSig(trilist.BooleanInput[joinMap.MicMuteOff.JoinNumber]); + + trilist.SetSigFalseAction(joinMap.MicMuteOn.JoinNumber, PrivacyModeOn); + trilist.SetSigFalseAction(joinMap.MicMuteOff.JoinNumber, PrivacyModeOff); + trilist.SetSigFalseAction(joinMap.MicMuteToggle.JoinNumber, PrivacyModeToggle); + } + + private void LinkVideoCodecCommMonitorToApi(ICommunicationMonitor codec, BasicTriList trilist, VideoCodecControllerJoinMap joinMap) + { + codec.CommunicationMonitor.IsOnlineFeedback.LinkInputSig(trilist.BooleanInput[joinMap.IsOnline.JoinNumber]); + } + + private void LinkVideoCodecParticipantsToApi(IHasParticipants codec, BasicTriList trilist, VideoCodecControllerJoinMap joinMap) + { + codec.Participants.ParticipantsListHasChanged += (sender, args) => + { + string participantsXSig; + + if (codec.Participants.CurrentParticipants.Count == 0) + { + participantsXSig = Encoding.GetEncoding(XSigEncoding).GetString(_clearBytes, 0, _clearBytes.Length); + trilist.SetString(joinMap.CurrentParticipants.JoinNumber, participantsXSig); + trilist.SetUshort(joinMap.ParticipantCount.JoinNumber, (ushort)codec.Participants.CurrentParticipants.Count); + return; + } + + participantsXSig = UpdateParticipantsXSig(codec.Participants.CurrentParticipants); + + trilist.SetString(joinMap.CurrentParticipants.JoinNumber, participantsXSig); + + trilist.SetUshort(joinMap.ParticipantCount.JoinNumber, (ushort)codec.Participants.CurrentParticipants.Count); + }; + } + + private string UpdateParticipantsXSig(List currentParticipants) + { + const int maxParticipants = 50; + const int maxDigitals = 5; + const int maxStrings = 1; + const int offset = maxDigitals + maxStrings; + var digitalIndex = maxStrings * maxParticipants; //15 + var stringIndex = 0; + var meetingIndex = 0; + + var tokenArray = new XSigToken[maxParticipants * offset]; + + foreach (var participant in currentParticipants) + { + if (meetingIndex >= maxParticipants * offset) break; + + //digitals + tokenArray[digitalIndex] = new XSigDigitalToken(digitalIndex + 1, participant.AudioMuteFb); + tokenArray[digitalIndex + 1] = new XSigDigitalToken(digitalIndex + 2, participant.VideoMuteFb); + tokenArray[digitalIndex + 2] = new XSigDigitalToken(digitalIndex + 3, participant.CanMuteVideo); + tokenArray[digitalIndex + 3] = new XSigDigitalToken(digitalIndex + 4, participant.CanUnmuteVideo); + tokenArray[digitalIndex + 4] = new XSigDigitalToken(digitalIndex + 5, participant.IsHost); + + //serials + tokenArray[stringIndex] = new XSigSerialToken(stringIndex + 1, participant.Name); + + digitalIndex += maxDigitals; + meetingIndex += offset; + stringIndex += maxStrings; + } + + while (meetingIndex < maxParticipants * offset) + { + tokenArray[digitalIndex] = new XSigDigitalToken(digitalIndex + 1, false); + tokenArray[digitalIndex + 1] = new XSigDigitalToken(digitalIndex + 2, false); + tokenArray[digitalIndex + 2] = new XSigDigitalToken(digitalIndex + 3, false); + tokenArray[digitalIndex + 3] = new XSigDigitalToken(digitalIndex + 4, false); + tokenArray[digitalIndex + 4] = new XSigDigitalToken(digitalIndex + 5, false); + + //serials + tokenArray[stringIndex] = new XSigSerialToken(stringIndex + 1, String.Empty); + + digitalIndex += maxDigitals; + meetingIndex += offset; + stringIndex += maxStrings; + } + + return GetXSigString(tokenArray); + } + + private void LinkVideoCodecContentSharingToApi(BasicTriList trilist, VideoCodecControllerJoinMap joinMap) + { + SharingContentIsOnFeedback.LinkInputSig(trilist.BooleanInput[joinMap.SourceShareStart.JoinNumber]); + SharingContentIsOnFeedback.LinkComplementInputSig(trilist.BooleanInput[joinMap.SourceShareEnd.JoinNumber]); + + SharingSourceFeedback.LinkInputSig(trilist.StringInput[joinMap.CurrentSource.JoinNumber]); + + trilist.SetSigFalseAction(joinMap.SourceShareStart.JoinNumber, StartSharing); + trilist.SetSigFalseAction(joinMap.SourceShareEnd.JoinNumber, StopSharing); + + trilist.SetBoolSigAction(joinMap.SourceShareAutoStart.JoinNumber, (b) => AutoShareContentWhileInCall = b); + } + + // TODO [ ] 2021-01-06, jkd: Added to debug OBTP dialing issues + private List _currentMeetings = new List(); + + private void LinkVideoCodecScheduleToApi(IHasScheduleAwareness codec, BasicTriList trilist, VideoCodecControllerJoinMap joinMap) + { + trilist.SetSigFalseAction(joinMap.UpdateMeetings.JoinNumber, codec.GetSchedule); + + trilist.SetUShortSigAction(joinMap.MinutesBeforeMeetingStart.JoinNumber, (i) => + { + codec.CodecSchedule.MeetingWarningMinutes = i; + }); + + // TODO [ ] 2021-01-06, jkd: Added to debug OBTP dialing issues + trilist.SetSigFalseAction(joinMap.DialMeeting1.JoinNumber, () => + { + var mtg = 1; + var index = mtg - 1; + Debug.Console(1, this, "Meeting {0} Selected (EISC dig-o{1}) > _currentMeetings[{2}].Id: {3}, Title: {4}", + mtg, joinMap.DialMeeting1.JoinNumber, index, _currentMeetings[index].Id, _currentMeetings[index].Title); + if (_currentMeetings[index] != null) + Dial(_currentMeetings[index]); + }); + // TODO [ ] 2021-01-06, jkd: Added to debug OBTP dialing issues + trilist.SetSigFalseAction(joinMap.DialMeeting2.JoinNumber, () => + { + var mtg = 2; + var index = mtg - 1; + Debug.Console(1, this, "Meeting {0} Selected (EISC dig-o{1}) > _currentMeetings[{2}].Id: {3}, Title: {4}", + mtg, joinMap.DialMeeting2.JoinNumber, index, _currentMeetings[index].Id, _currentMeetings[index].Title); + if (_currentMeetings[index] != null) + Dial(_currentMeetings[index]); + }); + // TODO [ ] 2021-01-06, jkd: Added to debug OBTP dialing issues + trilist.SetSigFalseAction(joinMap.DialMeeting3.JoinNumber, () => + { + var mtg = 3; + var index = mtg - 1; + Debug.Console(1, this, "Meeting {0} Selected (EISC dig-o{1}) > _currentMeetings[{2}].Id: {3}, Title: {4}", + mtg, joinMap.DialMeeting3.JoinNumber, index, _currentMeetings[index].Id, _currentMeetings[index].Title); + if (_currentMeetings[index] != null) + Dial(_currentMeetings[index]); + }); + + codec.CodecSchedule.MeetingsListHasChanged += (sender, args) => UpdateMeetingsList(codec, trilist, joinMap); + codec.CodecSchedule.MeetingEventChange += (sender, args) => + { + if (args.ChangeType == eMeetingEventChangeType.MeetingStartWarning) + { + UpdateMeetingsList(codec, trilist, joinMap); + } + }; + } + + private void UpdateMeetingsList(IHasScheduleAwareness codec, BasicTriList trilist, VideoCodecControllerJoinMap joinMap) + { + var currentTime = DateTime.Now; + + // TODO [ ] 2021-01-06, jkd: Added to debug OBTP dialing issues + // - changed var currentMeetings >> field _currentMeetings + //_currentMeetings.Clear(); + _currentMeetings = codec.CodecSchedule.Meetings.Where(m => m.StartTime >= currentTime || m.EndTime >= currentTime).ToList(); + + // TODO [ ] 2021-01-06, jkd: Added to debug OBTP dialing issues + // - moved the trilist.SetSigFlaseAction(joinMap.DialMeeting1..3.JoinNumber) lambda's to LinkVideoCodecScheduleToApi + + var meetingsData = UpdateMeetingsListXSig(_currentMeetings); + trilist.SetString(joinMap.Schedule.JoinNumber, meetingsData); + trilist.SetUshort(joinMap.MeetingCount.JoinNumber, (ushort)_currentMeetings.Count); + } + + private string UpdateMeetingsListXSig(List meetings) + { + const int maxMeetings = 3; + const int maxDigitals = 2; + const int maxStrings = 7; + const int offset = maxDigitals + maxStrings; + var digitalIndex = maxStrings * maxMeetings; //15 + var stringIndex = 0; + var meetingIndex = 0; + + var tokenArray = new XSigToken[maxMeetings * offset]; + /* + * Digitals + * IsJoinable - 1 + * IsDialable - 2 + * + * Serials + * Organizer - 1 + * Title - 2 + * Start Date - 3 + * Start Time - 4 + * End Date - 5 + * End Time - 6 + * Id - 7 + */ + + + foreach (var meeting in meetings) + { + var currentTime = DateTime.Now; + + if (meeting.StartTime < currentTime && meeting.EndTime < currentTime) continue; + + if (meetingIndex >= maxMeetings * offset) + { + Debug.Console(2, this, "Max Meetings reached"); + break; + } + + //digitals + tokenArray[digitalIndex] = new XSigDigitalToken(digitalIndex + 1, meeting.Joinable); + tokenArray[digitalIndex + 1] = new XSigDigitalToken(digitalIndex + 2, meeting.Id != "0"); + + //serials + tokenArray[stringIndex] = new XSigSerialToken(stringIndex + 1, meeting.Organizer); + tokenArray[stringIndex + 1] = new XSigSerialToken(stringIndex + 2, meeting.Title); + tokenArray[stringIndex + 2] = new XSigSerialToken(stringIndex + 3, meeting.StartTime.ToShortDateString()); + tokenArray[stringIndex + 3] = new XSigSerialToken(stringIndex + 4, meeting.StartTime.ToShortTimeString()); + tokenArray[stringIndex + 4] = new XSigSerialToken(stringIndex + 5, meeting.EndTime.ToShortDateString()); + tokenArray[stringIndex + 5] = new XSigSerialToken(stringIndex + 6, meeting.EndTime.ToShortTimeString()); + tokenArray[stringIndex + 6] = new XSigSerialToken(stringIndex + 7, meeting.Id); + + + digitalIndex += maxDigitals; + meetingIndex += offset; + stringIndex += maxStrings; + } + + while (meetingIndex < maxMeetings * offset) + { + Debug.Console(2, this, "Clearing unused data. Meeting Index: {0} MaxMeetings * Offset: {1}", + meetingIndex, maxMeetings * offset); + + //digitals + tokenArray[digitalIndex] = new XSigDigitalToken(digitalIndex + 1, false); + tokenArray[digitalIndex + 1] = new XSigDigitalToken(digitalIndex + 2, false); + + //serials + tokenArray[stringIndex] = new XSigSerialToken(stringIndex + 1, String.Empty); + tokenArray[stringIndex + 1] = new XSigSerialToken(stringIndex + 2, String.Empty); + tokenArray[stringIndex + 2] = new XSigSerialToken(stringIndex + 3, String.Empty); + tokenArray[stringIndex + 3] = new XSigSerialToken(stringIndex + 4, String.Empty); + tokenArray[stringIndex + 4] = new XSigSerialToken(stringIndex + 5, String.Empty); + tokenArray[stringIndex + 5] = new XSigSerialToken(stringIndex + 6, String.Empty); + tokenArray[stringIndex + 6] = new XSigSerialToken(stringIndex + 7, String.Empty); + + digitalIndex += maxDigitals; + meetingIndex += offset; + stringIndex += maxStrings; + } + + return GetXSigString(tokenArray); + } + + private void LinkVideoCodecDirectoryToApi(IHasDirectory codec, BasicTriList trilist, VideoCodecControllerJoinMap joinMap) + { + codec.CurrentDirectoryResultIsNotDirectoryRoot.LinkComplementInputSig( + trilist.BooleanInput[joinMap.DirectoryIsRoot.JoinNumber]); + + trilist.SetSigFalseAction(joinMap.DirectoryRoot.JoinNumber, codec.SetCurrentDirectoryToRoot); + + trilist.SetStringSigAction(joinMap.DirectorySearchString.JoinNumber, codec.SearchDirectory); + + trilist.SetUShortSigAction(joinMap.DirectorySelectRow.JoinNumber, (i) => SelectDirectoryEntry(codec, i)); + + trilist.SetSigFalseAction(joinMap.DirectoryRoot.JoinNumber, codec.SetCurrentDirectoryToRoot); + + trilist.SetSigFalseAction(joinMap.DirectoryFolderBack.JoinNumber, codec.GetDirectoryParentFolderContents); + + codec.DirectoryResultReturned += (sender, args) => + { + trilist.SetUshort(joinMap.DirectoryRowCount.JoinNumber, (ushort)args.Directory.CurrentDirectoryResults.Count); + + var clearBytes = XSigHelpers.ClearOutputs(); + + trilist.SetString(joinMap.DirectoryEntries.JoinNumber, + Encoding.GetEncoding(XSigEncoding).GetString(clearBytes, 0, clearBytes.Length)); + var directoryXSig = UpdateDirectoryXSig(args.Directory, !codec.CurrentDirectoryResultIsNotDirectoryRoot.BoolValue); + + trilist.SetString(joinMap.DirectoryEntries.JoinNumber, directoryXSig); + }; + } + + private void SelectDirectoryEntry(IHasDirectory codec, ushort i) + { + var entry = codec.CurrentDirectoryResult.CurrentDirectoryResults[i - 1]; + + if (entry is DirectoryFolder) + { + codec.GetDirectoryFolderContents(entry.FolderId); + return; + } + + var dialableEntry = entry as IInvitableContact; + + if (dialableEntry != null) + { + Dial(dialableEntry); + return; + } + + var entryToDial = entry as DirectoryContact; + + if (entryToDial == null) return; + + Dial(entryToDial.ContactMethods[0].Number); + } + + private string UpdateDirectoryXSig(CodecDirectory directory, bool isRoot) + { + var contactIndex = 1; + var tokenArray = new XSigToken[directory.CurrentDirectoryResults.Count]; + + foreach (var entry in directory.CurrentDirectoryResults) + { + var arrayIndex = contactIndex - 1; + + if (entry is DirectoryFolder && entry.ParentFolderId == "root") + { + tokenArray[arrayIndex] = new XSigSerialToken(contactIndex, String.Format("[+] {0}", entry.Name)); + + contactIndex++; + + continue; + } + + if (isRoot && String.IsNullOrEmpty(entry.FolderId)) continue; + + tokenArray[arrayIndex] = new XSigSerialToken(contactIndex, entry.Name); + + contactIndex++; + } + + return GetXSigString(tokenArray); + } + + private void LinkVideoCodecCallControlsToApi(BasicTriList trilist, VideoCodecControllerJoinMap joinMap) + { + trilist.SetSigFalseAction(joinMap.ManualDial.JoinNumber, + () => Dial(trilist.StringOutput[joinMap.CurrentDialString.JoinNumber].StringValue)); + + //End All calls for now + trilist.SetSigFalseAction(joinMap.EndCall.JoinNumber, EndAllCalls); + + trilist.SetBool(joinMap.HookState.JoinNumber, IsInCall); + + CallStatusChange += (sender, args) => + { + trilist.SetBool(joinMap.HookState.JoinNumber, IsInCall); + + Debug.Console(1, this, "Call Direction: {0}", args.CallItem.Direction); + Debug.Console(1, this, "Call is incoming: {0}", args.CallItem.Direction == eCodecCallDirection.Incoming); + trilist.SetBool(joinMap.IncomingCall.JoinNumber, args.CallItem.Direction == eCodecCallDirection.Incoming && args.CallItem.Status != eCodecCallStatus.Disconnected); + + if (args.CallItem.Direction == eCodecCallDirection.Incoming) + { + trilist.SetSigFalseAction(joinMap.IncomingAnswer.JoinNumber, () => AcceptCall(args.CallItem)); + trilist.SetSigFalseAction(joinMap.IncomingReject.JoinNumber, () => RejectCall(args.CallItem)); + } + + trilist.SetString(joinMap.CurrentCallData.JoinNumber, UpdateCallStatusXSig()); + }; + } + + private string UpdateCallStatusXSig() + { + const int maxCalls = 8; + const int maxStrings = 5; + const int offset = 6; + var stringIndex = 0; + var digitalIndex = maxStrings * maxCalls; + var arrayIndex = 0; + + var tokenArray = new XSigToken[maxCalls * offset]; //set array size for number of calls * pieces of info + + foreach (var call in ActiveCalls) + { + if (arrayIndex >= maxCalls * offset) + break; + //digitals + tokenArray[arrayIndex] = new XSigDigitalToken(digitalIndex + 1, call.IsActiveCall); + + //serials + tokenArray[arrayIndex + 1] = new XSigSerialToken(stringIndex + 1, call.Name ?? String.Empty); + tokenArray[arrayIndex + 2] = new XSigSerialToken(stringIndex + 2, call.Number ?? String.Empty); + tokenArray[arrayIndex + 3] = new XSigSerialToken(stringIndex + 3, call.Direction.ToString()); + tokenArray[arrayIndex + 4] = new XSigSerialToken(stringIndex + 4, call.Type.ToString()); + tokenArray[arrayIndex + 5] = new XSigSerialToken(stringIndex + 5, call.Status.ToString()); + + arrayIndex += offset; + stringIndex += maxStrings; + digitalIndex++; + } + while (digitalIndex < maxCalls) + { + //digitals + tokenArray[arrayIndex] = new XSigDigitalToken(digitalIndex + 1, false); + + //serials + tokenArray[arrayIndex + 1] = new XSigSerialToken(stringIndex + 1, String.Empty); + tokenArray[arrayIndex + 2] = new XSigSerialToken(stringIndex + 2, String.Empty); + tokenArray[arrayIndex + 3] = new XSigSerialToken(stringIndex + 3, String.Empty); + tokenArray[arrayIndex + 4] = new XSigSerialToken(stringIndex + 4, String.Empty); + tokenArray[arrayIndex + 5] = new XSigSerialToken(stringIndex + 5, String.Empty); + + arrayIndex += offset; + stringIndex += maxStrings; + digitalIndex++; + } + + return GetXSigString(tokenArray); + } + + private void LinkVideoCodecDtmfToApi(BasicTriList trilist, VideoCodecControllerJoinMap joinMap) + { + trilist.SetSigFalseAction(joinMap.Dtmf0.JoinNumber, () => SendDtmf("0")); + trilist.SetSigFalseAction(joinMap.Dtmf1.JoinNumber, () => SendDtmf("1")); + trilist.SetSigFalseAction(joinMap.Dtmf2.JoinNumber, () => SendDtmf("2")); + trilist.SetSigFalseAction(joinMap.Dtmf3.JoinNumber, () => SendDtmf("3")); + trilist.SetSigFalseAction(joinMap.Dtmf4.JoinNumber, () => SendDtmf("4")); + trilist.SetSigFalseAction(joinMap.Dtmf5.JoinNumber, () => SendDtmf("5")); + trilist.SetSigFalseAction(joinMap.Dtmf6.JoinNumber, () => SendDtmf("6")); + trilist.SetSigFalseAction(joinMap.Dtmf7.JoinNumber, () => SendDtmf("7")); + trilist.SetSigFalseAction(joinMap.Dtmf8.JoinNumber, () => SendDtmf("8")); + trilist.SetSigFalseAction(joinMap.Dtmf9.JoinNumber, () => SendDtmf("9")); + trilist.SetSigFalseAction(joinMap.DtmfStar.JoinNumber, () => SendDtmf("*")); + trilist.SetSigFalseAction(joinMap.DtmfPound.JoinNumber, () => SendDtmf("#")); + } + + private void LinkVideoCodecCameraLayoutsToApi(IHasCodecLayouts codec, BasicTriList trilist, VideoCodecControllerJoinMap joinMap) + { + trilist.SetSigFalseAction(joinMap.CameraLayout.JoinNumber, codec.LocalLayoutToggle); + + codec.LocalLayoutFeedback.LinkInputSig(trilist.StringInput[joinMap.CameraLayoutStringFb.JoinNumber]); + } + + private void LinkVideoCodecCameraModeToApi(IHasCameraAutoMode codec, BasicTriList trilist, VideoCodecControllerJoinMap joinMap) + { + trilist.SetSigFalseAction(joinMap.CameraModeAuto.JoinNumber, codec.CameraAutoModeOn); + trilist.SetSigFalseAction(joinMap.CameraModeManual.JoinNumber, codec.CameraAutoModeOff); + + codec.CameraAutoModeIsOnFeedback.OutputChange += (o, a) => + { + var offCodec = codec as IHasCameraOff; + + if (offCodec != null) + { + if (offCodec.CameraIsOffFeedback.BoolValue) + { + trilist.SetBool(joinMap.CameraModeAuto.JoinNumber, false); + trilist.SetBool(joinMap.CameraModeManual.JoinNumber, false); + trilist.SetBool(joinMap.CameraModeOff.JoinNumber, true); + return; + } + + trilist.SetBool(joinMap.CameraModeAuto.JoinNumber, a.BoolValue); + trilist.SetBool(joinMap.CameraModeManual.JoinNumber, !a.BoolValue); + trilist.SetBool(joinMap.CameraModeOff.JoinNumber, false); + return; + } + + trilist.SetBool(joinMap.CameraModeAuto.JoinNumber, a.BoolValue); + trilist.SetBool(joinMap.CameraModeManual.JoinNumber, !a.BoolValue); + trilist.SetBool(joinMap.CameraModeOff.JoinNumber, false); + }; + + var offModeCodec = codec as IHasCameraOff; + + if (offModeCodec != null) + { + if (offModeCodec.CameraIsOffFeedback.BoolValue) + { + trilist.SetBool(joinMap.CameraModeAuto.JoinNumber, false); + trilist.SetBool(joinMap.CameraModeManual.JoinNumber, false); + trilist.SetBool(joinMap.CameraModeOff.JoinNumber, true); + return; + } + + trilist.SetBool(joinMap.CameraModeAuto.JoinNumber, codec.CameraAutoModeIsOnFeedback.BoolValue); + trilist.SetBool(joinMap.CameraModeManual.JoinNumber, !codec.CameraAutoModeIsOnFeedback.BoolValue); + trilist.SetBool(joinMap.CameraModeOff.JoinNumber, false); + return; + } + + trilist.SetBool(joinMap.CameraModeAuto.JoinNumber, codec.CameraAutoModeIsOnFeedback.BoolValue); + trilist.SetBool(joinMap.CameraModeManual.JoinNumber, !codec.CameraAutoModeIsOnFeedback.BoolValue); + trilist.SetBool(joinMap.CameraModeOff.JoinNumber, false); + } + + private void LinkVideoCodecSelfviewToApi(IHasCodecSelfView codec, BasicTriList trilist, + VideoCodecControllerJoinMap joinMap) + { + trilist.SetSigFalseAction(joinMap.CameraSelfView.JoinNumber, codec.SelfViewModeToggle); + + codec.SelfviewIsOnFeedback.LinkInputSig(trilist.BooleanInput[joinMap.CameraSelfView.JoinNumber]); + } + + private void LinkVideoCodecCameraToApi(IHasCodecCameras codec, BasicTriList trilist, VideoCodecControllerJoinMap joinMap) + { + //Camera PTZ + trilist.SetBoolSigAction(joinMap.CameraTiltUp.JoinNumber, (b) => + { + if (codec.SelectedCamera == null) return; + var camera = codec.SelectedCamera as IHasCameraPtzControl; + + if (camera == null) return; + + if (b) camera.TiltUp(); + else camera.TiltStop(); + }); + + trilist.SetBoolSigAction(joinMap.CameraTiltDown.JoinNumber, (b) => + { + if (codec.SelectedCamera == null) return; + var camera = codec.SelectedCamera as IHasCameraPtzControl; + + if (camera == null) return; + + if (b) camera.TiltDown(); + else camera.TiltStop(); + }); + trilist.SetBoolSigAction(joinMap.CameraPanLeft.JoinNumber, (b) => + { + if (codec.SelectedCamera == null) return; + var camera = codec.SelectedCamera as IHasCameraPtzControl; + + if (camera == null) return; + + if (b) camera.PanLeft(); + else camera.PanStop(); + }); + trilist.SetBoolSigAction(joinMap.CameraPanRight.JoinNumber, (b) => + { + if (codec.SelectedCamera == null) return; + var camera = codec.SelectedCamera as IHasCameraPtzControl; + + if (camera == null) return; + + if (b) camera.PanRight(); + else camera.PanStop(); + }); + + trilist.SetBoolSigAction(joinMap.CameraZoomIn.JoinNumber, (b) => + { + if (codec.SelectedCamera == null) return; + var camera = codec.SelectedCamera as IHasCameraPtzControl; + + if (camera == null) return; + + if (b) camera.ZoomIn(); + else camera.ZoomStop(); + }); + + trilist.SetBoolSigAction(joinMap.CameraZoomOut.JoinNumber, (b) => + { + if (codec.SelectedCamera == null) return; + var camera = codec.SelectedCamera as IHasCameraPtzControl; + + if (camera == null) return; + + if (b) camera.ZoomOut(); + else camera.ZoomStop(); + }); + + //Camera Select + trilist.SetUShortSigAction(joinMap.CameraNumberSelect.JoinNumber, (i) => + { + if (codec.SelectedCamera == null) return; + + codec.SelectCamera(codec.Cameras[i].Key); + }); + + codec.CameraSelected += (sender, args) => + { + var i = (ushort)codec.Cameras.FindIndex((c) => c.Key == args.SelectedCamera.Key); + + if (codec is IHasCodecRoomPresets) + { + return; + } + + if (!(args.SelectedCamera is IHasCameraPresets)) + { + return; + } + + var cam = args.SelectedCamera as IHasCameraPresets; + SetCameraPresetNames(cam.Presets); + + (args.SelectedCamera as IHasCameraPresets).PresetsListHasChanged += (o, eventArgs) => SetCameraPresetNames(cam.Presets); + + trilist.SetUShortSigAction(joinMap.CameraPresetSelect.JoinNumber, + (a) => + { + cam.PresetSelect(a); + trilist.SetUshort(joinMap.CameraPresetSelect.JoinNumber, a); + }); + + trilist.SetSigFalseAction(joinMap.CameraPresetSave.JoinNumber, + () => + { + cam.PresetStore(trilist.UShortOutput[joinMap.CameraPresetSelect.JoinNumber].UShortValue, + String.Empty); + trilist.PulseBool(joinMap.CameraPresetSave.JoinNumber, 3000); + }); + }; + + if (!(codec is IHasCodecRoomPresets)) return; + + var presetCodec = codec as IHasCodecRoomPresets; + + presetCodec.CodecRoomPresetsListHasChanged += + (sender, args) => SetCameraPresetNames(presetCodec.NearEndPresets); + + //Camera Presets + trilist.SetUShortSigAction(joinMap.CameraPresetSelect.JoinNumber, (i) => + { + presetCodec.CodecRoomPresetSelect(i); + + trilist.SetUshort(joinMap.CameraPresetSelect.JoinNumber, i); + }); + + trilist.SetSigFalseAction(joinMap.CameraPresetSave.JoinNumber, + () => + { + presetCodec.CodecRoomPresetStore( + trilist.UShortOutput[joinMap.CameraPresetSelect.JoinNumber].UShortValue, String.Empty); + trilist.PulseBool(joinMap.CameraPresetSave.JoinNumber, 3000); + }); + } + + private string SetCameraPresetNames(IEnumerable presets) + { + return SetCameraPresetNames(presets.Select(p => p.Description).ToList()); + } + + private string SetCameraPresetNames(IEnumerable presets) + { + return SetCameraPresetNames(presets.Select(p => p.Description).ToList()); + } + + private string SetCameraPresetNames(ICollection presets) + { + var i = 1; //start index for xsig; + + var tokenArray = new XSigToken[presets.Count]; + + foreach (var preset in presets) + { + var cameraPreset = new XSigSerialToken(i, preset); + tokenArray[i - 1] = cameraPreset; + i++; + } + + return GetXSigString(tokenArray); + } + + private string GetXSigString(XSigToken[] tokenArray) + { + string returnString; + using (var s = new MemoryStream()) + { + using (var tw = new XSigTokenStreamWriter(s, true)) + { + tw.WriteXSigData(tokenArray); + } + + var xSig = s.ToArray(); + + returnString = Encoding.GetEncoding(XSigEncoding).GetString(xSig, 0, xSig.Length); + } + + return returnString; + } + + #endregion + } + + + /// + /// Used to track the status of syncronizing the phonebook values when connecting to a codec or refreshing the phonebook info + /// + public class CodecPhonebookSyncState : IKeyed + { + private bool _InitialSyncComplete; + + public CodecPhonebookSyncState(string key) + { + Key = key; + + CodecDisconnected(); + } + + public bool InitialSyncComplete + { + get { return _InitialSyncComplete; } + private set + { + if (value == true) + { + var handler = InitialSyncCompleted; + if (handler != null) + { + handler(this, new EventArgs()); + } + } + _InitialSyncComplete = value; + } + } + + public bool InitialPhonebookFoldersWasReceived { get; private set; } + + public bool NumberOfContactsWasReceived { get; private set; } + + public bool PhonebookRootEntriesWasRecieved { get; private set; } + + public bool PhonebookHasFolders { get; private set; } + + public int NumberOfContacts { get; private set; } + + #region IKeyed Members + + public string Key { get; private set; } + + #endregion + + public event EventHandler InitialSyncCompleted; + + public void InitialPhonebookFoldersReceived() + { + InitialPhonebookFoldersWasReceived = true; + + CheckSyncStatus(); + } + + public void PhonebookRootEntriesReceived() + { + PhonebookRootEntriesWasRecieved = true; + + CheckSyncStatus(); + } + + public void SetPhonebookHasFolders(bool value) + { + PhonebookHasFolders = value; + + Debug.Console(1, this, "Phonebook has folders: {0}", PhonebookHasFolders); + } + + public void SetNumberOfContacts(int contacts) + { + NumberOfContacts = contacts; + NumberOfContactsWasReceived = true; + + Debug.Console(1, this, "Phonebook contains {0} contacts.", NumberOfContacts); + + CheckSyncStatus(); + } + + public void CodecDisconnected() + { + InitialPhonebookFoldersWasReceived = false; + PhonebookHasFolders = false; + NumberOfContacts = 0; + NumberOfContactsWasReceived = false; + } + + private void CheckSyncStatus() + { + if (InitialPhonebookFoldersWasReceived && NumberOfContactsWasReceived && PhonebookRootEntriesWasRecieved) + { + InitialSyncComplete = true; + Debug.Console(1, this, "Initial Phonebook Sync Complete!"); + } + else + { + InitialSyncComplete = false; + } + } + } } \ No newline at end of file diff --git a/essentials-framework/Essentials Devices Common/Essentials Devices Common/VideoCodec/ZoomRoom/ZoomRoom.cs b/essentials-framework/Essentials Devices Common/Essentials Devices Common/VideoCodec/ZoomRoom/ZoomRoom.cs index fc440e5b..980c7a61 100644 --- a/essentials-framework/Essentials Devices Common/Essentials Devices Common/VideoCodec/ZoomRoom/ZoomRoom.cs +++ b/essentials-framework/Essentials Devices Common/Essentials Devices Common/VideoCodec/ZoomRoom/ZoomRoom.cs @@ -1655,6 +1655,7 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.ZoomRoom public override void Dial(Meeting meeting) { + Debug.Console(1, this,"Dialing meeting.Id: {0} Title: {1}", meeting.Id, meeting.Title); SendText(string.Format("zCommand Dial Start meetingNumber: {0}", meeting.Id)); }