diff --git a/PepperDashEssentials/Room/Config/EssentialsRoomConfig.cs b/PepperDashEssentials/Room/Config/EssentialsRoomConfig.cs
index a6233f6d..7077d9c2 100644
--- a/PepperDashEssentials/Room/Config/EssentialsRoomConfig.cs
+++ b/PepperDashEssentials/Room/Config/EssentialsRoomConfig.cs
@@ -66,7 +66,7 @@ namespace PepperDash.Essentials.Room.Config
///
///
public static Core.Privacy.MicrophonePrivacyController GetMicrophonePrivacy(
- EssentialsRoomPropertiesConfig props, EssentialsHuddleVtc1Room room)
+ EssentialsRoomPropertiesConfig props, IPrivacy room)
{
var microphonePrivacy = props.MicrophonePrivacy;
if (microphonePrivacy == null)
@@ -95,28 +95,30 @@ namespace PepperDash.Essentials.Room.Config
if (behaviour == "trackroomstate")
{
// Tie LED enable to room power state
- room.OnFeedback.OutputChange += (o, a) =>
+ var essRoom = room as EssentialsRoomBase;
+ essRoom.OnFeedback.OutputChange += (o, a) =>
{
- if (room.OnFeedback.BoolValue)
+ if (essRoom.OnFeedback.BoolValue)
mP.EnableLeds = true;
else
mP.EnableLeds = false;
};
- mP.EnableLeds = room.OnFeedback.BoolValue;
+ mP.EnableLeds = essRoom.OnFeedback.BoolValue;
}
else if (behaviour == "trackcallstate")
{
// Tie LED enable to room power state
- room.InCallFeedback.OutputChange += (o, a) =>
+ var inCallRoom = room as IHasInCallFeedback;
+ inCallRoom.InCallFeedback.OutputChange += (o, a) =>
{
- if (room.InCallFeedback.BoolValue)
+ if (inCallRoom.InCallFeedback.BoolValue)
mP.EnableLeds = true;
else
mP.EnableLeds = false;
};
- mP.EnableLeds = room.InCallFeedback.BoolValue;
+ mP.EnableLeds = inCallRoom.InCallFeedback.BoolValue;
}
return mP;
diff --git a/PepperDashEssentials/Room/Types/EssentialsDualDisplayRoom.cs b/PepperDashEssentials/Room/Types/EssentialsDualDisplayRoom.cs
index 4978744b..8477682b 100644
--- a/PepperDashEssentials/Room/Types/EssentialsDualDisplayRoom.cs
+++ b/PepperDashEssentials/Room/Types/EssentialsDualDisplayRoom.cs
@@ -1,68 +1,636 @@
-//using System;
-//using System.Collections.Generic;
-//using System.Linq;
-//using System.Text;
-//using Crestron.SimplSharp;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using Crestron.SimplSharp;
-//using Newtonsoft.Json;
+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;
-//using PepperDash.Essentials.Devices.Common.VideoCodec;
-//using PepperDash.Essentials.Devices.Common.AudioCodec;
+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;
+using PepperDash.Essentials.Devices.Common.VideoCodec;
+using PepperDash.Essentials.Devices.Common.AudioCodec;
-//namespace PepperDash.Essentials.Room.Types
-//{
-// public class EssentialsDualDisplayRoom : EssentialsNDisplayRoomBase, IHasCurrentVolumeControls,
-// IRunRouteAction, IPrivacy, IRunDefaultCallRoute, IHasVideoCodec, IHasAudioCodec
-// {
-// public event EventHandler CurrentVolumeDeviceChange;
+namespace PepperDash.Essentials.Room.Types
+{
+ public class EssentialsDualDisplayRoom : EssentialsNDisplayRoomBase, IHasCurrentVolumeControls,
+ IRunRouteAction, IPrivacy, IRunDefaultCallRoute, IHasVideoCodec, IHasAudioCodec, IHasInCallFeedback
+ {
+ public event EventHandler CurrentVolumeDeviceChange;
-// public EssentialsHuddleVtc1PropertiesConfig PropertiesConfig { get; private set; }
+ public EssentialsDualDisplayRoomPropertiesConfig PropertiesConfig { get; private set; }
-// //************************
-// // Call-related stuff
+ //************************
+ // Call-related stuff
-// public BoolFeedback InCallFeedback { get; private set; }
+ public BoolFeedback InCallFeedback { get; private set; }
-// ///
-// /// States: 0 for on hook, 1 for video, 2 for audio, 3 for telekenesis
-// ///
-// public IntFeedback CallTypeFeedback { get; private set; }
+ ///
+ /// States: 0 for on hook, 1 for video, 2 for audio, 3 for telekenesis
+ ///
+ public IntFeedback CallTypeFeedback { get; private set; }
-// ///
-// ///
-// ///
-// public BoolFeedback PrivacyModeIsOnFeedback { get; private set; }
+ ///
+ ///
+ ///
+ public BoolFeedback PrivacyModeIsOnFeedback { get; private set; }
-// ///
-// /// When something in the room is sharing with the far end or through other means
-// ///
-// public BoolFeedback IsSharingFeedback { get; private set; }
+ ///
+ /// When something in the room is sharing with the far end or through other means
+ ///
+ public BoolFeedback IsSharingFeedback { get; private set; }
-// IRoutingSinkWithSwitching LeftDisplay { get; private set; }
-// IRoutingSinkWithSwitching RightDisplay { get; private set; }
+ IRoutingSinkWithSwitching LeftDisplay { get; private set; }
+ IRoutingSinkWithSwitching RightDisplay { get; private set; }
-// protected override Func OnFeedbackFunc
-// {
-// get
-// {
-// return () =>
-// {
-// var leftDisp = LeftDisplay as DisplayBase;
-// var rightDisp = RightDisplay as DisplayBase;
-// var val = leftDisp != null && leftDisp.CurrentSourceInfo != null
-// && leftDisp.CurrentSourceInfo.Type == eSourceListItemType.Route
-// && rightDisp != null && rightDisp.CurrentSourceInfo != null
-// && rightDisp.CurrentSourceInfo.Type == eSourceListItemType.Route;
-// return val;
-// };
-// }
-// }
-// }
-//}
\ No newline at end of file
+ protected override Func OnFeedbackFunc
+ {
+ get
+ {
+ return () =>
+ {
+ var leftDisp = LeftDisplay as DisplayBase;
+ var rightDisp = RightDisplay as DisplayBase;
+ var val = leftDisp != null && leftDisp.CurrentSourceInfo != null
+ && leftDisp.CurrentSourceInfo.Type == eSourceListItemType.Route
+ && rightDisp != null && rightDisp.CurrentSourceInfo != null
+ && rightDisp.CurrentSourceInfo.Type == eSourceListItemType.Route;
+ return val;
+ };
+ }
+ }
+
+ ///
+ ///
+ ///
+ protected override Func IsWarmingFeedbackFunc
+ {
+ get
+ {
+ return () =>
+ {
+ 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;
+ };
+ }
+ }
+
+ ///
+ ///
+ ///
+ protected override Func IsCoolingFeedbackFunc
+ {
+ get
+ {
+ return () =>
+ {
+ 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;
+ };
+ }
+ }
+
+ public IBasicVolumeControls DefaultAudioDevice { get; private set; }
+ public IBasicVolumeControls DefaultVolumeControls { get; private set; }
+
+ public VideoCodecBase VideoCodec { get; private set; }
+
+ public AudioCodecBase AudioCodec { get; private set; }
+
+ public bool ExcludeFromGlobalFunctions { get; set; }
+
+ public string DefaultSourceItem { get; set; }
+
+ public ushort DefaultVolume { get; set; }
+
+ ///
+ /// If room is off, enables power on to last source. Default true
+ ///
+ public bool EnablePowerOnToLastSource { get; set; }
+ string LastSourceKey;
+
+ ///
+ /// Sets the volume control device, and attaches/removes InUseTrackers with "audio"
+ /// tag to device.
+ ///
+ 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;
+
+ ///
+ /// "codecOsd"
+ ///
+ public string DefaultCodecRouteString { get { return "codecOsd"; } }
+
+ ///
+ /// Temporary implementation. Returns the schedule-ready object or null if none. Fow now,
+ /// always returns the VideoCodec if it is capable
+ ///
+ public IHasScheduleAwareness ScheduleSource { get { return VideoCodec as IHasScheduleAwareness; } }
+
+ CCriticalSection SourceSelectLock = new CCriticalSection();
+
+ public EssentialsDualDisplayRoom(DeviceConfig config)
+ : base(config)
+ {
+ try
+ {
+ PropertiesConfig = JsonConvert.DeserializeObject
+ (config.Properties.ToString());
+
+ var leftDispKey = PropertiesConfig.Displays[EssentialsDualDisplayRoomPropertiesConfig.LeftDisplayId];
+
+ if (!string.IsNullOrEmpty(leftDispKey))
+ LeftDisplay = DeviceManager.GetDeviceForKey(leftDispKey) as IRoutingSinkWithSwitching;
+ else
+ Debug.Console(0, this, "Unable to get LeftDisplay for Room");
+
+ var rightDispKey = PropertiesConfig.Displays[EssentialsDualDisplayRoomPropertiesConfig.RightDisplayId];
+
+ if (!string.IsNullOrEmpty(rightDispKey))
+ LeftDisplay = DeviceManager.GetDeviceForKey(rightDispKey) as IRoutingSinkWithSwitching;
+ else
+ Debug.Console(0, this, "Unable to get LeftDisplay for Room");
+
+ VideoCodec = DeviceManager.GetDeviceForKey(PropertiesConfig.VideoCodecKey) as
+ PepperDash.Essentials.Devices.Common.VideoCodec.VideoCodecBase;
+ if (VideoCodec == null)
+ throw new ArgumentNullException("codec cannot be null");
+
+ AudioCodec = DeviceManager.GetDeviceForKey(PropertiesConfig.AudioCodecKey) as
+ PepperDash.Essentials.Devices.Common.AudioCodec.AudioCodecBase;
+ if (AudioCodec == null)
+ Debug.Console(0, this, "No Audio Codec Found");
+
+ DefaultAudioDevice = DeviceManager.GetDeviceForKey(PropertiesConfig.DefaultAudioKey) as IBasicVolumeControls;
+
+ Initialize();
+ }
+ catch (Exception e)
+ {
+ Debug.Console(1, this, "Error building room \n{0}", e);
+ }
+ }
+
+ void Initialize()
+ {
+ if (DefaultAudioDevice is IBasicVolumeControls)
+ DefaultVolumeControls = DefaultAudioDevice as IBasicVolumeControls;
+ else if (DefaultAudioDevice is IHasVolumeDevice)
+ DefaultVolumeControls = (DefaultAudioDevice as IHasVolumeDevice).VolumeDevice;
+ CurrentVolumeControls = DefaultVolumeControls;
+
+
+ var leftDisp = LeftDisplay as DisplayBase;
+ if (leftDisp != null)
+ InitializeDisplay(leftDisp);
+
+ var rightDisp = RightDisplay as DisplayBase;
+ if (rightDisp != null)
+ InitializeDisplay(rightDisp);
+
+ // Get Microphone Privacy object, if any
+ 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);
+
+ Debug.Console(2, this, "Emergency Config evaluated.");
+
+ // Combines call feedback from both codecs if available
+ InCallFeedback = new BoolFeedback(() =>
+ {
+ bool inAudioCall = false;
+ bool inVideoCall = false;
+
+ if (AudioCodec != null)
+ inAudioCall = AudioCodec.IsInCall;
+
+ if (VideoCodec != null)
+ inVideoCall = VideoCodec.IsInCall;
+
+ if (inAudioCall || inVideoCall)
+ return true;
+ else
+ return false;
+ });
+
+ VideoCodec.CallStatusChange += (o, a) => this.InCallFeedback.FireUpdate();
+
+ if (AudioCodec != null)
+ AudioCodec.CallStatusChange += (o, a) => this.InCallFeedback.FireUpdate();
+
+ IsSharingFeedback = new BoolFeedback(() => VideoCodec.SharingContentIsOnFeedback.BoolValue);
+ VideoCodec.SharingContentIsOnFeedback.OutputChange += (o, a) => this.IsSharingFeedback.FireUpdate();
+
+ // link privacy to VC (for now?)
+ PrivacyModeIsOnFeedback = new BoolFeedback(() => VideoCodec.PrivacyModeIsOnFeedback.BoolValue);
+ VideoCodec.PrivacyModeIsOnFeedback.OutputChange += (o, a) => this.PrivacyModeIsOnFeedback.FireUpdate();
+
+ CallTypeFeedback = new IntFeedback(() => 0);
+
+ SourceListKey = "default";
+ EnablePowerOnToLastSource = true;
+ }
+
+ void InitializeDisplay(DisplayBase disp)
+ {
+ if (disp != null)
+ {
+ // Link power, warming, cooling to display
+ disp.PowerIsOnFeedback.OutputChange += (o, a) =>
+ {
+ if (disp.PowerIsOnFeedback.BoolValue != OnFeedback.BoolValue)
+ {
+ if (!disp.PowerIsOnFeedback.BoolValue)
+ disp.CurrentSourceInfo = null;
+ OnFeedback.FireUpdate();
+ }
+ if (disp.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();
+ };
+ }
+ }
+
+ protected override void CustomSetConfig(DeviceConfig config)
+ {
+ var newPropertiesConfig = JsonConvert.DeserializeObject(config.Properties.ToString());
+
+ if (newPropertiesConfig != null)
+ PropertiesConfig = newPropertiesConfig;
+
+ ConfigWriter.UpdateRoomConfig(config);
+ }
+
+ public override bool CustomActivate()
+ {
+ // Add Occupancy object from config
+ if (PropertiesConfig.Occupancy != null)
+ this.SetRoomOccupancy(DeviceManager.GetDeviceForKey(PropertiesConfig.Occupancy.DeviceKey) as
+ IOccupancyStatusProvider, PropertiesConfig.Occupancy.TimeoutMinutes);
+
+ this.LogoUrl = PropertiesConfig.Logo.GetUrl();
+ this.SourceListKey = PropertiesConfig.SourceListKey;
+ this.DefaultSourceItem = PropertiesConfig.DefaultSourceItem;
+ this.DefaultVolume = (ushort)(PropertiesConfig.Volumes.Master.Level * 65535 / 100);
+
+ return base.CustomActivate();
+ }
+
+ ///
+ ///
+ ///
+ protected override void EndShutdown()
+ {
+ VideoCodec.EndAllCalls();
+
+ SetDefaultLevels();
+
+ RunDefaultPresentRoute();
+
+ CrestronEnvironment.Sleep(1000);
+
+ RunRouteAction("roomOff");
+ }
+
+ ///
+ /// Routes the default source item, if any. Returns true when default route exists
+ ///
+ public override bool RunDefaultPresentRoute()
+ {
+ if (DefaultSourceItem != null)
+ RunRouteAction(DefaultSourceItem);
+
+ return DefaultSourceItem != null;
+ }
+
+ ///
+ /// Sets up the room when started into call mode without presenting a source
+ ///
+ ///
+ public bool RunDefaultCallRoute()
+ {
+ RunRouteAction(DefaultCodecRouteString);
+ return true;
+ }
+
+ ///
+ ///
+ ///
+ ///
+ public void RunRouteAction(string routeKey)
+ {
+ RunRouteAction(routeKey, null);
+ }
+
+ ///
+ /// Gets a source from config list SourceListKey and dynamically build and executes the
+ /// route or commands
+ ///
+ ///
+ public void RunRouteAction(string routeKey, Action successCallback)
+ {
+ // Run this on a separate thread
+ new CTimer(o =>
+ {
+ // try to prevent multiple simultaneous selections
+ SourceSelectLock.TryEnter();
+
+ try
+ {
+
+ Debug.Console(1, this, "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;
+ }
+
+ // End usage timer on last source
+ if (!string.IsNullOrEmpty(LastSourceKey))
+ {
+ var usageLastSource = dict[LastSourceKey].SourceDevice as IUsageTracking;
+ if (usageLastSource != null && usageLastSource.UsageTracker != null)
+ {
+ try
+ {
+ // There MAY have been failures in here. Protect
+ usageLastSource.UsageTracker.EndDeviceUsage();
+ }
+ catch (Exception e)
+ {
+ Debug.Console(1, this, "*#* EXCEPTION in end usage tracking:\r{0}", e);
+ }
+ }
+ }
+
+ // Let's run it
+ var item = dict[routeKey];
+ if (routeKey.ToLower() != "roomoff")
+ {
+
+ LastSourceKey = routeKey;
+ }
+ else
+ CurrentSourceInfoKey = null;
+
+ // hand off the individual routes to this helper
+ foreach (var route in item.RouteList)
+ DoRouteItem(route);
+
+ // Start usage timer on routed source
+ var usageNewSource = item.SourceDevice as IUsageTracking;
+ if (usageNewSource != null && usageNewSource.UsageTracker != null) // Have to make sure there is a usage tracker!
+ {
+ (item.SourceDevice as IUsageTracking).UsageTracker.StartDeviceUsage();
+ }
+
+ // See if this can be moved into common, base-class method -------------
+
+
+ // 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;
+ }
+
+ OnFeedback.FireUpdate();
+
+ // report back when done
+ if (successCallback != null)
+ successCallback();
+ }
+ catch (Exception e)
+ {
+ Debug.Console(1, this, "ERROR in routing: {0}", e);
+ }
+
+ SourceSelectLock.Leave();
+ }, 0); // end of CTimer
+ }
+
+
+ ///
+ ///
+ ///
+ ///
+ void DoRouteItem(SourceRouteListItem route)
+ {
+ // 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);
+ }
+ else
+ DoRoute(route);
+ }
+
+ ///
+ ///
+ ///
+ ///
+ ///
+ bool DoRoute(SourceRouteListItem route)
+ {
+ IRoutingSinkNoSwitching dest = null;
+
+ if (route.DestinationKey.Equals("$defaultaudio", StringComparison.OrdinalIgnoreCase))
+ dest = DefaultAudioDevice as IRoutingSinkNoSwitching;
+ else if (route.DestinationKey.Equals("$defaultDisplay", StringComparison.OrdinalIgnoreCase))
+ dest = DefaultDisplay;
+ else
+ dest = DeviceManager.GetDeviceForKey(route.DestinationKey) as IRoutingSinkNoSwitching;
+
+ 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 IPower)
+ (dest as IPower).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
+ }
+
+ ///
+ /// Does what it says
+ ///
+ public override void SetDefaultLevels()
+ {
+ Debug.Console(1, this, "Restoring default levels");
+ var vc = CurrentVolumeControls as IBasicVolumeWithFeedback;
+ if (vc != null)
+ vc.SetVolume(DefaultVolume);
+ }
+ ///
+ /// Will power the room on with the last-used source
+ ///
+ public override void PowerOnToDefaultOrLastSource()
+ {
+ if (!EnablePowerOnToLastSource || LastSourceKey == null)
+ return;
+ RunRouteAction(LastSourceKey);
+ }
+
+ ///
+ /// Runs "roomOff" action on all rooms not set to ExcludeFromGlobalFunctions
+ ///
+ 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");
+ }
+
+ #region IPrivacy Members
+
+
+ public void PrivacyModeOff()
+ {
+ VideoCodec.PrivacyModeOff();
+ }
+
+ public void PrivacyModeOn()
+ {
+ VideoCodec.PrivacyModeOn();
+ }
+
+ public void PrivacyModeToggle()
+ {
+ VideoCodec.PrivacyModeToggle();
+ }
+
+ #endregion
+ }
+}
\ No newline at end of file
diff --git a/PepperDashEssentials/Room/Types/EssentialsHuddleVtc1Room.cs b/PepperDashEssentials/Room/Types/EssentialsHuddleVtc1Room.cs
index a6e2abee..d37119f4 100644
--- a/PepperDashEssentials/Room/Types/EssentialsHuddleVtc1Room.cs
+++ b/PepperDashEssentials/Room/Types/EssentialsHuddleVtc1Room.cs
@@ -17,7 +17,7 @@ using PepperDash.Essentials.Devices.Common.AudioCodec;
namespace PepperDash.Essentials
{
public class EssentialsHuddleVtc1Room : EssentialsRoomBase, IHasCurrentSourceInfoChange,
- IPrivacy, IHasCurrentVolumeControls, IRunRouteAction, IRunDefaultCallRoute, IHasVideoCodec, IHasAudioCodec, IHasDefaultDisplay
+ IPrivacy, IHasCurrentVolumeControls, IRunRouteAction, IRunDefaultCallRoute, IHasVideoCodec, IHasAudioCodec, IHasDefaultDisplay, IHasInCallFeedback
{
public event EventHandler CurrentVolumeDeviceChange;
public event SourceInfoChangeHandler CurrentSourceChange;
@@ -251,29 +251,28 @@ namespace PepperDash.Essentials
}
};
- disp.IsWarmingUpFeedback.OutputChange += (o, a) =>
- {
+ disp.IsWarmingUpFeedback.OutputChange += (o, a) =>
+ {
IsWarmingUpFeedback.FireUpdate();
if (!IsWarmingUpFeedback.BoolValue)
(CurrentVolumeControls as IBasicVolumeWithFeedback).SetVolume(DefaultVolume);
};
- disp.IsCoolingDownFeedback.OutputChange += (o, a) =>
+ disp.IsCoolingDownFeedback.OutputChange += (o, a) =>
{
- IsCoolingDownFeedback.FireUpdate();
+ IsCoolingDownFeedback.FireUpdate();
};
-
- // Get Microphone Privacy object, if any
- 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);
-
- Debug.Console(2, this, "Emergency Config evaluated.");
}
+ // Get Microphone Privacy object, if any
+ 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);
+
+ Debug.Console(2, this, "Emergency Config evaluated.");
+
// Combines call feedback from both codecs if available
InCallFeedback = new BoolFeedback(() =>
{
diff --git a/essentials-framework/Essentials Core/PepperDashEssentialsBase/Room/Interfaces.cs b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Room/Interfaces.cs
index e2a9f438..e0d042a2 100644
--- a/essentials-framework/Essentials Core/PepperDashEssentialsBase/Room/Interfaces.cs
+++ b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Room/Interfaces.cs
@@ -6,6 +6,17 @@ using Crestron.SimplSharp;
namespace PepperDash.Essentials.Core
{
+ ///
+ /// For rooms with in call feedback
+ ///
+ public interface IHasInCallFeedback
+ {
+ BoolFeedback InCallFeedback { get; }
+ }
+
+ ///
+ /// For rooms with a single display
+ ///
public interface IHasDefaultDisplay
{
IRoutingSinkWithSwitching DefaultDisplay { get; }