cleaned out framework files; added framework submodule; referneced p.core to reference in framework; moved essentials.sln; changed paths in sln to match; test build

This commit is contained in:
Heath Volmer
2018-06-28 13:59:14 -06:00
parent 058ea730ed
commit 0e9d1e4c35
413 changed files with 33026 additions and 71338 deletions

View File

@@ -0,0 +1,462 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Crestron.SimplSharp;
using PepperDash.Core;
using PepperDash.Essentials.Core;
using PepperDash.Essentials.Room.Config;
namespace PepperDash.Essentials
{
public class EssentialsHuddleSpaceRoom : EssentialsRoomBase, IHasCurrentSourceInfoChange
{
public event EventHandler<VolumeDeviceChangeEventArgs> CurrentVolumeDeviceChange;
public event SourceInfoChangeHandler CurrentSingleSourceChange;
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 EssentialsRoomPropertiesConfig Config { get; private set; }
public IRoutingSinkWithSwitching DefaultDisplay { get; private set; }
public IRoutingSinkNoSwitching DefaultAudioDevice { get; private set; }
public IBasicVolumeControls DefaultVolumeControls { get; private set; }
public bool ExcludeFromGlobalFunctions { get; set; }
/// <summary>
/// The config name of the source list
/// </summary>
public string SourceListKey { 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; }
private set
{
if (value == _CurrentSourceInfo) return;
var handler = CurrentSingleSourceChange;
// 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(this, _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(this, _CurrentSourceInfo, ChangeType.DidChange);
}
}
SourceListItem _CurrentSourceInfo;
public string CurrentSourceInfoKey { get; private set; }
/// <summary>
///
/// </summary>
/// <param name="key"></param>
/// <param name="name"></param>
public EssentialsHuddleSpaceRoom(string key, string name, IRoutingSinkWithSwitching defaultDisplay,
IRoutingSinkNoSwitching defaultAudio, EssentialsRoomPropertiesConfig config)
: base(key, name)
{
Config = config;
DefaultDisplay = defaultDisplay;
DefaultAudioDevice = defaultAudio;
if (defaultAudio is IBasicVolumeControls)
DefaultVolumeControls = defaultAudio as IBasicVolumeControls;
else if (defaultAudio is IHasVolumeDevice)
DefaultVolumeControls = (defaultAudio as IHasVolumeDevice).VolumeDevice;
CurrentVolumeControls = DefaultVolumeControls;
var disp = DefaultDisplay as DisplayBase;
if (disp != null)
{
// Link power, warming, cooling to display
disp.PowerIsOnFeedback.OutputChange += (o, a) =>
{
if (disp.PowerIsOnFeedback.BoolValue != OnFeedback.BoolValue)
{
if (!disp.PowerIsOnFeedback.BoolValue)
CurrentSourceInfo = null;
OnFeedback.FireUpdate();
}
};
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;
}
/// <summary>
///
/// </summary>
protected override void EndShutdown()
{
SetDefaultLevels();
RunDefaultRoute();
CrestronEnvironment.Sleep(1000);
RunRouteAction("roomOff");
}
/// <summary>
/// Routes the default source item, if any
/// </summary>
public void RunDefaultRoute()
{
//if (DefaultSourceItem != null && !OnFeedback.BoolValue)
RunRouteAction(DefaultSourceItem);
}
/// <summary>
///
/// </summary>
/// <param name="routeKey"></param>
public void RunRouteAction(string routeKey)
{
RunRouteAction(routeKey, null);
}
/// <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(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;
}
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 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)
{
IRoutingSinkNoSwitching 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 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
}
/// <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

