From c22e95cad26179e50aa764325fe7f90e0d3d8546 Mon Sep 17 00:00:00 2001 From: Neil Dorin Date: Fri, 25 Oct 2019 16:08:55 -0600 Subject: [PATCH] Added remaining methods for EssentialsDualDisplayRoom. Added IHasInCallFeedback interface to be applied to rooms with conferencing --- .../Room/Config/EssentialsRoomConfig.cs | 16 +- .../Room/Types/EssentialsDualDisplayRoom.cs | 680 ++++++++++++++++-- .../Room/Types/EssentialsHuddleVtc1Room.cs | 29 +- .../Room/Interfaces.cs | 11 + 4 files changed, 658 insertions(+), 78 deletions(-) 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; }