diff --git a/Essentials Core/PepperDashEssentialsBase/Touchpanels/TriListExtensions.cs b/Essentials Core/PepperDashEssentialsBase/Touchpanels/TriListExtensions.cs index be666c5f..15287a64 100644 --- a/Essentials Core/PepperDashEssentialsBase/Touchpanels/TriListExtensions.cs +++ b/Essentials Core/PepperDashEssentialsBase/Touchpanels/TriListExtensions.cs @@ -162,6 +162,14 @@ namespace PepperDash.Essentials.Core tl.BooleanInput[sigNum].BoolValue = value; } + /// + /// Helper method to set the value of a ushort Sig on TriList + /// + public static void SetUshort(this BasicTriList tl, uint sigNum, ushort value) + { + tl.UShortInput[sigNum].UShortValue = value; + } + /// /// Helper method to set the value of a string Sig on TriList /// diff --git a/Essentials Devices Common/Essentials Devices Common/Codec/CodecActiveCallItem.cs b/Essentials Devices Common/Essentials Devices Common/Codec/CodecActiveCallItem.cs index b85b2089..8cded7f6 100644 --- a/Essentials Devices Common/Essentials Devices Common/Codec/CodecActiveCallItem.cs +++ b/Essentials Devices Common/Essentials Devices Common/Codec/CodecActiveCallItem.cs @@ -1,27 +1,38 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using Crestron.SimplSharp; - -namespace PepperDash.Essentials.Devices.Common.Codec - -{ - public class CodecActiveCallItem - { - public string Name { get; set; } - - public string Number { get; set; } - - public eCodecCallType Type { get; set; } - - public eCodecCallStatus Status { get; set; } - - public eCodecCallDirection Direction { get; set; } - - public string Id { get; set; } - - public object CallMetaData { get; set; } - } - +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using Crestron.SimplSharp; + +namespace PepperDash.Essentials.Devices.Common.Codec + +{ + public class CodecActiveCallItem + { + public string Name { get; set; } + + public string Number { get; set; } + + public eCodecCallType Type { get; set; } + + public eCodecCallStatus Status { get; set; } + + public string Id { get; set; } + + public object CallMetaData { get; set; } + + /// + /// Returns true when this call is any status other than + /// Unknown, Disconnected, Disconnecting + /// + public bool IsActiveCall + { + get + { + return !(Status == eCodecCallStatus.Disconnected + || Status == eCodecCallStatus.Disconnecting + || Status == eCodecCallStatus.Unknown); + } + } + } } \ No newline at end of file diff --git a/Essentials Devices Common/Essentials Devices Common/Codec/eCodecCallStatus.cs b/Essentials Devices Common/Essentials Devices Common/Codec/eCodecCallStatus.cs index c73fabe5..a6aa2bf7 100644 --- a/Essentials Devices Common/Essentials Devices Common/Codec/eCodecCallStatus.cs +++ b/Essentials Devices Common/Essentials Devices Common/Codec/eCodecCallStatus.cs @@ -5,88 +5,21 @@ using System.Text; using Crestron.SimplSharp; namespace PepperDash.Essentials.Devices.Common.Codec - { public enum eCodecCallStatus - { - Unknown = 0, - Idle, - Dialing, - Ringing, - Connecting, - Connected, - Disconnecting, - Incoming, - OnHold, - EarlyMedia, - Preserved, - RemotePreserved, - Disconnected - } - - public class CodecCallStatus - { - - /// - /// Takes the Cisco status and converts to the matching enum - /// - /// - /// - public static eCodecCallStatus ConvertToStatusEnum(string s) - { - switch (s) - { - case "Idle": - { - return eCodecCallStatus.Idle; - } - case "Dialling": - { - return eCodecCallStatus.Dialing; - } - case "Ringing": - { - return eCodecCallStatus.Ringing; - } - case "Connecting": - { - return eCodecCallStatus.Connecting; - } - case "Connected": - { - return eCodecCallStatus.Connected; - } - case "Disconnecting": - { - return eCodecCallStatus.Disconnecting; - } - case "Incoming": - { - return eCodecCallStatus.Incoming; - } - case "OnHold": - { - return eCodecCallStatus.OnHold; - } - case "EarlyMedia": - { - return eCodecCallStatus.EarlyMedia; - } - case "Preserved": - { - return eCodecCallStatus.Preserved; - } - case "RemotePreserved": - { - return eCodecCallStatus.RemotePreserved; - } - case "Disconnected": - { - return eCodecCallStatus.Disconnected; - } - default: - return eCodecCallStatus.Unknown; - } - } + { + Unknown = 0, + Connected, + Connecting, + Dialing, + Disconnected, + Disconnecting, + EarlyMedia, + Idle, + Incoming, + OnHold, + Ringing, + Preserved, + RemotePreserved, } } \ No newline at end of file diff --git a/Essentials Devices Common/Essentials Devices Common/Codec/iHasDialer.cs b/Essentials Devices Common/Essentials Devices Common/Codec/iHasDialer.cs index 9ec7ba71..4826adf6 100644 --- a/Essentials Devices Common/Essentials Devices Common/Codec/iHasDialer.cs +++ b/Essentials Devices Common/Essentials Devices Common/Codec/iHasDialer.cs @@ -22,7 +22,6 @@ namespace PepperDash.Essentials.Devices.Common.Codec void RejectCall(CodecActiveCallItem item); void SendDtmf(string digit); - IntFeedback ActiveCallCountFeedback { get; } BoolFeedback IncomingCallFeedback { get; } } diff --git a/Essentials Devices Common/Essentials Devices Common/VideoCodec/MockVC/MockVC.cs b/Essentials Devices Common/Essentials Devices Common/VideoCodec/MockVC/MockVC.cs index 53e5e2f1..ed2bc949 100644 --- a/Essentials Devices Common/Essentials Devices Common/VideoCodec/MockVC/MockVC.cs +++ b/Essentials Devices Common/Essentials Devices Common/VideoCodec/MockVC/MockVC.cs @@ -17,7 +17,7 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec : base(key, name) { // Debug helpers - ActiveCallCountFeedback.OutputChange += (o, a) => Debug.Console(1, this, "InCall={0}", ActiveCallCountFeedback.IntValue); + //ActiveCallCountFeedback.OutputChange += (o, a) => Debug.Console(1, this, "InCall={0}", ActiveCallCountFeedback.IntValue); IncomingCallFeedback.OutputChange += (o, a) => Debug.Console(1, this, "IncomingCall={0}", _IncomingCall); MuteFeedback.OutputChange += (o, a) => Debug.Console(1, this, "Mute={0}", _IsMuted); PrivacyModeIsOnFeedback.OutputChange += (o, a) => Debug.Console(1, this, "Privacy={0}", _PrivacyModeIsOn); @@ -25,11 +25,6 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec VolumeLevelFeedback.OutputChange += (o, a) => Debug.Console(1, this, "Volume={0}", _VolumeLevel); } - protected override Func ActiveCallCountFeedbackFunc - { - get { return () => ActiveCalls.Count; } - } - protected override Func IncomingCallFeedbackFunc { get { return () => _IncomingCall; } @@ -69,7 +64,7 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec var call = new CodecActiveCallItem() { Name = s, Number = s, Id = s, Status = eCodecCallStatus.Dialing }; ActiveCalls.Add(call); OnCallStatusChange(eCodecCallStatus.Unknown, call.Status, call); - ActiveCallCountFeedback.FireUpdate(); + //ActiveCallCountFeedback.FireUpdate(); // Simulate 2-second ring, then connecting, then connected new CTimer(o => { @@ -86,9 +81,8 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec { Debug.Console(1, this, "EndCall"); ActiveCalls.Remove(call); - SetNewCallStatusAndFireCallStatusChange(eCodecCallStatus.Disconnected, call); - ActiveCallCountFeedback.FireUpdate(); + //ActiveCallCountFeedback.FireUpdate(); } /// @@ -102,7 +96,7 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec ActiveCalls.Remove(call); SetNewCallStatusAndFireCallStatusChange(eCodecCallStatus.Disconnected, call); } - ActiveCallCountFeedback.FireUpdate(); + //ActiveCallCountFeedback.FireUpdate(); } /// @@ -122,6 +116,9 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec public override void RejectCall(CodecActiveCallItem call) { Debug.Console(1, this, "RejectCall"); + ActiveCalls.Remove(call); + SetNewCallStatusAndFireCallStatusChange(eCodecCallStatus.Disconnected, call); + //ActiveCallCountFeedback.FireUpdate(); } /// @@ -259,7 +256,6 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec SetNewCallStatusAndFireCallStatusChange(eCodecCallStatus.Incoming, call); _IncomingCall = true; IncomingCallFeedback.FireUpdate(); - ActiveCallCountFeedback.FireUpdate(); } /// @@ -274,7 +270,6 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec SetNewCallStatusAndFireCallStatusChange(eCodecCallStatus.Incoming, call); _IncomingCall = true; IncomingCallFeedback.FireUpdate(); - ActiveCallCountFeedback.FireUpdate(); } /// @@ -286,17 +281,6 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec } - /// - /// - /// - public void ListCalls() - { - var sb = new StringBuilder(); - foreach (var c in ActiveCalls) - sb.AppendFormat("{0} {1} -- {2}\r", c.Id, c.Number, c.Name); - Debug.Console(1, "{0}", sb.ToString()); - } - #region IRoutingOutputs Members public RoutingPortCollection OutputPorts diff --git a/Essentials Devices Common/Essentials Devices Common/VideoCodec/VideoCodecBase.cs b/Essentials Devices Common/Essentials Devices Common/VideoCodec/VideoCodecBase.cs index 304fe1d8..a97e4ee0 100644 --- a/Essentials Devices Common/Essentials Devices Common/VideoCodec/VideoCodecBase.cs +++ b/Essentials Devices Common/Essentials Devices Common/VideoCodec/VideoCodecBase.cs @@ -35,24 +35,15 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec #endregion /// - /// Returns whether any call in ActiveCalls is actually "active" - /// - public bool IsInCall - { - get - { - return ActiveCalls.Any(c => - !(c.Status == eCodecCallStatus.Unknown - || c.Status == eCodecCallStatus.Disconnected - || c.Status == eCodecCallStatus.Disconnecting)); - } - } + /// Returns true when any call is not in state Unknown, Disconnecting, Disconnected + /// + public bool IsInCall { get { return ActiveCalls.Any(c => c.IsActiveCall); } } public BoolFeedback IncomingCallFeedback { get; private set; } - public IntFeedback ActiveCallCountFeedback { get; private set; } + //public IntFeedback ActiveCallCountFeedback { get; private set; } - abstract protected Func ActiveCallCountFeedbackFunc { get; } + //abstract protected Func ActiveCallCountFeedbackFunc { get; } abstract protected Func IncomingCallFeedbackFunc { get; } abstract protected Func PrivacyModeIsOnFeedbackFunc { get; } abstract protected Func VolumeLevelFeedbackFunc { get; } @@ -64,7 +55,6 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec public VideoCodecBase(string key, string name) : base(key, name) { - ActiveCallCountFeedback = new IntFeedback(ActiveCallCountFeedbackFunc); IncomingCallFeedback = new BoolFeedback(IncomingCallFeedbackFunc); PrivacyModeIsOnFeedback = new BoolFeedback(PrivacyModeIsOnFeedbackFunc); VolumeLevelFeedback = new IntFeedback(VolumeLevelFeedbackFunc); @@ -73,26 +63,9 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec InputPorts = new RoutingPortCollection(); - ActiveCallCountFeedback.OutputChange += new EventHandler(ActiveCallCountFeedback_OutputChange); - ActiveCalls = new List(); } - /// - /// - /// - /// - /// - void ActiveCallCountFeedback_OutputChange(object sender, EventArgs e) - { - if (UsageTracker != null) - { - if (IsInCall) - UsageTracker.StartDeviceUsage(); - else - UsageTracker.EndDeviceUsage(); - } - } #region IHasDialer Members public abstract void Dial(string s); @@ -125,19 +98,18 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec protected void SetNewCallStatusAndFireCallStatusChange(eCodecCallStatus newStatus, CodecActiveCallItem call) { var prevStatus = call.Status; - call.Status = newStatus; + call.Status = newStatus; OnCallStatusChange(prevStatus, newStatus, call); } /// - /// Helper method to notify of call status change event + /// /// /// /// /// protected void OnCallStatusChange(eCodecCallStatus previousStatus, eCodecCallStatus newStatus, CodecActiveCallItem item) - { - Debug.Console(1, this, "Call Status Changed from {0} to {1} on call {2}", previousStatus, newStatus, item.Id); + { var handler = CallStatusChange; if (handler != null) handler(this, new CodecCallStatusItemChangeEventArgs(previousStatus, newStatus, item)); @@ -178,6 +150,18 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec public StringFeedback SharingSourceFeedback { get; private set; } #endregion + + // **** DEBUGGING THINGS **** + /// + /// + /// + public virtual void ListCalls() + { + var sb = new StringBuilder(); + foreach (var c in ActiveCalls) + sb.AppendFormat("{0} {1} -- {2} {3}\r", c.Id, c.Number, c.Name, c.Status); + Debug.Console(1, "{0}", sb.ToString()); + } } /// diff --git a/Essentials/PepperDashEssentials/UI/JoinConstants/UIUshortJoin.cs b/Essentials/PepperDashEssentials/UI/JoinConstants/UIUshortJoin.cs index 4f42b960..69165d8d 100644 --- a/Essentials/PepperDashEssentials/UI/JoinConstants/UIUshortJoin.cs +++ b/Essentials/PepperDashEssentials/UI/JoinConstants/UIUshortJoin.cs @@ -40,5 +40,10 @@ /// 3922 /// public const uint PresentationListCaretMode = 3922; + + /// + /// 15024 - Modes 0: On hook, 1: Phone, 2: Video + /// + public const uint CallHeaderButtonMode = 15024; } } \ No newline at end of file diff --git a/Essentials/PepperDashEssentials/UIDrivers/EssentialsHuddleVTC/HuddleVTCPanelAvFunctionsDriver.cs b/Essentials/PepperDashEssentials/UIDrivers/EssentialsHuddleVTC/HuddleVTCPanelAvFunctionsDriver.cs index b4bbcb62..b041e28f 100644 --- a/Essentials/PepperDashEssentials/UIDrivers/EssentialsHuddleVTC/HuddleVTCPanelAvFunctionsDriver.cs +++ b/Essentials/PepperDashEssentials/UIDrivers/EssentialsHuddleVTC/HuddleVTCPanelAvFunctionsDriver.cs @@ -155,6 +155,12 @@ namespace PepperDash.Essentials //PowerOffTimeout = 30000; //TriList.StringInput[UIStringJoin.StartActivityText].StringValue = "Tap an activity below"; + + // Reveal proper header buttons with/without lighting + if(false) // has lighting + TriList.SetBool(UIBoolJoin.CallLeftHeaderButtonVisible, true); + else + TriList.SetBool(UIBoolJoin.CallRightHeaderButtonVisible, true); } /// diff --git a/Essentials/PepperDashEssentials/UIDrivers/VC/EssentialsVideoCodecUiDriver.cs b/Essentials/PepperDashEssentials/UIDrivers/VC/EssentialsVideoCodecUiDriver.cs index ba8ead8f..81d40683 100644 --- a/Essentials/PepperDashEssentials/UIDrivers/VC/EssentialsVideoCodecUiDriver.cs +++ b/Essentials/PepperDashEssentials/UIDrivers/VC/EssentialsVideoCodecUiDriver.cs @@ -9,11 +9,16 @@ using PepperDash.Core; using PepperDash.Essentials; using PepperDash.Essentials.Core; using PepperDash.Essentials.Core.SmartObjects; +using PepperDash.Essentials.Devices.Common.Codec; using PepperDash.Essentials.Devices.Common.VideoCodec; namespace PepperDash.Essentials.UIDrivers.VC { + +#warning When InCall, keypad text should clear. Keypad becomes DTMF only. Delete is gone and disabled. Send keypresses immediately to SendDTMF. Queue them in disaply string. +#warning when Call ends, clear keypad text. +#warning FOR SPARK - (GFX also) we need a staging bar for in call state where there is no camera button /// /// This fella will likely need to interact with the room's source, although that is routed via the spark... /// Probably needs event or FB to feed AV driver - to show two-mute volume when appropriate. @@ -60,6 +65,8 @@ namespace PepperDash.Essentials.UIDrivers.VC StringBuilder DialStringBuilder = new StringBuilder(); BoolFeedback DialStringBackspaceVisibleFeedback; + ModalDialog IncomingCallModal; + /// /// /// @@ -72,6 +79,8 @@ namespace PepperDash.Essentials.UIDrivers.VC SetupCallStagingPopover(); SetupDialKeypad(); + codec.CallStatusChange += new EventHandler(Codec_CallStatusChange); + InCall = new BoolFeedback(() => false); LocalPrivacyIsMuted = new BoolFeedback(() => false); @@ -93,7 +102,98 @@ namespace PepperDash.Essentials.UIDrivers.VC DialStringBackspaceVisibleFeedback .LinkInputSig(TriList.BooleanInput[UIBoolJoin.KeyboardClearVisible]); - Codec.ActiveCallCountFeedback.OutputChange += new EventHandler(InCallFeedback_OutputChange); + } + + /// + /// Handles status changes for calls + /// + /// + /// + void Codec_CallStatusChange(object sender, CodecCallStatusItemChangeEventArgs e) + { + var call = e.CallItem; + Debug.Console(1, "*#* UI: Codec status {0}: {1} --> {2}", call.Name, e.PreviousStatus, e.NewStatus); + switch (e.NewStatus) + { + case eCodecCallStatus.Connected: + // fire at SRL item + Debug.Console(1, "*#* UI: Call Connected {0}", call.Name); + break; + case eCodecCallStatus.Connecting: + // fire at SRL item + Debug.Console(1, "*#* UI: Call Connecting {0}", call.Name); + break; + case eCodecCallStatus.Dialing: + Debug.Console(1, "*#* UI: Call Dialing {0}", call.Name); + break; + case eCodecCallStatus.Disconnected: + Debug.Console(1, "*#* UI: Call Disconnecting {0}", call.Name); + break; + case eCodecCallStatus.Disconnecting: + break; + case eCodecCallStatus.EarlyMedia: + break; + case eCodecCallStatus.Idle: + break; + case eCodecCallStatus.Incoming: + // fire up a modal + ShowIncomingModal(call); + break; + case eCodecCallStatus.OnHold: + break; + case eCodecCallStatus.Preserved: + break; + case eCodecCallStatus.RemotePreserved: + break; + case eCodecCallStatus.Ringing: + break; + default: + break; + } + TriList.UShortInput[UIUshortJoin.VCStagingConnectButtonMode].UShortValue = (ushort)(Codec.IsInCall ? 1 : 0); + StagingBarInterlock.ShowInterlocked(Codec.IsInCall ? + UIBoolJoin.VCStagingActivePopoverVisible : UIBoolJoin.VCStagingInactivePopoverVisible); + // Set mode of header button + if (!Codec.IsInCall) + TriList.SetUshort(UIUshortJoin.CallHeaderButtonMode, 0); + else if(Codec.ActiveCalls.Any(c => c.Type == eCodecCallType.Video)) + TriList.SetUshort(UIUshortJoin.CallHeaderButtonMode, 2); + else + TriList.SetUshort(UIUshortJoin.CallHeaderButtonMode, 1); + + // Update list of calls + var activeList = Codec.ActiveCalls.Where(c => c.IsActiveCall).ToList(); + Debug.Console(1, "*#* UI - Codec has {0} calls", activeList.Count); + + } + + /// + /// + /// + void ShowIncomingModal(CodecActiveCallItem call) + { + IncomingCallModal = new ModalDialog(TriList); + string msg; + string icon; + if (call.Type == eCodecCallType.Audio) + { + icon = "Phone"; + msg = string.Format("Incoming phone call from: {0}", call.Name); + } + else + { + icon = "Camera"; + msg = string.Format("Incoming video call from: {0}", call.Name); + } + IncomingCallModal.PresentModalDialog(2, "Incoming Call", icon, msg, + "Ignore", "Accept", false, false, b => + { + if (b == 1) + Codec.RejectCall(call); + else //2 + Codec.AcceptCall(call); + IncomingCallModal = null; + }); } /// @@ -196,28 +296,6 @@ namespace PepperDash.Essentials.UIDrivers.VC Codec.Dial(DialStringBuilder.ToString()); } - /// - /// - /// - void InCallFeedback_OutputChange(object sender, EventArgs e) - { - var inCall = Codec.IsInCall; - Debug.Console(1, "*#* Codec Driver InCallFeedback change={0}", InCall); - TriList.UShortInput[UIUshortJoin.VCStagingConnectButtonMode].UShortValue = (ushort)(inCall ? 1 : 0); - StagingBarInterlock.ShowInterlocked( - inCall ? UIBoolJoin.VCStagingActivePopoverVisible : UIBoolJoin.VCStagingInactivePopoverVisible); - - if (Codec.IsInCall) // Call is starting - { - // Header icon - // Volume bar needs to have mic mute - } - else // ending - { - // Header icon - // Volume bar no mic mute (or hidden if no source?) - } - } /// /// diff --git a/Release Package/PepperDashEssentials.cpz b/Release Package/PepperDashEssentials.cpz index 849b24fc..feb3c651 100644 Binary files a/Release Package/PepperDashEssentials.cpz and b/Release Package/PepperDashEssentials.cpz differ diff --git a/Release Package/PepperDashEssentials.dll b/Release Package/PepperDashEssentials.dll index d92b4ced..4a9581ef 100644 Binary files a/Release Package/PepperDashEssentials.dll and b/Release Package/PepperDashEssentials.dll differ diff --git a/devjson commands.json b/devjson commands.json index c1e69fc2..a8afd494 100644 --- a/devjson commands.json +++ b/devjson commands.json @@ -8,4 +8,12 @@ devjson:1 {"deviceKey":"timer","methodName":"Cancel" } devjson:1 {"deviceKey":"timer","methodName":"Reset" } -devjson:1 {"deviceKey":"room1","methodName":"Shutdown" } \ No newline at end of file +devjson:1 {"deviceKey":"room1","methodName":"Shutdown" } + +devjson:1 {"deviceKey":"mockVc-1", "methodName":"TestIncomingVideoCall", "params": ["123-456-7890"]} + +devjson:1 {"deviceKey":"mockVc-1", "methodName":"TestIncomingAudioCall", "params": ["111-111-1111"]} + +devjson:1 {"deviceKey":"mockVc-1", "methodName":"TestIncomingVideoCall", "params": ["444-444-4444"]} + +devjson:1 {"deviceKey":"mockVc-1", "methodName":"ListCalls"}