@@ -0,0 +1,850 @@
<<<<<<< HEAD
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Crestron.SimplSharp;
using PepperDash.Core;
using PepperDash.Essentials.Core;
using PepperDash.Essentials.Room.Config;
namespace PepperDash.Essentials
{
public class EssentialsHuddleSpaceRoom : EssentialsRoomBase, IHasCurrentSourceInfoChange
{
public event EventHandler<VolumeDeviceChangeEventArgs> CurrentVolumeDeviceChange;
public event SourceInfoChangeHandler CurrentSingleSourceChange;
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 EssentialsRoomPropertiesConfig Config { get; private set; }
public IRoutingSinkWithSwitching DefaultDisplay { get; private set; }
public IRoutingSinkNoSwitching DefaultAudioDevice { get; private set; }
public IBasicVolumeControls DefaultVolumeControls { get; private set; }
public bool ExcludeFromGlobalFunctions { get; set; }
/// <summary>
/// The config name of the source list
/// </summary>
public string SourceListKey { 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; }
private set
{
if (value == _CurrentSourceInfo) return;
var handler = CurrentSingleSourceChange;
// 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(this, _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(this, _CurrentSourceInfo, ChangeType.DidChange);
}
}
SourceListItem _CurrentSourceInfo;
public string CurrentSourceInfoKey { get; private set; }
/// <summary>
///
/// </summary>
/// <param name="key"></param>
/// <param name="name"></param>
public EssentialsHuddleSpaceRoom(string key, string name, IRoutingSinkWithSwitching defaultDisplay,
IRoutingSinkNoSwitching defaultAudio, EssentialsRoomPropertiesConfig config)
: base(key, name)
{
Config = config;
DefaultDisplay = defaultDisplay;
DefaultAudioDevice = defaultAudio;
if (defaultAudio is IBasicVolumeControls)
DefaultVolumeControls = defaultAudio as IBasicVolumeControls;
else if (defaultAudio is IHasVolumeDevice)
DefaultVolumeControls = (defaultAudio as IHasVolumeDevice).VolumeDevice;
CurrentVolumeControls = DefaultVolumeControls;
var disp = DefaultDisplay as DisplayBase;
if (disp != null)
{
// Link power, warming, cooling to display
disp.PowerIsOnFeedback.OutputChange += (o, a) =>
{
if (disp.PowerIsOnFeedback.BoolValue != OnFeedback.BoolValue)
{
if (!disp.PowerIsOnFeedback.BoolValue)
CurrentSourceInfo = null;
OnFeedback.FireUpdate();
}
};
disp.IsWarmingUpFeedback.OutputChange += (o, a) =>
{
IsWarmingUpFeedback.FireUpdate();
if (!IsWarmingUpFeedback.BoolValue)
(DefaultDisplay as IBasicVolumeWithFeedback).SetVolume(DefaultVolume);
};
disp.IsCoolingDownFeedback.OutputChange += (o, a) =>
{
IsCoolingDownFeedback.FireUpdate();
if (IsCoolingDownFeedback.BoolValue)
(DefaultDisplay as IBasicVolumeWithFeedback).SetVolume(DefaultVolume);
};
}
SourceListKey = "default";
EnablePowerOnToLastSource = true;
}
/// <summary>
///
/// </summary>
public override void Shutdown()
{
RunRouteAction("roomOff");
}
/// <summary>
/// Routes the default source item, if any
/// </summary>
public void RunDefaultRoute()
{
if (DefaultSourceItem != null)
RunRouteAction(DefaultSourceItem);
}
/// <summary>
///
/// </summary>
/// <param name="routeKey"></param>
public void RunRouteAction(string routeKey)
{
RunRouteAction(routeKey, null);
}
/// <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(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;
}
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 on room, 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;
}
CurrentVolumeControls = volDev;
// 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 void PowerOnToDefaultOrLastSource()
{
if (!EnablePowerOnToLastSource || LastSourceKey == null)
return;
RunRouteAction(LastSourceKey);
}
/// <summary>
/// Does what it says
/// </summary>
public override void SetDefaultLevels()
{
Debug.Console(0, this, "SetDefaultLevels not implemented");
}
/// <summary>
///
/// </summary>
/// <param name="route"></param>
/// <returns></returns>
bool DoRoute(SourceRouteListItem route)
{
IRoutingSinkNoSwitching 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 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;
=======
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Crestron.SimplSharp;
using PepperDash.Core;
using PepperDash.Essentials.Core;
using PepperDash.Essentials.Room.Config;
namespace PepperDash.Essentials
{
public class EssentialsHuddleSpaceRoom : EssentialsRoomBase, IHasCurrentSourceInfoChange
{
public event EventHandler<VolumeDeviceChangeEventArgs> CurrentVolumeDeviceChange;
public event SourceInfoChangeHandler CurrentSingleSourceChange;
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 EssentialsRoomPropertiesConfig Config { get; private set; }
public IRoutingSinkWithSwitching DefaultDisplay { get; private set; }
public IRoutingSinkNoSwitching DefaultAudioDevice { get; private set; }
public IBasicVolumeControls DefaultVolumeControls { get; private set; }
public bool ExcludeFromGlobalFunctions { get; set; }
/// <summary>
/// The config name of the source list
/// </summary>
public string SourceListKey { 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; }
private set
{
if (value == _CurrentSourceInfo) return;
var handler = CurrentSingleSourceChange;
// 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(this, _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(this, _CurrentSourceInfo, ChangeType.DidChange);
}
}
SourceListItem _CurrentSourceInfo;
public string CurrentSourceInfoKey { get; private set; }
/// <summary>
///
/// </summary>
/// <param name="key"></param>
/// <param name="name"></param>
public EssentialsHuddleSpaceRoom(string key, string name, IRoutingSinkWithSwitching defaultDisplay,
IRoutingSinkNoSwitching defaultAudio, EssentialsRoomPropertiesConfig config)
: base(key, name)
{
Config = config;
DefaultDisplay = defaultDisplay;
DefaultAudioDevice = defaultAudio;
if (defaultAudio is IBasicVolumeControls)
DefaultVolumeControls = defaultAudio as IBasicVolumeControls;
else if (defaultAudio is IHasVolumeDevice)
DefaultVolumeControls = (defaultAudio as IHasVolumeDevice).VolumeDevice;
CurrentVolumeControls = DefaultVolumeControls;
var disp = DefaultDisplay as DisplayBase;
if (disp != null)
{
// Link power, warming, cooling to display
disp.PowerIsOnFeedback.OutputChange += (o, a) =>
{
if (disp.PowerIsOnFeedback.BoolValue != OnFeedback.BoolValue)
{
if (!disp.PowerIsOnFeedback.BoolValue)
CurrentSourceInfo = null;
OnFeedback.FireUpdate();
}
};
disp.IsWarmingUpFeedback.OutputChange += (o, a) =>
{
IsWarmingUpFeedback.FireUpdate();
if (!IsWarmingUpFeedback.BoolValue)
(DefaultDisplay as IBasicVolumeWithFeedback).SetVolume(DefaultVolume);
};
disp.IsCoolingDownFeedback.OutputChange += (o, a) =>
{
IsCoolingDownFeedback.FireUpdate();
if (IsCoolingDownFeedback.BoolValue)
(DefaultDisplay as IBasicVolumeWithFeedback).SetVolume(DefaultVolume);
};
}
SourceListKey = "default";
EnablePowerOnToLastSource = true;
}
/// <summary>
///
/// </summary>
protected override void EndShutdown()
{
RunRouteAction("roomOff");
}
/// <summary>
/// Routes the default source item, if any
/// </summary>
public void RunDefaultRoute()
{
if (DefaultSourceItem != null)
RunRouteAction(DefaultSourceItem);
}
/// <summary>
///
/// </summary>
/// <param name="routeKey"></param>
public void RunRouteAction(string routeKey)
{
RunRouteAction(routeKey, null);
}
/// <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(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;
}
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 on room, 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;
}
CurrentVolumeControls = volDev;
// 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 void PowerOnToDefaultOrLastSource()
{
if (!EnablePowerOnToLastSource || LastSourceKey == null)
return;
RunRouteAction(LastSourceKey);
}
/// <summary>
/// Does what it says
/// </summary>
public override void SetDefaultLevels()
{
Debug.Console(0, this, "SetDefaultLevels not implemented");
}
/// <summary>
///
/// </summary>
/// <param name="route"></param>
/// <returns></returns>
bool DoRoute(SourceRouteListItem route)
{
IRoutingSinkNoSwitching 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 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;
>>>>>>> origin/feature/ecs-342
}
public override void RoomVacatedForTimeoutPeriod(object o)
{
//Implement this
}
/// <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

