moving interfaces and base classes into Core from Devices Common

maybe too far down the rabbit hole?
This commit is contained in:
Andrew Welker
2020-06-26 22:57:39 -06:00
parent bb87e2f53b
commit 68ea7bba84
58 changed files with 1565 additions and 183 deletions

View File

@@ -0,0 +1,67 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Crestron.SimplSharp;
using Newtonsoft.Json;
using Newtonsoft.Json.Converters;
namespace PepperDash.Essentials.Core.Devices.Codec
{
public class CodecActiveCallItem
{
[JsonProperty("name")]
public string Name { get; set; }
[JsonProperty("number")]
public string Number { get; set; }
[JsonProperty("type")]
[JsonConverter(typeof(StringEnumConverter))]
public eCodecCallType Type { get; set; }
[JsonProperty("status")]
[JsonConverter(typeof(StringEnumConverter))]
public eCodecCallStatus Status { get; set; }
[JsonProperty("direction")]
[JsonConverter(typeof(StringEnumConverter))]
public eCodecCallDirection Direction { get; set; }
[JsonProperty("id")]
public string Id { get; set; }
//public object CallMetaData { get; set; }
/// <summary>
/// Returns true when this call is any status other than
/// Unknown, Disconnected, Disconnecting
/// </summary>
[JsonProperty("isActiveCall")]
public bool IsActiveCall
{
get
{
return !(Status == eCodecCallStatus.Disconnected
|| Status == eCodecCallStatus.Disconnecting
|| Status == eCodecCallStatus.Idle
|| Status == eCodecCallStatus.Unknown);
}
}
}
/// <summary>
///
/// </summary>
public class CodecCallStatusItemChangeEventArgs : EventArgs
{
public CodecActiveCallItem CallItem { get; private set; }
public CodecCallStatusItemChangeEventArgs(CodecActiveCallItem item)
{
CallItem = item;
}
}
}

View File

@@ -0,0 +1,41 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Crestron.SimplSharp;
namespace PepperDash.Essentials.Core.Devices.Codec
{
public enum eCodecCallDirection
{
Unknown = 0, Incoming, Outgoing
}
public class CodecCallDirection
{
/// <summary>
/// Takes the Cisco call type and converts to the matching enum
/// </summary>
/// <param name="s"></param>
/// <returns></returns>
public static eCodecCallDirection ConvertToDirectionEnum(string s)
{
switch (s.ToLower())
{
case "incoming":
{
return eCodecCallDirection.Incoming;
}
case "outgoing":
{
return eCodecCallDirection.Outgoing;
}
default:
return eCodecCallDirection.Unknown;
}
}
}
}

View File

