Compare commits

..

39 Commits

Author SHA1 Message Date
Andrew Welker
50aafb088e Merge branch 'development' into hotfix/mockvc-fixes 2021-08-27 10:11:47 -06:00
Neil Dorin
bfd383dfc7 fix(essentials): Minor fixes for MockVc to make behavior more consistent with real hardware 2021-08-27 09:48:43 -06:00
Andrew Welker
b853e8ed37 Merge pull request #808 from PepperDash/hotfix/4series-cultureinfo-for-time-formats-and-dm-4kz-fix
Hotfix/4series cultureinfo for time formats and dm 4kz fix
2021-08-26 18:15:18 -06:00
Andrew Welker
60c2d4df01 Merge branch 'development' into hotfix/4series-cultureinfo-for-time-formats-and-dm-4kz-fix 2021-08-26 17:59:32 -06:00
Neil Dorin
8ab87af859 Merge pull request #807 from PepperDash/hotfix/4series-cultureinfo-for-time-formats-and-dm-4kz-fix 2021-08-26 17:52:07 -06:00
Neil Dorin
47035d8386 fix(essentials): Attempt to catch case where meeting popup may not be dismissed if the room is on and the meeting is no longer joinable 2021-08-26 17:38:49 -06:00
Neil Dorin
c84ec4c899 fix(essentials): #806 switches method to print times for consistent 12h format
fix(essentials): #806 Updates more uses of ToShortTimeString()

fix(essentials): #806 fixes for VideoCodecUIDriver

fix(essentials): #806 final fixes for time format
2021-08-26 17:20:04 -06:00
Neil Dorin
4444328600 fix(essentials): #804 #805 Updates to prevent attempting to access null AudioSourceFeedback property on 4kz TX models 2021-08-26 16:48:56 -06:00
Andrew Welker
0d3eb42495 Merge pull request #803 from PepperDash/hotfix/add-IPasswordPrompt
Hotfix/add i password prompt
2021-08-20 17:06:21 -06:00
Neil Dorin
540a00861c fix(essentials): Adds missing file in .csproj 2021-08-19 16:02:24 -06:00
Neil Dorin
0014dd7a14 feat(essentials): #801 Adds IHasStartMeeting interface and implments on ZoomRoom 2021-08-19 15:19:19 -06:00
Neil Dorin
f922b871a1 refactor(essentials): Switches from zoom specific contact class to generic InvitableDirectoryContact class 2021-08-19 14:57:00 -06:00
Neil Dorin
b2331fa1e5 feat(essentials): Adds IsInvitableContact property with getter to DirectoryContact 2021-08-19 14:14:14 -06:00
Neil Dorin
8bf4b0d568 fix(essentails): Increase phonebook list limit to 10000 2021-08-19 12:49:11 -06:00
Neil Dorin
621205e65c fix(essentials): Hides password prompt on successful call connection 2021-08-19 12:04:11 -06:00
Neil Dorin
62fcf3856f fix(essentials): Minor update to clear out previous password text when displaying password prompt 2021-08-19 09:37:21 -06:00
Neil Dorin
dad986414c feat(essentials): Updated EssentialsVideoCodecUIDriver to display password prompt when joining password protected meeting 2021-08-18 17:55:04 -06:00
Andrew Welker
55766b21ba Merge pull request #799 from PepperDash/hotfix/room-method-updates
Hotfix/room method updates
2021-08-18 16:17:23 -06:00
Andrew Welker
21bc6a05de Merge branch 'development' into hotfix/room-method-updates 2021-08-18 16:05:46 -06:00
Neil Dorin
f298b5cc41 feat(essentials): Implements IPasswordPrompt on ZoomRoom 2021-08-18 14:45:16 -06:00
Neil Dorin
f8129fe7ae feat(essentials): #800 adds public access modifier on properties 2021-08-18 13:35:48 -06:00
Neil Dorin
dbdaedcca3 feat(essentials): #800 Adds IPasswordPrompt 2021-08-18 13:25:26 -06:00
Neil Dorin
893950d8c4 Merge pull request #798 from PepperDash/hotfix/room-method-updates 2021-08-18 08:30:53 -06:00
Andrew Welker
b780351bf0 Merge branch 'main' into hotfix/room-method-updates 2021-08-18 07:38:11 -06:00
Andrew Welker
6a1671aae1 ci: Remove PR trigger 2021-08-17 22:25:18 -06:00
Andrew Welker
9a1a23c88a fix: Instantiate Availability class when 2021-08-17 22:23:41 -06:00
Andrew Welker
3c352bbd20 Merge pull request #795 from PepperDash/hotfix/sg-ui-issue
Hotfix/sg UI issue
2021-08-17 22:04:56 -06:00
Andrew Welker
8ab3e45d96 Merge branch 'development' into hotfix/sg-ui-issue 2021-08-17 21:49:16 -06:00
Andrew Welker
11e5123fdf Merge pull request #790 from PepperDash/hotfix/zoomroom-duplicate-participant-in-list
Hotfix/zoomroom duplicate participant in list
2021-08-17 21:49:03 -06:00
Andrew Welker
2e4bb7466c Merge pull request #794 from PepperDash/hotfix/sg-ui-issue
fix(essentials): #792 refactors logic to show/hide SelectASourceVisible subpage
2021-08-17 21:48:50 -06:00
Neil Dorin
36a41ac477 fix(essentials): #792 refactors logic to show/hide SelectASourceVisible subpage 2021-08-17 18:00:41 -06:00
Andrew Welker
92f4d37cd6 refactor: Clean up Room Interfaces to help with ambiguities 2021-08-17 16:54:02 -06:00
Andrew Welker
b9479bab70 refactor: Rename Initialize to InitializeRoom 2021-08-17 16:54:01 -06:00
Andrew Welker
c6d10ba87e Merge branch 'development' into hotfix/zoomroom-duplicate-participant-in-list 2021-08-17 16:52:52 -06:00
Andrew Welker
fd94a94ee9 Merge pull request #789 from PepperDash/hotfix/zoomroom-duplicate-participant-in-list
Hotfix/zoomroom duplicate participant in list
2021-08-17 16:26:18 -06:00
Jason DeVito
3fa2954ca0 style: Updated formatting for ZoomRoom.cs and IHasParticipants.cs 2021-08-17 16:46:24 -05:00
Jason DeVito
c4f6afa412 Fixed debug references used for call status that were printing Status.Call.Sharing.State. Added GetCurrentCallParticipants method to referesh participant list. Updated UpdateCallStatus to resolve issue with duplicate participants when admitted from the waiting room. 2021-08-17 15:56:57 -05:00
Jason DeVito
6bdda5451b Updated UpdateCallStatus method to fix call status references previously looking at Status.Call.Sharing.State. Added else statement to 'if(ActiveCalls.Count == 0)' used to cleanup after calls that refreshs the participant list. Added GetCurrentCallParticipant method used to poll the participant list. 2021-08-17 15:14:02 -05:00
Andrew Welker
3ee8c07ecd Merge pull request #786 from PepperDash/hotfix/IMobileControl3
feat(essentials): Adds IMobileControl3 interface to maintain backwards compatibility
2021-08-16 15:06:00 -06:00
46 changed files with 1943 additions and 2505 deletions

View File

