Compare commits

..

62 Commits

Author SHA1 Message Date
Neil Dorin
a76f4c15dc Updates to IHasScheduleAwareness 2021-06-29 09:47:56 -06:00
Neil Dorin
b19e2e38ad Merge pull request #727 from PepperDash/hotfix/add-eisc-server-client-options-to-eiscapiadvanced-factory
Hotfix/add eisc server client options to eiscapiadvanced factory
2021-06-24 16:53:14 -06:00
Neil Dorin
9a7fe553f9 Merge branch 'development' into hotfix/add-eisc-server-client-options-to-eiscapiadvanced-factory 2021-06-24 16:35:29 -06:00
Andrew Welker
895b76a0cd Merge pull request #723 from PepperDash/hotfix/zoom-room-views
Hotfix/zoom room views
2021-06-24 13:28:48 -06:00
Neil Dorin
5c9996e728 adds new type options to use EISCClient and EISCServer in eiscapiadvanced 2021-06-17 13:49:09 -06:00
Andrew Welker
0cc2328276 Merge branch 'development' into hotfix/zoom-room-views 2021-06-17 10:03:42 -06:00
Andrew Welker
8fadfa98f2 Merge pull request #724 from PepperDash/hotfix/zoom-room-views
Hotfix/zoom room views
2021-06-17 10:02:17 -06:00
Andrew Welker
1ccf54003f Merge branch 'main' into hotfix/zoom-room-views 2021-06-17 09:32:04 -06:00
Neil Dorin
54769ce270 Merge pull request #722 from PepperDash/hotfix/plugin-loading
Hotfix/plugin loading
2021-06-16 17:20:57 -06:00
Andrew Welker
6b85323949 Merge branch 'development' into hotfix/plugin-loading 2021-06-16 15:17:52 -06:00
Andrew Welker
319d8f99c5 Merge pull request #721 from PepperDash/hotfix/plugin-loading
adds check for abstract class before attempting to create instance
2021-06-16 15:17:32 -06:00
Neil Dorin
cc742f4291 adds check for abstract class before attempting to create instance 2021-06-16 13:11:45 -06:00
Jason DeVito
6beff106ec Updated packages.config to track latest PepperDash Core release. Updated ZoomRoom LinkZoomRoomToApi to update the bridge when it comes online. 2021-06-10 17:45:23 -05:00
Neil Dorin
cb35aa13f5 lets it fall through conditions to fire the ParticipantsChanged event if an already pinned participant is found 2021-06-09 17:55:55 -06:00
Neil Dorin
b71523bd2d Adds condition to not check for already pinned participant if incoming message has user id < 0 2021-06-09 17:38:50 -06:00
Neil Dorin
0c56da112c Changes to respond to new pinned participant message by clearing out already pinned participant fb first. 2021-06-09 17:07:25 -06:00
Neil Dorin
08f4d8e9a2 Attempts to unpin participant from same screenIndex if one is already pinned. 2021-06-09 16:57:42 -06:00
Neil Dorin
25e7e9634a updates PD Core version to include xsig token fixes 2021-06-09 16:56:56 -06:00
Neil Dorin
7ac3f81ea5 Initialize SreenIndexIsPinnedToFb to -1. Adds debugging for xsig tokens 2021-06-09 16:14:18 -06:00
Neil Dorin
1c06e8381b Fixed inverted video mute FB and adds debug statements to help see participant pin status 2021-06-09 13:30:36 -06:00
Jason DeVito
f5305197b3 Updates to LinkZoomRoomApi method 2021-06-09 13:37:01 -05:00
Jason DeVito
1805ebaf0f Converted ZoomRoom Layout Size properties and methods to interface, IHasSelfviewSize, following the patterns implemented for IHasSelfviewPosition and SelfviewPipPosition. 2021-06-08 17:56:00 -05:00
Jason DeVito
ca8207f2bd Removed Layout Position properties and methods. Using SelfviewPipPosition properties and methods. 2021-06-08 15:20:42 -05:00
Neil Dorin
4e81859695 Merge pull request #719 from PepperDash/bugfix/setdevicestreamdebug-fix
Bugfix/setdevicestreamdebug fix
2021-06-08 13:45:08 -06:00
Jason DeVito
655bb954fa Updated IHasCodecLayouts and ZoomRoom to test feedback of Layout Size and Layout Position. 2021-06-08 14:38:33 -05:00
Andrew Welker
1ebacf3f0f Fix formatting issue 2021-06-08 12:12:59 -06:00
Andrew Welker
7de0251188 add ConvertType method to convert type
This method should allow for using a string value in place of an enum as a parameter. Integers will still fail.
2021-06-08 11:44:09 -06:00
Jason DeVito
492e593263 Updated IHasCodecLayouts to implement Layout Position selection and feedback, updated bridge map to map Layout Position signals. Updated ZoomRoom to implement Layout Position selection and feedback. 2021-06-07 22:22:00 -05:00
Jason DeVito
afe2046c81 Added methods to select Call Layout Size. 2021-06-07 14:45:40 -05:00
Neil Dorin
98d3a4a2fa Merge pull request #713 from PepperDash/release/1.9.0
1.9.0
2021-05-25 14:48:52 -06:00
Andrew Welker
1702c69b73 Merge branch 'main' into release/1.9.0 2021-05-25 14:37:27 -06:00
Andrew Welker
722d28b1b3 Merge pull request #710 from PepperDash/hotfix/techroom-preset-recall-event
Hotfix/techroom preset recall event
2021-05-24 13:32:46 -06:00
Andrew Welker
ef7da0d7af Merge branch 'development' into hotfix/techroom-preset-recall-event 2021-05-24 13:19:45 -06:00
Neil Dorin
77d8e63a31 Merge pull request #709 from PepperDash/hotfix/techroom-preset-recall-event
Hotfix/techroom preset recall event
2021-05-24 12:59:54 -06:00
Neil Dorin
d2d99d4bfa Merge branch 'main' into hotfix/techroom-preset-recall-event 2021-05-24 12:45:27 -06:00
Neil Dorin
4bd71b04bf Merge pull request #708 from PepperDash/feature/add-zoomroom-participant-actions
Feature/add zoomroom participant actions
2021-05-20 20:34:45 -06:00
Andrew Welker
c5bcd89695 Merge branch 'development' into feature/add-zoomroom-participant-actions 2021-05-20 18:34:58 -06:00
Jason DeVito
c7cc98bff7 Removed old TODO's from VideoCodecBase.cs. Marked TODO's for Issue #697. 2021-05-20 19:32:11 -05:00
Jason DeVito
db60f8f1be ResponseObject.cs updates: Added and tested SortParticipantListtByHandStatus method. Found an issue with HandStatus response, property names include ': ', updated JsonProperty definitions to account for issues with expected returns vs. actual returns. 2021-05-20 15:43:02 -05:00
Andrew Welker
e82efdde2d Merge pull request #707 from PepperDash/hotfix/devjson-overload-fix
fix:(EssentialsCore) Add ability for `devjson` command to handle overloads
2021-05-20 11:04:23 -06:00
Andrew Welker
d00c8bed5f fix:(EssentialsCore) Add ability for devjson command to handle overloads
The `devjson` command needs to ability to handle overloads. With this change, if a method is an overloaded method, the command will get all methods on an object that match the entered method name, then get the first entry in the list of methods that matches the length of the provided parameters list.

