Compare commits

...

42 Commits

Author SHA1 Message Date
Andrew Welker
c452ef90bb add QR checksum back 2020-11-20 12:40:33 -07:00
Andrew Welker
f3ddce99d5 got it building... 2020-11-19 14:16:34 -07:00
Andrew Welker
ef215e8b16 more updates 2020-11-19 12:11:23 -07:00
Andrew Welker
19f39d7373 more updates and moves 2020-11-19 12:11:12 -07:00
Andrew Welker
58f88037f5 getting project files correct 2020-11-19 10:58:38 -07:00
Andrew Welker
8821bffee7 more moving things 2020-11-19 10:57:08 -07:00
Andrew Welker
63bd25c0e1 moving things around 2020-11-19 10:57:00 -07:00
Andrew Welker
febef3f5b1 getting closer... 2020-11-19 10:52:47 -07:00
Andrew Welker
e3d9f6be6e getting refs right 2020-11-19 10:48:43 -07:00
Andrew Welker
d18a099fe4 fixing cisco class 2020-11-19 10:00:20 -07:00
Andrew Welker
64c233e36b fixing things 2020-11-19 09:56:48 -07:00
Andrew Welker
8244b6f02f add missing files 2020-11-19 09:44:56 -07:00
Andrew Welker
c2ee9be9fe add files that didn't come through in the rebase 2020-11-19 09:14:40 -07:00
Andrew Welker
89952f3d37 fixing some namespace issues 2020-11-19 09:13:34 -07:00
Andrew Welker
7b3ef897fb updates to get things back working 2020-11-19 08:00:17 -07:00
Andrew Welker
97995df962 refactoring and cleanup 2020-11-18 15:37:08 -07:00
Andrew Welker
c1381acc92 made config publicly accessible 2020-11-18 15:25:02 -07:00
Andrew Welker
edb3c70d27 add comm monitor for fusion stuff 2020-11-18 15:25:02 -07:00
Andrew Welker
21b8a86d21 getting asset created 2020-11-18 15:25:02 -07:00
Andrew Welker
374ce13add updates for dual-display Fusion 2020-11-18 15:25:02 -07:00
Andrew Welker
3856a96e5f add dual display fusion controller 2020-11-18 15:25:01 -07:00
Andrew Welker
6b8aa0afe6 refactoring Fusion room classes
added DualDisplay Fusion support
2020-11-18 15:23:27 -07:00
Andrew Welker
153c7f2409 add dual display room and config 2020-11-18 15:14:23 -07:00
Andrew Welker
4fa9e6ba17 modify VTC1 room class to work with modified base class 2020-11-18 15:14:23 -07:00
Andrew Welker
c5b51c8976 renamed room folder -> rooms 2020-11-18 15:14:23 -07:00
Andrew Welker
6d27faa918 renamed room -> rooms
started on Dual Display room;
2020-11-18 15:14:23 -07:00
Andrew Welker
7a1aec5dfc files moving around 2020-11-18 15:14:22 -07:00
Andrew Welker
3262b491c9 reorganizing devices folder 2020-11-18 15:11:40 -07:00
Andrew Welker
cb4a8640f0 Got things moved successfully 2020-11-18 15:11:39 -07:00
Andrew Welker
fcb2f88be7 moving interfaces and base classes into Core from Devices Common
maybe too far down the rabbit hole?
2020-11-18 15:07:55 -07:00
Andrew Welker
6f5a4f17fa refactoring and more refactoring 2020-11-18 14:45:21 -07:00
Andrew Welker
c5aa8d29cb refactoring room classes 2020-11-18 14:38:13 -07:00
Andrew Welker
18a362f979 temporarily suppressing some compile errors 2020-11-18 14:37:03 -07:00
Andrew Welker
20257e425e Refactoring things to base class 2020-11-18 14:37:03 -07:00
Andrew Welker
38adaf623f update config with DestinationList 2020-11-18 14:32:53 -07:00
Andrew Welker
6f300402aa added classes for support of destination lists in configuration. 2020-11-18 14:32:52 -07:00
Andrew Welker
f01ed3d876 some refactoring and formatting 2020-11-18 14:32:52 -07:00
Andrew Welker
878e5ab9fb refactoring and cleanup 2020-11-18 14:32:52 -07:00
Andrew Welker
43e39a5222 refactoring and cleanup 2020-11-18 14:32:28 -07:00
Andrew Welker
e84423eb64 cleanup VtcRoom 2020-11-18 14:30:46 -07:00
Andrew Welker
013bcfd9d4 Cleanup for EssentialHuddleSpaceRoom 2020-11-18 14:29:36 -07:00
Andrew Welker
78f4cd6abe Cleanup for EssentialsRoomBase 2020-11-18 14:29:00 -07:00
128 changed files with 8353 additions and 3134 deletions

View File

@@ -12,10 +12,10 @@ using PepperDash.Core;
using PepperDash.Essentials.Core;
using PepperDash.Essentials.Core.Bridges;
using PepperDash.Essentials.Core.Config;
using PepperDash.Essentials.Core.Fusion;
using PepperDash.Essentials.Core.Rooms.Config;
using PepperDash.Essentials.Devices.Common;
using PepperDash.Essentials.DM;
using PepperDash.Essentials.Fusion;
using PepperDash.Essentials.Room.Config;
using Newtonsoft.Json;
using PepperDash.Essentials.Core.DeviceTypeInterfaces;

View File

@@ -0,0 +1,574 @@
using System;
using System.Collections.Generic;
using System.Linq;
using Crestron.SimplSharp;
using Crestron.SimplSharp.CrestronIO;
using Crestron.SimplSharpPro;
using Crestron.SimplSharpPro.CrestronThread;
using Crestron.SimplSharpPro.Diagnostics;
using Crestron.SimplSharp.Reflection;
using PepperDash.Core;
using PepperDash.Essentials.Core;
using PepperDash.Essentials.Core.Bridges;
using PepperDash.Essentials.Core.Config;
using PepperDash.Essentials.Core.Rooms.Config;
using PepperDash.Essentials.DM;
using PepperDash.Essentials.Fusion;
using PepperDash.Essentials.Room.Config;
using Newtonsoft.Json;
using PepperDash.Essentials.Core.DeviceTypeInterfaces;
using EssentialsRoomConfigHelper = PepperDash.Essentials.Core.Rooms.Config.EssentialsRoomConfigHelper;
namespace PepperDash.Essentials
{
public class ControlSystem : CrestronControlSystem
{
HttpLogoServer LogoServer;
private CTimer _startTimer;
private const long StartupTime = 500;
public ControlSystem()
: base()
{
Thread.MaxNumberOfUserThreads = 400;
Global.ControlSystem = this;
DeviceManager.Initialize(this);
SystemMonitor.ProgramInitialization.ProgramInitializationUnderUserControl = true;
}
/// <summary>
/// Entry point for the program
/// </summary>
public override void InitializeSystem()
{
_startTimer = new CTimer(StartSystem,StartupTime);
}
private void StartSystem(object obj)
{
DeterminePlatform();
if (Debug.DoNotLoadOnNextBoot)
{
CrestronConsole.AddNewConsoleCommand(s => GoWithLoad(), "go", "Loads configuration file",
ConsoleAccessLevelEnum.AccessOperator);
}
CrestronConsole.AddNewConsoleCommand(PluginLoader.ReportAssemblyVersions, "reportversions", "Reports the versions of the loaded assemblies", ConsoleAccessLevelEnum.AccessOperator);
CrestronConsole.AddNewConsoleCommand(PepperDash.Essentials.Core.DeviceFactory.GetDeviceFactoryTypes, "gettypes", "Gets the device types that can be built. Accepts a filter string.", ConsoleAccessLevelEnum.AccessOperator);
CrestronConsole.AddNewConsoleCommand(BridgeHelper.PrintJoinMap, "getjoinmap", "map(s) for bridge or device on bridge [brKey [devKey]]", ConsoleAccessLevelEnum.AccessOperator);
CrestronConsole.AddNewConsoleCommand(s =>
{
Debug.Console(0, Debug.ErrorLogLevel.Notice, "CONSOLE MESSAGE: {0}", s);
}, "appdebugmessage", "Writes message to log", ConsoleAccessLevelEnum.AccessOperator);
CrestronConsole.AddNewConsoleCommand(s =>
{
foreach (var tl in TieLineCollection.Default)
CrestronConsole.ConsoleCommandResponse(" {0}\r", tl);
},
"listtielines", "Prints out all tie lines", ConsoleAccessLevelEnum.AccessOperator);
CrestronConsole.AddNewConsoleCommand(s =>
{
CrestronConsole.ConsoleCommandResponse
("Current running configuration. This is the merged system and template configuration");
CrestronConsole.ConsoleCommandResponse(Newtonsoft.Json.JsonConvert.SerializeObject
(ConfigReader.ConfigObject, Newtonsoft.Json.Formatting.Indented));
}, "showconfig", "Shows the current running merged config", ConsoleAccessLevelEnum.AccessOperator);
CrestronConsole.AddNewConsoleCommand(s =>
{
CrestronConsole.ConsoleCommandResponse("This system can be found at the following URLs:\r" +
"System URL: {0}\r" +
"Template URL: {1}", ConfigReader.ConfigObject.SystemUrl, ConfigReader.ConfigObject.TemplateUrl);
}, "portalinfo", "Shows portal URLS from configuration", ConsoleAccessLevelEnum.AccessOperator);
CrestronConsole.AddNewConsoleCommand(DeviceManager.GetRoutingPorts,
"getroutingports", "Reports all routing ports, if any. Requires a device key", ConsoleAccessLevelEnum.AccessOperator);
if (!Debug.DoNotLoadOnNextBoot)
{
GoWithLoad();
return;
}
SystemMonitor.ProgramInitialization.ProgramInitializationComplete = true;
}
/// <summary>
/// Determines if the program is running on a processor (appliance) or server (VC-4).
///
/// Sets Global.FilePathPrefix and Global.ApplicationDirectoryPathPrefix based on platform
/// </summary>
public void DeterminePlatform()
{
try
{
Debug.Console(0, Debug.ErrorLogLevel.Notice, "Determining Platform....");
string filePathPrefix;
var dirSeparator = Global.DirectorySeparator;
string directoryPrefix;
directoryPrefix = Crestron.SimplSharp.CrestronIO.Directory.GetApplicationRootDirectory();
var fullVersion = Assembly.GetExecutingAssembly().GetCustomAttributes(typeof(AssemblyInformationalVersionAttribute), false);
AssemblyInformationalVersionAttribute fullVersionAtt = fullVersion[0] as AssemblyInformationalVersionAttribute;
Global.SetAssemblyVersion(fullVersionAtt.InformationalVersion);
if (CrestronEnvironment.DevicePlatform != eDevicePlatform.Server) // Handles 3-series running Windows CE OS
{
Debug.Console(0, Debug.ErrorLogLevel.Notice, "Starting Essentials v{0} on 3-series Appliance", Global.AssemblyVersion);
// Check if User/ProgramX exists
if (Directory.Exists(Global.ApplicationDirectoryPathPrefix + dirSeparator + "User"
+ dirSeparator + string.Format("program{0}", InitialParametersClass.ApplicationNumber)))
{
Debug.Console(0, @"User/program{0} directory found", InitialParametersClass.ApplicationNumber);
filePathPrefix = directoryPrefix + dirSeparator + "User"
+ dirSeparator + string.Format("program{0}", InitialParametersClass.ApplicationNumber) + dirSeparator;
}
// Check if Nvram/Programx exists
else if (Directory.Exists(directoryPrefix + dirSeparator + "Nvram"
+ dirSeparator + string.Format("program{0}", InitialParametersClass.ApplicationNumber)))
{
Debug.Console(0, @"Nvram/program{0} directory found", InitialParametersClass.ApplicationNumber);
filePathPrefix = directoryPrefix + dirSeparator + "Nvram"
+ dirSeparator + string.Format("program{0}", InitialParametersClass.ApplicationNumber) + dirSeparator;
}
// If neither exists, set path to User/ProgramX
else
{
Debug.Console(0, @"No previous directory found. Using User/program{0}", InitialParametersClass.ApplicationNumber);
filePathPrefix = directoryPrefix + dirSeparator + "User"
+ dirSeparator + string.Format("program{0}", InitialParametersClass.ApplicationNumber) + dirSeparator;
}
}
else // Handles Linux OS (Virtual Control)
{
Debug.Console(0, Debug.ErrorLogLevel.Notice, "Starting Essentials v{0} on Virtual Control Server", Global.AssemblyVersion);
// Set path to User/
filePathPrefix = directoryPrefix + dirSeparator + "User" + dirSeparator;
}
Global.SetFilePathPrefix(filePathPrefix);
}
catch (Exception e)
{
Debug.Console(0, "Unable to Determine Platform due to Exception: {0}", e.Message);
}
}
/// <summary>
/// Begins the process of loading resources including plugins and configuration data
/// </summary>
public void GoWithLoad()
{
try
{
Debug.SetDoNotLoadOnNextBoot(false);
PluginLoader.AddProgramAssemblies();
new Core.DeviceFactory();
new Devices.Common.DeviceFactory();
new DM.DeviceFactory();
new DeviceFactory();
Debug.Console(0, Debug.ErrorLogLevel.Notice, "Starting Essentials load from configuration");
var filesReady = SetupFilesystem();
if (filesReady)
{
Debug.Console(0, Debug.ErrorLogLevel.Notice, "Checking for plugins");
PluginLoader.LoadPlugins();
Debug.Console(0, Debug.ErrorLogLevel.Notice, "Folder structure verified. Loading config...");
if (!ConfigReader.LoadConfig2())
{
Debug.Console(0, Debug.ErrorLogLevel.Error, "Essentials Load complete with errors");
return;
}
Load();
Debug.Console(0, Debug.ErrorLogLevel.Notice, "Essentials load complete\r\n" +
"-------------------------------------------------------------");
}
else
{
Debug.Console(0,
@"----------------------------------------------
------------------------------------------------
------------------------------------------------
Essentials file structure setup completed.
Please load config, sgd and ir files and
restart program.
------------------------------------------------
------------------------------------------------
------------------------------------------------");
}
}
catch (Exception e)
{
Debug.Console(0, "FATAL INITIALIZE ERROR. System is in an inconsistent state:\r\n{0}", e);
}
finally
{
// Notify the OS that the program intitialization has completed
SystemMonitor.ProgramInitialization.ProgramInitializationComplete = true;
}
}
/// <summary>
/// Verifies filesystem is set up. IR, SGD, and programX folders
/// </summary>
bool SetupFilesystem()
{
Debug.Console(0, "Verifying and/or creating folder structure");
var configDir = Global.FilePathPrefix;
var configExists = Directory.Exists(configDir);
if (!configExists)
Directory.Create(configDir);
var irDir = Global.FilePathPrefix + "ir";
if (!Directory.Exists(irDir))
Directory.Create(irDir);
var sgdDir = Global.FilePathPrefix + "sgd";
if (!Directory.Exists(sgdDir))
Directory.Create(sgdDir);
var pluginDir = Global.FilePathPrefix + "plugins";
if (!Directory.Exists(pluginDir))
Directory.Create(pluginDir);
return configExists;
}
/// <summary>
///
/// </summary>
public void TearDown()
{
Debug.Console(0, "Tearing down existing system");
DeviceManager.DeactivateAll();
TieLineCollection.Default.Clear();
foreach (var key in DeviceManager.GetDevices())
DeviceManager.RemoveDevice(key);
Debug.Console(0, "Tear down COMPLETE");
}
/// <summary>
///
/// </summary>
void Load()
{
LoadDevices();
LoadTieLines();
LoadRooms();
LoadLogoServer();
DeviceManager.ActivateAll();
var mobileControl = GetMobileControlDevice();
if (mobileControl == null) return;
mobileControl.LinkSystemMonitorToAppServer();
}
/// <summary>
/// Reads all devices from config and adds them to DeviceManager
/// </summary>
public void LoadDevices()
{
// Build the processor wrapper class
DeviceManager.AddDevice(new PepperDash.Essentials.Core.Devices.CrestronProcessor("processor"));
// Add global System Monitor device
if (CrestronEnvironment.DevicePlatform == eDevicePlatform.Appliance)
{
DeviceManager.AddDevice(
new PepperDash.Essentials.Core.Monitoring.SystemMonitorController("systemMonitor"));
}
foreach (var devConf in ConfigReader.ConfigObject.Devices)
{
try
{
Debug.Console(0, Debug.ErrorLogLevel.Notice, "Creating device '{0}', type '{1}'", devConf.Key, devConf.Type);
// Skip this to prevent unnecessary warnings
if (devConf.Key == "processor")
{
if (devConf.Type.ToLower() != Global.ControlSystem.ControllerPrompt.ToLower())
Debug.Console(0,
"WARNING: Config file defines processor type as '{0}' but actual processor is '{1}'! Some ports may not be available",
devConf.Type.ToUpper(), Global.ControlSystem.ControllerPrompt.ToUpper());
// Check if the processor is a DMPS model
if (this.ControllerPrompt.IndexOf("dmps", StringComparison.OrdinalIgnoreCase) > -1)
{
Debug.Console(2, "Adding DmpsRoutingController for {0} to Device Manager.", this.ControllerPrompt);
var propertiesConfig = JsonConvert.DeserializeObject<DM.Config.DmpsRoutingPropertiesConfig>(devConf.Properties.ToString());
if(propertiesConfig == null)
propertiesConfig = new DM.Config.DmpsRoutingPropertiesConfig();
var dmpsRoutingController = DmpsRoutingController.GetDmpsRoutingController("processor-avRouting", this.ControllerPrompt, propertiesConfig);
DeviceManager.AddDevice(dmpsRoutingController);
}
else if (this.ControllerPrompt.IndexOf("mpc3", StringComparison.OrdinalIgnoreCase) > -1)
{
Debug.Console(2, "MPC3 processor type detected. Adding Mpc3TouchpanelController.");
var butToken = devConf.Properties["buttons"];
if (butToken != null)
{
var buttons = butToken.ToObject<Dictionary<string, Essentials.Core.Touchpanels.KeypadButton>>();
var tpController = new Essentials.Core.Touchpanels.Mpc3TouchpanelController(devConf.Key, devConf.Name, Global.ControlSystem, buttons);
DeviceManager.AddDevice(tpController);
}
else
{
Debug.Console(0, Debug.ErrorLogLevel.Error, "Error: Unable to deserialize buttons collection for device: {0}", devConf.Key);
}
}
else
{
Debug.Console(2, "************Processor is not DMPS type***************");
}
continue;
}
// Try local factories first
IKeyed newDev = null;
if (newDev == null)
newDev = PepperDash.Essentials.Core.DeviceFactory.GetDevice(devConf);
if (newDev != null)
DeviceManager.AddDevice(newDev);
else
Debug.Console(0, Debug.ErrorLogLevel.Notice, "ERROR: Cannot load unknown device type '{0}', key '{1}'.", devConf.Type, devConf.Key);
}
catch (Exception e)
{
Debug.Console(0, Debug.ErrorLogLevel.Notice, "ERROR: Creating device {0}. Skipping device. \r{1}", devConf.Key, e);
}
}
Debug.Console(0, Debug.ErrorLogLevel.Notice, "All Devices Loaded.");
}
/// <summary>
/// Helper method to load tie lines. This should run after devices have loaded
/// </summary>
public void LoadTieLines()
{
// In the future, we can't necessarily just clear here because devices
// might be making their own internal sources/tie lines
var tlc = TieLineCollection.Default;
//tlc.Clear();
if (ConfigReader.ConfigObject.TieLines == null)
{
return;
}
foreach (var tieLineConfig in ConfigReader.ConfigObject.TieLines)
{
var newTL = tieLineConfig.GetTieLine();
if (newTL != null)
tlc.Add(newTL);
}
Debug.Console(0, Debug.ErrorLogLevel.Notice, "All Tie Lines Loaded.");
}
/// <summary>
/// Reads all rooms from config and adds them to DeviceManager
/// </summary>
public void LoadRooms()
{
if (ConfigReader.ConfigObject.Rooms == null)
{
Debug.Console(0, Debug.ErrorLogLevel.Notice, "Notice: Configuration contains no rooms - Is this intentional? This may be a valid configuration.");
return;
}
foreach (var roomConfig in ConfigReader.ConfigObject.Rooms)
{
var room = EssentialsRoomConfigHelper.GetRoomObject(roomConfig) as EssentialsRoomBase;
if (room == null)
{
Debug.Console(0, Debug.ErrorLogLevel.Notice, "WARNING: Cannot create room from config, key '{0}'", roomConfig.Key);'
return;
}
var huddleRoom = room as EssentialsHuddleSpaceRoom;
var vtcRoom = room as EssentialsHuddleVtc1Room;
if (huddleRoom != null)
{
DeviceManager.AddDevice(huddleRoom);
Debug.Console(0, Debug.ErrorLogLevel.Notice, "Attempting to build Mobile Control Bridge...");
CreateMobileControlBridge(room);
}
else if (room is EssentialsHuddleVtc1Room)
{
DeviceManager.AddDevice(room);
Debug.Console(0, Debug.ErrorLogLevel.Notice, "Attempting to build Mobile Control Bridge...");
// Mobile Control bridge
var bridge = new MobileControlEssentialsHuddleSpaceRoomBridge(huddleRoom);
AddBridgePostActivationHelper(bridge); // Lets things happen later when all devices are present
DeviceManager.AddDevice(bridge);
Debug.Console(0, Debug.ErrorLogLevel.Notice, "Attempting to build Mobile Control Bridge...");
CreateMobileControlBridge(room);
}
else
{
Debug.Console(0, Debug.ErrorLogLevel.Notice, "Room is NOT EssentialsRoom, attempting to add to DeviceManager w/o Fusion");
DeviceManager.AddDevice(room);
}
Debug.Console(0, Debug.ErrorLogLevel.Notice, "Room is EssentialsHuddleVtc1Room, attempting to add to DeviceManager with Fusion");
DeviceManager.AddDevice(new EssentialsHuddleVtc1FusionController(vtcRoom, 0xf1));
Debug.Console(0, Debug.ErrorLogLevel.Notice, "Attempting to build Mobile Control Bridge...");
// Mobile Control bridge
var bridge = new MobileControlEssentialsHuddleSpaceRoomBridge(room);
AddBridgePostActivationHelper(bridge); // Lets things happen later when all devices are present
DeviceManager.AddDevice(bridge);
continue;
}
else
Debug.Console(0, Debug.ErrorLogLevel.Notice, "Notice: Cannot create room from config, key '{0}' - Is this intentional? This may be a valid configuration.", roomConfig.Key);
}
Debug.Console(0, Debug.ErrorLogLevel.Notice, "All Rooms Loaded.");
}
private static void CreateMobileControlBridge(EssentialsRoomBase room)
{
var mobileControl = GetMobileControlDevice();
if (mobileControl == null) return;
mobileControl.CreateMobileControlRoomBridge(room, mobileControl);
Debug.Console(0, Debug.ErrorLogLevel.Notice, "Mobile Control Bridge Added...");
}
private static IMobileControl GetMobileControlDevice()
{
var mobileControlList = DeviceManager.AllDevices.OfType<IMobileControl>().ToList();
if (mobileControlList.Count > 1)
{
Debug.Console(0, Debug.ErrorLogLevel.Warning,
"Multiple instances of Mobile Control Server found.");
return null;
}
if (mobileControlList.Count > 0)
{
return mobileControlList[0];
}
Debug.Console(0, Debug.ErrorLogLevel.Notice, "Mobile Control not enabled for this system");
return null;
}
/// <summary>
/// Fires up a logo server if not already running
/// </summary>
void LoadLogoServer()
{
if (ConfigReader.ConfigObject.Rooms == null)
{
Debug.Console(0, Debug.ErrorLogLevel.Notice, "No rooms configured. Bypassing Logo server startup.");
return;
}
if (
!ConfigReader.ConfigObject.Rooms.Any(
CheckRoomConfig))
{
Debug.Console(0, Debug.ErrorLogLevel.Notice, "No rooms configured to use system Logo server. Bypassing Logo server startup");
return;
}
try
{
LogoServer = new HttpLogoServer(8080, Global.DirectorySeparator + "html" + Global.DirectorySeparator + "logo");
}
catch (Exception)
{
Debug.Console(0, Debug.ErrorLogLevel.Notice, "NOTICE: Logo server cannot be started. Likely already running in another program");
}
}
private bool CheckRoomConfig(DeviceConfig c)
{
string logoDark = null;
string logoLight = null;
string logo = null;
if (c.Properties["logoDark"] != null)
{
logoDark = c.Properties["logoDark"].Value<string>("type");
}
if (c.Properties["logoLight"] != null)
{
logoLight = c.Properties["logoLight"].Value<string>("type");
}
if (c.Properties["logo"] != null)
{
logo = c.Properties["logo"].Value<string>("type");
}
return ((logoDark != null && logoDark == "system") ||
(logoLight != null && logoLight == "system") || (logo != null && logo == "system"));
}
}
}

View File

