Merge remote-tracking branch 'origin/feature/ecs-407' into feature/cisco-spark-2

Conflicts:
	Essentials Devices Common/Essentials Devices Common/Codec/CodecActiveCallItem.cs
This commit is contained in:
Neil Dorin
2017-09-20 18:19:03 -06:00
17 changed files with 2458 additions and 1816 deletions

View File

@@ -1,18 +1,18 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Crestron.SimplSharp;
namespace PepperDash.Essentials.Devices.Common.VideoCodec
{
public class CodecActiveCallItem
{
public string Name { get; set; }
public string Number { 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; }
@@ -21,21 +21,7 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec
public string Id { get; set; }
public object CallMetaData { get; set; }
}
public enum eCodecCallType
{
Unknown = 0, Audio, Video, AudioCanEscalate, ForwardAllCall
public object CallMetaData { get; set; }
}
public enum eCodecCallStatus
{
Unknown = 0, Idle, Dialing, Ringing, Connecting, Connected, Disconnecting, Incoming, OnHold, EarlyMedia, Preserved, RemotePreserved, Disconnected
}
public enum eCodecCallDirection
{
Unknown = 0, Incoming, Outgoing
}
}

View File

@@ -0,0 +1,50 @@
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; }
<<<<<<< HEAD:Essentials Devices Common/Essentials Devices Common/Codec/CodecActiveCallItem.cs
public eCodecCallType Type { get; set; }
public eCodecCallStatus Status { get; set; }
public string Id { get; set; }
=======
public eCodecCallType Type { get; set; }
public eCodecCallStatus Status { get; set; }
public string Id { get; set; }
public object CallMetaData { get; set; }
>>>>>>> origin/feature/cisco-spark-2:Essentials Devices Common/Essentials Devices Common/VideoCodec/CodecActiveCallItem.cs
}
public enum eCodecCallType
{
Unknown = 0, Audio, Video
<<<<<<< HEAD:Essentials Devices Common/Essentials Devices Common/Codec/CodecActiveCallItem.cs
}
public enum eCodecCallStatus
{
Unknown = 0, Dialing, Connected, Incoming, OnHold, Disconnected
=======
}
public enum eCodecCallStatus
{
Unknown = 0, Dialing, Connected, Incoming, OnHold, Disconnected
>>>>>>> origin/feature/cisco-spark-2:Essentials Devices Common/Essentials Devices Common/VideoCodec/CodecActiveCallItem.cs
}
}

View File

@@ -0,0 +1,14 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Crestron.SimplSharp;
namespace PepperDash.Essentials.Devices.Common.Codec
{
public enum eCodecCallDirection
{
Unknown = 0, Incoming, Outgoing
}
}

View File

@@ -0,0 +1,92 @@
using System;
using System.Collections.Generic;
using System.Linq;
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
{
/// <summary>
/// Takes the Cisco status and converts to the matching enum
/// </summary>
/// <param name="s"></param>
/// <returns></returns>
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;
}
}
}
}

View File

@@ -0,0 +1,54 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Crestron.SimplSharp;
namespace PepperDash.Essentials.Devices.Common.Codec
{
public enum eCodecCallType
{
Unknown = 0,
Audio,
Video,
AudioCanEscalate,
ForwardAllCall
}
public class CodecCallType
{
/// <summary>
/// Takes the Cisco call type and converts to the matching enum
/// </summary>
/// <param name="s"></param>
/// <returns></returns>
public static eCodecCallType ConvertToTypeEnum(string s)
{
switch (s)
{
case "Audio":
{
return eCodecCallType.Audio;
}
case "Video":
{
return eCodecCallType.Video;
}
case "AudioCanEscalate":
{
return eCodecCallType.AudioCanEscalate;
}
case "ForwardAllCall":
{
return eCodecCallType.ForwardAllCall;
}
default:
return eCodecCallType.Unknown;
}
}
}
}

View File