This won't work in all cases, as there may be situations where the parameters of the methods have the same length, but different types. In that situation, it's likely that the conversion from `Object` to the desired type will fail, in which case, the command will notify the user that something went wrong.
2021-05-20 10:52:12 -06:00
Andrew Welker
a91af6bd75 Merge pull request #703 from PepperDash/feature/add-rfi-issue-template
Adds RFI Template
2021-05-20 09:22:23 -06:00
Neil Dorin
2d36b80800 Adds CH5 option 2021-05-14 15:46:12 -06:00
Neil Dorin
e152b9a504 Merge branch 'development' into feature/add-rfi-issue-template 2021-05-14 15:05:25 -06:00
Neil Dorin
eac7c91327 Create rfi_request.md 2021-05-13 18:07:03 -06:00
Jason DeVito
ac0d5e59a0 ZoomRoom.cs, commented out Debug statement @ line 874 to remove 'JSON Curly Brace Count:' messages in console when using debug level 2. 2021-05-12 11:27:33 -05:00
Andrew Welker
78be8ec5f2 Merge pull request #701 from PepperDash/feature/reconfigurable-device-write-control
Feature/reconfigurable device write control
2021-05-11 20:22:04 -06:00
Jason Alborough
5fc4ff6027 #700 FIxes issue where ConfigWrite.UpdateDeviceConfig and UpdateRoomConfig do not write config to file 2021-05-11 20:28:15 -04:00
Neil Dorin
63853739f3 Updates object structure to deal with a bug in ZoomRoom 5.6.3 that responds with an incorrect object structure for the layout style property 2021-05-11 17:23:26 -06:00
Jason DeVito
c14193f9ac Updates to VideoCodecControllerJoinMap to fix joins for Participant triggers. Updated ZoomRoomJoinMaps to implement zConfiguration.eLayoutStyle to pass the name across the bridge. 2021-05-11 18:13:18 -05:00
Jason T Alborough
da179c01f5 Fixes UpdateDeviceConfig() 2021-05-11 17:52:26 -04:00
Jason Alborough
0ded3e30f9 Merge branch 'development' into feature/reconfigurable-device-write-control 2021-05-11 15:24:40 -04:00
Jason T Alborough
8d215930d9 Adds WriteControlProperty to ReconfigurableDevice
CameraBase now uses ReconfigurableDevice
2021-05-11 15:20:35 -04:00
Neil Dorin
b4edb021ee #698 merged in join map updates from JKD. Fixed enum bit comparison for available layout feedbacks 2021-05-11 12:23:27 -06:00
Neil Dorin
52caa98f33 Merge branch 'feature/add-zoomroom-layout-controls' into feature/add-zoomroom-participant-actions 2021-05-11 11:10:37 -06:00
Jason DeVito
4e041d1773 Removed unused DecodecParticipantsXSig method. 2021-05-11 11:36:17 -05:00
Jason DeVito
118bd5a54a Updates VideoCodecControllerJoinMap.cs to organize joins. Update to VideoCodecBase.cs UpdateParticipantsXSig. 2021-05-11 11:19:33 -05:00
Jason DeVito
116abbf962 Updates ZoomRoomJoinMap.cs with join numbers. Updated VideoCodecControllerJoinMap.cs to organize the joins in a logical pattern. Update VideoCodecBase to add the maxAnalogs to the logic calculating xsig indexes and offsets. 2021-05-11 08:34:16 -05:00
Neil Dorin
a06333e1c3 Adds temp join numbers for participant actions 2021-05-10 15:38:33 -06:00
Neil Dorin
d937dc14fc #698 Adds actions to toggle audio/video mute and pinning for participants 2021-05-10 15:09:33 -06:00
Neil Dorin
604f4ca22d #698 Adds join objects for participants audio/video mute and pin toggle 2021-05-10 12:58:07 -06:00
Neil Dorin
685c344785 #690 fixes incorrect conditional check before firing feedback 2021-04-20 14:38:24 -06:00
21 changed files with 7477 additions and 6033 deletions

27
.github/ISSUE_TEMPLATE/rfi_request.md vendored Normal file
View File

@@ -0,0 +1,27 @@
---
name: Request for Information
about: Request specific information about capabilities of the framework
title: "[RFI]-"
labels: RFI
assignees: ''
---
**What is your request?**
Please provide as much detail as possible.
**What is the intended use case**
- [ ] Essentials Standalone Application
- [ ] Essentials + SIMPL Windows Hybrid
**User Interface Requirements**
- [ ] Not Applicable (logic only)
- [ ] Crestron Smart Graphics Touchpanel
- [ ] Cisco Touch10
- [ ] Mobile Control
- [ ] Crestron CH5 Touchpanel interface
**Additional context**
Add any other context or screenshots about the request here.

View File