@@ -11,7 +11,7 @@ using PepperDash.Essentials.Core.Routing;
namespace PepperDash.Essentials
{
public class Amplifier : EssentialsDevice, IRoutingSinkNoSwitching
public class Amplifier : EssentialsDevice, IRoutingSink
{
public event SourceInfoChangeHandler CurrentSourceChange;

View File

@@ -1,359 +1,429 @@
using System;
using System.Linq;
using Crestron.SimplSharp;
using Crestron.SimplSharpPro;
using Crestron.SimplSharpPro.Fusion;
using PepperDash.Core;
using PepperDash.Essentials.Core;
using PepperDash.Essentials.Core.Config;
using PepperDash.Essentials.Core.Fusion;
namespace PepperDash.Essentials.Fusion
{
public class EssentialsHuddleVtc1FusionController : EssentialsHuddleSpaceFusionSystemControllerBase
{
BooleanSigData CodecIsInCall;
public EssentialsHuddleVtc1FusionController(EssentialsHuddleVtc1Room room, uint ipId)
: base(room, ipId)
{
}
/// <summary>
/// Called in base class constructor before RVI and GUID files are built
/// </summary>
protected override void ExecuteCustomSteps()
{
SetUpCodec();
}
/// <summary>
/// Creates a static asset for the codec and maps the joins to the main room symbol
/// </summary>
void SetUpCodec()
{
try
{
var codec = (Room as EssentialsHuddleVtc1Room).VideoCodec;
if (codec == null)
{
Debug.Console(1, this, "Cannot link codec to Fusion because codec is null");
return;
}
codec.UsageTracker = new UsageTracking(codec);
codec.UsageTracker.UsageIsTracked = true;
codec.UsageTracker.DeviceUsageEnded += UsageTracker_DeviceUsageEnded;
var codecPowerOnAction = new Action<bool>(b => { if (!b) codec.StandbyDeactivate(); });
var codecPowerOffAction = new Action<bool>(b => { if (!b) codec.StandbyActivate(); });
// Map FusionRoom Attributes:
// Codec volume
var codecVolume = FusionRoom.CreateOffsetUshortSig(50, "Volume - Fader01", eSigIoMask.InputOutputSig);
codecVolume.OutputSig.UserObject = new Action<ushort>(b => (codec as IBasicVolumeWithFeedback).SetVolume(b));
(codec as IBasicVolumeWithFeedback).VolumeLevelFeedback.LinkInputSig(codecVolume.InputSig);
// In Call Status
CodecIsInCall = FusionRoom.CreateOffsetBoolSig(69, "Conf - VC 1 In Call", eSigIoMask.InputSigOnly);
codec.CallStatusChange += new EventHandler<PepperDash.Essentials.Devices.Common.Codec.CodecCallStatusItemChangeEventArgs>(codec_CallStatusChange);
// Online status
if (codec is ICommunicationMonitor)
{
var c = codec as ICommunicationMonitor;
var codecOnline = FusionRoom.CreateOffsetBoolSig(122, "Online - VC 1", eSigIoMask.InputSigOnly);
codecOnline.InputSig.BoolValue = c.CommunicationMonitor.Status == MonitorStatus.IsOk;
c.CommunicationMonitor.StatusChange += (o, a) =>
{
codecOnline.InputSig.BoolValue = a.Status == MonitorStatus.IsOk;
};
Debug.Console(0, this, "Linking '{0}' communication monitor to Fusion '{1}'", codec.Key, "Online - VC 1");
}
// Codec IP Address
bool codecHasIpInfo = false;
var codecComm = codec.Communication;
string codecIpAddress = string.Empty;
int codecIpPort = 0;
StringSigData codecIpAddressSig;
StringSigData codecIpPortSig;
if(codecComm is GenericSshClient)
{
codecIpAddress = (codecComm as GenericSshClient).Hostname;
codecIpPort = (codecComm as GenericSshClient).Port;
codecHasIpInfo = true;
}
else if (codecComm is GenericTcpIpClient)
{
codecIpAddress = (codecComm as GenericTcpIpClient).Hostname;
codecIpPort = (codecComm as GenericTcpIpClient).Port;
codecHasIpInfo = true;
}
if (codecHasIpInfo)
{
codecIpAddressSig = FusionRoom.CreateOffsetStringSig(121, "IP Address - VC", eSigIoMask.InputSigOnly);
codecIpAddressSig.InputSig.StringValue = codecIpAddress;
codecIpPortSig = FusionRoom.CreateOffsetStringSig(150, "IP Port - VC", eSigIoMask.InputSigOnly);
codecIpPortSig.InputSig.StringValue = codecIpPort.ToString();
}
var tempAsset = new FusionAsset();
var deviceConfig = ConfigReader.ConfigObject.Devices.FirstOrDefault(c => c.Key.Equals(codec.Key));
if (FusionStaticAssets.ContainsKey(deviceConfig.Uid))
{
tempAsset = FusionStaticAssets[deviceConfig.Uid];
}
else
{
// Create a new asset
tempAsset = new FusionAsset(FusionRoomGuids.GetNextAvailableAssetNumber(FusionRoom), codec.Name, "Codec", "");
FusionStaticAssets.Add(deviceConfig.Uid, tempAsset);
}
var codecAsset = FusionRoom.CreateStaticAsset(tempAsset.SlotNumber, tempAsset.Name, "Display", tempAsset.InstanceId);
codecAsset.PowerOn.OutputSig.UserObject = codecPowerOnAction;
codecAsset.PowerOff.OutputSig.UserObject = codecPowerOffAction;
codec.StandbyIsOnFeedback.LinkComplementInputSig(codecAsset.PowerOn.InputSig);
// TODO: Map relevant attributes on asset symbol
codecAsset.TrySetMakeModel(codec);
codecAsset.TryLinkAssetErrorToCommunication(codec);
}
catch (Exception e)
{
Debug.Console(1, this, "Error setting up codec in Fusion: {0}", e);
}
}
void codec_CallStatusChange(object sender, PepperDash.Essentials.Devices.Common.Codec.CodecCallStatusItemChangeEventArgs e)
{
var codec = (Room as EssentialsHuddleVtc1Room).VideoCodec;
CodecIsInCall.InputSig.BoolValue = codec.IsInCall;
}
// These methods are overridden because they access the room class which is of a different type
protected override void CreateSymbolAndBasicSigs(uint ipId)
{
Debug.Console(1, this, "Creating Fusion Room symbol with GUID: {0}", RoomGuid);
FusionRoom = new FusionRoom(ipId, Global.ControlSystem, Room.Name, RoomGuid);
FusionRoom.ExtenderRoomViewSchedulingDataReservedSigs.Use();
FusionRoom.ExtenderFusionRoomDataReservedSigs.Use();
FusionRoom.Register();
FusionRoom.FusionStateChange += FusionRoom_FusionStateChange;
FusionRoom.ExtenderRoomViewSchedulingDataReservedSigs.DeviceExtenderSigChange += FusionRoomSchedule_DeviceExtenderSigChange;
FusionRoom.ExtenderFusionRoomDataReservedSigs.DeviceExtenderSigChange += ExtenderFusionRoomDataReservedSigs_DeviceExtenderSigChange;
FusionRoom.OnlineStatusChange += FusionRoom_OnlineStatusChange;
CrestronConsole.AddNewConsoleCommand(RequestFullRoomSchedule, "FusReqRoomSchedule", "Requests schedule of the room for the next 24 hours", ConsoleAccessLevelEnum.AccessOperator);
CrestronConsole.AddNewConsoleCommand(ModifyMeetingEndTimeConsoleHelper, "FusReqRoomSchMod", "Ends or extends a meeting by the specified time", ConsoleAccessLevelEnum.AccessOperator);
CrestronConsole.AddNewConsoleCommand(CreateAsHocMeeting, "FusCreateMeeting", "Creates and Ad Hoc meeting for on hour or until the next meeting", ConsoleAccessLevelEnum.AccessOperator);
// Room to fusion room
Room.OnFeedback.LinkInputSig(FusionRoom.SystemPowerOn.InputSig);
// Moved to
CurrentRoomSourceNameSig = FusionRoom.CreateOffsetStringSig(84, "Display 1 - Current Source", eSigIoMask.InputSigOnly);
// Don't think we need to get current status of this as nothing should be alive yet.
(Room as EssentialsHuddleVtc1Room).CurrentSourceChange += Room_CurrentSourceInfoChange;
FusionRoom.SystemPowerOn.OutputSig.SetSigFalseAction((Room as EssentialsHuddleVtc1Room).PowerOnToDefaultOrLastSource);
FusionRoom.SystemPowerOff.OutputSig.SetSigFalseAction(() => (Room as EssentialsHuddleVtc1Room).RunRouteAction("roomOff", Room.SourceListKey));
// NO!! room.RoomIsOn.LinkComplementInputSig(FusionRoom.SystemPowerOff.InputSig);
CrestronEnvironment.EthernetEventHandler += CrestronEnvironment_EthernetEventHandler;
}
protected override void SetUpSources()
{
// Sources
var dict = ConfigReader.ConfigObject.GetSourceListForKey((Room as EssentialsHuddleVtc1Room).SourceListKey);
if (dict != null)
{
// NEW PROCESS:
// Make these lists and insert the fusion attributes by iterating these
var setTopBoxes = dict.Where(d => d.Value.SourceDevice is ISetTopBoxControls);
uint i = 1;
foreach (var kvp in setTopBoxes)
{
TryAddRouteActionSigs("Display 1 - Source TV " + i, 188 + i, kvp.Key, kvp.Value.SourceDevice);
i++;
if (i > 5) // We only have five spots
break;
}
var discPlayers = dict.Where(d => d.Value.SourceDevice is IDiscPlayerControls);
i = 1;
foreach (var kvp in discPlayers)
{
TryAddRouteActionSigs("Display 1 - Source DVD " + i, 181 + i, kvp.Key, kvp.Value.SourceDevice);
i++;
if (i > 5) // We only have five spots
break;
}
var laptops = dict.Where(d => d.Value.SourceDevice is Core.Devices.Laptop);
i = 1;
foreach (var kvp in laptops)
{
TryAddRouteActionSigs("Display 1 - Source Laptop " + i, 166 + i, kvp.Key, kvp.Value.SourceDevice);
i++;
if (i > 10) // We only have ten spots???
break;
}
foreach (var kvp in dict)
{
var usageDevice = kvp.Value.SourceDevice as IUsageTracking;
if (usageDevice != null)
{
usageDevice.UsageTracker = new UsageTracking(usageDevice as Device);
usageDevice.UsageTracker.UsageIsTracked = true;
usageDevice.UsageTracker.DeviceUsageEnded += new EventHandler<DeviceUsageEventArgs>(UsageTracker_DeviceUsageEnded);
}
}
}
else
{
Debug.Console(1, this, "WARNING: Config source list '{0}' not found for room '{1}'",
(Room as EssentialsHuddleVtc1Room).SourceListKey, Room.Key);
}
}
protected override void SetUpDisplay()
{
try
{
//Setup Display Usage Monitoring
var displays = DeviceManager.AllDevices.Where(d => d is DisplayBase);
// Consider updating this in multiple display systems
foreach (DisplayBase display in displays)
{
display.UsageTracker = new UsageTracking(display);
display.UsageTracker.UsageIsTracked = true;
display.UsageTracker.DeviceUsageEnded += new EventHandler<DeviceUsageEventArgs>(UsageTracker_DeviceUsageEnded);
}
var defaultDisplay = (Room as EssentialsHuddleVtc1Room).DefaultDisplay as DisplayBase;
if (defaultDisplay == null)
{
Debug.Console(1, this, "Cannot link null display to Fusion because default display is null");
return;
}
var dispPowerOnAction = new Action<bool>(b => { if (!b) defaultDisplay.PowerOn(); });
var dispPowerOffAction = new Action<bool>(b => { if (!b) defaultDisplay.PowerOff(); });
// Display to fusion room sigs
FusionRoom.DisplayPowerOn.OutputSig.UserObject = dispPowerOnAction;
FusionRoom.DisplayPowerOff.OutputSig.UserObject = dispPowerOffAction;
var defaultDisplayTwoWay = defaultDisplay as IHasPowerControlWithFeedback;
if (defaultDisplayTwoWay != null)
{
defaultDisplayTwoWay.PowerIsOnFeedback.LinkInputSig(FusionRoom.DisplayPowerOn.InputSig);
}
if (defaultDisplay is IDisplayUsage)
(defaultDisplay as IDisplayUsage).LampHours.LinkInputSig(FusionRoom.DisplayUsage.InputSig);
MapDisplayToRoomJoins(1, 158, defaultDisplay);
var deviceConfig = ConfigReader.ConfigObject.Devices.FirstOrDefault(d => d.Key.Equals(defaultDisplay.Key));
//Check for existing asset in GUIDs collection
var tempAsset = new FusionAsset();
if (FusionStaticAssets.ContainsKey(deviceConfig.Uid))
{
tempAsset = FusionStaticAssets[deviceConfig.Uid];
}
else
{
// Create a new asset
tempAsset = new FusionAsset(FusionRoomGuids.GetNextAvailableAssetNumber(FusionRoom), defaultDisplay.Name, "Display", "");
FusionStaticAssets.Add(deviceConfig.Uid, tempAsset);
}
var dispAsset = FusionRoom.CreateStaticAsset(tempAsset.SlotNumber, tempAsset.Name, "Display", tempAsset.InstanceId);
dispAsset.PowerOn.OutputSig.UserObject = dispPowerOnAction;
dispAsset.PowerOff.OutputSig.UserObject = dispPowerOffAction;
var defaultTwoWayDisplay = defaultDisplay as IHasPowerControlWithFeedback;
if (defaultTwoWayDisplay != null)
{
defaultTwoWayDisplay.PowerIsOnFeedback.LinkInputSig(FusionRoom.DisplayPowerOn.InputSig);
if (defaultDisplay is IDisplayUsage)
(defaultDisplay as IDisplayUsage).LampHours.LinkInputSig(FusionRoom.DisplayUsage.InputSig);
defaultTwoWayDisplay.PowerIsOnFeedback.LinkInputSig(dispAsset.PowerOn.InputSig);
}
// Use extension methods
dispAsset.TrySetMakeModel(defaultDisplay);
dispAsset.TryLinkAssetErrorToCommunication(defaultDisplay);
}
catch (Exception e)
{
Debug.Console(1, this, "Error setting up display in Fusion: {0}", e);
}
}
protected override void MapDisplayToRoomJoins(int displayIndex, int joinOffset, DisplayBase display)
{
string displayName = string.Format("Display {0} - ", displayIndex);
if (display == (Room as EssentialsHuddleVtc1Room).DefaultDisplay)
{
// Power on
var defaultDisplayPowerOn = FusionRoom.CreateOffsetBoolSig((uint)joinOffset, displayName + "Power On", eSigIoMask.InputOutputSig);
defaultDisplayPowerOn.OutputSig.UserObject = new Action<bool>(b => { if (!b) display.PowerOn(); });
// Power Off
var defaultDisplayPowerOff = FusionRoom.CreateOffsetBoolSig((uint)joinOffset + 1, displayName + "Power Off", eSigIoMask.InputOutputSig);
defaultDisplayPowerOn.OutputSig.UserObject = new Action<bool>(b => { if (!b) display.PowerOff(); }); ;
var displayTwoWay = display as IHasPowerControlWithFeedback;
if (displayTwoWay != null)
{
displayTwoWay.PowerIsOnFeedback.LinkInputSig(defaultDisplayPowerOn.InputSig);
displayTwoWay.PowerIsOnFeedback.LinkInputSig(defaultDisplayPowerOn.InputSig);
}
// Current Source
var defaultDisplaySourceNone = FusionRoom.CreateOffsetBoolSig((uint)joinOffset + 8, displayName + "Source None", eSigIoMask.InputOutputSig);
defaultDisplaySourceNone.OutputSig.UserObject = new Action<bool>(b => { if (!b) (Room as EssentialsHuddleVtc1Room).RunRouteAction("roomOff", Room.SourceListKey); }); ;
}
}
}
using System;
using System.Linq;
using Crestron.SimplSharp;
using Crestron.SimplSharpPro;
using Crestron.SimplSharpPro.Fusion;
using PepperDash.Core;
using PepperDash.Essentials.Core;
using PepperDash.Essentials.Core.Config;
using PepperDash.Essentials.Core.Fusion;
namespace PepperDash.Essentials.Fusion
{
public class EssentialsHuddleVtc1FusionController : EssentialsHuddleSpaceFusionSystemControllerBase
{
private BooleanSigData _codecIsInCall;
public EssentialsHuddleVtc1FusionController(EssentialsHuddleVtc1Room room, uint ipId)
: base(room, ipId)
{
}
/// <summary>
/// Called in base class constructor before RVI and GUID files are built
/// </summary>
protected override void ExecuteCustomSteps()
{
SetUpCodec();
}
/// <summary>
/// Creates a static asset for the codec and maps the joins to the main room symbol
/// </summary>
private void SetUpCodec()
{
try
{
var essentialsHuddleVtc1Room = Room as EssentialsHuddleVtc1Room;
if (essentialsHuddleVtc1Room == null)
{
return;
}
var codec = essentialsHuddleVtc1Room.VideoCodec;
if (codec == null)
{
Debug.Console(1, this, "Cannot link codec to Fusion because codec is null");
return;
}
codec.UsageTracker = new UsageTracking(codec) {UsageIsTracked = true};
codec.UsageTracker.DeviceUsageEnded += UsageTracker_DeviceUsageEnded;
var codecPowerOnAction = new Action<bool>(b =>
{
if (!b)
{
codec.StandbyDeactivate();
}
});
var codecPowerOffAction = new Action<bool>(b =>
{
if (!b)
{
codec.StandbyActivate();
}
});
// Map FusionRoom Attributes:
// Codec volume
var codecVolume = FusionRoom.CreateOffsetUshortSig(50, "Volume - Fader01", eSigIoMask.InputOutputSig);
codecVolume.OutputSig.UserObject =
new Action<ushort>(b => (codec as IBasicVolumeWithFeedback).SetVolume(b));
(codec as IBasicVolumeWithFeedback).VolumeLevelFeedback.LinkInputSig(codecVolume.InputSig);
// In Call Status
_codecIsInCall = FusionRoom.CreateOffsetBoolSig(69, "Conf - VC 1 In Call", eSigIoMask.InputSigOnly);
codec.CallStatusChange += codec_CallStatusChange;
// Online status
if (codec is ICommunicationMonitor)
{
var c = codec as ICommunicationMonitor;
var codecOnline = FusionRoom.CreateOffsetBoolSig(122, "Online - VC 1", eSigIoMask.InputSigOnly);
codecOnline.InputSig.BoolValue = c.CommunicationMonitor.Status == MonitorStatus.IsOk;
c.CommunicationMonitor.StatusChange +=
(o, a) => { codecOnline.InputSig.BoolValue = a.Status == MonitorStatus.IsOk; };
Debug.Console(0, this, "Linking '{0}' communication monitor to Fusion '{1}'", codec.Key,
"Online - VC 1");
}
// Codec IP Address
bool codecHasIpInfo = false;
var codecComm = codec.Communication;
string codecIpAddress = string.Empty;
int codecIpPort = 0;
if (codecComm is GenericSshClient)
{
codecIpAddress = (codecComm as GenericSshClient).Hostname;
codecIpPort = (codecComm as GenericSshClient).Port;
codecHasIpInfo = true;
}
else if (codecComm is GenericTcpIpClient)
{
codecIpAddress = (codecComm as GenericTcpIpClient).Hostname;
codecIpPort = (codecComm as GenericTcpIpClient).Port;
codecHasIpInfo = true;
}
if (codecHasIpInfo)
{
StringSigData codecIpAddressSig = FusionRoom.CreateOffsetStringSig(121, "IP Address - VC",
eSigIoMask.InputSigOnly);
codecIpAddressSig.InputSig.StringValue = codecIpAddress;
StringSigData codecIpPortSig = FusionRoom.CreateOffsetStringSig(150, "IP Port - VC",
eSigIoMask.InputSigOnly);
codecIpPortSig.InputSig.StringValue = codecIpPort.ToString();
}
FusionAsset tempAsset;
var deviceConfig = ConfigReader.ConfigObject.Devices.FirstOrDefault(c => c.Key.Equals(codec.Key));
if (FusionStaticAssets.ContainsKey(deviceConfig.Uid))
{
tempAsset = FusionStaticAssets[deviceConfig.Uid];
}
else
{
// Create a new asset
tempAsset = new FusionAsset(FusionRoomGuids.GetNextAvailableAssetNumber(FusionRoom), codec.Name,
"Codec", "");
FusionStaticAssets.Add(deviceConfig.Uid, tempAsset);
}
var codecAsset = FusionRoom.CreateStaticAsset(tempAsset.SlotNumber, tempAsset.Name, "Display",
tempAsset.InstanceId);
codecAsset.PowerOn.OutputSig.UserObject = codecPowerOnAction;
codecAsset.PowerOff.OutputSig.UserObject = codecPowerOffAction;
codec.StandbyIsOnFeedback.LinkComplementInputSig(codecAsset.PowerOn.InputSig);
// TODO: Map relevant attributes on asset symbol
codecAsset.TrySetMakeModel(codec);
codecAsset.TryLinkAssetErrorToCommunication(codec);
}
catch (Exception e)
{
Debug.Console(1, this, "Error setting up codec in Fusion: {0}", e);
}
}
private void codec_CallStatusChange(object sender, Core.Devices.Codec.CodecCallStatusItemChangeEventArgs e)
{
var essentialsHuddleVtc1Room = Room as EssentialsHuddleVtc1Room;
if (essentialsHuddleVtc1Room == null)
{
return;
}
var codec = essentialsHuddleVtc1Room.VideoCodec;
_codecIsInCall.InputSig.BoolValue = codec.IsInCall;
}
// These methods are overridden because they access the room class which is of a different type
protected override void CreateSymbolAndBasicSigs(uint ipId)
{
Debug.Console(1, this, "Creating Fusion Room symbol with GUID: {0}", RoomGuid);
FusionRoom = new FusionRoom(ipId, Global.ControlSystem, Room.Name, RoomGuid);
FusionRoom.ExtenderRoomViewSchedulingDataReservedSigs.Use();
FusionRoom.ExtenderFusionRoomDataReservedSigs.Use();
FusionRoom.Register();
FusionRoom.FusionStateChange += FusionRoom_FusionStateChange;
FusionRoom.ExtenderRoomViewSchedulingDataReservedSigs.DeviceExtenderSigChange +=
FusionRoomSchedule_DeviceExtenderSigChange;
FusionRoom.ExtenderFusionRoomDataReservedSigs.DeviceExtenderSigChange +=
ExtenderFusionRoomDataReservedSigs_DeviceExtenderSigChange;
FusionRoom.OnlineStatusChange += FusionRoom_OnlineStatusChange;
CrestronConsole.AddNewConsoleCommand(RequestFullRoomSchedule, "FusReqRoomSchedule",
"Requests schedule of the room for the next 24 hours", ConsoleAccessLevelEnum.AccessOperator);
CrestronConsole.AddNewConsoleCommand(ModifyMeetingEndTimeConsoleHelper, "FusReqRoomSchMod",
"Ends or extends a meeting by the specified time", ConsoleAccessLevelEnum.AccessOperator);
CrestronConsole.AddNewConsoleCommand(CreateAdHocMeeting, "FusCreateMeeting",
"Creates and Ad Hoc meeting for on hour or until the next meeting",
ConsoleAccessLevelEnum.AccessOperator);
// Room to fusion room
Room.OnFeedback.LinkInputSig(FusionRoom.SystemPowerOn.InputSig);
// Moved to
CurrentRoomSourceNameSig = FusionRoom.CreateOffsetStringSig(84, "Display 1 - Current Source",
eSigIoMask.InputSigOnly);
// Don't think we need to get current status of this as nothing should be alive yet.
var essentialsHuddleVtc1Room = Room as EssentialsHuddleVtc1Room;
if (essentialsHuddleVtc1Room != null)
{
essentialsHuddleVtc1Room.CurrentSourceChange += Room_CurrentSourceInfoChange;
FusionRoom.SystemPowerOn.OutputSig.SetSigFalseAction(
essentialsHuddleVtc1Room.PowerOnToDefaultOrLastSource);
FusionRoom.SystemPowerOff.OutputSig.SetSigFalseAction(
() => essentialsHuddleVtc1Room.RunRouteAction("roomOff", Room.SourceListKey));
}
CrestronEnvironment.EthernetEventHandler += CrestronEnvironment_EthernetEventHandler;
}
protected override void SetUpSources()
{
// Sources
var essentialsHuddleVtc1Room = Room as EssentialsHuddleVtc1Room;
if (essentialsHuddleVtc1Room == null)
{
return;
}
var dict = ConfigReader.ConfigObject.GetSourceListForKey(essentialsHuddleVtc1Room.SourceListKey);
if (dict != null)
{
// NEW PROCESS:
// Make these lists and insert the fusion attributes by iterating these
var setTopBoxes = dict.Where(d => d.Value.SourceDevice is ISetTopBoxControls);
uint i = 1;
foreach (var kvp in setTopBoxes)
{
TryAddRouteActionSigs("Display 1 - Source TV " + i, 188 + i, kvp.Key, kvp.Value.SourceDevice);
i++;
if (i > 5) // We only have five spots
{
break;
}
}
var discPlayers = dict.Where(d => d.Value.SourceDevice is IDiscPlayerControls);
i = 1;
foreach (var kvp in discPlayers)
{
TryAddRouteActionSigs("Display 1 - Source DVD " + i, 181 + i, kvp.Key, kvp.Value.SourceDevice);
i++;
if (i > 5) // We only have five spots
{
break;
}
}
var laptops = dict.Where(d => d.Value.SourceDevice is Core.Devices.Laptop);
i = 1;
foreach (var kvp in laptops)
{
TryAddRouteActionSigs("Display 1 - Source Laptop " + i, 166 + i, kvp.Key, kvp.Value.SourceDevice);
i++;
if (i > 10) // We only have ten spots???
{
break;
}
}
foreach (var usageDevice in dict.Select(kvp => kvp.Value.SourceDevice).OfType<IUsageTracking>())
{
usageDevice.UsageTracker = new UsageTracking(usageDevice as Device) {UsageIsTracked = true};
usageDevice.UsageTracker.DeviceUsageEnded +=
UsageTracker_DeviceUsageEnded;
}
}
else
{
Debug.Console(1, this, "WARNING: Config source list '{0}' not found for room '{1}'",
essentialsHuddleVtc1Room.SourceListKey, Room.Key);
}
}
protected override void SetUpDisplay()
{
try
{
//Setup Display Usage Monitoring
var displays = DeviceManager.AllDevices.Where(d => d is DisplayBase);
// Consider updating this in multiple display systems
foreach (var display in displays.Cast<DisplayBase>())
{
display.UsageTracker = new UsageTracking(display) {UsageIsTracked = true};
display.UsageTracker.DeviceUsageEnded +=
UsageTracker_DeviceUsageEnded;
}
var essentialsHuddleVtc1Room = Room as EssentialsHuddleVtc1Room;
if (essentialsHuddleVtc1Room == null)
{
return;
}
var defaultDisplay = essentialsHuddleVtc1Room.DefaultDisplay as TwoWayDisplayBase;
if (defaultDisplay == null)
{
Debug.Console(1, this, "Cannot link null display to Fusion because default display is null");
return;
}
var dispPowerOnAction = new Action<bool>(b =>
{
if (!b)
{
defaultDisplay.PowerOn();
}
});
var dispPowerOffAction = new Action<bool>(b =>
{
if (!b)
{
defaultDisplay.PowerOff();
}
});
// Display to fusion room sigs
FusionRoom.DisplayPowerOn.OutputSig.UserObject = dispPowerOnAction;
FusionRoom.DisplayPowerOff.OutputSig.UserObject = dispPowerOffAction;
defaultDisplay.PowerIsOnFeedback.LinkInputSig(FusionRoom.DisplayPowerOn.InputSig);
if (defaultDisplay is IDisplayUsage)
{
(defaultDisplay as IDisplayUsage).LampHours.LinkInputSig(FusionRoom.DisplayUsage.InputSig);
}
MapDisplayToRoomJoins(1, 158, defaultDisplay);
var deviceConfig =
ConfigReader.ConfigObject.Devices.FirstOrDefault(d => d.Key.Equals(defaultDisplay.Key));
//Check for existing asset in GUIDs collection
FusionAsset tempAsset;
if (FusionStaticAssets.ContainsKey(deviceConfig.Uid))
{
tempAsset = FusionStaticAssets[deviceConfig.Uid];
}
else
{
// Create a new asset
tempAsset = new FusionAsset(FusionRoomGuids.GetNextAvailableAssetNumber(FusionRoom),
defaultDisplay.Name, "Display", "");
FusionStaticAssets.Add(deviceConfig.Uid, tempAsset);
}
var dispAsset = FusionRoom.CreateStaticAsset(tempAsset.SlotNumber, tempAsset.Name, "Display",
tempAsset.InstanceId);
dispAsset.PowerOn.OutputSig.UserObject = dispPowerOnAction;
dispAsset.PowerOff.OutputSig.UserObject = dispPowerOffAction;
defaultDisplay.PowerIsOnFeedback.LinkInputSig(dispAsset.PowerOn.InputSig);
// NO!! display.PowerIsOn.LinkComplementInputSig(dispAsset.PowerOff.InputSig);
// Use extension methods
dispAsset.TrySetMakeModel(defaultDisplay);
dispAsset.TryLinkAssetErrorToCommunication(defaultDisplay);
}
catch (Exception e)
{
Debug.Console(1, this, "Error setting up display in Fusion: {0}", e);
}
}
protected override void MapDisplayToRoomJoins(int displayIndex, int joinOffset, TwoWayDisplayBase display)
{
var displayName = string.Format("Display {0} - ", displayIndex);
var essentialsHuddleVtc1Room = Room as EssentialsHuddleVtc1Room;
if (essentialsHuddleVtc1Room == null || display != essentialsHuddleVtc1Room.DefaultDisplay)
{
return;
}
// Power on
var defaultDisplayPowerOn = FusionRoom.CreateOffsetBoolSig((uint) joinOffset, displayName + "Power On",
eSigIoMask.InputOutputSig);
defaultDisplayPowerOn.OutputSig.UserObject = new Action<bool>(b =>
{
if (!b)
{
display.PowerOn();
}
});
display.PowerIsOnFeedback.LinkInputSig(defaultDisplayPowerOn.InputSig);
// Power Off
FusionRoom.CreateOffsetBoolSig((uint) joinOffset + 1,
displayName + "Power Off", eSigIoMask.InputOutputSig);
defaultDisplayPowerOn.OutputSig.UserObject = new Action<bool>(b =>
{
if (!b)
{
display.PowerOff();
}
});
display.PowerIsOnFeedback.LinkInputSig(defaultDisplayPowerOn.InputSig);
// Current Source
var defaultDisplaySourceNone = FusionRoom.CreateOffsetBoolSig((uint) joinOffset + 8,
displayName + "Source None", eSigIoMask.InputOutputSig);
defaultDisplaySourceNone.OutputSig.UserObject = new Action<bool>(b =>
{
if (b)
{
return;
}
var huddleVtc1Room = Room as EssentialsHuddleVtc1Room;
if (huddleVtc1Room != null)
{
huddleVtc1Room.RunRouteAction("roomOff", Room.SourceListKey);
}
});
}
}
}

View File

@@ -129,23 +129,10 @@
<Compile Include="Bridges\JoinMaps\SetTopBoxControllerJoinMap.cs" />
<Compile Include="Bridges\JoinMaps\StatusSignControllerJoinMap.cs" />
<Compile Include="Bridges\JoinMaps\SystemMonitorJoinMap.cs" />
<Compile Include="ControlSystem.cs" />
<Compile Include="Factory\DeviceFactory.cs" />
<Compile Include="Devices\Amplifier.cs" />
<Compile Include="ControlSystem.cs" />
<Compile Include="Fusion\EssentialsHuddleVtc1FusionController.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="Room\Config\EssentialsDualDisplayRoomPropertiesConfig.cs" />
<Compile Include="Room\Config\EssentialsNDisplayRoomPropertiesConfig.cs" />
<Compile Include="Room\Config\DDVC01RoomPropertiesConfig.cs" />
<Compile Include="Room\Config\EssentialsPresentationPropertiesConfig.cs" />
<Compile Include="Room\Config\EssentialsHuddleRoomPropertiesConfig.cs" />
<Compile Include="Room\Config\EssentialsHuddleVtc1PropertiesConfig.cs" />
<Compile Include="Room\Config\EssentialsRoomEmergencyConfig.cs" />
<Compile Include="Room\Emergency\EsentialsRoomEmergencyContactClosure.cs" />
<Compile Include="Room\Types\EssentialsDualDisplayRoom.cs" />
<Compile Include="Room\Types\EssentialsHuddleVtc1Room.cs" />
<Compile Include="Room\Types\EssentialsNDisplayRoomBase.cs" />
<Compile Include="Room\Config\EssentialsRoomConfig.cs" />
<Compile Include="UIDrivers\Environment Drivers\EssentialsEnvironmentDriver.cs" />
<Compile Include="UIDrivers\Environment Drivers\EssentialsLightingDriver.cs" />
<Compile Include="UIDrivers\Environment Drivers\EssentialsShadeDriver.cs" />
@@ -175,7 +162,6 @@
<Compile Include="UI\JoinConstants\UIBoolJoin.cs" />
<Compile Include="UI\DualDisplaySourceSRLController.cs" />
<Compile Include="UI\SubpageReferenceListActivityItem.cs" />
<Compile Include="Room\Types\EssentialsHuddleSpaceRoom.cs" />
<Compile Include="UI\EssentialsTouchpanelController.cs" />
<Compile Include="UI\SubpageReferenceListSourceItem.cs" />
<None Include="app.config" />
@@ -216,6 +202,9 @@
<Name>PepperDash_Essentials_DM</Name>
</ProjectReference>
</ItemGroup>
<ItemGroup>
<Folder Include="UIDrivers\EssentialsDualDisplay\" />
</ItemGroup>
<Import Project="$(MSBuildBinPath)\Microsoft.CompactFramework.CSharp.targets" />
<ProjectExtensions>
<VisualStudio>

View File

@@ -1,14 +1,11 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Crestron.SimplSharp;
using Newtonsoft.Json;
using PepperDash.Core;
using PepperDash.Essentials.Core;
using PepperDash.Essentials.Core.Devices;
using PepperDash.Essentials.Core.Config;
using PepperDash.Essentials.Room.Config;
using PepperDash.Essentials.Devices.Common.Codec;
@@ -77,9 +74,8 @@ namespace PepperDash.Essentials
var leftDisp = LeftDisplay as DisplayBase;
var rightDisp = RightDisplay as DisplayBase;
if (leftDisp != null && RightDisplay != null)
return leftDisp.IsWarmingUpFeedback.BoolValue || rightDisp.IsWarmingUpFeedback.BoolValue;
else
return false;
return rightDisp != null && (leftDisp.IsWarmingUpFeedback.BoolValue || rightDisp.IsWarmingUpFeedback.BoolValue);
return false;
};
}
}
@@ -96,9 +92,8 @@ namespace PepperDash.Essentials
var leftDisp = LeftDisplay as DisplayBase;
var rightDisp = RightDisplay as DisplayBase;
if (leftDisp != null && RightDisplay != null)
return leftDisp.IsCoolingDownFeedback.BoolValue || rightDisp.IsCoolingDownFeedback.BoolValue;
else
return false;
return rightDisp != null && (leftDisp.IsCoolingDownFeedback.BoolValue || rightDisp.IsCoolingDownFeedback.BoolValue);
return false;
};
}
}
@@ -120,7 +115,7 @@ namespace PepperDash.Essentials
/// If room is off, enables power on to last source. Default true
/// </summary>
public bool EnablePowerOnToLastSource { get; set; }
string LastSourceKey;
string _lastSourceKey;
/// <summary>
/// Sets the volume control device, and attaches/removes InUseTrackers with "audio"
@@ -128,27 +123,27 @@ namespace PepperDash.Essentials
/// </summary>
public IBasicVolumeControls CurrentVolumeControls
{
get { return _CurrentAudioDevice; }
get { return _currentAudioDevice; }
set
{
if (value == _CurrentAudioDevice) return;
if (value == _currentAudioDevice) return;
var oldDev = _CurrentAudioDevice;
var oldDev = _currentAudioDevice;
// derigister this room from the device, if it can
if (oldDev is IInUseTracking)
(oldDev as IInUseTracking).InUseTracker.RemoveUser(this, "audio");
var handler = CurrentVolumeDeviceChange;
if (handler != null)
CurrentVolumeDeviceChange(this, new VolumeDeviceChangeEventArgs(oldDev, value, ChangeType.WillChange));
_CurrentAudioDevice = value;
_currentAudioDevice = value;
if (handler != null)
CurrentVolumeDeviceChange(this, new VolumeDeviceChangeEventArgs(oldDev, value, ChangeType.DidChange));
// register this room with new device, if it can
if (_CurrentAudioDevice is IInUseTracking)
(_CurrentAudioDevice as IInUseTracking).InUseTracker.AddUser(this, "audio");
if (_currentAudioDevice is IInUseTracking)
(_currentAudioDevice as IInUseTracking).InUseTracker.AddUser(this, "audio");
}
}
IBasicVolumeControls _CurrentAudioDevice;
IBasicVolumeControls _currentAudioDevice;
/// <summary>
/// "codecOsd"
@@ -161,7 +156,7 @@ namespace PepperDash.Essentials
/// </summary>
public IHasScheduleAwareness ScheduleSource { get { return VideoCodec as IHasScheduleAwareness; } }
CCriticalSection SourceSelectLock = new CCriticalSection();
readonly CCriticalSection _sourceSelectLock = new CCriticalSection();
public EssentialsDualDisplayRoom(DeviceConfig config)
: base(config)
@@ -196,12 +191,12 @@ namespace PepperDash.Essentials
}
VideoCodec = DeviceManager.GetDeviceForKey(PropertiesConfig.VideoCodecKey) as
PepperDash.Essentials.Devices.Common.VideoCodec.VideoCodecBase;
VideoCodecBase;
if (VideoCodec == null)
throw new ArgumentNullException("codec cannot be null");
AudioCodec = DeviceManager.GetDeviceForKey(PropertiesConfig.AudioCodecKey) as
PepperDash.Essentials.Devices.Common.AudioCodec.AudioCodecBase;
AudioCodecBase;
if (AudioCodec == null)
Debug.Console(0, this, "No Audio Codec Found");
@@ -217,8 +212,8 @@ namespace PepperDash.Essentials
void Initialize()
{
if (DefaultAudioDevice is IBasicVolumeControls)
DefaultVolumeControls = DefaultAudioDevice as IBasicVolumeControls;
if (DefaultAudioDevice != null)
DefaultVolumeControls = DefaultAudioDevice;
else if (DefaultAudioDevice is IHasVolumeDevice)
DefaultVolumeControls = (DefaultAudioDevice as IHasVolumeDevice).VolumeDevice;
CurrentVolumeControls = DefaultVolumeControls;
@@ -233,12 +228,12 @@ namespace PepperDash.Essentials
InitializeDisplay(rightDisp);
// Get Microphone Privacy object, if any
this.MicrophonePrivacy = EssentialsRoomConfigHelper.GetMicrophonePrivacy(PropertiesConfig, this);
MicrophonePrivacy = EssentialsRoomConfigHelper.GetMicrophonePrivacy(PropertiesConfig, this);
Debug.Console(2, this, "Microphone Privacy Config evaluated.");
// Get emergency object, if any
this.Emergency = EssentialsRoomConfigHelper.GetEmergency(PropertiesConfig, this);
Emergency = EssentialsRoomConfigHelper.GetEmergency(PropertiesConfig, this);
Debug.Console(2, this, "Emergency Config evaluated.");
@@ -254,23 +249,20 @@ namespace PepperDash.Essentials
if (VideoCodec != null)
inVideoCall = VideoCodec.IsInCall;
if (inAudioCall || inVideoCall)
return true;
else
return false;
return inAudioCall || inVideoCall;
});
VideoCodec.CallStatusChange += (o, a) => this.InCallFeedback.FireUpdate();
VideoCodec.CallStatusChange += (o, a) => InCallFeedback.FireUpdate();
if (AudioCodec != null)
AudioCodec.CallStatusChange += (o, a) => this.InCallFeedback.FireUpdate();
AudioCodec.CallStatusChange += (o, a) => InCallFeedback.FireUpdate();
IsSharingFeedback = new BoolFeedback(() => VideoCodec.SharingContentIsOnFeedback.BoolValue);
VideoCodec.SharingContentIsOnFeedback.OutputChange += (o, a) => this.IsSharingFeedback.FireUpdate();
VideoCodec.SharingContentIsOnFeedback.OutputChange += (o, a) => IsSharingFeedback.FireUpdate();
// link privacy to VC (for now?)
PrivacyModeIsOnFeedback = new BoolFeedback(() => VideoCodec.PrivacyModeIsOnFeedback.BoolValue);
VideoCodec.PrivacyModeIsOnFeedback.OutputChange += (o, a) => this.PrivacyModeIsOnFeedback.FireUpdate();
VideoCodec.PrivacyModeIsOnFeedback.OutputChange += (o, a) => PrivacyModeIsOnFeedback.FireUpdate();
CallTypeFeedback = new IntFeedback(() => 0);
@@ -304,13 +296,18 @@ namespace PepperDash.Essentials
disp.IsWarmingUpFeedback.OutputChange += (o, a) =>
{
IsWarmingUpFeedback.FireUpdate();
if (!IsWarmingUpFeedback.BoolValue)
(CurrentVolumeControls as IBasicVolumeWithFeedback).SetVolume(DefaultVolume);
};
disp.IsCoolingDownFeedback.OutputChange += (o, a) =>
{
IsCoolingDownFeedback.FireUpdate();
if (IsWarmingUpFeedback.BoolValue)
{
return;
}
var basicVolumeWithFeedback = CurrentVolumeControls as IBasicVolumeWithFeedback;
if (basicVolumeWithFeedback != null)
{
basicVolumeWithFeedback.SetVolume(DefaultVolume);
}
};
disp.IsCoolingDownFeedback.OutputChange += (o, a) => IsCoolingDownFeedback.FireUpdate();
}
}
@@ -328,7 +325,7 @@ namespace PepperDash.Essentials
{
// Add Occupancy object from config
if (PropertiesConfig.Occupancy != null)
this.SetRoomOccupancy(DeviceManager.GetDeviceForKey(PropertiesConfig.Occupancy.DeviceKey) as
SetRoomOccupancy(DeviceManager.GetDeviceForKey(PropertiesConfig.Occupancy.DeviceKey) as
IOccupancyStatusProvider, PropertiesConfig.Occupancy.TimeoutMinutes);
this.LogoUrlLightBkgnd = PropertiesConfig.LogoLight.GetLogoUrlLight();
@@ -381,6 +378,7 @@ namespace PepperDash.Essentials
///
/// </summary>
/// <param name="routeKey"></param>
/// <param name="sourceListKey"></param>
public void RunRouteAction(string routeKey, string sourceListKey)
{
RunRouteAction(routeKey, sourceListKey, null);
@@ -390,14 +388,17 @@ namespace PepperDash.Essentials
/// Gets a source from config list SourceListKey and dynamically build and executes the
/// route or commands
/// </summary>
/// <param name="name"></param>
/// <param name="routeKey"></param>
/// <param name="sourceListKey"></param>
/// <param name="successCallback"></param>
public void RunRouteAction(string routeKey, string sourceListKey, Action successCallback)
{
// Run this on a separate thread
new CTimer(o =>
//new CTimer
CrestronInvoke.BeginInvoke(o =>
{
// try to prevent multiple simultaneous selections
SourceSelectLock.TryEnter();
_sourceSelectLock.TryEnter();
try
{
@@ -419,9 +420,9 @@ namespace PepperDash.Essentials
}
// End usage timer on last source
if (!string.IsNullOrEmpty(LastSourceKey))
if (!string.IsNullOrEmpty(_lastSourceKey))
{
var usageLastSource = dict[LastSourceKey].SourceDevice as IUsageTracking;
var usageLastSource = dict[_lastSourceKey].SourceDevice as IUsageTracking;
if (usageLastSource != null && usageLastSource.UsageTracker != null)
{
try
@@ -441,7 +442,7 @@ namespace PepperDash.Essentials
if (routeKey.ToLower() != "roomoff")
{
LastSourceKey = routeKey;
_lastSourceKey = routeKey;
}
//else
// CurrentSourceInfoKey = null;
@@ -526,7 +527,7 @@ namespace PepperDash.Essentials
Debug.Console(1, this, "ERROR in routing: {0}", e);
}
SourceSelectLock.Leave();
_sourceSelectLock.Leave();
}, 0); // end of CTimer
}
@@ -535,6 +536,8 @@ namespace PepperDash.Essentials
///
/// </summary>
/// <param name="route"></param>
/// <param name="sourceItem"></param>
/// <param name="sourceItemKey"></param>
void DoRouteItem(SourceRouteListItem route, SourceListItem sourceItem, string sourceItemKey)
{
// if there is a $defaultAll on route, run two separate
@@ -558,7 +561,7 @@ namespace PepperDash.Essentials
/// </summary>
/// <param name="route"></param>
/// <returns></returns>
bool DoRoute(SourceRouteListItem route, SourceListItem sourceItem, string sourceItemKey)
private bool DoRoute(SourceRouteListItem route, SourceListItem sourceItem, string sourceItemKey)
{
IRoutingSink dest = null;
@@ -622,9 +625,9 @@ namespace PepperDash.Essentials
/// </summary>
public override void PowerOnToDefaultOrLastSource()
{
if (!EnablePowerOnToLastSource || LastSourceKey == null)
if (!EnablePowerOnToLastSource || _lastSourceKey == null)
return;
RunRouteAction(LastSourceKey, SourceListKey);
RunRouteAction(_lastSourceKey, SourceListKey);
}
/// <summary>
@@ -632,10 +635,11 @@ namespace PepperDash.Essentials
/// </summary>
public static void AllRoomsOff()
{
var allRooms = DeviceManager.AllDevices.Where(d =>
d is EssentialsHuddleSpaceRoom && !(d as EssentialsHuddleSpaceRoom).ExcludeFromGlobalFunctions);
var allRooms = DeviceManager.AllDevices.OfType<EssentialsHuddleSpaceRoom>().Where(d => !d.ExcludeFromGlobalFunctions);
foreach (var room in allRooms)
(room as EssentialsHuddleSpaceRoom).RunRouteAction("roomOff", (room as EssentialsHuddleSpaceRoom).SourceListKey);
{
room.RunRouteAction("roomOff", room.SourceListKey);
}
}
#region IPrivacy Members

View File

@@ -1,11 +1,5 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Crestron.SimplSharp;
using Newtonsoft.Json;
using PepperDash.Core;
using PepperDash.Essentials.Core;
using PepperDash.Essentials.Core.Config;
@@ -13,148 +7,21 @@ using PepperDash.Essentials.Room.Config;
namespace PepperDash.Essentials
{
public class EssentialsHuddleSpaceRoom : EssentialsRoomBase, IHasCurrentSourceInfoChange, IRunRouteAction, IRunDefaultPresentRoute, IHasCurrentVolumeControls, IHasDefaultDisplay
{
public event EventHandler<VolumeDeviceChangeEventArgs> CurrentVolumeDeviceChange;
public event SourceInfoChangeHandler CurrentSourceChange;
protected override Func<bool> OnFeedbackFunc
{
get
{
return () =>
{
var disp = DefaultDisplay as DisplayBase;
var val = CurrentSourceInfo != null
&& CurrentSourceInfo.Type == eSourceListItemType.Route
&& disp != null;
//&& disp.PowerIsOnFeedback.BoolValue;
return val;
};
}
}
/// <summary>
///
/// </summary>
protected override Func<bool> IsWarmingFeedbackFunc
{
get
{
return () =>
{
var disp = DefaultDisplay as DisplayBase;
if (disp != null)
return disp.IsWarmingUpFeedback.BoolValue;
else
return false;
};
}
}
/// <summary>
///
/// </summary>
protected override Func<bool> IsCoolingFeedbackFunc
{
get
{
return () =>
{
var disp = DefaultDisplay as DisplayBase;
if (disp != null)
return disp.IsCoolingDownFeedback.BoolValue;
else
return false;
};
}
}
public EssentialsHuddleRoomPropertiesConfig PropertiesConfig { get; private set; }
public IRoutingSinkWithSwitching DefaultDisplay { get; private set; }
public IRoutingSink DefaultAudioDevice { get; private set; }
public IBasicVolumeControls DefaultVolumeControls { 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; }
string LastSourceKey;
/// <summary>
///
/// </summary>
public IBasicVolumeControls CurrentVolumeControls
{
get { return _CurrentAudioDevice; }
set
{
if (value == _CurrentAudioDevice) return;
var oldDev = _CurrentAudioDevice;
// derigister this room from the device, if it can
if (oldDev is IInUseTracking)
(oldDev as IInUseTracking).InUseTracker.RemoveUser(this, "audio");
var handler = CurrentVolumeDeviceChange;
if (handler != null)
CurrentVolumeDeviceChange(this, new VolumeDeviceChangeEventArgs(oldDev, value, ChangeType.WillChange));
_CurrentAudioDevice = value;
if (handler != null)
CurrentVolumeDeviceChange(this, new VolumeDeviceChangeEventArgs(oldDev, value, ChangeType.DidChange));
// register this room with new device, if it can
if (_CurrentAudioDevice is IInUseTracking)
(_CurrentAudioDevice as IInUseTracking).InUseTracker.AddUser(this, "audio");
}
}
IBasicVolumeControls _CurrentAudioDevice;
/// <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);
}
}
SourceListItem _CurrentSourceInfo;
public string CurrentSourceInfoKey { get; set; }
public class EssentialsHuddleSpaceRoom : EssentialsRoomBase, IRunRouteAction,
IRunDefaultPresentRoute, IHasCurrentVolumeControls, IHasDefaultDisplay, IHasCurrentSourceInfoChange
{
public EssentialsHuddleSpaceRoom(DeviceConfig config)
: base(config)
{
try
{
PropertiesConfig = JsonConvert.DeserializeObject<EssentialsHuddleRoomPropertiesConfig>
(config.Properties.ToString());
DefaultDisplay = DeviceManager.GetDeviceForKey(PropertiesConfig.DefaultDisplayKey) as IRoutingSinkWithSwitching;
PropertiesConfig = config.Properties.ToObject<EssentialsHuddleRoomPropertiesConfig>();
DefaultDisplay =
DeviceManager.GetDeviceForKey(PropertiesConfig.DefaultDisplayKey) as IRoutingSinkWithSwitching;
//why are we assuming IRoutingSinkWithSwitching here?
DefaultAudioDevice = DeviceManager.GetDeviceForKey(PropertiesConfig.DefaultAudioKey) as IRoutingSinkWithSwitching;
DefaultAudioDevice =
DeviceManager.GetDeviceForKey(PropertiesConfig.DefaultAudioKey) as IRoutingSinkWithSwitching;
Initialize();
}
@@ -164,16 +31,57 @@ namespace PepperDash.Essentials
}
}
void Initialize()
{
public EssentialsHuddleRoomPropertiesConfig PropertiesConfig { get; private set; }
private void Initialize()
{
if (DefaultAudioDevice is IBasicVolumeControls)
{
DefaultVolumeControls = DefaultAudioDevice as IBasicVolumeControls;
}
else if (DefaultAudioDevice is IHasVolumeDevice)
{
DefaultVolumeControls = (DefaultAudioDevice as IHasVolumeDevice).VolumeDevice;
}
CurrentVolumeControls = DefaultVolumeControls;
SourceListKey = String.IsNullOrEmpty(PropertiesConfig.SourceListKey)
? "default"
: PropertiesConfig.SourceListKey;
EnablePowerOnToLastSource = true;
var disp = DefaultDisplay as DisplayBase;
if (disp != null)
if (disp == null)
{
return;
}
IsWarmingFeedbackFunc = () => disp.IsWarmingUpFeedback.BoolValue;
IsCoolingFeedbackFunc = () => disp.IsCoolingDownFeedback.BoolValue;
OnFeedbackFunc = () => CurrentSourceInfo != null
&& CurrentSourceInfo.Type == eSourceListItemType.Route;
InitializeDisplay(disp);
}
protected override void IsCoolingDownFeedbackOnOutputChange(object sender, FeedbackEventArgs feedbackEventArgs)
{
IsCoolingDownFeedback.FireUpdate();
}
protected override void PowerIsOnFeedbackOnOutputChange(object sender, FeedbackEventArgs feedbackEventArgs)
{
var display = sender as DisplayBase;
if (display == null)
{
return;
}
if (display.PowerIsOnFeedback.BoolValue == OnFeedback.BoolValue)
{
// Link power, warming, cooling to display
var dispTwoWay = disp as IHasPowerControlWithFeedback;
@@ -189,70 +97,57 @@ namespace PepperDash.Essentials
}
};
}
disp.IsWarmingUpFeedback.OutputChange += (o, a) =>
{
IsWarmingUpFeedback.FireUpdate();
if (!IsWarmingUpFeedback.BoolValue)
(DefaultDisplay as IBasicVolumeWithFeedback).SetVolume(DefaultVolume);
};
disp.IsCoolingDownFeedback.OutputChange += (o, a) =>
{
IsCoolingDownFeedback.FireUpdate();
};
}
SourceListKey = "default";
EnablePowerOnToLastSource = true;
}
if (!display.PowerIsOnFeedback.BoolValue)
{
CurrentSourceInfo = null;
}
OnFeedback.FireUpdate();
}
protected override void IsWarmingUpFeedbackOnOutputChange(object sender, FeedbackEventArgs feedbackEventArgs)
{
IsWarmingUpFeedback.FireUpdate();
if (IsWarmingUpFeedback.BoolValue)
{
return;
}
var displayVolumeControl = DefaultDisplay as IBasicVolumeWithFeedback;
if (displayVolumeControl == null)
{
Debug.Console(0, this, Debug.ErrorLogLevel.Error,
"Default display {0} is not volume control control provider", DefaultDisplay.Key);
return;
}
displayVolumeControl.SetVolume(DefaultVolume);
}
protected override void CustomSetConfig(DeviceConfig config)
{
var newPropertiesConfig = JsonConvert.DeserializeObject<EssentialsHuddleRoomPropertiesConfig>(config.Properties.ToString());
var newPropertiesConfig =
JsonConvert.DeserializeObject<EssentialsHuddleRoomPropertiesConfig>(config.Properties.ToString());
if (newPropertiesConfig != null)
PropertiesConfig = newPropertiesConfig;
ConfigWriter.UpdateRoomConfig(config);
}
/// <summary>
///
/// </summary>
protected override void EndShutdown()
{
SetDefaultLevels();
RunDefaultPresentRoute();
CrestronEnvironment.Sleep(1000);
Debug.Console(0, this, Debug.ErrorLogLevel.Notice, "Shutting down room");
RunRouteAction("roomOff");
}
/// <summary>
/// Routes the default source item, if any
/// </summary>
public override bool RunDefaultPresentRoute()
{
if (DefaultSourceItem == null)
{
Debug.Console(0, this, "Unable to run default present route, DefaultSourceItem is null.");
return false;
PropertiesConfig = newPropertiesConfig;
}
RunRouteAction(DefaultSourceItem);
return true;
ConfigWriter.UpdateRoomConfig(config);
}
public override bool CustomActivate()
{
// Add Occupancy object from config
if (PropertiesConfig.Occupancy != null)
this.SetRoomOccupancy(DeviceManager.GetDeviceForKey(PropertiesConfig.Occupancy.DeviceKey) as
{
SetRoomOccupancy(DeviceManager.GetDeviceForKey(PropertiesConfig.Occupancy.DeviceKey) as
IOccupancyStatusProvider, PropertiesConfig.Occupancy.TimeoutMinutes);
}
this.LogoUrlLightBkgnd = PropertiesConfig.LogoLight.GetLogoUrlLight();
this.LogoUrlDarkBkgnd = PropertiesConfig.LogoDark.GetLogoUrlDark();
@@ -263,272 +158,9 @@ namespace PepperDash.Essentials
return base.CustomActivate();
}
/// <summary>
///
/// </summary>
/// <param name="routeKey"></param>
public void RunRouteAction(string routeKey)
{
RunRouteAction(routeKey, new Action(() => { }));
}
/// <summary>
///
/// </summary>
/// <param name="routeKey"></param>
/// <param name="souceListKey"></param>
/// <param name="successCallback"></param>
public void RunRouteAction(string routeKey, string sourceListKey)
{
RunRouteAction(routeKey, new Action(() => { }));
}
/// <summary>
///
/// </summary>
/// <param name="routeKey"></param>
/// <param name="souceListKey"></param>
/// <param name="successCallback"></param>
public void RunRouteAction(string routeKey, string sourceListKey, Action successCallback)
{
if (string.IsNullOrEmpty(sourceListKey))
{
RunRouteAction(routeKey, successCallback);
}
else
throw new NotImplementedException();
}
/// <summary>
/// Gets a source from config list SourceListKey and dynamically build and executes the
/// route or commands
/// </summary>
/// <param name="name"></param>
public void RunRouteAction(string routeKey, Action successCallback)
{
// Run this on a separate thread
new CTimer(o =>
{
Debug.Console(0, this, Debug.ErrorLogLevel.Notice, "Run route action '{0}'", routeKey);
var dict = ConfigReader.ConfigObject.GetSourceListForKey(SourceListKey);
if(dict == null)
{
Debug.Console(1, this, "WARNING: Config source list '{0}' not found", SourceListKey);
return;
}
// Try to get the list item by it's string key
if (!dict.ContainsKey(routeKey))
{
Debug.Console(1, this, "WARNING: No item '{0}' found on config list '{1}'",
routeKey, SourceListKey);
return;
}
var item = dict[routeKey];
//Debug.Console(2, this, "Action {0} has {1} steps",
// item.SourceKey, item.RouteList.Count);
// End usage timer on last source
if (!string.IsNullOrEmpty(LastSourceKey))
{
var lastSource = dict[LastSourceKey].SourceDevice;
try
{
if (lastSource != null && lastSource is IUsageTracking)
(lastSource as IUsageTracking).UsageTracker.EndDeviceUsage();
}
catch (Exception e)
{
Debug.Console(1, this, "*#* EXCEPTION in end usage tracking (257):\r{0}", e);
}
}
// Let's run it
if (routeKey.ToLower() != "roomoff")
{
LastSourceKey = routeKey;
}
else
{
CurrentSourceInfoKey = null;
}
foreach (var route in item.RouteList)
{
// if there is a $defaultAll on route, run two separate
if (route.DestinationKey.Equals("$defaultAll", StringComparison.OrdinalIgnoreCase))
{
// Going to assume a single-path route for now
var tempVideo = new SourceRouteListItem
{
DestinationKey = "$defaultDisplay",
SourceKey = route.SourceKey,
Type = eRoutingSignalType.Video
};
DoRoute(tempVideo);
//var tempAudio = new SourceRouteListItem
//{
// DestinationKey = "$defaultAudio",
// SourceKey = route.SourceKey,
// Type = eRoutingSignalType.Audio
//};
//DoRoute(tempAudio);
//continue; -- not sure why this was here
}
else
DoRoute(route);
}
// Start usage timer on routed source
if (item.SourceDevice is IUsageTracking)
{
(item.SourceDevice as IUsageTracking).UsageTracker.StartDeviceUsage();
}
// Set volume control, using default if non provided
IBasicVolumeControls volDev = null;
// Handle special cases for volume control
if (string.IsNullOrEmpty(item.VolumeControlKey)
|| item.VolumeControlKey.Equals("$defaultAudio", StringComparison.OrdinalIgnoreCase))
volDev = DefaultVolumeControls;
else if (item.VolumeControlKey.Equals("$defaultDisplay", StringComparison.OrdinalIgnoreCase))
volDev = DefaultDisplay as IBasicVolumeControls;
// Or a specific device, probably rarely used.
else
{
var dev = DeviceManager.GetDeviceForKey(item.VolumeControlKey);
if (dev is IBasicVolumeControls)
volDev = dev as IBasicVolumeControls;
else if (dev is IHasVolumeDevice)
volDev = (dev as IHasVolumeDevice).VolumeDevice;
}
if (volDev != CurrentVolumeControls)
{
// zero the volume on the device we are leaving.
// Set the volume to default on device we are entering
if (ZeroVolumeWhenSwtichingVolumeDevices && CurrentVolumeControls is IBasicVolumeWithFeedback)
{
var vd = CurrentVolumeControls as IBasicVolumeWithFeedback;
SavedVolumeLevels[vd] = (uint)vd.VolumeLevelFeedback.IntValue;
vd.SetVolume(0);
}
CurrentVolumeControls = volDev;
if (ZeroVolumeWhenSwtichingVolumeDevices && CurrentVolumeControls is IBasicVolumeWithFeedback)
{
var vd = CurrentVolumeControls as IBasicVolumeWithFeedback;
ushort vol = (SavedVolumeLevels.ContainsKey(vd) ? (ushort)SavedVolumeLevels[vd] : DefaultVolume);
vd.SetVolume(vol);
}
}
// store the name and UI info for routes
if (item.SourceKey == "$off")
{
CurrentSourceInfoKey = routeKey;
CurrentSourceInfo = null;
}
else if (item.SourceKey != null)
{
CurrentSourceInfoKey = routeKey;
CurrentSourceInfo = item;
}
// And finally, set the "control". This will trigger event
//CurrentControlDevice = DeviceManager.GetDeviceForKey(item.SourceKey) as Device;
OnFeedback.FireUpdate();
// report back when done
if (successCallback != null)
successCallback();
}, 0); // end of CTimer
}
/// <summary>
/// Will power the room on with the last-used source
/// </summary>
public override void PowerOnToDefaultOrLastSource()
{
if (!EnablePowerOnToLastSource || LastSourceKey == null)
return;
RunRouteAction(LastSourceKey);
}
/// <summary>
/// Does what it says
/// </summary>
public override void SetDefaultLevels()
{
Debug.Console(1, this, "Restoring default levels");
var vc = CurrentVolumeControls as IBasicVolumeWithFeedback;
if (vc != null)
vc.SetVolume(DefaultVolume);
}
/// <summary>
///
/// </summary>
/// <param name="route"></param>
/// <returns></returns>
bool DoRoute(SourceRouteListItem route)
{
IRoutingSink dest = null;
if (route.DestinationKey.Equals("$defaultaudio", StringComparison.OrdinalIgnoreCase))
dest = DefaultAudioDevice;
else if (route.DestinationKey.Equals("$defaultDisplay", StringComparison.OrdinalIgnoreCase))
dest = DefaultDisplay;
else
dest = DeviceManager.GetDeviceForKey(route.DestinationKey) as IRoutingSink;
if (dest == null)
{
Debug.Console(1, this, "Cannot route, unknown destination '{0}'", route.DestinationKey);
return false;
}
if (route.SourceKey.Equals("$off", StringComparison.OrdinalIgnoreCase))
{
dest.ReleaseRoute();
if (dest is IHasPowerControl)
(dest as IHasPowerControl).PowerOff();
}
else
{
var source = DeviceManager.GetDeviceForKey(route.SourceKey) as IRoutingOutputs;
if (source == null)
{
Debug.Console(1, this, "Cannot route unknown source '{0}' to {1}", route.SourceKey, route.DestinationKey);
return false;
}
dest.ReleaseAndMakeRoute(source, route.Type);
}
return true;
}
public override void RoomVacatedForTimeoutPeriod(object o)
{
//Implement this
//TODO: Implement RoomVacatedForTimeoutPeriod
}
/// <summary>
/// Runs "roomOff" action on all rooms not set to ExcludeFromGlobalFunctions
/// </summary>
public static void AllRoomsOff()
{
var allRooms = DeviceManager.AllDevices.Where(d =>
d is EssentialsHuddleSpaceRoom && !(d as EssentialsHuddleSpaceRoom).ExcludeFromGlobalFunctions);
foreach (var room in allRooms)
(room as EssentialsHuddleSpaceRoom).RunRouteAction("roomOff");
}
}
}
}

View File

@@ -1,7 +1,5 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Crestron.SimplSharp;
using Newtonsoft.Json;
@@ -13,7 +11,7 @@ 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.DeviceTypeInterfaces;
using PepperDash.Essentials.Core.DeviceTypeInterfaces;
namespace PepperDash.Essentials
{
@@ -50,71 +48,7 @@ namespace PepperDash.Essentials
public BoolFeedback IsSharingFeedback { get; private set; }
//************************
public override string SourceListKey
{
get
{
return _SourceListKey;
}
set
{
_SourceListKey = value;
SetCodecExternalSources();
}
}
protected override Func<bool> OnFeedbackFunc
{
get
{
return () =>
{
var disp = DefaultDisplay as DisplayBase;
var val = CurrentSourceInfo != null
&& CurrentSourceInfo.Type == eSourceListItemType.Route
&& disp != null;
//&& disp.PowerIsOnFeedback.BoolValue;
return val;
};
}
}
/// <summary>
///
/// </summary>
protected override Func<bool> IsWarmingFeedbackFunc
{
get
{
return () =>
{
var disp = DefaultDisplay as DisplayBase;
if (disp != null)
return disp.IsWarmingUpFeedback.BoolValue;
else
return false;
};
}
}
/// <summary>
///
/// </summary>
protected override Func<bool> IsCoolingFeedbackFunc
{
get
{
return () =>
{
var disp = DefaultDisplay as DisplayBase;
if (disp != null)
return disp.IsCoolingDownFeedback.BoolValue;
else
return false;
};
}
}
public EssentialsHuddleVtc1PropertiesConfig PropertiesConfig { get; private set; }
public IRoutingSinkWithSwitching DefaultDisplay { get; private set; }
@@ -135,59 +69,31 @@ namespace PepperDash.Essentials
/// If room is off, enables power on to last source. Default true
/// </summary>
public bool EnablePowerOnToLastSource { get; set; }
string LastSourceKey;
/// <summary>
/// Sets the volume control device, and attaches/removes InUseTrackers with "audio"
/// tag to device.
/// </summary>
public IBasicVolumeControls CurrentVolumeControls
{
get { return _CurrentAudioDevice; }
set
{
if (value == _CurrentAudioDevice) return;
var oldDev = _CurrentAudioDevice;
// derigister this room from the device, if it can
if (oldDev is IInUseTracking)
(oldDev as IInUseTracking).InUseTracker.RemoveUser(this, "audio");
var handler = CurrentVolumeDeviceChange;
if (handler != null)
CurrentVolumeDeviceChange(this, new VolumeDeviceChangeEventArgs(oldDev, value, ChangeType.WillChange));
_CurrentAudioDevice = value;
if (handler != null)
CurrentVolumeDeviceChange(this, new VolumeDeviceChangeEventArgs(oldDev, value, ChangeType.DidChange));
// register this room with new device, if it can
if (_CurrentAudioDevice is IInUseTracking)
(_CurrentAudioDevice as IInUseTracking).InUseTracker.AddUser(this, "audio");
}
}
IBasicVolumeControls _CurrentAudioDevice;
private string _lastSourceKey;
/// <summary>
/// The SourceListItem last run - containing names and icons
/// </summary>
public SourceListItem CurrentSourceInfo
{
get { return _CurrentSourceInfo; }
get { return _currentSourceInfo; }
set
{
if (value == _CurrentSourceInfo) return;
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(_currentSourceInfo != null && _currentSourceInfo.SourceDevice is IInUseTracking)
(_currentSourceInfo.SourceDevice as IInUseTracking).InUseTracker.RemoveUser(this, "control");
if (handler != null)
handler(_CurrentSourceInfo, ChangeType.WillChange);
handler(_currentSourceInfo, ChangeType.WillChange);
_CurrentSourceInfo = value;
_currentSourceInfo = value;
// add to in-use tracking
if (_CurrentSourceInfo != null && _CurrentSourceInfo.SourceDevice is IInUseTracking)
(_CurrentSourceInfo.SourceDevice as IInUseTracking).InUseTracker.AddUser(this, "control");
if (_currentSourceInfo != null && _currentSourceInfo.SourceDevice is IInUseTracking)
(_currentSourceInfo.SourceDevice as IInUseTracking).InUseTracker.AddUser(this, "control");
if (handler != null)
handler(_CurrentSourceInfo, ChangeType.DidChange);
@@ -198,7 +104,7 @@ namespace PepperDash.Essentials
}
}
}
SourceListItem _CurrentSourceInfo;
private SourceListItem _currentSourceInfo;
public string CurrentSourceInfoKey { get; set; }
@@ -213,7 +119,7 @@ namespace PepperDash.Essentials
/// </summary>
public IHasScheduleAwareness ScheduleSource { get { return VideoCodec as IHasScheduleAwareness; } }
CCriticalSection SourceSelectLock = new CCriticalSection();
private readonly CCriticalSection _sourceSelectLock = new CCriticalSection();
public EssentialsHuddleVtc1Room(DeviceConfig config)
: base(config)
@@ -232,7 +138,7 @@ namespace PepperDash.Essentials
throw new ArgumentNullException("codec cannot be null");
AudioCodec = DeviceManager.GetDeviceForKey(PropertiesConfig.AudioCodecKey) as
PepperDash.Essentials.Devices.Common.AudioCodec.AudioCodecBase;
AudioCodecBase;
if (AudioCodec == null)
Debug.Console(0, this, "No Audio Codec Found");
@@ -250,8 +156,8 @@ namespace PepperDash.Essentials
{
try
{
if (DefaultAudioDevice is IBasicVolumeControls)
DefaultVolumeControls = DefaultAudioDevice as IBasicVolumeControls;
if (DefaultAudioDevice != null)
DefaultVolumeControls = DefaultAudioDevice;
else if (DefaultAudioDevice is IHasVolumeDevice)
DefaultVolumeControls = (DefaultAudioDevice as IHasVolumeDevice).VolumeDevice;
CurrentVolumeControls = DefaultVolumeControls;
@@ -260,8 +166,8 @@ namespace PepperDash.Essentials
// Combines call feedback from both codecs if available
InCallFeedback = new BoolFeedback(() =>
{
bool inAudioCall = false;
bool inVideoCall = false;
var inAudioCall = false;
var inVideoCall = false;
if (AudioCodec != null)
inAudioCall = AudioCodec.IsInCall;
@@ -269,56 +175,16 @@ namespace PepperDash.Essentials
if (VideoCodec != null)
inVideoCall = VideoCodec.IsInCall;
if (inAudioCall || inVideoCall)
return true;
else
return false;
return inAudioCall || inVideoCall;
});
var disp = DefaultDisplay as DisplayBase;
if (disp != null)
{
// Link power, warming, cooling to display
var dispTwoWay = disp as IHasPowerControlWithFeedback;
if (dispTwoWay != null)
{
dispTwoWay.PowerIsOnFeedback.OutputChange += (o, a) =>
{
if (dispTwoWay.PowerIsOnFeedback.BoolValue != OnFeedback.BoolValue)
{
if (!dispTwoWay.PowerIsOnFeedback.BoolValue)
CurrentSourceInfo = null;
OnFeedback.FireUpdate();
}
if (dispTwoWay.PowerIsOnFeedback.BoolValue)
{
SetDefaultLevels();
}
};
}
disp.IsWarmingUpFeedback.OutputChange += (o, a) =>
{
IsWarmingUpFeedback.FireUpdate();
if (!IsWarmingUpFeedback.BoolValue)
(CurrentVolumeControls as IBasicVolumeWithFeedback).SetVolume(DefaultVolume);
};
disp.IsCoolingDownFeedback.OutputChange += (o, a) =>
{
IsCoolingDownFeedback.FireUpdate();
};
}
// Get Microphone Privacy object, if any MUST HAPPEN AFTER setting InCallFeedback
this.MicrophonePrivacy = EssentialsRoomConfigHelper.GetMicrophonePrivacy(PropertiesConfig, this);
MicrophonePrivacy = EssentialsRoomConfigHelper.GetMicrophonePrivacy(PropertiesConfig, this);
Debug.Console(2, this, "Microphone Privacy Config evaluated.");
// Get emergency object, if any
this.Emergency = EssentialsRoomConfigHelper.GetEmergency(PropertiesConfig, this);
Emergency = EssentialsRoomConfigHelper.GetEmergency(PropertiesConfig, this);
Debug.Console(2, this, "Emergency Config evaluated.");
@@ -327,19 +193,31 @@ namespace PepperDash.Essentials
VideoCodec.IsReadyChange += (o, a) => { this.SetCodecExternalSources(); SetCodecBranding(); };
if (AudioCodec != null)
AudioCodec.CallStatusChange += (o, a) => this.InCallFeedback.FireUpdate();
AudioCodec.CallStatusChange += (o, a) => InCallFeedback.FireUpdate();
IsSharingFeedback = new BoolFeedback(() => VideoCodec.SharingContentIsOnFeedback.BoolValue);
VideoCodec.SharingContentIsOnFeedback.OutputChange += (o, a) => this.IsSharingFeedback.FireUpdate();
VideoCodec.SharingContentIsOnFeedback.OutputChange += (o, a) => IsSharingFeedback.FireUpdate();
// link privacy to VC (for now?)
PrivacyModeIsOnFeedback = new BoolFeedback(() => VideoCodec.PrivacyModeIsOnFeedback.BoolValue);
VideoCodec.PrivacyModeIsOnFeedback.OutputChange += (o, a) => this.PrivacyModeIsOnFeedback.FireUpdate();
VideoCodec.PrivacyModeIsOnFeedback.OutputChange += (o, a) => PrivacyModeIsOnFeedback.FireUpdate();
CallTypeFeedback = new IntFeedback(() => 0);
SourceListKey = "default";
EnablePowerOnToLastSource = true;
var disp = DefaultDisplay as DisplayBase;
if (disp == null)
{
return;
}
OnFeedbackFunc = () => CurrentSourceInfo != null
&& CurrentSourceInfo.Type == eSourceListItemType.Route;
InitializeDisplay(disp);
}
catch (Exception e)
{
@@ -347,6 +225,50 @@ namespace PepperDash.Essentials
}
}
#region Overrides of EssentialsRoomBase
protected override void PowerIsOnFeedbackOnOutputChange(object sender, FeedbackEventArgs args)
{
var disp = sender as DisplayBase;
if (disp == null) return;
if (disp.PowerIsOnFeedback.BoolValue != OnFeedback.BoolValue)
{
if (!disp.PowerIsOnFeedback.BoolValue)
CurrentSourceInfo = null;
OnFeedback.FireUpdate();
}
if (disp.PowerIsOnFeedback.BoolValue)
{
SetDefaultLevels();
}
}
protected override void IsCoolingDownFeedbackOnOutputChange(object sender, FeedbackEventArgs args)
{
IsCoolingDownFeedback.FireUpdate();
}
protected override void IsWarmingUpFeedbackOnOutputChange(object sender, FeedbackEventArgs args)
{
IsWarmingUpFeedback.FireUpdate();
if (IsWarmingUpFeedback.BoolValue)
{
return;
}
var basicVolumeWithFeedback = CurrentVolumeControls as IBasicVolumeWithFeedback;
if (basicVolumeWithFeedback != null)
{
basicVolumeWithFeedback.SetVolume(DefaultVolume);
}
}
#endregion
protected override void CustomSetConfig(DeviceConfig config)
{
var newPropertiesConfig = JsonConvert.DeserializeObject<EssentialsHuddleVtc1PropertiesConfig>(config.Properties.ToString());
@@ -363,7 +285,7 @@ namespace PepperDash.Essentials
if (PropertiesConfig.Occupancy != null)
{
Debug.Console(0, this, Debug.ErrorLogLevel.Notice, "Setting Occupancy Provider for room");
this.SetRoomOccupancy(DeviceManager.GetDeviceForKey(PropertiesConfig.Occupancy.DeviceKey) as
SetRoomOccupancy(DeviceManager.GetDeviceForKey(PropertiesConfig.Occupancy.DeviceKey) as
IOccupancyStatusProvider, PropertiesConfig.Occupancy.TimeoutMinutes);
}
@@ -422,9 +344,9 @@ namespace PepperDash.Essentials
///
/// </summary>
/// <param name="routeKey"></param>
public void RunRouteAction(string routeKey)
public override void RunRouteAction(string routeKey)
{
RunRouteAction(routeKey, new Action(() => { }));
RunRouteAction(routeKey, () => { });
}
/// <summary>
@@ -432,8 +354,7 @@ namespace PepperDash.Essentials
/// </summary>
/// <param name="routeKey"></param>
/// <param name="souceListKey"></param>
/// <param name="successCallback"></param>
public void RunRouteAction(string routeKey, string sourceListKey)
public void RunRouteAction(string routeKey, string souceListKey)
{
if (string.IsNullOrEmpty(sourceListKey))
{
@@ -463,18 +384,18 @@ namespace PepperDash.Essentials
throw new NotImplementedException();
}
/// <summary>
/// Gets a source from config list SourceListKey and dynamically build and executes the
/// route or commands
/// </summary>
/// <param name="name"></param>
/// <summary>
/// Gets a source from config list SourceListKey and dynamically build and executes the
/// route or commands
/// </summary>
public void RunRouteAction(string routeKey, Action successCallback)
{
// Run this on a separate thread
new CTimer(o =>
//new CTimer
CrestronInvoke.BeginInvoke(o =>
{
// try to prevent multiple simultaneous selections
SourceSelectLock.TryEnter();
_sourceSelectLock.TryEnter();
try
{
@@ -496,9 +417,9 @@ namespace PepperDash.Essentials
}
// End usage timer on last source
if (!string.IsNullOrEmpty(LastSourceKey))
if (!string.IsNullOrEmpty(_lastSourceKey))
{
var usageLastSource = dict[LastSourceKey].SourceDevice as IUsageTracking;
var usageLastSource = dict[_lastSourceKey].SourceDevice as IUsageTracking;
if (usageLastSource != null && usageLastSource.UsageTracker != null)
{
try
@@ -518,7 +439,7 @@ namespace PepperDash.Essentials
if (routeKey.ToLower() != "roomoff")
{
LastSourceKey = routeKey;
_lastSourceKey = routeKey;
}
else
CurrentSourceInfoKey = null;
@@ -570,7 +491,7 @@ namespace PepperDash.Essentials
if (ZeroVolumeWhenSwtichingVolumeDevices && CurrentVolumeControls is IBasicVolumeWithFeedback)
{
var vd = CurrentVolumeControls as IBasicVolumeWithFeedback;
ushort vol = (SavedVolumeLevels.ContainsKey(vd) ? (ushort)SavedVolumeLevels[vd] : DefaultVolume);
var vol = (SavedVolumeLevels.ContainsKey(vd) ? (ushort)SavedVolumeLevels[vd] : DefaultVolume);
vd.SetVolume(vol);
}
}
@@ -614,7 +535,7 @@ namespace PepperDash.Essentials
Debug.Console(1, this, "ERROR in routing: {0}", e);
}
SourceSelectLock.Leave();
_sourceSelectLock.Leave();
}, 0); // end of CTimer
}
@@ -645,9 +566,9 @@ namespace PepperDash.Essentials
/// </summary>
/// <param name="route"></param>
/// <returns></returns>
bool DoRoute(SourceRouteListItem route)
private bool DoRoute(SourceRouteListItem route)
{
IRoutingSink dest = null;
IRoutingSink dest;
if (route.DestinationKey.Equals("$defaultaudio", StringComparison.OrdinalIgnoreCase))
dest = DefaultAudioDevice as IRoutingSinkNoSwitching;
@@ -702,9 +623,9 @@ namespace PepperDash.Essentials
/// </summary>
public override void PowerOnToDefaultOrLastSource()
{
if (!EnablePowerOnToLastSource || LastSourceKey == null)
if (!EnablePowerOnToLastSource || _lastSourceKey == null)
return;
RunRouteAction(LastSourceKey);
RunRouteAction(_lastSourceKey);
}
/// <summary>
@@ -715,7 +636,13 @@ namespace PepperDash.Essentials
var allRooms = DeviceManager.AllDevices.Where(d =>
d is EssentialsHuddleSpaceRoom && !(d as EssentialsHuddleSpaceRoom).ExcludeFromGlobalFunctions);
foreach (var room in allRooms)
(room as EssentialsHuddleSpaceRoom).RunRouteAction("roomOff");
{
var essentialsHuddleSpaceRoom = room as EssentialsHuddleSpaceRoom;
if (essentialsHuddleSpaceRoom != null)
{
essentialsHuddleSpaceRoom.RunRouteAction("roomOff");
}
}
}

View File

@@ -1,16 +1,6 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Crestron.SimplSharp;
using Newtonsoft.Json;
using PepperDash.Core;
using System.Collections.Generic;
using PepperDash.Essentials.Core;
using PepperDash.Essentials.Core.Devices;
using PepperDash.Essentials.Core.Config;
using PepperDash.Essentials.Room.Config;
namespace PepperDash.Essentials
{
@@ -23,7 +13,7 @@ namespace PepperDash.Essentials
public Dictionary<eSourceListItemDestinationTypes, IRoutingSinkWithSwitching> Displays { get; protected set;}
public EssentialsNDisplayRoomBase(DeviceConfig config)
protected EssentialsNDisplayRoomBase(DeviceConfig config)
: base (config)
{
Displays = new Dictionary<eSourceListItemDestinationTypes, IRoutingSinkWithSwitching>();

View File

@@ -111,7 +111,7 @@ namespace PepperDash.Essentials
/// <summary>
/// Reads the device keys from the config and gets the devices by key
/// </summary>
public void GetDevicesFromConfig(Room.Config.EssentialsEnvironmentPropertiesConfig EnvironmentPropertiesConfig)
public void GetDevicesFromConfig(Core.Rooms.Config.EssentialsEnvironmentPropertiesConfig EnvironmentPropertiesConfig)
{
if (EnvironmentPropertiesConfig != null)
{

View File

@@ -10,10 +10,11 @@ using Crestron.SimplSharpPro.DeviceSupport;
using PepperDash.Core;
using PepperDash.Essentials.Core;
using PepperDash.Essentials.Core.Devices.VideoCodec;
using PepperDash.Essentials.Core.SmartObjects;
using PepperDash.Essentials.Core.PageManagers;
using PepperDash.Essentials.Room.Config;
using PepperDash.Essentials.Devices.Common.Codec;
using PepperDash.Essentials.Core.Rooms.Config;
using PepperDash.Essentials.Core.Devices.Codec;
using PepperDash.Essentials.Devices.Common.VideoCodec;

View File

@@ -2,13 +2,11 @@
using System.Collections.Generic;
using Crestron.SimplSharp;
using Crestron.SimplSharpPro;
using Crestron.SimplSharpPro.UI;
using PepperDash.Core;
using PepperDash.Essentials.Core;
using PepperDash.Essentials.Core.Config;
using PepperDash.Essentials.Core.SmartObjects;
using PepperDash.Essentials.Core.PageManagers;
using PepperDash.Essentials.UIDrivers;
namespace PepperDash.Essentials
{
@@ -17,13 +15,18 @@ namespace PepperDash.Essentials
/// </summary>
public class EssentialsHuddlePanelAvFunctionsDriver : PanelDriverBase, IAVDriver
{
CrestronTouchpanelPropertiesConfig Config;
private readonly CrestronTouchpanelPropertiesConfig _config;
public enum UiDisplayMode
{
PresentationMode, AudioSetup
}
/// <summary>
/// The parent driver for this
/// </summary>
public PanelDriverBase Parent { get; private set; }
public uint StartPageVisibleJoin { get; private set; }
@@ -38,8 +41,8 @@ namespace PepperDash.Essentials
/// </summary>
public uint VolumeButtonPopupTimeout
{
get { return VolumeButtonsPopupFeedback.TimeoutMs; }
set { VolumeButtonsPopupFeedback.TimeoutMs = value; }
get { return _volumeButtonsPopupFeedback.TimeoutMs; }
set { _volumeButtonsPopupFeedback.TimeoutMs = value; }
}
/// <summary>
@@ -47,8 +50,8 @@ namespace PepperDash.Essentials
/// </summary>
public uint VolumeGaugePopupTimeout
{
get { return VolumeGaugeFeedback.TimeoutMs; }
set { VolumeGaugeFeedback.TimeoutMs = value; }
get { return _volumeGaugeFeedback.TimeoutMs; }
set { _volumeGaugeFeedback.TimeoutMs = value; }
}
/// <summary>
@@ -56,21 +59,12 @@ namespace PepperDash.Essentials
/// </summary>
public uint PowerOffTimeout { get; set; }
/// <summary>
///
/// </summary>
public string DefaultRoomKey
{
get { return _DefaultRoomKey; }
set
{
_DefaultRoomKey = value;
//CurrentRoom = DeviceManager.GetDeviceForKey(value) as EssentialsHuddleSpaceRoom;
}
}
string _DefaultRoomKey;
/// <summary>
///
/// </summary>
public string DefaultRoomKey { get; set; }
/// <summary>
/// <summary>
/// Indicates that the SetHeaderButtons method has completed successfully
/// </summary>
public bool HeaderButtonsAreSetUp { get; private set; }
@@ -80,13 +74,13 @@ namespace PepperDash.Essentials
/// </summary>
public EssentialsHuddleSpaceRoom CurrentRoom
{
get { return _CurrentRoom; }
get { return _currentRoom; }
set
{
SetCurrentRoom(value);
}
}
EssentialsHuddleSpaceRoom _CurrentRoom;
EssentialsHuddleSpaceRoom _currentRoom;
/// <summary>
///
@@ -96,88 +90,86 @@ namespace PepperDash.Essentials
/// <summary>
/// For hitting feedback
/// </summary>
BoolInputSig ShareButtonSig;
BoolInputSig EndMeetingButtonSig;
private readonly BoolInputSig _shareButtonSig;
private BoolInputSig _endMeetingButtonSig;
/// <summary>
/// Controls the extended period that the volume gauge shows on-screen,
/// as triggered by Volume up/down operations
/// </summary>
BoolFeedbackPulseExtender VolumeGaugeFeedback;
private readonly BoolFeedbackPulseExtender _volumeGaugeFeedback;
/// <summary>
/// Controls the period that the volume buttons show on non-hard-button
/// interfaces
/// </summary>
BoolFeedbackPulseExtender VolumeButtonsPopupFeedback;
private readonly BoolFeedbackPulseExtender _volumeButtonsPopupFeedback;
/// <summary>
/// The parent driver for this
/// </summary>
public PanelDriverBase Parent { get; private set; }
private readonly PanelDriverBase _parent;
/// <summary>
/// All children attached to this driver. For hiding and showing as a group.
/// </summary>
List<PanelDriverBase> ChildDrivers = new List<PanelDriverBase>();
private List<PanelDriverBase> _childDrivers = new List<PanelDriverBase>();
List<BoolInputSig> CurrentDisplayModeSigsInUse = new List<BoolInputSig>();
private readonly List<BoolInputSig> _currentDisplayModeSigsInUse = new List<BoolInputSig>();
//// Important smart objects
/// <summary>
/// Smart Object 3200
/// </summary>
SubpageReferenceList SourcesSrl;
private readonly SubpageReferenceList _sourcesSrl;
/// <summary>
/// Smart Object 15022
/// </summary>
SubpageReferenceList ActivityFooterSrl;
private readonly SubpageReferenceList _activityFooterSrl;
/// <summary>
/// Tracks which audio page group the UI is in
/// </summary>
UiDisplayMode CurrentDisplayMode;
private UiDisplayMode _currentDisplayMode;
/// <summary>
/// The AV page mangagers that have been used, to keep them alive for later
/// </summary>
Dictionary<object, PageManager> PageManagers = new Dictionary<object, PageManager>();
private readonly Dictionary<object, PageManager> _pageManagers = new Dictionary<object, PageManager>();
/// <summary>
/// Current page manager running for a source
/// </summary>
PageManager CurrentSourcePageManager;
private PageManager _currentSourcePageManager;
/// <summary>
/// Will auto-timeout a power off
/// </summary>
CTimer PowerOffTimer;
private CTimer _powerOffTimer;
ModalDialog PowerDownModal;
private ModalDialog _powerDownModal;
public JoinedSigInterlock PopupInterlock { get; private set; }
/// <summary>
/// The driver for the tech page. Lazy getter for memory usage
/// </summary>
PepperDash.Essentials.UIDrivers.EssentialsHuddleTechPageDriver TechDriver
EssentialsHuddleTechPageDriver TechDriver
{
get
{
if (_TechDriver == null)
_TechDriver = new PepperDash.Essentials.UIDrivers.EssentialsHuddleTechPageDriver(TriList, CurrentRoom.PropertiesConfig.Tech);
return _TechDriver;
get {
return _techDriver ??
(_techDriver = new EssentialsHuddleTechPageDriver(TriList, CurrentRoom.PropertiesConfig.Tech));
}
}
PepperDash.Essentials.UIDrivers.EssentialsHuddleTechPageDriver _TechDriver;
private EssentialsHuddleTechPageDriver _techDriver;
/// <summary>
/// Controls timeout of notification ribbon timer
/// </summary>
CTimer RibbonTimer;
private CTimer _ribbonTimer;
/// <summary>
/// Constructor
@@ -185,25 +177,25 @@ namespace PepperDash.Essentials
public EssentialsHuddlePanelAvFunctionsDriver(PanelDriverBase parent, CrestronTouchpanelPropertiesConfig config)
: base(parent.TriList)
{
Config = config;
Parent = parent;
_config = config;
_parent = parent;
PopupInterlock = new JoinedSigInterlock(TriList);
SourcesSrl = new SubpageReferenceList(TriList, 3200, 3, 3, 3);
ActivityFooterSrl = new SubpageReferenceList(TriList, 15022, 3, 3, 3);
ShareButtonSig = ActivityFooterSrl.BoolInputSig(1, 1);
_sourcesSrl = new SubpageReferenceList(TriList, 3200, 3, 3, 3);
_activityFooterSrl = new SubpageReferenceList(TriList, 15022, 3, 3, 3);
_shareButtonSig = _activityFooterSrl.BoolInputSig(1, 1);
SetupActivityFooterWhenRoomOff();
ShowVolumeGauge = true;
// One-second pulse extender for volume gauge
VolumeGaugeFeedback = new BoolFeedbackPulseExtender(1500);
VolumeGaugeFeedback.Feedback
_volumeGaugeFeedback = new BoolFeedbackPulseExtender(1500);
_volumeGaugeFeedback.Feedback
.LinkInputSig(TriList.BooleanInput[UIBoolJoin.VolumeGaugePopupVisible]);
VolumeButtonsPopupFeedback = new BoolFeedbackPulseExtender(4000);
VolumeButtonsPopupFeedback.Feedback
_volumeButtonsPopupFeedback = new BoolFeedbackPulseExtender(4000);
_volumeButtonsPopupFeedback.Feedback
.LinkInputSig(TriList.BooleanInput[UIBoolJoin.VolumeButtonPopupVisible]);
PowerOffTimeout = 30000;
@@ -224,9 +216,28 @@ namespace PepperDash.Essentials
return;
}
var roomConf = CurrentRoom.PropertiesConfig;
switch (_config.HeaderStyle.ToLower())
{
case CrestronTouchpanelPropertiesConfig.Habanero:
TriList.SetSigFalseAction(UIBoolJoin.HeaderRoomButtonPress, (() =>
{
if (CurrentRoom.IsMobileControlEnabled)
{
Debug.Console(1, "Showing Mobile Control Header Info");
PopupInterlock.ShowInterlockedWithToggle(UIBoolJoin.RoomHeaderInfoMCPageVisible);
}
else
{
Debug.Console(1, "Showing Non Mobile Control Header Info");
PopupInterlock.ShowInterlockedWithToggle(UIBoolJoin.RoomHeaderInfoPageVisible);
}
}));
break;
case CrestronTouchpanelPropertiesConfig.Verbose:
break;
}
if (Config.HeaderStyle.ToLower() == CrestronTouchpanelPropertiesConfig.Habanero)
if (_config.HeaderStyle.ToLower() == CrestronTouchpanelPropertiesConfig.Habanero)
{
TriList.SetSigFalseAction(UIBoolJoin.HeaderRoomButtonPress, () =>
{
@@ -242,7 +253,7 @@ namespace PepperDash.Essentials
}
});
}
else if (Config.HeaderStyle.ToLower() == CrestronTouchpanelPropertiesConfig.Verbose)
else if (_config.HeaderStyle.ToLower() == CrestronTouchpanelPropertiesConfig.Verbose)
{
TriList.SetSigFalseAction(UIBoolJoin.HeaderRoomButtonPress, () =>
{
@@ -259,9 +270,9 @@ namespace PepperDash.Essentials
});
}
TriList.SetBool(UIBoolJoin.DateAndTimeVisible, Config.ShowDate && Config.ShowTime);
TriList.SetBool(UIBoolJoin.DateOnlyVisible, Config.ShowDate && !Config.ShowTime);
TriList.SetBool(UIBoolJoin.TimeOnlyVisible, !Config.ShowDate && Config.ShowTime);
TriList.SetBool(UIBoolJoin.DateAndTimeVisible, _config.ShowDate && _config.ShowTime);
TriList.SetBool(UIBoolJoin.DateOnlyVisible, _config.ShowDate && !_config.ShowTime);
TriList.SetBool(UIBoolJoin.TimeOnlyVisible, !_config.ShowDate && _config.ShowTime);
TriList.SetBool(UIBoolJoin.TopBarHabaneroDynamicVisible, true);
TriList.BooleanInput[UIBoolJoin.ActivityFooterVisible].BoolValue = true;
@@ -348,8 +359,8 @@ namespace PepperDash.Essentials
{
TriList.SetBool(UIBoolJoin.LogoDefaultVisible, false);
TriList.SetBool(UIBoolJoin.LogoUrlVisible, true);
TriList.SetString(UIStringJoin.LogoUrlLightBkgnd, _CurrentRoom.LogoUrlLightBkgnd);
TriList.SetString(UIStringJoin.LogoUrlDarkBkgnd, _CurrentRoom.LogoUrlDarkBkgnd);
TriList.SetString(UIStringJoin.LogoUrlLightBkgnd, _currentRoom.LogoUrlLightBkgnd);
TriList.SetString(UIStringJoin.LogoUrlDarkBkgnd, _currentRoom.LogoUrlDarkBkgnd);
}
}
@@ -374,7 +385,7 @@ namespace PepperDash.Essentials
TriList.BooleanInput[UIBoolJoin.TapToBeginVisible].BoolValue = false;
TriList.BooleanInput[UIBoolJoin.SelectASourceVisible].BoolValue = false;
//TriList.BooleanInput[UIBoolJoin.StagingPageVisible].BoolValue = false;
VolumeButtonsPopupFeedback.ClearNow();
_volumeButtonsPopupFeedback.ClearNow();
//CancelPowerOff();
base.Hide();
@@ -391,12 +402,12 @@ namespace PepperDash.Essentials
TriList.SetBool(UIBoolJoin.NotificationRibbonVisible, true);
if (timeout > 0)
{
if (RibbonTimer != null)
RibbonTimer.Stop();
RibbonTimer = new CTimer(o =>
if (_ribbonTimer != null)
_ribbonTimer.Stop();
_ribbonTimer = new CTimer(o =>
{
TriList.SetBool(UIBoolJoin.NotificationRibbonVisible, false);
RibbonTimer = null;
_ribbonTimer = null;
}, timeout);
}
}
@@ -407,10 +418,10 @@ namespace PepperDash.Essentials
public void HideNotificationRibbon()
{
TriList.SetBool(UIBoolJoin.NotificationRibbonVisible, false);
if (RibbonTimer != null)
if (_ribbonTimer != null)
{
RibbonTimer.Stop();
RibbonTimer = null;
_ribbonTimer.Stop();
_ribbonTimer = null;
}
}
@@ -422,7 +433,7 @@ namespace PepperDash.Essentials
{
//Clear whatever is showing now.
HideAndClearCurrentDisplayModeSigsInUse();
CurrentDisplayMode = mode;
_currentDisplayMode = mode;
switch (mode)
{
case UiDisplayMode.PresentationMode:
@@ -440,7 +451,7 @@ namespace PepperDash.Essentials
TriList.BooleanInput[UIBoolJoin.SelectASourceVisible].BoolValue = false;
}
// Date/time
if (Config.ShowDate && Config.ShowTime)
if (_config.ShowDate && _config.ShowTime)
{
TriList.BooleanInput[UIBoolJoin.DateAndTimeVisible].BoolValue = true;
TriList.BooleanInput[UIBoolJoin.DateOnlyVisible].BoolValue = false;
@@ -449,8 +460,8 @@ namespace PepperDash.Essentials
else
{
TriList.BooleanInput[UIBoolJoin.DateAndTimeVisible].BoolValue = false;
TriList.BooleanInput[UIBoolJoin.DateOnlyVisible].BoolValue = Config.ShowDate;
TriList.BooleanInput[UIBoolJoin.TimeOnlyVisible].BoolValue = Config.ShowTime;
TriList.BooleanInput[UIBoolJoin.DateOnlyVisible].BoolValue = _config.ShowDate;
TriList.BooleanInput[UIBoolJoin.TimeOnlyVisible].BoolValue = _config.ShowTime;
}
ShowCurrentDisplayModeSigsInUse();
@@ -463,12 +474,12 @@ namespace PepperDash.Essentials
/// </summary>
void SetupActivityFooterWhenRoomOff()
{
ActivityFooterSrl.Clear();
ActivityFooterSrl.AddItem(new SubpageReferenceListActivityItem(1, ActivityFooterSrl, 0,
_activityFooterSrl.Clear();
_activityFooterSrl.AddItem(new SubpageReferenceListActivityItem(1, _activityFooterSrl, 0,
b => { if (!b) ShareButtonPressed(); }));
ActivityFooterSrl.Count = 1;
_activityFooterSrl.Count = 1;
TriList.UShortInput[UIUshortJoin.PresentationStagingCaretMode].UShortValue = 0;
ShareButtonSig.BoolValue = false;
_shareButtonSig.BoolValue = false;
}
/// <summary>
@@ -476,15 +487,15 @@ namespace PepperDash.Essentials
/// </summary>
void SetupActivityFooterWhenRoomOn()
{
ActivityFooterSrl.Clear();
ActivityFooterSrl.AddItem(new SubpageReferenceListActivityItem(1, ActivityFooterSrl,
_activityFooterSrl.Clear();
_activityFooterSrl.AddItem(new SubpageReferenceListActivityItem(1, _activityFooterSrl,
0, null));
ActivityFooterSrl.AddItem(new SubpageReferenceListActivityItem(2, ActivityFooterSrl,
_activityFooterSrl.AddItem(new SubpageReferenceListActivityItem(2, _activityFooterSrl,
4, b => { if (!b) PowerButtonPressed(); }));
ActivityFooterSrl.Count = 2;
_activityFooterSrl.Count = 2;
TriList.UShortInput[UIUshortJoin.PresentationStagingCaretMode].UShortValue = 1;
EndMeetingButtonSig = ActivityFooterSrl.BoolInputSig(2, 1);
ShareButtonSig.BoolValue = CurrentRoom.OnFeedback.BoolValue;
_endMeetingButtonSig = _activityFooterSrl.BoolInputSig(2, 1);
_shareButtonSig.BoolValue = CurrentRoom.OnFeedback.BoolValue;
}
/// <summary>
@@ -492,8 +503,8 @@ namespace PepperDash.Essentials
/// </summary>
void ShareButtonPressed()
{
ShareButtonSig.BoolValue = true;
TriList.BooleanInput[StartPageVisibleJoin].BoolValue = false;
_shareButtonSig.BoolValue = true;
TriList.BooleanInput[UIBoolJoin.StartPageVisible].BoolValue = false;
TriList.BooleanInput[UIBoolJoin.SourceStagingBarVisible].BoolValue = true;
TriList.BooleanInput[UIBoolJoin.SelectASourceVisible].BoolValue = true;
// Run default source when room is off and share is pressed
@@ -507,7 +518,7 @@ namespace PepperDash.Essentials
/// </summary>
void ShowCurrentDisplayModeSigsInUse()
{
foreach (var sig in CurrentDisplayModeSigsInUse)
foreach (var sig in _currentDisplayModeSigsInUse)
sig.BoolValue = true;
}
@@ -516,9 +527,9 @@ namespace PepperDash.Essentials
/// </summary>
void HideAndClearCurrentDisplayModeSigsInUse()
{
foreach (var sig in CurrentDisplayModeSigsInUse)
foreach (var sig in _currentDisplayModeSigsInUse)
sig.BoolValue = false;
CurrentDisplayModeSigsInUse.Clear();
_currentDisplayModeSigsInUse.Clear();
}
/// <summary>
@@ -526,7 +537,7 @@ namespace PepperDash.Essentials
/// </summary>
public override void BackButtonPressed()
{
switch (CurrentDisplayMode)
switch (_currentDisplayMode)
{
case UiDisplayMode.PresentationMode:
//CancelReturnToSourceTimer();
@@ -541,7 +552,7 @@ namespace PepperDash.Essentials
void BackToHome()
{
Hide();
Parent.Show();
_parent.Show();
}
/// <summary>
@@ -553,26 +564,28 @@ namespace PepperDash.Essentials
return;
var uiDev = CurrentRoom.CurrentSourceInfo.SourceDevice as IUiDisplayInfo;
PageManager pm = null;
// If we need a page manager, get an appropriate one
if (uiDev != null)
{
TriList.BooleanInput[UIBoolJoin.SelectASourceVisible].BoolValue = false;
// Got an existing page manager, get it
if (PageManagers.ContainsKey(uiDev))
pm = PageManagers[uiDev];
// Otherwise make an apporiate one
else if (uiDev is ISetTopBoxControls)
//pm = new SetTopBoxMediumPageManager(uiDev as ISetTopBoxControls, TriList);
pm = new SetTopBoxThreePanelPageManager(uiDev as ISetTopBoxControls, TriList);
else if (uiDev is IDiscPlayerControls)
pm = new DiscPlayerMediumPageManager(uiDev as IDiscPlayerControls, TriList);
else
pm = new DefaultPageManager(uiDev, TriList);
PageManagers[uiDev] = pm;
CurrentSourcePageManager = pm;
pm.Show();
}
// If we need a page manager, get an appropriate one
if (uiDev == null)
{
return;
}
TriList.BooleanInput[UIBoolJoin.SelectASourceVisible].BoolValue = false;
// Got an existing page manager, get it
PageManager pm;
if (_pageManagers.ContainsKey(uiDev))
pm = _pageManagers[uiDev];
// Otherwise make an apporiate one
else if (uiDev is ISetTopBoxControls)
//pm = new SetTopBoxMediumPageManager(uiDev as ISetTopBoxControls, TriList);
pm = new SetTopBoxThreePanelPageManager(uiDev as ISetTopBoxControls, TriList);
else if (uiDev is IDiscPlayerControls)
pm = new DiscPlayerMediumPageManager(uiDev as IDiscPlayerControls, TriList);
else
pm = new DefaultPageManager(uiDev, TriList);
_pageManagers[uiDev] = pm;
_currentSourcePageManager = pm;
pm.Show();
}
/// <summary>
@@ -583,7 +596,7 @@ namespace PepperDash.Essentials
void UiSelectSource(string key)
{
// Run the route and when it calls back, show the source
CurrentRoom.RunRouteAction(key, new Action(() => { }));
CurrentRoom.RunRouteAction(key, () => { });
}
/// <summary>
@@ -607,12 +620,12 @@ namespace PepperDash.Essentials
{
// Do we need to check where the UI is? No?
var timer = CurrentRoom.ShutdownPromptTimer;
EndMeetingButtonSig.BoolValue = true;
ShareButtonSig.BoolValue = false;
_endMeetingButtonSig.BoolValue = true;
_shareButtonSig.BoolValue = false;
if (CurrentRoom.ShutdownType == eShutdownType.Manual || CurrentRoom.ShutdownType == eShutdownType.Vacancy)
{
PowerDownModal = new ModalDialog(TriList);
_powerDownModal = new ModalDialog(TriList);
var message = string.Format("Meeting will end in {0} seconds", CurrentRoom.ShutdownPromptSeconds);
// Attach timer things to modal
@@ -626,15 +639,15 @@ namespace PepperDash.Essentials
{
if (!onFb.BoolValue)
{
EndMeetingButtonSig.BoolValue = false;
PowerDownModal.HideDialog();
_endMeetingButtonSig.BoolValue = false;
_powerDownModal.HideDialog();
onFb.OutputChange -= offHandler;
//gauge.OutputChange -= gaugeHandler;
}
};
onFb.OutputChange += offHandler;
PowerDownModal.PresentModalDialog(2, "End Meeting", "Power", message, "Cancel", "End Meeting Now", true, true,
_powerDownModal.PresentModalDialog(2, "End Meeting", "Power", message, "Cancel", "End Meeting Now", true, true,
but =>
{
if (but != 2) // any button except for End cancels
@@ -652,7 +665,7 @@ namespace PepperDash.Essentials
/// <param name="e"></param>
void ShutdownPromptTimer_HasFinished(object sender, EventArgs e)
{
EndMeetingButtonSig.BoolValue = false;
_endMeetingButtonSig.BoolValue = false;
CurrentRoom.ShutdownPromptTimer.TimeRemainingFeedback.OutputChange -= ShutdownPromptTimer_TimeRemainingFeedback_OutputChange;
CurrentRoom.ShutdownPromptTimer.PercentFeedback.OutputChange -= ShutdownPromptTimer_PercentFeedback_OutputChange;
}
@@ -664,10 +677,10 @@ namespace PepperDash.Essentials
/// <param name="e"></param>
void ShutdownPromptTimer_WasCancelled(object sender, EventArgs e)
{
if (PowerDownModal != null)
PowerDownModal.HideDialog();
EndMeetingButtonSig.BoolValue = false;
ShareButtonSig.BoolValue = CurrentRoom.OnFeedback.BoolValue;
if (_powerDownModal != null)
_powerDownModal.HideDialog();
_endMeetingButtonSig.BoolValue = false;
_shareButtonSig.BoolValue = CurrentRoom.OnFeedback.BoolValue;
CurrentRoom.ShutdownPromptTimer.TimeRemainingFeedback.OutputChange += ShutdownPromptTimer_TimeRemainingFeedback_OutputChange;
CurrentRoom.ShutdownPromptTimer.PercentFeedback.OutputChange -= ShutdownPromptTimer_PercentFeedback_OutputChange;
@@ -675,27 +688,38 @@ namespace PepperDash.Essentials
void ShutdownPromptTimer_TimeRemainingFeedback_OutputChange(object sender, EventArgs e)
{
var stringFeedback = sender as StringFeedback;
if (stringFeedback == null)
{
return;
}
var message = string.Format("Meeting will end in {0} seconds", (sender as StringFeedback).StringValue);
var message = string.Format("Meeting will end in {0} seconds", stringFeedback.StringValue);
TriList.StringInput[ModalDialog.MessageTextJoin].StringValue = message;
}
void ShutdownPromptTimer_PercentFeedback_OutputChange(object sender, EventArgs e)
{
var value = (ushort)((sender as IntFeedback).UShortValue * 65535 / 100);
TriList.UShortInput[ModalDialog.TimerGaugeJoin].UShortValue = value;
}
void ShutdownPromptTimer_PercentFeedback_OutputChange(object sender, EventArgs e)
{
var intFeedback = sender as IntFeedback;
if (intFeedback == null)
{
return;
}
var value = (ushort)(intFeedback.UShortValue * 65535 / 100);
TriList.UShortInput[ModalDialog.TimerGaugeJoin].UShortValue = value;
}
/// <summary>
/// <summary>
///
/// </summary>
void CancelPowerOffTimer()
{
if (PowerOffTimer != null)
{
PowerOffTimer.Stop();
PowerOffTimer = null;
}
if (_powerOffTimer == null)
{
return;
}
_powerOffTimer.Stop();
_powerOffTimer = null;
}
/// <summary>
@@ -703,13 +727,13 @@ namespace PepperDash.Essentials
/// </summary>
void VolumeButtonsTogglePress()
{
if (VolumeButtonsPopupFeedback.BoolValue)
VolumeButtonsPopupFeedback.ClearNow();
if (_volumeButtonsPopupFeedback.BoolValue)
_volumeButtonsPopupFeedback.ClearNow();
else
{
// Trigger the popup
VolumeButtonsPopupFeedback.BoolValue = true;
VolumeButtonsPopupFeedback.BoolValue = false;
_volumeButtonsPopupFeedback.BoolValue = true;
_volumeButtonsPopupFeedback.BoolValue = false;
}
}
@@ -721,8 +745,8 @@ namespace PepperDash.Essentials
{
// extend timeouts
if (ShowVolumeGauge)
VolumeGaugeFeedback.BoolValue = state;
VolumeButtonsPopupFeedback.BoolValue = state;
_volumeGaugeFeedback.BoolValue = state;
_volumeButtonsPopupFeedback.BoolValue = state;
if (CurrentRoom.CurrentVolumeControls != null)
CurrentRoom.CurrentVolumeControls.VolumeUp(state);
}
@@ -735,8 +759,8 @@ namespace PepperDash.Essentials
{
// extend timeouts
if (ShowVolumeGauge)
VolumeGaugeFeedback.BoolValue = state;
VolumeButtonsPopupFeedback.BoolValue = state;
_volumeGaugeFeedback.BoolValue = state;
_volumeButtonsPopupFeedback.BoolValue = state;
if (CurrentRoom.CurrentVolumeControls != null)
CurrentRoom.CurrentVolumeControls.VolumeDown(state);
}
@@ -747,31 +771,31 @@ namespace PepperDash.Essentials
/// </summary>
public void RefreshCurrentRoom(EssentialsHuddleSpaceRoom room)
{
if (_CurrentRoom != null)
if (_currentRoom != null)
{
// Disconnect current room
_CurrentRoom.CurrentVolumeDeviceChange -= this.CurrentRoom_CurrentAudioDeviceChange;
_currentRoom.CurrentVolumeDeviceChange -= CurrentRoom_CurrentAudioDeviceChange;
ClearAudioDeviceConnections();
_CurrentRoom.CurrentSourceChange -= this.CurrentRoom_SourceInfoChange;
DisconnectSource(_CurrentRoom.CurrentSourceInfo);
_CurrentRoom.ShutdownPromptTimer.HasStarted -= ShutdownPromptTimer_HasStarted;
_CurrentRoom.ShutdownPromptTimer.HasFinished -= ShutdownPromptTimer_HasFinished;
_CurrentRoom.ShutdownPromptTimer.WasCancelled -= ShutdownPromptTimer_WasCancelled;
_currentRoom.CurrentSourceChange -= CurrentRoom_SourceInfoChange;
DisconnectSource(_currentRoom.CurrentSourceInfo);
_currentRoom.ShutdownPromptTimer.HasStarted -= ShutdownPromptTimer_HasStarted;
_currentRoom.ShutdownPromptTimer.HasFinished -= ShutdownPromptTimer_HasFinished;
_currentRoom.ShutdownPromptTimer.WasCancelled -= ShutdownPromptTimer_WasCancelled;
_CurrentRoom.OnFeedback.OutputChange -= CurrentRoom_OnFeedback_OutputChange;
_CurrentRoom.IsWarmingUpFeedback.OutputChange -= CurrentRoom_IsWarmingFeedback_OutputChange;
_CurrentRoom.IsCoolingDownFeedback.OutputChange -= IsCoolingDownFeedback_OutputChange;
_currentRoom.OnFeedback.OutputChange -= CurrentRoom_OnFeedback_OutputChange;
_currentRoom.IsWarmingUpFeedback.OutputChange -= CurrentRoom_IsWarmingFeedback_OutputChange;
_currentRoom.IsCoolingDownFeedback.OutputChange -= IsCoolingDownFeedback_OutputChange;
}
_CurrentRoom = room;
_currentRoom = room;
if (_CurrentRoom != null)
if (_currentRoom != null)
{
// get the source list config and set up the source list
var config = ConfigReader.ConfigObject.SourceLists;
if (config.ContainsKey(_CurrentRoom.SourceListKey))
if (config.ContainsKey(_currentRoom.SourceListKey))
{
var srcList = config[_CurrentRoom.SourceListKey];
var srcList = config[_currentRoom.SourceListKey];
// Setup sources list
uint i = 1; // counter for UI list
foreach (var kvp in srcList)
@@ -788,16 +812,16 @@ namespace PepperDash.Essentials
continue;
}
var routeKey = kvp.Key;
var item = new SubpageReferenceListSourceItem(i++, SourcesSrl, srcConfig,
var item = new SubpageReferenceListSourceItem(i++, _sourcesSrl, srcConfig,
b => { if (!b) UiSelectSource(routeKey); });
SourcesSrl.AddItem(item); // add to the SRL
item.RegisterForSourceChange(_CurrentRoom);
_sourcesSrl.AddItem(item); // add to the SRL
item.RegisterForSourceChange(_currentRoom);
}
SourcesSrl.Count = (ushort)(i - 1);
_sourcesSrl.Count = (ushort)(i - 1);
}
// Name and logo
TriList.StringInput[UIStringJoin.CurrentRoomName].StringValue = _CurrentRoom.Name;
if (_CurrentRoom.LogoUrlLightBkgnd == null)
TriList.StringInput[UIStringJoin.CurrentRoomName].StringValue = _currentRoom.Name;
if (_currentRoom.LogoUrlLightBkgnd == null)
{
TriList.BooleanInput[UIBoolJoin.LogoDefaultVisible].BoolValue = true;
TriList.BooleanInput[UIBoolJoin.LogoUrlVisible].BoolValue = false;
@@ -806,28 +830,33 @@ namespace PepperDash.Essentials
{
TriList.BooleanInput[UIBoolJoin.LogoDefaultVisible].BoolValue = false;
TriList.BooleanInput[UIBoolJoin.LogoUrlVisible].BoolValue = true;
TriList.StringInput[UIStringJoin.LogoUrlLightBkgnd].StringValue = _CurrentRoom.LogoUrlLightBkgnd;
TriList.StringInput[UIStringJoin.LogoUrlLightBkgnd].StringValue = _CurrentRoom.LogoUrlDarkBkgnd;
TriList.StringInput[UIStringJoin.LogoUrlLightBkgnd].StringValue = _currentRoom.LogoUrlLightBkgnd;
TriList.StringInput[UIStringJoin.LogoUrlLightBkgnd].StringValue = _currentRoom.LogoUrlDarkBkgnd;
}
// Shutdown timer
_CurrentRoom.ShutdownPromptTimer.HasStarted += ShutdownPromptTimer_HasStarted;
_CurrentRoom.ShutdownPromptTimer.HasFinished += ShutdownPromptTimer_HasFinished;
_CurrentRoom.ShutdownPromptTimer.WasCancelled += ShutdownPromptTimer_WasCancelled;
_currentRoom.ShutdownPromptTimer.HasStarted += ShutdownPromptTimer_HasStarted;
_currentRoom.ShutdownPromptTimer.HasFinished += ShutdownPromptTimer_HasFinished;
_currentRoom.ShutdownPromptTimer.WasCancelled += ShutdownPromptTimer_WasCancelled;
// Link up all the change events from the room
_CurrentRoom.OnFeedback.OutputChange += CurrentRoom_OnFeedback_OutputChange;
_currentRoom.OnFeedback.OutputChange += CurrentRoom_OnFeedback_OutputChange;
CurrentRoom_SyncOnFeedback();
_CurrentRoom.IsWarmingUpFeedback.OutputChange += CurrentRoom_IsWarmingFeedback_OutputChange;
_CurrentRoom.IsCoolingDownFeedback.OutputChange += IsCoolingDownFeedback_OutputChange;
_currentRoom.IsWarmingUpFeedback.OutputChange += CurrentRoom_IsWarmingFeedback_OutputChange;
_currentRoom.IsCoolingDownFeedback.OutputChange += IsCoolingDownFeedback_OutputChange;
_CurrentRoom.CurrentVolumeDeviceChange += CurrentRoom_CurrentAudioDeviceChange;
_currentRoom.CurrentVolumeDeviceChange += CurrentRoom_CurrentAudioDeviceChange;
RefreshAudioDeviceConnections();
_CurrentRoom.CurrentSourceChange += CurrentRoom_SourceInfoChange;
_currentRoom.CurrentSourceChange += CurrentRoom_SourceInfoChange;
RefreshSourceInfo();
(Parent as EssentialsPanelMainInterfaceDriver).HeaderDriver.SetupHeaderButtons(this, CurrentRoom);
var essentialsPanelMainInterfaceDriver = _parent as EssentialsPanelMainInterfaceDriver;
if (essentialsPanelMainInterfaceDriver != null)
{
essentialsPanelMainInterfaceDriver.HeaderDriver.SetupHeaderButtons(this, CurrentRoom);
}
}
else
{
@@ -838,11 +867,11 @@ namespace PepperDash.Essentials
void SetCurrentRoom(EssentialsHuddleSpaceRoom room)
{
if (_CurrentRoom == room) return;
if (_currentRoom == room) return;
// Disconnect current (probably never called)
if (_CurrentRoom != null)
_CurrentRoom.ConfigChanged -= room_ConfigChanged;
if (_currentRoom != null)
_currentRoom.ConfigChanged -= room_ConfigChanged;
room.ConfigChanged -= room_ConfigChanged;
room.ConfigChanged += room_ConfigChanged;
@@ -852,8 +881,8 @@ namespace PepperDash.Essentials
StartPageVisibleJoin = UIBoolJoin.StartMCPageVisible;
UpdateMCJoins(room);
if (_CurrentRoom != null)
_CurrentRoom.MobileControlRoomBridge.UserCodeChanged -= MobileControlRoomBridge_UserCodeChanged;
if (_currentRoom != null)
_currentRoom.MobileControlRoomBridge.UserCodeChanged -= MobileControlRoomBridge_UserCodeChanged;
room.MobileControlRoomBridge.UserCodeChanged -= MobileControlRoomBridge_UserCodeChanged;
room.MobileControlRoomBridge.UserCodeChanged += MobileControlRoomBridge_UserCodeChanged;
@@ -868,7 +897,7 @@ namespace PepperDash.Essentials
void MobileControlRoomBridge_UserCodeChanged(object sender, EventArgs e)
{
UpdateMCJoins(_CurrentRoom);
UpdateMCJoins(_currentRoom);
}
void UpdateMCJoins(EssentialsHuddleSpaceRoom room)
@@ -885,7 +914,7 @@ namespace PepperDash.Essentials
/// <param name="e"></param>
void room_ConfigChanged(object sender, EventArgs e)
{
RefreshCurrentRoom(_CurrentRoom);
RefreshCurrentRoom(_currentRoom);
}
/// <summary>
@@ -898,7 +927,7 @@ namespace PepperDash.Essentials
void CurrentRoom_SyncOnFeedback()
{
var value = _CurrentRoom.OnFeedback.BoolValue;
var value = _currentRoom.OnFeedback.BoolValue;
//Debug.Console(2, CurrentRoom, "UI: Is on event={0}", value);
TriList.BooleanInput[UIBoolJoin.RoomIsOn].BoolValue = value;
@@ -960,15 +989,14 @@ namespace PepperDash.Essentials
// Hide whatever is showing
if (IsVisible)
{
if (CurrentSourcePageManager != null)
if (_currentSourcePageManager != null)
{
CurrentSourcePageManager.Hide();
CurrentSourcePageManager = null;
_currentSourcePageManager.Hide();
_currentSourcePageManager = null;
}
}
if (previousInfo == null) return;
var previousDev = previousInfo.SourceDevice;
var previousDev = previousInfo.SourceDevice;
// device type interfaces
if (previousDev is ISetTopBoxControls)
@@ -999,7 +1027,7 @@ namespace PepperDash.Essentials
{
var routeInfo = CurrentRoom.CurrentSourceInfo;
// This will show off popup too
if (this.IsVisible)
if (IsVisible)
ShowCurrentSource();
if (routeInfo == null)// || !CurrentRoom.OnFeedback.BoolValue)
@@ -1007,22 +1035,23 @@ namespace PepperDash.Essentials
// Check for power off and insert "Room is off"
TriList.StringInput[UIStringJoin.CurrentSourceName].StringValue = "Room is off";
TriList.StringInput[UIStringJoin.CurrentSourceIcon].StringValue = "Power";
this.Hide();
Parent.Show();
Hide();
_parent.Show();
return;
}
else if (CurrentRoom.CurrentSourceInfo != null)
{
TriList.StringInput[UIStringJoin.CurrentSourceName].StringValue = routeInfo.PreferredName;
TriList.StringInput[UIStringJoin.CurrentSourceIcon].StringValue = routeInfo.Icon; // defaults to "blank"
}
else
{
TriList.StringInput[UIStringJoin.CurrentSourceName].StringValue = "---";
TriList.StringInput[UIStringJoin.CurrentSourceIcon].StringValue = "Blank";
}
// Connect controls
if (CurrentRoom.CurrentSourceInfo != null)
{
TriList.StringInput[UIStringJoin.CurrentSourceName].StringValue = routeInfo.PreferredName;
TriList.StringInput[UIStringJoin.CurrentSourceIcon].StringValue = routeInfo.Icon; // defaults to "blank"
}
else
{
TriList.StringInput[UIStringJoin.CurrentSourceName].StringValue = "---";
TriList.StringInput[UIStringJoin.CurrentSourceIcon].StringValue = "Blank";
}
// Connect controls
if (routeInfo.SourceDevice != null)
ConnectControlDeviceMethods(routeInfo.SourceDevice);
}

View File

@@ -13,7 +13,7 @@ using PepperDash.Essentials.Core.Config;
using PepperDash.Essentials.Core.SmartObjects;
using PepperDash.Essentials.Core.Touchpanels.Keyboards;
using PepperDash.Essentials.Devices.Displays;
using PepperDash.Essentials.Room.Config;
using PepperDash.Essentials.Core.Rooms.Config;
namespace PepperDash.Essentials.UIDrivers
{

View File

@@ -8,9 +8,9 @@ using Crestron.SimplSharpPro.UI;
using PepperDash.Core;
using PepperDash.Essentials.Core;
using PepperDash.Essentials.Core.Config;
using PepperDash.Essentials.Core.Devices.Codec;
using PepperDash.Essentials.Core.SmartObjects;
using PepperDash.Essentials.Core.PageManagers;
using PepperDash.Essentials.Room.Config;
using PepperDash.Essentials.Devices.Common.Codec;
using PepperDash.Essentials.Devices.Common.VideoCodec;
@@ -93,15 +93,15 @@ namespace PepperDash.Essentials
/// </summary>
SubpageReferenceList ActivityFooterSrl;
/// <summary>
///
/// </summary>
/// <summary>
///
/// </summary>
public SubpageReferenceList MeetingOrContactMethodModalSrl { get; set; }
/// <summary>
/// The list of buttons on the header. Managed with visibility only
/// </summary>
//SmartObjectHeaderButtonList HeaderButtonsList;
/// <summary>
/// The list of buttons on the header. Managed with visibility only
/// </summary>
//SmartObjectHeaderButtonList HeaderButtonsList;
/// <summary>
/// The AV page mangagers that have been used, to keep them alive for later
@@ -126,7 +126,7 @@ namespace PepperDash.Essentials
/// <summary>
///
/// </summary>
//ModalDialog WarmingCoolingModal;
//ModalDialog WarmingCoolingModal;
/// <summary>
/// Represents
@@ -178,12 +178,12 @@ namespace PepperDash.Essentials
/// </summary>
UiDisplayMode CurrentMode = UiDisplayMode.Start;
CTimer NextMeetingTimer;
CTimer NextMeetingTimer;
/// <summary>
/// Tracks the last meeting that was cancelled
/// </summary>
string LastMeetingDismissedId;
/// <summary>
/// Tracks the last meeting that was cancelled
/// </summary>
string LastMeetingDismissedId;
/// <summary>
/// Constructor
@@ -205,11 +205,11 @@ namespace PepperDash.Essentials
ShareButtonSig = ActivityFooterSrl.BoolInputSig(1, 1);
EndMeetingButtonSig = ActivityFooterSrl.BoolInputSig(3, 1);
MeetingOrContactMethodModalSrl = new SubpageReferenceList(TriList, UISmartObjectJoin.MeetingListSRL, 3, 3, 5);
MeetingOrContactMethodModalSrl = new SubpageReferenceList(TriList, UISmartObjectJoin.MeetingListSRL, 3, 3, 5);
// buttons are added in SetCurrentRoom
//HeaderButtonsList = new SmartObjectHeaderButtonList(TriList.SmartObjects[UISmartObjectJoin.HeaderButtonList]);
// buttons are added in SetCurrentRoom
//HeaderButtonsList = new SmartObjectHeaderButtonList(TriList.SmartObjects[UISmartObjectJoin.HeaderButtonList]);
SetupActivityFooterWhenRoomOff();
@@ -245,17 +245,17 @@ namespace PepperDash.Essentials
{
if (CurrentRoom.IsMobileControlEnabled)
{
Debug.Console(1, "Showing Mobile Control Header Info");
Debug.Console(1, "Showing Mobile Control Header Info");
PopupInterlock.ShowInterlockedWithToggle(UIBoolJoin.RoomHeaderInfoMCPageVisible);
}
else
{
Debug.Console(1, "Showing Non Mobile Control Header Info");
Debug.Console(1, "Showing Non Mobile Control Header Info");
PopupInterlock.ShowInterlockedWithToggle(UIBoolJoin.RoomHeaderInfoPageVisible);
}
});
}
else if (Config.HeaderStyle.ToLower() == CrestronTouchpanelPropertiesConfig.Verbose)
else if (Config.HeaderStyle.ToLower() == CrestronTouchpanelPropertiesConfig.Verbose)
{
TriList.SetSigFalseAction(UIBoolJoin.HeaderRoomButtonPress, () =>
{
@@ -276,7 +276,7 @@ namespace PepperDash.Essentials
TriList.SetBool(UIBoolJoin.DateOnlyVisible, Config.ShowDate && !Config.ShowTime);
TriList.SetBool(UIBoolJoin.TimeOnlyVisible, !Config.ShowDate && Config.ShowTime);
TriList.SetBool(UIBoolJoin.TopBarHabaneroDynamicVisible, true);
TriList.SetBool(UIBoolJoin.TopBarHabaneroDynamicVisible, true);
TriList.SetBool(UIBoolJoin.ActivityFooterVisible, true);
@@ -288,29 +288,29 @@ namespace PepperDash.Essentials
if (CurrentRoom.OnFeedback.BoolValue)
{
TriList.SetBool(UIBoolJoin.TapToBeginVisible, false);
SetupActivityFooterWhenRoomOn();
SetupActivityFooterWhenRoomOn();
}
else
{
TriList.SetBool(StartPageVisibleJoin, true);
TriList.SetBool(UIBoolJoin.TapToBeginVisible, true);
SetupActivityFooterWhenRoomOff();
SetupActivityFooterWhenRoomOff();
}
ShowCurrentDisplayModeSigsInUse();
// *** Header Buttons ***
// Generic "close" button for popup modals
TriList.SetSigFalseAction(UIBoolJoin.InterlockedModalClosePress, PopupInterlock.HideAndClear);
// Volume related things
TriList.SetSigFalseAction(UIBoolJoin.VolumeDefaultPress, () => CurrentRoom.SetDefaultLevels());
TriList.SetString(UIStringJoin.AdvancedVolumeSlider1Text, "Room");
//if (TriList is CrestronApp)
// TriList.BooleanInput[UIBoolJoin.GearButtonVisible].BoolValue = false;
//else
// TriList.BooleanInput[UIBoolJoin.GearButtonVisible].BoolValue = true;
//if (TriList is CrestronApp)
// TriList.BooleanInput[UIBoolJoin.GearButtonVisible].BoolValue = false;
//else
// TriList.BooleanInput[UIBoolJoin.GearButtonVisible].BoolValue = true;
// power-related functions
// Note: some of these are not directly-related to the huddle space UI, but are held over
@@ -323,7 +323,7 @@ namespace PepperDash.Essentials
(CurrentRoom.DefaultDisplay as IHasPowerControl).PowerToggle();
});
SetupNextMeetingTimer();
SetupNextMeetingTimer();
base.Show();
}
@@ -333,12 +333,12 @@ namespace PepperDash.Essentials
/// </summary>
public void ShowActiveCallsList()
{
TriList.SetBool(UIBoolJoin.CallEndAllConfirmVisible, true);
if(PopupInterlock.CurrentJoin == UIBoolJoin.HeaderActiveCallsListVisible)
TriList.SetBool(UIBoolJoin.CallEndAllConfirmVisible, true);
if (PopupInterlock.CurrentJoin == UIBoolJoin.HeaderActiveCallsListVisible)
PopupInterlock.ShowInterlockedWithToggle(UIBoolJoin.HeaderActiveCallsListVisible);
else
{
if((CurrentRoom.ScheduleSource as VideoCodecBase).IsInCall)
if ((CurrentRoom.ScheduleSource as VideoCodecBase).IsInCall)
PopupInterlock.ShowInterlockedWithToggle(UIBoolJoin.HeaderActiveCallsListVisible);
}
}
@@ -377,14 +377,14 @@ namespace PepperDash.Essentials
public override void Hide()
{
HideAndClearCurrentDisplayModeSigsInUse();
TriList.SetBool(UIBoolJoin.TopBarHabaneroDynamicVisible, false);
TriList.SetBool(UIBoolJoin.TopBarHabaneroDynamicVisible, false);
TriList.BooleanInput[UIBoolJoin.ActivityFooterVisible].BoolValue = false;
TriList.BooleanInput[StartPageVisibleJoin].BoolValue = false;
TriList.BooleanInput[UIBoolJoin.TapToBeginVisible].BoolValue = false;
TriList.BooleanInput[UIBoolJoin.SelectASourceVisible].BoolValue = false;
if (NextMeetingTimer != null)
NextMeetingTimer.Stop();
HideNextMeetingPopup();
if (NextMeetingTimer != null)
NextMeetingTimer.Stop();
HideNextMeetingPopup();
base.Hide();
}
@@ -401,7 +401,8 @@ namespace PepperDash.Essentials
{
if (RibbonTimer != null)
RibbonTimer.Stop();
RibbonTimer = new CTimer(o => {
RibbonTimer = new CTimer(o =>
{
TriList.SetBool(UIBoolJoin.NotificationRibbonVisible, false);
RibbonTimer = null;
}, timeout);
@@ -421,145 +422,145 @@ namespace PepperDash.Essentials
}
}
void SetupNextMeetingTimer()
{
var ss = CurrentRoom.ScheduleSource;
if (ss != null)
{
NextMeetingTimer = new CTimer(o => ShowNextMeetingTimerCallback(), null, 0, 60000);
}
}
void SetupNextMeetingTimer()
{
var ss = CurrentRoom.ScheduleSource;
if (ss != null)
{
NextMeetingTimer = new CTimer(o => ShowNextMeetingTimerCallback(), null, 0, 60000);
}
}
/// <summary>
///
/// </summary>
void ShowNextMeetingTimerCallback()
{
// Every 60 seconds, refresh the calendar
RefreshMeetingsList();
// check meetings list for the closest, joinable meeting
var ss = CurrentRoom.ScheduleSource;
var meetings = ss.CodecSchedule.Meetings;
/// <summary>
///
/// </summary>
void ShowNextMeetingTimerCallback()
{
// Every 60 seconds, refresh the calendar
RefreshMeetingsList();
// check meetings list for the closest, joinable meeting
var ss = CurrentRoom.ScheduleSource;
var meetings = ss.CodecSchedule.Meetings;
if (meetings.Count > 0)
{
// If the room is off pester the user
// If the room is on, and the meeting is joinable
// and the LastMeetingDismissed != this meeting
if (meetings.Count > 0)
{
// If the room is off pester the user
// If the room is on, and the meeting is joinable
// and the LastMeetingDismissed != this meeting
var lastMeetingDismissed = meetings.FirstOrDefault(m => m.Id == LastMeetingDismissedId);
Debug.Console(0, "*#* Room on: {0}, lastMeetingDismissedId: {1} {2} *#*",
CurrentRoom.OnFeedback.BoolValue,
LastMeetingDismissedId,
lastMeetingDismissed != null ? lastMeetingDismissed.StartTime.ToShortTimeString() : "");
var lastMeetingDismissed = meetings.FirstOrDefault(m => m.Id == LastMeetingDismissedId);
Debug.Console(0, "*#* Room on: {0}, lastMeetingDismissedId: {1} {2} *#*",
CurrentRoom.OnFeedback.BoolValue,
LastMeetingDismissedId,
lastMeetingDismissed != null ? lastMeetingDismissed.StartTime.ToShortTimeString() : "");
var meeting = meetings.LastOrDefault(m => m.Joinable);
if (CurrentRoom.OnFeedback.BoolValue
&& lastMeetingDismissed == meeting)
{
return;
}
var meeting = meetings.LastOrDefault(m => m.Joinable);
if (CurrentRoom.OnFeedback.BoolValue
&& lastMeetingDismissed == meeting)
{
return;
}
LastMeetingDismissedId = null;
// Clear the popup when we run out of meetings
if (meeting == null)
{
HideNextMeetingPopup();
}
else
{
TriList.SetString(UIStringJoin.MeetingsOrContactMethodListTitleText, "Upcoming meeting");
TriList.SetString(UIStringJoin.NextMeetingStartTimeText, meeting.StartTime.ToShortTimeString());
TriList.SetString(UIStringJoin.NextMeetingEndTimeText, meeting.EndTime.ToShortTimeString());
TriList.SetString(UIStringJoin.NextMeetingTitleText, meeting.Title);
TriList.SetString(UIStringJoin.NextMeetingNameText, meeting.Organizer);
TriList.SetString(UIStringJoin.NextMeetingButtonLabel, "Join");
TriList.SetSigFalseAction(UIBoolJoin.NextMeetingJoinPress, () =>
{
HideNextMeetingPopup();
PopupInterlock.Hide();
RoomOnAndDialMeeting(meeting);
});
TriList.SetString(UIStringJoin.NextMeetingSecondaryButtonLabel, "Show Schedule");
TriList.SetSigFalseAction(UIBoolJoin.CalendarHeaderButtonPress, () =>
{
HideNextMeetingPopup();
//CalendarPress();
RefreshMeetingsList();
PopupInterlock.ShowInterlocked(UIBoolJoin.MeetingsOrContacMethodsListVisible);
});
var indexOfNext = meetings.IndexOf(meeting) + 1;
// indexOf = 3, 4 meetings :
if (indexOfNext < meetings.Count)
TriList.SetString(UIStringJoin.NextMeetingFollowingMeetingText,
meetings[indexOfNext].StartTime.ToShortTimeString());
else
TriList.SetString(UIStringJoin.NextMeetingFollowingMeetingText, "No more meetings today");
TriList.SetSigFalseAction(UIBoolJoin.NextMeetingModalClosePress, () =>
{
// Mark the meeting to not re-harass the user
if(CurrentRoom.OnFeedback.BoolValue)
LastMeetingDismissedId = meeting.Id;
HideNextMeetingPopup();
});
TriList.SetBool(UIBoolJoin.NextMeetingModalVisible, true);
}
}
}
/// <summary>
///
/// </summary>
void HideNextMeetingPopup()
{
TriList.SetBool(UIBoolJoin.NextMeetingModalVisible, false);
}
/// <summary>
/// Calendar should only be visible when it's supposed to
/// </summary>
public void CalendarPress()
{
//RefreshMeetingsList(); // List should be up-to-date
PopupInterlock.ShowInterlockedWithToggle(UIBoolJoin.MeetingsOrContacMethodsListVisible);
}
/// <summary>
/// Dials a meeting after turning on room (if necessary)
/// </summary>
void RoomOnAndDialMeeting(Meeting meeting)
{
Action dialAction = () =>
{
var d = CurrentRoom.ScheduleSource as VideoCodecBase;
if (d != null)
LastMeetingDismissedId = null;
// Clear the popup when we run out of meetings
if (meeting == null)
{
HideNextMeetingPopup();
}
else
{
TriList.SetString(UIStringJoin.MeetingsOrContactMethodListTitleText, "Upcoming meeting");
TriList.SetString(UIStringJoin.NextMeetingStartTimeText, meeting.StartTime.ToShortTimeString());
TriList.SetString(UIStringJoin.NextMeetingEndTimeText, meeting.EndTime.ToShortTimeString());
TriList.SetString(UIStringJoin.NextMeetingTitleText, meeting.Title);
TriList.SetString(UIStringJoin.NextMeetingNameText, meeting.Organizer);
TriList.SetString(UIStringJoin.NextMeetingButtonLabel, "Join");
TriList.SetSigFalseAction(UIBoolJoin.NextMeetingJoinPress, () =>
{
d.Dial(meeting);
LastMeetingDismissedId = meeting.Id; // To prevent prompts for already-joined call
HideNextMeetingPopup();
PopupInterlock.Hide();
RoomOnAndDialMeeting(meeting);
});
TriList.SetString(UIStringJoin.NextMeetingSecondaryButtonLabel, "Show Schedule");
TriList.SetSigFalseAction(UIBoolJoin.CalendarHeaderButtonPress, () =>
{
HideNextMeetingPopup();
//CalendarPress();
RefreshMeetingsList();
PopupInterlock.ShowInterlocked(UIBoolJoin.MeetingsOrContacMethodsListVisible);
});
var indexOfNext = meetings.IndexOf(meeting) + 1;
// indexOf = 3, 4 meetings :
if (indexOfNext < meetings.Count)
TriList.SetString(UIStringJoin.NextMeetingFollowingMeetingText,
meetings[indexOfNext].StartTime.ToShortTimeString());
else
TriList.SetString(UIStringJoin.NextMeetingFollowingMeetingText, "No more meetings today");
TriList.SetSigFalseAction(UIBoolJoin.NextMeetingModalClosePress, () =>
{
// Mark the meeting to not re-harass the user
if (CurrentRoom.OnFeedback.BoolValue)
LastMeetingDismissedId = meeting.Id;
HideNextMeetingPopup();
});
TriList.SetBool(UIBoolJoin.NextMeetingModalVisible, true);
}
}
}
/// <summary>
///
/// </summary>
void HideNextMeetingPopup()
{
TriList.SetBool(UIBoolJoin.NextMeetingModalVisible, false);
}
/// <summary>
/// Calendar should only be visible when it's supposed to
/// </summary>
public void CalendarPress()
{
//RefreshMeetingsList(); // List should be up-to-date
PopupInterlock.ShowInterlockedWithToggle(UIBoolJoin.MeetingsOrContacMethodsListVisible);
}
/// <summary>
/// Dials a meeting after turning on room (if necessary)
/// </summary>
void RoomOnAndDialMeeting(Meeting meeting)
{
Action dialAction = () =>
{
var d = CurrentRoom.ScheduleSource as VideoCodecBase;
if (d != null)
{
d.Dial(meeting);
LastMeetingDismissedId = meeting.Id; // To prevent prompts for already-joined call
}
};
if (CurrentRoom.OnFeedback.BoolValue)
dialAction();
else
{
// Rig a one-time handler to catch when the room is warmed and then dial call
EventHandler<FeedbackEventArgs> oneTimeHandler = null;
oneTimeHandler = (o, a) =>
{
if (!CurrentRoom.IsWarmingUpFeedback.BoolValue)
{
CurrentRoom.IsWarmingUpFeedback.OutputChange -= oneTimeHandler;
dialAction();
}
};
if (CurrentRoom.OnFeedback.BoolValue)
dialAction();
else
{
// Rig a one-time handler to catch when the room is warmed and then dial call
EventHandler<FeedbackEventArgs> oneTimeHandler = null;
oneTimeHandler = (o, a) =>
{
if (!CurrentRoom.IsWarmingUpFeedback.BoolValue)
{
CurrentRoom.IsWarmingUpFeedback.OutputChange -= oneTimeHandler;
dialAction();
}
};
CurrentRoom.IsWarmingUpFeedback.OutputChange += oneTimeHandler;
ActivityCallButtonPressed();
}
}
};
CurrentRoom.IsWarmingUpFeedback.OutputChange += oneTimeHandler;
ActivityCallButtonPressed();
}
}
/// <summary>
/// Reveals the tech page and puts away anything that's in the way.
@@ -591,11 +592,11 @@ namespace PepperDash.Essentials
void SetupActivityFooterWhenRoomOn()
{
ActivityFooterSrl.Clear();
ActivityFooterSrl.AddItem(new SubpageReferenceListActivityItem(1, ActivityFooterSrl, 0,
ActivityFooterSrl.AddItem(new SubpageReferenceListActivityItem(1, ActivityFooterSrl, 0,
b => { if (!b) ActivityShareButtonPressed(); }));
ActivityFooterSrl.AddItem(new SubpageReferenceListActivityItem(2, ActivityFooterSrl, 3,
b => { if (!b) ActivityCallButtonPressed(); }));
ActivityFooterSrl.AddItem(new SubpageReferenceListActivityItem(3, ActivityFooterSrl, 4,
ActivityFooterSrl.AddItem(new SubpageReferenceListActivityItem(3, ActivityFooterSrl, 4,
b => { if (!b) EndMeetingPress(); }));
ActivityFooterSrl.Count = 3;
TriList.SetUshort(UIUshortJoin.PresentationStagingCaretMode, 2); // center
@@ -607,9 +608,9 @@ namespace PepperDash.Essentials
/// </summary>
void SetActivityFooterFeedbacks()
{
CallButtonSig.BoolValue = CurrentMode == UiDisplayMode.Call
CallButtonSig.BoolValue = CurrentMode == UiDisplayMode.Call
&& CurrentRoom.ShutdownType == eShutdownType.None;
ShareButtonSig.BoolValue = CurrentMode == UiDisplayMode.Presentation
ShareButtonSig.BoolValue = CurrentMode == UiDisplayMode.Presentation
&& CurrentRoom.ShutdownType == eShutdownType.None;
EndMeetingButtonSig.BoolValue = CurrentRoom.ShutdownType != eShutdownType.None;
}
@@ -622,13 +623,13 @@ namespace PepperDash.Essentials
if (VCDriver.IsVisible)
return;
HideLogo();
HideNextMeetingPopup();
HideNextMeetingPopup();
TriList.SetBool(StartPageVisibleJoin, false);
TriList.SetBool(UIBoolJoin.SourceStagingBarVisible, false);
TriList.SetBool(UIBoolJoin.SelectASourceVisible, false);
if (CurrentSourcePageManager != null)
CurrentSourcePageManager.Hide();
PowerOnFromCall();
PowerOnFromCall();
CurrentMode = UiDisplayMode.Call;
SetActivityFooterFeedbacks();
VCDriver.Show();
@@ -639,45 +640,45 @@ namespace PepperDash.Essentials
/// </summary>
void ActivityShareButtonPressed()
{
SetupSourceList();
SetupSourceList();
if (VCDriver.IsVisible)
VCDriver.Hide();
HideNextMeetingPopup();
HideNextMeetingPopup();
TriList.SetBool(StartPageVisibleJoin, false);
TriList.SetBool(UIBoolJoin.CallStagingBarVisible, false);
TriList.SetBool(UIBoolJoin.SourceStagingBarVisible, true);
// Run default source when room is off and share is pressed
if (!CurrentRoom.OnFeedback.BoolValue)
{
if (!CurrentRoom.OnFeedback.BoolValue)
{
// If there's no default, show UI elements
if (!CurrentRoom.RunDefaultPresentRoute())
TriList.SetBool(UIBoolJoin.SelectASourceVisible, true);
}
{
if (!CurrentRoom.OnFeedback.BoolValue)
{
// If there's no default, show UI elements
if (!CurrentRoom.RunDefaultPresentRoute())
TriList.SetBool(UIBoolJoin.SelectASourceVisible, true);
}
}
else // room is on show what's active or select a source if nothing is yet active
{
if(CurrentRoom.CurrentSourceInfo == null || CurrentRoom.CurrentSourceInfoKey == CurrentRoom.DefaultCodecRouteString)
if (CurrentRoom.CurrentSourceInfo == null || CurrentRoom.CurrentSourceInfoKey == EssentialsHuddleVtc1Room.DefaultCodecRouteString)
TriList.SetBool(UIBoolJoin.SelectASourceVisible, true);
else if (CurrentSourcePageManager != null)
CurrentSourcePageManager.Show();
}
CurrentMode = UiDisplayMode.Presentation;
SetupSourceList();
SetupSourceList();
SetActivityFooterFeedbacks();
}
/// <summary>
/// Powers up the system to the codec route, if not already on.
/// </summary>
void PowerOnFromCall()
{
if (!CurrentRoom.OnFeedback.BoolValue)
{
CurrentRoom.RunDefaultCallRoute();
}
}
/// <summary>
/// Powers up the system to the codec route, if not already on.
/// </summary>
void PowerOnFromCall()
{
if (!CurrentRoom.OnFeedback.BoolValue)
{
CurrentRoom.RunDefaultCallRoute();
}
}
/// <summary>
/// Shows all sigs that are in CurrentDisplayModeSigsInUse
@@ -704,22 +705,22 @@ namespace PepperDash.Essentials
/// </summary>
void ShowCurrentSource()
{
if (CurrentRoom.CurrentSourceInfo == null)
return;
if (CurrentRoom.CurrentSourceInfo == null)
return;
if (CurrentRoom.CurrentSourceInfo.SourceDevice == null)
{
TriList.SetBool(UIBoolJoin.SelectASourceVisible, true);
return;
}
if (CurrentRoom.CurrentSourceInfo.SourceDevice == null)
{
TriList.SetBool(UIBoolJoin.SelectASourceVisible, true);
return;
}
var uiDev = CurrentRoom.CurrentSourceInfo.SourceDevice as IUiDisplayInfo;
PageManager pm = null;
// If we need a page manager, get an appropriate one
if (uiDev != null)
{
TriList.SetBool(UIBoolJoin.SelectASourceVisible, false);
// Got an existing page manager, get it
TriList.SetBool(UIBoolJoin.SelectASourceVisible, false);
// Got an existing page manager, get it
if (PageManagers.ContainsKey(uiDev))
pm = PageManagers[uiDev];
// Otherwise make an apporiate one
@@ -758,15 +759,15 @@ namespace PepperDash.Essentials
CurrentRoom.StartShutdown(eShutdownType.Manual);
}
/// <summary>
/// Puts away modals and things that might be up when call comes in
/// </summary>
public void PrepareForCodecIncomingCall()
{
if (PowerDownModal != null && PowerDownModal.ModalIsVisible)
PowerDownModal.CancelDialog();
PopupInterlock.Hide();
}
/// <summary>
/// Puts away modals and things that might be up when call comes in
/// </summary>
public void PrepareForCodecIncomingCall()
{
if (PowerDownModal != null && PowerDownModal.ModalIsVisible)
PowerDownModal.CancelDialog();
PopupInterlock.Hide();
}
/// <summary>
///
@@ -911,7 +912,7 @@ namespace PepperDash.Essentials
_CurrentRoom.OnFeedback.OutputChange -= CurrentRoom_OnFeedback_OutputChange;
_CurrentRoom.IsWarmingUpFeedback.OutputChange -= CurrentRoom_IsWarmingFeedback_OutputChange;
_CurrentRoom.IsCoolingDownFeedback.OutputChange -= CurrentRoom_IsCoolingDownFeedback_OutputChange;
_CurrentRoom.InCallFeedback.OutputChange -= CurrentRoom_InCallFeedback_OutputChange;
_CurrentRoom.InCallFeedback.OutputChange -= CurrentRoom_InCallFeedback_OutputChange;
}
_CurrentRoom = room;
@@ -920,7 +921,7 @@ namespace PepperDash.Essentials
{
// get the source list config and set up the source list
SetupSourceList();
SetupSourceList();
// Name and logo
TriList.StringInput[UIStringJoin.CurrentRoomName].StringValue = _CurrentRoom.Name;
@@ -931,12 +932,12 @@ namespace PepperDash.Essentials
_CurrentRoom.ShutdownPromptTimer.HasFinished += ShutdownPromptTimer_HasFinished;
_CurrentRoom.ShutdownPromptTimer.WasCancelled += ShutdownPromptTimer_WasCancelled;
// Link up all the change events from the room
// Link up all the change events from the room
_CurrentRoom.OnFeedback.OutputChange += CurrentRoom_OnFeedback_OutputChange;
CurrentRoom_SyncOnFeedback();
_CurrentRoom.IsWarmingUpFeedback.OutputChange += CurrentRoom_IsWarmingFeedback_OutputChange;
_CurrentRoom.IsCoolingDownFeedback.OutputChange += CurrentRoom_IsCoolingDownFeedback_OutputChange;
_CurrentRoom.InCallFeedback.OutputChange += CurrentRoom_InCallFeedback_OutputChange;
_CurrentRoom.InCallFeedback.OutputChange += CurrentRoom_InCallFeedback_OutputChange;
_CurrentRoom.CurrentVolumeDeviceChange += CurrentRoom_CurrentAudioDeviceChange;
@@ -974,7 +975,7 @@ namespace PepperDash.Essentials
if (_CurrentRoom == room) return;
// Disconnect current (probably never called)
if(_CurrentRoom != null)
if (_CurrentRoom != null)
_CurrentRoom.ConfigChanged -= room_ConfigChanged;
room.ConfigChanged -= room_ConfigChanged;
@@ -1021,81 +1022,81 @@ namespace PepperDash.Essentials
RefreshCurrentRoom(_CurrentRoom);
}
/// <summary>
///
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
void CurrentRoom_InCallFeedback_OutputChange(object sender, EventArgs e)
{
var inCall = CurrentRoom.InCallFeedback.BoolValue;
if (inCall)
{
// Check if transitioning to in call - and non-sharable source is in use
if (CurrentRoom.CurrentSourceInfo != null && CurrentRoom.CurrentSourceInfo.DisableCodecSharing)
{
Debug.Console(1, CurrentRoom, "Transitioning to in-call, cancelling non-sharable source");
CurrentRoom.RunRouteAction("codecOsd", CurrentRoom.SourceListKey);
}
}
/// <summary>
///
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
void CurrentRoom_InCallFeedback_OutputChange(object sender, EventArgs e)
{
var inCall = CurrentRoom.InCallFeedback.BoolValue;
if (inCall)
{
// Check if transitioning to in call - and non-sharable source is in use
if (CurrentRoom.CurrentSourceInfo != null && CurrentRoom.CurrentSourceInfo.DisableCodecSharing)
{
Debug.Console(1, CurrentRoom, "Transitioning to in-call, cancelling non-sharable source");
CurrentRoom.RunRouteAction("codecOsd", CurrentRoom.SourceListKey);
}
}
SetupSourceList();
}
SetupSourceList();
}
/// <summary>
///
/// </summary>
void SetupSourceList()
{
var inCall = CurrentRoom.InCallFeedback.BoolValue;
var config = ConfigReader.ConfigObject.SourceLists;
if (config.ContainsKey(_CurrentRoom.SourceListKey))
{
var srcList = config[_CurrentRoom.SourceListKey].OrderBy(kv => kv.Value.Order);
/// <summary>
///
/// </summary>
void SetupSourceList()
{
// Setup sources list
SourceStagingSrl.Clear();
uint i = 1; // counter for UI list
foreach (var kvp in srcList)
{
var srcConfig = kvp.Value;
Debug.Console(1, "**** {0}, {1}, {2}, {3}, {4}", srcConfig.PreferredName, srcConfig.IncludeInSourceList,
srcConfig.DisableCodecSharing, inCall, this.CurrentMode);
// Skip sources marked as not included, and filter list of non-sharable sources when in call
// or on share screen
if (!srcConfig.IncludeInSourceList || (inCall && srcConfig.DisableCodecSharing)
|| this.CurrentMode == UiDisplayMode.Call && srcConfig.DisableCodecSharing)
{
Debug.Console(1, "Skipping {0}", srcConfig.PreferredName);
continue;
}
var inCall = CurrentRoom.InCallFeedback.BoolValue;
var config = ConfigReader.ConfigObject.SourceLists;
var routeKey = kvp.Key;
var item = new SubpageReferenceListSourceItem(i++, SourceStagingSrl, srcConfig,
b => { if (!b) UiSelectSource(routeKey); });
SourceStagingSrl.AddItem(item); // add to the SRL
item.RegisterForSourceChange(_CurrentRoom);
Debug.Console(1, "**** KEY {0}", kvp.Key);
}
SourceStagingSrl.Count = (ushort)(i - 1);
}
}
if (config.ContainsKey(_CurrentRoom.SourceListKey))
{
var srcList = config[_CurrentRoom.SourceListKey].OrderBy(kv => kv.Value.Order);
/// <summary>
/// If the schedule changes, this event will fire
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
void CodecSchedule_MeetingsListHasChanged(object sender, EventArgs e)
{
RefreshMeetingsList();
}
// Setup sources list
SourceStagingSrl.Clear();
uint i = 1; // counter for UI list
foreach (var kvp in srcList)
{
var srcConfig = kvp.Value;
Debug.Console(1, "**** {0}, {1}, {2}, {3}, {4}", srcConfig.PreferredName, srcConfig.IncludeInSourceList,
srcConfig.DisableCodecSharing, inCall, this.CurrentMode);
// Skip sources marked as not included, and filter list of non-sharable sources when in call
// or on share screen
if (!srcConfig.IncludeInSourceList || (inCall && srcConfig.DisableCodecSharing)
|| this.CurrentMode == UiDisplayMode.Call && srcConfig.DisableCodecSharing)
{
Debug.Console(1, "Skipping {0}", srcConfig.PreferredName);
continue;
}
var routeKey = kvp.Key;
var item = new SubpageReferenceListSourceItem(i++, SourceStagingSrl, srcConfig,
b => { if (!b) UiSelectSource(routeKey); });
SourceStagingSrl.AddItem(item); // add to the SRL
item.RegisterForSourceChange(_CurrentRoom);
Debug.Console(1, "**** KEY {0}", kvp.Key);
}
SourceStagingSrl.Count = (ushort)(i - 1);
}
}
/// <summary>
/// If the schedule changes, this event will fire
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
void CodecSchedule_MeetingsListHasChanged(object sender, EventArgs e)
{
RefreshMeetingsList();
}
/// <summary>
/// Updates the current shared source label on the call list when the source changes
@@ -1128,51 +1129,51 @@ namespace PepperDash.Essentials
string callListSharedSourceLabel;
if (_CurrentRoom.VideoCodec.SharingContentIsOnFeedback.BoolValue && _CurrentRoom.CurrentSourceInfo != null)
{
Debug.Console(0, "*#* CurrentRoom.CurrentSourceInfo = {0}",
_CurrentRoom.CurrentSourceInfo != null ? _CurrentRoom.CurrentSourceInfo.SourceKey : "Nada!");
callListSharedSourceLabel = _CurrentRoom.CurrentSourceInfo.PreferredName;
}
else
callListSharedSourceLabel = "None";
if (_CurrentRoom.VideoCodec.SharingContentIsOnFeedback.BoolValue && _CurrentRoom.CurrentSourceInfo != null)
{
Debug.Console(0, "*#* CurrentRoom.CurrentSourceInfo = {0}",
_CurrentRoom.CurrentSourceInfo != null ? _CurrentRoom.CurrentSourceInfo.SourceKey : "Nada!");
callListSharedSourceLabel = _CurrentRoom.CurrentSourceInfo.PreferredName;
}
else
callListSharedSourceLabel = "None";
TriList.StringInput[UIStringJoin.CallSharedSourceNameText].StringValue = callListSharedSourceLabel;
}
/// <summary>
///
/// </summary>
void RefreshMeetingsList()
{
/// <summary>
///
/// </summary>
void RefreshMeetingsList()
{
// See if this is helpful or if the callback response in the codec class maybe doesn't come it time?
// Let's build list from event
// CurrentRoom.ScheduleSource.GetSchedule();
// CurrentRoom.ScheduleSource.GetSchedule();
TriList.SetString(UIStringJoin.MeetingsOrContactMethodListIcon, "Calendar");
TriList.SetString(UIStringJoin.MeetingsOrContactMethodListTitleText, "Today's Meetings");
ushort i = 0;
foreach (var m in CurrentRoom.ScheduleSource.CodecSchedule.Meetings)
{
i++;
MeetingOrContactMethodModalSrl.StringInputSig(i, 1).StringValue = m.StartTime.ToShortTimeString();
MeetingOrContactMethodModalSrl.StringInputSig(i, 2).StringValue = m.EndTime.ToShortTimeString();
MeetingOrContactMethodModalSrl.StringInputSig(i, 3).StringValue = m.Title;
MeetingOrContactMethodModalSrl.StringInputSig(i, 4).StringValue = string.Format("<br>{0}",m.Organizer);
ushort i = 0;
foreach (var m in CurrentRoom.ScheduleSource.CodecSchedule.Meetings)
{
i++;
MeetingOrContactMethodModalSrl.StringInputSig(i, 1).StringValue = m.StartTime.ToShortTimeString();
MeetingOrContactMethodModalSrl.StringInputSig(i, 2).StringValue = m.EndTime.ToShortTimeString();
MeetingOrContactMethodModalSrl.StringInputSig(i, 3).StringValue = m.Title;
MeetingOrContactMethodModalSrl.StringInputSig(i, 4).StringValue = string.Format("<br>{0}", m.Organizer);
MeetingOrContactMethodModalSrl.StringInputSig(i, 5).StringValue = "Join";
MeetingOrContactMethodModalSrl.BoolInputSig(i, 2).BoolValue = m.Joinable;
var mm = m; // lambda scope
MeetingOrContactMethodModalSrl.GetBoolFeedbackSig(i, 1).SetSigFalseAction(() =>
{
PopupInterlock.Hide();
ActivityCallButtonPressed();
var d = CurrentRoom.ScheduleSource as VideoCodecBase;
if (d != null)
RoomOnAndDialMeeting(mm);
});
}
MeetingOrContactMethodModalSrl.Count = i;
MeetingOrContactMethodModalSrl.BoolInputSig(i, 2).BoolValue = m.Joinable;
var mm = m; // lambda scope
MeetingOrContactMethodModalSrl.GetBoolFeedbackSig(i, 1).SetSigFalseAction(() =>
{
PopupInterlock.Hide();
ActivityCallButtonPressed();
var d = CurrentRoom.ScheduleSource as VideoCodecBase;
if (d != null)
RoomOnAndDialMeeting(mm);
});
}
MeetingOrContactMethodModalSrl.Count = i;
if (i == 0) // Show item indicating no meetings are booked for rest of day
{
@@ -1184,12 +1185,12 @@ namespace PepperDash.Essentials
MeetingOrContactMethodModalSrl.StringInputSig(1, 4).StringValue = string.Empty;
MeetingOrContactMethodModalSrl.StringInputSig(1, 5).StringValue = string.Empty;
}
}
}
/// <summary>
/// For room on/off changes
/// </summary>
void CurrentRoom_OnFeedback_OutputChange(object sender, EventArgs e)
/// <summary>
/// For room on/off changes
/// </summary>
void CurrentRoom_OnFeedback_OutputChange(object sender, EventArgs e)
{
CurrentRoom_SyncOnFeedback();
}
@@ -1221,8 +1222,8 @@ namespace PepperDash.Essentials
SetActivityFooterFeedbacks();
TriList.BooleanInput[UIBoolJoin.VolumeDualMute1Visible].BoolValue = false;
TriList.BooleanInput[UIBoolJoin.SourceStagingBarVisible].BoolValue = false;
// Clear this so that the pesky meeting warning can resurface every minute when off
LastMeetingDismissedId = null;
// Clear this so that the pesky meeting warning can resurface every minute when off
LastMeetingDismissedId = null;
}
}
@@ -1233,11 +1234,11 @@ namespace PepperDash.Essentials
{
if (CurrentRoom.IsWarmingUpFeedback.BoolValue)
{
ShowNotificationRibbon("Room is powering on. Please wait...", 0);
ShowNotificationRibbon("Room is powering on. Please wait...", 0);
}
else
{
ShowNotificationRibbon("Room is powered on. Welcome.", 2000);
ShowNotificationRibbon("Room is powered on. Welcome.", 2000);
}
}
@@ -1250,11 +1251,11 @@ namespace PepperDash.Essentials
{
if (CurrentRoom.IsCoolingDownFeedback.BoolValue)
{
ShowNotificationRibbon("Room is powering off. Please wait.", 0);
ShowNotificationRibbon("Room is powering off. Please wait.", 0);
}
else
{
HideNotificationRibbon();
HideNotificationRibbon();
}
}

View File

@@ -10,11 +10,14 @@ using Crestron.SimplSharpPro.DeviceSupport;
using PepperDash.Core;
using PepperDash.Essentials;
using PepperDash.Essentials.Core;
using PepperDash.Essentials.Core.Devices.VideoCodec;
using PepperDash.Essentials.Core.SmartObjects;
using PepperDash.Essentials.Core.Touchpanels.Keyboards;
using PepperDash.Essentials.Core.Devices.Codec;
using PepperDash.Essentials.Devices.Common.Cameras;
using PepperDash.Essentials.Devices.Common.Codec;
using PepperDash.Essentials.Devices.Common.VideoCodec;
using PepperDash.Essentials.Devices.Common.Cameras;
using PepperDash.Essentials.Devices.Core.VideoCodec;
namespace PepperDash.Essentials.UIDrivers.VC
{

View File

@@ -1,7 +1,7 @@
using System;
using PepperDash.Essentials.Core;
namespace PepperDash_Essentials_Core.Bridges.JoinMaps
namespace PepperDash.Essentials.Core.Bridges.JoinMaps
{
public class GlsPartitionSensorJoinMap : JoinMapBaseAdvanced
{

View File

@@ -1,7 +1,7 @@
using System;
using PepperDash.Essentials.Core;
namespace PepperDash_Essentials_Core.Bridges.JoinMaps
namespace PepperDash.Essentials.Core.Bridges.JoinMaps
{
public class VideoCodecControllerJoinMap : JoinMapBaseAdvanced
{

View File

@@ -6,6 +6,7 @@ using Crestron.SimplSharp;
using Newtonsoft.Json;
using PepperDash.Core;
using PepperDash.Essentials.Core;
using PepperDash.Essentials.Core.Devices;
namespace PepperDash.Essentials.Core.Config
{
@@ -23,7 +24,10 @@ namespace PepperDash.Essentials.Core.Config
[JsonProperty("sourceLists")]
public Dictionary<string, Dictionary<string, SourceListItem>> SourceLists { get; set; }
[JsonProperty("tieLines")]
[JsonProperty("destinationLists")]
public Dictionary<string, Dictionary<string, DestinationListItem>> DestinationLists { get; set; }
[JsonProperty("tieLines")]
public List<TieLineConfig> TieLines { get; set; }
[JsonProperty("joinMaps")]
@@ -40,6 +44,14 @@ namespace PepperDash.Essentials.Core.Config
return SourceLists[key];
}
public Dictionary<string, DestinationListItem> GetDestinationListForKey(string key)
{
if (string.IsNullOrEmpty(key) || !SourceLists.ContainsKey(key))
return null;
return DestinationLists[key];
}
/// <summary>
/// Checks Devices for an item with a Key that matches and returns it if found. Otherwise, retunes null
/// </summary>
@@ -52,12 +64,9 @@ namespace PepperDash.Essentials.Core.Config
var deviceConfig = Devices.FirstOrDefault(d => d.Key.Equals(key));
if (deviceConfig != null)
return deviceConfig;
else
{
return null;
}
//removed if statement that was here...
//DeviceConfig will be null if it's not found in the list
return deviceConfig;
}
}
}

View File

@@ -0,0 +1,62 @@
using System;
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,18 @@
using System;
namespace PepperDash.Essentials.Devices.Common.Codec
{
public interface IHasExternalSourceSwitching
{
bool ExternalSourceListEnabled { get; }
string ExternalSourceInputPort { get; }
void AddExternalSource(string connectorId, string key, string name, eExternalSourceType type);
void SetExternalSourceState(string key, eExternalSourceMode mode);
void ClearExternalSources();
void SetSelectedSource(string key);
Action<string, string> RunRouteAction { set;}
}
public enum eExternalSourceType { camera, desktop, document_camera, mediaplayer, PC, whiteboard, other }
public enum eExternalSourceMode { Ready, NotReady, Hidden, Error }
}

View File

@@ -0,0 +1,59 @@
using System;
using System.Collections.Generic;
namespace PepperDash.Essentials.Devices.Common.VideoCodec.Interfaces
{
public interface IHasParticipants
{
CodecParticipants Participants { get; }
}
public interface IHasParticipantVideoMute:IHasParticipants
{
void MuteVideoForParticipant(int userId);
void UnmuteVideoForParticipant(int userId);
void ToggleVideoForParticipant(int userId);
}
public interface IHasParticipantAudioMute:IHasParticipantVideoMute
{
void MuteAudioForParticipant(int userId);
void UnmuteAudioForParticipant(int userId);
void ToggleAudioForParticipant(int userId);
}
public class CodecParticipants
{
private List<Participant> _currentParticipants;
public List<Participant> CurrentParticipants {
get { return _currentParticipants; }
set
{
_currentParticipants = value;
var handler = ParticipantsListHasChanged;
if(handler == null) return;
handler(this, new EventArgs());
}
}
public event EventHandler<EventArgs> ParticipantsListHasChanged;
public CodecParticipants()
{
_currentParticipants = new List<Participant>();
}
}
public class Participant
{
public bool IsHost { get; set; }
public string Name { get; set; }
public bool CanMuteVideo { get; set; }
public bool CanUnmuteVideo { get; set; }
public bool VideoMuteFb { get; set; }
public bool AudioMuteFb { get; set; }
}
}

View File

@@ -0,0 +1,14 @@
using PepperDash.Essentials.Core;
using PepperDash.Essentials.Core.Devices;
namespace PepperDash.Essentials.Core.DeviceTypeInterfaces
{
public interface IHasSelfviewPosition
{
StringFeedback SelfviewPipPositionFeedback { get; }
void SelfviewPipPositionSet(CodecCommandWithLabel position);
void SelfviewPipPositionToggle();
}
}

View File

@@ -0,0 +1,35 @@
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,83 @@
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,48 @@
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,36 @@
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,95 @@
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};
}
public void UpdateRecentCallsList(List<CallHistoryEntry> entries)
{
RecentCalls = entries;
OnRecentCallsListChange();
}
private void OnRecentCallsListChange()
{
var handler = RecentCallsListHasChanged;
if (handler != null)
{
handler(this, new EventArgs());
}
}
public void RemoveEntry(CallHistoryEntry entry)
{
RecentCalls.Remove(entry);
OnRecentCallsListChange();
}
public void UpdateCallHistory(List<CallHistoryEntry> newList)
{
RecentCalls = newList;
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,240 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Crestron.SimplSharp;
using Newtonsoft.Json;
using Newtonsoft.Json.Converters;
using PepperDash.Core;
using PepperDash.Essentials.Core;
using PepperDash.Essentials.Core.Devices.VideoCodec;
using PepperDash.Essentials.Devices.Common.VideoCodec;
namespace PepperDash.Essentials.Devices.Common.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>
[Obsolete("Please use the Stack-based history instead")]
List<CodecDirectory> DirectoryBrowseHistory { get; }
}
public interface IHasDirectoryHistoryStack : IHasDirectory
{
Stack<CodecDirectory> DirectoryBrowseHistoryStack { 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; }
[JsonProperty("parentFolderId")]
public string ParentFolderId { get; set; }
}
/// <summary>
/// Represents a folder type DirectoryItem
/// </summary>
public class DirectoryFolder : DirectoryItem
{
[JsonProperty("contacts")]
public List<DirectoryContact> Contacts { 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,185 @@
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;
private int _meetingWarningMinutes = 5;
public int MeetingWarningMinutes
{
get { return _meetingWarningMinutes; }
set { _meetingWarningMinutes = value; }
}
/// <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);
}
public CodecScheduleAwareness(long pollTime)
{
Meetings = new List<Meeting>();
_scheduleChecker = new CTimer(CheckSchedule, null, pollTime, pollTime);
}
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 (var m in Meetings)
{
var 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 int MinutesBeforeMeeting;
public string Id { get; set; }
public string Organizer { get; set; }
public string Title { get; set; }
public string Agenda { get; set; }
public TimeSpan MeetingWarningMinutes
{
get { return TimeSpan.FromMinutes(MinutesBeforeMeeting); }
}
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(-MinutesBeforeMeeting) <= 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,16 @@
namespace PepperDash.Essentials.Core.Devices.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

@@ -1,4 +1,4 @@
namespace PepperDash_Essentials_Core.DeviceTypeInterfaces
namespace PepperDash.Essentials.Core.DeviceTypeInterfaces
{
public interface IHasBranding
{

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

@@ -1,6 +1,6 @@
using PepperDash.Essentials.Core;
namespace PepperDash_Essentials_Core.DeviceTypeInterfaces
namespace PepperDash.Essentials.Core.DeviceTypeInterfaces
{
public interface IHasPhoneDialing
{

View File

@@ -0,0 +1,34 @@
using PepperDash.Essentials.Devices.Common.VideoCodec;
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

@@ -1,7 +1,7 @@
using System;
using System.Collections.Generic;
namespace PepperDash_Essentials_Core.DeviceTypeInterfaces
namespace PepperDash.Essentials.Core.DeviceTypeInterfaces
{
public interface ILanguageDefinition
{

View File

@@ -1,7 +1,7 @@
using System;
using System.Collections.Generic;
namespace PepperDash_Essentials_Core.DeviceTypeInterfaces
namespace PepperDash.Essentials.Core.DeviceTypeInterfaces
{
public interface ILanguageProvider
{

View File

@@ -1,6 +1,6 @@
using PepperDash.Core;
namespace PepperDash_Essentials_Core.DeviceTypeInterfaces
namespace PepperDash.Essentials.Core.DeviceTypeInterfaces
{
public class LanguageLabel
{

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,99 @@
using System;
using System.Collections.Generic;
using System.Linq;
using PepperDash.Essentials.Core.Devices.Codec;
namespace PepperDash.Essentials.Core.Devices.AudioCodec
{
public abstract class AudioCodecBase : EssentialsDevice, IHasDialer, IUsageTracking, IAudioCodecInfo
{
public event EventHandler<CodecCallStatusItemChangeEventArgs> CallStatusChange;
public AudioCodecInfo CodecInfo { 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>
/// 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;
}
}
// In most cases only a single call can be active
public List<CodecActiveCallItem> ActiveCalls { get; set; }
public AudioCodecBase(string key, string name)
: base(key, name)
{
ActiveCalls = new List<CodecActiveCallItem>();
}
/// <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 (UsageTracker != null)
{
if (IsInCall && !UsageTracker.UsageTrackingStarted)
UsageTracker.StartDeviceUsage();
else if (UsageTracker.UsageTrackingStarted && !IsInCall)
UsageTracker.EndDeviceUsage();
}
}
#region IHasDialer Members
public abstract void Dial(string number);
public abstract void EndCall(CodecActiveCallItem activeCall);
public abstract void EndAllCalls();
public abstract void AcceptCall(CodecActiveCallItem item);
public abstract void RejectCall(CodecActiveCallItem item);
public abstract void SendDtmf(string digit);
#endregion
}
}

View File

@@ -10,7 +10,7 @@ using PepperDash.Core;
using PepperDash.Essentials.Core;
using PepperDash.Essentials.Core.Bridges;
using PepperDash.Essentials.Core.Presets;
using PepperDash.Essentials.Devices.Common.Codec;
using PepperDash.Essentials.Core.Devices.Codec;
using Newtonsoft.Json;

View File

@@ -84,7 +84,7 @@ namespace PepperDash.Essentials.Core
{
Debug.Console(2, "Getting Description Attribute from class: '{0}'", typeof(T).FullName);
var descriptionAttribute = typeof(T).GetCustomAttributes(typeof(DescriptionAttribute), true) as DescriptionAttribute[];
string description = descriptionAttribute[0].Description;
string description = descriptionAttribute[0].Description;
var snippetAttribute = typeof(T).GetCustomAttributes(typeof(ConfigSnippetAttribute), true) as ConfigSnippetAttribute[];
DeviceFactory.AddFactoryForType(typeName.ToLower(), description, typeof(T), BuildDevice);
}

View File

@@ -0,0 +1,17 @@
namespace PepperDash.Essentials.Core.Devices
{
/// <summary>
/// Represents a codec command that might need to have a friendly label applied for UI feedback purposes
/// </summary>
public class CodecCommandWithLabel
{
public string Command { get; set; }
public string Label { get; set; }
public CodecCommandWithLabel(string command, string label)
{
Command = command;
Label = label;
}
}
}

View File

@@ -0,0 +1,50 @@
using Newtonsoft.Json;
using PepperDash.Essentials.Core;
namespace PepperDash.Essentials.Core.Devices
{
public class DestinationListItem
{
[JsonProperty("sinkKey")]
public string SinkKey { get; set; }
private EssentialsDevice _sinkDevice;
[JsonIgnore]
public EssentialsDevice SinkDevice
{
get { return _sinkDevice ?? (_sinkDevice = DeviceManager.GetDeviceForKey(SinkKey) as EssentialsDevice); }
}
public string PreferredName
{
get
{
if (!string.IsNullOrEmpty(Name))
{
return Name;
}
return SinkDevice == null ? "---" : SinkDevice.Name;
}
}
[JsonProperty("name")]
public string Name { get; set; }
[JsonProperty("includeInDestinationList")]
public bool IncludeInDestinationList { get; set; }
[JsonProperty("order")]
public int Order { get; set; }
[JsonProperty("surfaceLocation")]
public int SurfaceLocation { get; set; }
[JsonProperty("verticalLocation")]
public int VerticalLocation { get; set; }
[JsonProperty("horizontalLocation")]
public int HorizontalLocation { get; set; }
}
}

View File

@@ -7,7 +7,7 @@ using PepperDash.Essentials.Core;
using PepperDash.Essentials.Core.Bridges;
using PepperDash.Essentials.Core.Config;
namespace PepperDash_Essentials_Core.Devices
namespace PepperDash.Essentials.Core.Devices
{
public class GenericIrController: EssentialsBridgeableDevice
{

View File

@@ -0,0 +1,22 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Crestron.SimplSharp;
namespace PepperDash.Essentials.Devices.Common.Cameras
{
/// <summary>
/// Describes a camera with preset functionality
/// </summary>
public interface IHasCameraPresets
{
event EventHandler<EventArgs> PresetsListHasChanged;
List<CameraPreset> Presets { get; }
void PresetSelect(int preset);
void PresetStore(int preset, string description);
}
}

View File

@@ -2,21 +2,21 @@
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Crestron.SimplSharp;
namespace PepperDash.Essentials.Core
{
public interface IBasicVideoMute
{
void VideoMuteToggle();
}
public interface IBasicVideoMuteWithFeedback : IBasicVideoMute
{
BoolFeedback VideoMuteIsOn { get; }
void VideoMuteOn();
void VideoMuteOff();
}
using Crestron.SimplSharp;
namespace PepperDash.Essentials.Core
{
public interface IBasicVideoMute
{
void VideoMuteToggle();
}
public interface IBasicVideoMuteWithFeedback : IBasicVideoMute
{
BoolFeedback VideoMuteIsOn { get; }
void VideoMuteOn();
void VideoMuteOff();
}
}

View File

@@ -0,0 +1,41 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Crestron.SimplSharp;
using Newtonsoft.Json;
using PepperDash.Core;
using PepperDash.Essentials.Core.Presets;
namespace PepperDash.Essentials.Devices.Common.VideoCodec
{
/// <summary>
/// Interface for camera presets
/// </summary>
public interface IHasCodecRoomPresets
{
event EventHandler<EventArgs> CodecRoomPresetsListHasChanged;
List<CodecRoomPreset> NearEndPresets { get; }
List<CodecRoomPreset> FarEndRoomPresets { get; }
void CodecRoomPresetSelect(int preset);
void CodecRoomPresetStore(int preset, string description);
}
/// <summary>
/// Represents a room preset on a video codec. Typically stores camera position(s) and video routing. Can be recalled by Far End if enabled.
/// </summary>
public class CodecRoomPreset : PresetBase
{
public CodecRoomPreset(int id, string description, bool def, bool isDef)
: base(id, description, def, isDef)
{
}
}
}

View File

@@ -1,13 +1,6 @@
using System;
using System.Collections.Generic;
using Crestron.SimplSharp;
using Crestron.SimplSharp.CrestronIO;
using Crestron.SimplSharpPro;
using System.Collections.Generic;
using Newtonsoft.Json;
using Newtonsoft.Json.Converters;
using Newtonsoft.Json.Linq;
using PepperDash.Core;
namespace PepperDash.Essentials.Core
{
@@ -31,16 +24,11 @@ namespace PepperDash.Essentials.Core
/// Returns the source Device for this, if it exists in DeviceManager
/// </summary>
[JsonIgnore]
public Device SourceDevice
public EssentialsDevice SourceDevice
{
get
{
if (_SourceDevice == null)
_SourceDevice = DeviceManager.GetDeviceForKey(SourceKey) as Device;
return _SourceDevice;
}
get { return _sourceDevice ?? (_sourceDevice = DeviceManager.GetDeviceForKey(SourceKey) as EssentialsDevice); }
}
Device _SourceDevice;
private EssentialsDevice _sourceDevice;
/// <summary>
/// Gets either the source's Name or this AlternateName property, if
@@ -51,13 +39,12 @@ namespace PepperDash.Essentials.Core
{
get
{
if (string.IsNullOrEmpty(Name))
{
if (SourceDevice == null)
return "---";
return SourceDevice.Name;
}
return Name;
if (!string.IsNullOrEmpty(Name))
{
return Name;
}
return SourceDevice == null ? "---" : SourceDevice.Name;
}
}

View File

@@ -4,7 +4,7 @@ using System.Linq;
using System.Text;
using Crestron.SimplSharp;
namespace PepperDash_Essentials_Core
namespace PepperDash.Essentials.Core
{
public class IsReadyEventArgs : EventArgs
{

View File

@@ -0,0 +1,218 @@
using System;
using System.Linq;
using Crestron.SimplSharpPro;
using PepperDash.Core;
using PepperDash.Essentials.Core.Config;
namespace PepperDash.Essentials.Core.Fusion
{
public class EssentialsDualDisplayFusionController:EssentialsHuddleSpaceFusionSystemControllerBase
{
private BooleanSigData _codecIsInCall;
private readonly EssentialsDualDisplayRoom _room;
public EssentialsDualDisplayFusionController(EssentialsDualDisplayRoom room, uint ipId) : base(room, ipId)
{
_room = room;
}
#region Overrides of EssentialsHuddleSpaceFusionSystemControllerBase
protected override void ExecuteCustomSteps()
{
var leftDisplay = _room.LeftDisplay as DisplayBase;
var rightDisplay = _room.RightDisplay as DisplayBase;
SetUpCodec();
SetUpDisplay(leftDisplay);
SetUpDisplay(rightDisplay);
base.ExecuteCustomSteps();
}
#endregion
#region Overrides of EssentialsHuddleSpaceFusionSystemControllerBase
protected override void SetUpDisplay()
{
Debug.Console(1, this, "No default Display fo this room");
}
private void SetUpDisplay(DisplayBase display)
{
FusionAsset tempAsset;
display.UsageTracker = new UsageTracking(display){UsageIsTracked = true};
display.UsageTracker.DeviceUsageEnded += UsageTrackerOnDeviceUsageEnded;
var config = ConfigReader.ConfigObject.Devices.SingleOrDefault((d) => d.Key == display.Key);
if (!FusionStaticAssets.TryGetValue(config.Uid, out tempAsset))
{
tempAsset = new FusionAsset(FusionRoomGuids.GetNextAvailableAssetNumber(FusionRoom), display.Name,
"Display", "");
FusionStaticAssets.Add(config.Uid, tempAsset);
}
var displayAsset = FusionRoom.CreateStaticAsset(tempAsset.SlotNumber, tempAsset.Name, "Display",
tempAsset.InstanceId);
displayAsset.PowerOn.OutputSig.UserObject = new Action<bool>(b => { if (b) display.PowerOn(); });
displayAsset.PowerOff.OutputSig.UserObject = new Action<bool>(b => { if (b) display.PowerOff(); });
if (!(display is ICommunicationMonitor))
{
return;
}
var displayCommMonitor = display as ICommunicationMonitor;
displayAsset.Connected.InputSig.BoolValue = displayCommMonitor.CommunicationMonitor.Status ==
MonitorStatus.IsOk;
displayCommMonitor.CommunicationMonitor.StatusChange += (o, a) =>
{
displayAsset.Connected.InputSig.BoolValue = displayCommMonitor.CommunicationMonitor.Status ==
MonitorStatus.IsOk;
};
}
private void UsageTrackerOnDeviceUsageEnded(object sender, DeviceUsageEventArgs deviceUsageEventArgs)
{
throw new NotImplementedException();
}
#endregion
/// <summary>
/// Creates a static asset for the codec and maps the joins to the main room symbol
/// </summary>
private void SetUpCodec()
{
try
{
var essentialsHuddleVtc1Room = Room as EssentialsHuddleVtc1Room;
if (essentialsHuddleVtc1Room == null)
{
return;
}
var codec = essentialsHuddleVtc1Room.VideoCodec;
if (codec == null)
{
Debug.Console(1, this, "Cannot link codec to Fusion because codec is null");
return;
}
codec.UsageTracker = new UsageTracking(codec) { UsageIsTracked = true };
codec.UsageTracker.DeviceUsageEnded += UsageTracker_DeviceUsageEnded;
var codecPowerOnAction = new Action<bool>(b =>
{
if (!b)
{
codec.StandbyDeactivate();
}
});
var codecPowerOffAction = new Action<bool>(b =>
{
if (!b)
{
codec.StandbyActivate();
}
});
// Map FusionRoom Attributes:
// Codec volume
var codecVolume = FusionRoom.CreateOffsetUshortSig(50, "Volume - Fader01", eSigIoMask.InputOutputSig);
codecVolume.OutputSig.UserObject =
new Action<ushort>(b => (codec as IBasicVolumeWithFeedback).SetVolume(b));
(codec as IBasicVolumeWithFeedback).VolumeLevelFeedback.LinkInputSig(codecVolume.InputSig);
// In Call Status
_codecIsInCall = FusionRoom.CreateOffsetBoolSig(69, "Conf - VC 1 In Call", eSigIoMask.InputSigOnly);
codec.CallStatusChange += codec_CallStatusChange;
// Online status
if (codec is ICommunicationMonitor)
{
var c = codec as ICommunicationMonitor;
var codecOnline = FusionRoom.CreateOffsetBoolSig(122, "Online - VC 1", eSigIoMask.InputSigOnly);
codecOnline.InputSig.BoolValue = c.CommunicationMonitor.Status == MonitorStatus.IsOk;
c.CommunicationMonitor.StatusChange +=
(o, a) => { codecOnline.InputSig.BoolValue = a.Status == MonitorStatus.IsOk; };
Debug.Console(0, this, "Linking '{0}' communication monitor to Fusion '{1}'", codec.Key,
"Online - VC 1");
}
// Codec IP Address
var codecHasIpInfo = false;
var codecComm = codec.Communication;
var codecIpAddress = string.Empty;
var codecIpPort = 0;
if (codecComm is GenericSshClient)
{
codecIpAddress = (codecComm as GenericSshClient).Hostname;
codecIpPort = (codecComm as GenericSshClient).Port;
codecHasIpInfo = true;
}
else if (codecComm is GenericTcpIpClient)
{
codecIpAddress = (codecComm as GenericTcpIpClient).Hostname;
codecIpPort = (codecComm as GenericTcpIpClient).Port;
codecHasIpInfo = true;
}
if (codecHasIpInfo)
{
var codecIpAddressSig = FusionRoom.CreateOffsetStringSig(121, "IP Address - VC",
eSigIoMask.InputSigOnly);
codecIpAddressSig.InputSig.StringValue = codecIpAddress;
var codecIpPortSig = FusionRoom.CreateOffsetStringSig(150, "IP Port - VC",
eSigIoMask.InputSigOnly);
codecIpPortSig.InputSig.StringValue = codecIpPort.ToString();
}
FusionAsset tempAsset;
var deviceConfig = ConfigReader.ConfigObject.Devices.FirstOrDefault(c => c.Key.Equals(codec.Key));
if (FusionStaticAssets.ContainsKey(deviceConfig.Uid))
{
tempAsset = FusionStaticAssets[deviceConfig.Uid];
}
else
{
// Create a new asset
tempAsset = new FusionAsset(FusionRoomGuids.GetNextAvailableAssetNumber(FusionRoom), codec.Name,
"Codec", "");
FusionStaticAssets.Add(deviceConfig.Uid, tempAsset);
}
var codecAsset = FusionRoom.CreateStaticAsset(tempAsset.SlotNumber, tempAsset.Name, "Display",
tempAsset.InstanceId);
codecAsset.PowerOn.OutputSig.UserObject = codecPowerOnAction;
codecAsset.PowerOff.OutputSig.UserObject = codecPowerOffAction;
codec.StandbyIsOnFeedback.LinkComplementInputSig(codecAsset.PowerOn.InputSig);
codecAsset.TrySetMakeModel(codec);
codecAsset.TryLinkAssetErrorToCommunication(codec);
}
catch (Exception e)
{
Debug.Console(1, this, "Error setting up codec in Fusion: {0}", e);
}
}
private void codec_CallStatusChange(object sender, Devices.Codec.CodecCallStatusItemChangeEventArgs e)
{
var codec = _room.VideoCodec;
_codecIsInCall.InputSig.BoolValue = codec.IsInCall;
}
}
}

View File

@@ -0,0 +1,219 @@
using System;
using System.Linq;
using Crestron.SimplSharpPro;
using PepperDash.Core;
using PepperDash.Essentials.Core.Config;
namespace PepperDash.Essentials.Core.Fusion
{
public class EssentialsHuddleVtc1FusionController : EssentialsHuddleSpaceFusionSystemControllerBase
{
private BooleanSigData _codecIsInCall;
private readonly EssentialsHuddleVtc1Room _room;
public EssentialsHuddleVtc1FusionController(EssentialsHuddleVtc1Room room, uint ipId)
: base(room, ipId)
{
_room = room;
}
/// <summary>
/// Called in base class constructor before RVI and GUID files are built
/// </summary>
protected override void ExecuteCustomSteps()
{
SetUpCodec();
base.ExecuteCustomSteps();
}
/// <summary>
/// Creates a static asset for the codec and maps the joins to the main room symbol
/// </summary>
private void SetUpCodec()
{
try
{
var codec = _room.VideoCodec;
if (codec == null)
{
Debug.Console(1, this, "Cannot link codec to Fusion because codec is null");
return;
}
codec.UsageTracker = new UsageTracking(codec) {UsageIsTracked = true};
codec.UsageTracker.DeviceUsageEnded += UsageTracker_DeviceUsageEnded;
var codecPowerOnAction = new Action<bool>(b =>
{
if (!b)
{
codec.StandbyDeactivate();
}
});
var codecPowerOffAction = new Action<bool>(b =>
{
if (!b)
{
codec.StandbyActivate();
}
});
// Map FusionRoom Attributes:
// Codec volume
var codecVolume = FusionRoom.CreateOffsetUshortSig(50, "Volume - Fader01", eSigIoMask.InputOutputSig);
codecVolume.OutputSig.UserObject =
new Action<ushort>(b => (codec as IBasicVolumeWithFeedback).SetVolume(b));
(codec as IBasicVolumeWithFeedback).VolumeLevelFeedback.LinkInputSig(codecVolume.InputSig);
// In Call Status
_codecIsInCall = FusionRoom.CreateOffsetBoolSig(69, "Conf - VC 1 In Call", eSigIoMask.InputSigOnly);
codec.CallStatusChange += codec_CallStatusChange;
// Online status
if (codec is ICommunicationMonitor)
{
var c = codec as ICommunicationMonitor;
var codecOnline = FusionRoom.CreateOffsetBoolSig(122, "Online - VC 1", eSigIoMask.InputSigOnly);
codecOnline.InputSig.BoolValue = c.CommunicationMonitor.Status == MonitorStatus.IsOk;
c.CommunicationMonitor.StatusChange +=
(o, a) => { codecOnline.InputSig.BoolValue = a.Status == MonitorStatus.IsOk; };
Debug.Console(0, this, "Linking '{0}' communication monitor to Fusion '{1}'", codec.Key,
"Online - VC 1");
}
// Codec IP Address
var codecHasIpInfo = false;
var codecComm = codec.Communication;
var codecIpAddress = string.Empty;
var codecIpPort = 0;
if (codecComm is GenericSshClient)
{
codecIpAddress = (codecComm as GenericSshClient).Hostname;
codecIpPort = (codecComm as GenericSshClient).Port;
codecHasIpInfo = true;
}
else if (codecComm is GenericTcpIpClient)
{
codecIpAddress = (codecComm as GenericTcpIpClient).Hostname;
codecIpPort = (codecComm as GenericTcpIpClient).Port;
codecHasIpInfo = true;
}
if (codecHasIpInfo)
{
var codecIpAddressSig = FusionRoom.CreateOffsetStringSig(121, "IP Address - VC",
eSigIoMask.InputSigOnly);
codecIpAddressSig.InputSig.StringValue = codecIpAddress;
var codecIpPortSig = FusionRoom.CreateOffsetStringSig(150, "IP Port - VC",
eSigIoMask.InputSigOnly);
codecIpPortSig.InputSig.StringValue = codecIpPort.ToString();
}
FusionAsset tempAsset;
var deviceConfig = ConfigReader.ConfigObject.Devices.FirstOrDefault(c => c.Key.Equals(codec.Key));
if (FusionStaticAssets.ContainsKey(deviceConfig.Uid))
{
tempAsset = FusionStaticAssets[deviceConfig.Uid];
}
else
{
// Create a new asset
tempAsset = new FusionAsset(FusionRoomGuids.GetNextAvailableAssetNumber(FusionRoom), codec.Name,
"Codec", "");
FusionStaticAssets.Add(deviceConfig.Uid, tempAsset);
}
var codecAsset = FusionRoom.CreateStaticAsset(tempAsset.SlotNumber, tempAsset.Name, "Display",
tempAsset.InstanceId);
codecAsset.PowerOn.OutputSig.UserObject = codecPowerOnAction;
codecAsset.PowerOff.OutputSig.UserObject = codecPowerOffAction;
codec.StandbyIsOnFeedback.LinkComplementInputSig(codecAsset.PowerOn.InputSig);
// TODO: Map relevant attributes on asset symbol
codecAsset.TrySetMakeModel(codec);
codecAsset.TryLinkAssetErrorToCommunication(codec);
}
catch (Exception e)
{
Debug.Console(1, this, "Error setting up codec in Fusion: {0}", e);
}
}
#region Overrides of EssentialsHuddleSpaceFusionSystemControllerBase
protected override void SetUpDisplay()
{
base.SetUpDisplay();
var defaultDisplay = _room.DefaultDisplay as TwoWayDisplayBase;
if (defaultDisplay == null)
{
Debug.Console(1, this, "Cannot link null display to Fusion because default display is null");
return;
}
var deviceConfig =
ConfigReader.ConfigObject.Devices.FirstOrDefault(d => d.Key.Equals(defaultDisplay.Key));
//Check for existing asset in GUIDs collection
FusionAsset tempAsset;
if (FusionStaticAssets.ContainsKey(deviceConfig.Uid))
{
tempAsset = FusionStaticAssets[deviceConfig.Uid];
}
else
{
// Create a new asset
tempAsset = new FusionAsset(FusionRoomGuids.GetNextAvailableAssetNumber(FusionRoom),
defaultDisplay.Name, "Display", "");
FusionStaticAssets.Add(deviceConfig.Uid, tempAsset);
}
var dispPowerOnAction = new Action<bool>(b =>
{
if (!b)
{
defaultDisplay.PowerOn();
}
});
var dispPowerOffAction = new Action<bool>(b =>
{
if (!b)
{
defaultDisplay.PowerOff();
}
});
var dispAsset = FusionRoom.CreateStaticAsset(tempAsset.SlotNumber, tempAsset.Name, "Display",
tempAsset.InstanceId);
dispAsset.PowerOn.OutputSig.UserObject = dispPowerOnAction;
dispAsset.PowerOff.OutputSig.UserObject = dispPowerOffAction;
defaultDisplay.PowerIsOnFeedback.LinkInputSig(dispAsset.PowerOn.InputSig);
// NO!! display.PowerIsOn.LinkComplementInputSig(dispAsset.PowerOff.InputSig);
// Use extension methods
dispAsset.TrySetMakeModel(defaultDisplay);
dispAsset.TryLinkAssetErrorToCommunication(defaultDisplay);
}
#endregion
private void codec_CallStatusChange(object sender, Devices.Codec.CodecCallStatusItemChangeEventArgs e)
{
var codec = _room.VideoCodec;
_codecIsInCall.InputSig.BoolValue = codec.IsInCall;
}
}
}

View File

@@ -10,6 +10,7 @@ using PepperDash.Core;
using PepperDash.Essentials.Core;
using PepperDash.Essentials.Core.Config;
using PepperDash.Essentials.Core.Devices;
using PepperDash.Essentials.Core.Rooms;
namespace PepperDash.Essentials.Core.Fusion
{
@@ -40,43 +41,43 @@ namespace PepperDash.Essentials.Core.Fusion
var devProps = JsonConvert.DeserializeObject<RoomOnToDefaultSourceWhenOccupiedConfig>(deviceConfig.Properties.ToString());
var enableFeature = roomInfo.FusionCustomProperties.FirstOrDefault(p => p.ID.Equals("EnRoomOnWhenOccupied"));
var enableFeature = roomInfo.FusionCustomProperties.FirstOrDefault(p => p.Id.Equals("EnRoomOnWhenOccupied"));
if (enableFeature != null)
devProps.EnableRoomOnWhenOccupied = bool.Parse(enableFeature.CustomFieldValue);
var enableTime = roomInfo.FusionCustomProperties.FirstOrDefault(p => p.ID.Equals("RoomOnWhenOccupiedStartTime"));
var enableTime = roomInfo.FusionCustomProperties.FirstOrDefault(p => p.Id.Equals("RoomOnWhenOccupiedStartTime"));
if (enableTime != null)
devProps.OccupancyStartTime = enableTime.CustomFieldValue;
var disableTime = roomInfo.FusionCustomProperties.FirstOrDefault(p => p.ID.Equals("RoomOnWhenOccupiedEndTime"));
var disableTime = roomInfo.FusionCustomProperties.FirstOrDefault(p => p.Id.Equals("RoomOnWhenOccupiedEndTime"));
if (disableTime != null)
devProps.OccupancyEndTime = disableTime.CustomFieldValue;
var enableSunday = roomInfo.FusionCustomProperties.FirstOrDefault(p => p.ID.Equals("EnRoomOnWhenOccupiedSun"));
var enableSunday = roomInfo.FusionCustomProperties.FirstOrDefault(p => p.Id.Equals("EnRoomOnWhenOccupiedSun"));
if (enableSunday != null)
devProps.EnableSunday = bool.Parse(enableSunday.CustomFieldValue);
var enableMonday = roomInfo.FusionCustomProperties.FirstOrDefault(p => p.ID.Equals("EnRoomOnWhenOccupiedMon"));
var enableMonday = roomInfo.FusionCustomProperties.FirstOrDefault(p => p.Id.Equals("EnRoomOnWhenOccupiedMon"));
if (enableMonday != null)
devProps.EnableMonday = bool.Parse(enableMonday.CustomFieldValue);
var enableTuesday = roomInfo.FusionCustomProperties.FirstOrDefault(p => p.ID.Equals("EnRoomOnWhenOccupiedTue"));
var enableTuesday = roomInfo.FusionCustomProperties.FirstOrDefault(p => p.Id.Equals("EnRoomOnWhenOccupiedTue"));
if (enableTuesday != null)
devProps.EnableTuesday = bool.Parse(enableTuesday.CustomFieldValue);
var enableWednesday = roomInfo.FusionCustomProperties.FirstOrDefault(p => p.ID.Equals("EnRoomOnWhenOccupiedWed"));
var enableWednesday = roomInfo.FusionCustomProperties.FirstOrDefault(p => p.Id.Equals("EnRoomOnWhenOccupiedWed"));
if (enableWednesday != null)
devProps.EnableWednesday = bool.Parse(enableWednesday.CustomFieldValue);
var enableThursday = roomInfo.FusionCustomProperties.FirstOrDefault(p => p.ID.Equals("EnRoomOnWhenOccupiedThu"));
var enableThursday = roomInfo.FusionCustomProperties.FirstOrDefault(p => p.Id.Equals("EnRoomOnWhenOccupiedThu"));
if (enableThursday != null)
devProps.EnableThursday = bool.Parse(enableThursday.CustomFieldValue);
var enableFriday = roomInfo.FusionCustomProperties.FirstOrDefault(p => p.ID.Equals("EnRoomOnWhenOccupiedFri"));
var enableFriday = roomInfo.FusionCustomProperties.FirstOrDefault(p => p.Id.Equals("EnRoomOnWhenOccupiedFri"));
if (enableFriday != null)
devProps.EnableFriday = bool.Parse(enableFriday.CustomFieldValue);
var enableSaturday = roomInfo.FusionCustomProperties.FirstOrDefault(p => p.ID.Equals("EnRoomOnWhenOccupiedSat"));
var enableSaturday = roomInfo.FusionCustomProperties.FirstOrDefault(p => p.Id.Equals("EnRoomOnWhenOccupiedSat"));
if (enableSaturday != null)
devProps.EnableSaturday = bool.Parse(enableSaturday.CustomFieldValue);
@@ -95,7 +96,7 @@ namespace PepperDash.Essentials.Core.Fusion
}
// Set the help message
var helpMessage = roomInfo.FusionCustomProperties.FirstOrDefault(p => p.ID.Equals("RoomHelpMessage"));
var helpMessage = roomInfo.FusionCustomProperties.FirstOrDefault(p => p.Id.Equals("RoomHelpMessage"));
if (helpMessage != null)
{
//Debug.Console(1, "Current Help Message: {0}. New Help Message: {1}", deviceConfig.Properties["help"]["message"].Value<string>(ToString()), helpMessage.CustomFieldValue);

View File

@@ -12,7 +12,6 @@ using Crestron.SimplSharpPro.DeviceSupport;
using PepperDash.Core;
using PepperDash.Essentials.Core;
using PepperDash.Essentials.Core.Config;
using PepperDash_Essentials_Core;
namespace PepperDash.Essentials.Core

View File

@@ -4,7 +4,7 @@ using Crestron.SimplSharpPro.GeneralIO;
using Newtonsoft.Json;
using PepperDash.Core;
using PepperDash.Essentials.Core.Bridges;
using PepperDash_Essentials_Core.Bridges.JoinMaps;
using PepperDash.Essentials.Core.Bridges.JoinMaps;
using System;
using System.Collections.Generic;

View File

@@ -186,19 +186,30 @@
<Compile Include="Device Info\DeviceInfo.cs" />
<Compile Include="Device Info\DeviceInfoEventArgs.cs" />
<Compile Include="Device Info\IDeviceInfoProvider.cs" />
<Compile Include="Devices\CodecInterfaces.cs" />
<Compile Include="Devices\Base Classes\AudioCodecBase.cs" />
<Compile Include="Devices\Base Classes\CameraBase.cs" />
<Compile Include="Devices\Base Classes\EssentialsBridgeableDevice.cs" />
<Compile Include="Devices\Base Classes\EssentialsDevice.cs" />
<Compile Include="Devices\CodecCommandWithLabel.cs" />
<Compile Include="Devices\Interfaces\CameraControl.cs" />
<Compile Include="Devices\Interfaces\CodecInterfaces.cs" />
<Compile Include="Devices\CrestronProcessor.cs" />
<Compile Include="Devices\DeviceApiBase.cs" />
<Compile Include="Devices\DestinationListItem.cs" />
<Compile Include="Devices\Base Classes\DeviceApiBase.cs" />
<Compile Include="Devices\DeviceFeedbackExtensions.cs" />
<Compile Include="Devices\EssentialsBridgeableDevice.cs" />
<Compile Include="Devices\EssentialsDevice.cs" />
<Compile Include="Devices\GenericIRController.cs" />
<Compile Include="Devices\IDspPreset.cs" />
<Compile Include="Devices\IProjectorInterfaces.cs" />
<Compile Include="Devices\Interfaces\IHasCameraPresets.cs" />
<Compile Include="Devices\Interfaces\IProjectorInterfaces.cs" />
<Compile Include="Devices\PC\InRoomPc.cs" />
<Compile Include="Devices\PC\Laptop.cs" />
<Compile Include="Devices\ReconfigurableDevice.cs" />
<Compile Include="Devices\Base Classes\ReconfigurableDevice.cs" />
<Compile Include="Devices\Base Classes\VideoCodecBase.cs" />
<Compile Include="Devices\RoomPresets.cs" />
<Compile Include="Devices\VolumeDeviceChangeEventArgs.cs" />
<Compile Include="DeviceTypeInterfaces\Codec\IHasExternalSourceSwitching.cs" />
<Compile Include="DeviceTypeInterfaces\Codec\IHasParticipants.cs" />
<Compile Include="DeviceTypeInterfaces\Codec\IHasSelfviewPosition.cs" />
<Compile Include="DeviceTypeInterfaces\LanguageLabel.cs" />
<Compile Include="DeviceTypeInterfaces\ILanguageProvider.cs" />
<Compile Include="DeviceTypeInterfaces\IHasBranding.cs" />
@@ -206,6 +217,24 @@
<Compile Include="DeviceTypeInterfaces\IHasFarEndContentStatus.cs" />
<Compile Include="DeviceTypeInterfaces\IHasPhoneDialing.cs" />
<Compile Include="DeviceTypeInterfaces\IMobileControl.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="Factory\ReadyEventArgs.cs" />
@@ -215,7 +244,9 @@
<Compile Include="Feedbacks\IntFeedback.cs" />
<Compile Include="Feedbacks\SerialFeedback.cs" />
<Compile Include="Feedbacks\StringFeedback.cs" />
<Compile Include="Fusion\EssentialsDualDisplayFusionController.cs" />
<Compile Include="Fusion\EssentialsHuddleSpaceFusionSystemControllerBase.cs" />
<Compile Include="Fusion\EssentialsHuddleVtc1FusionController.cs" />
<Compile Include="Fusion\FusionCustomPropertiesBridge.cs" />
<Compile Include="Fusion\FusionEventHandlers.cs" />
<Compile Include="Fusion\FusionProcessorQueries.cs" />
@@ -250,8 +281,8 @@
<Compile Include="Config\InfoConfig.cs" />
<Compile Include="Config\DeviceConfig.cs" />
<Compile Include="Devices\DisplayUiConstants.cs" />
<Compile Include="Devices\IUsageTracking.cs" />
<Compile Include="Devices\DeviceJsonApi.cs" />
<Compile Include="Devices\Interfaces\IUsageTracking.cs" />
<Compile Include="Devices\Base Classes\DeviceJsonApi.cs" />
<Compile Include="Devices\SourceListItem.cs" />
<Compile Include="DeviceTypeInterfaces\IDisplayBasic.cs" />
<Compile Include="DeviceTypeInterfaces\IDumbSource.cs" />
@@ -268,7 +299,7 @@
<Compile Include="DeviceTypeInterfaces\ITransport.cs" />
<Compile Include="Devices\GenericMonitoredTcpDevice.cs" />
<Compile Include="DeviceTypeInterfaces\INumeric.cs" />
<Compile Include="Devices\IVolumeAndAudioInterfaces.cs" />
<Compile Include="Devices\Interfaces\IVolumeAndAudioInterfaces.cs" />
<Compile Include="Display\BasicIrDisplay.cs" />
<Compile Include="Feedbacks\BoolFeedbackOneShot.cs" />
<Compile Include="Ramps and Increments\NumericalHelpers.cs" />
@@ -276,10 +307,24 @@
<Compile Include="Remotes\ButtonExtensions.cs" />
<Compile Include="Remotes\CrestronRemotePropertiesConfig.cs" />
<Compile Include="Remotes\Hrxx0WirelessRemoteController.cs" />
<Compile Include="Room\Behaviours\RoomOnToDefaultSourceWhenOccupied.cs" />
<Compile Include="Room\EssentialsRoomBase.cs" />
<Compile Include="Room\Interfaces.cs" />
<Compile Include="Room\iOccupancyStatusProvider.cs" />
<Compile Include="Rooms\Behaviours\RoomOnToDefaultSourceWhenOccupied.cs" />
<Compile Include="Rooms\Config\DDVC01RoomPropertiesConfig.cs" />
<Compile Include="Rooms\Config\EssentialsDualDisplayRoomPropertiesConfig.cs" />
<Compile Include="Rooms\Config\EssentialsHuddleRoomPropertiesConfig.cs" />
<Compile Include="Rooms\Config\EssentialsHuddleVtc1PropertiesConfig.cs" />
<Compile Include="Rooms\Config\EssentialsNDisplayRoomPropertiesConfig.cs" />
<Compile Include="Rooms\Config\EssentialsPresentationPropertiesConfig.cs" />
<Compile Include="Rooms\Config\EssentialsVolumeLevelConfig.cs" />
<Compile Include="Rooms\Emergency\EsentialsRoomEmergencyContactClosure.cs" />
<Compile Include="Rooms\EssentialsRoomBase.cs" />
<Compile Include="Rooms\Config\EssentialsRoomConfig.cs" />
<Compile Include="Rooms\Config\EssentialsRoomEmergencyConfig.cs" />
<Compile Include="Rooms\Interfaces.cs" />
<Compile Include="Rooms\iOccupancyStatusProvider.cs" />
<Compile Include="Rooms\Types\EssentialsDualDisplayRoom.cs" />
<Compile Include="Rooms\Types\EssentialsHuddleSpaceRoom.cs" />
<Compile Include="Rooms\Types\EssentialsHuddleVtc1Room.cs" />
<Compile Include="Rooms\Types\EssentialsNDisplayRoomBase.cs" />
<Compile Include="Routing\DummyRoutingInputsDevice.cs" />
<Compile Include="Routing\ICardPortsDevice.cs" />
<Compile Include="InUseTracking\IInUseTracking.cs" />
@@ -290,10 +335,10 @@
<Compile Include="Monitoring\StatusMonitorBase.cs" />
<Compile Include="Monitoring\Interfaces.cs" />
<Compile Include="Monitoring\GenericCommunicationMonitor.cs" />
<Compile Include="Devices\AudioInterfaces.cs" />
<Compile Include="Devices\IAttachVideoStatusExtensions.cs" />
<Compile Include="Devices\IHasFeedbacks.cs" />
<Compile Include="Devices\SmartObjectBaseTypes.cs" />
<Compile Include="Devices\Interfaces\AudioInterfaces.cs" />
<Compile Include="Devices\Interfaces\IAttachVideoStatusExtensions.cs" />
<Compile Include="Devices\Interfaces\IHasFeedbacks.cs" />
<Compile Include="Devices\Base Classes\SmartObjectBaseTypes.cs" />
<Compile Include="Devices\PresentationDeviceType.cs" />
<Compile Include="Display\MockDisplay.cs" />
<Compile Include="Ethernet\EthernetStatistics.cs" />
@@ -338,11 +383,11 @@
<Compile Include="Devices\IrOutputPortController.cs" />
<Compile Include="Display\DisplayBase.cs" />
<Compile Include="Feedbacks\FeedbackBase.cs" />
<Compile Include="Room\Room.cs" />
<Compile Include="Rooms\Room.cs" />
<Compile Include="SmartObjects\SubpageReferencList\SourceListSubpageReferenceList.cs" />
<Compile Include="Touchpanels\ModalDialog.cs" />
<Compile Include="TriListBridges\HandlerBridge.cs" />
<Compile Include="Devices\FIND HOMES Interfaces.cs" />
<Compile Include="Devices\Interfaces\Interfaces.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="SigHelper.cs" />
<Compile Include="SmartObjects\SubpageReferencList\SubpageReferenceList.cs" />

View File

@@ -1,7 +1,7 @@
using System;
using PepperDash.Core;
namespace PepperDash_Essentials_Core.Queues
namespace PepperDash.Essentials.Core.Queues
{
/// <summary>
/// IBasicCommunication Message for IQueue

View File

@@ -3,7 +3,7 @@ using Crestron.SimplSharp;
using Crestron.SimplSharpPro.CrestronThread;
using PepperDash.Core;
namespace PepperDash_Essentials_Core.Queues
namespace PepperDash.Essentials.Core.Queues
{
/// <summary>
/// Threadsafe processing of queued items with pacing if required

View File

@@ -5,7 +5,7 @@ using System.Text;
using Crestron.SimplSharp;
using PepperDash.Core;
namespace PepperDash_Essentials_Core.Queues
namespace PepperDash.Essentials.Core.Queues
{
public interface IQueue<T> : IKeyed, IDisposable where T : class
{

View File

@@ -1,4 +1,4 @@
namespace PepperDash_Essentials_Core.Queues
namespace PepperDash.Essentials.Core.Queues
{
public interface IQueueMessage
{

View File

@@ -1,6 +1,6 @@
using System;
namespace PepperDash_Essentials_Core.Queues
namespace PepperDash.Essentials.Core.Queues
{
/// <summary>
/// Message class for processing strings via an IQueue

View File

@@ -2,7 +2,7 @@
using Crestron.SimplSharp;
using PepperDash.Core;
namespace PepperDash_Essentials_Core.Queues
namespace PepperDash.Essentials.Core.Queues
{
public sealed class StringResponseProcessor : IKeyed, IDisposable
{

View File

@@ -83,7 +83,7 @@ namespace PepperDash.Essentials.Core
}
}
void _gateway_IsReadyEvent(object sender, PepperDash_Essentials_Core.IsReadyEventArgs e)
void _gateway_IsReadyEvent(object sender, Core.IsReadyEventArgs e)
{
if (e.IsReady != true) return;
_remote = GetHr1x0WirelessRemote(_config);

View File

@@ -1,368 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Crestron.SimplSharp;
using Crestron.SimplSharp.Scheduler;
using PepperDash.Core;
using PepperDash.Essentials.Core;
using PepperDash.Essentials.Core.Config;
using PepperDash.Essentials.Core.Devices;
using PepperDash.Essentials.Core.DeviceTypeInterfaces;
namespace PepperDash.Essentials.Core
{
/// <summary>
///
/// </summary>
public abstract class EssentialsRoomBase : ReconfigurableDevice
{
/// <summary>
///
/// </summary>
public BoolFeedback OnFeedback { get; private set; }
/// <summary>
/// Fires when the RoomOccupancy object is set
/// </summary>
public event EventHandler<EventArgs> RoomOccupancyIsSet;
public BoolFeedback IsWarmingUpFeedback { get; private set; }
public BoolFeedback IsCoolingDownFeedback { get; private set; }
public IOccupancyStatusProvider RoomOccupancy { get; private set; }
public bool OccupancyStatusProviderIsRemote { get; private set; }
protected abstract Func<bool> IsWarmingFeedbackFunc { get; }
protected abstract Func<bool> IsCoolingFeedbackFunc { get; }
/// <summary>
/// Indicates if this room is Mobile Control Enabled
/// </summary>
public bool IsMobileControlEnabled { get; private set; }
/// <summary>
/// The bridge for this room if Mobile Control is enabled
/// </summary>
public IMobileControlRoomBridge MobileControlRoomBridge { get; private set; }
/// <summary>
/// The config name of the source list
/// </summary>
///
protected string _SourceListKey;
public virtual string SourceListKey {
get
{
return _SourceListKey;
}
set
{
_SourceListKey = value;
}
}
/// <summary>
/// Timer used for informing the UIs of a shutdown
/// </summary>
public SecondsCountdownTimer ShutdownPromptTimer { get; private set; }
/// <summary>
///
/// </summary>
public int ShutdownPromptSeconds { get; set; }
public int ShutdownVacancySeconds { get; set; }
public eShutdownType ShutdownType { get; private set; }
public EssentialsRoomEmergencyBase Emergency { get; set; }
public Core.Privacy.MicrophonePrivacyController MicrophonePrivacy { get; set; }
public string LogoUrlLightBkgnd { get; set; }
public string LogoUrlDarkBkgnd { get; set; }
protected SecondsCountdownTimer RoomVacancyShutdownTimer { get; private set; }
public eVacancyMode VacancyMode { get; private set; }
/// <summary>
/// Seconds after vacancy prompt is displayed until shutdown
/// </summary>
protected int RoomVacancyShutdownSeconds;
/// <summary>
/// Seconds after vacancy detected until prompt is displayed
/// </summary>
protected int RoomVacancyShutdownPromptSeconds;
/// <summary>
///
/// </summary>
protected abstract Func<bool> OnFeedbackFunc { get; }
protected Dictionary<IBasicVolumeWithFeedback, uint> SavedVolumeLevels = new Dictionary<IBasicVolumeWithFeedback, uint>();
/// <summary>
/// When volume control devices change, should we zero the one that we are leaving?
/// </summary>
public bool ZeroVolumeWhenSwtichingVolumeDevices { get; private set; }
public EssentialsRoomBase(DeviceConfig config)
: base(config)
{
// Setup the ShutdownPromptTimer
ShutdownPromptTimer = new SecondsCountdownTimer(Key + "-offTimer");
ShutdownPromptTimer.IsRunningFeedback.OutputChange += (o, a) =>
{
if (!ShutdownPromptTimer.IsRunningFeedback.BoolValue)
ShutdownType = eShutdownType.None;
};
ShutdownPromptTimer.HasFinished += (o, a) => Shutdown(); // Shutdown is triggered
ShutdownPromptSeconds = 60;
ShutdownVacancySeconds = 120;
ShutdownType = eShutdownType.None;
RoomVacancyShutdownTimer = new SecondsCountdownTimer(Key + "-vacancyOffTimer");
//RoomVacancyShutdownTimer.IsRunningFeedback.OutputChange += (o, a) =>
//{
// if (!RoomVacancyShutdownTimer.IsRunningFeedback.BoolValue)
// ShutdownType = ShutdownType.Vacancy;
//};
RoomVacancyShutdownTimer.HasFinished += new EventHandler<EventArgs>(RoomVacancyShutdownPromptTimer_HasFinished); // Shutdown is triggered
RoomVacancyShutdownPromptSeconds = 1500; // 25 min to prompt warning
RoomVacancyShutdownSeconds = 240; // 4 min after prompt will trigger shutdown prompt
VacancyMode = eVacancyMode.None;
OnFeedback = new BoolFeedback(OnFeedbackFunc);
IsWarmingUpFeedback = new BoolFeedback(IsWarmingFeedbackFunc);
IsCoolingDownFeedback = new BoolFeedback(IsCoolingFeedbackFunc);
AddPostActivationAction(() =>
{
if (RoomOccupancy != null)
OnRoomOccupancyIsSet();
});
}
public override bool CustomActivate()
{
SetUpMobileControl();
return base.CustomActivate();
}
/// <summary>
/// If mobile control is enabled, sets the appropriate properties
/// </summary>
void SetUpMobileControl()
{
var mcBridgeKey = string.Format("mobileControlBridge-{0}", Key);
var mcBridge = DeviceManager.GetDeviceForKey(mcBridgeKey);
if (mcBridge == null)
{
Debug.Console(1, this, "*********************Mobile Control Bridge Not found for this room.");
IsMobileControlEnabled = false;
return;
}
else
{
MobileControlRoomBridge = mcBridge as IMobileControlRoomBridge;
Debug.Console(1, this, "*********************Mobile Control Bridge found and enabled for this room");
IsMobileControlEnabled = true;
}
}
void RoomVacancyShutdownPromptTimer_HasFinished(object sender, EventArgs e)
{
switch (VacancyMode)
{
case eVacancyMode.None:
StartRoomVacancyTimer(eVacancyMode.InInitialVacancy);
break;
case eVacancyMode.InInitialVacancy:
StartRoomVacancyTimer(eVacancyMode.InShutdownWarning);
break;
case eVacancyMode.InShutdownWarning:
{
StartShutdown(eShutdownType.Vacancy);
Debug.Console(0, this, Debug.ErrorLogLevel.Notice, "Shutting Down due to vacancy.");
break;
}
default:
break;
}
}
/// <summary>
///
/// </summary>
/// <param name="type"></param>
public void StartShutdown(eShutdownType type)
{
// Check for shutdowns running. Manual should override other shutdowns
if (type == eShutdownType.Manual)
ShutdownPromptTimer.SecondsToCount = ShutdownPromptSeconds;
else if (type == eShutdownType.Vacancy)
ShutdownPromptTimer.SecondsToCount = ShutdownVacancySeconds;
ShutdownType = type;
ShutdownPromptTimer.Start();
Debug.Console(0, this, Debug.ErrorLogLevel.Notice, "ShutdownPromptTimer Started. Type: {0}. Seconds: {1}", ShutdownType, ShutdownPromptTimer.SecondsToCount);
}
public void StartRoomVacancyTimer(eVacancyMode mode)
{
if (mode == eVacancyMode.None)
RoomVacancyShutdownTimer.SecondsToCount = RoomVacancyShutdownPromptSeconds;
else if (mode == eVacancyMode.InInitialVacancy)
RoomVacancyShutdownTimer.SecondsToCount = RoomVacancyShutdownSeconds;
else if (mode == eVacancyMode.InShutdownWarning)
RoomVacancyShutdownTimer.SecondsToCount = 60;
VacancyMode = mode;
RoomVacancyShutdownTimer.Start();
Debug.Console(0, this, Debug.ErrorLogLevel.Notice, "Vacancy Timer Started. Mode: {0}. Seconds: {1}", VacancyMode, RoomVacancyShutdownTimer.SecondsToCount);
}
/// <summary>
/// Resets the vacancy mode and shutsdwon the room
/// </summary>
public void Shutdown()
{
VacancyMode = eVacancyMode.None;
EndShutdown();
}
/// <summary>
/// This method is for the derived class to define it's specific shutdown
/// requirements but should not be called directly. It is called by Shutdown()
/// </summary>
protected abstract void EndShutdown();
/// <summary>
/// Override this to implement a default volume level(s) method
/// </summary>
public abstract void SetDefaultLevels();
/// <summary>
/// Sets the object to be used as the IOccupancyStatusProvider for the room. Can be an Occupancy Aggregator or a specific device
/// </summary>
/// <param name="statusProvider"></param>
public void SetRoomOccupancy(IOccupancyStatusProvider statusProvider, int timeoutMinutes)
{
if (statusProvider == null)
{
Debug.Console(0, this, "ERROR: Occupancy sensor device is null");
return;
}
Debug.Console(0, this, Debug.ErrorLogLevel.Notice, "Room Occupancy set to device: '{0}'", (statusProvider as Device).Key);
Debug.Console(0, this, Debug.ErrorLogLevel.Notice, "Timeout Minutes from Config is: {0}", timeoutMinutes);
// If status provider is fusion, set flag to remote
if (statusProvider is Core.Fusion.EssentialsHuddleSpaceFusionSystemControllerBase)
OccupancyStatusProviderIsRemote = true;
if(timeoutMinutes > 0)
RoomVacancyShutdownSeconds = timeoutMinutes * 60;
Debug.Console(0, this, Debug.ErrorLogLevel.Notice, "RoomVacancyShutdownSeconds set to {0}", RoomVacancyShutdownSeconds);
RoomOccupancy = statusProvider;
RoomOccupancy.RoomIsOccupiedFeedback.OutputChange -= RoomIsOccupiedFeedback_OutputChange;
RoomOccupancy.RoomIsOccupiedFeedback.OutputChange += RoomIsOccupiedFeedback_OutputChange;
OnRoomOccupancyIsSet();
}
void OnRoomOccupancyIsSet()
{
var handler = RoomOccupancyIsSet;
if (handler != null)
handler(this, new EventArgs());
}
/// <summary>
/// To allow base class to power room on to last source
/// </summary>
public abstract void PowerOnToDefaultOrLastSource();
/// <summary>
/// To allow base class to power room on to default source
/// </summary>
/// <returns></returns>
public abstract bool RunDefaultPresentRoute();
void RoomIsOccupiedFeedback_OutputChange(object sender, EventArgs e)
{
if (RoomOccupancy.RoomIsOccupiedFeedback.BoolValue == false)
{
Debug.Console(1, this, Debug.ErrorLogLevel.Notice, "Notice: Vacancy Detected");
// Trigger the timer when the room is vacant
StartRoomVacancyTimer(eVacancyMode.InInitialVacancy);
}
else
{
Debug.Console(1, this, Debug.ErrorLogLevel.Notice, "Notice: Occupancy Detected");
// Reset the timer when the room is occupied
RoomVacancyShutdownTimer.Cancel();
}
}
/// <summary>
/// Executes when RoomVacancyShutdownTimer expires. Used to trigger specific room actions as needed. Must nullify the timer object when executed
/// </summary>
/// <param name="o"></param>
public abstract void RoomVacatedForTimeoutPeriod(object o);
}
/// <summary>
/// To describe the various ways a room may be shutting down
/// </summary>
public enum eShutdownType
{
None = 0,
External,
Manual,
Vacancy
}
public enum eVacancyMode
{
None = 0,
InInitialVacancy,
InShutdownWarning
}
/// <summary>
///
/// </summary>
public enum eWarmingCoolingMode
{
None,
Warming,
Cooling
}
public abstract class EssentialsRoomEmergencyBase : IKeyed
{
public string Key { get; private set; }
public EssentialsRoomEmergencyBase(string key)
{
Key = key;
}
}
}

View File

@@ -1,19 +1,12 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Crestron.SimplSharp;
using Crestron.SimplSharp.Scheduler;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using PepperDash.Core;
using PepperDash.Essentials.Core;
using PepperDash.Essentials.Core.Config;
using PepperDash.Essentials.Core.Devices;
namespace PepperDash.Essentials.Core
namespace PepperDash.Essentials.Core.Rooms
{
/// <summary>
/// A device that when linked to a room can power the room on when enabled during scheduled hours.

View File

@@ -0,0 +1,26 @@
using System.Collections.Generic;
using Newtonsoft.Json;
using PepperDash.Essentials.Core.Config;
namespace PepperDash.Essentials.Core.Rooms.Config
{
public class DDVC01RoomPropertiesConfig : EssentialsHuddleVtc1PropertiesConfig
{
[JsonProperty("roomPhoneNumber")]
public string RoomPhoneNumber { get; set; }
[JsonProperty("roomURI")]
public string RoomURI { get; set; }
[JsonProperty("speedDials")]
public List<DDVC01SpeedDial> SpeedDials { get; set; }
[JsonProperty("volumeSliderNames")]
public List<string> VolumeSliderNames { get; set; }
}
public class DDVC01SpeedDial
{
[JsonProperty("name")]
public string Name { get; set; }
[JsonProperty("number")]
public string Number { get; set; }
}
}

View File

@@ -0,0 +1,7 @@
namespace PepperDash.Essentials.Core.Rooms.Config
{
public class EssentialsDualDisplayRoomPropertiesConfig : EssentialsNDisplayRoomPropertiesConfig
{
}
}

View File

@@ -0,0 +1,35 @@
using Newtonsoft.Json;
using PepperDash.Essentials.Core.Config;
namespace PepperDash.Essentials.Core.Rooms.Config
{
/// <summary>
///
/// </summary>
public class EssentialsHuddleRoomPropertiesConfig : EssentialsRoomPropertiesConfig
{
/// <summary>
/// The key of the default display device
/// </summary>
[JsonProperty("defaultDisplayKey")]
public string DefaultDisplayKey { get; set; }
/// <summary>
/// The key of the default audio device
/// </summary>
[JsonProperty("defaultAudioKey")]
public string DefaultAudioKey { get; set; }
/// <summary>
/// The key of the source list for the room
/// </summary>
[JsonProperty("sourceListKey")]
public string SourceListKey { get; set; }
/// <summary>
/// The key of the default source item from the source list
/// </summary>
[JsonProperty("defaultSourceItem")]
public string DefaultSourceItem { get; set; }
}
}

View File

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

View File

@@ -0,0 +1,28 @@
using System.Collections.Generic;
using PepperDash.Core;
using PepperDash.Essentials.Core;
using Newtonsoft.Json;
using PepperDash.Essentials.Core.Config;
namespace PepperDash.Essentials.Core.Rooms.Config
{
/// <summary>
///
/// </summary>
public class EssentialsNDisplayRoomPropertiesConfig : EssentialsHuddleVtc1PropertiesConfig
{
[JsonProperty("defaultAudioBehavior")]
public string DefaultAudioBehavior { get; set; }
[JsonProperty("defaultVideoBehavior")]
public string DefaultVideoBehavior { get; set; }
[JsonProperty("destinationListKey")]
public string DestinationListKey { get; set; }
}
public class DisplayItem : IKeyName
{
public string Key { get; set; }
public string Name { get; set; }
}
}

View File

@@ -0,0 +1,23 @@
using System.Collections.Generic;
using PepperDash.Essentials.Core.Config;
namespace PepperDash.Essentials.Core.Rooms.Config
{
/// <summary>
///
/// </summary>
public class EssentialsPresentationRoomPropertiesConfig : EssentialsRoomPropertiesConfig
{
public string DefaultAudioBehavior { get; set; }
public string DefaultAudioKey { get; set; }
public string DefaultVideoBehavior { get; set; }
public List<string> DisplayKeys { get; set; }
public string SourceListKey { get; set; }
public bool HasDsp { get; set; }
public EssentialsPresentationRoomPropertiesConfig()
{
DisplayKeys = new List<string>();
}
}
}

View File

@@ -0,0 +1,296 @@
using System.Collections.Generic;
using Crestron.SimplSharp;
using Newtonsoft.Json;
using PepperDash.Core;
using PepperDash.Essentials.Core.Config;
using PepperDash.Essentials.Core.Privacy;
namespace PepperDash.Essentials.Core.Rooms.Config
{
public class EssentialsRoomConfigHelper
{
/// <summary>
/// Returns a room object from this config data
/// </summary>
/// <returns></returns>
public static Device GetRoomObject(DeviceConfig roomConfig)
{
var typeName = roomConfig.Type.ToLower();
EssentialsRoomBase rm;
if (typeName == "huddle")
{
var huddle = new EssentialsHuddleSpaceRoom(roomConfig);
return huddle;
}
if (typeName == "huddlevtc1")
{
rm = new EssentialsHuddleVtc1Room(roomConfig);
return rm;
}
if (typeName == "ddvc01Bridge")
{
return new Device(roomConfig.Key, roomConfig.Name); // placeholder device that does nothing.
}
if (typeName != "dualdisplay")
{
return null;
}
//rm = new EssentialsDualDisplayRoom();
return null;
}
/// <summary>
/// Gets and operating, standalone emergegncy object that can be plugged into a room.
/// Returns null if there is no emergency defined
/// </summary>
public static EssentialsRoomEmergencyBase GetEmergency(EssentialsRoomPropertiesConfig props, EssentialsRoomBase room)
{
// This emergency
var emergency = props.Emergency;
if (emergency == null)
{
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;
}
/// <summary>
///
/// </summary>
/// <param name="props"></param>
/// <param name="room"></param>
/// <returns></returns>
public static MicrophonePrivacyController GetMicrophonePrivacy(
EssentialsRoomPropertiesConfig props, IPrivacy room)
{
var microphonePrivacy = props.MicrophonePrivacy;
if (microphonePrivacy == null)
{
Debug.Console(0, "Cannot create microphone privacy with null properties");
return null;
}
// Get the MicrophonePrivacy device from the device manager
var mP = (DeviceManager.GetDeviceForKey(props.MicrophonePrivacy.DeviceKey) as
MicrophonePrivacyController);
// Set this room as the IPrivacy device
if (mP == null)
{
Debug.Console(0, "ERROR: Selected device {0} is not MicrophonePrivacyController", props.MicrophonePrivacy.DeviceKey);
return null;
}
mP.SetPrivacyDevice(room);
var behaviour = props.MicrophonePrivacy.Behaviour.ToLower();
if (behaviour == null)
{
Debug.Console(0, "WARNING: No behaviour defined for MicrophonePrivacyController");
return null;
}
switch (behaviour)
{
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;
}
}
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;
}
}
break;
}
return mP;
}
}
/// <summary>
///
/// </summary>
public class EssentialsRoomPropertiesConfig
{
[JsonProperty("addresses")]
public EssentialsRoomAddressPropertiesConfig Addresses { get; set; }
[JsonProperty("description")]
public string Description { get; set; }
[JsonProperty("emergency")]
public EssentialsRoomEmergencyConfig Emergency { get; set; }
[JsonProperty("help")]
public EssentialsHelpPropertiesConfig Help { get; set; }
[JsonProperty("helpMessage")]
public string HelpMessage { get; set; }
[JsonProperty("environment")]
public EssentialsEnvironmentPropertiesConfig Environment { get; set; }
[JsonProperty("logo")]
public EssentialsLogoPropertiesConfig Logo { get; set; }
[JsonProperty("microphonePrivacy")]
public EssentialsRoomMicrophonePrivacyConfig MicrophonePrivacy { get; set; }
[JsonProperty("occupancy")]
public EssentialsRoomOccSensorConfig Occupancy { get; set; }
[JsonProperty("oneButtonMeeting")]
public EssentialsOneButtonMeetingPropertiesConfig OneButtonMeeting { get; set; }
[JsonProperty("shutdownVacancySeconds")]
public int ShutdownVacancySeconds { get; set; }
[JsonProperty("shutdownPromptSeconds")]
public int ShutdownPromptSeconds { get; set; }
[JsonProperty("tech")]
public EssentialsRoomTechConfig Tech { get; set; }
[JsonProperty("volumes")]
public EssentialsRoomVolumesConfig Volumes { get; set; }
[JsonProperty("zeroVolumeWhenSwtichingVolumeDevices")]
public bool ZeroVolumeWhenSwtichingVolumeDevices { get; set; }
}
public class EssentialsEnvironmentPropertiesConfig
{
public bool Enabled { get; set; }
[JsonProperty("deviceKeys")]
public List<string> DeviceKeys { get; set; }
public EssentialsEnvironmentPropertiesConfig()
{
DeviceKeys = new List<string>();
}
}
public class EssentialsRoomMicrophonePrivacyConfig
{
[JsonProperty("deviceKey")]
public string DeviceKey { get; set; }
[JsonProperty("behaviour")]
public string Behaviour { get; set; }
}
/// <summary>
/// Properties for the help text box
/// </summary>
public class EssentialsHelpPropertiesConfig
{
[JsonProperty("message")]
public string Message { get; set; }
[JsonProperty("showCallButton")]
public bool ShowCallButton { get; set; }
/// <summary>
/// Defaults to "Call Help Desk"
/// </summary>
[JsonProperty("callButtonText")]
public string CallButtonText { get; set; }
public EssentialsHelpPropertiesConfig()
{
CallButtonText = "Call Help Desk";
}
}
/// <summary>
///
/// </summary>
public class EssentialsOneButtonMeetingPropertiesConfig
{
[JsonProperty("enable")]
public bool Enable { get; set; }
}
public class EssentialsRoomAddressPropertiesConfig
{
[JsonProperty("phoneNumber")]
public string PhoneNumber { get; set; }
[JsonProperty("sipAddress")]
public string SipAddress { get; set; }
}
/// <summary>
/// Properties for the room's logo on panels
/// </summary>
public class EssentialsLogoPropertiesConfig
{
[JsonProperty("type")]
public string Type { get; set; }
[JsonProperty("url")]
public string Url { get; set; }
/// <summary>
/// Gets either the custom URL, a local-to-processor URL, or null if it's a default logo
/// </summary>
public string GetUrl()
{
if (Type == "url")
return Url;
if (Type == "system")
return string.Format("http://{0}:8080/logo.png",
CrestronEthernetHelper.GetEthernetParameter(CrestronEthernetHelper.ETHERNET_PARAMETER_TO_GET.GET_CURRENT_IP_ADDRESS, 0));
return null;
}
}
/// <summary>
/// Represents occupancy sensor(s) setup for a room
/// </summary>
public class EssentialsRoomOccSensorConfig
{
[JsonProperty("deviceKey")]
public string DeviceKey { get; set; }
[JsonProperty("timeoutMinutes")]
public int TimeoutMinutes { get; set; }
}
public class EssentialsRoomTechConfig
{
[JsonProperty("password")]
public string Password { get; set; }
}
}

View File

@@ -0,0 +1,30 @@
namespace PepperDash.Essentials.Core.Rooms.Config
{
/// <summary>
///
/// </summary>
public class EssentialsRoomEmergencyConfig
{
public EssentialsRoomEmergencyTriggerConfig Trigger { get; set; }
public string Behavior { get; set; }
}
/// <summary>
///
/// </summary>
public class EssentialsRoomEmergencyTriggerConfig
{
/// <summary>
/// contact,
/// </summary>
public string Type { get; set; }
/// <summary>
/// Input number if contact
/// </summary>
public int Number { get; set; }
public bool TriggerOnClose { get; set; }
}
}

View File

@@ -0,0 +1,64 @@
namespace PepperDash.Essentials.Core
{
/// <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

@@ -0,0 +1,47 @@
using System;
using Crestron.SimplSharpPro;
using PepperDash.Essentials.Core.Rooms.Config;
namespace PepperDash.Essentials.Core.Rooms
{
public class EssentialsRoomEmergencyContactClosure : EssentialsRoomEmergencyBase
{
EssentialsRoomBase Room;
string Behavior;
bool TriggerOnClose;
public EssentialsRoomEmergencyContactClosure(string key, EssentialsRoomEmergencyConfig config, EssentialsRoomBase room) :
base(key)
{
Room = room;
var cs = Global.ControlSystem;
if (config.Trigger.Type.Equals("contact", StringComparison.OrdinalIgnoreCase))
{
var portNum = (uint)config.Trigger.Number;
if (portNum <= cs.NumberOfDigitalInputPorts)
{
cs.DigitalInputPorts[portNum].Register();
cs.DigitalInputPorts[portNum].StateChange += EsentialsRoomEmergencyContactClosure_StateChange;
}
}
Behavior = config.Behavior;
TriggerOnClose = config.Trigger.TriggerOnClose;
}
void EsentialsRoomEmergencyContactClosure_StateChange(DigitalInput digitalInput, DigitalInputEventArgs args)
{
if (args.State && TriggerOnClose || !args.State && !TriggerOnClose)
RunEmergencyBehavior();
}
/// <summary>
///
/// </summary>
public void RunEmergencyBehavior()
{
if (Behavior.Equals("shutdown"))
Room.Shutdown();
}
}
}

View File

@@ -0,0 +1,849 @@
using System;
using System.Collections.Generic;
using System.Linq;
using Crestron.SimplSharp;
using PepperDash.Core;
using PepperDash.Essentials.Core.Config;
using PepperDash.Essentials.Core.Devices;
using PepperDash.Essentials.Core.DeviceTypeInterfaces;
using PepperDash.Essentials.Core.Rooms.Config;
namespace PepperDash.Essentials.Core
{
/// <summary>
///
/// </summary>
public abstract class EssentialsRoomBase : ReconfigurableDevice
{
protected EssentialsRoomPropertiesConfig BaseConfig;
protected IBasicVolumeControls CurrentAudioDevice;
protected Func<bool> IsCoolingFeedbackFunc;
protected Func<bool> IsWarmingFeedbackFunc;
protected string LastSourceKey;
public string LogoUrlLightBkgnd { get; set; }
public string LogoUrlDarkBkgnd { get; set; }
/// <summary>
/// Indicates if this room is Mobile Control Enabled
/// </summary>
public bool IsMobileControlEnabled { get; private set; }
/// <summary>
/// The bridge for this room if Mobile Control is enabled
/// </summary>
public IMobileControlRoomBridge MobileControlRoomBridge { get; private set; }
/// <summary>
///
/// </summary>
protected Func<bool> OnFeedbackFunc;
/// <summary>
/// Seconds after vacancy detected until prompt is displayed
/// </summary>
protected int RoomVacancyShutdownPromptSeconds;
/// <summary>
/// Seconds after vacancy prompt is displayed until shutdown
/// </summary>
protected int RoomVacancyShutdownSeconds;
protected CCriticalSection RoutingLock = new CCriticalSection();
protected Dictionary<IBasicVolumeWithFeedback, uint> SavedVolumeLevels =
new Dictionary<IBasicVolumeWithFeedback, uint>();
private SourceListItem _currentSourceInfo;
/// <summary>
/// If room is off, enables power on to last source. Default true
/// </summary>
public bool EnablePowerOnToLastSource { get; set; }
public const string DefaultSourceListKey = "default";
protected EssentialsRoomBase(DeviceConfig config)
: base(config)
{
BaseConfig = config.Properties.ToObject<EssentialsRoomPropertiesConfig>();
ZeroVolumeWhenSwtichingVolumeDevices = BaseConfig.ZeroVolumeWhenSwtichingVolumeDevices;
SetupShutdownPrompt();
SetupRoomVacancyShutdown();
OnFeedback = new BoolFeedback(OnFeedbackFunc);
IsWarmingUpFeedback = new BoolFeedback(IsWarmingFeedbackFunc);
IsCoolingDownFeedback = new BoolFeedback(IsCoolingFeedbackFunc);
AddPostActivationAction(() =>
{
if (RoomOccupancy != null)
{
OnRoomOccupancyIsSet();
}
});
}
public IRoutingSinkWithSwitching DefaultDisplay { get; protected set; }
public IRoutingSink DefaultAudioDevice { get; protected set; }
public IBasicVolumeControls DefaultVolumeControls { get; protected set; }
public string DefaultSourceItem { get; set; }
public ushort DefaultVolume { get; set; }
/// <summary>
/// Sets the volume control device, and attaches/removes InUseTrackers with "audio"
/// tag to device.
/// </summary>
public IBasicVolumeControls CurrentVolumeControls
{
get { return CurrentAudioDevice; }
set
{
if (value == CurrentAudioDevice)
{
return;
}
var handler = CurrentVolumeDeviceChange;
if (handler != null)
{
handler(this,
new VolumeDeviceChangeEventArgs(CurrentAudioDevice, value, ChangeType.WillChange));
}
var oldDevice = CurrentAudioDevice as IInUseTracking;
var newDevice = value as IInUseTracking;
UpdateInUseTracking(oldDevice, newDevice);
CurrentAudioDevice = value;
if (handler == null)
{
return;
}
handler(this,
new VolumeDeviceChangeEventArgs(CurrentAudioDevice, value, ChangeType.DidChange));
}
}
public bool ExcludeFromGlobalFunctions { get; set; }
public BoolFeedback OnFeedback { get; private set; }
public BoolFeedback IsWarmingUpFeedback { get; private set; }
public BoolFeedback IsCoolingDownFeedback { get; private set; }
public IOccupancyStatusProvider RoomOccupancy { get; private set; }
public bool OccupancyStatusProviderIsRemote { get; private set; }
/// <summary>
/// The config name of the source list
/// </summary>
public string SourceListKey { get; set; }
/// <summary>
/// Timer used for informing the UIs of a shutdown
/// </summary>
public SecondsCountdownTimer ShutdownPromptTimer { get; private set; }
public int ShutdownPromptSeconds { get; set; }
public int ShutdownVacancySeconds { get; set; }
public eShutdownType ShutdownType { get; private set; }
public EssentialsRoomEmergencyBase Emergency { get; set; }
public Privacy.MicrophonePrivacyController MicrophonePrivacy { get; set; }
public string LogoUrl { get; set; }
protected SecondsCountdownTimer RoomVacancyShutdownTimer { get; private set; }
public eVacancyMode VacancyMode { get; private set; }
/// <summary>
/// When volume control devices change, should we zero the one that we are leaving?
/// </summary>
public bool ZeroVolumeWhenSwtichingVolumeDevices { get; private set; }
#region IHasCurrentSourceInfoChange Members
public event SourceInfoChangeHandler CurrentSourceChange;
public string CurrentSourceInfoKey { get; set; }
/// <summary>
/// The SourceListItem last run - containing names and icons
/// </summary>
public SourceListItem CurrentSourceInfo
{
get { return _currentSourceInfo; }
set
{
if (value == _currentSourceInfo)
{
return;
}
var handler = CurrentSourceChange;
if (handler != null)
{
handler(_currentSourceInfo, ChangeType.WillChange);
}
var oldSource = _currentSourceInfo as IInUseTracking;
var newSource = value as IInUseTracking;
UpdateInUseTracking(oldSource, newSource);
_currentSourceInfo = value;
if (handler == null)
{
return;
}
handler(_currentSourceInfo, ChangeType.DidChange);
}
}
#endregion
public event EventHandler<VolumeDeviceChangeEventArgs> CurrentVolumeDeviceChange;
/// <summary>
/// Fires when the RoomOccupancy object is set
/// </summary>
public event EventHandler<EventArgs> RoomOccupancyIsSet;
private void SetupRoomVacancyShutdown()
{
RoomVacancyShutdownTimer = new SecondsCountdownTimer(Key + "-vacancyOffTimer");
RoomVacancyShutdownTimer.HasFinished += RoomVacancyShutdownPromptTimer_HasFinished; // Shutdown is triggered
RoomVacancyShutdownPromptSeconds = 1500; // 25 min to prompt warning
RoomVacancyShutdownSeconds = 240; // 4 min after prompt will trigger shutdown prompt
VacancyMode = eVacancyMode.None;
}
/// <summary>
/// If mobile control is enabled, sets the appropriate properties
/// </summary>
void SetUpMobileControl()
{
var mcBridgeKey = string.Format("mobileControlBridge-{0}", Key);
var mcBridge = DeviceManager.GetDeviceForKey(mcBridgeKey);
if (mcBridge == null)
{
Debug.Console(1, this, "*********************Mobile Control Bridge Not found for this room.");
IsMobileControlEnabled = false;
return;
}
else
{
MobileControlRoomBridge = mcBridge as IMobileControlRoomBridge;
Debug.Console(1, this, "*********************Mobile Control Bridge found and enabled for this room");
IsMobileControlEnabled = true;
}
}
private void SetupShutdownPrompt()
{
// Setup the ShutdownPromptTimer
ShutdownPromptTimer = new SecondsCountdownTimer(Key + "-offTimer");
ShutdownPromptTimer.IsRunningFeedback.OutputChange += (o, a) =>
{
if (!ShutdownPromptTimer.IsRunningFeedback.BoolValue)
{
ShutdownType = eShutdownType.None;
}
};
ShutdownPromptTimer.HasFinished += (o, a) => Shutdown(); // Shutdown is triggered
ShutdownPromptSeconds = 60;
ShutdownVacancySeconds = 120;
ShutdownType = eShutdownType.None;
}
protected void InitializeDisplay(TwoWayDisplayBase display)
{
// Link power, warming, cooling to display
display.PowerIsOnFeedback.OutputChange += PowerIsOnFeedbackOnOutputChange;
display.IsWarmingUpFeedback.OutputChange += IsWarmingUpFeedbackOnOutputChange;
display.IsCoolingDownFeedback.OutputChange += IsCoolingDownFeedbackOnOutputChange;
}
protected void UpdateInUseTracking(IInUseTracking oldDev, IInUseTracking newDev)
{
// derigister this room from the device, if it can
if (oldDev != null)
{
oldDev.InUseTracker.RemoveUser(this, "audio");
}
// register this room with new device, if it can
if (newDev != null)
{
newDev.InUseTracker.AddUser(this, "audio");
}
}
protected abstract void PowerIsOnFeedbackOnOutputChange(object sender, FeedbackEventArgs args);
protected abstract void IsWarmingUpFeedbackOnOutputChange(object sender, FeedbackEventArgs args);
protected abstract void IsCoolingDownFeedbackOnOutputChange(object sender, FeedbackEventArgs args);
private void RoomVacancyShutdownPromptTimer_HasFinished(object sender, EventArgs e)
{
switch (VacancyMode)
{
case eVacancyMode.None:
StartRoomVacancyTimer(eVacancyMode.InInitialVacancy);
break;
case eVacancyMode.InInitialVacancy:
StartRoomVacancyTimer(eVacancyMode.InShutdownWarning);
break;
case eVacancyMode.InShutdownWarning:
{
StartShutdown(eShutdownType.Vacancy);
Debug.Console(0, this, Debug.ErrorLogLevel.Notice, "Shutting Down due to vacancy.");
break;
}
}
}
/// <summary>
///
/// </summary>
/// <param name="type"></param>
public void StartShutdown(eShutdownType type)
{
// Check for shutdowns running. Manual should override other shutdowns
switch (type)
{
case eShutdownType.Manual:
ShutdownPromptTimer.SecondsToCount = ShutdownPromptSeconds;
break;
case eShutdownType.Vacancy:
ShutdownPromptTimer.SecondsToCount = ShutdownVacancySeconds;
break;
}
ShutdownType = type;
ShutdownPromptTimer.Start();
Debug.Console(0, this, Debug.ErrorLogLevel.Notice, "ShutdownPromptTimer Started. Type: {0}. Seconds: {1}",
ShutdownType, ShutdownPromptTimer.SecondsToCount);
}
public void StartRoomVacancyTimer(eVacancyMode mode)
{
switch (mode)
{
case eVacancyMode.None:
RoomVacancyShutdownTimer.SecondsToCount = RoomVacancyShutdownPromptSeconds;
break;
case eVacancyMode.InInitialVacancy:
RoomVacancyShutdownTimer.SecondsToCount = RoomVacancyShutdownSeconds;
break;
case eVacancyMode.InShutdownWarning:
RoomVacancyShutdownTimer.SecondsToCount = 60;
break;
}
VacancyMode = mode;
RoomVacancyShutdownTimer.Start();
Debug.Console(0, this, Debug.ErrorLogLevel.Notice, "Vacancy Timer Started. Mode: {0}. Seconds: {1}",
VacancyMode, RoomVacancyShutdownTimer.SecondsToCount);
}
/// <summary>
/// Resets the vacancy mode and shutsdwon the room
/// </summary>
public void Shutdown()
{
VacancyMode = eVacancyMode.None;
EndShutdown();
}
/// <summary>
/// This method is for the derived class to define it's specific shutdown
/// requirements but should not be called directly. It is called by Shutdown()
/// </summary>
protected virtual void EndShutdown()
{
SetDefaultLevels();
RunDefaultPresentRoute();
//CrestronEnvironment.Sleep(1000); //why?
Debug.Console(0, this, Debug.ErrorLogLevel.Notice, "Shutting down room");
RunRouteAction("roomOff");
}
/// <summary>
/// Override this to implement a default volume level(s) method
/// </summary>
public virtual void SetDefaultLevels()
{
Debug.Console(1, this, "Restoring default levels");
var vc = CurrentVolumeControls as IBasicVolumeWithFeedback;
if (vc != null)
{
vc.SetVolume(DefaultVolume);
}
}
/// <summary>
/// Sets the object to be used as the IOccupancyStatusProvider for the room. Can be an Occupancy Aggregator or a specific device
/// </summary>
/// <param name="statusProvider"></param>
/// <param name="timeoutMinutes"></param>
public void SetRoomOccupancy(IOccupancyStatusProvider statusProvider, int timeoutMinutes)
{
var provider = statusProvider as IKeyed;
if (provider == null)
{
Debug.Console(0, this, "ERROR: Occupancy sensor device is null");
return;
}
Debug.Console(0, this, Debug.ErrorLogLevel.Notice, "Room Occupancy set to device: '{0}'", provider.Key);
Debug.Console(0, this, Debug.ErrorLogLevel.Notice, "Timeout Minutes from Config is: {0}", timeoutMinutes);
// If status provider is fusion, set flag to remote
if (statusProvider is Fusion.EssentialsHuddleSpaceFusionSystemControllerBase)
{
OccupancyStatusProviderIsRemote = true;
}
if (timeoutMinutes > 0)
{
RoomVacancyShutdownSeconds = timeoutMinutes*60;
}
Debug.Console(0, this, Debug.ErrorLogLevel.Notice, "RoomVacancyShutdownSeconds set to {0}",
RoomVacancyShutdownSeconds);
RoomOccupancy = statusProvider;
RoomOccupancy.RoomIsOccupiedFeedback.OutputChange -= RoomIsOccupiedFeedback_OutputChange;
RoomOccupancy.RoomIsOccupiedFeedback.OutputChange += RoomIsOccupiedFeedback_OutputChange;
OnRoomOccupancyIsSet();
}
private void OnRoomOccupancyIsSet()
{
var handler = RoomOccupancyIsSet;
if (handler != null)
{
handler(this, new EventArgs());
}
}
/// <summary>
/// To allow base class to power room on to last source
/// </summary>
public virtual void PowerOnToDefaultOrLastSource()
{
if (!EnablePowerOnToLastSource || LastSourceKey == null)
{
return;
}
RunRouteAction(LastSourceKey);
}
/// <summary>
/// To allow base class to power room on to default source
/// </summary>
/// <returns></returns>
public virtual bool RunDefaultPresentRoute()
{
if (DefaultSourceItem == null)
{
Debug.Console(0, this, "Unable to run default present route, DefaultSourceItem is null.");
return false;
}
RunRouteAction(DefaultSourceItem);
return true;
}
private void RoomIsOccupiedFeedback_OutputChange(object sender, EventArgs e)
{
if (RoomOccupancy.RoomIsOccupiedFeedback.BoolValue == false)
{
Debug.Console(1, this, Debug.ErrorLogLevel.Notice, "Notice: Vacancy Detected");
// Trigger the timer when the room is vacant
StartRoomVacancyTimer(eVacancyMode.InInitialVacancy);
}
else
{
Debug.Console(1, this, Debug.ErrorLogLevel.Notice, "Notice: Occupancy Detected");
// Reset the timer when the room is occupied
RoomVacancyShutdownTimer.Cancel();
}
}
/// <summary>
/// Executes when RoomVacancyShutdownTimer expires. Used to trigger specific room actions as needed. Must nullify the timer object when executed
/// </summary>
/// <param name="o"></param>
public abstract void RoomVacatedForTimeoutPeriod(object o);
/// <summary>
///
/// </summary>
/// <param name="routeKey"></param>
public virtual void RunRouteAction(string routeKey)
{
RunRouteAction(routeKey, String.Empty, () => { });
}
/// <summary>
/// Gets a source from config list SourceListKey and dynamically build and executes the
/// route or commands
/// </summary>
public virtual void RunRouteAction(string routeKey, Action successCallback)
{
RunRouteAction(routeKey, String.Empty, successCallback);
}
/// <summary>
///
/// </summary>
/// <param name="routeKey"></param>
/// <param name="sourceListKey"></param>
public virtual void RunRouteAction(string routeKey, string sourceListKey)
{
RunRouteAction(routeKey, sourceListKey, () => { });
}
/// <summary>
///
/// </summary>
/// <param name="routeKey"></param>
/// <param name="sourceListKey"></param>
/// <param name="successCallback"></param>
public virtual void RunRouteAction(string routeKey, string sourceListKey, Action successCallback)
{
var routeObject =
new {RouteKey = routeKey, SourceListKey = sourceListKey, SuccessCallback = successCallback};
CrestronInvoke.BeginInvoke(RunRouteAction, routeObject); // end of BeginInvoke
}
protected virtual void RunRouteAction(object routeObject)
{
try
{
RoutingLock.Enter();
var routeObj = new {RouteKey = "", SourceListKey = "", SuccessCallback = new Action(() => { })};
routeObj = Cast(routeObj, routeObject);
Debug.Console(0, this, Debug.ErrorLogLevel.Notice, "Run route action '{0}'", routeObj.RouteKey);
var sourceList = GetSourceListForKey(routeObj.RouteKey, routeObj.SourceListKey);
if (sourceList == null)
{
Debug.Console(0, this, "No source list found for key {0}", routeObj.SourceListKey);
return;
}
var item = sourceList[routeObj.RouteKey];
// End usage timer on last source
StopUsageTrackingOnCurrentSource(sourceList);
// Let's run it
if (routeObj.RouteKey.ToLower() != "roomoff")
{
LastSourceKey = routeObj.RouteKey;
}
else
{
CurrentSourceInfoKey = null;
}
foreach (var route in item.RouteList)
{
var tempVideo = new SourceRouteListItem
{
DestinationKey = "$defaultDisplay",
SourceKey = route.SourceKey,
Type = eRoutingSignalType.Video
};
var routeItem = route.DestinationKey.Equals("$defaultAll", StringComparison.OrdinalIgnoreCase)
? tempVideo
: route;
DoRoute(routeItem);
}
// Start usage timer on routed source
if (item.SourceDevice is IUsageTracking)
{
(item.SourceDevice as IUsageTracking).UsageTracker.StartDeviceUsage();
}
// Set volume control, using default if non provided
SetVolumeControl(item);
// store the name and UI info for routes
if (item.SourceKey == "$off")
{
CurrentSourceInfoKey = routeObj.RouteKey;
CurrentSourceInfo = null;
}
else if (item.SourceKey != null)
{
CurrentSourceInfoKey = routeObj.RouteKey;
CurrentSourceInfo = item;
}
OnFeedback.FireUpdate();
// report back when done
if (routeObj.SuccessCallback != null)
{
routeObj.SuccessCallback();
}
}
finally
{
RoutingLock.Leave();
}
}
private static T Cast<T>(T typeHolder, object m)
{
return (T) m;
}
/// <summary>
///
/// </summary>
/// <param name="route"></param>
/// <returns></returns>
protected void DoRoute(SourceRouteListItem route)
{
var dest = GetDestination(route);
if (route.SourceKey.Equals("$off", StringComparison.OrdinalIgnoreCase))
{
dest.ReleaseRoute();
if (dest is IHasPowerControl)
{
(dest as IHasPowerControl).PowerOff();
}
}
else
{
var source = DeviceManager.GetDeviceForKey(route.SourceKey) as IRoutingOutputs;
if (source == null)
{
Debug.Console(1, this, "Cannot route unknown source '{0}' to {1}", route.SourceKey,
route.DestinationKey);
return;
}
dest.ReleaseAndMakeRoute(source, route.Type);
}
}
private IRoutingSink GetDestination(SourceRouteListItem route)
{
IRoutingSink dest;
if (route.DestinationKey.Equals("$defaultaudio", StringComparison.OrdinalIgnoreCase))
{
dest = DefaultAudioDevice;
}
else if (route.DestinationKey.Equals("$defaultDisplay", StringComparison.OrdinalIgnoreCase))
{
dest = DefaultDisplay;
}
else
{
dest = DeviceManager.GetDeviceForKey(route.DestinationKey) as IRoutingSink;
}
if (dest != null)
{
return dest;
}
Debug.Console(1, this, "Cannot route, unknown destination '{0}'", route.DestinationKey);
return dest;
}
private void SetVolumeControl(SourceListItem item)
{
IBasicVolumeControls volDev = null;
// Handle special cases for volume control
if (string.IsNullOrEmpty(item.VolumeControlKey)
|| item.VolumeControlKey.Equals("$defaultAudio", StringComparison.OrdinalIgnoreCase))
{
volDev = DefaultVolumeControls;
}
else if (item.VolumeControlKey.Equals("$defaultDisplay", StringComparison.OrdinalIgnoreCase))
{
volDev = DefaultDisplay as IBasicVolumeControls;
}
else
{
var dev = DeviceManager.GetDeviceForKey(item.VolumeControlKey);
if (dev is IBasicVolumeControls)
{
volDev = dev as IBasicVolumeControls;
}
else if (dev is IHasVolumeDevice)
{
volDev = (dev as IHasVolumeDevice).VolumeDevice;
}
}
if (volDev == CurrentVolumeControls)
{
return;
}
IBasicVolumeWithFeedback vd;
// zero the volume on the device we are leaving.
// Set the volume to default on device we are entering
if (ZeroVolumeWhenSwtichingVolumeDevices && CurrentVolumeControls is IBasicVolumeWithFeedback)
{
vd = CurrentVolumeControls as IBasicVolumeWithFeedback;
SavedVolumeLevels[vd] = (uint) vd.VolumeLevelFeedback.IntValue;
vd.SetVolume(0);
}
CurrentVolumeControls = volDev;
if (!ZeroVolumeWhenSwtichingVolumeDevices || !(CurrentVolumeControls is IBasicVolumeWithFeedback))
{
return;
}
vd = CurrentVolumeControls as IBasicVolumeWithFeedback;
var vol = (SavedVolumeLevels.ContainsKey(vd) ? (ushort) SavedVolumeLevels[vd] : DefaultVolume);
vd.SetVolume(vol);
}
private void StopUsageTrackingOnCurrentSource(Dictionary<string, SourceListItem> sourceList)
{
if (string.IsNullOrEmpty(LastSourceKey))
{
return;
}
var lastSource = sourceList[LastSourceKey].SourceDevice;
try
{
if (lastSource is IUsageTracking)
{
(lastSource as IUsageTracking).UsageTracker.EndDeviceUsage();
}
}
catch (Exception e)
{
Debug.Console(1, this, "*#* EXCEPTION in end usage tracking (257):\r{0}", e);
}
}
private Dictionary<string, SourceListItem> GetSourceListForKey(string routeKey, string sourceListKey)
{
var slKey = String.IsNullOrEmpty(sourceListKey) ? SourceListKey : sourceListKey;
var sourceList = ConfigReader.ConfigObject.GetSourceListForKey(slKey);
if (sourceList == null)
{
Debug.Console(1, this, "WARNING: Config source list '{0}' not found", slKey);
return null;
}
// Try to get the list item by it's string key
if (sourceList.ContainsKey(routeKey))
{
return sourceList;
}
Debug.Console(1, this, "WARNING: No source list '{0}' found in config source lists '{1}'",
routeKey, SourceListKey);
return null;
}
/// <summary>
/// Runs "roomOff" action on all rooms not set to ExcludeFromGlobalFunctions
/// </summary>
public static void AllRoomsOff()
{
var allRooms = DeviceManager.AllDevices.OfType<EssentialsRoomBase>().Where(d =>
!d.ExcludeFromGlobalFunctions);
foreach (var room in allRooms)
{
room.RunRouteAction("roomOff");
}
}
}
/// <summary>
/// To describe the various ways a room may be shutting down
/// </summary>
public enum eShutdownType
{
None = 0,
External,
Manual,
Vacancy
}
public enum eVacancyMode
{
None = 0,
InInitialVacancy,
InShutdownWarning
}
/// <summary>
///
/// </summary>
public enum eWarmingCoolingMode
{
None,
Warming,
Cooling
}
public abstract class EssentialsRoomEmergencyBase : IKeyed
{
protected EssentialsRoomEmergencyBase(string key)
{
Key = key;
}
#region IKeyed Members
public string Key { get; private set; }
#endregion
}
}

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

@@ -0,0 +1,318 @@
using System;
using System.Collections.Generic;
using System.Linq;
using PepperDash.Core;
using PepperDash.Essentials.Core;
using PepperDash.Essentials.Core.Config;
using PepperDash.Essentials.Core.Devices.AudioCodec;
using PepperDash.Essentials.Core.Devices.VideoCodec;
using PepperDash.Essentials.Core.Rooms;
using PepperDash.Essentials.Core.Rooms.Config;
using PepperDash.Essentials.Core.Devices;
using PepperDash.Essentials.Devices.Common.VideoCodec;
namespace PepperDash.Essentials
{
public class EssentialsDualDisplayRoom : EssentialsRoomBase, IHasCurrentSourceInfoChange,
IPrivacy, IHasCurrentVolumeControls, IRunRouteAction, IRunDefaultCallRoute, IHasVideoCodec, IHasAudioCodec,
IHasDefaultDisplay, IHasInCallFeedback
{
public const string DefaultDestinationListKey = "default";
private const string LeftDestinationKey = "leftDisplay";
private const string RightDestinationKey = "rightDisplay";
/// <summary>
/// "codecOsd"
/// </summary>
public const string DefaultCodecRouteString = "codecOsd";
private readonly EssentialsDualDisplayRoomPropertiesConfig _config;
private string _destinationListKey;
public EssentialsDualDisplayRoom(DeviceConfig config) : base(config)
{
_config = config.Properties.ToObject<EssentialsDualDisplayRoomPropertiesConfig>();
DefaultDisplay = DeviceManager.GetDeviceForKey(_config.DefaultDisplayKey) as IRoutingSinkWithSwitching;
DefaultAudioDevice = DeviceManager.GetDeviceForKey(_config.DefaultAudioKey) as IRoutingSinkWithSwitching;
VideoCodec = DeviceManager.GetDeviceForKey(_config.VideoCodecKey) as VideoCodecBase;
if (VideoCodec == null)
{
throw new ArgumentNullException("codec cannot be null");
}
AudioCodec = DeviceManager.GetDeviceForKey(_config.AudioCodecKey) as AudioCodecBase;
if (AudioCodec == null)
{
Debug.Console(0, this, "No audio codec found");
}
Initialize();
}
public Dictionary<string, DestinationListItem> DestinationList { get; private set; }
public BoolFeedback LeftDisplayIsWarmingUpFeedback { get; private set; }
public BoolFeedback RightDisplayIsWarmingUpFeedback { get; private set; }
public BoolFeedback LeftDisplayIsCoolingDownFeedback { get; private set; }
public BoolFeedback RightDisplayIsCoolingDownFeedback { get; private set; }
public IRoutingSinkWithSwitching LeftDisplay { get; private set; }
public IRoutingSinkWithSwitching RightDisplay { get; private set; }
#region IHasAudioCodec Members
public AudioCodecBase AudioCodec { get; private set; }
#endregion
#region IHasVideoCodec Members
public BoolFeedback InCallFeedback { get; private set; }
public IntFeedback CallTypeFeedback { get; private set; }
public BoolFeedback IsSharingFeedback { get; private set; }
public VideoCodecBase VideoCodec { get; private set; }
#endregion
#region IPrivacy Members
public BoolFeedback PrivacyModeIsOnFeedback { get; private set; }
public void PrivacyModeOff()
{
VideoCodec.PrivacyModeOff();
}
public void PrivacyModeOn()
{
VideoCodec.PrivacyModeOn();
}
public void PrivacyModeToggle()
{
VideoCodec.PrivacyModeToggle();
}
#endregion
#region IRunDefaultCallRoute Members
/// <summary>
/// Sets up the room when started into call mode without presenting a source
/// </summary>
/// <returns></returns>
public bool RunDefaultCallRoute()
{
RunRouteAction(DefaultCodecRouteString);
return true;
}
#endregion
private void Initialize()
{
try
{
if (DefaultAudioDevice is IBasicVolumeControls)
{
DefaultVolumeControls = DefaultAudioDevice as IBasicVolumeControls;
}
else if (DefaultAudioDevice is IHasVolumeDevice)
{
DefaultVolumeControls = (DefaultAudioDevice as IHasVolumeDevice).VolumeDevice;
}
CurrentVolumeControls = DefaultVolumeControls;
_destinationListKey = String.IsNullOrEmpty(_config.DestinationListKey)
? DefaultDestinationListKey
: _config.DestinationListKey;
SourceListKey = String.IsNullOrEmpty(_config.SourceListKey)
? DefaultSourceListKey
: _config.SourceListKey;
InitializeDestinations();
InCallFeedback = new BoolFeedback(() =>
{
var inAudioCall = AudioCodec != null && AudioCodec.IsInCall;
var inVideoCall = VideoCodec != null && VideoCodec.IsInCall;
return inAudioCall || inVideoCall;
});
MicrophonePrivacy = EssentialsRoomConfigHelper.GetMicrophonePrivacy(_config, this);
Emergency = EssentialsRoomConfigHelper.GetEmergency(_config, this);
VideoCodec.CallStatusChange += (o, a) => InCallFeedback.FireUpdate();
if (AudioCodec != null)
{
AudioCodec.CallStatusChange += (o, a) => InCallFeedback.FireUpdate();
}
IsSharingFeedback = new BoolFeedback(() => VideoCodec.SharingContentIsOnFeedback.BoolValue);
VideoCodec.SharingContentIsOnFeedback.OutputChange += (o, a) => IsSharingFeedback.FireUpdate();
PrivacyModeIsOnFeedback = new BoolFeedback(() => VideoCodec.PrivacyModeIsOnFeedback.BoolValue);
VideoCodec.PrivacyModeIsOnFeedback.OutputChange += (o, a) => PrivacyModeIsOnFeedback.FireUpdate();
CallTypeFeedback = new IntFeedback(() => 0);
}
catch (Exception e)
{
Debug.Console(0, this, "Error Initializing Room: {0}", e);
}
}
private void InitializeDestinations()
{
DestinationList = ConfigReader.ConfigObject.GetDestinationListForKey(_destinationListKey);
if (DestinationList == null)
{
Debug.Console(0, Debug.ErrorLogLevel.Error, "No destination list with key {0} found",
_destinationListKey);
return;
}
//left destination is defined as the display on the 0 surface, at location 0,0 (h, v)
var leftDest = GetDestinationForKey(LeftDestinationKey);
//not found by key, check by expected location
if (leftDest == null)
{
DestinationList.Values.FirstOrDefault(
li => li.SurfaceLocation == 0 && li.HorizontalLocation == 0 && li.VerticalLocation == 0);
}
//right destination is defined as the display on the 0 surface, at location 0,0 (h, v)
var rightDest = GetDestinationForKey(RightDestinationKey);
//not found by key, check by expected location
if (rightDest == null)
{
DestinationList.Values.FirstOrDefault(
li => li.SurfaceLocation == 0 && li.HorizontalLocation == 1 && li.VerticalLocation == 0);
}
if (leftDest == null || rightDest == null)
{
Debug.Console(0, Debug.ErrorLogLevel.Error, "Dual destinations not defined. Please check configuration");
return;
}
var leftDisplay = leftDest.SinkDevice as TwoWayDisplayBase;
var rightDisplay = rightDest.SinkDevice as TwoWayDisplayBase;
if (leftDisplay == null || rightDisplay == null)
{
Debug.Console(0, Debug.ErrorLogLevel.Error,
"Display for key {0} && key {1} not found. Please check configurattion");
Debug.Console(0, Debug.ErrorLogLevel.Error, "LeftDisplay: {0}\r\nRightDisplay: {1}", leftDest.SinkKey,
rightDest.SinkKey);
return;
}
//need displays as DisplayBase later instead of IRoutingSinkWithSwtich
LeftDisplay = leftDisplay;
RightDisplay = rightDisplay;
//TODO: Check this definition for on for dual display rooms
OnFeedbackFunc = () => CurrentSourceInfo != null && CurrentSourceInfo.Type == eSourceListItemType.Route;
IsWarmingFeedbackFunc =
() => leftDisplay.IsWarmingUpFeedback.BoolValue || rightDisplay.IsWarmingUpFeedback.BoolValue;
IsCoolingFeedbackFunc = () => leftDisplay.IsWarmingUpFeedback.BoolValue ||
rightDisplay.IsCoolingDownFeedback.BoolValue;
LeftDisplayIsWarmingUpFeedback = new BoolFeedback(() => leftDisplay.IsWarmingUpFeedback.BoolValue);
LeftDisplayIsCoolingDownFeedback = new BoolFeedback(() => leftDisplay.IsCoolingDownFeedback.BoolValue);
RightDisplayIsWarmingUpFeedback = new BoolFeedback(() => rightDisplay.IsWarmingUpFeedback.BoolValue);
RightDisplayIsCoolingDownFeedback = new BoolFeedback(() => rightDisplay.IsCoolingDownFeedback.BoolValue);
InitializeDisplay(leftDisplay);
InitializeDisplay(rightDisplay);
}
private DestinationListItem GetDestinationForKey(string key)
{
DestinationListItem returnValue;
DestinationList.TryGetValue(key, out returnValue);
return returnValue;
}
protected override void IsCoolingDownFeedbackOnOutputChange(object sender, FeedbackEventArgs args)
{
IsCoolingDownFeedback.FireUpdate();
LeftDisplayIsCoolingDownFeedback.FireUpdate();
RightDisplayIsCoolingDownFeedback.FireUpdate();
}
public override void RoomVacatedForTimeoutPeriod(object o)
{
throw new NotImplementedException();
}
protected override void IsWarmingUpFeedbackOnOutputChange(object sender, FeedbackEventArgs args)
{
IsWarmingUpFeedback.FireUpdate();
LeftDisplayIsWarmingUpFeedback.FireUpdate();
RightDisplayIsWarmingUpFeedback.FireUpdate();
}
protected override void PowerIsOnFeedbackOnOutputChange(object sender, FeedbackEventArgs args)
{
var ld = LeftDisplay as TwoWayDisplayBase;
var rd = RightDisplay as TwoWayDisplayBase;
if (ld == null || rd == null)
{
return;
}
//if room is already on and either display is still on, no need to fire update
if (OnFeedback.BoolValue && (ld.PowerIsOnFeedback.BoolValue || rd.PowerIsOnFeedback.BoolValue))
{
return;
}
//if both displays are off, room is off, clear the current source
if (!ld.PowerIsOnFeedback.BoolValue && !rd.PowerIsOnFeedback.BoolValue)
{
CurrentSourceInfo = null;
}
OnFeedback.FireUpdate();
}
public void RouteAction(string sourceKey, string destinationKey)
{
var routeItem = new SourceRouteListItem
{
DestinationKey = destinationKey,
SourceKey = sourceKey,
Type = eRoutingSignalType.AudioVideo
};
DoRoute(routeItem);
}
}
}

View File

@@ -0,0 +1,153 @@
using System;
using Newtonsoft.Json;
using PepperDash.Core;
using PepperDash.Essentials.Core;
using PepperDash.Essentials.Core.Config;
using PepperDash.Essentials.Core.Rooms;
using PepperDash.Essentials.Core.Rooms.Config;
namespace PepperDash.Essentials
{
public class EssentialsHuddleSpaceRoom : EssentialsRoomBase, IRunRouteAction,
IRunDefaultPresentRoute, IHasCurrentVolumeControls, IHasDefaultDisplay, IHasCurrentSourceInfoChange
{
public EssentialsHuddleSpaceRoom(DeviceConfig config)
: base(config)
{
try
{
PropertiesConfig = config.Properties.ToObject<EssentialsHuddleRoomPropertiesConfig>();
DefaultDisplay =
DeviceManager.GetDeviceForKey(PropertiesConfig.DefaultDisplayKey) as IRoutingSinkWithSwitching;
//why are we assuming IRoutingSinkWithSwitching here?
DefaultAudioDevice =
DeviceManager.GetDeviceForKey(PropertiesConfig.DefaultAudioKey) as IRoutingSinkWithSwitching;
Initialize();
}
catch (Exception e)
{
Debug.Console(1, this, "Error building room: \n{0}", e);
}
}
public EssentialsHuddleRoomPropertiesConfig PropertiesConfig { get; private set; }
private void Initialize()
{
if (DefaultAudioDevice is IBasicVolumeControls)
{
DefaultVolumeControls = DefaultAudioDevice as IBasicVolumeControls;
}
else if (DefaultAudioDevice is IHasVolumeDevice)
{
DefaultVolumeControls = (DefaultAudioDevice as IHasVolumeDevice).VolumeDevice;
}
CurrentVolumeControls = DefaultVolumeControls;
SourceListKey = String.IsNullOrEmpty(PropertiesConfig.SourceListKey)
? DefaultSourceListKey
: PropertiesConfig.SourceListKey;
EnablePowerOnToLastSource = true;
var disp = DefaultDisplay as TwoWayDisplayBase;
if (disp == null)
{
return;
}
IsWarmingFeedbackFunc = () => disp.IsWarmingUpFeedback.BoolValue;
IsCoolingFeedbackFunc = () => disp.IsCoolingDownFeedback.BoolValue;
OnFeedbackFunc = () => CurrentSourceInfo != null
&& CurrentSourceInfo.Type == eSourceListItemType.Route;
InitializeDisplay(disp);
}
protected override void IsCoolingDownFeedbackOnOutputChange(object sender, FeedbackEventArgs feedbackEventArgs)
{
IsCoolingDownFeedback.FireUpdate();
}
protected override void PowerIsOnFeedbackOnOutputChange(object sender, FeedbackEventArgs feedbackEventArgs)
{
var display = sender as TwoWayDisplayBase;
if (display == null)
{
return;
}
if (display.PowerIsOnFeedback.BoolValue == OnFeedback.BoolValue)
{
return;
}
if (!display.PowerIsOnFeedback.BoolValue)
{
CurrentSourceInfo = null;
}
OnFeedback.FireUpdate();
}
protected override void IsWarmingUpFeedbackOnOutputChange(object sender, FeedbackEventArgs feedbackEventArgs)
{
IsWarmingUpFeedback.FireUpdate();
if (IsWarmingUpFeedback.BoolValue)
{
return;
}
var displayVolumeControl = DefaultDisplay as IBasicVolumeWithFeedback;
if (displayVolumeControl == null)
{
Debug.Console(0, this, Debug.ErrorLogLevel.Error,
"Default display {0} is not volume control control provider", DefaultDisplay.Key);
return;
}
displayVolumeControl.SetVolume(DefaultVolume);
}
protected override void CustomSetConfig(DeviceConfig config)
{
var newPropertiesConfig =
JsonConvert.DeserializeObject<EssentialsHuddleRoomPropertiesConfig>(config.Properties.ToString());
if (newPropertiesConfig != null)
{
PropertiesConfig = newPropertiesConfig;
}
ConfigWriter.UpdateRoomConfig(config);
}
public override bool CustomActivate()
{
// Add Occupancy object from config
if (PropertiesConfig.Occupancy != null)
{
SetRoomOccupancy(DeviceManager.GetDeviceForKey(PropertiesConfig.Occupancy.DeviceKey) as
IOccupancyStatusProvider, PropertiesConfig.Occupancy.TimeoutMinutes);
}
LogoUrl = PropertiesConfig.Logo.GetUrl();
SourceListKey = PropertiesConfig.SourceListKey;
DefaultSourceItem = PropertiesConfig.DefaultSourceItem;
DefaultVolume = (ushort) (PropertiesConfig.Volumes.Master.Level*65535/100);
return base.CustomActivate();
}
public override void RoomVacatedForTimeoutPeriod(object o)
{
//TODO: Implement RoomVacatedForTimeoutPeriod
}
}
}

Some files were not shown because too many files have changed in this diff Show More