@@ -0,0 +1,572 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Crestron.SimplSharp;
using PepperDash.Core;
using PepperDash.Essentials.Core;
using PepperDash.Essentials.Room.Config;
using PepperDash.Essentials.Devices.Common.Codec;
using PepperDash.Essentials.Devices.Common.VideoCodec;
namespace PepperDash.Essentials
{
public class EssentialsHuddleVtc1Room : EssentialsRoomBase, IHasCurrentSourceInfoChange, IPrivacy, IHasCurrentVolumeControls
{
public event EventHandler<VolumeDeviceChangeEventArgs> CurrentVolumeDeviceChange;
public event SourceInfoChangeHandler CurrentSingleSourceChange;
//************************
// Call-related stuff
public BoolFeedback InCallFeedback { get; private set; }
/// <summary>
/// Make this more specific
/// </summary>
public List<CodecActiveCallItem> ActiveCalls { get; private set; }
/// <summary>
/// States: 0 for on hook, 1 for video, 2 for audio, 3 for telekenesis
/// </summary>
public IntFeedback CallTypeFeedback { get; private set; }
/// <summary>
///
/// </summary>
public BoolFeedback PrivacyModeIsOnFeedback { get; private set; }
/// <summary>
/// When something in the room is sharing with the far end or through other means
/// </summary>
public BoolFeedback IsSharingFeedback { get; private set; }
//************************
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 Config { get; private set; }
public IRoutingSinkWithSwitching DefaultDisplay { get; private set; }
public IBasicVolumeControls DefaultAudioDevice { get; private set; }
public IBasicVolumeControls DefaultVolumeControls { get; private set; }
public VideoCodecBase VideoCodec { get; private set; }
public bool ExcludeFromGlobalFunctions { get; set; }
/// <summary>
/// The config name of the source list
/// </summary>
public string SourceListKey { 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>
/// 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;
/// <summary>
/// The SourceListItem last run - containing names and icons
/// </summary>
public SourceListItem CurrentSourceInfo
{
get { return _CurrentSourceInfo; }
private set
{
if (value == _CurrentSourceInfo) return;
var handler = CurrentSingleSourceChange;
// 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(this, _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(this, _CurrentSourceInfo, ChangeType.DidChange);
}
}
SourceListItem _CurrentSourceInfo;
public string CurrentSourceInfoKey { get; private set; }
/// <summary>
/// "codecOsd"
/// </summary>
public string DefaultCodecRouteString { get { return "codecOsd"; } }
/// <summary>
/// Temporary implementation. Returns the schedule-ready object or null if none. Fow now,
/// always returns the VideoCodec if it is capable
/// </summary>
public IHasScheduleAwareness ScheduleSource { get { return VideoCodec as IHasScheduleAwareness; } }
CCriticalSection SourceSelectLock = new CCriticalSection();
/// <summary>
///
/// </summary>
/// <param name="key"></param>
/// <param name="name"></param>
public EssentialsHuddleVtc1Room(string key, string name, IRoutingSinkWithSwitching defaultDisplay,
IBasicVolumeControls defaultAudio, VideoCodecBase codec, EssentialsHuddleVtc1PropertiesConfig config)
: base(key, name)
{
if (codec == null)
throw new ArgumentNullException("codec cannot be null");
Config = config;
DefaultDisplay = defaultDisplay;
VideoCodec = codec;
DefaultAudioDevice = defaultAudio;
if (defaultAudio is IBasicVolumeControls)
DefaultVolumeControls = defaultAudio as IBasicVolumeControls;
else if (defaultAudio is IHasVolumeDevice)
DefaultVolumeControls = (defaultAudio as IHasVolumeDevice).VolumeDevice;
CurrentVolumeControls = DefaultVolumeControls;
var disp = DefaultDisplay as DisplayBase;
if (disp != null)
{
// Link power, warming, cooling to display
disp.PowerIsOnFeedback.OutputChange += (o, a) =>
{
if (disp.PowerIsOnFeedback.BoolValue != OnFeedback.BoolValue)
{
if (!disp.PowerIsOnFeedback.BoolValue)
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();
};
}
InCallFeedback = new BoolFeedback(() => VideoCodec.IsInCall);
VideoCodec.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;
}
/// <summary>
///
/// </summary>
protected override void EndShutdown()
{
VideoCodec.EndAllCalls();
SetDefaultLevels();
RunDefaultPresentRoute();
CrestronEnvironment.Sleep(1000);
RunRouteAction("roomOff");
}
/// <summary>
/// Routes the default source item, if any. Returns true when default route exists
/// </summary>
public bool RunDefaultPresentRoute()
{
//if (DefaultSourceItem != null)
RunRouteAction(DefaultSourceItem);
return DefaultSourceItem != null;
}
/// <summary>
/// Sets up the room when started into call mode without presenting a source
/// </summary>
/// <returns></returns>
public bool RunDefaultCallRoute()
{
RunRouteAction(DefaultCodecRouteString);
return true;
}
/// <summary>
///
/// </summary>
/// <param name="routeKey"></param>
public void RunRouteAction(string routeKey)
{
RunRouteAction(routeKey, null);
}
/// <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 =>
{
// 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
}
/// <summary>
///
/// </summary>
/// <param name="route"></param>
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);
}
/// <summary>
///
/// </summary>
/// <param name="route"></param>
/// <returns></returns>
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
}
/// <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>
/// Will power the room on with the last-used source
/// </summary>
public void PowerOnToDefaultOrLastSource()
{
if (!EnablePowerOnToLastSource || LastSourceKey == null)
return;
RunRouteAction(LastSourceKey);
}
/// <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");
}
#region IPrivacy Members
public void PrivacyModeOff()
{
VideoCodec.PrivacyModeOff();
}
public void PrivacyModeOn()
{
VideoCodec.PrivacyModeOn();
}
public void PrivacyModeToggle()
{
VideoCodec.PrivacyModeToggle();
}
#endregion
}
}