@@ -107,14 +107,18 @@ namespace PepperDash.Essentials
private void TunerPresetsOnPresetRecalled(ISetTopBoxNumericKeypad device, string channel)
{
//Debug.Console(2, this, "TunerPresetsOnPresetRecalled");
if (!_currentPresets.ContainsKey(device.Key))
{
return;
}
//Debug.Console(2, this, "Tuner Key: {0} Channel: {1}", device.Key, channel);
_currentPresets[device.Key] = channel;
if (!CurrentPresetsFeedbacks.ContainsKey(device.Key))
if (CurrentPresetsFeedbacks.ContainsKey(device.Key))
{
CurrentPresetsFeedbacks[device.Key].FireUpdate();
}

View File

@@ -385,7 +385,7 @@ namespace PepperDash.Essentials.Core.Bridges
{
public EiscApiAdvancedFactory()
{
TypeNames = new List<string> { "eiscapiadv", "eiscapiadvanced", "vceiscapiadv", "vceiscapiadvanced" };
TypeNames = new List<string> { "eiscapiadv", "eiscapiadvanced", "eiscapiadvancedserver", "eiscapiadvancedclient", "vceiscapiadv", "vceiscapiadvanced" };
}
public override EssentialsDevice BuildDevice(DeviceConfig dc)
@@ -403,6 +403,16 @@ namespace PepperDash.Essentials.Core.Bridges
controlProperties.TcpSshProperties.Address, Global.ControlSystem);
return new EiscApiAdvanced(dc, eisc);
}
case "eiscapiadvancedserver":
{
var eisc = new EISCServer(controlProperties.IpIdInt, Global.ControlSystem);
return new EiscApiAdvanced(dc, eisc);
}
case "eiscapiadvancedclient":
{
var eisc = new EISCClient(controlProperties.IpIdInt, controlProperties.TcpSshProperties.Address, Global.ControlSystem);
return new EiscApiAdvanced(dc, eisc);
}
case "vceiscapiadv":
case "vceiscapiadvanced":
{

View File

@@ -1,162 +1,162 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Crestron.SimplSharp;
using Crestron.SimplSharp.CrestronIO;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using PepperDash.Core;
namespace PepperDash.Essentials.Core.Config
{
/// <summary>
/// Responsible for updating config at runtime, and writing the updates out to a local file
/// </summary>
public class ConfigWriter
{
public const string LocalConfigFolder = "LocalConfig";
public const long WriteTimeout = 30000;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Crestron.SimplSharp;
using Crestron.SimplSharp.CrestronIO;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using PepperDash.Core;
namespace PepperDash.Essentials.Core.Config
{
/// <summary>
/// Responsible for updating config at runtime, and writing the updates out to a local file
/// </summary>
public class ConfigWriter
{
public const string LocalConfigFolder = "LocalConfig";
public const long WriteTimeout = 30000;
public static CTimer WriteTimer;
static CCriticalSection fileLock = new CCriticalSection();
/// <summary>
/// Updates the config properties of a device
/// </summary>
/// <param name="deviceKey"></param>
/// <param name="properties"></param>
/// <returns></returns>
public static bool UpdateDeviceProperties(string deviceKey, JToken properties)
{
bool success = false;
// Get the current device config
var deviceConfig = ConfigReader.ConfigObject.Devices.FirstOrDefault(d => d.Key.Equals(deviceKey));
if (deviceConfig != null)
{
// Replace the current properties JToken with the new one passed into this method
deviceConfig.Properties = properties;
Debug.Console(1, "Updated properties of device: '{0}'", deviceKey);
success = true;
}
ResetTimer();
return success;
}
public static bool UpdateDeviceConfig(DeviceConfig config)
{
bool success = false;
var deviceConfig = ConfigReader.ConfigObject.Devices.FirstOrDefault(d => d.Key.Equals(config.Key));
if (deviceConfig != null)
{
deviceConfig = config;
Debug.Console(1, "Updated config of device: '{0}'", config.Key);
success = true;
}
ResetTimer();
return success;
}
public static bool UpdateRoomConfig(DeviceConfig config)
{
bool success = false;
var deviceConfig = ConfigReader.ConfigObject.Rooms.FirstOrDefault(d => d.Key.Equals(config.Key));
if (deviceConfig != null)
{
deviceConfig = config;
Debug.Console(1, "Updated config of device: '{0}'", config.Key);
success = true;
}
ResetTimer();
return success;
}
/// <summary>
/// Resets (or starts) the write timer
/// </summary>
static void ResetTimer()
{
if (WriteTimer == null)
WriteTimer = new CTimer(WriteConfigFile, WriteTimeout);
WriteTimer.Reset(WriteTimeout);
Debug.Console(1, "Config File write timer has been reset.");
}
/// <summary>
/// Writes the current config to a file in the LocalConfig subfolder
/// </summary>
/// <returns></returns>
private static void WriteConfigFile(object o)
{
var filePath = Global.FilePathPrefix + LocalConfigFolder + Global.DirectorySeparator + "configurationFile.json";
var configData = JsonConvert.SerializeObject(ConfigReader.ConfigObject);
WriteFile(filePath, configData);
}
/// <summary>
/// Writes
/// </summary>
/// <param name="filepath"></param>
/// <param name="o"></param>
public static void WriteFile(string filePath, string configData)
{
if (WriteTimer != null)
WriteTimer.Stop();
Debug.Console(0, Debug.ErrorLogLevel.Notice, "Writing Configuration to file");
Debug.Console(0, Debug.ErrorLogLevel.Notice, "Attempting to write config file: '{0}'", filePath);
try
{
if (fileLock.TryEnter())
{
using (StreamWriter sw = new StreamWriter(filePath))
{
sw.Write(configData);
sw.Flush();
}
}
else
{
Debug.Console(0, Debug.ErrorLogLevel.Error, "Unable to enter FileLock");
}
}
catch (Exception e)
{
Debug.Console(0, Debug.ErrorLogLevel.Error, "Error: Config write failed: \r{0}", e);
}
finally
{
if (fileLock != null && !fileLock.Disposed)
fileLock.Leave();
}
}
}
static CCriticalSection fileLock = new CCriticalSection();
/// <summary>
/// Updates the config properties of a device
/// </summary>
/// <param name="deviceKey"></param>
/// <param name="properties"></param>
/// <returns></returns>
public static bool UpdateDeviceProperties(string deviceKey, JToken properties)
{
bool success = false;
// Get the current device config
var deviceConfig = ConfigReader.ConfigObject.Devices.FirstOrDefault(d => d.Key.Equals(deviceKey));
if (deviceConfig != null)
{
// Replace the current properties JToken with the new one passed into this method
deviceConfig.Properties = properties;
Debug.Console(1, "Updated properties of device: '{0}'", deviceKey);
success = true;
}
ResetTimer();
return success;
}
public static bool UpdateDeviceConfig(DeviceConfig config)
{
bool success = false;
var deviceConfigIndex = ConfigReader.ConfigObject.Devices.FindIndex(d => d.Key.Equals(config.Key));
if (deviceConfigIndex >= 0)
{
ConfigReader.ConfigObject.Devices[deviceConfigIndex] = config;
Debug.Console(1, "Updated config of device: '{0}'", config.Key);
success = true;
}
ResetTimer();
return success;
}
public static bool UpdateRoomConfig(DeviceConfig config)
{
bool success = false;
var roomConfigIndex = ConfigReader.ConfigObject.Rooms.FindIndex(d => d.Key.Equals(config.Key));
if (roomConfigIndex >= 0)
{
ConfigReader.ConfigObject.Rooms[roomConfigIndex] = config;
Debug.Console(1, "Updated room of device: '{0}'", config.Key);
success = true;
}
ResetTimer();
return success;
}
/// <summary>
/// Resets (or starts) the write timer
/// </summary>
static void ResetTimer()
{
if (WriteTimer == null)
WriteTimer = new CTimer(WriteConfigFile, WriteTimeout);
WriteTimer.Reset(WriteTimeout);
Debug.Console(1, "Config File write timer has been reset.");
}
/// <summary>
/// Writes the current config to a file in the LocalConfig subfolder
/// </summary>
/// <returns></returns>
private static void WriteConfigFile(object o)
{
var filePath = Global.FilePathPrefix + LocalConfigFolder + Global.DirectorySeparator + "configurationFile.json";
var configData = JsonConvert.SerializeObject(ConfigReader.ConfigObject);
WriteFile(filePath, configData);
}
/// <summary>
/// Writes
/// </summary>
/// <param name="filepath"></param>
/// <param name="o"></param>
public static void WriteFile(string filePath, string configData)
{
if (WriteTimer != null)
WriteTimer.Stop();
Debug.Console(0, Debug.ErrorLogLevel.Notice, "Writing Configuration to file");
Debug.Console(0, Debug.ErrorLogLevel.Notice, "Attempting to write config file: '{0}'", filePath);
try
{
if (fileLock.TryEnter())
{
using (StreamWriter sw = new StreamWriter(filePath))
{
sw.Write(configData);
sw.Flush();
}
}
else
{
Debug.Console(0, Debug.ErrorLogLevel.Error, "Unable to enter FileLock");
}
}
catch (Exception e)
{
Debug.Console(0, Debug.ErrorLogLevel.Error, "Error: Config write failed: \r{0}", e);
}
finally
{
if (fileLock != null && !fileLock.Disposed)
fileLock.Leave();
}
}
}
}

View File

@@ -20,8 +20,23 @@ namespace PepperDash.Essentials.Core
/// <param name="json"></param>
public static void DoDeviceActionWithJson(string json)
{
var action = JsonConvert.DeserializeObject<DeviceActionWrapper>(json);
DoDeviceAction(action);
if (String.IsNullOrEmpty(json))
{
CrestronConsole.ConsoleCommandResponse(
"Please provide a JSON object matching the format {\"deviceKey\":\"myDevice\", \"methodName\":\"someMethod\", \"params\": [\"param1\", true]}.\r\nIf the method has no parameters, the \"params\" object may be omitted.");
return;
}
try
{
var action = JsonConvert.DeserializeObject<DeviceActionWrapper>(json);
DoDeviceAction(action);
}
catch (Exception ex)
{
CrestronConsole.ConsoleCommandResponse("Incorrect format for JSON. Please check that the format matches {\"deviceKey\":\"myDevice\", \"methodName\":\"someMethod\", \"params\": [\"param1\", true]}");
}
}
@@ -33,31 +48,65 @@ namespace PepperDash.Essentials.Core
{
var key = action.DeviceKey;
var obj = FindObjectOnPath(key);
if (obj == null)
return;
if (obj == null)
{
CrestronConsole.ConsoleCommandResponse("Unable to find object at path {0}", key);
return;
}
CType t = obj.GetType();
var method = t.GetMethod(action.MethodName);
if (method == null)
{
Debug.Console(0, "Method '{0}' not found", action.MethodName);
return;
}
var mParams = method.GetParameters();
// Add empty params if not provided
if (action.Params == null) action.Params = new object[0];
if (mParams.Length > action.Params.Length)
{
Debug.Console(0, "Method '{0}' requires {1} params", action.MethodName, mParams.Length);
return;
}
object[] convertedParams = mParams
.Select((p, i) => Convert.ChangeType(action.Params[i], p.ParameterType,
System.Globalization.CultureInfo.InvariantCulture))
.ToArray();
object ret = method.Invoke(obj, convertedParams);
if (action.Params == null)
{
//no params, so setting action.Params to empty array
action.Params = new object[0];
}
CType t = obj.GetType();
try
{
var methods = t.GetMethods().Where(m => m.Name == action.MethodName).ToList();
var method = methods.Count == 1 ? methods[0] : methods.FirstOrDefault(m => m.GetParameters().Length == action.Params.Length);
if (method == null)
{
CrestronConsole.ConsoleCommandResponse(
"Unable to find method with name {0} and that matches parameters {1}", action.MethodName,
action.Params);
return;
}
var mParams = method.GetParameters();
var convertedParams = mParams
.Select((p, i) => ConvertType(action.Params[i], p.ParameterType))
.ToArray();
method.Invoke(obj, convertedParams);
CrestronConsole.ConsoleCommandResponse("Method {0} successfully called on device {1}", method.Name,
action.DeviceKey);
}
catch (Exception ex)
{
CrestronConsole.ConsoleCommandResponse("Unable to call method with name {0}. {1}", action.MethodName,
ex.Message);}
}
private static object ConvertType(object value, Type conversionType)
{
if (!conversionType.IsEnum)
{
return Convert.ChangeType(value, conversionType, System.Globalization.CultureInfo.InvariantCulture);
}
var stringValue = Convert.ToString(value);
if (String.IsNullOrEmpty(stringValue))
{
throw new InvalidCastException(
String.Format("{0} cannot be converted to a string prior to conversion to enum"));
}
return Enum.Parse(conversionType, stringValue, true);
}
/// <summary>
/// Gets the properties on a device
/// </summary>
@@ -242,6 +291,8 @@ namespace PepperDash.Essentials.Core
//var props = t.GetProperties().Select(p => new PropertyNameType(p, obj));
//return JsonConvert.SerializeObject(props, Formatting.Indented);
}
}
public class DeviceActionWrapper

View File

@@ -435,7 +435,7 @@ namespace PepperDash.Essentials.Core
var min = Convert.ToUInt32(timeout);
device.StreamDebugging.SetDebuggingWithSpecificTimeout(debugSetting, min);
Debug.Console(0, "Device: '{0}' debug level set to {1) for {2} minutes", deviceKey, debugSetting, min);
Debug.Console(0, "Device: '{0}' debug level set to {1} for {2} minutes", deviceKey, debugSetting, min);
}
catch (Exception e)

View File

@@ -7,6 +7,8 @@ using Crestron.SimplSharpPro.DeviceSupport;
using PepperDash.Core;
using PepperDash.Essentials.Core.Bridges;
using PepperDash.Essentials.Core.Config;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
namespace PepperDash.Essentials.Core.Devices
{
@@ -52,6 +54,8 @@ namespace PepperDash.Essentials.Core.Devices
Name = config.Name;
}
/// <summary>
/// Used by the extending class to allow for any custom actions to be taken (tell the ConfigWriter to write config, etc)
/// </summary>

View File