@@ -0,0 +1,89 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Crestron.SimplSharp;
namespace PepperDash.Essentials.Core.Devices.Codec
{
public enum eCodecCallStatus
{
Unknown = 0,
Connected,
Connecting,
Dialing,
Disconnected,
Disconnecting,
EarlyMedia,
Idle,
OnHold,
Ringing,
Preserved,
RemotePreserved,
}
public class CodecCallStatus
{
/// <summary>
/// Takes the Cisco call type and converts to the matching enum
/// </summary>
/// <param name="s"></param>
/// <returns></returns>
public static eCodecCallStatus ConvertToStatusEnum(string s)
{
switch (s)
{
case "Connected":
{
return eCodecCallStatus.Connected;
}
case "Connecting":
{
return eCodecCallStatus.Connecting;
}
case "Dialling":
{
return eCodecCallStatus.Dialing;
}
case "Disconnected":
{
return eCodecCallStatus.Disconnected;
}
case "Disconnecting":
{
return eCodecCallStatus.Disconnecting;
}
case "EarlyMedia":
{
return eCodecCallStatus.EarlyMedia;
}
case "Idle":
{
return eCodecCallStatus.Idle;
}
case "OnHold":
{
return eCodecCallStatus.OnHold;
}
case "Ringing":
{
return eCodecCallStatus.Ringing;
}
case "Preserved":
{
return eCodecCallStatus.Preserved;
}
case "RemotePreserved":
{
return eCodecCallStatus.RemotePreserved;
}
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.Core.Devices.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,42 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Crestron.SimplSharp;
namespace PepperDash.Essentials.Core.Devices.Codec
{
public enum eMeetingPrivacy
{
Unknown = 0,
Public,
Private
}
public class CodecCallPrivacy
{
/// <summary>
/// Takes the Cisco privacy type and converts to the matching enum
/// </summary>
/// <param name="s"></param>
/// <returns></returns>
public static eMeetingPrivacy ConvertToDirectionEnum(string s)
{
switch (s.ToLower())
{
case "public":
{
return eMeetingPrivacy.Public;
}
case "private":
{
return eMeetingPrivacy.Private;
}
default:
return eMeetingPrivacy.Unknown;
}
}
}
}

View File

@@ -0,0 +1,10 @@
namespace PepperDash.Essentials.Core.Devices.Codec
{
/// <summary>
/// Defines minimum volume controls for a codec device with dialing capabilities
/// </summary>
public interface ICodecAudio : IBasicVolumeWithFeedback, IPrivacy
{
}
}

View File

@@ -0,0 +1,22 @@
using System.Collections.Generic;
namespace PepperDash.Essentials.Core.Devices.Codec
{
public interface IHasCallFavorites
{
CodecCallFavorites CallFavorites { get; }
}
/// <summary>
/// Represents favorites entries for a codec device
/// </summary>
public class CodecCallFavorites
{
public List<CodecActiveCallItem> Favorites { get; set; }
public CodecCallFavorites()
{
Favorites = new List<CodecActiveCallItem>();
}
}
}

View File

@@ -0,0 +1,83 @@
using System;
using System.Collections.Generic;
using Newtonsoft.Json;
using Newtonsoft.Json.Converters;
namespace PepperDash.Essentials.Core.Devices.Codec
{
public interface IHasCallHistory
{
CodecCallHistory CallHistory { get; }
void RemoveCallHistoryEntry(CodecCallHistory.CallHistoryEntry entry);
}
public enum eCodecOccurrenceType
{
Unknown = 0,
Placed,
Received,
NoAnswer
}
/// <summary>
/// Represents the recent call history for a codec device
/// </summary>
public class CodecCallHistory
{
public event EventHandler<EventArgs> RecentCallsListHasChanged;
public List<CallHistoryEntry> RecentCalls { get; private set; }
/// <summary>
/// Item that gets added to the list when there are no recent calls in history
/// </summary>
readonly CallHistoryEntry _listEmptyEntry;
public CallHistoryEntry ListEmptyEntry
{
get { return _listEmptyEntry; }
}
public CodecCallHistory()
{
_listEmptyEntry = new CallHistoryEntry() { Name = "No Recent Calls" };
RecentCalls = new List<CallHistoryEntry> {_listEmptyEntry};
}
private void OnRecentCallsListChange()
{
var handler = RecentCallsListHasChanged;
if (handler != null)
{
handler(this, new EventArgs());
}
}
public void RemoveEntry(CallHistoryEntry entry)
{
RecentCalls.Remove(entry);
OnRecentCallsListChange();
}
/// <summary>
/// Generic call history entry, not device specific
/// </summary>
public class CallHistoryEntry : CodecActiveCallItem
{
[JsonConverter(typeof (IsoDateTimeConverter))]
[JsonProperty("startTime")]
public DateTime StartTime { get; set; }
[JsonConverter(typeof (StringEnumConverter))]
[JsonProperty("occurrenceType")]
public eCodecOccurrenceType OccurrenceType { get; set; }
[JsonProperty("occurrenceHistoryId")]
public string OccurrenceHistoryId { get; set; }
}
}
}

View File

@@ -0,0 +1,24 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Crestron.SimplSharp;
using PepperDash.Core;
using PepperDash.Essentials.Core;
namespace PepperDash.Essentials.Core.Devices.Codec
{
public interface IHasContentSharing
{
BoolFeedback SharingContentIsOnFeedback { get; }
StringFeedback SharingSourceFeedback { get; }
bool AutoShareContentWhileInCall { get; }
void StartSharing();
void StopSharing();
}
}

View File

@@ -0,0 +1,24 @@
using System;
namespace PepperDash.Essentials.Core.Devices.Codec
{
/// <summary>
/// Requirements for a device that has dialing capabilities
/// </summary>
public interface IHasDialer
{
// Add requirements for Dialer functionality
event EventHandler<CodecCallStatusItemChangeEventArgs> CallStatusChange;
void Dial(string number);
void EndCall(CodecActiveCallItem activeCall);
void EndAllCalls();
void AcceptCall(CodecActiveCallItem item);
void RejectCall(CodecActiveCallItem item);
void SendDtmf(string digit);
bool IsInCall { get; }
}
}

View File

@@ -0,0 +1,223 @@
using System;
using System.Collections.Generic;
using System.Linq;
using Newtonsoft.Json;
using Newtonsoft.Json.Converters;
using PepperDash.Essentials.Core.Devices.VideoCodec;
namespace PepperDash.Essentials.Core.Devices.Codec
{
/// <summary>
/// Defines the API for codecs with a directory
/// </summary>
public interface IHasDirectory
{
event EventHandler<DirectoryEventArgs> DirectoryResultReturned;
CodecDirectory DirectoryRoot { get; }
CodecDirectory CurrentDirectoryResult { get; }
CodecPhonebookSyncState PhonebookSyncState { get; }
void SearchDirectory(string searchString);
void GetDirectoryFolderContents(string folderId);
void SetCurrentDirectoryToRoot();
void GetDirectoryParentFolderContents();
BoolFeedback CurrentDirectoryResultIsNotDirectoryRoot { get; }
/// <summary>
/// Tracks the directory browse history when browsing beyond the root directory
/// </summary>
List<CodecDirectory> DirectoryBrowseHistory { get; }
}
/// <summary>
///
/// </summary>
public class DirectoryEventArgs : EventArgs
{
public CodecDirectory Directory { get; set; }
public bool DirectoryIsOnRoot { get; set; }
}
/// <summary>
/// Represents a codec directory
/// </summary>
public class CodecDirectory
{
/// <summary>
/// Represents the contents of the directory
/// </summary>
[JsonProperty("directoryResults")]
public List<DirectoryItem> CurrentDirectoryResults { get; private set; }
/// <summary>
/// Used to store the ID of the current folder for CurrentDirectoryResults
/// </summary>
[JsonProperty("resultsFolderId")]
public string ResultsFolderId { get; set; }
public CodecDirectory()
{
CurrentDirectoryResults = new List<DirectoryItem>();
}
/// <summary>
/// Adds folders to the directory
/// </summary>
/// <param name="folders"></param>
public void AddFoldersToDirectory(List<DirectoryItem> folders)
{
if(folders != null)
CurrentDirectoryResults.AddRange(folders);
SortDirectory();
}
/// <summary>
/// Adds contacts to the directory
/// </summary>
/// <param name="contacts"></param>
public void AddContactsToDirectory(List<DirectoryItem> contacts)
{
if(contacts != null)
CurrentDirectoryResults.AddRange(contacts);
SortDirectory();
}
/// <summary>
/// Sorts the DirectoryResults list to display all folders alphabetically, then all contacts alphabetically
/// </summary>
private void SortDirectory()
{
var sortedFolders = new List<DirectoryItem>();
sortedFolders.AddRange(CurrentDirectoryResults.Where(f => f is DirectoryFolder));
sortedFolders.OrderBy(f => f.Name);
var sortedContacts = new List<DirectoryItem>();
sortedContacts.AddRange(CurrentDirectoryResults.Where(c => c is DirectoryContact));
sortedFolders.OrderBy(c => c.Name);
CurrentDirectoryResults.Clear();
CurrentDirectoryResults.AddRange(sortedFolders);
CurrentDirectoryResults.AddRange(sortedContacts);
}
}
/// <summary>
/// Used to decorate a contact to indicate it can be invided to a meeting
/// </summary>
public interface IInvitableContact
{
}
/// <summary>
/// Represents an item in the directory
/// </summary>
public class DirectoryItem : ICloneable
{
public object Clone()
{
return this.MemberwiseClone();
}
[JsonProperty("folderId")]
public string FolderId { get; set; }
[JsonProperty("name")]
public string Name { get; set; }
}
/// <summary>
/// Represents a folder type DirectoryItem
/// </summary>
public class DirectoryFolder : DirectoryItem
{
[JsonProperty("contacts")]
public List<DirectoryContact> Contacts { get; set; }
[JsonProperty("parentFolderId")]
public string ParentFolderId { get; set; }
public DirectoryFolder()
{
Contacts = new List<DirectoryContact>();
}
}
/// <summary>
/// Represents a contact type DirectoryItem
/// </summary>
public class DirectoryContact : DirectoryItem
{
[JsonProperty("contactId")]
public string ContactId { get; set; }
[JsonProperty("title")]
public string Title { get; set; }
[JsonProperty("contactMethods")]
public List<ContactMethod> ContactMethods { get; set; }
public DirectoryContact()
{
ContactMethods = new List<ContactMethod>();
}
}
/// <summary>
/// Represents a method of contact for a contact
/// </summary>
public class ContactMethod
{
[JsonProperty("contactMethodId")]
public string ContactMethodId { get; set; }
[JsonProperty("number")]
public string Number { get; set; }
[JsonProperty("device")]
[JsonConverter(typeof(StringEnumConverter))]
public eContactMethodDevice Device { get; set; }
[JsonProperty("callType")]
[JsonConverter(typeof(StringEnumConverter))]
public eContactMethodCallType CallType { get; set; }
}
/// <summary>
///
/// </summary>
public enum eContactMethodDevice
{
Unknown = 0,
Mobile,
Other,
Telephone,
Video
}
/// <summary>
///
/// </summary>
public enum eContactMethodCallType
{
Unknown = 0,
Audio,
Video
}
}

View File

@@ -0,0 +1,165 @@
using System;
using System.Collections.Generic;
using Crestron.SimplSharp;
namespace PepperDash.Essentials.Core.Devices.Codec
{
public enum eMeetingEventChangeType
{
Unkown = 0,
MeetingStartWarning,
MeetingStart,
MeetingEndWarning,
MeetingEnd
}
public interface IHasScheduleAwareness
{
CodecScheduleAwareness CodecSchedule { get; }
void GetSchedule();
}
public class CodecScheduleAwareness
{
List<Meeting> _Meetings;
public event EventHandler<MeetingEventArgs> MeetingEventChange;
public event EventHandler<EventArgs> MeetingsListHasChanged;
/// <summary>
/// Setter triggers MeetingsListHasChanged event
/// </summary>
public List<Meeting> Meetings
{
get
{
return _Meetings;
}
set
{
_Meetings = value;
var handler = MeetingsListHasChanged;
if (handler != null)
{
handler(this, new EventArgs());
}
}
}
private CTimer ScheduleChecker;
public CodecScheduleAwareness()
{
Meetings = new List<Meeting>();
ScheduleChecker = new CTimer(CheckSchedule, null, 1000, 1000);
}
private void OnMeetingChange(eMeetingEventChangeType changeType, Meeting meeting)
{
var handler = MeetingEventChange;
if (handler != null)
{
handler(this, new MeetingEventArgs() { ChangeType = changeType, Meeting = meeting });
}
}
private void CheckSchedule(object o)
{
// Iterate the meeting list and check if any meeting need to do anythingk
const double meetingTimeEpsilon = 0.0001;
foreach (Meeting m in Meetings)
{
eMeetingEventChangeType changeType = eMeetingEventChangeType.Unkown;
if (m.TimeToMeetingStart.TotalMinutes <= m.MeetingWarningMinutes.TotalMinutes) // Meeting is about to start
changeType = eMeetingEventChangeType.MeetingStartWarning;
else if (Math.Abs(m.TimeToMeetingStart.TotalMinutes) < meetingTimeEpsilon) // Meeting Start
changeType = eMeetingEventChangeType.MeetingStart;
else if (m.TimeToMeetingEnd.TotalMinutes <= m.MeetingWarningMinutes.TotalMinutes) // Meeting is about to end
changeType = eMeetingEventChangeType.MeetingEndWarning;
else if (Math.Abs(m.TimeToMeetingEnd.TotalMinutes) < meetingTimeEpsilon) // Meeting has ended
changeType = eMeetingEventChangeType.MeetingEnd;
if (changeType != eMeetingEventChangeType.Unkown)
OnMeetingChange(changeType, m);
}
}
}
/// <summary>
/// Generic class to represent a meeting (Cisco or Polycom OBTP or Fusion)
/// </summary>
public class Meeting
{
public TimeSpan MeetingWarningMinutes = TimeSpan.FromMinutes(5);
public string Id { get; set; }
public string Organizer { get; set; }
public string Title { get; set; }
public string Agenda { get; set; }
public TimeSpan TimeToMeetingStart
{
get
{
return StartTime - DateTime.Now;
}
}
public TimeSpan TimeToMeetingEnd
{
get
{
return EndTime - DateTime.Now;
}
}
public DateTime StartTime { get; set; }
public DateTime EndTime { get; set; }
public TimeSpan Duration
{
get
{
return EndTime - StartTime;
}
}
public eMeetingPrivacy Privacy { get; set; }
public bool Joinable
{
get
{
return StartTime.AddMinutes(-5) <= DateTime.Now
&& DateTime.Now <= EndTime; //.AddMinutes(-5);
}
}
//public string ConferenceNumberToDial { get; set; }
public string ConferencePassword { get; set; }
public bool IsOneButtonToPushMeeting { get; set; }
public List<Call> Calls { get; private set; }
public Meeting()
{
Calls = new List<Call>();
}
}
public class Call
{
public string Number { get; set; }
public string Protocol { get; set; }
public string CallRate { get; set; }
public string CallType { get; set; }
}
public class MeetingEventArgs : EventArgs
{
public eMeetingEventChangeType ChangeType { get; set; }
public Meeting Meeting { get; set; }
}
}

View File

@@ -0,0 +1,18 @@
namespace PepperDash.Essentials.Core.Devices.AudioCodec
{
/// <summary>
/// Implements a common set of data about a codec
/// </summary>
public interface IAudioCodecInfo
{
AudioCodecInfo CodecInfo { get; }
}
/// <summary>
/// Stores general information about a codec
/// </summary>
public abstract class AudioCodecInfo
{
public abstract string PhoneNumber { get; set; }
}
}

View File

@@ -0,0 +1,18 @@
using PepperDash.Essentials.Core;
namespace PepperDash.Essentials.Devices.Core.AudioCodec
{
/// <summary>
/// For rooms that have audio codec
/// </summary>
public interface IHasAudioCodec
{
AudioCodecBase AudioCodec { get; }
BoolFeedback InCallFeedback { get; }
///// <summary>
///// Make this more specific
///// </summary>
//List<PepperDash.Essentials.Devices.Common.Codec.CodecActiveCallItem> ActiveCalls { get; }
}
}

View File

@@ -0,0 +1,22 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Crestron.SimplSharp;
using PepperDash.Essentials.Core;
namespace PepperDash.Essentials.Devices.Core.VideoCodec
{
/// <summary>
/// Defines the required elements for layout control
/// </summary>
public interface IHasCodecLayouts
{
StringFeedback LocalLayoutFeedback { get; }
void LocalLayoutToggle();
void LocalLayoutToggleSingleProminent();
void MinMaxLayoutToggle();
}
}

View File

@@ -0,0 +1,26 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Crestron.SimplSharp;
using PepperDash.Essentials.Core;
namespace PepperDash.Essentials.Devices.Core.VideoCodec
{
/// <summary>
/// Defines the requred elements for selfview control
/// </summary>
public interface IHasCodecSelfView
{
BoolFeedback SelfviewIsOnFeedback { get; }
bool ShowSelfViewByDefault { get; }
void SelfViewModeOn();
void SelfViewModeOff();
void SelfViewModeToggle();
}
}

View File

@@ -0,0 +1,32 @@
namespace PepperDash.Essentials.Core.Devices.VideoCodec
{
/// <summary>
/// For rooms that have video codec
/// </summary>
public interface IHasVideoCodec
{
VideoCodecBase VideoCodec { get; }
BoolFeedback InCallFeedback { get; }
///// <summary>
///// Make this more specific
///// </summary>
//List<PepperDash.Essentials.Devices.Common.Codec.CodecActiveCallItem> ActiveCalls { get; }
/// <summary>
/// States: 0 for on hook, 1 for video, 2 for audio, 3 for telekenesis
/// </summary>
IntFeedback CallTypeFeedback { get; }
/// <summary>
///
/// </summary>
BoolFeedback PrivacyModeIsOnFeedback { get; }
/// <summary>
/// When something in the room is sharing with the far end or through other means
/// </summary>
BoolFeedback IsSharingFeedback { get; }
}
}

View File

@@ -0,0 +1,30 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Crestron.SimplSharp;
namespace PepperDash.Essentials.Core.Devices.Codec
{
/// <summary>
/// Implements a common set of data about a codec
/// </summary>
public interface iVideoCodecInfo
{
VideoCodecInfo CodecInfo { get; }
}
/// <summary>
/// Stores general information about a codec
/// </summary>
public abstract class VideoCodecInfo
{
public abstract bool MultiSiteOptionIsEnabled { get; }
public abstract string IpAddress { get; }
public abstract string SipPhoneNumber { get; }
public abstract string E164Alias { get; }
public abstract string H323Id { get; }
public abstract string SipUri { get; }
public abstract bool AutoAnswerEnabled { get; }
}
}

View File

@@ -0,0 +1,323 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using PepperDash.Core;
using PepperDash.Essentials.Core.Config;
using PepperDash.Essentials.Core.Routing;
using PepperDash.Essentials.Core.Devices.Codec;
namespace PepperDash.Essentials.Core.Devices.VideoCodec
{
public abstract class VideoCodecBase : ReconfigurableDevice, IRoutingInputsOutputs,
IUsageTracking, IHasDialer, IHasContentSharing, ICodecAudio, iVideoCodecInfo
{
/// <summary>
/// Fires when the status of any active, dialing, or incoming call changes or is new
/// </summary>
public event EventHandler<CodecCallStatusItemChangeEventArgs> CallStatusChange;
public event EventHandler<EventArgs> IsReadyChange;
public IBasicCommunication Communication { get; protected set; }
#region IUsageTracking Members
/// <summary>
/// This object can be added by outside users of this class to provide usage tracking
/// for various services
/// </summary>
public UsageTracking UsageTracker { get; set; }
#endregion
/// <summary>
/// An internal pseudo-source that is routable and connected to the osd input
/// </summary>
public DummyRoutingInputsDevice OsdSource { get; protected set; }
public RoutingPortCollection<RoutingInputPort> InputPorts { get; private set; }
public RoutingPortCollection<RoutingOutputPort> OutputPorts { get; private set; }
/// <summary>
/// Returns true when any call is not in state Unknown, Disconnecting, Disconnected
/// </summary>
public bool IsInCall
{
get
{
bool value;
if (ActiveCalls != null)
value = ActiveCalls.Any(c => c.IsActiveCall);
else
value = false;
return value;
}
}
public BoolFeedback StandbyIsOnFeedback { get; private set; }
abstract protected Func<bool> PrivacyModeIsOnFeedbackFunc { get; }
abstract protected Func<int> VolumeLevelFeedbackFunc { get; }
abstract protected Func<bool> MuteFeedbackFunc { get; }
abstract protected Func<bool> StandbyIsOnFeedbackFunc { get; }
public List<CodecActiveCallItem> ActiveCalls { get; set; }
public VideoCodecInfo CodecInfo { get; protected set; }
public bool ShowSelfViewByDefault { get; protected set; }
public bool IsReady { get; protected set; }
public 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<RoutingInputPort>();
OutputPorts = new RoutingPortCollection<RoutingOutputPort>();
ActiveCalls = new List<CodecActiveCallItem>();
}
#region IHasDialer Members
public abstract void Dial(string number);
public abstract void Dial(Meeting meeting);
public virtual void Dial(IInvitableContact contact)
{
}
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
public virtual List<Feedback> Feedbacks
{
get
{
return new List<Feedback>
{
PrivacyModeIsOnFeedback,
SharingSourceFeedback
};
}
}
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)
{
call.Status = newStatus;
OnCallStatusChange(call);
}
/// <summary>
///
/// </summary>
/// <param name="previousStatus"></param>
/// <param name="newStatus"></param>
/// <param name="item"></param>
protected 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();
}
}
/// <summary>
/// Sets IsReady property and fires the event. Used for dependent classes to sync up their data.
/// </summary>
protected void SetIsReady()
{
IsReady = true;
var h = IsReadyChange;
if(h != null)
h(this, new EventArgs());
}
#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 IHasSharing 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; }
abstract protected Func<string> SharingSourceFeedbackFunc { get; }
abstract protected Func<bool> SharingContentIsOnFeedbackFunc { get; }
#endregion
// **** DEBUGGING THINGS ****
/// <summary>
///
/// </summary>
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();
}
/// <summary>
/// Used to track the status of syncronizing the phonebook values when connecting to a codec or refreshing the phonebook info
/// </summary>
public class CodecPhonebookSyncState : IKeyed
{
bool _InitialSyncComplete;
public event EventHandler<EventArgs> InitialSyncCompleted;
public string Key { 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 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; }
public CodecPhonebookSyncState(string key)
{
Key = key;
CodecDisconnected();
}
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;
}
void CheckSyncStatus()
{
if (InitialPhonebookFoldersWasReceived && NumberOfContactsWasReceived && PhonebookRootEntriesWasRecieved)
{
InitialSyncComplete = true;
Debug.Console(1, this, "Initial Phonebook Sync Complete!");
}
else
InitialSyncComplete = false;
}
}
}