View File

@@ -0,0 +1,967 @@
<<<<<<< HEAD
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Crestron.SimplSharp;
using PepperDash.Core;
using PepperDash.Essentials.Core;
using PepperDash.Essentials.Room.Config;
using PepperDash.Essentials.Devices.Common.Codec;
using PepperDash.Essentials.Devices.Common.VideoCodec;
namespace PepperDash.Essentials
{
public class EssentialsHuddleVtc1Room : EssentialsRoomBase, IHasCurrentSourceInfoChange, IPrivacy
{
public event EventHandler<VolumeDeviceChangeEventArgs> CurrentVolumeDeviceChange;
public event SourceInfoChangeHandler CurrentSingleSourceChange;
//************************
// Call-related stuff
public BoolFeedback InCallFeedback { get; private set; }
/// <summary>
/// Make this more specific
/// </summary>
public List<CodecActiveCallItem> ActiveCalls { get; private set; }
/// <summary>
/// States: 0 for on hook, 1 for video, 2 for audio, 3 for telekenesis
/// </summary>
public IntFeedback CallTypeFeedback { get; private set; }
/// <summary>
///
/// </summary>
public BoolFeedback PrivacyModeIsOnFeedback { get; private set; }
/// <summary>
/// When something in the room is sharing with the far end or through other means
/// </summary>
public BoolFeedback IsSharingFeedback { get; private set; }
//************************
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 Config { get; private set; }
public IRoutingSinkWithSwitching DefaultDisplay { get; private set; }
public IBasicVolumeControls DefaultAudioDevice { get; private set; }
public IBasicVolumeControls DefaultVolumeControls { get; private set; }
public VideoCodecBase VideoCodec { get; private set; }
public bool ExcludeFromGlobalFunctions { get; set; }
/// <summary>
/// The config name of the source list
/// </summary>
public string SourceListKey { 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; }
private set
{
if (value == _CurrentSourceInfo) return;
var handler = CurrentSingleSourceChange;
// 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(this, _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(this, _CurrentSourceInfo, ChangeType.DidChange);
}
}
SourceListItem _CurrentSourceInfo;
public string CurrentSourceInfoKey { get; private set; }
/// <summary>
/// "codecOsd"
/// </summary>
public string DefaultCodecRouteString { get { return "codecOsd"; } }
/// <summary>
/// Temporary implementation. Returns the schedule-ready object or null if none. Fow now,
/// always returns the VideoCodec if it is capable
/// </summary>
public IHasScheduleAwareness ScheduleSource { get { return VideoCodec as IHasScheduleAwareness; } }
/// <summary>
///
/// </summary>
/// <param name="key"></param>
/// <param name="name"></param>
public EssentialsHuddleVtc1Room(string key, string name, IRoutingSinkWithSwitching defaultDisplay,
IBasicVolumeControls defaultAudio, VideoCodecBase codec, EssentialsHuddleVtc1PropertiesConfig config)
: base(key, name)
{
if (codec == null)
throw new ArgumentNullException("codec cannot be null");
Config = config;
DefaultDisplay = defaultDisplay;
VideoCodec = codec;
DefaultAudioDevice = defaultAudio;
if (defaultAudio is IBasicVolumeControls)
DefaultVolumeControls = defaultAudio as IBasicVolumeControls;
else if (defaultAudio is IHasVolumeDevice)
DefaultVolumeControls = (defaultAudio as IHasVolumeDevice).VolumeDevice;
CurrentVolumeControls = DefaultVolumeControls;
var disp = DefaultDisplay as DisplayBase;
if (disp != null)
{
// Link power, warming, cooling to display
disp.PowerIsOnFeedback.OutputChange += (o, a) =>
{
if (disp.PowerIsOnFeedback.BoolValue != OnFeedback.BoolValue)
{
if (!disp.PowerIsOnFeedback.BoolValue)
CurrentSourceInfo = null;
OnFeedback.FireUpdate();
}
if (disp.PowerIsOnFeedback.BoolValue)
{
SetDefaultLevels();
}
};
disp.IsWarmingUpFeedback.OutputChange += (o, a) =>
{
IsWarmingUpFeedback.FireUpdate();
if (!IsWarmingUpFeedback.BoolValue)
(DefaultDisplay as IBasicVolumeWithFeedback).SetVolume(DefaultVolume);
};
disp.IsCoolingDownFeedback.OutputChange += (o, a) =>
{
IsCoolingDownFeedback.FireUpdate();
if (IsCoolingDownFeedback.BoolValue)
(DefaultDisplay as IBasicVolumeWithFeedback).SetVolume(DefaultVolume);
};
}
InCallFeedback = new BoolFeedback(() => VideoCodec.IsInCall);
IsSharingFeedback = new BoolFeedback(() => VideoCodec.SharingSourceFeedback.StringValue != null);
// 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;
}
/// <summary>
///
/// </summary>
public override void Shutdown()
{
RunRouteAction("roomOff");
VideoCodec.EndAllCalls();
}
/// <summary>
/// Routes the default source item, if any. Returns true when default route exists
/// </summary>
public bool RunDefaultPresentRoute()
{
if (DefaultSourceItem != null)
RunRouteAction(DefaultSourceItem);
return DefaultSourceItem != null;
}
/// <summary>
/// Sets up the room when started into call mode without presenting a source
/// </summary>
/// <returns></returns>
public bool RunDefaultCallRoute()
{
RunRouteAction(DefaultCodecRouteString);
return true;
}
/// <summary>
///
/// </summary>
/// <param name="routeKey"></param>
public void RunRouteAction(string routeKey)
{
RunRouteAction(routeKey, null);
}
/// <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 =>
{
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)
{
}
}
}
// 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();
}
// 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);
}
}, 0); // end of CTimer
}
/// <summary>
///
/// </summary>
/// <param name="route"></param>
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);
}
/// <summary>
///
/// </summary>
/// <param name="route"></param>
/// <returns></returns>
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;
=======
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Crestron.SimplSharp;
using PepperDash.Core;
using PepperDash.Essentials.Core;
using PepperDash.Essentials.Room.Config;
using PepperDash.Essentials.Devices.Common.Codec;
using PepperDash.Essentials.Devices.Common.VideoCodec;
namespace PepperDash.Essentials
{
public class EssentialsHuddleVtc1Room : EssentialsRoomBase, IHasCurrentSourceInfoChange, IPrivacy
{
public event EventHandler<VolumeDeviceChangeEventArgs> CurrentVolumeDeviceChange;
public event SourceInfoChangeHandler CurrentSingleSourceChange;
//************************
// Call-related stuff
public BoolFeedback InCallFeedback { get; private set; }
/// <summary>
/// Make this more specific
/// </summary>
public List<CodecActiveCallItem> ActiveCalls { get; private set; }
/// <summary>
/// States: 0 for on hook, 1 for video, 2 for audio, 3 for telekenesis
/// </summary>
public IntFeedback CallTypeFeedback { get; private set; }
/// <summary>
///
/// </summary>
public BoolFeedback PrivacyModeIsOnFeedback { get; private set; }
/// <summary>
/// When something in the room is sharing with the far end or through other means
/// </summary>
public BoolFeedback IsSharingFeedback { get; private set; }
//************************
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 Config { get; private set; }
public IRoutingSinkWithSwitching DefaultDisplay { get; private set; }
public IBasicVolumeControls DefaultAudioDevice { get; private set; }
public IBasicVolumeControls DefaultVolumeControls { get; private set; }
public VideoCodecBase VideoCodec { get; private set; }
public bool ExcludeFromGlobalFunctions { get; set; }
/// <summary>
/// The config name of the source list
/// </summary>
public string SourceListKey { 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; }
private set
{
if (value == _CurrentSourceInfo) return;
var handler = CurrentSingleSourceChange;
// 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(this, _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(this, _CurrentSourceInfo, ChangeType.DidChange);
}
}
SourceListItem _CurrentSourceInfo;
public string CurrentSourceInfoKey { get; private set; }
/// <summary>
/// "codecOsd"
/// </summary>
public string DefaultCodecRouteString { get { return "codecOsd"; } }
/// <summary>
/// Temporary implementation. Returns the schedule-ready object or null if none. Fow now,
/// always returns the VideoCodec if it is capable
/// </summary>
public IHasScheduleAwareness ScheduleSource { get { return VideoCodec as IHasScheduleAwareness; } }
/// <summary>
///
/// </summary>
/// <param name="key"></param>
/// <param name="name"></param>
public EssentialsHuddleVtc1Room(string key, string name, IRoutingSinkWithSwitching defaultDisplay,
IBasicVolumeControls defaultAudio, VideoCodecBase codec, EssentialsHuddleVtc1PropertiesConfig config)
: base(key, name)
{
if (codec == null)
throw new ArgumentNullException("codec cannot be null");
Config = config;
DefaultDisplay = defaultDisplay;
VideoCodec = codec;
DefaultAudioDevice = defaultAudio;
if (defaultAudio is IBasicVolumeControls)
DefaultVolumeControls = defaultAudio as IBasicVolumeControls;
else if (defaultAudio is IHasVolumeDevice)
DefaultVolumeControls = (defaultAudio as IHasVolumeDevice).VolumeDevice;
CurrentVolumeControls = DefaultVolumeControls;
var disp = DefaultDisplay as DisplayBase;
if (disp != null)
{
// Link power, warming, cooling to display
disp.PowerIsOnFeedback.OutputChange += (o, a) =>
{
if (disp.PowerIsOnFeedback.BoolValue != OnFeedback.BoolValue)
{
if (!disp.PowerIsOnFeedback.BoolValue)
CurrentSourceInfo = null;
OnFeedback.FireUpdate();
}
if (disp.PowerIsOnFeedback.BoolValue)
{
SetDefaultLevels();
}
};
disp.IsWarmingUpFeedback.OutputChange += (o, a) =>
{
IsWarmingUpFeedback.FireUpdate();
if (!IsWarmingUpFeedback.BoolValue)
(DefaultDisplay as IBasicVolumeWithFeedback).SetVolume(DefaultVolume);
};
disp.IsCoolingDownFeedback.OutputChange += (o, a) =>
{
IsCoolingDownFeedback.FireUpdate();
if (IsCoolingDownFeedback.BoolValue)
(DefaultDisplay as IBasicVolumeWithFeedback).SetVolume(DefaultVolume);
};
}
InCallFeedback = new BoolFeedback(() => VideoCodec.IsInCall);
IsSharingFeedback = new BoolFeedback(() => VideoCodec.SharingSourceFeedback.StringValue != null);
// 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;
}
/// <summary>
///
/// </summary>
protected override void EndShutdown()
{
RunRouteAction("roomOff");
VideoCodec.EndAllCalls();
}
/// <summary>
/// Routes the default source item, if any. Returns true when default route exists
/// </summary>
public bool RunDefaultPresentRoute()
{
if (DefaultSourceItem != null)
RunRouteAction(DefaultSourceItem);
return DefaultSourceItem != null;
}
/// <summary>
/// Sets up the room when started into call mode without presenting a source
/// </summary>
/// <returns></returns>
public bool RunDefaultCallRoute()
{
RunRouteAction(DefaultCodecRouteString);
return true;
}
/// <summary>
///
/// </summary>
/// <param name="routeKey"></param>
public void RunRouteAction(string routeKey)
{
RunRouteAction(routeKey, null);
}
/// <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 =>
{
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();
}
// 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);
}
}, 0); // end of CTimer
}
/// <summary>
///
/// </summary>
/// <param name="route"></param>
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);
}
/// <summary>
///
/// </summary>
/// <param name="route"></param>
/// <returns></returns>
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;
>>>>>>> origin/feature/ecs-342
}
public override void RoomVacatedForTimeoutPeriod(object o)
{
//Implement this
}
/// <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>
/// Will power the room on with the last-used source
/// </summary>
public void PowerOnToDefaultOrLastSource()
{
if (!EnablePowerOnToLastSource || LastSourceKey == null)
return;
RunRouteAction(LastSourceKey);
}
/// <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");
}
#region IPrivacy Members
public void PrivacyModeOff()
{
VideoCodec.PrivacyModeOff();
}
public void PrivacyModeOn()
{
VideoCodec.PrivacyModeOn();
}
public void PrivacyModeToggle()
{
VideoCodec.PrivacyModeToggle();
}
#endregion
}
}