@@ -375,7 +375,7 @@ namespace PepperDash.Essentials
{
try
{
if (typeof (IPluginDeviceFactory).IsAssignableFrom(type))
if (typeof (IPluginDeviceFactory).IsAssignableFrom(type) && !type.IsAbstract)
{
var plugin =
(IPluginDeviceFactory) Crestron.SimplSharp.Reflection.Activator.CreateInstance(type);

View File

@@ -8,6 +8,8 @@ using Crestron.SimplSharp.Reflection;
using Crestron.SimplSharpPro.DeviceSupport;
using PepperDash.Core;
using PepperDash.Essentials.Core;
using PepperDash.Essentials.Core.Devices;
using PepperDash.Essentials.Core.Config;
using PepperDash.Essentials.Core.Bridges;
using PepperDash.Essentials.Core.Presets;
using PepperDash.Essentials.Devices.Common.Codec;
@@ -25,7 +27,7 @@ namespace PepperDash.Essentials.Devices.Common.Cameras
Focus = 8
}
public abstract class CameraBase : EssentialsDevice, IRoutingOutputs
public abstract class CameraBase : ReconfigurableDevice, IRoutingOutputs
{
public eCameraControlMode ControlMode { get; protected set; }
@@ -70,12 +72,18 @@ namespace PepperDash.Essentials.Devices.Common.Cameras
// A bitmasked value to indicate the movement capabilites of this camera
protected eCameraCapabilities Capabilities { get; set; }
protected CameraBase(string key, string name) :
base(key, name)
{
OutputPorts = new RoutingPortCollection<RoutingOutputPort>();
protected CameraBase(DeviceConfig config) : base(config)
{
OutputPorts = new RoutingPortCollection<RoutingOutputPort>();
ControlMode = eCameraControlMode.Manual;
ControlMode = eCameraControlMode.Manual;
}
protected CameraBase(string key, string name) :
this (new DeviceConfig{Name = name, Key = key})
{
}
protected void LinkCameraToApi(CameraBase cameraDevice, BasicTriList trilist, uint joinStart, string joinMapKey,

View File

@@ -4,6 +4,8 @@ using System.Linq;
using System.Text;
using Crestron.SimplSharp;
using Newtonsoft.Json;
namespace PepperDash.Essentials.Devices.Common.Codec
{
public enum eMeetingEventChangeType
@@ -115,17 +117,24 @@ namespace PepperDash.Essentials.Devices.Common.Codec
/// </summary>
public class Meeting
{
[JsonProperty("minutesBeforeMeeting")]
public int MinutesBeforeMeeting;
[JsonProperty("id")]
public string Id { get; set; }
[JsonProperty("organizer")]
public string Organizer { get; set; }
[JsonProperty("title")]
public string Title { get; set; }
[JsonProperty("agenda")]
public string Agenda { get; set; }
[JsonProperty("meetingWarningMinutes")]
public TimeSpan MeetingWarningMinutes
{
get { return TimeSpan.FromMinutes(MinutesBeforeMeeting); }
}
[JsonProperty("timeToMeetingStart")]
public TimeSpan TimeToMeetingStart
{
get
@@ -133,6 +142,7 @@ namespace PepperDash.Essentials.Devices.Common.Codec
return StartTime - DateTime.Now;
}
}
[JsonProperty("timeToMeetingEnd")]
public TimeSpan TimeToMeetingEnd
{
get
@@ -140,8 +150,11 @@ namespace PepperDash.Essentials.Devices.Common.Codec
return EndTime - DateTime.Now;
}
}
[JsonProperty("startTime")]
public DateTime StartTime { get; set; }
[JsonProperty("endTime")]
public DateTime EndTime { get; set; }
[JsonProperty("duration")]
public TimeSpan Duration
{
get
@@ -149,7 +162,9 @@ namespace PepperDash.Essentials.Devices.Common.Codec
return EndTime - StartTime;
}
}
[JsonProperty("privacy")]
public eMeetingPrivacy Privacy { get; set; }
[JsonProperty("joinable")]
public bool Joinable
{
get
@@ -159,9 +174,12 @@ namespace PepperDash.Essentials.Devices.Common.Codec
}
}
//public string ConferenceNumberToDial { get; set; }
[JsonProperty("conferencePassword")]
public string ConferencePassword { get; set; }
[JsonProperty("isOneButtonToPushMeeting")]
public bool IsOneButtonToPushMeeting { get; set; }
[JsonProperty("calls")]
public List<Call> Calls { get; private set; }
public Meeting()

View File

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

View File

@@ -27,8 +27,8 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec
{
event EventHandler<LayoutInfoChangedEventArgs> AvailableLayoutsChanged;
BoolFeedback LayoutViewIsOnFirstPageFeedback { get; } // TODO: #697 Consider modifying to report button visibility in func
BoolFeedback LayoutViewIsOnLastPageFeedback { get; } // TODO: #697 Consider modifying to report button visibility in func
BoolFeedback LayoutViewIsOnFirstPageFeedback { get; } // TODO: #697 [*] Consider modifying to report button visibility in func
BoolFeedback LayoutViewIsOnLastPageFeedback { get; } // TODO: #697 [*] Consider modifying to report button visibility in func
BoolFeedback CanSwapContentWithThumbnailFeedback { get; }
BoolFeedback ContentSwappedWithThumbnailFeedback { get; }

View File

@@ -90,5 +90,11 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.Interfaces
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,13 @@
using PepperDash.Essentials.Devices.Common.VideoCodec.Cisco;
namespace PepperDash.Essentials.Core.DeviceTypeInterfaces
{
public interface IHasSelfviewSize
{
StringFeedback SelfviewPipSizeFeedback { get; }
void SelfviewPipSizeSet(CodecCommandWithLabel size);
void SelfviewPipSizeToggle();
}
}

View File

@@ -396,10 +396,12 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec
if (_CodecSchedule == null || _CodecSchedule.Meetings.Count == 0
|| _CodecSchedule.Meetings[_CodecSchedule.Meetings.Count - 1].StartTime < DateTime.Now)
{
_CodecSchedule = new CodecScheduleAwareness();
_CodecSchedule = new CodecScheduleAwareness(10000);
for (int i = 0; i < 5; i++)
{
var m = new Meeting();
m.Id = i.ToString();
m.Organizer = "Employee " + 1;
m.StartTime = DateTime.Now.AddMinutes(3).AddHours(i);
m.EndTime = DateTime.Now.AddHours(i).AddMinutes(30);
m.Title = "Meeting " + i;

View File

@@ -28,6 +28,7 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec
IUsageTracking, IHasDialer, IHasContentSharing, ICodecAudio, iVideoCodecInfo, IBridgeAdvanced
{
private const int XSigEncoding = 28591;
protected const int MaxParticipants = 50;
private readonly byte[] _clearBytes = XSigHelpers.ClearOutputs();
protected VideoCodecBase(DeviceConfig config)
: base(config)
@@ -271,14 +272,14 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec
public abstract void LinkToApi(BasicTriList trilist, uint joinStart, string joinMapKey, EiscApiAdvanced bridge);
/// <summary>
/// Use this method when using a plain VideoCodecControllerJoinMap
/// </summary>
/// <param name="codec"></param>
/// <param name="trilist"></param>
/// <param name="joinStart"></param>
/// <param name="joinMapKey"></param>
/// <param name="bridge"></param>
/// <summary>
/// Use this method when using a plain VideoCodecControllerJoinMap
/// </summary>
/// <param name="codec"></param>
/// <param name="trilist"></param>
/// <param name="joinStart"></param>
/// <param name="joinMapKey"></param>
/// <param name="bridge"></param>
protected void LinkVideoCodecToApi(VideoCodecBase codec, BasicTriList trilist, uint joinStart, string joinMapKey,
EiscApiAdvanced bridge)
{
@@ -296,144 +297,144 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec
bridge.AddJoinMap(Key, joinMap);
}
LinkVideoCodecToApi(codec, trilist, joinMap);
LinkVideoCodecToApi(codec, trilist, joinMap);
}
/// <summary>
/// Use this method when you need to pass in a join map that extends VideoCodecControllerJoinMap
/// </summary>
/// <param name="codec"></param>
/// <param name="trilist"></param>
/// <param name="joinMap"></param>
protected void LinkVideoCodecToApi(VideoCodecBase codec, BasicTriList trilist, VideoCodecControllerJoinMap joinMap)
{
Debug.Console(1, this, "Linking to Trilist {0}", trilist.ID.ToString("X"));
/// <summary>
/// Use this method when you need to pass in a join map that extends VideoCodecControllerJoinMap
/// </summary>
/// <param name="codec"></param>
/// <param name="trilist"></param>
/// <param name="joinMap"></param>
protected void LinkVideoCodecToApi(VideoCodecBase codec, BasicTriList trilist, VideoCodecControllerJoinMap joinMap)
{
Debug.Console(1, this, "Linking to Trilist {0}", trilist.ID.ToString("X"));
LinkVideoCodecDtmfToApi(trilist, joinMap);
LinkVideoCodecDtmfToApi(trilist, joinMap);
LinkVideoCodecCallControlsToApi(trilist, joinMap);
LinkVideoCodecCallControlsToApi(trilist, joinMap);
LinkVideoCodecContentSharingToApi(trilist, joinMap);
LinkVideoCodecContentSharingToApi(trilist, joinMap);
LinkVideoCodecPrivacyToApi(trilist, joinMap);
LinkVideoCodecPrivacyToApi(trilist, joinMap);
LinkVideoCodecVolumeToApi(trilist, joinMap);
LinkVideoCodecVolumeToApi(trilist, joinMap);
if (codec is ICommunicationMonitor)
{
LinkVideoCodecCommMonitorToApi(codec as ICommunicationMonitor, trilist, joinMap);
}
if (codec is ICommunicationMonitor)
{
LinkVideoCodecCommMonitorToApi(codec as ICommunicationMonitor, trilist, joinMap);
}
if (codec is IHasCodecCameras)
{
LinkVideoCodecCameraToApi(codec as IHasCodecCameras, trilist, joinMap);
}
if (codec is IHasCodecCameras)
{
LinkVideoCodecCameraToApi(codec as IHasCodecCameras, trilist, joinMap);
}
if (codec is IHasCodecSelfView)
{
LinkVideoCodecSelfviewToApi(codec as IHasCodecSelfView, trilist, joinMap);
}
if (codec is IHasCodecSelfView)
{
LinkVideoCodecSelfviewToApi(codec as IHasCodecSelfView, trilist, joinMap);
}
if (codec is IHasCameraAutoMode)
{
trilist.SetBool(joinMap.CameraSupportsAutoMode.JoinNumber, SupportsCameraAutoMode);
LinkVideoCodecCameraModeToApi(codec as IHasCameraAutoMode, trilist, joinMap);
}
if (codec is IHasCameraAutoMode)
{
trilist.SetBool(joinMap.CameraSupportsAutoMode.JoinNumber, SupportsCameraAutoMode);
LinkVideoCodecCameraModeToApi(codec as IHasCameraAutoMode, trilist, joinMap);
}
if (codec is IHasCameraOff)
{
trilist.SetBool(joinMap.CameraSupportsOffMode.JoinNumber, SupportsCameraOff);
LinkVideoCodecCameraOffToApi(codec as IHasCameraOff, trilist, joinMap);
}
if (codec is IHasCameraOff)
{
trilist.SetBool(joinMap.CameraSupportsOffMode.JoinNumber, SupportsCameraOff);
LinkVideoCodecCameraOffToApi(codec as IHasCameraOff, trilist, joinMap);
}
if (codec is IHasCodecLayouts)
{
LinkVideoCodecCameraLayoutsToApi(codec as IHasCodecLayouts, trilist, joinMap);
}
if (codec is IHasCodecLayouts)
{
LinkVideoCodecCameraLayoutsToApi(codec as IHasCodecLayouts, trilist, joinMap);
}
if (codec is IHasSelfviewPosition)
{
LinkVideoCodecSelfviewPositionToApi(codec as IHasSelfviewPosition, trilist, joinMap);
}
if (codec is IHasSelfviewPosition)
{
LinkVideoCodecSelfviewPositionToApi(codec as IHasSelfviewPosition, trilist, joinMap);
}
if (codec is IHasDirectory)
{
LinkVideoCodecDirectoryToApi(codec as IHasDirectory, trilist, joinMap);
}
if (codec is IHasDirectory)
{
LinkVideoCodecDirectoryToApi(codec as IHasDirectory, trilist, joinMap);
}
if (codec is IHasScheduleAwareness)
{
LinkVideoCodecScheduleToApi(codec as IHasScheduleAwareness, trilist, joinMap);
}
if (codec is IHasScheduleAwareness)
{
LinkVideoCodecScheduleToApi(codec as IHasScheduleAwareness, trilist, joinMap);
}
if (codec is IHasParticipants)
{
LinkVideoCodecParticipantsToApi(codec as IHasParticipants, trilist, joinMap);
}
if (codec is IHasParticipants)
{
LinkVideoCodecParticipantsToApi(codec as IHasParticipants, trilist, joinMap);
}
if (codec is IHasFarEndContentStatus)
{
(codec as IHasFarEndContentStatus).ReceivingContent.LinkInputSig(trilist.BooleanInput[joinMap.RecievingContent.JoinNumber]);
}
if (codec is IHasFarEndContentStatus)
{
(codec as IHasFarEndContentStatus).ReceivingContent.LinkInputSig(trilist.BooleanInput[joinMap.RecievingContent.JoinNumber]);
}
if (codec is IHasPhoneDialing)
{
LinkVideoCodecPhoneToApi(codec as IHasPhoneDialing, trilist, joinMap);
}
if (codec is IHasPhoneDialing)
{
LinkVideoCodecPhoneToApi(codec as IHasPhoneDialing, trilist, joinMap);
}
trilist.OnlineStatusChange += (device, args) =>
{
if (!args.DeviceOnLine) return;
trilist.OnlineStatusChange += (device, args) =>
{
if (!args.DeviceOnLine) return;
if (codec is IHasDirectory)
{
(codec as IHasDirectory).SetCurrentDirectoryToRoot();
}
if (codec is IHasDirectory)
{
(codec as IHasDirectory).SetCurrentDirectoryToRoot();
}
if (codec is IHasScheduleAwareness)
{
(codec as IHasScheduleAwareness).GetSchedule();
}
if (codec is IHasScheduleAwareness)
{
(codec as IHasScheduleAwareness).GetSchedule();
}
if (codec is IHasParticipants)
{
UpdateParticipantsXSig((codec as IHasParticipants).Participants.CurrentParticipants);
}
if (codec is IHasParticipants)
{
UpdateParticipantsXSig((codec as IHasParticipants).Participants.CurrentParticipants);
}
if (codec is IHasCameraAutoMode)
{
trilist.SetBool(joinMap.CameraSupportsAutoMode.JoinNumber, true);
if (codec is IHasCameraAutoMode)
{
trilist.SetBool(joinMap.CameraSupportsAutoMode.JoinNumber, true);
(codec as IHasCameraAutoMode).CameraAutoModeIsOnFeedback.FireUpdate();
}
(codec as IHasCameraAutoMode).CameraAutoModeIsOnFeedback.FireUpdate();
}
if (codec is IHasCodecSelfView)
{
(codec as IHasCodecSelfView).SelfviewIsOnFeedback.FireUpdate();
}
if (codec is IHasCodecSelfView)
{
(codec as IHasCodecSelfView).SelfviewIsOnFeedback.FireUpdate();
}
if (codec is IHasCameraAutoMode)
{
(codec as IHasCameraAutoMode).CameraAutoModeIsOnFeedback.FireUpdate();
}
if (codec is IHasCameraAutoMode)
{
(codec as IHasCameraAutoMode).CameraAutoModeIsOnFeedback.FireUpdate();
}
if (codec is IHasCameraOff)
{
(codec as IHasCameraOff).CameraIsOffFeedback.FireUpdate();
}
if (codec is IHasCameraOff)
{
(codec as IHasCameraOff).CameraIsOffFeedback.FireUpdate();
}
if (codec is IHasPhoneDialing)
{
(codec as IHasPhoneDialing).PhoneOffHookFeedback.FireUpdate();
}
if (codec is IHasPhoneDialing)
{
(codec as IHasPhoneDialing).PhoneOffHookFeedback.FireUpdate();
}
SharingContentIsOnFeedback.FireUpdate();
SharingContentIsOnFeedback.FireUpdate();
trilist.SetBool(joinMap.HookState.JoinNumber, IsInCall);
trilist.SetBool(joinMap.HookState.JoinNumber, IsInCall);
trilist.SetString(joinMap.CurrentCallData.JoinNumber, UpdateCallStatusXSig());
};
}
trilist.SetString(joinMap.CurrentCallData.JoinNumber, UpdateCallStatusXSig());
};
}
private void LinkVideoCodecPhoneToApi(IHasPhoneDialing codec, BasicTriList trilist, VideoCodecControllerJoinMap joinMap)
{
@@ -529,39 +530,96 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec
private void LinkVideoCodecParticipantsToApi(IHasParticipants codec, BasicTriList trilist, VideoCodecControllerJoinMap joinMap)
{
// make sure to update the values when the EISC comes online
trilist.OnlineStatusChange += (sender, args) =>
{
if (sender.IsOnline)
{
UpdateParticipantsXSig(codec, trilist, joinMap);
}
};
// set actions and update the values when the list changes
codec.Participants.ParticipantsListHasChanged += (sender, args) =>
{
string participantsXSig;
SetParticipantActions(trilist, joinMap, codec.Participants.CurrentParticipants);
if (codec.Participants.CurrentParticipants.Count == 0)
{
participantsXSig = Encoding.GetEncoding(XSigEncoding).GetString(_clearBytes, 0, _clearBytes.Length);
trilist.SetString(joinMap.CurrentParticipants.JoinNumber, participantsXSig);
trilist.SetUshort(joinMap.ParticipantCount.JoinNumber, (ushort)codec.Participants.CurrentParticipants.Count);
return;
}
participantsXSig = UpdateParticipantsXSig(codec.Participants.CurrentParticipants);
trilist.SetString(joinMap.CurrentParticipants.JoinNumber, participantsXSig);
trilist.SetUshort(joinMap.ParticipantCount.JoinNumber, (ushort)codec.Participants.CurrentParticipants.Count);
UpdateParticipantsXSig(codec, trilist, joinMap);
};
// TODO: #698 Figure out how to decode xsig data and trigger actions based on values from SIMPL
// trilist.SetStringSigAction(joinMap.CurrentParticipants.JoinNumber, // add method here to decode the xsig info and trigger actions
}
private void UpdateParticipantsXSig(IHasParticipants codec, BasicTriList trilist, VideoCodecControllerJoinMap joinMap)
{
string participantsXSig;
if (codec.Participants.CurrentParticipants.Count == 0)
{
participantsXSig = Encoding.GetEncoding(XSigEncoding).GetString(_clearBytes, 0, _clearBytes.Length);
trilist.SetString(joinMap.CurrentParticipants.JoinNumber, participantsXSig);
trilist.SetUshort(joinMap.ParticipantCount.JoinNumber, (ushort)codec.Participants.CurrentParticipants.Count);
return;
}
participantsXSig = UpdateParticipantsXSig(codec.Participants.CurrentParticipants);
trilist.SetString(joinMap.CurrentParticipants.JoinNumber, participantsXSig);
trilist.SetUshort(joinMap.ParticipantCount.JoinNumber, (ushort)codec.Participants.CurrentParticipants.Count);
}
/// <summary>
/// Sets the actions for each participant in the list
/// </summary>
private void SetParticipantActions(BasicTriList trilist, VideoCodecControllerJoinMap joinMap, List<Participant> currentParticipants)
{
uint index = 0; // track the index of the participant in the
foreach (var participant in currentParticipants)
{
var p = participant;
if (index > MaxParticipants) break;
var audioMuteCodec = this as IHasParticipantAudioMute;
if (audioMuteCodec != null)
{
trilist.SetSigFalseAction(joinMap.ParticipantAudioMuteToggleStart.JoinNumber + index,
() => audioMuteCodec.ToggleAudioForParticipant(p.UserId));
trilist.SetSigFalseAction(joinMap.ParticipantVideoMuteToggleStart.JoinNumber + index,
() => audioMuteCodec.ToggleVideoForParticipant(p.UserId));
}
var pinCodec = this as IHasParticipantPinUnpin;
if (pinCodec != null)
{
trilist.SetSigFalseAction(joinMap.ParticipantPinToggleStart.JoinNumber + index,
() => pinCodec.ToggleParticipantPinState(p.UserId, pinCodec.ScreenIndexToPinUserTo));
}
index++;
}
// Clear out any previously set actions
while (index < MaxParticipants)
{
trilist.ClearBoolSigAction(joinMap.ParticipantAudioMuteToggleStart.JoinNumber + index);
trilist.ClearBoolSigAction(joinMap.ParticipantVideoMuteToggleStart.JoinNumber + index);
trilist.ClearBoolSigAction(joinMap.ParticipantPinToggleStart.JoinNumber + index);
index++;
}
}
private string UpdateParticipantsXSig(List<Participant> currentParticipants)
{
const int maxParticipants = 50;
const int maxParticipants = MaxParticipants;
const int maxDigitals = 7;
const int maxStrings = 1;
const int maxAnalogs = 1;
const int offset = maxDigitals + maxStrings;
var digitalIndex = maxStrings * maxParticipants; //15
const int maxAnalogs = 1;
const int offset = maxDigitals + maxStrings + maxAnalogs; // 9
var digitalIndex = (maxStrings + maxAnalogs) * maxParticipants; // 100
var stringIndex = 0;
var analogIndex = 0;
var analogIndex = stringIndex + maxParticipants;
var meetingIndex = 0;
var tokenArray = new XSigToken[maxParticipants * offset];
@@ -570,6 +628,39 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec
{
if (meetingIndex >= maxParticipants * offset) break;
Debug.Console(2, this,
@"Updating Participant on xsig:
Name: {0} (s{9})
AudioMute: {1} (d{10})
VideoMute: {2} (d{11})
CanMuteVideo: {3} (d{12})
CanUMuteVideo: {4} (d{13})
IsHost: {5} (d{14})
HandIsRaised: {6} (d{15})
IsPinned: {7} (d{16})
ScreenIndexIsPinnedTo: {8} (a{17})
",
participant.Name,
participant.AudioMuteFb,
participant.VideoMuteFb,
participant.CanMuteVideo,
participant.CanUnmuteVideo,
participant.IsHost,
participant.HandIsRaisedFb,
participant.IsPinnedFb,
participant.ScreenIndexIsPinnedToFb,
stringIndex + 1,
digitalIndex + 1,
digitalIndex + 2,
digitalIndex + 3,
digitalIndex + 4,
digitalIndex + 5,
digitalIndex + 6,
digitalIndex + 7,
analogIndex + 1
);
//digitals
tokenArray[digitalIndex] = new XSigDigitalToken(digitalIndex + 1, participant.AudioMuteFb);
tokenArray[digitalIndex + 1] = new XSigDigitalToken(digitalIndex + 2, participant.VideoMuteFb);
@@ -577,44 +668,51 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec
tokenArray[digitalIndex + 3] = new XSigDigitalToken(digitalIndex + 4, participant.CanUnmuteVideo);
tokenArray[digitalIndex + 4] = new XSigDigitalToken(digitalIndex + 5, participant.IsHost);
tokenArray[digitalIndex + 5] = new XSigDigitalToken(digitalIndex + 6, participant.HandIsRaisedFb);
tokenArray[digitalIndex + 6] = new XSigDigitalToken(digitalIndex + 6, participant.IsPinnedFb);
tokenArray[digitalIndex + 6] = new XSigDigitalToken(digitalIndex + 7, participant.IsPinnedFb);
Debug.Console(2, this, "Index: {0} byte value: {1}", digitalIndex + 7, ComTextHelper.GetEscapedText(tokenArray[digitalIndex + 6].GetBytes()));
//serials
tokenArray[stringIndex] = new XSigSerialToken(stringIndex + 1, participant.Name);
//analogs
tokenArray[analogIndex] = new XSigAnalogToken(analogIndex + 1, (ushort)participant.ScreenIndexIsPinnedToFb);
//analogs
tokenArray[analogIndex] = new XSigAnalogToken(analogIndex + 1, (ushort)participant.ScreenIndexIsPinnedToFb);
digitalIndex += maxDigitals;
meetingIndex += offset;
stringIndex += maxStrings;
analogIndex += maxAnalogs;
analogIndex += maxAnalogs;
}
while (meetingIndex < maxParticipants * offset)
{
//digitals
//digitals
tokenArray[digitalIndex] = new XSigDigitalToken(digitalIndex + 1, false);
tokenArray[digitalIndex + 1] = new XSigDigitalToken(digitalIndex + 2, false);
tokenArray[digitalIndex + 2] = new XSigDigitalToken(digitalIndex + 3, false);
tokenArray[digitalIndex + 3] = new XSigDigitalToken(digitalIndex + 4, false);
tokenArray[digitalIndex + 4] = new XSigDigitalToken(digitalIndex + 5, false);
tokenArray[digitalIndex + 5] = new XSigDigitalToken(digitalIndex + 6, false);
tokenArray[digitalIndex + 6] = new XSigDigitalToken(digitalIndex + 7, false);
tokenArray[digitalIndex + 5] = new XSigDigitalToken(digitalIndex + 6, false);
tokenArray[digitalIndex + 6] = new XSigDigitalToken(digitalIndex + 7, false);
//serials
tokenArray[stringIndex] = new XSigSerialToken(stringIndex + 1, String.Empty);
//analogs
tokenArray[analogIndex] = new XSigAnalogToken(analogIndex + 1, 0);
//analogs
tokenArray[analogIndex] = new XSigAnalogToken(analogIndex + 1, 0);
digitalIndex += maxDigitals;
meetingIndex += offset;
stringIndex += maxStrings;
analogIndex += maxAnalogs;
analogIndex += maxAnalogs;
}
return GetXSigString(tokenArray);
var returnString = GetXSigString(tokenArray);
//Debug.Console(2, this, "{0}", ComTextHelper.GetEscapedText(Encoding.GetEncoding(28591).GetBytes(returnString)));
return returnString;
}
private void LinkVideoCodecContentSharingToApi(BasicTriList trilist, VideoCodecControllerJoinMap joinMap)
@@ -630,7 +728,6 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec
trilist.SetBoolSigAction(joinMap.SourceShareAutoStart.JoinNumber, (b) => AutoShareContentWhileInCall = b);
}
// TODO [ ] 2021-01-06, jkd: Added to debug OBTP dialing issues
private List<Meeting> _currentMeetings = new List<Meeting>();
private void LinkVideoCodecScheduleToApi(IHasScheduleAwareness codec, BasicTriList trilist, VideoCodecControllerJoinMap joinMap)
@@ -642,7 +739,6 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec
codec.CodecSchedule.MeetingWarningMinutes = i;
});
// TODO [ ] 2021-01-06, jkd: Added to debug OBTP dialing issues
trilist.SetSigFalseAction(joinMap.DialMeeting1.JoinNumber, () =>
{
var mtg = 1;
@@ -652,7 +748,7 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec
if (_currentMeetings[index] != null)
Dial(_currentMeetings[index]);
});
// TODO [ ] 2021-01-06, jkd: Added to debug OBTP dialing issues
trilist.SetSigFalseAction(joinMap.DialMeeting2.JoinNumber, () =>
{
var mtg = 2;
@@ -662,7 +758,7 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec
if (_currentMeetings[index] != null)
Dial(_currentMeetings[index]);
});
// TODO [ ] 2021-01-06, jkd: Added to debug OBTP dialing issues
trilist.SetSigFalseAction(joinMap.DialMeeting3.JoinNumber, () =>
{
var mtg = 3;
@@ -687,14 +783,8 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec
{
var currentTime = DateTime.Now;
// TODO [ ] 2021-01-06, jkd: Added to debug OBTP dialing issues
// - changed var currentMeetings >> field _currentMeetings
//_currentMeetings.Clear();
_currentMeetings = codec.CodecSchedule.Meetings.Where(m => m.StartTime >= currentTime || m.EndTime >= currentTime).ToList();
// TODO [ ] 2021-01-06, jkd: Added to debug OBTP dialing issues
// - moved the trilist.SetSigFlaseAction(joinMap.DialMeeting1..3.JoinNumber) lambda's to LinkVideoCodecScheduleToApi
var meetingsData = UpdateMeetingsListXSig(_currentMeetings);
trilist.SetString(joinMap.Schedule.JoinNumber, meetingsData);
trilist.SetUshort(joinMap.MeetingCount.JoinNumber, (ushort)_currentMeetings.Count);
@@ -882,7 +972,7 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec
Debug.Console(1, this, "Call Direction: {0}", args.CallItem.Direction);
Debug.Console(1, this, "Call is incoming: {0}", args.CallItem.Direction == eCodecCallDirection.Incoming);
trilist.SetBool(joinMap.IncomingCall.JoinNumber, args.CallItem.Direction == eCodecCallDirection.Incoming && args.CallItem.Status == eCodecCallStatus.Ringing);
trilist.SetBool(joinMap.IncomingCall.JoinNumber, args.CallItem.Direction == eCodecCallDirection.Incoming && args.CallItem.Status == eCodecCallStatus.Ringing);
if (args.CallItem.Direction == eCodecCallDirection.Incoming)
{

View File

@@ -4,158 +4,298 @@ using PepperDash.Essentials.Core.Bridges.JoinMaps;
namespace PepperDash.Essentials.Devices.Common.VideoCodec.ZoomRoom
{
public class ZoomRoomJoinMap : VideoCodecControllerJoinMap
{
// TODO: #697 Set join numbers
public class ZoomRoomJoinMap : VideoCodecControllerJoinMap
{
#region Digital
[JoinName("LayoutIsOnFirstPage")]
public JoinDataComplete LayoutIsOnFirstPage =
new JoinDataComplete(new JoinData { JoinNumber = 999, JoinSpan = 1 },
new JoinMetadata
{
Description = "Indicates if layout is on first page",
JoinCapabilities = eJoinCapabilities.ToSIMPL,
JoinType = eJoinType.Digital
});
[JoinName("CanSwapContentWithThumbnail")]
public JoinDataComplete CanSwapContentWithThumbnail = new JoinDataComplete(
new JoinData
{
JoinNumber = 206,
JoinSpan = 1
},
new JoinMetadata
{
Description = "FB Indicates if content can be swapped with thumbnail",
JoinCapabilities = eJoinCapabilities.ToSIMPL,
JoinType = eJoinType.Digital
});
[JoinName("LayoutIsOnLastPage")]
public JoinDataComplete LayoutIsOnLastPage =
new JoinDataComplete(new JoinData { JoinNumber = 999, JoinSpan = 1 },
new JoinMetadata
{
Description = "Indicates if layout is on first page",
JoinCapabilities = eJoinCapabilities.ToSIMPL,
JoinType = eJoinType.Digital
});
[JoinName("SwapContentWithThumbnail")]
public JoinDataComplete SwapContentWithThumbnail = new JoinDataComplete(
new JoinData
{
JoinNumber = 206,
JoinSpan = 1
},
new JoinMetadata
{
Description = "Pulse to swap content with thumbnail. FB reports current state",
JoinCapabilities = eJoinCapabilities.ToFromSIMPL,
JoinType = eJoinType.Digital
});
[JoinName("LayoutTurnToNextPage")]
public JoinDataComplete LayoutTurnToNextPage =
new JoinDataComplete(new JoinData { JoinNumber = 999, JoinSpan = 1 },
new JoinMetadata
{
Description = "Turns layout view to next page",
JoinCapabilities = eJoinCapabilities.FromSIMPL,
JoinType = eJoinType.Digital
});
[JoinName("GetAvailableLayouts")]
public JoinDataComplete GetAvailableLayouts = new JoinDataComplete(
new JoinData
{
JoinNumber = 215,
JoinSpan = 1
},
new JoinMetadata
{
Description = "Gets the available layouts. Will update the LayoutXXXXXIsAvailbale signals.",
JoinCapabilities = eJoinCapabilities.FromSIMPL,
JoinType = eJoinType.Digital
});
[JoinName("LayoutTurnToPreviousPage")]
public JoinDataComplete LayoutTurnToPreviousPage =
new JoinDataComplete(new JoinData { JoinNumber = 999, JoinSpan = 1 },
new JoinMetadata
{
Description = "Turns layout view to previous page",
JoinCapabilities = eJoinCapabilities.FromSIMPL,
JoinType = eJoinType.Digital
});
[JoinName("LayoutIsOnFirstPage")]
public JoinDataComplete LayoutIsOnFirstPage = new JoinDataComplete(
new JoinData
{
JoinNumber = 216,
JoinSpan = 1
},
new JoinMetadata
{
Description = "Indicates if layout is on first page",
JoinCapabilities = eJoinCapabilities.ToSIMPL,
JoinType = eJoinType.Digital
});
[JoinName("CanSwapContentWithThumbnail")]
public JoinDataComplete CanSwapContentWithThumbnail =
new JoinDataComplete(new JoinData { JoinNumber = 999, JoinSpan = 1 },
new JoinMetadata
{
Description = "FB Indicates if content can be swapped with thumbnail",
JoinCapabilities = eJoinCapabilities.ToSIMPL,
JoinType = eJoinType.Digital
});
[JoinName("LayoutIsOnLastPage")]
public JoinDataComplete LayoutIsOnLastPage = new JoinDataComplete(
new JoinData
{
JoinNumber = 217,
JoinSpan = 1
},
new JoinMetadata
{
Description = "Indicates if layout is on first page",
JoinCapabilities = eJoinCapabilities.ToSIMPL,
JoinType = eJoinType.Digital
});
[JoinName("SwapContentWithThumbnail")]
public JoinDataComplete SwapContentWithThumbnail =
new JoinDataComplete(new JoinData { JoinNumber = 999, JoinSpan = 1 },
new JoinMetadata
{
Description = "Pulse to swap content with thumbnail. FB reports current state",
JoinCapabilities = eJoinCapabilities.ToFromSIMPL,
JoinType = eJoinType.Digital
});
[JoinName("LayoutTurnToNextPage")]
public JoinDataComplete LayoutTurnToNextPage = new JoinDataComplete(
new JoinData
{
JoinNumber = 216,
JoinSpan = 1
},
new JoinMetadata
{
Description = "Turns layout view to next page",
JoinCapabilities = eJoinCapabilities.FromSIMPL,
JoinType = eJoinType.Digital
});
[JoinName("GetSetCurrentLayout")]
public JoinDataComplete GetSetCurrentLayout =
new JoinDataComplete(new JoinData { JoinNumber = 999, JoinSpan = 1 },
new JoinMetadata
{
Description = "Sets and reports the current layout. Use the LayoutXXXXIsAvailable signals to determine valid layouts",
JoinCapabilities = eJoinCapabilities.ToFromSIMPL,
JoinType = eJoinType.Serial
});
[JoinName("LayoutTurnToPreviousPage")]
public JoinDataComplete LayoutTurnToPreviousPage = new JoinDataComplete(
new JoinData
{
JoinNumber = 217,
JoinSpan = 1
},
new JoinMetadata
{
Description = "Turns layout view to previous page",
JoinCapabilities = eJoinCapabilities.FromSIMPL,
JoinType = eJoinType.Digital
});
[JoinName("GetAvailableLayouts")]
public JoinDataComplete GetAvailableLayouts =
new JoinDataComplete(new JoinData { JoinNumber = 999, JoinSpan = 1 },
new JoinMetadata
{
Description = "Gets the available layouts. Will update the LayoutXXXXXIsAvailbale signals.",
JoinCapabilities = eJoinCapabilities.FromSIMPL,
JoinType = eJoinType.Serial
});
[JoinName("LayoutGalleryIsAvailable")]
public JoinDataComplete LayoutGalleryIsAvailable = new JoinDataComplete(
new JoinData
{
JoinNumber = 221,
JoinSpan = 1
},
new JoinMetadata
{
Description = "FB Indicates if layout 'Gallery' is available",
JoinCapabilities = eJoinCapabilities.ToSIMPL,
JoinType = eJoinType.DigitalSerial
});
[JoinName("LayoutGalleryIsAvailable")]
public JoinDataComplete LayoutGalleryIsAvailable =
new JoinDataComplete(new JoinData { JoinNumber = 999, JoinSpan = 1 },
new JoinMetadata
{
Description = "FB Indicates if layout 'Gallery' is available",
JoinCapabilities = eJoinCapabilities.ToSIMPL,
JoinType = eJoinType.Digital
});
[JoinName("LayoutSpeakerIsAvailable")]
public JoinDataComplete LayoutSpeakerIsAvailable = new JoinDataComplete(
new JoinData
{
JoinNumber = 222,
JoinSpan = 1
},
new JoinMetadata
{
Description = "FB Indicates if layout 'Speaker' is available",
JoinCapabilities = eJoinCapabilities.ToSIMPL,
JoinType = eJoinType.DigitalSerial
});
[JoinName("LayoutSpeakerIsAvailable")]
public JoinDataComplete LayoutSpeakerIsAvailable =
new JoinDataComplete(new JoinData { JoinNumber = 999, JoinSpan = 1 },
new JoinMetadata
{
Description = "FB Indicates if layout 'Speaker' is available",
JoinCapabilities = eJoinCapabilities.ToSIMPL,
JoinType = eJoinType.Digital
});
[JoinName("LayoutStripIsAvailable")]
public JoinDataComplete LayoutStripIsAvailable = new JoinDataComplete(
new JoinData
{
JoinNumber = 223,
JoinSpan = 1
},
new JoinMetadata
{
Description = "FB Indicates if layout 'Strip' is available",
JoinCapabilities = eJoinCapabilities.ToSIMPL,
JoinType = eJoinType.DigitalSerial
});
[JoinName("LayoutStripIsAvailable")]
public JoinDataComplete LayoutStripIsAvailable =
new JoinDataComplete(new JoinData { JoinNumber = 999, JoinSpan = 1 },
new JoinMetadata
{
Description = "FB Indicates if layout 'Strip' is available",
JoinCapabilities = eJoinCapabilities.ToSIMPL,
JoinType = eJoinType.Digital
});
[JoinName("LayoutShareAllIsAvailable")]
public JoinDataComplete LayoutShareAllIsAvailable = new JoinDataComplete(
new JoinData
{
JoinNumber = 224,
JoinSpan = 1
},
new JoinMetadata
{
Description = "FB Indicates if layout 'ShareAll' is available",
JoinCapabilities = eJoinCapabilities.ToSIMPL,
JoinType = eJoinType.DigitalSerial
});
[JoinName("LayoutShareAllIsAvailable")]
public JoinDataComplete LayoutShareAllIsAvailable =
new JoinDataComplete(new JoinData { JoinNumber = 999, JoinSpan = 1 },
new JoinMetadata
{
Description = "FB Indicates if layout 'ShareAll' is available",
JoinCapabilities = eJoinCapabilities.ToSIMPL,
JoinType = eJoinType.Digital
});
// TODO: #714 [ ] JoinMap >> SelfivewPipSizeToggle
[JoinName("SelfviewPipSizeToggle")]
public JoinDataComplete SelfviewPipSizeToggle = new JoinDataComplete(
new JoinData
{
JoinNumber = 231,
JoinSpan = 1
},
new JoinMetadata
{
Description = "Toggles the selfview pip size, (aka layout size)",
JoinCapabilities = eJoinCapabilities.ToFromSIMPL,
JoinType = eJoinType.Digital
});
[JoinName("ScreenIndexToPinUserTo")]
public JoinDataComplete ScreenIndexToPinUserTo =
new JoinDataComplete(new JoinData { JoinNumber = 999, JoinSpan = 1 },
new JoinMetadata
{
Description = "Specifies the screen index a participant should be pinned to",
JoinCapabilities = eJoinCapabilities.FromSIMPL,
JoinType = eJoinType.Analog
});
//[JoinName("ParticipantAudioMuteToggleStart")]
//public JoinDataComplete ParticipantAudioMuteToggleStart = new JoinDataComplete(
// new JoinData
// {
// JoinNumber = 500,
// JoinSpan = 100
// },
// new JoinMetadata
// {
// Description = "Toggles the participant's audio mute status",
// JoinCapabilities = eJoinCapabilities.ToSIMPL,
// JoinType = eJoinType.Digital
// });
[JoinName("NumberOfScreens")]
public JoinDataComplete NumberOfScreens =
new JoinDataComplete(new JoinData { JoinNumber = 999, JoinSpan = 1 },
new JoinMetadata
{
Description = "Reports the number of screens connected",
JoinCapabilities = eJoinCapabilities.ToSIMPL,
JoinType = eJoinType.Analog
});
//[JoinName("ParticipantVideoMuteToggleStart")]
//public JoinDataComplete ParticipantVideoMuteToggleStart = new JoinDataComplete(
// new JoinData
// {
// JoinNumber = 800,
// JoinSpan = 100
// },
// new JoinMetadata
// {
// Description = "Toggles the participant's video mute status",
// JoinCapabilities = eJoinCapabilities.ToSIMPL,
// JoinType = eJoinType.Digital
// });
public ZoomRoomJoinMap(uint joinStart)
: base(joinStart, typeof(ZoomRoomJoinMap))
{
}
//[JoinName("ParticipantPinToggleStart")]
//public JoinDataComplete ParticipantPinToggleStart = new JoinDataComplete(
// new JoinData
// {
// JoinNumber = 1100,
// JoinSpan = 100
// },
// new JoinMetadata
// {
// Description = "Toggles the participant's pin status",
// JoinCapabilities = eJoinCapabilities.ToSIMPL,
// JoinType = eJoinType.Digital
// });
public ZoomRoomJoinMap(uint joinStart, Type type)
: base(joinStart, type)
{
}
}
#endregion
#region Analog
[JoinName("NumberOfScreens")]
public JoinDataComplete NumberOfScreens = new JoinDataComplete(
new JoinData
{
JoinNumber = 11,
JoinSpan = 1
},
new JoinMetadata
{
Description = "Reports the number of screens connected",
JoinCapabilities = eJoinCapabilities.ToSIMPL,
JoinType = eJoinType.Analog
});
[JoinName("ScreenIndexToPinUserTo")]
public JoinDataComplete ScreenIndexToPinUserTo = new JoinDataComplete(
new JoinData
{
JoinNumber = 11,
JoinSpan = 1
},
new JoinMetadata
{
Description = "Specifies the screen index a participant should be pinned to",
JoinCapabilities = eJoinCapabilities.FromSIMPL,
JoinType = eJoinType.Analog
});
#endregion
#region Serials
[JoinName("GetSetCurrentLayout")]
public JoinDataComplete GetSetCurrentLayout = new JoinDataComplete(
new JoinData
{
JoinNumber = 215,
JoinSpan = 1
},
new JoinMetadata
{
Description = "Sets and reports the current layout. Use the LayoutXXXXIsAvailable signals to determine valid layouts",
JoinCapabilities = eJoinCapabilities.ToFromSIMPL,
JoinType = eJoinType.Serial
});
// TODO: #714 [ ] JoinMap >> GetSetSelfviewPipSize
[JoinName("GetSetSelfviewPipSize")]
public JoinDataComplete GetSetSelfviewPipSize = new JoinDataComplete(
new JoinData
{
JoinNumber = 230,
JoinSpan = 1
},
new JoinMetadata
{
Description = "Sets and reports the selfview pip size, (aka layout size).",
JoinCapabilities = eJoinCapabilities.ToFromSIMPL,
JoinType = eJoinType.DigitalSerial
});
#endregion
public ZoomRoomJoinMap(uint joinStart)
: base(joinStart, typeof(ZoomRoomJoinMap))
{
}
public ZoomRoomJoinMap(uint joinStart, Type type)
: base(joinStart, type)
{
}
}
}

View File

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