View File

@@ -190,7 +190,26 @@
<Compile Include="Devices\PC\InRoomPc.cs" />
<Compile Include="Devices\PC\Laptop.cs" />
<Compile Include="Devices\ReconfigurableDevice.cs" />
<Compile Include="Devices\VideoCodecBase.cs" />
<Compile Include="Devices\VolumeDeviceChangeEventArgs.cs" />
<Compile Include="DeviceTypeInterfaces\Codec\CodecActiveCallItem.cs" />
<Compile Include="DeviceTypeInterfaces\Codec\eCodecCallDirection.cs" />
<Compile Include="DeviceTypeInterfaces\Codec\eCodecCallStatus.cs" />
<Compile Include="DeviceTypeInterfaces\Codec\eCodecCallType.cs" />
<Compile Include="DeviceTypeInterfaces\Codec\eMeetingPrivacy.cs" />
<Compile Include="DeviceTypeInterfaces\IAudioCodecInfo.cs" />
<Compile Include="DeviceTypeInterfaces\Codec\iCodecAudio.cs" />
<Compile Include="DeviceTypeInterfaces\IHasAudioCodec.cs" />
<Compile Include="DeviceTypeInterfaces\Codec\iHasCallFavorites.cs" />
<Compile Include="DeviceTypeInterfaces\Codec\iHasCallHistory.cs" />
<Compile Include="DeviceTypeInterfaces\IHasCodecLayouts.cs" />
<Compile Include="DeviceTypeInterfaces\IHasCodecSelfview.cs" />
<Compile Include="DeviceTypeInterfaces\Codec\iHasContentSharing.cs" />
<Compile Include="DeviceTypeInterfaces\Codec\iHasDialer.cs" />
<Compile Include="DeviceTypeInterfaces\Codec\iHasDirectory.cs" />
<Compile Include="DeviceTypeInterfaces\Codec\iHasScheduleAwareness.cs" />
<Compile Include="DeviceTypeInterfaces\IHasVideoCodec.cs" />
<Compile Include="DeviceTypeInterfaces\iVideoCodecInfo.cs" />
<Compile Include="Factory\DeviceFactory.cs" />
<Compile Include="Factory\IDeviceFactory.cs" />
<Compile Include="Feedbacks\BoolFeedback.cs" />
@@ -256,6 +275,7 @@
<Compile Include="Room\Config\EssentialsHuddleVtc1PropertiesConfig.cs" />
<Compile Include="Room\Config\EssentialsNDisplayRoomPropertiesConfig.cs" />
<Compile Include="Room\Config\EssentialsPresentationPropertiesConfig.cs" />
<Compile Include="Room\Config\EssentialsVolumeLevelConfig.cs" />
<Compile Include="Room\Emergency\EsentialsRoomEmergencyContactClosure.cs" />
<Compile Include="Room\EssentialsRoomBase.cs" />
<Compile Include="Room\Config\EssentialsRoomConfig.cs" />

