mirror of
https://github.com/PepperDash/Essentials.git
synced 2026-02-02 06:14:52 +00:00
Compare commits
36 Commits
1.8.5-alph
...
1.9.1-hotf
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
1805ebaf0f | ||
|
|
ca8207f2bd | ||
|
|
655bb954fa | ||
|
|
492e593263 | ||
|
|
afe2046c81 | ||
|
|
98d3a4a2fa | ||
|
|
1702c69b73 | ||
|
|
722d28b1b3 | ||
|
|
ef7da0d7af | ||
|
|
77d8e63a31 | ||
|
|
d2d99d4bfa | ||
|
|
4bd71b04bf | ||
|
|
c5bcd89695 | ||
|
|
c7cc98bff7 | ||
|
|
db60f8f1be | ||
|
|
e82efdde2d | ||
|
|
d00c8bed5f | ||
|
|
a91af6bd75 | ||
|
|
2d36b80800 | ||
|
|
e152b9a504 | ||
|
|
eac7c91327 | ||
|
|
ac0d5e59a0 | ||
|
|
78be8ec5f2 | ||
|
|
5fc4ff6027 | ||
|
|
63853739f3 | ||
|
|
c14193f9ac | ||
|
|
da179c01f5 | ||
|
|
0ded3e30f9 | ||
|
|
8d215930d9 | ||
|
|
b4edb021ee | ||
|
|
52caa98f33 | ||
|
|
4e041d1773 | ||
|
|
118bd5a54a | ||
|
|
a06333e1c3 | ||
|
|
d937dc14fc | ||
|
|
685c344785 |
27
.github/ISSUE_TEMPLATE/rfi_request.md
vendored
Normal file
27
.github/ISSUE_TEMPLATE/rfi_request.md
vendored
Normal 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.
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -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();
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
@@ -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,29 +48,47 @@ 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) => Convert.ChangeType(action.Params[i], p.ParameterType,
|
||||
System.Globalization.CultureInfo.InvariantCulture))
|
||||
.ToArray();
|
||||
var ret = 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);}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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" />
|
||||
|
||||
@@ -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; }
|
||||
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
@@ -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)
|
||||
@@ -541,28 +542,69 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec
|
||||
return;
|
||||
}
|
||||
|
||||
SetParticipantActions(trilist, joinMap, codec.Participants.CurrentParticipants);
|
||||
|
||||
participantsXSig = UpdateParticipantsXSig(codec.Participants.CurrentParticipants);
|
||||
|
||||
trilist.SetString(joinMap.CurrentParticipants.JoinNumber, participantsXSig);
|
||||
|
||||
trilist.SetUshort(joinMap.ParticipantCount.JoinNumber, (ushort)codec.Participants.CurrentParticipants.Count);
|
||||
};
|
||||
|
||||
// TODO: #698 [ ] Figure out how to decode xsig data and trigger actions based on values from SIMPL
|
||||
// add method here to decode the xsig info and trigger actions
|
||||
//trilist.SetStringSigAction(joinMap.CurrentParticipants.JoinNumber, DecodeParticipantsXSig);
|
||||
}
|
||||
|
||||
/// <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 + maxAnalogs;
|
||||
var digitalIndex = maxStrings + maxAnalogs * maxParticipants; //15
|
||||
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];
|
||||
@@ -577,8 +619,8 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec
|
||||
tokenArray[digitalIndex + 2] = new XSigDigitalToken(digitalIndex + 3, participant.CanMuteVideo);
|
||||
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 + 7, participant.IsPinnedFb);
|
||||
tokenArray[digitalIndex + 5] = new XSigDigitalToken(digitalIndex + 6, participant.HandIsRaisedFb);
|
||||
tokenArray[digitalIndex + 6] = new XSigDigitalToken(digitalIndex + 7, participant.IsPinnedFb);
|
||||
|
||||
//serials
|
||||
tokenArray[stringIndex] = new XSigSerialToken(stringIndex + 1, participant.Name);
|
||||
@@ -618,47 +660,6 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec
|
||||
return GetXSigString(tokenArray);
|
||||
}
|
||||
|
||||
// TODO: #698 [ ] Figure out how to decode xsig data and trigger actions based on values from SIMPL
|
||||
private void DecodeParticipantsXSig(string xsigData)
|
||||
{
|
||||
if (string.IsNullOrEmpty(xsigData)) return;
|
||||
var bytes = Encoding.GetEncoding(XSigEncoding).GetBytes(xsigData);
|
||||
using (var xsigStream = new XSigTokenStreamReader(new MemoryStream(bytes)))
|
||||
{
|
||||
XSigToken token = null;
|
||||
while ((token = xsigStream.ReadXSigToken()) != null)
|
||||
{
|
||||
switch (token.TokenType)
|
||||
{
|
||||
case XSigTokenType.Digital:
|
||||
{
|
||||
var data = token as XSigDigitalToken;
|
||||
if (data == null) return;
|
||||
Debug.Console(1, this, "xSig Data TokenType: {0} | Index: {1} | Value: {2}",
|
||||
data.TokenType, data.Index, data.Value.ToString());
|
||||
break;
|
||||
}
|
||||
case XSigTokenType.Analog:
|
||||
{
|
||||
var data = token as XSigAnalogToken;
|
||||
if (data == null) return;
|
||||
Debug.Console(1, this, "xSig Data TokenType: {0} | Index: {1} | Value: {2}",
|
||||
data.TokenType, data.Index, data.Value);
|
||||
break;
|
||||
}
|
||||
case XSigTokenType.Serial:
|
||||
{
|
||||
var data = token as XSigSerialToken;
|
||||
if (data == null) return;
|
||||
Debug.Console(1, this, "xSig Data TokenType: {0} | Index: {1} | Value: {2}", data.TokenType, data.Index,
|
||||
data.Value);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void LinkVideoCodecContentSharingToApi(BasicTriList trilist, VideoCodecControllerJoinMap joinMap)
|
||||
{
|
||||
SharingContentIsOnFeedback.LinkInputSig(trilist.BooleanInput[joinMap.SourceShareStart.JoinNumber]);
|
||||
@@ -672,7 +673,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)
|
||||
@@ -684,7 +684,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;
|
||||
@@ -694,7 +693,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;
|
||||
@@ -704,7 +703,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;
|
||||
@@ -729,14 +728,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);
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -6,8 +6,6 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.ZoomRoom
|
||||
{
|
||||
public class ZoomRoomJoinMap : VideoCodecControllerJoinMap
|
||||
{
|
||||
// TODO: #697 [X] Set join numbers
|
||||
|
||||
#region Digital
|
||||
|
||||
[JoinName("CanSwapContentWithThumbnail")]
|
||||
@@ -119,7 +117,7 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.ZoomRoom
|
||||
{
|
||||
Description = "FB Indicates if layout 'Gallery' is available",
|
||||
JoinCapabilities = eJoinCapabilities.ToSIMPL,
|
||||
JoinType = eJoinType.Digital
|
||||
JoinType = eJoinType.DigitalSerial
|
||||
});
|
||||
|
||||
[JoinName("LayoutSpeakerIsAvailable")]
|
||||
@@ -133,7 +131,7 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.ZoomRoom
|
||||
{
|
||||
Description = "FB Indicates if layout 'Speaker' is available",
|
||||
JoinCapabilities = eJoinCapabilities.ToSIMPL,
|
||||
JoinType = eJoinType.Digital
|
||||
JoinType = eJoinType.DigitalSerial
|
||||
});
|
||||
|
||||
[JoinName("LayoutStripIsAvailable")]
|
||||
@@ -147,7 +145,7 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.ZoomRoom
|
||||
{
|
||||
Description = "FB Indicates if layout 'Strip' is available",
|
||||
JoinCapabilities = eJoinCapabilities.ToSIMPL,
|
||||
JoinType = eJoinType.Digital
|
||||
JoinType = eJoinType.DigitalSerial
|
||||
});
|
||||
|
||||
[JoinName("LayoutShareAllIsAvailable")]
|
||||
@@ -161,50 +159,65 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.ZoomRoom
|
||||
{
|
||||
Description = "FB Indicates if layout 'ShareAll' is available",
|
||||
JoinCapabilities = eJoinCapabilities.ToSIMPL,
|
||||
JoinType = eJoinType.Digital
|
||||
});
|
||||
JoinType = eJoinType.DigitalSerial
|
||||
});
|
||||
|
||||
[JoinName("ParticipantAudioMuteToggleStart")]
|
||||
public JoinDataComplete ParticipantAudioMuteToggleStart = new JoinDataComplete(
|
||||
// TODO: #714 [ ] JoinMap >> SelfivewPipSizeToggle
|
||||
[JoinName("SelfviewPipSizeToggle")]
|
||||
public JoinDataComplete SelfviewPipSizeToggle = new JoinDataComplete(
|
||||
new JoinData
|
||||
{
|
||||
JoinNumber = 500,
|
||||
JoinSpan = 100
|
||||
JoinNumber = 231,
|
||||
JoinSpan = 1
|
||||
},
|
||||
new JoinMetadata
|
||||
{
|
||||
Description = "Toggles the participant's audio mute status",
|
||||
JoinCapabilities = eJoinCapabilities.ToSIMPL,
|
||||
Description = "Toggles the selfview pip size, (aka layout size)",
|
||||
JoinCapabilities = eJoinCapabilities.ToFromSIMPL,
|
||||
JoinType = eJoinType.Digital
|
||||
});
|
||||
});
|
||||
|
||||
[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
|
||||
});
|
||||
//[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("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
|
||||
});
|
||||
//[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
|
||||
// });
|
||||
|
||||
//[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
|
||||
// });
|
||||
|
||||
#endregion
|
||||
|
||||
@@ -256,7 +269,22 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.ZoomRoom
|
||||
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
|
||||
|
||||
|
||||
Reference in New Issue
Block a user