View File

@@ -0,0 +1,437 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Crestron.SimplSharp;
using PepperDash.Core;
using PepperDash.Essentials.Core;
using PepperDash.Essentials.Room.Config;
namespace PepperDash.Essentials
{
public class EssentialsPresentationRoom : EssentialsRoomBase, IHasCurrentSourceInfoChange
{
public event EventHandler<VolumeDeviceChangeEventArgs> CurrentVolumeDeviceChange;
public event SourceInfoChangeHandler CurrentSingleSourceChange;
public event SourceInfoChangeHandler CurrentDisplay1SourceChange;
public event SourceInfoChangeHandler CurrentDisplay2SourceChange;
protected override Func<bool> OnFeedbackFunc { get {
return () => (CurrentSingleSourceInfo != null
&& CurrentSingleSourceInfo.Type != eSourceListItemType.Off)
|| (Display1SourceInfo != null
&& Display1SourceInfo.Type != eSourceListItemType.Off)
|| (Display2SourceInfo != null
&& Display2SourceInfo.Type != eSourceListItemType.Off); } }
protected override Func<bool> IsWarmingFeedbackFunc { get { return () =>false;; } }
protected override Func<bool> IsCoolingFeedbackFunc { get { return () => false; } }
public EssentialsPresentationRoomPropertiesConfig Config { get; private set; }
public Dictionary<uint, IRoutingSinkNoSwitching> Displays { get; private set; }
public IRoutingSinkNoSwitching DefaultAudioDevice { get; private set; }
public IBasicVolumeControls DefaultVolumeControls { get; private set; }
/// <summary>
/// The config name of the source list
/// </summary>
public string SourceListKey { get; set; }
/// <summary>
/// If room is off, enables power on to last source. Default true
/// </summary>
public bool EnablePowerOnToLastSource { get; set; }
string LastSourceKey;
public enum eVideoRoutingMode
{
SelectSourceSelectDisplay, SourceToAllDisplays
}
public eVideoRoutingMode VideoRoutingMode { get; set; }
public enum eAudioRoutingMode
{
AudioFollowsLastVideo, SelectAudioFromDisplay
}
/// <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. The complex setter is
/// to add/remove this room to the source's InUseTracking, if it is capable
/// </summary>
public SourceListItem CurrentSingleSourceInfo
{
get { return _CurrentSingleSourceInfo; }
private set
{
if (value == _CurrentSingleSourceInfo) return;
var handler = CurrentSingleSourceChange;
// remove from in-use tracker, if so equipped
if(_CurrentSingleSourceInfo != null && _CurrentSingleSourceInfo.SourceDevice is IInUseTracking)
(_CurrentSingleSourceInfo.SourceDevice as IInUseTracking).InUseTracker.RemoveUser(this, "control");
if (handler != null)
handler(this, _CurrentSingleSourceInfo, ChangeType.WillChange);
_CurrentSingleSourceInfo = value;
// add to in-use tracking
if (_CurrentSingleSourceInfo != null && _CurrentSingleSourceInfo.SourceDevice is IInUseTracking)
(_CurrentSingleSourceInfo.SourceDevice as IInUseTracking).InUseTracker.AddUser(this, "control");
if (handler != null)
handler(this, _CurrentSingleSourceInfo, ChangeType.DidChange);
}
}
SourceListItem _CurrentSingleSourceInfo;
public SourceListItem Display1SourceInfo
{
get { return _Display1SourceInfo; }
set
{
if (value == _Display1SourceInfo) return;
var handler = CurrentDisplay1SourceChange;
if (handler != null)
handler(this, _Display1SourceInfo, ChangeType.WillChange);
_Display1SourceInfo = value;
if (handler != null)
handler(this, _Display1SourceInfo, ChangeType.DidChange);
}
}
SourceListItem _Display1SourceInfo;
public SourceListItem Display2SourceInfo
{
get { return _Display2SourceInfo; }
set
{
if (value == _Display2SourceInfo) return;
var handler = CurrentDisplay2SourceChange;
if (handler != null)
handler(this, _Display2SourceInfo, ChangeType.WillChange);
_Display2SourceInfo = value;
if (handler != null)
handler(this, _Display2SourceInfo, ChangeType.DidChange);
}
}
SourceListItem _Display2SourceInfo;
/// <summary>
/// If an audio dialer is available for this room
/// </summary>
public bool HasAudioDialer { get { return false; } }
/// <summary>
///
/// </summary>
/// <param name="key"></param>
/// <param name="name"></param>
public EssentialsPresentationRoom(string key, string name,
Dictionary<uint, IRoutingSinkNoSwitching> displays,
IBasicVolumeWithFeedback defaultVolume, EssentialsPresentationRoomPropertiesConfig config)
: base(key, name)
{
Config = config;
Displays = displays;
DefaultVolumeControls = defaultVolume;
CurrentVolumeControls = defaultVolume;
//DefaultAudioDevice = defaultAudio;
//if (defaultAudio is IBasicVolumeControls)
// DefaultVolumeControls = defaultAudio as IBasicVolumeControls;
//else if (defaultAudio is IHasVolumeDevice)
// DefaultVolumeControls = (defaultAudio as IHasVolumeDevice).VolumeDevice;
SourceListKey = "default";
EnablePowerOnToLastSource = true;
}
/// <summary>
/// Run the same source to all destinations
/// </summary>
/// <param name="sourceItem"></param>
public void RouteSourceToAllDestinations(SourceListItem sourceItem)
{
if (Config.Volumes.Master != null)
{
var audioDev = DeviceManager.GetDeviceForKey(Config.Volumes.Master.DeviceKey);
if (audioDev is IBasicVolumeWithFeedback)
{
}
}
foreach (var display in Displays.Values)
{
if (sourceItem != null)
DoVideoRoute(sourceItem.SourceKey, display.Key);
else
DoVideoRoute("$off", display.Key);
}
Display1SourceInfo = sourceItem;
Display2SourceInfo = sourceItem;
CurrentSingleSourceInfo = sourceItem;
OnFeedback.FireUpdate();
}
public void SourceToDisplay1(SourceListItem sourceItem)
{
DoVideoRoute(sourceItem.SourceKey, Displays[1].Key);
Display1SourceInfo = sourceItem;
OnFeedback.FireUpdate();
}
public void SourceToDisplay2(SourceListItem sourceItem)
{
DoVideoRoute(sourceItem.SourceKey, Displays[2].Key);
Display2SourceInfo = sourceItem;
OnFeedback.FireUpdate();
}
/// <summary>
/// Basic source -> destination routing
/// </summary>
void DoVideoRoute(string sourceKey, string destinationKey)
{
new CTimer(o =>
{
var dest = DeviceManager.GetDeviceForKey(destinationKey) as IRoutingSinkNoSwitching;
if (dest == null)
{
Debug.Console(1, this, "Cannot route. Destination '{0}' not found", destinationKey);
return;
}
// off is special case
if (sourceKey.Equals("$off", StringComparison.OrdinalIgnoreCase))
{
dest.ReleaseRoute();
if (dest is IPower)
(dest as IPower).PowerOff();
return;
}
var source = DeviceManager.GetDeviceForKey(sourceKey) as IRoutingOutputs;
if (source == null)
{
Debug.Console(1, this, "Cannot route. Source '{0}' not found", sourceKey);
return;
}
dest.ReleaseAndMakeRoute(source, eRoutingSignalType.Video);
}, 0);
}
/// <summary>
///
/// </summary>
protected override void EndShutdown()
{
RunRouteAction("roomoff");
}
/// <summary>
///
/// </summary>
/// <param name="routeKey"></param>
public void RunRouteAction(string routeKey)
{
RunRouteAction(routeKey, null);
}
/// <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(1, this, "Run room 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);
// Let's run it
if (routeKey.ToLower() != "roomoff")
LastSourceKey = routeKey;
foreach (var route in item.RouteList)
{
// if there is a $defaultAll on route, run two separate
if (route.DestinationKey.Equals("$defaultAll", StringComparison.OrdinalIgnoreCase))
{
var tempAudio = new SourceRouteListItem
{
DestinationKey = "$defaultDisplay",
SourceKey = route.SourceKey,
Type = eRoutingSignalType.Video
};
DoRoute(tempAudio);
var tempVideo = new SourceRouteListItem
{
DestinationKey = "$defaultAudio",
SourceKey = route.SourceKey,
Type = eRoutingSignalType.Audio
};
DoRoute(tempVideo);
continue;
}
else
DoRoute(route);
}
// Set volume control on room, 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;
}
CurrentVolumeControls = volDev;
// store the name and UI info for routes
if (item.SourceKey != null)
CurrentSingleSourceInfo = 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 void PowerOnToDefaultOrLastSource()
{
if (!EnablePowerOnToLastSource || LastSourceKey == null)
return;
RunRouteAction(LastSourceKey);
}
/// <summary>
/// Does what it says
/// </summary>
public override void SetDefaultLevels()
{
Debug.Console(0, this, "SetDefaultLevels not implemented");
}
/// <summary>
///
/// </summary>
/// <param name="route"></param>
/// <returns></returns>
bool DoRoute(SourceRouteListItem route)
{
IRoutingSinkNoSwitching 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 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
}
}
}