View File

@@ -1,12 +1,12 @@
using Newtonsoft.Json;
using PepperDash.Essentials.Core.Config;
namespace PepperDash.Essentials.Core.Rooms.Config
{
public class EssentialsHuddleVtc1PropertiesConfig : EssentialsConferenceRoomPropertiesConfig
public class EssentialsHuddleVtc1PropertiesConfig : EssentialsHuddleRoomPropertiesConfig
{
[JsonProperty("defaultDisplayKey")]
public string DefaultDisplayKey { get; set; }
[JsonProperty("videoCodecKey")]
public string VideoCodecKey { get; set; }
[JsonProperty("audioCodecKey")]
public string AudioCodecKey { get; set; }
}
}

View File

@@ -4,6 +4,7 @@ using Newtonsoft.Json;
using PepperDash.Core;
using PepperDash.Essentials.Core.Config;
using PepperDash.Essentials.Core.Privacy;
namespace PepperDash.Essentials.Core.Rooms.Config
{
@@ -16,30 +17,32 @@ namespace PepperDash.Essentials.Core.Rooms.Config
public static Device GetRoomObject(DeviceConfig roomConfig)
{
var typeName = roomConfig.Type.ToLower();
EssentialsRoomBase rm;
if (typeName == "huddle")
{
var huddle = new EssentialsHuddleSpaceRoom(roomConfig);
return huddle;
}
else if (typeName == "huddlevtc1")
{
var rm = new EssentialsHuddleVtc1Room(roomConfig);
if (typeName == "huddlevtc1")
{
rm = new EssentialsHuddleVtc1Room(roomConfig);
return rm;
}
else if (typeName == "ddvc01Bridge")
{
return new Device(roomConfig.Key, roomConfig.Name); // placeholder device that does nothing.
}
else if (typeName == "dualdisplay")
{
var rm = new EssentialsDualDisplayRoom(roomConfig);
return rm;
}
if (typeName == "ddvc01Bridge")
{
return new Device(roomConfig.Key, roomConfig.Name); // placeholder device that does nothing.
}
if (typeName != "dualdisplay")
{
return null;
}
return rm;
}
rm = new EssentialsDualDisplayRoom(roomConfig);
return null;
return rm;
}
/// <summary>
@@ -50,12 +53,14 @@ namespace PepperDash.Essentials.Core.Rooms.Config
{
// This emergency
var emergency = props.Emergency;
if (emergency != null)
if (emergency == null)
{
//switch on emergency type here. Right now only contact and shutdown
var e = new EssentialsRoomEmergencyContactClosure(room.Key + "-emergency", props.Emergency, room);
DeviceManager.AddDevice(e);
return null;
}
//switch on emergency type here. Right now only contact and shutdown
var e = new EssentialsRoomEmergencyContactClosure(room.Key + "-emergency", props.Emergency, room);
DeviceManager.AddDevice(e);
return null;
}
@@ -65,7 +70,7 @@ namespace PepperDash.Essentials.Core.Rooms.Config
/// <param name="props"></param>
/// <param name="room"></param>
/// <returns></returns>
public static Core.Privacy.MicrophonePrivacyController GetMicrophonePrivacy(
public static MicrophonePrivacyController GetMicrophonePrivacy(
EssentialsRoomPropertiesConfig props, IPrivacy room)
{
var microphonePrivacy = props.MicrophonePrivacy;
@@ -76,7 +81,7 @@ namespace PepperDash.Essentials.Core.Rooms.Config
}
// Get the MicrophonePrivacy device from the device manager
var mP = (DeviceManager.GetDeviceForKey(props.MicrophonePrivacy.DeviceKey) as
Core.Privacy.MicrophonePrivacyController);
MicrophonePrivacyController);
// Set this room as the IPrivacy device
if (mP == null)
{
@@ -92,33 +97,38 @@ namespace PepperDash.Essentials.Core.Rooms.Config
Debug.Console(0, "WARNING: No behaviour defined for MicrophonePrivacyController");
return null;
}
if (behaviour == "trackroomstate")
switch (behaviour)
{
// Tie LED enable to room power state
var essRoom = room as EssentialsRoomBase;
essRoom.OnFeedback.OutputChange += (o, a) =>
{
if (essRoom.OnFeedback.BoolValue)
mP.EnableLeds = true;
else
mP.EnableLeds = false;
};
case "trackroomstate":
{
// Tie LED enable to room power state
var essRoom = room as EssentialsRoomBase;
if (essRoom != null)
{
essRoom.OnFeedback.OutputChange += (o, a) =>
{
mP.EnableLeds = essRoom.OnFeedback.BoolValue;
};
mP.EnableLeds = essRoom.OnFeedback.BoolValue;
}
else if (behaviour == "trackcallstate")
{
// Tie LED enable to room power state
var inCallRoom = room as IHasInCallFeedback;
inCallRoom.InCallFeedback.OutputChange += (o, a) =>
{
if (inCallRoom.InCallFeedback.BoolValue)
mP.EnableLeds = true;
else
mP.EnableLeds = false;
};
mP.EnableLeds = essRoom.OnFeedback.BoolValue;
}
}
break;
case "trackcallstate":
{
// Tie LED enable to room power state
var inCallRoom = room as IHasInCallFeedback;
if (inCallRoom != null)
{
inCallRoom.InCallFeedback.OutputChange += (o, a) =>
{
mP.EnableLeds = inCallRoom.InCallFeedback.BoolValue;
};
mP.EnableLeds = inCallRoom.InCallFeedback.BoolValue;
mP.EnableLeds = inCallRoom.InCallFeedback.BoolValue;
}
}
break;
}
return mP;
@@ -177,25 +187,6 @@ namespace PepperDash.Essentials.Core.Rooms.Config
public bool ZeroVolumeWhenSwtichingVolumeDevices { get; set; }
}
public class EssentialsAvRoomPropertiesConfig : EssentialsRoomPropertiesConfig
{
[JsonProperty("defaultAudioKey")]
public string DefaultAudioKey { get; set; }
[JsonProperty("sourceListKey")]
public string SourceListKey { get; set; }
[JsonProperty("defaultSourceItem")]
public string DefaultSourceItem { get; set; }
}
public class EssentialsConferenceRoomPropertiesConfig : EssentialsAvRoomPropertiesConfig
{
[JsonProperty("videoCodecKey")]
public string VideoCodecKey { get; set; }
[JsonProperty("audioCodecKey")]
public string AudioCodecKey { get; set; }
}
public class EssentialsEnvironmentPropertiesConfig
{
public bool Enabled { get; set; }

View File

@@ -0,0 +1,64 @@
namespace PepperDash.Essentials
{
/// <summary>
///
/// </summary>
public class EssentialsRoomVolumesConfig
{
public EssentialsVolumeLevelConfig Master { get; set; }
public EssentialsVolumeLevelConfig Program { get; set; }
public EssentialsVolumeLevelConfig AudioCallRx { get; set; }
public EssentialsVolumeLevelConfig AudioCallTx { get; set; }
}
/// <summary>
///
/// </summary>
public class EssentialsVolumeLevelConfig
{
public string DeviceKey { get; set; }
public string Label { get; set; }
public int Level { get; set; }
/*
/// <summary>
/// Helper to get the device associated with key - one timer.
/// </summary>
public IBasicVolumeWithFeedback GetDevice()
{
// DM output card format: deviceKey--output~number, dm8x8-1--output~4
var match = Regex.Match(DeviceKey, @"([-_\w]+)--(\w+)~(\d+)");
if (match.Success)
{
var devKey = match.Groups[1].Value;
var chassis = DeviceManager.GetDeviceForKey(devKey) as DmChassisController;
if (chassis != null)
{
var outputNum = Convert.ToUInt32(match.Groups[3].Value);
if (chassis.VolumeControls.ContainsKey(outputNum)) // should always...
return chassis.VolumeControls[outputNum];
}
// No volume for some reason. We have failed as developers
return null;
}
// DSP format: deviceKey--levelName, biampTesira-1--master
match = Regex.Match(DeviceKey, @"([-_\w]+)--(.+)");
if (match.Success)
{
var devKey = match.Groups[1].Value;
var dsp = DeviceManager.GetDeviceForKey(devKey) as BiampTesiraForteDsp;
if (dsp != null)
{
var levelTag = match.Groups[2].Value;
if (dsp.LevelControlPoints.ContainsKey(levelTag)) // should always...
return dsp.LevelControlPoints[levelTag];
}
// No volume for some reason. We have failed as developers
return null;
}
return null;
}*/
}
}

View File

@@ -4,7 +4,7 @@ using System.Linq;
using System.Text;
using Crestron.SimplSharp;
namespace PepperDash.Essentials.Core
namespace PepperDash.Essentials.Core.Rooms
{
/// <summary>
/// For rooms with in call feedback

View File

@@ -8,7 +8,7 @@ using PepperDash.Core;
using PepperDash.Essentials.Core;
using PepperDash.Essentials.Core.Config;
using PepperDash.Essentials.Room.Config;
using PepperDash.Essentials.Devices.Common.Codec;
using PepperDash.Essentials.Core.Devices.Codec;
using PepperDash.Essentials.Devices.Common.VideoCodec;
using PepperDash.Essentials.Devices.Common.AudioCodec;

View File

@@ -7,10 +7,8 @@ using Newtonsoft.Json;
using PepperDash.Core;
using PepperDash.Essentials.Core;
using PepperDash.Essentials.Core.Config;
using PepperDash.Essentials.Room.Config;
using PepperDash.Essentials.Devices.Common.Codec;
using PepperDash.Essentials.Devices.Common.VideoCodec;
using PepperDash.Essentials.Devices.Common.AudioCodec;
using PepperDash.Essentials.Core.Rooms;
using PepperDash.Essentials.Core.Rooms.Config;
namespace PepperDash.Essentials
{
@@ -50,56 +48,16 @@ namespace PepperDash.Essentials
public EssentialsHuddleVtc1PropertiesConfig PropertiesConfig { get; private set; }
public IRoutingSinkWithSwitching DefaultDisplay { get; private set; }
public IBasicVolumeControls DefaultAudioDevice { get; private set; }
public IBasicVolumeControls DefaultVolumeControls { get; private set; }
public VideoCodecBase VideoCodec { get; private set; }
public AudioCodecBase AudioCodec { get; private set; }
public bool ExcludeFromGlobalFunctions { get; set; }
public string DefaultSourceItem { get; set; }
public ushort DefaultVolume { get; set; }
/// <summary>
/// If room is off, enables power on to last source. Default true
/// </summary>
public bool EnablePowerOnToLastSource { get; set; }
private string _lastSourceKey;
/// <summary>
/// The SourceListItem last run - containing names and icons
/// </summary>
public SourceListItem CurrentSourceInfo
{
get { return _currentSourceInfo; }
set
{
if (value == _currentSourceInfo) return;
var handler = CurrentSourceChange;
// remove from in-use tracker, if so equipped
if(_currentSourceInfo != null && _currentSourceInfo.SourceDevice is IInUseTracking)
(_currentSourceInfo.SourceDevice as IInUseTracking).InUseTracker.RemoveUser(this, "control");
if (handler != null)
handler(_currentSourceInfo, ChangeType.WillChange);
_currentSourceInfo = value;
// add to in-use tracking
if (_currentSourceInfo != null && _currentSourceInfo.SourceDevice is IInUseTracking)
(_currentSourceInfo.SourceDevice as IInUseTracking).InUseTracker.AddUser(this, "control");
if (handler != null)
handler(_currentSourceInfo, ChangeType.DidChange);
}
}
private SourceListItem _currentSourceInfo;
public string CurrentSourceInfoKey { get; set; }
/// <summary>
/// "codecOsd"