@@ -8,12 +8,9 @@ on:
- bugfix/*
- release/*
- development
pull_request:
branches:
- development
env:
# solution path doesn't need slashes unless there it is multiple folders deep
# solution path doesn't need slashes unless it is multiple folders deep
# solution name does not include extension. .sln is assumed
SOLUTION_PATH: PepperDashEssentials
SOLUTION_FILE: PepperDashEssentials

View File

@@ -489,11 +489,8 @@ namespace PepperDash.Essentials
{
DeviceManager.AddDevice(room);
if (!(room is EssentialsCombinedHuddleVtc1Room))
{
Debug.Console(0, Debug.ErrorLogLevel.Notice, "Room is EssentialsHuddleVtc1Room, attempting to add to DeviceManager with Fusion with IP-ID {0:X2}", fusionIpId);
DeviceManager.AddDevice(new EssentialsHuddleVtc1FusionController((IEssentialsHuddleVtc1Room)room, fusionIpId, fusionJoinMapKey));
}
Debug.Console(0, Debug.ErrorLogLevel.Notice, "Room is EssentialsHuddleVtc1Room, attempting to add to DeviceManager with Fusion with IP-ID {0:X2}", fusionIpId);
DeviceManager.AddDevice(new EssentialsHuddleVtc1FusionController((IEssentialsHuddleVtc1Room)room, fusionIpId, fusionJoinMapKey));
Debug.Console(0, Debug.ErrorLogLevel.Notice, "Attempting to build Mobile Control Bridge...");

View File

@@ -144,7 +144,6 @@
<Compile Include="Room\Config\EssentialsRoomEmergencyConfig.cs" />
<Compile Include="Room\Config\EssentialsTechRoomConfig.cs" />
<Compile Include="Room\Emergency\EsentialsRoomEmergencyContactClosure.cs" />
<Compile Include="Room\Types\EssentialsCombinedHuddleVtc1Room.cs" />
<Compile Include="Room\Types\EssentialsDualDisplayRoom.cs" />
<Compile Include="Room\Types\EssentialsHuddleVtc1Room.cs" />
<Compile Include="Room\Types\EssentialsNDisplayRoomBase.cs" />

View File

@@ -1,7 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<ControlSystem>
<Name>Test RMC3</Name>
<Address>auto 192.168.1.40;username crestron</Address>
<Name>192.168.10.1</Name>
<Address>auto 192.168.10.1</Address>
<ProgramSlot>Program01</ProgramSlot>
<Storage>Internal Flash</Storage>
</ControlSystem>

View File

@@ -39,10 +39,6 @@ namespace PepperDash.Essentials.Room.Config
{
return new EssentialsDualDisplayRoom(roomConfig);
}
if (typeName == "combinedhuddlevtc1")
{
return new EssentialsCombinedHuddleVtc1Room(roomConfig);
}
return typeName != "techroom" ? null : new EssentialsTechRoom(roomConfig);
}
@@ -187,12 +183,6 @@ namespace PepperDash.Essentials.Room.Config
[JsonProperty("zeroVolumeWhenSwtichingVolumeDevices")]
public bool ZeroVolumeWhenSwtichingVolumeDevices { get; set; }
/// <summary>
/// Indicates if this room represents a combination of other rooms
/// </summary>
[JsonProperty("isRoomCombinationScenario")]
public bool IsRoomCombinationScenario { get; set; }
public EssentialsRoomPropertiesConfig()
{
LogoLight = new EssentialsLogoPropertiesConfig();

View File

@@ -1,821 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Crestron.SimplSharp;
using Newtonsoft.Json;
using PepperDash.Core;
using PepperDash.Essentials.Core;
using PepperDash.Essentials.Core.Config;
using PepperDash.Essentials.Room.Config;
using PepperDash.Essentials.Devices.Common.Codec;
using PepperDash.Essentials.Devices.Common.VideoCodec;
using PepperDash.Essentials.Devices.Common.AudioCodec;
using PepperDash.Essentials.Core.DeviceTypeInterfaces;
namespace PepperDash.Essentials
{
public class EssentialsCombinedHuddleVtc1Room : EssentialsRoomBase, IEssentialsHuddleVtc1Room
{
private bool _codecExternalSourceChange;
public event EventHandler<VolumeDeviceChangeEventArgs> CurrentVolumeDeviceChange;
public event SourceInfoChangeHandler CurrentSourceChange;
//************************
// 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 displays = Displays.OfType<DisplayBase>().ToList();
var val = CurrentSourceInfo != null
&& CurrentSourceInfo.Type == eSourceListItemType.Route
&& displays.Count > 0;
//&& disp.PowerIsOnFeedback.BoolValue;
return val;
};
}
}
/// <summary>
///
/// </summary>
protected override Func<bool> IsWarmingFeedbackFunc
{
get
{
return () => Displays.OfType<TwoWayDisplayBase>().Any((d) => d.IsWarmingUpFeedback.BoolValue);
}
}
/// <summary>
///
/// </summary>
protected override Func<bool> IsCoolingFeedbackFunc
{
get
{
return () => Displays.OfType<TwoWayDisplayBase>().Any((d) => d.IsCoolingDownFeedback.BoolValue);
}
}
public EssentialsConferenceRoomPropertiesConfig PropertiesConfig { get; private set; }
private List<IRoutingSinkWithSwitching> Displays;
public IRoutingSinkWithSwitching DefaultDisplay { get; private set; }
public IBasicVolumeControls DefaultAudioDevice { get; private set; }
public IBasicVolumeControls DefaultVolumeControls { get; private set; }
public VideoCodecBase VideoCodec { get; private set; }
public AudioCodecBase AudioCodec { get; private set; }
public bool ExcludeFromGlobalFunctions { get; set; }
public string DefaultSourceItem { get; set; }
public ushort DefaultVolume { get; set; }
/// <summary>
/// If room is off, enables power on to last source. Default true
/// </summary>
public bool EnablePowerOnToLastSource { get; set; }
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; }
set
{
if (value == _CurrentSourceInfo) return;
var handler = CurrentSourceChange;
// remove from in-use tracker, if so equipped
if (_CurrentSourceInfo != null && _CurrentSourceInfo.SourceDevice is IInUseTracking)
(_CurrentSourceInfo.SourceDevice as IInUseTracking).InUseTracker.RemoveUser(this, "control");
if (handler != null)
handler(_CurrentSourceInfo, ChangeType.WillChange);
_CurrentSourceInfo = value;
// add to in-use tracking
if (_CurrentSourceInfo != null && _CurrentSourceInfo.SourceDevice is IInUseTracking)
(_CurrentSourceInfo.SourceDevice as IInUseTracking).InUseTracker.AddUser(this, "control");
if (handler != null)
handler(_CurrentSourceInfo, ChangeType.DidChange);
var vc = VideoCodec as IHasExternalSourceSwitching;
if (vc != null && !_codecExternalSourceChange)
{
vc.SetSelectedSource(CurrentSourceInfoKey);
}
_codecExternalSourceChange = false;
}
}
SourceListItem _CurrentSourceInfo;
public string CurrentSourceInfoKey { get; 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();
public EssentialsCombinedHuddleVtc1Room(DeviceConfig config)
: base(config)
{
try
{
PropertiesConfig = JsonConvert.DeserializeObject<EssentialsConferenceRoomPropertiesConfig>
(config.Properties.ToString());
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;
Displays = new List<IRoutingSinkWithSwitching>();
Initialize();
}
catch (Exception e)
{
Debug.Console(1, this, "Error building room: \n{0}", e);
}
}
void Initialize()
{
try
{
if (DefaultAudioDevice is IBasicVolumeControls)
DefaultVolumeControls = DefaultAudioDevice as IBasicVolumeControls;
else if (DefaultAudioDevice is IHasVolumeDevice)
DefaultVolumeControls = (DefaultAudioDevice as IHasVolumeDevice).VolumeDevice;
CurrentVolumeControls = DefaultVolumeControls;
// 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;
});
SetupDisplays();
// Get Microphone Privacy object, if any MUST HAPPEN AFTER setting InCallFeedback
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.");
VideoCodec.CallStatusChange += (o, a) => this.InCallFeedback.FireUpdate();
VideoCodec.IsReadyChange += (o, a) => { this.SetCodecExternalSources(); SetCodecBranding(); };
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);
SetSourceListKey();
EnablePowerOnToLastSource = true;
}
catch (Exception e)
{
Debug.Console(0, this, "Error Initializing Room: {0}", e);
}
}
private void SetupDisplays()
{
//DefaultDisplay = DeviceManager.GetDeviceForKey(PropertiesConfig.DefaultDisplayKey) as IRoutingSinkWithSwitching;
var destinationList = ConfigReader.ConfigObject.DestinationLists[PropertiesConfig.DestinationListKey];
foreach (var destination in destinationList)
{
var dest = destination.Value.SinkDevice as IRoutingSinkWithSwitching;
if (dest != null)
{
Displays.Add(dest);
}
var display = dest as DisplayBase;
if (display != null)
{
// Link power, warming, cooling to display
var dispTwoWay = display as IHasPowerControlWithFeedback;
if (dispTwoWay != null)
{
dispTwoWay.PowerIsOnFeedback.OutputChange += (o, a) =>
{
if (dispTwoWay.PowerIsOnFeedback.BoolValue != OnFeedback.BoolValue)
{
//if (!dispTwoWay.PowerIsOnFeedback.BoolValue)
// CurrentSourceInfo = null;
OnFeedback.FireUpdate();
}
if (dispTwoWay.PowerIsOnFeedback.BoolValue)
{
SetDefaultLevels();
}
};
}
display.IsWarmingUpFeedback.OutputChange += (o, a) =>
{
IsWarmingUpFeedback.FireUpdate();
if (!IsWarmingUpFeedback.BoolValue)
(CurrentVolumeControls as IBasicVolumeWithFeedback).SetVolume(DefaultVolume);
};
display.IsCoolingDownFeedback.OutputChange += (o, a) =>
{
IsCoolingDownFeedback.FireUpdate();
};
}
}
}
private void SetSourceListKey()
{
if (!string.IsNullOrEmpty(PropertiesConfig.SourceListKey))
{
SetSourceListKey(PropertiesConfig.SourceListKey);
}
else
{
SetSourceListKey(Key);
}
SetCodecExternalSources();
}
protected override void CustomSetConfig(DeviceConfig config)
{
var newPropertiesConfig = JsonConvert.DeserializeObject<EssentialsConferenceRoomPropertiesConfig>(config.Properties.ToString());
if (newPropertiesConfig != null)
PropertiesConfig = newPropertiesConfig;
ConfigWriter.UpdateRoomConfig(config);
}
public override bool CustomActivate()
{
// Add Occupancy object from config
if (PropertiesConfig.Occupancy != null)
{
Debug.Console(0, this, Debug.ErrorLogLevel.Notice, "Setting Occupancy Provider for room");
this.SetRoomOccupancy(DeviceManager.GetDeviceForKey(PropertiesConfig.Occupancy.DeviceKey) as
IOccupancyStatusProvider, PropertiesConfig.Occupancy.TimeoutMinutes);
}
this.LogoUrlLightBkgnd = PropertiesConfig.LogoLight.GetLogoUrlLight();
this.LogoUrlDarkBkgnd = PropertiesConfig.LogoDark.GetLogoUrlDark();
this.DefaultSourceItem = PropertiesConfig.DefaultSourceItem;
this.DefaultVolume = (ushort)(PropertiesConfig.Volumes.Master.Level * 65535 / 100);
return base.CustomActivate();
}
/// <summary>
///
/// </summary>
protected override void EndShutdown()
{
VideoCodec.EndAllCalls();
SetDefaultLevels();
RunDefaultPresentRoute();
CrestronEnvironment.Sleep(1000);
Debug.Console(0, this, Debug.ErrorLogLevel.Notice, "Shutting down room");
RunRouteAction("roomOff");
VideoCodec.StopSharing();
VideoCodec.StandbyActivate();
}
/// <summary>
/// Routes the default source item, if any. Returns true when default route exists
/// </summary>
public override 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;
}
public void RunRouteActionCodec(string routeKey, string sourceListKey)
{
_codecExternalSourceChange = true;
RunRouteAction(routeKey, sourceListKey);
}
/// <summary>
///
/// </summary>
/// <param name="routeKey"></param>
public void RunRouteAction(string routeKey)
{
RunRouteAction(routeKey, new Action(() => { }));
}
/// <summary>
///
/// </summary>
/// <param name="routeKey"></param>
/// <param name="souceListKey"></param>
/// <param name="successCallback"></param>
public void RunRouteAction(string routeKey, string sourceListKey)
{
if (string.IsNullOrEmpty(sourceListKey))
{
Debug.Console(1, this, "No sourceListKey present. RunRouteAction assumes default source list.");
RunRouteAction(routeKey, new Action(() => { }));
}
else
{
Debug.Console(1, this, "sourceListKey present but not yet implemented");
throw new NotImplementedException();
}
}
/// <summary>
///
/// </summary>
/// <param name="routeKey"></param>
/// <param name="souceListKey"></param>
/// <param name="successCallback"></param>
public void RunRouteAction(string routeKey, string sourceListKey, Action successCallback)
{
if (string.IsNullOrEmpty(sourceListKey))
{
RunRouteAction(routeKey, successCallback);
}
else
throw new NotImplementedException();
}
/// <summary>
/// Gets a source from config list SourceListKey and dynamically build and executes the
/// route or commands
/// </summary>
/// <param name="name"></param>
public void RunRouteAction(string routeKey, Action successCallback)
{
// Run this on a separate thread
new CTimer(o =>
{
// try to prevent multiple simultaneous selections
SourceSelectLock.TryEnter();
try
{
Debug.Console(0, this, Debug.ErrorLogLevel.Notice, "Run route action '{0}'", routeKey);
var dict = ConfigReader.ConfigObject.GetSourceListForKey(SourceListKey);
if (dict == null)
{
Debug.Console(1, this, "WARNING: Config source list '{0}' not found", SourceListKey);
return;
}
// Try to get the list item by it's string key
if (!dict.ContainsKey(routeKey))
{
Debug.Console(1, this, "WARNING: No item '{0}' found on config list '{1}'",
routeKey, SourceListKey);
return;
}
// 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();
if (OnFeedback.BoolValue)
{
if (VideoCodec.UsageTracker.InUseTracker.InUseFeedback.BoolValue)
{
Debug.Console(1, this, "Video Codec in use, deactivating standby on codec");
VideoCodec.StandbyDeactivate();
}
if (VideoCodec.StandbyIsOnFeedback.BoolValue)
{
VideoCodec.StandbyDeactivate();
}
else
{
Debug.Console(1, this, "Video codec not in standby. No need to wake.");
}
}
else
{
Debug.Console(1, this, "Room OnFeedback state: {0}", OnFeedback.BoolValue);
}
// 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))
{
foreach (var display in Displays)
{
var tempVideo = new SourceRouteListItem
{
DestinationKey = display.Key,
SourceKey = route.SourceKey,
Type = eRoutingSignalType.Video
};
DoRoute(tempVideo);
}
}
else
DoRoute(route);
}
/// <summary>
///
/// </summary>
/// <param name="route"></param>
/// <returns></returns>
bool DoRoute(SourceRouteListItem route)
{
IRoutingSink dest = null;
if (route.DestinationKey.Equals("$defaultaudio", StringComparison.OrdinalIgnoreCase))
dest = DefaultAudioDevice as IRoutingSink;
//else if (route.DestinationKey.Equals("$defaultDisplay", StringComparison.OrdinalIgnoreCase))
// dest = DefaultDisplay;
else
dest = DeviceManager.GetDeviceForKey(route.DestinationKey) as IRoutingSink;
if (dest == null)
{
Debug.Console(1, this, "Cannot route, unknown destination '{0}'", route.DestinationKey);
return false;
}
if (route.SourceKey.Equals("$off", StringComparison.OrdinalIgnoreCase))
{
dest.ReleaseRoute();
if (dest is IHasPowerControl)
(dest as IHasPowerControl).PowerOff();
}
else
{
var source = DeviceManager.GetDeviceForKey(route.SourceKey) as IRoutingOutputs;
if (source == null)
{
Debug.Console(1, this, "Cannot route unknown source '{0}' to {1}", route.SourceKey, route.DestinationKey);
return false;
}
dest.ReleaseAndMakeRoute(source, route.Type);
}
return true;
}
public override void RoomVacatedForTimeoutPeriod(object o)
{
//Implement this
}
/// <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 override 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 IEssentialsRoom && !(d as IEssentialsHuddleSpaceRoom).ExcludeFromGlobalFunctions);
foreach (var room in allRooms)
(room as IEssentialsHuddleSpaceRoom).RunRouteAction("roomOff");
}
/// <summary>
/// Setup the external sources for the Cisco Touch 10 devices that support IHasExternalSourceSwitch
/// </summary>
private void SetCodecExternalSources()
{
var videoCodecWithExternalSwitching = VideoCodec as IHasExternalSourceSwitching;
if (videoCodecWithExternalSwitching == null || !videoCodecWithExternalSwitching.ExternalSourceListEnabled)
{
return;
}
try
{
// Get the tie line that the external switcher is connected to
string codecInputConnectorName = ConfigReader.ConfigObject.TieLines.SingleOrDefault(
x => x.DestinationKey == VideoCodec.Key && x.DestinationPort == videoCodecWithExternalSwitching.ExternalSourceInputPort).DestinationPort;
videoCodecWithExternalSwitching.ClearExternalSources();
videoCodecWithExternalSwitching.RunRouteAction = RunRouteActionCodec;
var srcList = ConfigReader.ConfigObject.SourceLists.SingleOrDefault(x => x.Key == SourceListKey).Value.OrderBy(kv => kv.Value.Order); ;
foreach (var kvp in srcList)
{
var srcConfig = kvp.Value;
if (kvp.Key != DefaultCodecRouteString && kvp.Key != "roomOff")
{
videoCodecWithExternalSwitching.AddExternalSource(codecInputConnectorName, kvp.Key, srcConfig.PreferredName, PepperDash.Essentials.Devices.Common.VideoCodec.Cisco.eExternalSourceType.desktop);
videoCodecWithExternalSwitching.SetExternalSourceState(kvp.Key, PepperDash.Essentials.Devices.Common.VideoCodec.Cisco.eExternalSourceMode.Ready);
}
}
}
catch (Exception e)
{
Debug.Console(2, this, "Error setting codec external sources: {0}", e);
}
}
private void SetCodecBranding()
{
var vcWithBranding = VideoCodec as IHasBranding;
if (vcWithBranding == null) return;
Debug.Console(1, this, "Setting Codec Branding");
vcWithBranding.InitializeBranding(Key);
}
#region IPrivacy Members
public void PrivacyModeOff()
{
VideoCodec.PrivacyModeOff();
}
public void PrivacyModeOn()
{
VideoCodec.PrivacyModeOn();
}
public void PrivacyModeToggle()
{
VideoCodec.PrivacyModeToggle();
}
#endregion
}
}

View File

@@ -207,7 +207,7 @@ namespace PepperDash.Essentials
DefaultAudioDevice = DeviceManager.GetDeviceForKey(PropertiesConfig.DefaultAudioKey) as IBasicVolumeControls;
Initialize();
InitializeRoom();
}
catch (Exception e)
{
@@ -215,7 +215,7 @@ namespace PepperDash.Essentials
}
}
void Initialize()
void InitializeRoom()
{
if (DefaultAudioDevice is IBasicVolumeControls)
DefaultVolumeControls = DefaultAudioDevice as IBasicVolumeControls;

View File

@@ -156,7 +156,7 @@ namespace PepperDash.Essentials
DefaultAudioDevice = DeviceManager.GetDeviceForKey(PropertiesConfig.DefaultAudioKey) as IRoutingSinkWithSwitching;
Initialize();
InitializeRoom();
}
catch (Exception e)
{
@@ -164,7 +164,7 @@ namespace PepperDash.Essentials
}
}
void Initialize()
void InitializeRoom()
{
if (DefaultAudioDevice is IBasicVolumeControls)
DefaultVolumeControls = DefaultAudioDevice as IBasicVolumeControls;

View File

@@ -101,7 +101,7 @@ namespace PepperDash.Essentials
}
}
public EssentialsConferenceRoomPropertiesConfig PropertiesConfig { get; private set; }
public EssentialsHuddleVtc1PropertiesConfig PropertiesConfig { get; private set; }
public IRoutingSinkWithSwitching DefaultDisplay { get; private set; }
public IBasicVolumeControls DefaultAudioDevice { get; private set; }
@@ -210,7 +210,7 @@ namespace PepperDash.Essentials
{
PropertiesConfig = JsonConvert.DeserializeObject<EssentialsHuddleVtc1PropertiesConfig>
(config.Properties.ToString());
DefaultDisplay = DeviceManager.GetDeviceForKey((PropertiesConfig as EssentialsHuddleVtc1PropertiesConfig).DefaultDisplayKey) as IRoutingSinkWithSwitching;
DefaultDisplay = DeviceManager.GetDeviceForKey(PropertiesConfig.DefaultDisplayKey) as IRoutingSinkWithSwitching;
VideoCodec = DeviceManager.GetDeviceForKey(PropertiesConfig.VideoCodecKey) as
PepperDash.Essentials.Devices.Common.VideoCodec.VideoCodecBase;
@@ -226,7 +226,7 @@ namespace PepperDash.Essentials
DefaultAudioDevice = DeviceManager.GetDeviceForKey(PropertiesConfig.DefaultAudioKey) as IBasicVolumeControls;
Initialize();
InitializeRoom();
}
catch (Exception e)
{
@@ -234,7 +234,7 @@ namespace PepperDash.Essentials
}
}
void Initialize()
void InitializeRoom()
{
try
{

View File

@@ -0,0 +1,44 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Crestron.SimplSharp;
using PepperDash.Essentials.Core;
using PepperDash.Essentials.Core.DeviceTypeInterfaces;
using PepperDash.Essentials.Room.Config;
using PepperDash.Essentials.Core.Devices;
using PepperDash.Essentials.Devices.Common.Codec;
using PepperDash.Essentials.Devices.Common.VideoCodec;
using PepperDash.Essentials.Devices.Common.AudioCodec;
using PepperDash.Core;
namespace PepperDash.Essentials
{
public interface IEssentialsHuddleSpaceRoom : IEssentialsRoom, IHasCurrentSourceInfoChange, IRunRouteAction, IHasDefaultDisplay
{
bool ExcludeFromGlobalFunctions { get; }
void RunRouteAction(string routeKey);
EssentialsHuddleRoomPropertiesConfig PropertiesConfig { get; }
IBasicVolumeControls CurrentVolumeControls { get; }
event EventHandler<VolumeDeviceChangeEventArgs> CurrentVolumeDeviceChange;
}
public interface IEssentialsHuddleVtc1Room : IEssentialsRoom, IHasCurrentSourceInfoChange,
IHasCurrentVolumeControls, IRunRouteAction, IRunDefaultCallRoute, IHasVideoCodec, IHasAudioCodec, IHasDefaultDisplay
{
EssentialsHuddleVtc1PropertiesConfig PropertiesConfig { get; }
void RunRouteAction(string routeKey);
IHasScheduleAwareness ScheduleSource { get; }
string DefaultCodecRouteString { get; }
}
}

View File

@@ -10,9 +10,7 @@ namespace PepperDash.Essentials
public interface IEssentialsHuddleVtc1Room : IEssentialsRoom, IHasCurrentSourceInfoChange,
IPrivacy, IHasCurrentVolumeControls, IRunRouteAction, IRunDefaultCallRoute, IHasVideoCodec, IHasAudioCodec, IHasDefaultDisplay, IHasInCallFeedback
{
EssentialsConferenceRoomPropertiesConfig PropertiesConfig { get; }
bool ExcludeFromGlobalFunctions { get; }
EssentialsHuddleVtc1PropertiesConfig PropertiesConfig { get; }
void RunRouteAction(string routeKey);

View File

@@ -16,8 +16,6 @@ namespace PepperDash.Essentials
{
public class EssentialsTouchpanelController : EssentialsDevice, IHasBasicTriListWithSmartObject
{
private CrestronTouchpanelPropertiesConfig _propertiesConfig;
public BasicTriListWithSmartObject Panel { get; private set; }
public PanelDriverBase PanelDriver { get; private set; }
@@ -29,14 +27,7 @@ namespace PepperDash.Essentials
: base(key, name)
{
Panel = tsw;
if (!string.IsNullOrEmpty(sgdPath))
Panel.LoadSmartObjects(sgdPath);
else
Debug.Console(1, this, "No SGD file path defined");
tsw.LoadSmartObjects(sgdPath);
tsw.SigChange += Panel_SigChange;
}
@@ -46,7 +37,7 @@ namespace PepperDash.Essentials
Panel = dge;
if (!string.IsNullOrEmpty(sgdPath))
Panel.LoadSmartObjects(sgdPath);
dge.LoadSmartObjects(sgdPath);
else
Debug.Console(1, this, "No SGD file path defined");
@@ -59,7 +50,6 @@ namespace PepperDash.Essentials
public EssentialsTouchpanelController(string key, string name, string type, CrestronTouchpanelPropertiesConfig props, uint id)
: base(key, name)
{
_propertiesConfig = props;
Debug.Console(0, this, Debug.ErrorLogLevel.Notice, "Creating touchpanel hardware...");
type = type.ToLower();
@@ -71,8 +61,6 @@ namespace PepperDash.Essentials
app.ParameterProjectName.Value = props.ProjectName;
Panel = app;
}
else if (type == "xpanel")
Panel = new XpanelForSmartGraphics(id, Global.ControlSystem);
else if (type == "tsw550")
Panel = new Tsw550(id, Global.ControlSystem);
else if (type == "tsw552")
@@ -146,194 +134,10 @@ namespace PepperDash.Essentials
Panel.LoadSmartObjects(sgdName);
Panel.SigChange += Panel_SigChange;
AddPostActivationAction(() =>
{
// Check for IEssentialsRoomCombiner in DeviceManager and if found, subscribe to its event
var roomCombiner = DeviceManager.AllDevices.FirstOrDefault((d) => d is IEssentialsRoomCombiner) as IEssentialsRoomCombiner;
if (roomCombiner != null)
{
// Subscribe to the even
roomCombiner.RoomCombinationScenarioChanged += new EventHandler<EventArgs>(roomCombiner_RoomCombinationScenarioChanged);
// Connect to the initial roomKey
if (roomCombiner.CurrentScenario != null)
{
// Use the current scenario
DetermineRoomKeyFromScenario(roomCombiner.CurrentScenario);
}
else
{
// Current Scenario not yet set. Use default
SetupPanelDrivers(_propertiesConfig.DefaultRoomKey);
}
}
else
{
// No room combiner, use the default key
SetupPanelDrivers(_propertiesConfig.DefaultRoomKey);
}
});
}
void roomCombiner_RoomCombinationScenarioChanged(object sender, EventArgs e)
{
var roomCombiner = sender as IEssentialsRoomCombiner;
DetermineRoomKeyFromScenario(roomCombiner.CurrentScenario);
}
/// <summary>
/// Determines the room key to use based on the scenario
/// </summary>
/// <param name="scenario"></param>
void DetermineRoomKeyFromScenario(IRoomCombinationScenario scenario)
{
string newRoomKey = null;
if (scenario.UiMap.ContainsKey(Key))
{
newRoomKey = scenario.UiMap[Key];
}
else if (scenario.UiMap.ContainsKey(_propertiesConfig.DefaultRoomKey))
{
newRoomKey = scenario.UiMap[_propertiesConfig.DefaultRoomKey];
}
SetupPanelDrivers(newRoomKey);
}
/// <summary>
/// Sets up drivers and links them to the room specified
/// </summary>
/// <param name="roomKey">key of room to link the drivers to</param>
void SetupPanelDrivers(string roomKey)
{
// Clear out any existing actions
Panel.ClearAllSigActions();
Debug.Console(0, this, "Linking TP '{0}' to Room '{1}'", Key, roomKey);
var mainDriver = new EssentialsPanelMainInterfaceDriver(Panel, _propertiesConfig);
// Then the sub drivers
// spin up different room drivers depending on room type
var room = DeviceManager.GetDeviceForKey(roomKey);
if (room is IEssentialsHuddleSpaceRoom)
{
// Screen Saver Driver
mainDriver.ScreenSaverController = new ScreenSaverController(mainDriver, _propertiesConfig);
// Header Driver
Debug.Console(0, this, "Adding header driver");
mainDriver.HeaderDriver = new EssentialsHeaderDriver(mainDriver, _propertiesConfig);
// AV Driver
Debug.Console(0, this, "Adding huddle space AV driver");
var avDriver = new EssentialsHuddlePanelAvFunctionsDriver(mainDriver, _propertiesConfig);
avDriver.DefaultRoomKey = roomKey;
mainDriver.AvDriver = avDriver;
avDriver.CurrentRoom = room as IEssentialsHuddleSpaceRoom;
// Environment Driver
if (avDriver.CurrentRoom.PropertiesConfig.Environment != null && avDriver.CurrentRoom.PropertiesConfig.Environment.DeviceKeys.Count > 0)
{
Debug.Console(0, this, "Adding environment driver");
mainDriver.EnvironmentDriver = new EssentialsEnvironmentDriver(mainDriver, _propertiesConfig);
mainDriver.EnvironmentDriver.GetDevicesFromConfig(avDriver.CurrentRoom.PropertiesConfig.Environment);
}
mainDriver.HeaderDriver.SetupHeaderButtons(avDriver, avDriver.CurrentRoom);
if (Panel is TswFt5ButtonSystem)
{
var tsw = Panel as TswFt5ButtonSystem;
// Wire up hard keys
tsw.Power.UserObject = new Action<bool>(b => { if (!b) avDriver.PowerButtonPressed(); });
if (mainDriver.EnvironmentDriver != null)
tsw.Lights.UserObject = new Action<bool>(b =>
{
if (!b)
{
mainDriver.EnvironmentDriver.Toggle();
}
});
tsw.Up.UserObject = new Action<bool>(avDriver.VolumeUpPress);
tsw.Down.UserObject = new Action<bool>(avDriver.VolumeDownPress);
}
}
else if (room is IEssentialsHuddleVtc1Room)
{
Debug.Console(0, this, "Adding huddle space VTC AV driver");
// Screen Saver Driver
mainDriver.ScreenSaverController = new ScreenSaverController(mainDriver, _propertiesConfig);
// Header Driver
mainDriver.HeaderDriver = new EssentialsHeaderDriver(mainDriver, _propertiesConfig);
// AV Driver
var avDriver = new EssentialsHuddleVtc1PanelAvFunctionsDriver(mainDriver, _propertiesConfig);
var codecDriver = new PepperDash.Essentials.UIDrivers.VC.EssentialsVideoCodecUiDriver(Panel, avDriver,
(room as IEssentialsHuddleVtc1Room).VideoCodec, mainDriver.HeaderDriver);
avDriver.SetVideoCodecDriver(codecDriver);
avDriver.DefaultRoomKey = roomKey;
mainDriver.AvDriver = avDriver;
avDriver.CurrentRoom = room as IEssentialsHuddleVtc1Room;
// Environment Driver
if (avDriver.CurrentRoom.PropertiesConfig.Environment != null && avDriver.CurrentRoom.PropertiesConfig.Environment.DeviceKeys.Count > 0)
{
Debug.Console(0, this, "Adding environment driver");
mainDriver.EnvironmentDriver = new EssentialsEnvironmentDriver(mainDriver, _propertiesConfig);
mainDriver.EnvironmentDriver.GetDevicesFromConfig(avDriver.CurrentRoom.PropertiesConfig.Environment);
}
mainDriver.HeaderDriver.SetupHeaderButtons(avDriver, avDriver.CurrentRoom);
if (Panel is TswFt5ButtonSystem)
{
var tsw = Panel as TswFt5ButtonSystem;
// Wire up hard keys
tsw.Power.UserObject = new Action<bool>(b => { if (!b) avDriver.EndMeetingPress(); });
if (mainDriver.EnvironmentDriver != null)
tsw.Lights.UserObject = new Action<bool>(b =>
{
if (!b)
{
mainDriver.EnvironmentDriver.Toggle();
}
});
tsw.Up.UserObject = new Action<bool>(avDriver.VolumeUpPress);
tsw.Down.UserObject = new Action<bool>(avDriver.VolumeDownPress);
}
LoadAndShowDriver(mainDriver);
}
else
{
Debug.Console(0, this, "ERROR: Cannot load AvFunctionsDriver for room '{0}'", roomKey);
}
}
public void LoadAndShowDriver(PanelDriverBase driver)
{
if (PanelDriver != null)
{
var mainDriver = PanelDriver as EssentialsPanelMainInterfaceDriver;
if (mainDriver != null)
{
mainDriver.Dispose();
}
}
PanelDriver = driver;
driver.Show();
}
@@ -344,6 +148,7 @@ namespace PepperDash.Essentials
PanelDriver.BackButtonPressed();
}
void ExtenderSystemReservedSigs_DeviceExtenderSigChange(DeviceExtender currentDeviceExtender, SigEventArgs args)
{
// If the sig is transitioning on, mark it in case it was home button that transitioned it
@@ -420,6 +225,119 @@ namespace PepperDash.Essentials
var panelController = new EssentialsTouchpanelController(dc.Key, dc.Name, dc.Type, props, comm.IpIdInt);
panelController.AddPostActivationAction(() =>
{
var mainDriver = new EssentialsPanelMainInterfaceDriver(panelController.Panel, props);
// Then the sub drivers
// spin up different room drivers depending on room type
var room = DeviceManager.GetDeviceForKey(props.DefaultRoomKey);
if (room is IEssentialsHuddleSpaceRoom)
{
// Screen Saver Driver
mainDriver.ScreenSaverController = new ScreenSaverController(mainDriver, props);
// Header Driver
Debug.Console(0, panelController, "Adding header driver");
mainDriver.HeaderDriver = new EssentialsHeaderDriver(mainDriver, props);
// AV Driver
Debug.Console(0, panelController, "Adding huddle space AV driver");
var avDriver = new EssentialsHuddlePanelAvFunctionsDriver(mainDriver, props);
avDriver.DefaultRoomKey = props.DefaultRoomKey;
mainDriver.AvDriver = avDriver;
avDriver.CurrentRoom = room as IEssentialsHuddleSpaceRoom;
// Environment Driver
if (avDriver.CurrentRoom.PropertiesConfig.Environment != null && avDriver.CurrentRoom.PropertiesConfig.Environment.DeviceKeys.Count > 0)
{
Debug.Console(0, panelController, "Adding environment driver");
mainDriver.EnvironmentDriver = new EssentialsEnvironmentDriver(mainDriver, props);
mainDriver.EnvironmentDriver.GetDevicesFromConfig(avDriver.CurrentRoom.PropertiesConfig.Environment);
}
mainDriver.HeaderDriver.SetupHeaderButtons(avDriver, avDriver.CurrentRoom);
panelController.LoadAndShowDriver(mainDriver); // This is a little convoluted.
if (panelController.Panel is TswFt5ButtonSystem)
{
var tsw = panelController.Panel as TswFt5ButtonSystem;
// Wire up hard keys
tsw.Power.UserObject = new Action<bool>(b => { if (!b) avDriver.PowerButtonPressed(); });
//tsw.Home.UserObject = new Action<bool>(b => { if (!b) HomePressed(); });
if (mainDriver.EnvironmentDriver != null)
tsw.Lights.UserObject = new Action<bool>(b =>
{
if (!b)
{
//mainDriver.AvDriver.PopupInterlock.ShowInterlockedWithToggle(mainDriver.EnvironmentDriver.BackgroundSubpageJoin);
mainDriver.EnvironmentDriver.Toggle();
}
});
tsw.Up.UserObject = new Action<bool>(avDriver.VolumeUpPress);
tsw.Down.UserObject = new Action<bool>(avDriver.VolumeDownPress);
}
}
else if (room is IEssentialsHuddleVtc1Room)
{
Debug.Console(0, panelController, "Adding huddle space VTC AV driver");
// Screen Saver Driver
mainDriver.ScreenSaverController = new ScreenSaverController(mainDriver, props);
// Header Driver
mainDriver.HeaderDriver = new EssentialsHeaderDriver(mainDriver, props);
// AV Driver
var avDriver = new EssentialsHuddleVtc1PanelAvFunctionsDriver(mainDriver, props);
var codecDriver = new PepperDash.Essentials.UIDrivers.VC.EssentialsVideoCodecUiDriver(panelController.Panel, avDriver,
(room as IEssentialsHuddleVtc1Room).VideoCodec, mainDriver.HeaderDriver);
avDriver.SetVideoCodecDriver(codecDriver);
avDriver.DefaultRoomKey = props.DefaultRoomKey;
mainDriver.AvDriver = avDriver;
avDriver.CurrentRoom = room as IEssentialsHuddleVtc1Room;
// Environment Driver
if (avDriver.CurrentRoom.PropertiesConfig.Environment != null && avDriver.CurrentRoom.PropertiesConfig.Environment.DeviceKeys.Count > 0)
{
Debug.Console(0, panelController, "Adding environment driver");
mainDriver.EnvironmentDriver = new EssentialsEnvironmentDriver(mainDriver, props);
mainDriver.EnvironmentDriver.GetDevicesFromConfig(avDriver.CurrentRoom.PropertiesConfig.Environment);
}
mainDriver.HeaderDriver.SetupHeaderButtons(avDriver, avDriver.CurrentRoom);
panelController.LoadAndShowDriver(mainDriver); // This is a little convoluted.
if (panelController.Panel is TswFt5ButtonSystem)
{
var tsw = panelController.Panel as TswFt5ButtonSystem;
// Wire up hard keys
tsw.Power.UserObject = new Action<bool>(b => { if (!b) avDriver.EndMeetingPress(); });
//tsw.Home.UserObject = new Action<bool>(b => { if (!b) HomePressed(); });
if (mainDriver.EnvironmentDriver != null)
tsw.Lights.UserObject = new Action<bool>(b =>
{
if (!b)
{
//mainDriver.AvDriver.PopupInterlock.ShowInterlockedWithToggle(mainDriver.EnvironmentDriver.BackgroundSubpageJoin);
mainDriver.EnvironmentDriver.Toggle();
}
});
tsw.Up.UserObject = new Action<bool>(avDriver.VolumeUpPress);
tsw.Down.UserObject = new Action<bool>(avDriver.VolumeDownPress);
}
}
else
{
Debug.Console(0, panelController, "ERROR: Cannot load AvFunctionsDriver for room '{0}'", props.DefaultRoomKey);
}
});
return panelController;
}
}

View File

@@ -948,5 +948,24 @@ namespace PepperDash.Essentials
/// 15214
/// </summary>
public const uint PinDialogDot4 = 15214;
// Password Prompt Dialog **************************
/// <summary>
/// 15301
/// </summary>
public const uint PasswordPromptDialogVisible = 15301;
/// <summary>
/// 15302
/// </summary>
public const uint PasswordPromptTextPress = 15302;
/// <summary>
/// 15306
/// </summary>
public const uint PasswordPromptCancelPress = 15306;
/// <summary>
/// 15307
/// </summary>
public const uint PasswordPromptErrorVisible = 15307;
}
}

View File

@@ -118,6 +118,14 @@ namespace PepperDash.Essentials
//----- through 3120
/// <summary>
/// 3201
/// </summary>
public const uint PasswordPromptMessageText = 3201;
/// <summary>
/// 3202
/// </summary>
public const uint PasswordPromptPasswordText = 3202;
/// <summary>
/// 3812

View File

@@ -14,8 +14,6 @@ namespace PepperDash.Essentials
{
public SourceListItem SourceItem { get; private set; }
private IHasCurrentSourceInfoChange _room;
public SubpageReferenceListSourceItem(uint index, SubpageReferenceList owner,
SourceListItem sourceItem, Action<bool> routeAction)
: base(index, owner)
@@ -27,7 +25,6 @@ namespace PepperDash.Essentials
public void RegisterForSourceChange(IHasCurrentSourceInfoChange room)
{
_room = room;
room.CurrentSourceChange -= room_CurrentSourceInfoChange;
room.CurrentSourceChange += room_CurrentSourceInfoChange;
}
@@ -47,9 +44,6 @@ namespace PepperDash.Essentials
{
Owner.BoolInputSig(Index, 1).UserObject = null;
Owner.StringInputSig(Index, 1).StringValue = "";
if(_room != null)
_room.CurrentSourceChange -= room_CurrentSourceInfoChange;
}
/// <summary>

View File

@@ -11,7 +11,7 @@ namespace PepperDash.Essentials
/// <summary>
///
/// </summary>
public class EssentialsPanelMainInterfaceDriver : PanelDriverBase, IHasScreenSaverController, IDisposable
public class EssentialsPanelMainInterfaceDriver : PanelDriverBase, IHasScreenSaverController
{
CTimer InactivityTimer;
@@ -69,35 +69,6 @@ namespace PepperDash.Essentials
}
}
#region IDisposable Members
public void Dispose()
{
var avDriver = AvDriver as PanelDriverBase;
if (avDriver != null)
{
avDriver.Hide();
}
if (ScreenSaverController != null)
{
ScreenSaverController.Dispose();
}
if (HeaderDriver != null)
{
HeaderDriver.Hide();
}
if (EnvironmentDriver != null)
{
EnvironmentDriver.Hide();
}
if (CurrentChildDriver != null)
{
CurrentChildDriver.Hide();
}
}
#endregion
void ExtenderTouchDetectionReservedSigs_DeviceExtenderSigChange(Crestron.SimplSharpPro.DeviceExtender currentDeviceExtender, Crestron.SimplSharpPro.SigEventArgs args)
{
@@ -159,7 +130,7 @@ namespace PepperDash.Essentials
if(CurrentChildDriver != null)
CurrentChildDriver.BackButtonPressed();
}
}
}
public interface IHasScreenSaverController
{

View File

@@ -306,7 +306,7 @@ namespace PepperDash.Essentials
TriList.SetSigFalseAction(UIBoolJoin.DisplayPowerTogglePress, () =>
{
if (CurrentRoom != null && CurrentRoom.DefaultDisplay != null && CurrentRoom.DefaultDisplay is IHasPowerControl)
if (CurrentRoom != null && CurrentRoom.DefaultDisplay is IHasPowerControl)
(CurrentRoom.DefaultDisplay as IHasPowerControl).PowerToggle();
});

View File

@@ -1,6 +1,7 @@
using System;
using System.Linq;
using System.Collections.Generic;
using System.Globalization;
using Crestron.SimplSharp;
using Crestron.SimplSharpPro;
using Crestron.SimplSharpPro.UI;
@@ -338,7 +339,7 @@ namespace PepperDash.Essentials
TriList.SetSigFalseAction(UIBoolJoin.DisplayPowerTogglePress, () =>
{
if (CurrentRoom != null && CurrentRoom.DefaultDisplay != null && CurrentRoom.DefaultDisplay is IHasPowerControl)
if (CurrentRoom != null && CurrentRoom.DefaultDisplay is IHasPowerControl)
(CurrentRoom.DefaultDisplay as IHasPowerControl).PowerToggle();
});
@@ -467,15 +468,19 @@ namespace PepperDash.Essentials
// and the LastMeetingDismissed != this meeting
var lastMeetingDismissed = meetings.FirstOrDefault(m => m.Id == LastMeetingDismissedId);
//Debug.Console(1, "*#* Room on: {0}, lastMeetingDismissedId: {1} {2} *#*",
// CurrentRoom.OnFeedback.BoolValue,
// LastMeetingDismissedId,
// lastMeetingDismissed != null ? lastMeetingDismissed.StartTime.ToShortTimeString() : "");
Debug.Console(0, "*#* Room on: {0}, lastMeetingDismissedId: {1} {2} *#*",
CurrentRoom.OnFeedback.BoolValue,
LastMeetingDismissedId,
lastMeetingDismissed != null ? lastMeetingDismissed.StartTime.ToString("t", Global.Culture) : "");
var meeting = meetings.LastOrDefault(m => m.Joinable);
if (CurrentRoom.OnFeedback.BoolValue
&& lastMeetingDismissed == meeting)
{
// meeting no longer joinable, hide popup
if(meeting == null)
HideNextMeetingPopup();
return;
}
@@ -487,9 +492,11 @@ namespace PepperDash.Essentials
}
else
{
TriList.SetString(UIStringJoin.MeetingsOrContactMethodListTitleText, "Upcoming meeting");
TriList.SetString(UIStringJoin.NextMeetingStartTimeText, meeting.StartTime.ToShortTimeString());
TriList.SetString(UIStringJoin.NextMeetingEndTimeText, meeting.EndTime.ToShortTimeString());
TriList.SetString(UIStringJoin.NextMeetingStartTimeText, meeting.StartTime.ToString("t", Global.Culture));
TriList.SetString(UIStringJoin.NextMeetingEndTimeText, meeting.EndTime.ToString("t", Global.Culture));
TriList.SetString(UIStringJoin.NextMeetingTitleText, meeting.Title);
TriList.SetString(UIStringJoin.NextMeetingNameText, meeting.Organizer);
TriList.SetString(UIStringJoin.NextMeetingButtonLabel, "Join");
@@ -512,7 +519,7 @@ namespace PepperDash.Essentials
// indexOf = 3, 4 meetings :
if (indexOfNext < meetings.Count)
TriList.SetString(UIStringJoin.NextMeetingFollowingMeetingText,
meetings[indexOfNext].StartTime.ToShortTimeString());
meetings[indexOfNext].StartTime.ToString("t", Global.Culture));
else
TriList.SetString(UIStringJoin.NextMeetingFollowingMeetingText, "No more meetings today");
@@ -1209,8 +1216,8 @@ namespace PepperDash.Essentials
foreach (var m in CurrentRoom.ScheduleSource.CodecSchedule.Meetings)
{
i++;
MeetingOrContactMethodModalSrl.StringInputSig(i, 1).StringValue = m.StartTime.ToShortTimeString();
MeetingOrContactMethodModalSrl.StringInputSig(i, 2).StringValue = m.EndTime.ToShortTimeString();
MeetingOrContactMethodModalSrl.StringInputSig(i, 1).StringValue = m.StartTime.ToString("t", Global.Culture);
MeetingOrContactMethodModalSrl.StringInputSig(i, 2).StringValue = m.EndTime.ToString("t", Global.Culture);
MeetingOrContactMethodModalSrl.StringInputSig(i, 3).StringValue = m.Title;
MeetingOrContactMethodModalSrl.StringInputSig(i, 4).StringValue = string.Format("<br>{0}",m.Organizer);
MeetingOrContactMethodModalSrl.StringInputSig(i, 5).StringValue = "Join";

View File

@@ -12,7 +12,7 @@ namespace PepperDash.Essentials
/// <summary>
/// Driver responsible for controlling the screenshaver showing the client logo, MC connection information and QR Code. Moves the elements around to prevent screen burn in
/// </summary>
public class ScreenSaverController : PanelDriverBase, IDisposable
public class ScreenSaverController : PanelDriverBase
{
/// <summary>
@@ -42,7 +42,7 @@ namespace PepperDash.Essentials
PositionInterlock = new JoinedSigInterlock(parent.TriList);
var cmdName = String.Format("shwscrsvr-{0:X2}", parent.TriList.ID);
var cmdName = String.Format("shwscrsvr-{0}", parent.TriList.ID);
CrestronConsole.AddNewConsoleCommand((o) => Show(), cmdName, "Shows Panel Screensaver", ConsoleAccessLevelEnum.AccessOperator);
@@ -51,8 +51,6 @@ namespace PepperDash.Essentials
public override void Show()
{
Debug.Console(2, "Showing ScreenSaverController: {0:X2}", TriList.ID);
if (_parent.AvDriver != null)
{
_parent.AvDriver.PopupInterlock.ShowInterlocked(UIBoolJoin.MCScreenSaverVisible);
@@ -67,11 +65,10 @@ namespace PepperDash.Essentials
public override void Hide()
{
Debug.Console(2, "Hiding ScreenSaverController: {0:X2}", TriList.ID);
Debug.Console(1, "Hiding ScreenSaverController");
if (PositionTimer != null)
{
Debug.Console(2, "Stopping PositionTimer: {0:X2}", TriList.ID);
PositionTimer.Stop();
PositionTimer.Dispose();
PositionTimer = null;
@@ -89,8 +86,6 @@ namespace PepperDash.Essentials
void StartPositionTimer()
{
Debug.Console(2, "Starting Position Timer: {0:X2}", TriList.ID);
if (PositionTimer == null)
{
PositionTimer = new CTimer((o) => PositionTimerExpired(), PositionTimeoutMs);
@@ -122,7 +117,7 @@ namespace PepperDash.Essentials
CurrentPositionIndex = 0;
}
Debug.Console(2, "ScreenSaver Position Timer Expired: Setting new position: {0} ID: {1:X2}", CurrentPositionIndex, TriList.ID);
Debug.Console(1, "ScreenSaver Position Timer Expired: Setting new position: {0}", CurrentPositionIndex);
}
//
@@ -134,19 +129,9 @@ namespace PepperDash.Essentials
void ClearAllPositions()
{
Debug.Console(2, "Hiding all screensaver positions: {0:X2}", TriList.ID);
Debug.Console(1, "Hiding all screensaver positions");
PositionInterlock.HideAndClear();
}
#region IDisposable Members
public void Dispose()
{
Hide();
}
#endregion
}
}

View File

@@ -2,6 +2,7 @@
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Globalization;
using System.Text.RegularExpressions;
using Crestron.SimplSharp;
using Crestron.SimplSharpPro;
@@ -83,6 +84,9 @@ namespace PepperDash.Essentials.UIDrivers.VC
StringBuilder SearchStringBuilder = new StringBuilder();
BoolFeedback SearchStringBackspaceVisibleFeedback;
StringFeedback PasswordStringFeedback;
StringBuilder PasswordStringBuilder = new StringBuilder();
ModalDialog IncomingCallModal;
eKeypadMode KeypadMode;
@@ -174,8 +178,22 @@ namespace PepperDash.Essentials.UIDrivers.VC
});
SearchStringFeedback.LinkInputSig(triList.StringInput[UIStringJoin.CodecDirectorySearchEntryText]);
SetupDirectoryList();
PasswordStringFeedback = new StringFeedback(() =>
{
if (PasswordStringBuilder.Length > 0)
{
Parent.Keyboard.EnableGoButton();
return PasswordStringBuilder.ToString();
}
else
{
Parent.Keyboard.DisableGoButton();
return "";
}
});
PasswordStringFeedback.LinkInputSig(triList.StringInput[UIStringJoin.PasswordPromptPasswordText]);
SetupDirectoryList();
SearchStringBackspaceVisibleFeedback = new BoolFeedback(() => SearchStringBuilder.Length > 0);
SearchStringBackspaceVisibleFeedback.LinkInputSig(triList.BooleanInput[UIBoolJoin.VCDirectoryBackspaceVisible]);
@@ -193,14 +211,18 @@ namespace PepperDash.Essentials.UIDrivers.VC
triList.SetSigHeldAction(UIBoolJoin.VCDirectoryBackspacePress, 500,
StartSearchBackspaceRepeat, StopSearchBackspaceRepeat, SearchKeypadBackspacePress);
if (Codec is IPasswordPrompt)
{
SetupPasswordPrompt();
}
// If the codec is ready, then get the values we want, otherwise wait
if (Codec.IsReady)
Codec_IsReady();
else
codec.IsReadyChange += (o, a) => Codec_IsReady();
}
catch (Exception e)
{
@@ -301,6 +323,7 @@ namespace PepperDash.Essentials.UIDrivers.VC
{
case eCodecCallStatus.Connected:
// fire at SRL item
HidePasswordPrompt();
KeypadMode = eKeypadMode.DTMF;
DialStringBuilder.Remove(0, DialStringBuilder.Length);
DialStringFeedback.FireUpdate();
@@ -520,6 +543,7 @@ namespace PepperDash.Essentials.UIDrivers.VC
VCControlsInterlock.StatusChanged += new EventHandler<StatusChangedEventArgs>(VCControlsInterlock_StatusChanged);
var codecOffCameras = Codec as IHasCameraOff;
var supportsCameraOffMode = Codec.SupportsCameraOff;
@@ -530,7 +554,6 @@ namespace PepperDash.Essentials.UIDrivers.VC
if (codecAutoCameras != null && supportsAutoCameraMode)
{
CameraModeList.SetItemButtonAction(1,(b) => codecAutoCameras.CameraAutoModeOn());
TriList.SmartObjects[UISmartObjectJoin.VCCameraMode].BooleanInput["Item 1 Visible"].BoolValue = true;
codecAutoCameras.CameraAutoModeIsOnFeedback.LinkInputSig(CameraModeList.SmartObject.BooleanInput["Item 1 Selected"]);
@@ -560,7 +583,6 @@ namespace PepperDash.Essentials.UIDrivers.VC
}
};
}
// Manual button always visible
@@ -572,7 +594,6 @@ namespace PepperDash.Essentials.UIDrivers.VC
if (codecOffCameras != null && supportsCameraOffMode)
{
TriList.SmartObjects[UISmartObjectJoin.VCCameraMode].BooleanInput["Item 3 Visible"].BoolValue = true;
codecOffCameras.CameraIsOffFeedback.LinkInputSig(CameraModeList.SmartObject.BooleanInput["Item 3 Selected"]);
CameraModeList.SetItemButtonAction(3, (b) => codecOffCameras.CameraOff());
@@ -600,7 +621,6 @@ namespace PepperDash.Essentials.UIDrivers.VC
}
};
}
}
@@ -989,7 +1009,7 @@ namespace PepperDash.Essentials.UIDrivers.VC
// if it's today, show a simpler string
string timeText = null;
if (c.StartTime.Date == DateTime.Now.Date)
timeText = c.StartTime.ToShortTimeString();
timeText = c.StartTime.ToString("t", Global.Culture);
else if (c.StartTime == DateTime.MinValue)
timeText = "";
else
@@ -1333,7 +1353,21 @@ namespace PepperDash.Essentials.UIDrivers.VC
/// </summary>
void RevealKeyboard()
{
if (VCControlsInterlock.CurrentJoin == UIBoolJoin.VCKeypadWithFavoritesVisible && KeypadMode == eKeypadMode.Dial)
if (_passwordPromptDialogVisible)
{
Debug.Console(2, "Attaching Keyboard to PasswordPromptDialog");
DetachDialKeyboard();
DetachSearchKeyboard();
var kb = Parent.Keyboard;
kb.KeyPress -= Keyboard_PasswordKeyPress;
kb.KeyPress += Keyboard_PasswordKeyPress;
kb.HideAction = this.DetachPasswordKeyboard;
kb.GoButtonText = "Submit";
kb.GoButtonVisible = true;
PasswordStringCheckEnables();
kb.Show();
}
else if (VCControlsInterlock.CurrentJoin == UIBoolJoin.VCKeypadWithFavoritesVisible && KeypadMode == eKeypadMode.Dial)
{
var kb = Parent.Keyboard;
kb.KeyPress -= Keyboard_DialKeyPress;
@@ -1355,6 +1389,7 @@ namespace PepperDash.Essentials.UIDrivers.VC
SearchStringKeypadCheckEnables();
kb.Show();
}
}
/// <summary>
@@ -1410,6 +1445,32 @@ namespace PepperDash.Essentials.UIDrivers.VC
}
}
/// <summary>
/// Event handler for keyboard dialing
/// </summary>
void Keyboard_PasswordKeyPress(object sender, PepperDash.Essentials.Core.Touchpanels.Keyboards.KeyboardControllerPressEventArgs e)
{
if (_passwordPromptDialogVisible)
{
if (e.Text != null)
PasswordStringBuilder.Append(e.Text);
else
{
if (e.SpecialKey == KeyboardSpecialKey.Backspace)
PasswordKeypadBackspacePress();
else if (e.SpecialKey == KeyboardSpecialKey.Clear)
PasswordKeypadClear();
else if (e.SpecialKey == KeyboardSpecialKey.GoButton)
{
(Codec as IPasswordPrompt).SubmitPassword(PasswordStringBuilder.ToString());
HidePasswordPrompt();
}
}
PasswordStringFeedback.FireUpdate();
PasswordStringCheckEnables();
}
}
/// <summary>
/// Call
/// </summary>
@@ -1423,6 +1484,11 @@ namespace PepperDash.Essentials.UIDrivers.VC
Parent.Keyboard.KeyPress -= Keyboard_SearchKeyPress;
}
void DetachPasswordKeyboard()
{
Parent.Keyboard.KeyPress -= Keyboard_PasswordKeyPress;
}
/// <summary>
/// Shows the camera controls subpage
/// </summary>
@@ -1676,6 +1742,40 @@ namespace PepperDash.Essentials.UIDrivers.VC
Parent.Keyboard.DisableGoButton();
}
/// <summary>
/// Clears the Password keypad
/// </summary>
void PasswordKeypadClear()
{
PasswordStringBuilder.Remove(0, SearchStringBuilder.Length);
PasswordStringFeedback.FireUpdate();
PasswordStringCheckEnables();
}
/// <summary>
///
/// </summary>
void PasswordKeypadBackspacePress()
{
PasswordStringBuilder.Remove(PasswordStringBuilder.Length - 1, 1);
PasswordStringFeedback.FireUpdate();
PasswordStringCheckEnables();
}
/// <summary>
/// Checks the enabled states of various elements around the keypad
/// </summary>
void PasswordStringCheckEnables()
{
var textIsEntered = PasswordStringBuilder.Length > 0;
if (textIsEntered)
Parent.Keyboard.EnableGoButton();
else
Parent.Keyboard.DisableGoButton();
}
/// <summary>
/// Returns the text value for the keypad dial entry field
@@ -1721,5 +1821,61 @@ namespace PepperDash.Essentials.UIDrivers.VC
Dial = 0,
DTMF
}
void SetupPasswordPrompt()
{
var passwordPromptCodec = Codec as IPasswordPrompt;
passwordPromptCodec.PasswordRequired += new EventHandler<PasswordPromptEventArgs>(passwordPromptCodec_PasswordRequired);
TriList.SetSigFalseAction(UIBoolJoin.PasswordPromptCancelPress, HidePasswordPrompt);
TriList.SetSigFalseAction(UIBoolJoin.PasswordPromptTextPress, RevealKeyboard);
}
void passwordPromptCodec_PasswordRequired(object sender, PasswordPromptEventArgs e)
{
if (e.LoginAttemptCancelled)
{
HidePasswordPrompt();
return;
}
if (!string.IsNullOrEmpty(e.Message))
{
TriList.SetString(UIStringJoin.PasswordPromptMessageText, e.Message);
}
if (e.LoginAttemptFailed)
{
// TODO: Show a message modal to indicate the login attempt failed
return;
}
TriList.SetBool(UIBoolJoin.PasswordPromptErrorVisible, e.LastAttemptWasIncorrect);
ShowPasswordPrompt();
}
private bool _passwordPromptDialogVisible;
void ShowPasswordPrompt()
{
// Clear out any previous data
PasswordKeypadClear();
_passwordPromptDialogVisible = true;
TriList.SetBool(UIBoolJoin.PasswordPromptDialogVisible, _passwordPromptDialogVisible);
RevealKeyboard();
}
void HidePasswordPrompt()
{
if (_passwordPromptDialogVisible)
{
_passwordPromptDialogVisible = false;
Parent.Keyboard.Hide();
TriList.SetBool(UIBoolJoin.PasswordPromptDialogVisible, _passwordPromptDialogVisible);
}
}
}
}

View File

@@ -42,6 +42,3 @@ devjson:2 {"deviceKey":"display01Comm-com", "methodName":"SendText", "params": [
devjson:10 {"deviceKey":"dmLink-ssh", "methodName":"Connect", "params": []}
devjson:2 {"deviceKey":"roomCombiner", "methodName":"SetRoomCombinationScenario", "params": ["combined"]}
devjson:2 {"deviceKey":"roomCombiner", "methodName":"SetRoomCombinationScenario", "params": ["divided"]}

View File

@@ -8,7 +8,7 @@ namespace PepperDash.Essentials.Core.DeviceTypeInterfaces
/// </summary>
public interface IMobileControl : IKeyed
{
void CreateMobileControlRoomBridge(IEssentialsRoom room, IMobileControl parent);
void CreateMobileControlRoomBridge(EssentialsRoomBase room, IMobileControl parent);
void LinkSystemMonitorToAppServer();
}

View File

@@ -0,0 +1,56 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Crestron.SimplSharp;
namespace PepperDash.Essentials.Core
{
/// <summary>
/// Describes the functionality required to prompt a user to enter a password
/// </summary>
public interface IPasswordPrompt
{
/// <summary>
/// Notifies when a password is required or is entered incorrectly
/// </summary>
event EventHandler<PasswordPromptEventArgs> PasswordRequired;
/// <summary>
/// Submits the password
/// </summary>
/// <param name="password"></param>
void SubmitPassword(string password);
}
public class PasswordPromptEventArgs : EventArgs
{
/// <summary>
/// Indicates if the last submitted password was incorrect
/// </summary>
public bool LastAttemptWasIncorrect { get; private set; }
/// <summary>
/// Indicates that the login attempt has failed
/// </summary>
public bool LoginAttemptFailed { get; private set; }
/// <summary>
/// Indicates that the process was cancelled and the prompt should be dismissed
/// </summary>
public bool LoginAttemptCancelled { get; private set; }
/// <summary>
/// A message to be displayed to the user
/// </summary>
public string Message { get; private set; }
public PasswordPromptEventArgs(bool lastAttemptIncorrect, bool loginFailed, bool loginCancelled, string message)
{
LastAttemptWasIncorrect = lastAttemptIncorrect;
LoginAttemptFailed = loginFailed;
LoginAttemptCancelled = loginCancelled;
Message = message;
}
}
}

View File

@@ -1,5 +1,6 @@
using System;
using System.Text.RegularExpressions;
using System.Globalization;
using Crestron.SimplSharp;
using System.Collections.Generic;
using Crestron.SimplSharp.CrestronIO;
@@ -28,6 +29,10 @@ namespace PepperDash.Essentials.Core
public static eCrestronSeries ProcessorSeries { get { return CrestronEnvironment.ProgramCompatibility; } }
// TODO: consider making this configurable later
public static IFormatProvider Culture = CultureInfo.CreateSpecificCulture("en-US");
/// <summary>
/// The file path prefix to the folder containing configuration files
/// </summary>

View File

@@ -203,6 +203,7 @@
<Compile Include="Devices\PC\Laptop.cs" />
<Compile Include="Devices\ReconfigurableDevice.cs" />
<Compile Include="Devices\VolumeDeviceChangeEventArgs.cs" />
<Compile Include="DeviceTypeInterfaces\IPasswordPrompt.cs" />
<Compile Include="DeviceTypeInterfaces\ITvPresetsProvider.cs" />
<Compile Include="DeviceTypeInterfaces\LanguageLabel.cs" />
<Compile Include="DeviceTypeInterfaces\ILanguageProvider.cs" />

View File

@@ -54,20 +54,13 @@ namespace PepperDash.Essentials.Core
SetupPartitionStateProviders();
SetRooms();
if (isInAutoMode)
{
DetermineRoomCombinationScenario();
}
else
{
SetRoomCombinationScenario(_propertiesConfig.defaultScenarioKey);
}
});
}
void CreateScenarios()
{
RoomCombinationScenarios = new List<IRoomCombinationScenario>();
foreach (var scenarioConfig in _propertiesConfig.Scenarios)
{
var scenario = new RoomCombinationScenario(scenarioConfig);
@@ -167,26 +160,12 @@ namespace PepperDash.Essentials.Core
{
return _currentScenario;
}
private set
set
{
if (value != _currentScenario)
{
// Deactivate the old scenario first
if (_currentScenario != null)
{
_currentScenario.Deactivate();
}
_currentScenario = value;
// Activate the new scenario
if (_currentScenario != null)
{
_currentScenario.Activate();
Debug.Console(1, this, "Current Scenario: {0}", _currentScenario.Name);
}
Debug.Console(1, this, "Current Scenario: {0}", _currentScenario.Name);
var handler = RoomCombinationScenarioChanged;
if (handler != null)
{
@@ -241,11 +220,9 @@ namespace PepperDash.Essentials.Core
// Get the scenario
var scenario = RoomCombinationScenarios.FirstOrDefault((s) => s.Key.Equals(scenarioKey));
// Set the parition states from the scenario manually
if (scenario != null)
{
Debug.Console(0, this, "Manually setting scenario to '{0}'", scenario.Key);
foreach (var partitionState in scenario.PartitionStates)
{
var partition = Partitions.FirstOrDefault((p) => p.Key.Equals(partitionState.PartitionKey));
@@ -254,25 +231,15 @@ namespace PepperDash.Essentials.Core
{
if (partitionState.PartitionPresent)
{
Debug.Console(0, this, "Manually setting state to Present for: '{0}'", partition.Key);
partition.SetPartitionStatePresent();
}
else
{
Debug.Console(0, this, "Manually setting state to Not Present for: '{0}'", partition.Key);
partition.SetPartitionStateNotPresent();
}
}
else
{
Debug.Console(1, this, "Unable to find partition with key: '{0}'", partitionState.PartitionKey);
}
}
}
else
{
Debug.Console(1, this, "Unable to find scenario with key: '{0}'", scenarioKey);
}
}
#endregion

View File

@@ -30,7 +30,7 @@ namespace PepperDash.Essentials.Core
/// <summary>
/// The list of rooms keys that can be combined
/// </summary>
[JsonProperty("roomKeys")]
[JsonProperty("roomMap")]
public List<string> RoomKeys {get; set;}
/// <summary>
@@ -87,9 +87,6 @@ namespace PepperDash.Essentials.Core
[JsonProperty("partitionStates")]
public List<PartitionState> PartitionStates { get; set; }
/// <summary>
/// Determines which UI devices get mapped to which room in this scenario. The Key should be the key of the UI device and the Value should be the key of the room to map to
/// </summary>
[JsonProperty("uiMap")]
public Dictionary<string, string> UiMap { get; set; }

View File

@@ -78,11 +78,6 @@ namespace PepperDash.Essentials.Core
/// </summary>
void Activate();
/// <summary>
/// Deactivates this room combination scenario
/// </summary>
void Deactivate();
/// <summary>
/// The state of the partitions that would activate this scenario
/// </summary>

View File

@@ -4,8 +4,6 @@ using System.Linq;
using System.Text;
using Crestron.SimplSharp;
using PepperDash.Core;
using Newtonsoft.Json;
namespace PepperDash.Essentials.Core
@@ -29,9 +27,9 @@ namespace PepperDash.Essentials.Core
public BoolFeedback IsActiveFeedback { get; private set; }
private List<DeviceActionWrapper> activationActions;
List<DeviceActionWrapper> activationActions;
private List<DeviceActionWrapper> deactivationActions;
List<DeviceActionWrapper> deactivationActions;
public RoomCombinationScenario(RoomCombinationScenarioConfig config)
{
@@ -54,8 +52,6 @@ namespace PepperDash.Essentials.Core
public void Activate()
{
Debug.Console(1, "Activating Scenario: '{0}' with {1} action(s) defined", Name, activationActions.Count);
if (activationActions != null)
{
foreach (var action in activationActions)
@@ -70,8 +66,6 @@ namespace PepperDash.Essentials.Core
public void Deactivate()
{
Debug.Console(1, "Deactivating Scenario: '{0}' with {1} action(s) defined", Name, deactivationActions.Count);
if (deactivationActions != null)
{
foreach (var action in deactivationActions)

View File

@@ -15,7 +15,7 @@ namespace PepperDash.Essentials.Core
/// <summary>
/// Describes the basic functionality of an EssentialsRoom
/// </summary>
public interface IEssentialsRoom : IKeyName, IReconfigurableDevice
public interface IEssentialsRoom : IKeyName, IReconfigurableDevice, IRunDefaultPresentRoute
{
BoolFeedback OnFeedback { get; }
@@ -56,7 +56,6 @@ namespace PepperDash.Essentials.Core
void SetRoomOccupancy(IOccupancyStatusProvider statusProvider, int timeoutMinutes);
void PowerOnToDefaultOrLastSource();
bool RunDefaultPresentRoute();
void SetDefaultLevels();

View File

@@ -206,27 +206,6 @@ namespace PepperDash.Essentials.Core
return ClearSigAction(tl.StringOutput[sigNum]) as StringOutputSig;
}
/// <summary>
/// Clears all actions on all sigs
/// </summary>
public static void ClearAllSigActions(this BasicTriList t1)
{
foreach (var sig in t1.BooleanOutput)
{
ClearSigAction(sig);
}
foreach (var sig in t1.UShortOutput)
{
ClearSigAction(sig);
}
foreach (var sig in t1.StringOutput)
{
ClearSigAction(sig);
}
}
/// <summary>
/// Helper method to set the value of a bool Sig on TriList
/// </summary>

View File

@@ -1,40 +1,40 @@
using Crestron.SimplSharpPro;
using System;
using System.Linq;
//using Crestron.SimplSharpPro.DeviceSupport;
using Crestron.SimplSharpPro.DeviceSupport;
using Crestron.SimplSharpPro.DM;
using Crestron.SimplSharpPro.DM.Endpoints;
using Crestron.SimplSharpPro.DM.Endpoints.Transmitters;
using PepperDash.Core;
using PepperDash.Essentials.Core;
using PepperDash.Essentials.Core.Bridges;
namespace PepperDash.Essentials.DM
{
using eVst = eX02VideoSourceType;
using Crestron.SimplSharpPro;
using System;
using System.Linq;
//using Crestron.SimplSharpPro.DeviceSupport;
using Crestron.SimplSharpPro.DeviceSupport;
using Crestron.SimplSharpPro.DM;
using Crestron.SimplSharpPro.DM.Endpoints;
using Crestron.SimplSharpPro.DM.Endpoints.Transmitters;
using PepperDash.Core;
using PepperDash.Essentials.Core;
using PepperDash.Essentials.Core.Bridges;
namespace PepperDash.Essentials.DM
{
using eVst = eX02VideoSourceType;
using eAst = eX02AudioSourceType;
public class DmTx4kz202CController : DmTxControllerBase, ITxRoutingWithFeedback,
IIROutputPorts, IComPorts
{
public DmTx4kz202C Tx { get; private set; }
public RoutingInputPortWithVideoStatuses HdmiIn1 { get; private set; }
public RoutingInputPortWithVideoStatuses HdmiIn2 { get; private set; }
public RoutingOutputPort DmOut { get; private set; }
public RoutingOutputPort HdmiLoopOut { get; private set; }
public override StringFeedback ActiveVideoInputFeedback { get; protected set; }
public IntFeedback VideoSourceNumericFeedback { get; protected set; }
public IntFeedback AudioSourceNumericFeedback { get; protected set; }
public IntFeedback HdmiIn1HdcpCapabilityFeedback { get; protected set; }
public IntFeedback HdmiIn2HdcpCapabilityFeedback { get; protected set; }
public BoolFeedback Hdmi1VideoSyncFeedback { get; protected set; }
public BoolFeedback Hdmi2VideoSyncFeedback { get; protected set; }
//public override IntFeedback HdcpSupportAllFeedback { get; protected set; }
public class DmTx4kz202CController : DmTxControllerBase, ITxRoutingWithFeedback,
IIROutputPorts, IComPorts
{
public DmTx4kz202C Tx { get; private set; }
public RoutingInputPortWithVideoStatuses HdmiIn1 { get; private set; }
public RoutingInputPortWithVideoStatuses HdmiIn2 { get; private set; }
public RoutingOutputPort DmOut { get; private set; }
public RoutingOutputPort HdmiLoopOut { get; private set; }
public override StringFeedback ActiveVideoInputFeedback { get; protected set; }
public IntFeedback VideoSourceNumericFeedback { get; protected set; }
public IntFeedback AudioSourceNumericFeedback { get; protected set; }
public IntFeedback HdmiIn1HdcpCapabilityFeedback { get; protected set; }
public IntFeedback HdmiIn2HdcpCapabilityFeedback { get; protected set; }
public BoolFeedback Hdmi1VideoSyncFeedback { get; protected set; }
public BoolFeedback Hdmi2VideoSyncFeedback { get; protected set; }
//public override IntFeedback HdcpSupportAllFeedback { get; protected set; }
//public override ushort HdcpSupportCapability { get; protected set; }
//IroutingNumericEvent
public event EventHandler<RoutingNumericEventArgs> NumericSwitchChange;
@@ -47,48 +47,48 @@ namespace PepperDash.Essentials.DM
{
var newEvent = NumericSwitchChange;
if (newEvent != null) newEvent(this, e);
}
/// <summary>
/// Helps get the "real" inputs, including when in Auto
/// </summary>
public eX02VideoSourceType ActualActiveVideoInput
{
get
{
if (Tx.VideoSourceFeedback != eVst.Auto)
return Tx.VideoSourceFeedback;
if (Tx.HdmiInputs[1].SyncDetectedFeedback.BoolValue)
return eVst.Hdmi1;
return Tx.HdmiInputs[2].SyncDetectedFeedback.BoolValue ? eVst.Hdmi2 : eVst.AllDisabled;
}
}
public RoutingPortCollection<RoutingInputPort> InputPorts
{
get
{
return new RoutingPortCollection<RoutingInputPort>
{
HdmiIn1,
HdmiIn2,
AnyVideoInput
};
}
}
public RoutingPortCollection<RoutingOutputPort> OutputPorts
{
get
{
return new RoutingPortCollection<RoutingOutputPort> { DmOut, HdmiLoopOut };
}
}
public DmTx4kz202CController(string key, string name, DmTx4kz202C tx)
: base(key, name, tx)
{
}
/// <summary>
/// Helps get the "real" inputs, including when in Auto
/// </summary>
public eX02VideoSourceType ActualActiveVideoInput
{
get
{
if (Tx.VideoSourceFeedback != eVst.Auto)
return Tx.VideoSourceFeedback;
if (Tx.HdmiInputs[1].SyncDetectedFeedback.BoolValue)
return eVst.Hdmi1;
return Tx.HdmiInputs[2].SyncDetectedFeedback.BoolValue ? eVst.Hdmi2 : eVst.AllDisabled;
}
}
public RoutingPortCollection<RoutingInputPort> InputPorts
{
get
{
return new RoutingPortCollection<RoutingInputPort>
{
HdmiIn1,
HdmiIn2,
AnyVideoInput
};
}
}
public RoutingPortCollection<RoutingOutputPort> OutputPorts
{
get
{
return new RoutingPortCollection<RoutingOutputPort> { DmOut, HdmiLoopOut };
}
}
public DmTx4kz202CController(string key, string name, DmTx4kz202C tx)
: base(key, name, tx)
{
Tx = tx;
HdmiIn1 = new RoutingInputPortWithVideoStatuses(DmPortName.HdmiIn1,
@@ -104,208 +104,208 @@ namespace PepperDash.Essentials.DM
FeedbackMatchObject = eVst.Hdmi2
};
ActiveVideoInputFeedback = new StringFeedback("ActiveVideoInput",
() => ActualActiveVideoInput.ToString());
Tx.HdmiInputs[1].InputStreamChange += InputStreamChangeEvent;
Tx.HdmiInputs[2].InputStreamChange += InputStreamChangeEvent;
Tx.BaseEvent += Tx_BaseEvent;
Tx.OnlineStatusChange += Tx_OnlineStatusChange;
VideoSourceNumericFeedback = new IntFeedback(() => (int)Tx.VideoSourceFeedback);
//Return VideoSourceFeedback here as DM-TX-4KZ-202-C does not support audio breakaway
AudioSourceNumericFeedback = new IntFeedback(() => (int)Tx.VideoSourceFeedback);
HdmiIn1HdcpCapabilityFeedback = new IntFeedback("HdmiIn1HdcpCapability", () => (int)tx.HdmiInputs[1].HdcpCapabilityFeedback);
HdmiIn2HdcpCapabilityFeedback = new IntFeedback("HdmiIn2HdcpCapability", () => (int)tx.HdmiInputs[2].HdcpCapabilityFeedback);
HdcpStateFeedback =
new IntFeedback(
() =>
tx.HdmiInputs[1].HdcpCapabilityFeedback > tx.HdmiInputs[2].HdcpCapabilityFeedback
? (int)tx.HdmiInputs[1].HdcpCapabilityFeedback
: (int)tx.HdmiInputs[2].HdcpCapabilityFeedback);
HdcpSupportCapability = eHdcpCapabilityType.Hdcp2_2Support;
Hdmi1VideoSyncFeedback = new BoolFeedback(() => (bool)tx.HdmiInputs[1].SyncDetectedFeedback.BoolValue);
Hdmi2VideoSyncFeedback = new BoolFeedback(() => (bool)tx.HdmiInputs[2].SyncDetectedFeedback.BoolValue);
var combinedFuncs = new VideoStatusFuncsWrapper
{
HdcpActiveFeedbackFunc = () =>
(ActualActiveVideoInput == eVst.Hdmi1
&& tx.HdmiInputs[1].VideoAttributes.HdcpActiveFeedback.BoolValue)
|| (ActualActiveVideoInput == eVst.Hdmi2
&& tx.HdmiInputs[2].VideoAttributes.HdcpActiveFeedback.BoolValue),
HdcpStateFeedbackFunc = () =>
{
if (ActualActiveVideoInput == eVst.Hdmi1)
return tx.HdmiInputs[1].VideoAttributes.HdcpStateFeedback.ToString();
if (ActualActiveVideoInput == eVst.Hdmi2)
return tx.HdmiInputs[2].VideoAttributes.HdcpStateFeedback.ToString();
return "";
},
VideoResolutionFeedbackFunc = () =>
{
if (ActualActiveVideoInput == eVst.Hdmi1)
return tx.HdmiInputs[1].VideoAttributes.GetVideoResolutionString();
if (ActualActiveVideoInput == eVst.Hdmi2)
return tx.HdmiInputs[2].VideoAttributes.GetVideoResolutionString();
return "";
},
VideoSyncFeedbackFunc = () =>
(ActualActiveVideoInput == eVst.Hdmi1
&& tx.HdmiInputs[1].SyncDetectedFeedback.BoolValue)
|| (ActualActiveVideoInput == eVst.Hdmi2
&& tx.HdmiInputs[2].SyncDetectedFeedback.BoolValue)
};
AnyVideoInput = new RoutingInputPortWithVideoStatuses(DmPortName.AnyVideoIn,
eRoutingSignalType.Audio | eRoutingSignalType.Video, eRoutingPortConnectionType.None, 0, this, combinedFuncs);
DmOut = new RoutingOutputPort(DmPortName.DmOut, eRoutingSignalType.Audio | eRoutingSignalType.Video,
eRoutingPortConnectionType.DmCat, null, this);
HdmiLoopOut = new RoutingOutputPort(DmPortName.HdmiLoopOut, eRoutingSignalType.Audio | eRoutingSignalType.Video,
eRoutingPortConnectionType.Hdmi, null, this);
AddToFeedbackList(ActiveVideoInputFeedback, VideoSourceNumericFeedback, AudioSourceNumericFeedback,
AnyVideoInput.VideoStatus.HasVideoStatusFeedback, AnyVideoInput.VideoStatus.HdcpActiveFeedback,
AnyVideoInput.VideoStatus.HdcpStateFeedback, AnyVideoInput.VideoStatus.VideoResolutionFeedback,
AnyVideoInput.VideoStatus.VideoSyncFeedback, HdmiIn1HdcpCapabilityFeedback, HdmiIn2HdcpCapabilityFeedback,
Hdmi1VideoSyncFeedback, Hdmi2VideoSyncFeedback);
// Set Ports for CEC
HdmiIn1.Port = Tx.HdmiInputs[1];
HdmiIn2.Port = Tx.HdmiInputs[2];
HdmiLoopOut.Port = Tx.HdmiOutput;
DmOut.Port = Tx.DmOutput;
}
public override bool CustomActivate()
{
// Link up all of these damned events to the various RoutingPorts via a helper handler
Tx.HdmiInputs[1].InputStreamChange += (o, a) => FowardInputStreamChange(HdmiIn1, a.EventId);
Tx.HdmiInputs[1].VideoAttributes.AttributeChange += (o, a) => ForwardVideoAttributeChange(HdmiIn1, a.EventId);
Tx.HdmiInputs[2].InputStreamChange += (o, a) => FowardInputStreamChange(HdmiIn2, a.EventId);
Tx.HdmiInputs[2].VideoAttributes.AttributeChange += (o, a) => ForwardVideoAttributeChange(HdmiIn2, a.EventId);
// Base does register and sets up comm monitoring.
return base.CustomActivate();
}
public override void LinkToApi(BasicTriList trilist, uint joinStart, string joinMapKey, EiscApiAdvanced bridge)
{
var joinMap = GetDmTxJoinMap(joinStart, joinMapKey);
if (Hdmi1VideoSyncFeedback != null)
{
Hdmi1VideoSyncFeedback.LinkInputSig(trilist.BooleanInput[joinMap.Input1VideoSyncStatus.JoinNumber]);
}
if (Hdmi2VideoSyncFeedback != null)
{
Hdmi2VideoSyncFeedback.LinkInputSig(trilist.BooleanInput[joinMap.Input2VideoSyncStatus.JoinNumber]);
}
LinkDmTxToApi(this, trilist, joinMap, bridge);
}
public void ExecuteNumericSwitch(ushort input, ushort output, eRoutingSignalType type)
{
Debug.Console(2, this, "Executing Numeric Switch to input {0}.", input);
switch (type)
{
case eRoutingSignalType.Video:
switch (input)
{
case 0:
{
ExecuteSwitch(eVst.Auto, null, type);
break;
}
case 1:
{
ExecuteSwitch(HdmiIn1.Selector, null, type);
break;
}
case 2:
{
ExecuteSwitch(HdmiIn2.Selector, null, type);
break;
}
case 3:
{
ExecuteSwitch(eVst.AllDisabled, null, type);
break;
}
}
break;
case eRoutingSignalType.Audio:
switch (input)
{
case 0:
{
ExecuteSwitch(eAst.Auto, null, type);
break;
}
case 1:
{
ExecuteSwitch(eAst.Hdmi1, null, type);
break;
}
case 2:
{
ExecuteSwitch(eAst.Hdmi2, null, type);
break;
}
case 3:
{
ExecuteSwitch(eAst.AllDisabled, null, type);
break;
}
}
break;
}
}
public void ExecuteSwitch(object inputSelector, object outputSelector, eRoutingSignalType signalType)
{
if ((signalType & eRoutingSignalType.Video) == eRoutingSignalType.Video)
Tx.VideoSource = (eVst)inputSelector;
if(((signalType & eRoutingSignalType.Audio) == eRoutingSignalType.Audio))
Debug.Console(2, this, "Unable to execute audio-only switch for tx {0}", Key);
}
void InputStreamChangeEvent(EndpointInputStream inputStream, EndpointInputStreamEventArgs args)
{
Debug.Console(2, "{0} event {1} stream {2}", Tx.ToString(), inputStream.ToString(), args.EventId.ToString());
switch (args.EventId)
{
case EndpointInputStreamEventIds.HdcpSupportOffFeedbackEventId:
case EndpointInputStreamEventIds.HdcpSupportOnFeedbackEventId:
case EndpointInputStreamEventIds.HdcpCapabilityFeedbackEventId:
if (inputStream == Tx.HdmiInputs[1]) HdmiIn1HdcpCapabilityFeedback.FireUpdate();
if (inputStream == Tx.HdmiInputs[2]) HdmiIn2HdcpCapabilityFeedback.FireUpdate();
break;
case EndpointInputStreamEventIds.SyncDetectedFeedbackEventId:
if (inputStream == Tx.HdmiInputs[1]) Hdmi1VideoSyncFeedback.FireUpdate();
if (inputStream == Tx.HdmiInputs[2]) Hdmi2VideoSyncFeedback.FireUpdate();
break;
}
ActiveVideoInputFeedback = new StringFeedback("ActiveVideoInput",
() => ActualActiveVideoInput.ToString());
Tx.HdmiInputs[1].InputStreamChange += InputStreamChangeEvent;
Tx.HdmiInputs[2].InputStreamChange += InputStreamChangeEvent;
Tx.BaseEvent += Tx_BaseEvent;
Tx.OnlineStatusChange += Tx_OnlineStatusChange;
VideoSourceNumericFeedback = new IntFeedback(() => (int)Tx.VideoSourceFeedback);
//Return VideoSourceFeedback here as DM-TX-4KZ-202-C does not support audio breakaway
AudioSourceNumericFeedback = new IntFeedback(() => (int)Tx.VideoSourceFeedback);
HdmiIn1HdcpCapabilityFeedback = new IntFeedback("HdmiIn1HdcpCapability", () => (int)tx.HdmiInputs[1].HdcpCapabilityFeedback);
HdmiIn2HdcpCapabilityFeedback = new IntFeedback("HdmiIn2HdcpCapability", () => (int)tx.HdmiInputs[2].HdcpCapabilityFeedback);
HdcpStateFeedback =
new IntFeedback(
() =>
tx.HdmiInputs[1].HdcpCapabilityFeedback > tx.HdmiInputs[2].HdcpCapabilityFeedback
? (int)tx.HdmiInputs[1].HdcpCapabilityFeedback
: (int)tx.HdmiInputs[2].HdcpCapabilityFeedback);
HdcpSupportCapability = eHdcpCapabilityType.Hdcp2_2Support;
Hdmi1VideoSyncFeedback = new BoolFeedback(() => (bool)tx.HdmiInputs[1].SyncDetectedFeedback.BoolValue);
Hdmi2VideoSyncFeedback = new BoolFeedback(() => (bool)tx.HdmiInputs[2].SyncDetectedFeedback.BoolValue);
var combinedFuncs = new VideoStatusFuncsWrapper
{
HdcpActiveFeedbackFunc = () =>
(ActualActiveVideoInput == eVst.Hdmi1
&& tx.HdmiInputs[1].VideoAttributes.HdcpActiveFeedback.BoolValue)
|| (ActualActiveVideoInput == eVst.Hdmi2
&& tx.HdmiInputs[2].VideoAttributes.HdcpActiveFeedback.BoolValue),
HdcpStateFeedbackFunc = () =>
{
if (ActualActiveVideoInput == eVst.Hdmi1)
return tx.HdmiInputs[1].VideoAttributes.HdcpStateFeedback.ToString();
if (ActualActiveVideoInput == eVst.Hdmi2)
return tx.HdmiInputs[2].VideoAttributes.HdcpStateFeedback.ToString();
return "";
},
VideoResolutionFeedbackFunc = () =>
{
if (ActualActiveVideoInput == eVst.Hdmi1)
return tx.HdmiInputs[1].VideoAttributes.GetVideoResolutionString();
if (ActualActiveVideoInput == eVst.Hdmi2)
return tx.HdmiInputs[2].VideoAttributes.GetVideoResolutionString();
return "";
},
VideoSyncFeedbackFunc = () =>
(ActualActiveVideoInput == eVst.Hdmi1
&& tx.HdmiInputs[1].SyncDetectedFeedback.BoolValue)
|| (ActualActiveVideoInput == eVst.Hdmi2
&& tx.HdmiInputs[2].SyncDetectedFeedback.BoolValue)
};
AnyVideoInput = new RoutingInputPortWithVideoStatuses(DmPortName.AnyVideoIn,
eRoutingSignalType.Audio | eRoutingSignalType.Video, eRoutingPortConnectionType.None, 0, this, combinedFuncs);
DmOut = new RoutingOutputPort(DmPortName.DmOut, eRoutingSignalType.Audio | eRoutingSignalType.Video,
eRoutingPortConnectionType.DmCat, null, this);
HdmiLoopOut = new RoutingOutputPort(DmPortName.HdmiLoopOut, eRoutingSignalType.Audio | eRoutingSignalType.Video,
eRoutingPortConnectionType.Hdmi, null, this);
AddToFeedbackList(ActiveVideoInputFeedback, VideoSourceNumericFeedback, AudioSourceNumericFeedback,
AnyVideoInput.VideoStatus.HasVideoStatusFeedback, AnyVideoInput.VideoStatus.HdcpActiveFeedback,
AnyVideoInput.VideoStatus.HdcpStateFeedback, AnyVideoInput.VideoStatus.VideoResolutionFeedback,
AnyVideoInput.VideoStatus.VideoSyncFeedback, HdmiIn1HdcpCapabilityFeedback, HdmiIn2HdcpCapabilityFeedback,
Hdmi1VideoSyncFeedback, Hdmi2VideoSyncFeedback);
// Set Ports for CEC
HdmiIn1.Port = Tx.HdmiInputs[1];
HdmiIn2.Port = Tx.HdmiInputs[2];
HdmiLoopOut.Port = Tx.HdmiOutput;
DmOut.Port = Tx.DmOutput;
}
public override bool CustomActivate()
{
// Link up all of these damned events to the various RoutingPorts via a helper handler
Tx.HdmiInputs[1].InputStreamChange += (o, a) => FowardInputStreamChange(HdmiIn1, a.EventId);
Tx.HdmiInputs[1].VideoAttributes.AttributeChange += (o, a) => ForwardVideoAttributeChange(HdmiIn1, a.EventId);
Tx.HdmiInputs[2].InputStreamChange += (o, a) => FowardInputStreamChange(HdmiIn2, a.EventId);
Tx.HdmiInputs[2].VideoAttributes.AttributeChange += (o, a) => ForwardVideoAttributeChange(HdmiIn2, a.EventId);
// Base does register and sets up comm monitoring.
return base.CustomActivate();
}
public override void LinkToApi(BasicTriList trilist, uint joinStart, string joinMapKey, EiscApiAdvanced bridge)
{
var joinMap = GetDmTxJoinMap(joinStart, joinMapKey);
if (Hdmi1VideoSyncFeedback != null)
{
Hdmi1VideoSyncFeedback.LinkInputSig(trilist.BooleanInput[joinMap.Input1VideoSyncStatus.JoinNumber]);
}
if (Hdmi2VideoSyncFeedback != null)
{
Hdmi2VideoSyncFeedback.LinkInputSig(trilist.BooleanInput[joinMap.Input2VideoSyncStatus.JoinNumber]);
}
LinkDmTxToApi(this, trilist, joinMap, bridge);
}
public void ExecuteNumericSwitch(ushort input, ushort output, eRoutingSignalType type)
{
Debug.Console(2, this, "Executing Numeric Switch to input {0}.", input);
switch (type)
{
case eRoutingSignalType.Video:
switch (input)
{
case 0:
{
ExecuteSwitch(eVst.Auto, null, type);
break;
}
case 1:
{
ExecuteSwitch(HdmiIn1.Selector, null, type);
break;
}
case 2:
{
ExecuteSwitch(HdmiIn2.Selector, null, type);
break;
}
case 3:
{
ExecuteSwitch(eVst.AllDisabled, null, type);
break;
}
}
break;
case eRoutingSignalType.Audio:
switch (input)
{
case 0:
{
ExecuteSwitch(eAst.Auto, null, type);
break;
}
case 1:
{
ExecuteSwitch(eAst.Hdmi1, null, type);
break;
}
case 2:
{
ExecuteSwitch(eAst.Hdmi2, null, type);
break;
}
case 3:
{
ExecuteSwitch(eAst.AllDisabled, null, type);
break;
}
}
break;
}
}
public void ExecuteSwitch(object inputSelector, object outputSelector, eRoutingSignalType signalType)
{
if ((signalType & eRoutingSignalType.Video) == eRoutingSignalType.Video)
Tx.VideoSource = (eVst)inputSelector;
if(((signalType & eRoutingSignalType.Audio) == eRoutingSignalType.Audio))
Debug.Console(2, this, "Unable to execute audio-only switch for tx {0}", Key);
}
void InputStreamChangeEvent(EndpointInputStream inputStream, EndpointInputStreamEventArgs args)
{
Debug.Console(2, "{0} event {1} stream {2}", Tx.ToString(), inputStream.ToString(), args.EventId.ToString());
switch (args.EventId)
{
case EndpointInputStreamEventIds.HdcpSupportOffFeedbackEventId:
case EndpointInputStreamEventIds.HdcpSupportOnFeedbackEventId:
case EndpointInputStreamEventIds.HdcpCapabilityFeedbackEventId:
if (inputStream == Tx.HdmiInputs[1]) HdmiIn1HdcpCapabilityFeedback.FireUpdate();
if (inputStream == Tx.HdmiInputs[2]) HdmiIn2HdcpCapabilityFeedback.FireUpdate();
break;
case EndpointInputStreamEventIds.SyncDetectedFeedbackEventId:
if (inputStream == Tx.HdmiInputs[1]) Hdmi1VideoSyncFeedback.FireUpdate();
if (inputStream == Tx.HdmiInputs[2]) Hdmi2VideoSyncFeedback.FireUpdate();
break;
}
}
void Tx_OnlineStatusChange(GenericBase currentDevice, OnlineOfflineEventArgs args)
@@ -313,7 +313,7 @@ namespace PepperDash.Essentials.DM
var localVideoInputPort =
InputPorts.FirstOrDefault(p => (eVst)p.Selector == Tx.VideoSourceFeedback);
var localAudioInputPort =
InputPorts.FirstOrDefault(p => (eAst)p.Selector == Tx.AudioSourceFeedback);
InputPorts.FirstOrDefault(p => (eVst)p.Selector == Tx.VideoSourceFeedback);
ActiveVideoInputFeedback.FireUpdate();
VideoSourceNumericFeedback.FireUpdate();
@@ -338,68 +338,68 @@ namespace PepperDash.Essentials.DM
OnSwitchChange(new RoutingNumericEventArgs(1, VideoSourceNumericFeedback.UShortValue, OutputPorts.First(), localVideoInputPort, eRoutingSignalType.Video));
break;
case EndpointTransmitterBase.AudioSourceFeedbackEventId:
var localInputAudioPort = InputPorts.FirstOrDefault(p => (eAst)p.Selector == Tx.AudioSourceFeedback);
Debug.Console(2, this, " Audio Source: {0}", Tx.AudioSourceFeedback);
var localInputAudioPort = InputPorts.FirstOrDefault(p => (eVst)p.Selector == Tx.VideoSourceFeedback);
Debug.Console(2, this, " Audio Source: {0}", Tx.VideoSourceFeedback);
AudioSourceNumericFeedback.FireUpdate();
OnSwitchChange(new RoutingNumericEventArgs(1, AudioSourceNumericFeedback.UShortValue, OutputPorts.First(), localInputAudioPort, eRoutingSignalType.Audio));
break;
}
}
/// <summary>
/// Relays the input stream change to the appropriate RoutingInputPort.
/// </summary>
void FowardInputStreamChange(RoutingInputPortWithVideoStatuses inputPort, int eventId)
{
if (eventId != EndpointInputStreamEventIds.SyncDetectedFeedbackEventId)
{
return;
}
inputPort.VideoStatus.VideoSyncFeedback.FireUpdate();
AnyVideoInput.VideoStatus.VideoSyncFeedback.FireUpdate();
}
/// <summary>
/// Relays the VideoAttributes change to a RoutingInputPort
/// </summary>
void ForwardVideoAttributeChange(RoutingInputPortWithVideoStatuses inputPort, int eventId)
{
//// LOCATION: Crestron.SimplSharpPro.DM.VideoAttributeEventIds
//Debug.Console(2, this, "VideoAttributes_AttributeChange event id={0} from {1}",
// args.EventId, (sender as VideoAttributesEnhanced).Owner.GetType());
switch (eventId)
{
case VideoAttributeEventIds.HdcpActiveFeedbackEventId:
inputPort.VideoStatus.HdcpActiveFeedback.FireUpdate();
AnyVideoInput.VideoStatus.HdcpActiveFeedback.FireUpdate();
break;
case VideoAttributeEventIds.HdcpStateFeedbackEventId:
inputPort.VideoStatus.HdcpStateFeedback.FireUpdate();
AnyVideoInput.VideoStatus.HdcpStateFeedback.FireUpdate();
break;
case VideoAttributeEventIds.HorizontalResolutionFeedbackEventId:
case VideoAttributeEventIds.VerticalResolutionFeedbackEventId:
inputPort.VideoStatus.VideoResolutionFeedback.FireUpdate();
AnyVideoInput.VideoStatus.VideoResolutionFeedback.FireUpdate();
break;
case VideoAttributeEventIds.FramesPerSecondFeedbackEventId:
inputPort.VideoStatus.VideoResolutionFeedback.FireUpdate();
AnyVideoInput.VideoStatus.VideoResolutionFeedback.FireUpdate();
break;
}
}
#region IIROutputPorts Members
public CrestronCollection<IROutputPort> IROutputPorts { get { return Tx.IROutputPorts; } }
public int NumberOfIROutputPorts { get { return Tx.NumberOfIROutputPorts; } }
#endregion
#region IComPorts Members
public CrestronCollection<ComPort> ComPorts { get { return Tx.ComPorts; } }
public int NumberOfComPorts { get { return Tx.NumberOfComPorts; } }
#endregion
}
}
/// <summary>
/// Relays the input stream change to the appropriate RoutingInputPort.
/// </summary>
void FowardInputStreamChange(RoutingInputPortWithVideoStatuses inputPort, int eventId)
{
if (eventId != EndpointInputStreamEventIds.SyncDetectedFeedbackEventId)
{
return;
}
inputPort.VideoStatus.VideoSyncFeedback.FireUpdate();
AnyVideoInput.VideoStatus.VideoSyncFeedback.FireUpdate();
}
/// <summary>
/// Relays the VideoAttributes change to a RoutingInputPort
/// </summary>
void ForwardVideoAttributeChange(RoutingInputPortWithVideoStatuses inputPort, int eventId)
{
//// LOCATION: Crestron.SimplSharpPro.DM.VideoAttributeEventIds
//Debug.Console(2, this, "VideoAttributes_AttributeChange event id={0} from {1}",
// args.EventId, (sender as VideoAttributesEnhanced).Owner.GetType());
switch (eventId)
{
case VideoAttributeEventIds.HdcpActiveFeedbackEventId:
inputPort.VideoStatus.HdcpActiveFeedback.FireUpdate();
AnyVideoInput.VideoStatus.HdcpActiveFeedback.FireUpdate();
break;
case VideoAttributeEventIds.HdcpStateFeedbackEventId:
inputPort.VideoStatus.HdcpStateFeedback.FireUpdate();
AnyVideoInput.VideoStatus.HdcpStateFeedback.FireUpdate();
break;
case VideoAttributeEventIds.HorizontalResolutionFeedbackEventId:
case VideoAttributeEventIds.VerticalResolutionFeedbackEventId:
inputPort.VideoStatus.VideoResolutionFeedback.FireUpdate();
AnyVideoInput.VideoStatus.VideoResolutionFeedback.FireUpdate();
break;
case VideoAttributeEventIds.FramesPerSecondFeedbackEventId:
inputPort.VideoStatus.VideoResolutionFeedback.FireUpdate();
AnyVideoInput.VideoStatus.VideoResolutionFeedback.FireUpdate();
break;
}
}
#region IIROutputPorts Members
public CrestronCollection<IROutputPort> IROutputPorts { get { return Tx.IROutputPorts; } }
public int NumberOfIROutputPorts { get { return Tx.NumberOfIROutputPorts; } }
#endregion
#region IComPorts Members
public CrestronCollection<ComPort> ComPorts { get { return Tx.ComPorts; } }
public int NumberOfComPorts { get { return Tx.NumberOfComPorts; } }
#endregion
}
}

View File

@@ -339,7 +339,7 @@ namespace PepperDash.Essentials.DM
var localVideoInputPort =
InputPorts.FirstOrDefault(p => (eVst)p.Selector == Tx.VideoSourceFeedback);
var localAudioInputPort =
InputPorts.FirstOrDefault(p => (eAst)p.Selector == Tx.AudioSourceFeedback);
InputPorts.FirstOrDefault(p => (eVst)p.Selector == Tx.VideoSourceFeedback);
ActiveVideoInputFeedback.FireUpdate();
VideoSourceNumericFeedback.FireUpdate();
@@ -364,8 +364,8 @@ namespace PepperDash.Essentials.DM
OnSwitchChange(new RoutingNumericEventArgs(1, VideoSourceNumericFeedback.UShortValue, OutputPorts.First(), localVideoInputPort, eRoutingSignalType.Video));
break;
case EndpointTransmitterBase.AudioSourceFeedbackEventId:
var localInputAudioPort = InputPorts.FirstOrDefault(p => (eAst)p.Selector == Tx.AudioSourceFeedback);
Debug.Console(2, this, " Audio Source: {0}", Tx.AudioSourceFeedback);
var localInputAudioPort = InputPorts.FirstOrDefault(p => (eVst)p.Selector == Tx.VideoSourceFeedback);
Debug.Console(2, this, " Audio Source: {0}", Tx.VideoSourceFeedback);
AudioSourceNumericFeedback.FireUpdate();
OnSwitchChange(new RoutingNumericEventArgs(1, AudioSourceNumericFeedback.UShortValue, OutputPorts.First(), localInputAudioPort, eRoutingSignalType.Audio));
break;

View File

@@ -11,10 +11,9 @@ namespace PepperDash.Essentials.Devices.Common.AudioCodec
/// <summary>
/// For rooms that have audio codec
/// </summary>
public interface IHasAudioCodec
public interface IHasAudioCodec:IHasInCallFeedback
{
AudioCodecBase AudioCodec { get; }
BoolFeedback InCallFeedback { get; }
///// <summary>
///// Make this more specific

View File

@@ -160,7 +160,19 @@ namespace PepperDash.Essentials.Devices.Common.Codec
/// </summary>
public interface IInvitableContact
{
bool IsInvitableContact { get; }
}
public class InvitableDirectoryContact : DirectoryContact, IInvitableContact
{
[JsonProperty("isInvitableContact")]
public bool IsInvitableContact
{
get
{
return this is IInvitableContact;
}
}
}
/// <summary>
@@ -209,8 +221,6 @@ namespace PepperDash.Essentials.Devices.Common.Codec
[JsonProperty("title")]
public string Title { get; set; }
[JsonProperty("contactMethods")]
public List<ContactMethod> ContactMethods { get; set; }

View File

@@ -123,6 +123,7 @@
<Compile Include="VideoCodec\Interfaces\IHasParticipants.cs" />
<Compile Include="VideoCodec\Interfaces\IHasSelfviewPosition.cs" />
<Compile Include="VideoCodec\Interfaces\IHasSelfviewSize.cs" />
<Compile Include="VideoCodec\Interfaces\IHasStartMeeting.cs" />
<Compile Include="VideoCodec\Interfaces\iVideoCodecInfo.cs" />
<Compile Include="Codec\iHasCallFavorites.cs" />
<Compile Include="Codec\iHasCallHistory.cs" />

View File

@@ -24,9 +24,9 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.Cisco
{
enum eCommandType { SessionStart, SessionEnd, Command, GetStatus, GetConfiguration };
public enum eExternalSourceType {camera, desktop, document_camera, mediaplayer, PC, whiteboard, other}
public enum eExternalSourceMode {Ready, NotReady, Hidden, Error}
public enum eExternalSourceMode {Ready, NotReady, Hidden, Error}
public class CiscoSparkCodec : VideoCodecBase, IHasCallHistory, IHasCallFavorites, IHasDirectoryHistoryStack,
public class CiscoSparkCodec : VideoCodecBase, IHasCallHistory, IHasCallFavorites, IHasDirectory,
IHasScheduleAwareness, IOccupancyStatusProvider, IHasCodecLayouts, IHasCodecSelfView,
ICommunicationMonitor, IRouting, IHasCodecCameras, IHasCameraAutoMode, IHasCodecRoomPresets, IHasExternalSourceSwitching, IHasBranding, IHasCameraOff, IHasCameraMute
{
@@ -106,9 +106,6 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.Cisco
/// </summary>
public CodecDirectory DirectoryRoot { get; private set; }
private CodecDirectory _currentDirectoryResult;
/// <summary>
/// Represents the current state of the directory and is computed on get
/// </summary>
@@ -116,15 +113,10 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.Cisco
{
get
{
return _currentDirectoryResult;
}
private set
{
_currentDirectoryResult = value;
CurrentDirectoryResultIsNotDirectoryRoot.FireUpdate();
OnDirectoryResultReturned(_currentDirectoryResult);
if (DirectoryBrowseHistory.Count > 0)
return DirectoryBrowseHistory[DirectoryBrowseHistory.Count - 1];
else
return DirectoryRoot;
}
}
@@ -135,8 +127,6 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.Cisco
/// </summary>
public List<CodecDirectory> DirectoryBrowseHistory { get; private set; }
public Stack<CodecDirectory> DirectoryBrowseHistoryStack { get; private set; }
public CodecScheduleAwareness CodecSchedule { get; private set; }
/// <summary>
@@ -362,7 +352,8 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.Cisco
CallHistory = new CodecCallHistory();
if (props.Favorites != null)
if (props.Favorites != null)
{
CallFavorites = new CodecCallFavorites();
CallFavorites.Favorites = props.Favorites;
@@ -372,12 +363,15 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.Cisco
DirectoryBrowseHistory = new List<CodecDirectory>();
DirectoryBrowseHistoryStack = new Stack<CodecDirectory>();
CurrentDirectoryResultIsNotDirectoryRoot = new BoolFeedback(() => DirectoryBrowseHistory.Count > 0);
CurrentDirectoryResultIsNotDirectoryRoot = new BoolFeedback(() => CurrentDirectoryResult != DirectoryRoot);
CurrentDirectoryResultIsNotDirectoryRoot.FireUpdate();
CodecSchedule = new CodecScheduleAwareness();
//Set Feedback Actions
SetFeedbackActions();
CodecOsdIn = new RoutingInputPort(RoutingPortNames.CodecOsd, eRoutingSignalType.Audio | eRoutingSignalType.Video,
eRoutingPortConnectionType.Hdmi, new Action(StopSharing), this);
HdmiIn2 = new RoutingInputPort(RoutingPortNames.HdmiIn2, eRoutingSignalType.Audio | eRoutingSignalType.Video,
@@ -412,9 +406,6 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.Cisco
BrandingEnabled = props.UiBranding.Enable;
_brandingUrl = props.UiBranding.BrandingUrl;
//Set Feedback Actions
SetFeedbackActions();
}
private void SetFeedbackActions()
@@ -438,11 +429,11 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.Cisco
}
catch (Exception ex)
{
Debug.Console(0, this, "Error setting MainVideoMute Action: {0}", ex);
Debug.Console(0, this, "Error setting MainVideuMute Action: {0}", ex);
if (ex.InnerException != null)
{
Debug.Console(0, this, "Error setting MainVideoMute Action: {0}", ex);
Debug.Console(0, this, "Error setting MainVideuMute Action: {0}", ex);
}
}
}
@@ -752,6 +743,10 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.Cisco
}
/// <summary>
/// Appends the delimiter and send the command to the codec
/// </summary>
/// <param name="command"></param>
public void SendText(string command)
{
if (CommDebuggingIsOn)
@@ -1034,8 +1029,6 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.Cisco
PhonebookSyncState.PhonebookRootEntriesReceived();
CurrentDirectoryResult = DirectoryRoot;
PrintDirectory(DirectoryRoot);
}
else if (PhonebookSyncState.InitialSyncComplete)
@@ -1047,7 +1040,9 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.Cisco
PrintDirectory(directoryResults);
CurrentDirectoryResult = directoryResults;
DirectoryBrowseHistory.Add(directoryResults);
OnDirectoryResultReturned(directoryResults);
}
}
@@ -1078,6 +1073,8 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.Cisco
/// <param name="result"></param>
void OnDirectoryResultReturned(CodecDirectory result)
{
CurrentDirectoryResultIsNotDirectoryRoot.FireUpdate();
// This will return the latest results to all UIs. Multiple indendent UI Directory browsing will require a different methodology
var handler = DirectoryResultReturned;
if (handler != null)
@@ -1229,8 +1226,6 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.Cisco
/// <param name="searchString"></param>
public void SearchDirectory(string searchString)
{
DirectoryBrowseHistoryStack.Push(CurrentDirectoryResult);
SendText(string.Format("xCommand Phonebook Search SearchString: \"{0}\" PhonebookType: {1} ContactType: Contact Limit: {2}", searchString, PhonebookMode, PhonebookResultsLimit));
}
@@ -1240,8 +1235,6 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.Cisco
/// <param name="folderId"></param>
public void GetDirectoryFolderContents(string folderId)
{
DirectoryBrowseHistoryStack.Push(CurrentDirectoryResult);
SendText(string.Format("xCommand Phonebook Search FolderId: {0} PhonebookType: {1} ContactType: Any Limit: {2}", folderId, PhonebookMode, PhonebookResultsLimit));
}
@@ -1251,12 +1244,24 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.Cisco
/// <returns></returns>
public void GetDirectoryParentFolderContents()
{
if (DirectoryBrowseHistoryStack.Count == 0)
var currentDirectory = new CodecDirectory();
if (DirectoryBrowseHistory.Count > 0)
{
return;
var lastItemIndex = DirectoryBrowseHistory.Count - 1;
var parentDirectoryContents = DirectoryBrowseHistory[lastItemIndex];
DirectoryBrowseHistory.Remove(DirectoryBrowseHistory[lastItemIndex]);
currentDirectory = parentDirectoryContents;
}
else
{
currentDirectory = DirectoryRoot;
}
CurrentDirectoryResult = DirectoryBrowseHistoryStack.Pop();
OnDirectoryResultReturned(currentDirectory);
}
/// <summary>
@@ -1264,9 +1269,9 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.Cisco
/// </summary>
public void SetCurrentDirectoryToRoot()
{
DirectoryBrowseHistoryStack.Clear();
DirectoryBrowseHistory.Clear();
CurrentDirectoryResult = DirectoryRoot;
OnDirectoryResultReturned(DirectoryRoot);
}
/// <summary>
@@ -1878,27 +1883,17 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.Cisco
{
get
{
try
if (CodecStatus.Status.SIP != null && CodecStatus.Status.SIP.AlternateURI.Primary.URI.Value != null)
{
if (CodecStatus.Status.SIP != null && !string.IsNullOrEmpty(CodecStatus.Status.SIP.AlternateURI.Primary.URI.Value))
{
return CodecStatus.Status.SIP.AlternateURI.Primary.URI.Value;
}
else if (CodecStatus.Status.UserInterface != null &&
CodecStatus.Status.UserInterface.ContactInfo != null && CodecStatus.Status.UserInterface.ContactInfo.ContactMethod != null)
{
return CodecStatus.Status.UserInterface.ContactInfo.ContactMethod[0].Number.Value;
}
else
{
return string.Empty;
}
return CodecStatus.Status.SIP.AlternateURI.Primary.URI.Value;
}
catch (Exception e)
else if (CodecStatus.Status.UserInterface != null &&
CodecStatus.Status.UserInterface.ContactInfo.ContactMethod[0].Number.Value != null)
{
Debug.Console(2, "Error getting SipUri: {0}", e);
return CodecStatus.Status.UserInterface.ContactInfo.ContactMethod[0].Number.Value;
}
else
return string.Empty;
}
}
}

View File

@@ -1,100 +1,102 @@
using System;
using System.Collections.Generic;
using PepperDash.Core;
using PepperDash.Essentials.Core;
namespace PepperDash.Essentials.Devices.Common.VideoCodec.Interfaces
{
/// <summary>
/// Describes a device that has call participants
/// </summary>
public interface IHasParticipants
{
CodecParticipants Participants { get; }
}
/// <summary>
/// Describes a device that has call participants
/// </summary>
public interface IHasParticipants
{
CodecParticipants Participants { get; }
}
/// <summary>
/// Describes the ability to mute and unmute a participant's video in a meeting
/// </summary>
public interface IHasParticipantVideoMute:IHasParticipants
{
void MuteVideoForParticipant(int userId);
void UnmuteVideoForParticipant(int userId);
void ToggleVideoForParticipant(int userId);
}
/// <summary>
/// Describes the ability to mute and unmute a participant's video in a meeting
/// </summary>
public interface IHasParticipantVideoMute : IHasParticipants
{
void MuteVideoForParticipant(int userId);
void UnmuteVideoForParticipant(int userId);
void ToggleVideoForParticipant(int userId);
}
/// <summary>
/// Describes the ability to mute and unmute a participant's audio in a meeting
/// </summary>
public interface IHasParticipantAudioMute : IHasParticipantVideoMute
{
void MuteAudioForParticipant(int userId);
void UnmuteAudioForParticipant(int userId);
void ToggleAudioForParticipant(int userId);
}
/// <summary>
/// Describes the ability to mute and unmute a participant's audio in a meeting
/// </summary>
public interface IHasParticipantAudioMute : IHasParticipantVideoMute
{
void MuteAudioForParticipant(int userId);
void UnmuteAudioForParticipant(int userId);
void ToggleAudioForParticipant(int userId);
}
/// <summary>
/// Describes the ability to pin and unpin a participant in a meeting
/// </summary>
public interface IHasParticipantPinUnpin : IHasParticipants
{
IntFeedback NumberOfScreensFeedback { get; }
int ScreenIndexToPinUserTo { get; }
/// <summary>
/// Describes the ability to pin and unpin a participant in a meeting
/// </summary>
public interface IHasParticipantPinUnpin : IHasParticipants
{
IntFeedback NumberOfScreensFeedback { get; }
int ScreenIndexToPinUserTo { get; }
void PinParticipant(int userId, int screenIndex);
void UnPinParticipant(int userId);
void ToggleParticipantPinState(int userId, int screenIndex);
}
void PinParticipant(int userId, int screenIndex);
void UnPinParticipant(int userId);
void ToggleParticipantPinState(int userId, int screenIndex);
}
public class CodecParticipants
{
private List<Participant> _currentParticipants;
public List<Participant> CurrentParticipants {
get { return _currentParticipants; }
set
{
_currentParticipants = value;
OnParticipantsChanged();
}
}
public class CodecParticipants
{
private List<Participant> _currentParticipants;
public event EventHandler<EventArgs> ParticipantsListHasChanged;
public List<Participant> CurrentParticipants
{
get { return _currentParticipants; }
set
{
_currentParticipants = value;
OnParticipantsChanged();
}
}
public CodecParticipants()
{
_currentParticipants = new List<Participant>();
}
public event EventHandler<EventArgs> ParticipantsListHasChanged;
public void OnParticipantsChanged()
{
var handler = ParticipantsListHasChanged;
public CodecParticipants()
{
_currentParticipants = new List<Participant>();
}
if (handler == null) return;
public void OnParticipantsChanged()
{
var handler = ParticipantsListHasChanged;
handler(this, new EventArgs());
}
}
if (handler == null) return;
/// <summary>
/// Represents a call participant
/// </summary>
public class Participant
{
public int UserId { get; set; }
public bool IsHost { get; set; }
public string Name { get; set; }
public bool CanMuteVideo { get; set; }
public bool CanUnmuteVideo { get; set; }
public bool VideoMuteFb { get; set; }
public bool AudioMuteFb { get; set; }
public bool HandIsRaisedFb { get; set; }
public bool IsPinnedFb { get; set; }
public int ScreenIndexIsPinnedToFb { get; set; }
handler(this, new EventArgs());
}
}
public Participant()
{
// Initialize to -1 (no screen)
ScreenIndexIsPinnedToFb = -1;
}
}
/// <summary>
/// Represents a call participant
/// </summary>
public class Participant
{
public int UserId { get; set; }
public bool IsHost { get; set; }
public string Name { get; set; }
public bool CanMuteVideo { get; set; }
public bool CanUnmuteVideo { get; set; }
public bool VideoMuteFb { get; set; }
public bool AudioMuteFb { get; set; }
public bool HandIsRaisedFb { get; set; }
public bool IsPinnedFb { get; set; }
public int ScreenIndexIsPinnedToFb { get; set; }
public Participant()
{
// Initialize to -1 (no screen)
ScreenIndexIsPinnedToFb = -1;
}
}
}

View File

@@ -0,0 +1,25 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Crestron.SimplSharp;
namespace PepperDash.Essentials.Devices.Common.VideoCodec.Interfaces
{
/// <summary>
/// Describes the ability to start an ad-hoc meeting
/// </summary>
public interface IHasStartMeeting
{
/// <summary>
/// The default meeting duration in minutes
/// </summary>
uint DefaultMeetingDurationMin { get; }
/// <summary>
/// Start an ad-hoc meeting for the specified duration
/// </summary>
/// <param name="duration"></param>
void StartMeeting(uint duration);
}
}

View File

@@ -11,10 +11,9 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec
/// <summary>
/// For rooms that have video codec
/// </summary>
public interface IHasVideoCodec
public interface IHasVideoCodec:IHasInCallFeedback,IPrivacy
{
VideoCodecBase VideoCodec { get; }
BoolFeedback InCallFeedback { get; }
///// <summary>
///// Make this more specific
@@ -26,11 +25,6 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec
/// </summary>
IntFeedback CallTypeFeedback { get; }
/// <summary>
///
/// </summary>
BoolFeedback PrivacyModeIsOnFeedback { get; }
/// <summary>
/// When something in the room is sharing with the far end or through other means
/// </summary>

View File

@@ -123,12 +123,14 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec
/// Creates the fake OSD source, and connects it's AudioVideo output to the CodecOsdIn input
/// to enable routing
/// </summary>
void CreateOsdSource()
private void CreateOsdSource()
{
OsdSource = new DummyRoutingInputsDevice(Key + "[osd]");
DeviceManager.AddDevice(OsdSource);
var tl = new TieLine(OsdSource.AudioVideoOutputPort, CodecOsdIn);
TieLineCollection.Default.Add(tl);
//foreach(var input in Status.Video.
}
/// <summary>
@@ -429,8 +431,8 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec
m.MinutesBeforeMeeting = 5;
m.Id = i.ToString();
m.Organizer = "Employee " + 1;
m.StartTime = DateTime.Now.AddMinutes(5).AddHours(i);
m.EndTime = DateTime.Now.AddHours(i).AddMinutes(50);
m.StartTime = DateTime.Now.AddMinutes(6).AddHours(i);
m.EndTime = DateTime.Now.AddHours(i).AddMinutes(16);
m.Title = "Meeting " + i;
m.Calls.Add(new Call() { Number = i + "meeting@fake.com"});
_CodecSchedule.Meetings.Add(m);
@@ -580,6 +582,10 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec
void SetupCameras()
{
SupportsCameraAutoMode = true;
SupportsCameraOff = false;
Cameras = new List<CameraBase>();
var internalCamera = new MockVCCamera(Key + "-camera1", "Near End", this);
@@ -596,8 +602,6 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec
CameraAutoModeIsOnFeedback = new BoolFeedback(() => _CameraAutoModeIsOn);
SupportsCameraAutoMode = true;
CameraAutoModeIsOnFeedback.FireUpdate();
DeviceManager.AddDevice(internalCamera);
@@ -605,18 +609,7 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec
NearEndPresets = new List<CodecRoomPreset>(15); // Fix the capacity to emulate Cisco
if (PropertiesConfig.Presets != null && PropertiesConfig.Presets.Count > 0)
{
NearEndPresets = PropertiesConfig.Presets;
}
else
{
for (int i = 1; i <= NearEndPresets.Capacity; i++)
{
var label = string.Format("Near End Preset {0}", i);
NearEndPresets.Add(new CodecRoomPreset(i, label, true, false));
}
}
NearEndPresets = PropertiesConfig.Presets;
FarEndRoomPresets = new List<CodecRoomPreset>(15); // Fix the capacity to emulate Cisco

View File

@@ -18,11 +18,5 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec
[JsonProperty("presets")]
public List<CodecRoomPreset> Presets { get; set; }
public MockVcPropertiesConfig()
{
Favorites = new List<CodecActiveCallItem>();
Presets = new List<CodecRoomPreset>();
}
}
}

View File

@@ -836,10 +836,10 @@ ScreenIndexIsPinnedTo: {8} (a{17})
//serials
tokenArray[stringIndex] = new XSigSerialToken(stringIndex + 1, meeting.Organizer);
tokenArray[stringIndex + 1] = new XSigSerialToken(stringIndex + 2, meeting.Title);
tokenArray[stringIndex + 2] = new XSigSerialToken(stringIndex + 3, meeting.StartTime.ToShortDateString());
tokenArray[stringIndex + 3] = new XSigSerialToken(stringIndex + 4, meeting.StartTime.ToShortTimeString());
tokenArray[stringIndex + 4] = new XSigSerialToken(stringIndex + 5, meeting.EndTime.ToShortDateString());
tokenArray[stringIndex + 5] = new XSigSerialToken(stringIndex + 6, meeting.EndTime.ToShortTimeString());
tokenArray[stringIndex + 2] = new XSigSerialToken(stringIndex + 3, meeting.StartTime.ToString("t", Global.Culture));
tokenArray[stringIndex + 3] = new XSigSerialToken(stringIndex + 4, meeting.StartTime.ToString("t", Global.Culture));
tokenArray[stringIndex + 4] = new XSigSerialToken(stringIndex + 5, meeting.EndTime.ToString("t", Global.Culture));
tokenArray[stringIndex + 5] = new XSigSerialToken(stringIndex + 6, meeting.EndTime.ToString("t", Global.Culture));
tokenArray[stringIndex + 6] = new XSigSerialToken(stringIndex + 7, meeting.Id);

View File

@@ -236,14 +236,6 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.ZoomRoom
}
}
/// <summary>
/// Used to be able to inplement IInvitableContact on DirectoryContact
/// </summary>
public class ZoomDirectoryContact : DirectoryContact, IInvitableContact
{
}
public class Phonebook
{
[JsonProperty("Contacts")]
@@ -302,7 +294,7 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.ZoomRoom
foreach (Contact c in zoomContacts)
{
var contact = new ZoomDirectoryContact { Name = c.ScreenName, ContactId = c.Jid };
var contact = new InvitableDirectoryContact { Name = c.ScreenName, ContactId = c.Jid };
contact.ContactMethods.Add(new ContactMethod() { Number = c.Jid, Device = eContactMethodDevice.Video, CallType = eContactMethodCallType.Video, ContactMethodId = c.Jid });
@@ -927,6 +919,15 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.ZoomRoom
PhoneCallStatus_InCall,
PhoneCallStatus_Init,
}
public class MeetingNeedsPassword
{
[JsonProperty("needsPassword")]
public bool NeedsPassword { get; set; }
[JsonProperty("wrongAndRetry")]
public bool WrongAndRetry { get; set; }
}
}
/// <summary>

View File

@@ -1,3 +1,3 @@
<packages>
<package id="PepperDashCore" version="1.1.0" targetFramework="net35" allowedVersions="[1.0,1.1)"/>
<package id="PepperDashCore" version="1.0.48" targetFramework="net35" allowedVersions="[1.0,1.1)"/>
</packages>