@@ -0,0 +1,184 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Crestron.SimplSharp;
namespace PepperDash.Essentials.Devices.Common.Codec
{
public interface IHasCallHistory
{
List<CallHistory.CallHistoryEntry> RecentCalls { get; }
void RemoveEntry(CallHistory.CallHistoryEntry entry);
}
public enum eCodecOccurrenctType
{
Unknown = 0,
Placed,
Received,
NoAnswer
}
public class CallHistory
{
/// <summary>
/// Generic call history entry, not device specific
/// </summary>
public class CallHistoryEntry
{
public string DisplayName { get; set; }
public string CallBackNumber { get; set; }
public DateTime StartTime { get; set; }
public eCodecOccurrenctType OccurenceType { get; set; }
public string OccurrenceHistoryId { get; set; }
}
/// <summary>
/// Converts a list of call history entries returned by a Cisco codec to the generic list type
/// </summary>
/// <param name="entries"></param>
/// <returns></returns>
public static List<CallHistoryEntry> ConvertCiscoCallHistoryToGeneric(List<CiscoCallHistory.Entry> entries)
{
var genericEntries = new List<CallHistoryEntry>();
foreach (CiscoCallHistory.Entry entry in entries)
{
genericEntries.Add(new CallHistoryEntry()
{
DisplayName = entry.DisplayName.Value,
CallBackNumber = entry.CallbackNumber.Value,
StartTime = entry.LastOccurrenceStartTime.Value,
OccurrenceHistoryId = entry.LastOccurrenceHistoryId.Value,
OccurenceType = ConvertToOccurenceTypeEnum(entry.OccurrenceType.Value)
});
}
return genericEntries;
}
/// <summary>
/// Takes the Cisco occurence type and converts it to the matching enum
/// </summary>
/// <param name="s"></para
public static eCodecOccurrenctType ConvertToOccurenceTypeEnum(string s)
{
switch (s)
{
case "Placed":
{
return eCodecOccurrenctType.Placed;
}
case "Received":
{
return eCodecOccurrenctType.Received;
}
case "NoAnswer":
{
return eCodecOccurrenctType.NoAnswer;
}
default:
return eCodecOccurrenctType.Unknown;
}
}
}
public class CiscoCallHistory
{
public class CallbackNumber
{
public string Value { get; set; }
}
public class DisplayName
{
public string Value { get; set; }
}
public class LastOccurrenceStartTime
{
public DateTime Value { get; set; }
}
public class LastOccurrenceDaysAgo
{
public string Value { get; set; }
}
public class LastOccurrenceHistoryId
{
public string Value { get; set; }
}
public class OccurrenceType
{
public string Value { get; set; }
}
public class IsAcknowledged
{
public string Value { get; set; }
}
public class OccurrenceCount
{
public string Value { get; set; }
}
public class Entry
{
public string id { get; set; }
public CallbackNumber CallbackNumber { get; set; }
public DisplayName DisplayName { get; set; }
public LastOccurrenceStartTime LastOccurrenceStartTime { get; set; }
public LastOccurrenceDaysAgo LastOccurrenceDaysAgo { get; set; }
public LastOccurrenceHistoryId LastOccurrenceHistoryId { get; set; }
public OccurrenceType OccurrenceType { get; set; }
public IsAcknowledged IsAcknowledged { get; set; }
public OccurrenceCount OccurrenceCount { get; set; }
}
public class Offset
{
public string Value { get; set; }
}
public class Limit
{
public string Value { get; set; }
}
public class ResultInfo
{
public Offset Offset { get; set; }
public Limit Limit { get; set; }
}
public class CallHistoryRecentsResult
{
public string status { get; set; }
public List<Entry> Entry { get; set; }
public ResultInfo ResultInfo { get; set; }
}
public class CommandResponse
{
public CallHistoryRecentsResult CallHistoryRecentsResult { get; set; }
}
public class RootObject
{
public CommandResponse CommandResponse { get; set; }
}
}
}

View File

@@ -24,5 +24,17 @@ namespace PepperDash.Essentials.Devices.Common.Codec
IntFeedback ActiveCallCountFeedback { get; }
BoolFeedback IncomingCallFeedback { get; }
}
public interface IHasDirectory
{
}
public interface IHasObtp
{
// Upcoming Meeting warning event
}
}

View File

@@ -103,7 +103,11 @@
<Reference Include="System.Data" />
</ItemGroup>
<ItemGroup>
<Compile Include="Codec\eCodecCallDirection.cs" />
<Compile Include="Codec\eCodecCallType.cs" />
<Compile Include="Codec\eCodecCallStatus.cs" />
<Compile Include="Codec\iCodecAudio.cs" />
<Compile Include="Codec\iHasCallHistory.cs" />
<Compile Include="Codec\iHasDialer.cs" />
<Compile Include="Crestron\Gateways\CenRfgwController.cs" />
<Compile Include="Display\ComTcpDisplayBase.cs" />