View File

@@ -0,0 +1,272 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Crestron.SimplSharp;
using PepperDash.Core;
using PepperDash.Essentials.Core;
using PepperDash.Essentials.Devices.Common.Occupancy;
namespace PepperDash.Essentials
{
/// <summary>
///
/// </summary>
public interface IHasCurrentSourceInfoChange
{
event SourceInfoChangeHandler CurrentSingleSourceChange;
}
/// <summary>
///
/// </summary>
public abstract class EssentialsRoomBase : Device
{
/// <summary>
///
/// </summary>
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; }
protected abstract Func<bool> IsWarmingFeedbackFunc { get; }
protected abstract Func<bool> IsCoolingFeedbackFunc { get; }
/// <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 PepperDash.Essentials.Room.EssentialsRoomEmergencyBase Emergency { get; set; }
public PepperDash.Essentials.Devices.Common.Microphones.MicrophonePrivacyController MicrophonePrivacy { get; set; }
public string LogoUrl { 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; }
/// <summary>
///
/// </summary>
/// <param name="key"></param>
/// <param name="name"></param>
public EssentialsRoomBase(string key, string name) : base(key, name)
{
// 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);
}
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, "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();
}
public void StartRoomVacancyTimer(eVacancyMode mode)
{
if (mode == eVacancyMode.None)
RoomVacancyShutdownTimer.SecondsToCount = RoomVacancyShutdownPromptSeconds;
else if (mode == eVacancyMode.InInitialVacancy)
RoomVacancyShutdownTimer.SecondsToCount = RoomVacancyShutdownSeconds;
VacancyMode = mode;
RoomVacancyShutdownTimer.Start();
Debug.Console(0, this, "Vacancy Timer Started.");
}
/// <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;
}
// If status provider is fusion, set flag to remote
if (statusProvider is PepperDash.Essentials.Fusion.EssentialsHuddleSpaceFusionSystemControllerBase)
OccupancyStatusProviderIsRemote = true;
if(timeoutMinutes > 0)
RoomVacancyShutdownSeconds = timeoutMinutes * 60;
RoomOccupancy = statusProvider;
RoomOccupancy.RoomIsOccupiedFeedback.OutputChange += RoomIsOccupiedFeedback_OutputChange;
}
void RoomIsOccupiedFeedback_OutputChange(object sender, EventArgs e)
{
if (RoomOccupancy.RoomIsOccupiedFeedback.BoolValue == false)
{
Debug.Console(1, this, "Notice: Vacancy Detected");
// Trigger the timer when the room is vacant
StartRoomVacancyTimer(eVacancyMode.InInitialVacancy);
}
else
{
Debug.Console(1, this, "Notice: Occupancy Detected");
// Reset the timer when the room is occupied
RoomVacancyShutdownTimer.Cancel();
}
}
//void SwapVolumeDevices(IBasicVolumeControls currentDevice, IBasicVolumeControls newDevice)
//{
//}
/// <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
}
}