View File

@@ -19,7 +19,7 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.Cisco
{
enum eCommandType { SessionStart, SessionEnd, Command, GetStatus, GetConfiguration };
public class CiscoCodec : VideoCodecBase
public class CiscoCodec : VideoCodecBase, IHasCallHistory
{
public IBasicCommunication Communication { get; private set; }
public CommunicationGather PortGather { get; private set; }
@@ -31,7 +31,7 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.Cisco
public BoolFeedback RoomIsOccupiedFeedback { get; private set; }
public BoolFeedback PeopleCountFeedback { get; private set; }
public IntFeedback PeopleCountFeedback { get; private set; }
public BoolFeedback SpeakerTrackIsOnFeedback { get; private set; }
@@ -41,7 +41,11 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.Cisco
private CiscoCodecConfiguration.RootObject CodecConfiguration;
private CiscoCodecStatus.RootObject CodecStatus;
private CiscoCodecStatus.RootObject CodecStatus;
private CiscoCallHistory.RootObject CodecCallHistory;
public List<CallHistory.CallHistoryEntry> RecentCalls { get; private set; }
//private CiscoCodecEvents.RootObject CodecEvent;
@@ -72,11 +76,15 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.Cisco
}
}
/// <summary>
/// Gets the value of the currently shared source, or returns null
/// </summary>
protected override Func<string> SharingSourceFeedbackFunc
{
#warning figure out how to return the key of the shared source somehow
get
{
return () => "Todo";
{
return () => "todo";
}
}
@@ -110,7 +118,12 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.Cisco
{
return () => CodecStatus.Status.Cameras.SpeakerTrack.Status.BoolValue;
}
}
}
protected override Func<int> ActiveCallCountFeedbackFunc
{
get { return () => ActiveCalls.Count; }
}
//private HttpsClient Client;
@@ -142,36 +155,61 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.Cisco
public CiscoCodec(string key, string name, IBasicCommunication comm, int serverPort)
: base(key, name)
{
StandbyIsOnFeedback = new BoolFeedback(StandbyStateFeedbackFunc);
StandbyIsOnFeedback = new BoolFeedback(StandbyStateFeedbackFunc);
RoomIsOccupiedFeedback = new BoolFeedback(RoomIsOccupiedFeedbackFunc);
PeopleCountFeedback = new IntFeedback(PeopleCountFeedbackFunc);
SpeakerTrackIsOnFeedback = new BoolFeedback(SpeakerTrackIsOnFeedbackFunc);
Communication = comm;
SyncState = new CodecSyncState(key + "--sync");
SyncState = new CodecSyncState(key + "--sync");
SyncState.InitialSyncCompleted += new EventHandler<EventArgs>(SyncState_InitialSyncCompleted);
PortGather = new CommunicationGather(Communication, Delimiter);
PortGather.IncludeDelimiter = true;
PortGather.LineReceived += this.Port_LineReceived;
//ServerPort = serverPort;
CodecObtp = new CiscoOneButtonToPush();
PhoneBook = new Corporate_Phone_Book();
CodecConfiguration = new CiscoCodecConfiguration.RootObject();
CodecStatus = new CiscoCodecStatus.RootObject();
//CodecEvent = new CiscoCodecEvents.RootObject();
CodecStatus.Status.Audio.Volume.ValueChangedAction = VolumeLevelFeedback.FireUpdate;
CodecStatus.Status.Audio.VolumeMute.ValueChangedAction = MuteFeedback.FireUpdate;
CodecStatus.Status.Audio.Microphones.Mute.ValueChangedAction = PrivacyModeIsOnFeedback.FireUpdate;
CodecStatus.Status.Standby.State.ValueChangedAction = StandbyIsOnFeedback.FireUpdate;
CodecStatus = new CiscoCodecStatus.RootObject();
CodecCallHistory = new CiscoCallHistory.RootObject();
CodecStatus.Status.Audio.Volume.ValueChangedAction = VolumeLevelFeedback.FireUpdate;
CodecStatus.Status.Audio.VolumeMute.ValueChangedAction = MuteFeedback.FireUpdate;
CodecStatus.Status.Audio.Microphones.Mute.ValueChangedAction = PrivacyModeIsOnFeedback.FireUpdate;
CodecStatus.Status.Standby.State.ValueChangedAction = StandbyIsOnFeedback.FireUpdate;
CodecStatus.Status.RoomAnalytics.PeoplePresence.ValueChangedAction = RoomIsOccupiedFeedback.FireUpdate;
CodecStatus.Status.RoomAnalytics.PeopleCount.Current.ValueChangedAction = PeopleCountFeedback.FireUpdate;
CodecStatus.Status.Cameras.SpeakerTrack.Status.ValueChangedAction = SpeakerTrackIsOnFeedback.FireUpdate;
//ServerPort = serverPort;
//Client = new HttpsClient();
//Server = new HttpApiServer();
}
/// <summary>
/// Fires when initial codec sync is completed. Used to then send commands to get call history, phonebook, bookings, etc.
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
void SyncState_InitialSyncCompleted(object sender, EventArgs e)
{
SendText("xCommand CallHistory Recents Limit: 20 Order: OccurrenceTime");
// Get bookings for the day
//SendText("xCommand Bookings List Days: 1 DayOffset: 0");
// Get Phonebook (determine local/corporate from config, and set results limit)
//SendText("xCommand Phonebook Search PhonebookType: {0} ContactType: Folder Limit: {0}", PhonebookType, PhonebookResultsLimit);
}
/// <summary>
@@ -230,6 +268,7 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.Cisco
prefix + "/Configuration" + Delimiter +
prefix + "/Status/Audio" + Delimiter +
prefix + "/Status/Call" + Delimiter +
prefix + "/Status/Conference/Presentation" + Delimiter +
prefix + "/Status/Cameras/SpeakerTrack" + Delimiter +
prefix + "/Status/RoomAnalytics" + Delimiter +
prefix + "/Status/Standby" + Delimiter +
@@ -312,30 +351,31 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.Cisco
//Debug.Console(1, this, "Building JSON:\n{0}", JsonMessage.ToString());
return;
}
if (!SyncState.InitialSyncComplete)
{
switch (args.Text.Trim().ToLower()) // remove the whitespace
{
case "*r login successful":
{
SendText("xPreferences outputmode json");
break;
}
case "xpreferences outputmode json":
{
if (!SyncState.InitialStatusMessageWasReceived)
SendText("xStatus");
break;
}
case "xfeedback register /event/calldisconnect":
{
SyncState.FeedbackRegistered();
break;
}
}
}
if (!SyncState.InitialSyncComplete)
{
switch (args.Text.Trim().ToLower()) // remove the whitespace
{
case "*r login successful":
{
SendText("xPreferences outputmode json");
break;
}
case "xpreferences outputmode json":
{
if(!SyncState.InitialStatusMessageWasReceived)
SendText("xStatus");
break;
}
case "xfeedback register":
{
SyncState.FeedbackRegistered();
break;
}
}
}
}
public void SendText(string command)
@@ -519,6 +559,8 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.Cisco
if (response.IndexOf("\"Status\":{") > -1)
{
// Status Message
// Check to see if this is a call status message received after the initial status message
if(SyncState.InitialStatusMessageWasReceived && response.IndexOf("\"Call\":{") > -1)
{
@@ -536,15 +578,38 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.Cisco
{
// If an existing call object is found with a matching ID, populate the existing call with the new data.
// (must reserialize the object so that we can use PopulateObject() to overlay the new or updated properties on the existing object)
JsonConvert.PopulateObject(JsonConvert.SerializeObject(call), existingCall);
JsonConvert.PopulateObject(JsonConvert.SerializeObject(call), existingCall);
var tempActiveCall = ActiveCalls.FirstOrDefault(c => c.Id.Equals(call.id));
// store previous status to pass to event handler
var previousStatus = tempActiveCall.Status;
// Update properties of ActiveCallItem
tempActiveCall.Status = CodecCallStatus.ConvertToStatusEnum(call.Status.Value);
tempActiveCall.Type = CodecCallType.ConvertToTypeEnum(call.CallType.Value);
tempActiveCall.Name = call.DisplayName.Value;
SetNewCallStatusAndFireCallStatusChange(previousStatus, tempActiveCall);
}
else
{
// Add the call
callStatus.Status.Call.Add(call);
callStatus.Status.Call.Add(call);
var newCallItem = new CodecActiveCallItem()
{
Id = call.id,
Status = CodecCallStatus.ConvertToStatusEnum(call.Status.Value),
Name = call.DisplayName.Value,
Number = call.RemoteNumber.Value,
Type = CodecCallType.ConvertToTypeEnum(call.CallType.Value)
};
// Add a call to the ActiveCalls List
//ActiveCalls.Add(new CodecActiveCallItem() { Id = call.id, Status = call.Status.Value, Name = call.DisplayName.Value, Number = call.RemoteNumber.Value, Type = call.Status.Value.ToString()
ActiveCalls.Add(newCallItem);
SetNewCallStatusAndFireCallStatusChange(newCallItem.Status, newCallItem);
}
// Handle call.status to determine if we need to fire an event notifying of an incoming call or a call disconnect
@@ -562,6 +627,8 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.Cisco
}
else if (response.IndexOf("\"Configuration\":{") > -1)
{
// Configuration Message
JsonConvert.PopulateObject(response, CodecConfiguration);
if (!SyncState.InitialConfigurationMessageWasReceived)
@@ -576,11 +643,36 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.Cisco
}
else if (response.IndexOf("\"Event\":{") > -1)
{
// Event Message
CiscoCodecEvents.RootObject eventReceived = new CiscoCodecEvents.RootObject();
JsonConvert.PopulateObject(response, eventReceived);
EvalutateEvent(eventReceived);
}
else if (response.IndexOf("\"CommandResponse\":{") > -1)
{
// CommandResponse Message
if (response.IndexOf("\"CallHistoryRecentsResult\":{") > -1)
{
JsonConvert.PopulateObject(response, CodecCallHistory);
RecentCalls = CallHistory.ConvertCiscoCallHistoryToGeneric(CodecCallHistory.CommandResponse.CallHistoryRecentsResult.Entry);
if (Debug.Level == 1)
{
Debug.Console(1, this, "RecentCalls:\n");
foreach (CallHistory.CallHistoryEntry entry in RecentCalls)
{
Debug.Console(1, this, "\nName: {0}\nNumber{1}\nStartTime{2}\nType{3}\n", entry.DisplayName, entry.CallBackNumber, entry.StartTime.ToString(), entry.OccurenceType);
}
}
}
}
}
@@ -588,7 +680,8 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.Cisco
{
Debug.Console(1, this, "Error Deserializing feedback from codec: {0}", ex);
}
}
}
/// <summary>
/// Evaluates an event received from the codec
@@ -598,12 +691,21 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.Cisco
{
if (eventReceived.Event.CallDisconnect != null)
{
var tempCall = CodecStatus.Status.Call.FirstOrDefault(c => c.id.Equals(eventReceived.Event.CallDisconnect.CallId));
var tempCall = CodecStatus.Status.Call.FirstOrDefault(c => c.id.Equals(eventReceived.Event.CallDisconnect.CallId.Value));
if(tempCall != null)
{
CodecStatus.Status.Call.Remove(tempCall);
// Remove the call from the xStatus object
CodecStatus.Status.Call.Remove(tempCall);
var tempActiveCall = ActiveCalls.FirstOrDefault(c => c.Id.Equals(eventReceived.Event.CallDisconnect.CallId.Value));
// Remove the call from the Active calls list
if (tempActiveCall != null)
ActiveCalls.Remove(tempActiveCall);
// Notify of the call disconnection
SetNewCallStatusAndFireCallStatusChange(eCodecCallStatus.Disconnected, tempActiveCall);
}
}
}
@@ -798,22 +900,44 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.Cisco
public void Reboot()
{
SendText("xCommand SystemUnit Boot Action: Restart");
}
public void RemoveEntry(CallHistory.CallHistoryEntry entry)
{
if (RecentCalls != null)
{
RecentCalls.Remove(entry);
}
}
protected override Func<int> ActiveCallCountFeedbackFunc
{
get { return () => 0; }
}
}
/// <summary>
/// Tracks the initial sycnronization state of the codec when making a connection
/// </summary>
public class CodecSyncState : IKeyed
{
{
bool _InitialSyncComplete;
public event EventHandler<EventArgs> InitialSyncCompleted;
public string Key { get; private set; }
public bool InitialSyncComplete { get; private set; }
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 InitialStatusMessageWasReceived { get; private set; }

View File

@@ -13,6 +13,7 @@ using Cisco_SX80_Corporate_Phone_Book;
using PepperDash.Core;
using PepperDash.Essentials.Core;
using PepperDash.Essentials.Core.Routing;
using PepperDash.Essentials.Devices.Common.Codec;
namespace PepperDash.Essentials.Devices.Common.VideoCodec.Cisco
{
@@ -28,6 +29,12 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.Cisco
public BoolFeedback StandbyIsOnFeedback { get; private set; }
public BoolFeedback RoomIsOccupiedFeedback { get; private set; }
public BoolFeedback PeopleCountFeedback { get; private set; }
public BoolFeedback SpeakerTrackIsOnFeedback { get; private set; }
private CiscoOneButtonToPush CodecObtp;
private Corporate_Phone_Book PhoneBook;
@@ -36,7 +43,11 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.Cisco
private CiscoCodecStatus.RootObject CodecStatus;
<<<<<<< HEAD
private CiscoCodecEvents.RootObject CodecEvent;
=======
//private CiscoCodecEvents.RootObject CodecEvent;
>>>>>>> origin/feature/cisco-spark-2
/// <summary>
/// Gets and returns the scaled volume of the codec
@@ -67,12 +78,42 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.Cisco
protected override Func<string> SharingSourceFeedbackFunc
{
get { return () => "Fix me fuckers"; }
get
{
return () => "Todo";
}
}
protected override Func<bool> MuteFeedbackFunc
{
get { return () => false; }
get
{
return () => CodecStatus.Status.Audio.VolumeMute.BoolValue;
}
}
protected Func<bool> RoomIsOccupiedFeedbackFunc
{
get
{
return () => CodecStatus.Status.RoomAnalytics.PeoplePresence.BoolValue;
}
}
protected Func<int> PeopleCountFeedbackFunc
{
get
{
return () => CodecStatus.Status.RoomAnalytics.PeopleCount.Current.IntValue;
}
}
protected Func<bool> SpeakerTrackIsOnFeedbackFunc
{
get
{
return () => CodecStatus.Status.Cameras.SpeakerTrack.Status.BoolValue;
}
}
//private HttpsClient Client;
@@ -125,7 +166,7 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.Cisco
CodecStatus = new CiscoCodecStatus.RootObject();
CodecEvent = new CiscoCodecEvents.RootObject();
//CodecEvent = new CiscoCodecEvents.RootObject();
CodecStatus.Status.Audio.Volume.ValueChangedAction = VolumeLevelFeedback.FireUpdate;
CodecStatus.Status.Audio.VolumeMute.ValueChangedAction = MuteFeedback.FireUpdate;
@@ -482,6 +523,38 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.Cisco
if (response.IndexOf("\"Status\":{") > -1)
{
// Check to see if this is a call status message received after the initial status message
if(SyncState.InitialStatusMessageWasReceived && response.IndexOf("\"Call\":{") > -1)
{
CiscoCodecStatus.RootObject callStatus = new CiscoCodecStatus.RootObject();
JsonConvert.PopulateObject(response, callStatus);
// Iterate through the call objects in the response
foreach (CiscoCodecStatus.Call call in callStatus.Status.Call)
{
// Look for a matching call id in the existing status structure
var existingCall = CodecStatus.Status.Call.FirstOrDefault(c => c.id.Equals(call.id));
if (existingCall != null)
{
// If an existing call object is found with a matching ID, populate the existing call with the new data.
// (must reserialize the object so that we can use PopulateObject() to overlay the new or updated properties on the existing object)
JsonConvert.PopulateObject(JsonConvert.SerializeObject(call), existingCall);
}
else
{
// Add the call
callStatus.Status.Call.Add(call);
// Add a call to the ActiveCalls List
//ActiveCalls.Add(new CodecActiveCallItem() { Id = call.id, Status = call.Status.Value, Name = call.DisplayName.Value, Number = call.RemoteNumber.Value, Type = call.Status.Value.ToString()
}
// Handle call.status to determine if we need to fire an event notifying of an incoming call or a call disconnect
}
}
JsonConvert.PopulateObject(response, CodecStatus);
if (!SyncState.InitialStatusMessageWasReceived)
@@ -507,7 +580,11 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.Cisco
}
else if (response.IndexOf("\"Event\":{") > -1)
{
JsonConvert.PopulateObject(response, CodecEvent);
CiscoCodecEvents.RootObject eventReceived = new CiscoCodecEvents.RootObject();
JsonConvert.PopulateObject(response, eventReceived);
EvalutateEvent(eventReceived);
}
}
@@ -517,6 +594,24 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.Cisco
}
}
/// <summary>
/// Evaluates an event received from the codec
/// </summary>
/// <param name="eventReceived"></param>
void EvalutateEvent(CiscoCodecEvents.RootObject eventReceived)
{
if (eventReceived.Event.CallDisconnect != null)
{
var tempCall = CodecStatus.Status.Call.FirstOrDefault(c => c.id.Equals(eventReceived.Event.CallDisconnect.CallId));
if(tempCall != null)
{
CodecStatus.Status.Call.Remove(tempCall);
}
}
}
public override void ExecuteSwitch(object selector)
{
(selector as Action)();
@@ -551,11 +646,6 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.Cisco
SendText(string.Format("xCommand Dial BookingId: {0}", s));
}
<<<<<<< HEAD
public override void EndCall(string s)
{
SendText(string.Format("xCommand Call Disconnect CallId: {0}", GetCallId()));
=======
public override void EndCall(CodecActiveCallItem activeCall)
{
SendText(string.Format("xCommand Call Disconnect CallId: {0}", activeCall.Id));
@@ -567,15 +657,14 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.Cisco
{
SendText(string.Format("xCommand Call Disconnect CallId: {0}", activeCall.Id));
}
>>>>>>> origin/feature/cisco-spark-2
}
public override void AcceptCall()
public override void AcceptCall(CodecActiveCallItem item)
{
SendText("xCommand Call Accept");
}
public override void RejectCall()
public override void RejectCall(CodecActiveCallItem item)
{
SendText("xCommand Call Reject");
}

View File

@@ -66,30 +66,28 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec
public override void Dial(string s)
{
Debug.Console(1, this, "Dial: {0}", s);
var item = new CodecActiveCallItem() { Name = s, Number = s, Id = s, Status = eCodecCallStatus.Dialing };
ActiveCalls.Add(item);
OnCallStatusChange(eCodecCallStatus.Unknown, item.Status, item);
var call = new CodecActiveCallItem() { Name = s, Number = s, Id = s, Status = eCodecCallStatus.Dialing };
ActiveCalls.Add(call);
OnCallStatusChange(eCodecCallStatus.Unknown, call.Status, call);
ActiveCallCountFeedback.FireUpdate();
// Simulate 2-second ring
// Simulate 2-second ring, then connecting, then connected
new CTimer(o =>
{
var prevStatus = item.Status;
item.Status = eCodecCallStatus.Connected;
item.Type = eCodecCallType.Video;
OnCallStatusChange(prevStatus, item.Status, item);
call.Type = eCodecCallType.Video;
SetNewCallStatusAndFireCallStatusChange(eCodecCallStatus.Connecting, call);
new CTimer(oo => SetNewCallStatusAndFireCallStatusChange(eCodecCallStatus.Connected, call), 1000);
}, 2000);
}
/// <summary>
///
/// </summary>
public override void EndCall(CodecActiveCallItem activeCall)
public override void EndCall(CodecActiveCallItem call)
{
Debug.Console(1, this, "EndCall");
ActiveCalls.Remove(activeCall);
var prevStatus = activeCall.Status;
activeCall.Status = eCodecCallStatus.Disconnected;
OnCallStatusChange(prevStatus, activeCall.Status, activeCall);
ActiveCalls.Remove(call);
SetNewCallStatusAndFireCallStatusChange(eCodecCallStatus.Disconnected, call);
ActiveCallCountFeedback.FireUpdate();
}
@@ -99,23 +97,29 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec
public override void EndAllCalls()
{
Debug.Console(1, this, "EndAllCalls");
ActiveCalls.Clear();
foreach (var call in ActiveCalls)
{
ActiveCalls.Remove(call);
SetNewCallStatusAndFireCallStatusChange(eCodecCallStatus.Disconnected, call);
}
ActiveCallCountFeedback.FireUpdate();
}
/// <summary>
/// For a call from the test methods below
/// </summary>
public override void AcceptCall(CodecActiveCallItem item)
public override void AcceptCall(CodecActiveCallItem call)
{
Debug.Console(1, this, "AcceptCall");
SetNewCallStatusAndFireCallStatusChange(eCodecCallStatus.Connecting, call);
new CTimer(o => SetNewCallStatusAndFireCallStatusChange(eCodecCallStatus.Connected, call), 1000);
// should already be in active list
}
/// <summary>
/// For a call from the test methods below
/// </summary>
public override void RejectCall(CodecActiveCallItem item)
public override void RejectCall(CodecActiveCallItem call)
{
Debug.Console(1, this, "RejectCall");
}
@@ -247,16 +251,32 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec
///
/// </summary>
/// <param name="url"></param>
public void TestIncomingCall(string url)
public void TestIncomingVideoCall(string url)
{
Debug.Console(1, this, "TestIncomingCall from {0}", url);
var item = new CodecActiveCallItem() { Name = url, Id = url, Number = url, Status = eCodecCallStatus.Incoming, Type= eCodecCallType.Unknown };
ActiveCalls.Add(item);
Debug.Console(1, this, "TestIncomingVideoCall from {0}", url);
var call = new CodecActiveCallItem() { Name = url, Id = url, Number = url, Type= eCodecCallType.Video };
ActiveCalls.Add(call);
SetNewCallStatusAndFireCallStatusChange(eCodecCallStatus.Incoming, call);
_IncomingCall = true;
IncomingCallFeedback.FireUpdate();
ActiveCallCountFeedback.FireUpdate();
}
/// <summary>
///
/// </summary>
/// <param name="url"></param>
public void TestIncomingAudioCall(string url)
{
Debug.Console(1, this, "TestIncomingAudioCall from {0}", url);
var call = new CodecActiveCallItem() { Name = url, Id = url, Number = url, Type = eCodecCallType.Audio };
ActiveCalls.Add(call);
SetNewCallStatusAndFireCallStatusChange(eCodecCallStatus.Incoming, call);
_IncomingCall = true;
IncomingCallFeedback.FireUpdate();
ActiveCallCountFeedback.FireUpdate();
}
/// <summary>
///
/// </summary>
@@ -266,6 +286,9 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec
}
/// <summary>
///
/// </summary>
public void ListCalls()
{
var sb = new StringBuilder();
@@ -278,7 +301,7 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec
public RoutingPortCollection<RoutingOutputPort> OutputPorts
{
get { throw new NotImplementedException(); }
get { return new RoutingPortCollection<RoutingOutputPort>(); }
}
#endregion

View File

@@ -35,9 +35,18 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec
#endregion
/// <summary>
/// Returns true when ActiveCallCountFeedback is > 0
/// </summary>
public bool IsInCall { get { return ActiveCallCountFeedback.IntValue > 0; } }
/// Returns whether any call in ActiveCalls is actually "active"
/// </summary>
public bool IsInCall
{
get
{
return ActiveCalls.Any(c =>
!(c.Status == eCodecCallStatus.Unknown
|| c.Status == eCodecCallStatus.Disconnected
|| c.Status == eCodecCallStatus.Disconnecting));
}
}
public BoolFeedback IncomingCallFeedback { get; private set; }
@@ -87,11 +96,7 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec
#region IHasDialer Members
public abstract void Dial(string s);
public void EndCall(object activeCall)
{
}
public abstract void EndCall(CodecActiveCallItem activeCall);
public abstract void EndCall(CodecActiveCallItem call);
public abstract void EndAllCalls();
public abstract void AcceptCall(CodecActiveCallItem call);
public abstract void RejectCall(CodecActiveCallItem call);
@@ -115,13 +120,24 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec
public abstract void ExecuteSwitch(object selector);
/// <summary>
///
/// Helper method to fire CallStatusChange event with old and new status
/// </summary>
protected void SetNewCallStatusAndFireCallStatusChange(eCodecCallStatus newStatus, CodecActiveCallItem call)
{
var prevStatus = call.Status;
call.Status = newStatus;
OnCallStatusChange(prevStatus, newStatus, call);
}
/// <summary>
/// Helper method to notify of call status change event
/// </summary>
/// <param name="previousStatus"></param>
/// <param name="newStatus"></param>
/// <param name="item"></param>
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));