Merge pull request #938 from PepperDash/release/1.10.0

Release/1.10.0
This commit is contained in:
Andrew Welker
2022-04-28 10:07:06 -06:00
committed by GitHub
35 changed files with 7164 additions and 5114 deletions

View File

@@ -98,7 +98,7 @@ jobs:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
Push_Nuget_Package:
needs: Build_Project
runs-on: windows-latest
runs-on: windows-2019
steps:
- name: Download Build Version Info
uses: actions/download-artifact@v1

View File

@@ -82,7 +82,7 @@ jobs:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
Push_Nuget_Package:
needs: Build_Project
runs-on: windows-latest
runs-on: windows-2019
steps:
- name: Download Build Version Info
uses: actions/download-artifact@v1

View File

@@ -56,6 +56,9 @@ namespace PepperDash.Essentials.Room.Config
[JsonProperty("mirroredTuners")]
public Dictionary<uint, string> MirroredTuners { get; set; }
[JsonProperty("helpMessage")]
public string HelpMessage { get; set; }
/// <summary>
/// Indicates the room
/// </summary>

View File

@@ -89,7 +89,7 @@ namespace PepperDash.Essentials
}
}
public EssentialsConferenceRoomPropertiesConfig PropertiesConfig { get; private set; }
public EssentialsHuddleVtc1PropertiesConfig PropertiesConfig { get; private set; }
private List<IRoutingSinkWithSwitching> Displays;
@@ -199,7 +199,7 @@ namespace PepperDash.Essentials
{
try
{
PropertiesConfig = JsonConvert.DeserializeObject<EssentialsConferenceRoomPropertiesConfig>
PropertiesConfig = JsonConvert.DeserializeObject<EssentialsHuddleVtc1PropertiesConfig>
(config.Properties.ToString());
VideoCodec = DeviceManager.GetDeviceForKey(PropertiesConfig.VideoCodecKey) as
@@ -361,7 +361,7 @@ namespace PepperDash.Essentials
protected override void CustomSetConfig(DeviceConfig config)
{
var newPropertiesConfig = JsonConvert.DeserializeObject<EssentialsConferenceRoomPropertiesConfig>(config.Properties.ToString());
var newPropertiesConfig = JsonConvert.DeserializeObject<EssentialsHuddleVtc1PropertiesConfig>(config.Properties.ToString());
if (newPropertiesConfig != null)
PropertiesConfig = newPropertiesConfig;

View File

@@ -101,7 +101,7 @@ namespace PepperDash.Essentials
}
}
public EssentialsConferenceRoomPropertiesConfig PropertiesConfig { get; private set; }
public EssentialsHuddleVtc1PropertiesConfig PropertiesConfig { get; private set; }
public IRoutingSinkWithSwitching DefaultDisplay { get; private set; }
public IBasicVolumeControls DefaultAudioDevice { get; private set; }

View File

@@ -19,7 +19,7 @@ namespace PepperDash.Essentials
{
public class EssentialsTechRoom : EssentialsRoomBase, ITvPresetsProvider, IBridgeAdvanced, IRunDirectRouteAction
{
private readonly EssentialsTechRoomConfig _config;
public EssentialsTechRoomConfig PropertiesConfig { get; private set; }
private readonly Dictionary<string, TwoWayDisplayBase> _displays;
private readonly DevicePresetsModel _tunerPresets;
@@ -57,16 +57,16 @@ namespace PepperDash.Essentials
public EssentialsTechRoom(DeviceConfig config) : base(config)
{
_config = config.Properties.ToObject<EssentialsTechRoomConfig>();
PropertiesConfig = config.Properties.ToObject<EssentialsTechRoomConfig>();
_tunerPresets = new DevicePresetsModel(String.Format("{0}-presets", config.Key), _config.PresetsFileName);
_tunerPresets = new DevicePresetsModel(String.Format("{0}-presets", config.Key), PropertiesConfig.PresetsFileName);
_tunerPresets.SetFileName(_config.PresetsFileName);
_tunerPresets.SetFileName(PropertiesConfig.PresetsFileName);
_tunerPresets.PresetRecalled += TunerPresetsOnPresetRecalled;
_tuners = GetDevices<IRSetTopBoxBase>(_config.Tuners);
_displays = GetDevices<TwoWayDisplayBase>(_config.Displays);
_tuners = GetDevices<IRSetTopBoxBase>(PropertiesConfig.Tuners);
_displays = GetDevices<TwoWayDisplayBase>(PropertiesConfig.Displays);
RoomPowerIsOnFeedback = new BoolFeedback(() => RoomPowerIsOn);
@@ -153,7 +153,7 @@ namespace PepperDash.Essentials
private void CreateOrUpdateScheduledEvents()
{
var eventsConfig = _config.ScheduledEvents;
var eventsConfig = PropertiesConfig.ScheduledEvents;
GetOrCreateScheduleGroup();
@@ -207,21 +207,21 @@ namespace PepperDash.Essentials
{
//update config based on key of scheduleEvent
GetOrCreateScheduleGroup();
var existingEventIndex = _config.ScheduledEvents.FindIndex((e) => e.Key == scheduledEvent.Key);
var existingEventIndex = PropertiesConfig.ScheduledEvents.FindIndex((e) => e.Key == scheduledEvent.Key);
if (existingEventIndex < 0)
{
_config.ScheduledEvents.Add(scheduledEvent);
PropertiesConfig.ScheduledEvents.Add(scheduledEvent);
}
else
{
_config.ScheduledEvents[existingEventIndex] = scheduledEvent;
PropertiesConfig.ScheduledEvents[existingEventIndex] = scheduledEvent;
}
//create or update event based on config
CreateOrUpdateSingleEvent(scheduledEvent);
//save config
Config.Properties = JToken.FromObject(_config);
Config.Properties = JToken.FromObject(PropertiesConfig);
CustomSetConfig(Config);
//Fire Event
@@ -230,7 +230,7 @@ namespace PepperDash.Essentials
public List<ScheduledEventConfig> GetScheduledEvents()
{
return _config.ScheduledEvents ?? new List<ScheduledEventConfig>();
return PropertiesConfig.ScheduledEvents ?? new List<ScheduledEventConfig>();
}
private void OnScheduledEventUpdate()
@@ -242,14 +242,14 @@ namespace PepperDash.Essentials
return;
}
handler(this, new ScheduledEventEventArgs {ScheduledEvents = _config.ScheduledEvents});
handler(this, new ScheduledEventEventArgs {ScheduledEvents = PropertiesConfig.ScheduledEvents});
}
public event EventHandler<ScheduledEventEventArgs> ScheduledEventsChanged;
private void HandleScheduledEvent(ScheduledEvent schevent, ScheduledEventCommon.eCallbackReason type)
{
var eventConfig = _config.ScheduledEvents.FirstOrDefault(e => e.Key == schevent.Name);
var eventConfig = PropertiesConfig.ScheduledEvents.FirstOrDefault(e => e.Key == schevent.Name);
if (eventConfig == null)
{
@@ -286,11 +286,11 @@ Params: {2}"
{
Debug.Console(2, this, "Room Powering On");
var dummySource = DeviceManager.GetDeviceForKey(_config.DummySourceKey) as IRoutingOutputs;
var dummySource = DeviceManager.GetDeviceForKey(PropertiesConfig.DummySourceKey) as IRoutingOutputs;
if (dummySource == null)
{
Debug.Console(1, this, "Unable to get source with key: {0}", _config.DummySourceKey);
Debug.Console(1, this, "Unable to get source with key: {0}", PropertiesConfig.DummySourceKey);
return;
}
@@ -376,12 +376,12 @@ Params: {2}"
bridge.AddJoinMap(Key, joinMap);
}
if (_config.IsPrimary)
if (PropertiesConfig.IsPrimary)
{
Debug.Console(1, this, "Linking Primary system Tuner Preset Mirroring");
if (_config.MirroredTuners != null && _config.MirroredTuners.Count > 0)
if (PropertiesConfig.MirroredTuners != null && PropertiesConfig.MirroredTuners.Count > 0)
{
foreach (var tuner in _config.MirroredTuners)
foreach (var tuner in PropertiesConfig.MirroredTuners)
{
var f = CurrentPresetsFeedbacks[tuner.Value];
@@ -423,9 +423,9 @@ Params: {2}"
{
Debug.Console(1, this, "Linking Secondary system Tuner Preset Mirroring");
if (_config.MirroredTuners != null && _config.MirroredTuners.Count > 0)
if (PropertiesConfig.MirroredTuners != null && PropertiesConfig.MirroredTuners.Count > 0)
{
foreach (var tuner in _config.MirroredTuners)
foreach (var tuner in PropertiesConfig.MirroredTuners)
{
var t = _tuners[tuner.Value];

View File

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

View File

@@ -493,10 +493,10 @@ namespace PepperDash.Essentials
// and the LastMeetingDismissed != this meeting
var lastMeetingDismissed = meetings.FirstOrDefault(m => m.Id == LastMeetingDismissedId);
Debug.Console(0, "*#* Room on: {0}, lastMeetingDismissedId: {1} {2} *#*",
CurrentRoom.OnFeedback.BoolValue,
LastMeetingDismissedId,
lastMeetingDismissed != null ? lastMeetingDismissed.StartTime.ToString("t", Global.Culture) : "");
//Debug.Console(0, "*#* Room on: {0}, lastMeetingDismissedId: {1} {2} *#*",
// CurrentRoom.OnFeedback.BoolValue,
// LastMeetingDismissedId,
// lastMeetingDismissed != null ? lastMeetingDismissed.StartTime.ToString("t", Global.Culture) : "");
var meeting = meetings.LastOrDefault(m => m.Joinable);
if (CurrentRoom.OnFeedback.BoolValue

View File

@@ -52,7 +52,7 @@ namespace PepperDash.Essentials
{
var prevJoin = CurrentJoin;
var wasShown = _IsShown;
Debug.Console(2, "Trilist {0:X2}, interlock swapping {1} for {2}", TriList.ID, CurrentJoin, join);
//Debug.Console(2, "Trilist {0:X2}, interlock swapping {1} for {2}", TriList.ID, CurrentJoin, join);
if (CurrentJoin == join && TriList.BooleanInput[join].BoolValue)
return;
SetButDontShow(join);
@@ -71,7 +71,7 @@ namespace PepperDash.Essentials
var prevJoin = CurrentJoin;
var wasShown = IsShown;
Debug.Console(2, "Trilist {0:X2}, interlock swapping {1} for {2}", TriList.ID, CurrentJoin, join);
//Debug.Console(2, "Trilist {0:X2}, interlock swapping {1} for {2}", TriList.ID, CurrentJoin, join);
if (CurrentJoin == join)
HideAndClear();
else
@@ -92,7 +92,7 @@ namespace PepperDash.Essentials
{
var prevJoin = CurrentJoin;
var wasShown = IsShown;
Debug.Console(2, "Trilist {0:X2}, interlock hiding {1}", TriList.ID, CurrentJoin);
//Debug.Console(2, "Trilist {0:X2}, interlock hiding {1}", TriList.ID, CurrentJoin);
Hide();
CurrentJoin = 0;
@@ -108,7 +108,7 @@ namespace PepperDash.Essentials
var prevJoin = CurrentJoin;
var wasShown = IsShown;
Debug.Console(2, "Trilist {0:X2}, interlock hiding {1}", TriList.ID, CurrentJoin);
//Debug.Console(2, "Trilist {0:X2}, interlock hiding {1}", TriList.ID, CurrentJoin);
if (CurrentJoin > 0)
{
TriList.BooleanInput[CurrentJoin].BoolValue = false;
@@ -125,7 +125,7 @@ namespace PepperDash.Essentials
var prevJoin = CurrentJoin;
var wasShown = IsShown;
Debug.Console(2, "Trilist {0:X2}, interlock showing {1}", TriList.ID, CurrentJoin);
//Debug.Console(2, "Trilist {0:X2}, interlock showing {1}", TriList.ID, CurrentJoin);
if (CurrentJoin > 0)
{
TriList.BooleanInput[CurrentJoin].BoolValue = true;

View File

@@ -51,7 +51,7 @@ namespace PepperDash.Essentials
public override void Show()
{
Debug.Console(2, "Showing ScreenSaverController: {0:X2}", TriList.ID);
//Debug.Console(2, "Showing ScreenSaverController: {0:X2}", TriList.ID);
if (_parent.AvDriver != null)
{
@@ -67,11 +67,11 @@ namespace PepperDash.Essentials
public override void Hide()
{
Debug.Console(2, "Hiding ScreenSaverController: {0:X2}", TriList.ID);
//Debug.Console(2, "Hiding ScreenSaverController: {0:X2}", TriList.ID);
if (PositionTimer != null)
{
Debug.Console(2, "Stopping PositionTimer: {0:X2}", TriList.ID);
//Debug.Console(2, "Stopping PositionTimer: {0:X2}", TriList.ID);
PositionTimer.Stop();
PositionTimer.Dispose();
PositionTimer = null;
@@ -89,7 +89,7 @@ namespace PepperDash.Essentials
void StartPositionTimer()
{
Debug.Console(2, "Starting Position Timer: {0:X2}", TriList.ID);
//Debug.Console(2, "Starting Position Timer: {0:X2}", TriList.ID);
if (PositionTimer == null)
{
@@ -122,7 +122,7 @@ namespace PepperDash.Essentials
CurrentPositionIndex = 0;
}
Debug.Console(2, "ScreenSaver Position Timer Expired: Setting new position: {0} ID: {1:X2}", CurrentPositionIndex, TriList.ID);
//Debug.Console(2, "ScreenSaver Position Timer Expired: Setting new position: {0} ID: {1:X2}", CurrentPositionIndex, TriList.ID);
}
//
@@ -134,7 +134,7 @@ namespace PepperDash.Essentials
void ClearAllPositions()
{
Debug.Console(2, "Hiding all screensaver positions: {0:X2}", TriList.ID);
//Debug.Console(2, "Hiding all screensaver positions: {0:X2}", TriList.ID);
PositionInterlock.HideAndClear();
}

View File

@@ -16,11 +16,28 @@ namespace PepperDash.Essentials.Core
/// <summary>
/// Used for monitoring comms that are IBasicCommunication. Will send a poll string and provide an event when
/// statuses change.
/// Default monitoring uses TextReceived event on Client.
/// </summary>
public class GenericCommunicationMonitor : StatusMonitorBase
{
public IBasicCommunication Client { get; private set; }
/// <summary>
/// Will monitor Client.BytesReceived if set to true. Otherwise the default is to monitor Client.TextReceived
/// </summary>
public bool MonitorBytesReceived { get; private set; }
/// <summary>
/// Return true if the Client is ISocketStatus
/// </summary>
public bool IsSocket
{
get
{
return Client is ISocketStatus;
}
}
long PollTime;
CTimer PollTimer;
string PollString;
@@ -46,8 +63,20 @@ namespace PepperDash.Essentials.Core
Client = client;
PollTime = pollTime;
PollString = pollString;
if (IsSocket)
{
(Client as ISocketStatus).ConnectionChange += new EventHandler<GenericSocketStatusChageEventArgs>(socket_ConnectionChange);
}
}
public GenericCommunicationMonitor(IKeyed parent, IBasicCommunication client, long pollTime,
long warningTime, long errorTime, string pollString, bool monitorBytesReceived) :
this(parent, client, pollTime, warningTime, errorTime, pollString)
{
SetMonitorBytesReceived(monitorBytesReceived);
}
/// <summary>
/// Poll is a provided action instead of string
/// </summary>
@@ -69,6 +98,19 @@ namespace PepperDash.Essentials.Core
Client = client;
PollTime = pollTime;
PollAction = pollAction;
if (IsSocket)
{
(Client as ISocketStatus).ConnectionChange += new EventHandler<GenericSocketStatusChageEventArgs>(socket_ConnectionChange);
}
}
public GenericCommunicationMonitor(IKeyed parent, IBasicCommunication client, long pollTime,
long warningTime, long errorTime, Action pollAction, bool monitorBytesReceived) :
this(parent, client, pollTime, warningTime, errorTime, pollAction)
{
SetMonitorBytesReceived(monitorBytesReceived);
}
@@ -79,23 +121,96 @@ namespace PepperDash.Essentials.Core
CommunicationMonitorConfig props) :
this(parent, client, props.PollInterval, props.TimeToWarning, props.TimeToError, props.PollString)
{
if (IsSocket)
{
(Client as ISocketStatus).ConnectionChange += new EventHandler<GenericSocketStatusChageEventArgs>(socket_ConnectionChange);
}
}
/// <summary>
/// Builds the monitor from a config object and takes a bool to specify whether to monitor BytesReceived
/// Default is to monitor TextReceived
/// </summary>
/// <param name="parent"></param>
/// <param name="client"></param>
/// <param name="props"></param>
/// <param name="monitorBytesReceived"></param>
public GenericCommunicationMonitor(IKeyed parent, IBasicCommunication client, CommunicationMonitorConfig props, bool monitorBytesReceived) :
this(parent, client, props.PollInterval, props.TimeToWarning, props.TimeToError, props.PollString)
{
SetMonitorBytesReceived(monitorBytesReceived);
}
void SetMonitorBytesReceived(bool monitorBytesReceived)
{
MonitorBytesReceived = monitorBytesReceived;
}
public override void Start()
{
Client.BytesReceived += Client_BytesReceived;
Poll();
PollTimer = new CTimer(o => Poll(), null, PollTime, PollTime);
if (MonitorBytesReceived)
{
Client.BytesReceived += Client_BytesReceived;
}
else
{
Client.TextReceived += Client_TextReceived;
}
if (!IsSocket)
{
BeginPolling();
}
}
void socket_ConnectionChange(object sender, GenericSocketStatusChageEventArgs e)
{
if (!e.Client.IsConnected)
{
// Immediately stop polling and notify that device is offline
Stop();
Status = MonitorStatus.InError;
ResetErrorTimers();
}
else
{
// Start polling and set status to unknow and let poll result update the status to IsOk when a response is received
Status = MonitorStatus.StatusUnknown;
Start();
BeginPolling();
}
}
void BeginPolling()
{
Poll();
PollTimer = new CTimer(o => Poll(), null, PollTime, PollTime);
}
public override void Stop()
{
Client.BytesReceived -= this.Client_BytesReceived;
PollTimer.Stop();
PollTimer = null;
StopErrorTimers();
if(MonitorBytesReceived)
{
Client.BytesReceived -= this.Client_BytesReceived;
}
else
{
Client.TextReceived -= Client_TextReceived;
}
if (PollTimer != null)
{
PollTimer.Stop();
PollTimer = null;
StopErrorTimers();
}
}
void Client_TextReceived(object sender, GenericCommMethodReceiveTextArgs e)
{
DataReceived();
}
/// <summary>
/// Upon any receipt of data, set everything to ok!
/// </summary>
@@ -103,10 +218,14 @@ namespace PepperDash.Essentials.Core
/// <param name="e"></param>
void Client_BytesReceived(object sender, GenericCommMethodReceiveBytesArgs e)
{
Status = MonitorStatus.IsOk;
ResetErrorTimers();
//
}
DataReceived();
}
void DataReceived()
{
Status = MonitorStatus.IsOk;
ResetErrorTimers();
}
void Poll()
{
@@ -124,19 +243,6 @@ namespace PepperDash.Essentials.Core
Debug.Console(2, this, "Comm not connected");
}
}
/// <summary>
/// When the client connects, and we're waiting for it, respond and disconect from event
/// </summary>
void OneTimeConnectHandler(object o, EventArgs a)
{
if (Client.IsConnected)
{
//Client.IsConnected -= OneTimeConnectHandler;
Debug.Console(2, this, "Comm connected");
Poll();
}
}
}

View File

@@ -118,7 +118,7 @@ namespace PepperDash.Essentials.Core.Queues
/// <param name="capacity"></param>
public GenericQueue(string key, int pacing, Thread.eThreadPriority priority, int capacity)
: this(key, priority, capacity, pacing)
{
{
}
/// <summary>
@@ -139,7 +139,8 @@ namespace PepperDash.Essentials.Core.Queues
_queue = new CrestronQueue<IQueueMessage>(cap);
_worker = new Thread(ProcessQueue, null, Thread.eThreadStartOptions.Running)
{
Priority = priority
Priority = priority,
Name = _key
};
SetDelayValues(pacing);

View File

@@ -29,6 +29,7 @@ namespace PepperDash.Essentials.Devices.Common.Cameras
public abstract class CameraBase : ReconfigurableDevice, IRoutingOutputs
{
[JsonProperty("controlMode", NullValueHandling = NullValueHandling.Ignore)]
public eCameraControlMode ControlMode { get; protected set; }
#region IRoutingOutputs Members
@@ -37,6 +38,7 @@ namespace PepperDash.Essentials.Devices.Common.Cameras
#endregion
[JsonProperty("canPan", NullValueHandling = NullValueHandling.Ignore)]
public bool CanPan
{
get
@@ -44,7 +46,7 @@ namespace PepperDash.Essentials.Devices.Common.Cameras
return (Capabilities & eCameraCapabilities.Pan) == eCameraCapabilities.Pan;
}
}
[JsonProperty("canTilt", NullValueHandling = NullValueHandling.Ignore)]
public bool CanTilt
{
get
@@ -52,7 +54,7 @@ namespace PepperDash.Essentials.Devices.Common.Cameras
return (Capabilities & eCameraCapabilities.Tilt) == eCameraCapabilities.Tilt;
}
}
[JsonProperty("canZoom", NullValueHandling = NullValueHandling.Ignore)]
public bool CanZoom
{
get
@@ -60,7 +62,7 @@ namespace PepperDash.Essentials.Devices.Common.Cameras
return (Capabilities & eCameraCapabilities.Zoom) == eCameraCapabilities.Zoom;
}
}
[JsonProperty("canFocus", NullValueHandling = NullValueHandling.Ignore)]
public bool CanFocus
{
get

View File

@@ -57,6 +57,11 @@ namespace PepperDash.Essentials.Devices.Common.Cameras
void CameraMuteToggle();
}
public interface IHasCameraMuteWithUnmuteReqeust : IHasCameraMute
{
event EventHandler VideoUnmuteRequested;
}
public class CameraSelectedEventArgs : EventArgs
{
public CameraBase SelectedCamera { get; private set; }

View File

@@ -12,34 +12,40 @@ namespace PepperDash.Essentials.Devices.Common.Codec
{
public class CodecActiveCallItem
{
[JsonProperty("name")]
[JsonProperty("name", NullValueHandling = NullValueHandling.Ignore)]
public string Name { get; set; }
[JsonProperty("number")]
[JsonProperty("number", NullValueHandling = NullValueHandling.Ignore)]
public string Number { get; set; }
[JsonProperty("type")]
[JsonProperty("type", NullValueHandling = NullValueHandling.Ignore)]
[JsonConverter(typeof(StringEnumConverter))]
public eCodecCallType Type { get; set; }
[JsonProperty("status")]
[JsonProperty("status", NullValueHandling = NullValueHandling.Ignore)]
[JsonConverter(typeof(StringEnumConverter))]
public eCodecCallStatus Status { get; set; }
[JsonProperty("direction")]
[JsonProperty("direction", NullValueHandling = NullValueHandling.Ignore)]
[JsonConverter(typeof(StringEnumConverter))]
public eCodecCallDirection Direction { get; set; }
[JsonProperty("id")]
[JsonProperty("id", NullValueHandling = NullValueHandling.Ignore)]
public string Id { get; set; }
[JsonProperty("isOnHold", NullValueHandling = NullValueHandling.Ignore)]
public bool IsOnHold { get; set; }
[JsonProperty("duration", NullValueHandling = NullValueHandling.Ignore)]
public TimeSpan Duration { get; set; }
//public object CallMetaData { get; set; }
/// <summary>
/// Returns true when this call is any status other than
/// Unknown, Disconnected, Disconnecting
/// </summary>
[JsonProperty("isActiveCall")]
[JsonProperty("isActiveCall", NullValueHandling = NullValueHandling.Ignore)]
public bool IsActiveCall
{
get

View File

@@ -0,0 +1,23 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Crestron.SimplSharp;
namespace PepperDash.Essentials.Devices.Common.Codec
{
public interface IHasCallHold
{
/// <summary>
/// Put the specified call on hold
/// </summary>
/// <param name="activeCall"></param>
void HoldCall(CodecActiveCallItem activeCall);
/// <summary>
/// Resume the specified call
/// </summary>
/// <param name="activeCall"></param>
void ResumeCall(CodecActiveCallItem activeCall);
}
}

View File

@@ -23,9 +23,9 @@ namespace PepperDash.Essentials.Devices.Common.Codec
public enum eCodecOccurrenceType
{
Unknown = 0,
Placed,
Received,
NoAnswer
Placed = 1,
Received = 2,
NoAnswer = 3,
}
/// <summary>

View File

@@ -65,8 +65,9 @@ namespace PepperDash.Essentials.Devices.Common.Codec
{
/// <summary>
/// Represents the contents of the directory
/// We don't want to serialize this for messages to MobileControl. MC can combine Contacts and Folders to get the same data
/// </summary>
[JsonProperty("directoryResults")]
[JsonIgnore]
public List<DirectoryItem> CurrentDirectoryResults { get; private set; }
[JsonProperty("contacts")]

View File

@@ -99,7 +99,7 @@ namespace PepperDash.Essentials.Devices.Displays
WarmupTime = 10000;
CooldownTime = 8000;
CommunicationMonitor = new GenericCommunicationMonitor(this, Communication, 2000, 120000, 300000, StatusGet);
CommunicationMonitor = new GenericCommunicationMonitor(this, Communication, 2000, 120000, 300000, StatusGet, true);
DeviceManager.AddDevice(CommunicationMonitor);
VolumeIncrementer = new ActionIncrementer(655, 0, 65535, 800, 80,

View File

@@ -108,6 +108,7 @@
<Compile Include="Codec\eCodecCallStatus.cs" />
<Compile Include="Codec\eMeetingPrivacy.cs" />
<Compile Include="Codec\iCodecAudio.cs" />
<Compile Include="Codec\IHasCallHold.cs" />
<Compile Include="Codec\IHasDoNotDisturb.cs" />
<Compile Include="Codec\IHasExternalSourceSwitching.cs" />
<Compile Include="ImageProcessors\TVOneCorio.cs" />
@@ -131,6 +132,7 @@
<Compile Include="VideoCodec\Interfaces\IHasSelfviewSize.cs" />
<Compile Include="VideoCodec\Interfaces\IHasStandbyMode.cs" />
<Compile Include="VideoCodec\Interfaces\IHasStartMeeting.cs" />
<Compile Include="VideoCodec\Interfaces\IJoinCalls.cs" />
<Compile Include="VideoCodec\Interfaces\iVideoCodecInfo.cs" />
<Compile Include="Codec\iHasCallFavorites.cs" />
<Compile Include="Codec\iHasCallHistory.cs" />

View File

@@ -41,12 +41,12 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.Cisco
public void PanLeft()
{
ParentCodec.SendText(string.Format("xCommand Call FarEndControl Camera Move Value: Left CallId: {0}", CallId));
ParentCodec.EnqueueCommand(string.Format("xCommand Call FarEndControl Camera Move Value: Left CallId: {0}", CallId));
}
public void PanRight()
{
ParentCodec.SendText(string.Format("xCommand Call FarEndControl Camera Move Value: Right CallId: {0}", CallId));
ParentCodec.EnqueueCommand(string.Format("xCommand Call FarEndControl Camera Move Value: Right CallId: {0}", CallId));
}
public void PanStop()
@@ -60,12 +60,12 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.Cisco
public void TiltDown()
{
ParentCodec.SendText(string.Format("xCommand Call FarEndControl Camera Move Value: Down CallId: {0}", CallId));
ParentCodec.EnqueueCommand(string.Format("xCommand Call FarEndControl Camera Move Value: Down CallId: {0}", CallId));
}
public void TiltUp()
{
ParentCodec.SendText(string.Format("xCommand Call FarEndControl Camera Move Value: Up CallId: {0}", CallId));
ParentCodec.EnqueueCommand(string.Format("xCommand Call FarEndControl Camera Move Value: Up CallId: {0}", CallId));
}
public void TiltStop()
@@ -79,12 +79,12 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.Cisco
public void ZoomIn()
{
ParentCodec.SendText(string.Format("xCommand Call FarEndControl Camera Move Value: ZoomIn CallId: {0}", CallId));
ParentCodec.EnqueueCommand(string.Format("xCommand Call FarEndControl Camera Move Value: ZoomIn CallId: {0}", CallId));
}
public void ZoomOut()
{
ParentCodec.SendText(string.Format("xCommand Call FarEndControl Camera Move Value: ZoomOut CallId: {0}", CallId));
ParentCodec.EnqueueCommand(string.Format("xCommand Call FarEndControl Camera Move Value: ZoomOut CallId: {0}", CallId));
}
public void ZoomStop()
@@ -97,7 +97,7 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.Cisco
void Stop()
{
ParentCodec.SendText(string.Format("xCommand Call FarEndControl Camera Stop CallId: {0}", CallId));
ParentCodec.EnqueueCommand(string.Format("xCommand Call FarEndControl Camera Stop CallId: {0}", CallId));
}
public void LinkToApi(BasicTriList trilist, uint joinStart, string joinMapKey, EiscApiAdvanced bridge)
@@ -116,7 +116,7 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.Cisco
/// <summary>
/// The ID of the camera on the codec
/// </summary>
protected uint CameraId { get; private set; }
public uint CameraId { get; private set; }
/// <summary>
/// Valid range 1-15
@@ -202,7 +202,7 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.Cisco
{
if (!isMoving)
{
ParentCodec.SendText(string.Format("xCommand Camera Ramp CameraId: {0} Pan: Left PanSpeed: {1}", CameraId, PanSpeed));
ParentCodec.EnqueueCommand(string.Format("xCommand Camera Ramp CameraId: {0} Pan: Left PanSpeed: {1}", CameraId, PanSpeed));
isPanning = true;
}
}
@@ -211,14 +211,14 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.Cisco
{
if (!isMoving)
{
ParentCodec.SendText(string.Format("xCommand Camera Ramp CameraId: {0} Pan: Right PanSpeed: {1}", CameraId, PanSpeed));
ParentCodec.EnqueueCommand(string.Format("xCommand Camera Ramp CameraId: {0} Pan: Right PanSpeed: {1}", CameraId, PanSpeed));
isPanning = true;
}
}
public void PanStop()
{
ParentCodec.SendText(string.Format("xCommand Camera Ramp CameraId: {0} Pan: Stop", CameraId));
ParentCodec.EnqueueCommand(string.Format("xCommand Camera Ramp CameraId: {0} Pan: Stop", CameraId));
isPanning = false;
}
@@ -232,7 +232,7 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.Cisco
{
if (!isMoving)
{
ParentCodec.SendText(string.Format("xCommand Camera Ramp CameraId: {0} Tilt: Down TiltSpeed: {1}", CameraId, TiltSpeed));
ParentCodec.EnqueueCommand(string.Format("xCommand Camera Ramp CameraId: {0} Tilt: Down TiltSpeed: {1}", CameraId, TiltSpeed));
isTilting = true;
}
}
@@ -241,14 +241,14 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.Cisco
{
if (!isMoving)
{
ParentCodec.SendText(string.Format("xCommand Camera Ramp CameraId: {0} Tilt: Up TiltSpeed: {1}", CameraId, TiltSpeed));
ParentCodec.EnqueueCommand(string.Format("xCommand Camera Ramp CameraId: {0} Tilt: Up TiltSpeed: {1}", CameraId, TiltSpeed));
isTilting = true;
}
}
public void TiltStop()
{
ParentCodec.SendText(string.Format("xCommand Camera Ramp CameraId: {0} Tilt: Stop", CameraId));
ParentCodec.EnqueueCommand(string.Format("xCommand Camera Ramp CameraId: {0} Tilt: Stop", CameraId));
isTilting = false;
}
@@ -260,7 +260,7 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.Cisco
{
if (!isMoving)
{
ParentCodec.SendText(string.Format("xCommand Camera Ramp CameraId: {0} Zoom: In ZoomSpeed: {1}", CameraId, ZoomSpeed));
ParentCodec.EnqueueCommand(string.Format("xCommand Camera Ramp CameraId: {0} Zoom: In ZoomSpeed: {1}", CameraId, ZoomSpeed));
isZooming = true;
}
}
@@ -269,14 +269,14 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.Cisco
{
if (!isMoving)
{
ParentCodec.SendText(string.Format("xCommand Camera Ramp CameraId: {0} Zoom: Out ZoomSpeed: {1}", CameraId, ZoomSpeed));
ParentCodec.EnqueueCommand(string.Format("xCommand Camera Ramp CameraId: {0} Zoom: Out ZoomSpeed: {1}", CameraId, ZoomSpeed));
isZooming = true;
}
}
public void ZoomStop()
{
ParentCodec.SendText(string.Format("xCommand Camera Ramp CameraId: {0} Zoom: Stop", CameraId));
ParentCodec.EnqueueCommand(string.Format("xCommand Camera Ramp CameraId: {0} Zoom: Stop", CameraId));
isZooming = false;
}
@@ -288,7 +288,7 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.Cisco
{
if (!isMoving)
{
ParentCodec.SendText(string.Format("xCommand Camera Ramp CameraId: {0} Focus: Near", CameraId));
ParentCodec.EnqueueCommand(string.Format("xCommand Camera Ramp CameraId: {0} Focus: Near", CameraId));
isFocusing = true;
}
}
@@ -297,20 +297,20 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.Cisco
{
if (!isMoving)
{
ParentCodec.SendText(string.Format("xCommand Camera Ramp CameraId: {0} Focus: Far", CameraId));
ParentCodec.EnqueueCommand(string.Format("xCommand Camera Ramp CameraId: {0} Focus: Far", CameraId));
isFocusing = true;
}
}
public void FocusStop()
{
ParentCodec.SendText(string.Format("xCommand Camera Ramp CameraId: {0} Focus: Stop", CameraId));
ParentCodec.EnqueueCommand(string.Format("xCommand Camera Ramp CameraId: {0} Focus: Stop", CameraId));
isFocusing = false;
}
public void TriggerAutoFocus()
{
ParentCodec.SendText(string.Format("xCommand Camera TriggerAutofocus CameraId: {0}", CameraId));
ParentCodec.EnqueueCommand(string.Format("xCommand Camera TriggerAutofocus CameraId: {0}", CameraId));
}
#endregion

View File

@@ -9,11 +9,39 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.Cisco
{
#region Digital
[JoinName("PresentationLocalOnly")]
public JoinDataComplete PresentationLocalOnly = new JoinDataComplete(
new JoinData
{
JoinNumber = 205,
JoinSpan = 1
},
new JoinMetadata
{
Description = "Presentation Local Only Feedback",
JoinCapabilities = eJoinCapabilities.ToSIMPL,
JoinType = eJoinType.Digital
});
[JoinName("PresentationLocalRemote")]
public JoinDataComplete PresentationLocalRemote = new JoinDataComplete(
new JoinData
{
JoinNumber = 206,
JoinSpan = 1
},
new JoinMetadata
{
Description = "Presentation Local and Remote Feedback",
JoinCapabilities = eJoinCapabilities.ToSIMPL,
JoinType = eJoinType.Digital
});
[JoinName("ActivateDoNotDisturbMode")]
public JoinDataComplete ActivateDoNotDisturbMode = new JoinDataComplete(
new JoinData
{
JoinNumber = 221,
JoinNumber = 241,
JoinSpan = 1
},
new JoinMetadata
@@ -27,7 +55,7 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.Cisco
public JoinDataComplete DeactivateDoNotDisturbMode = new JoinDataComplete(
new JoinData
{
JoinNumber = 222,
JoinNumber = 242,
JoinSpan = 1
},
new JoinMetadata
@@ -41,7 +69,7 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.Cisco
public JoinDataComplete ToggleDoNotDisturbMode = new JoinDataComplete(
new JoinData
{
JoinNumber = 223,
JoinNumber = 243,
JoinSpan = 1
},
new JoinMetadata
@@ -55,7 +83,7 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.Cisco
public JoinDataComplete ActivateStandby = new JoinDataComplete(
new JoinData
{
JoinNumber = 226,
JoinNumber = 246,
JoinSpan = 1
},
new JoinMetadata
@@ -69,7 +97,7 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.Cisco
public JoinDataComplete DeactivateStandby = new JoinDataComplete(
new JoinData
{
JoinNumber = 227,
JoinNumber = 247,
JoinSpan = 1
},
new JoinMetadata
@@ -83,7 +111,7 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.Cisco
public JoinDataComplete ActivateHalfWakeMode = new JoinDataComplete(
new JoinData
{
JoinNumber = 228,
JoinNumber = 248,
JoinSpan = 1
},
new JoinMetadata
@@ -97,7 +125,7 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.Cisco
public JoinDataComplete EnteringStandbyMode = new JoinDataComplete(
new JoinData
{
JoinNumber = 229,
JoinNumber = 249,
JoinSpan = 1
},
new JoinMetadata
@@ -112,12 +140,55 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.Cisco
#region Analog
[JoinName("RingtoneVolume")]
public JoinDataComplete RingtoneVolume = new JoinDataComplete(
new JoinData
{
JoinNumber = 21,
JoinSpan = 1
},
new JoinMetadata
{
Description = "Ringtone volume set/FB. Valid values are 0 - 100 in increments of 5 (5, 10, 15, 20, etc.)",
JoinCapabilities = eJoinCapabilities.ToFromSIMPL,
JoinType = eJoinType.Analog
});
[JoinName("PresentationSource")]
public JoinDataComplete PresentationSource = new JoinDataComplete(
new JoinData
{
JoinNumber = 201,
JoinSpan = 1
},
new JoinMetadata
{
Description = "Presentation set/FB. Valid values are 0 - 6 depending on the codec model.",
JoinCapabilities = eJoinCapabilities.ToFromSIMPL,
JoinType = eJoinType.Analog
});
#endregion
#region Serials
[JoinName("CommandToDevice")]
public JoinDataComplete CommandToDevice = new JoinDataComplete(
new JoinData
{
JoinNumber = 5,
JoinSpan = 1
},
new JoinMetadata
{
Description = "Sends a serial command to the device. Do not include the delimiter, it will be added automatically.",
JoinCapabilities = eJoinCapabilities.FromSIMPL,
JoinType = eJoinType.Serial
});
#endregion

View File

@@ -50,8 +50,16 @@ namespace PepperDash.Essentials.Devices.Common.Codec
public uint PhonebookResultsLimit { get; set; }
[JsonProperty("UiBranding")]
public BrandingLogoProperties UiBranding { get; set; }
public BrandingLogoProperties UiBranding { get; set; }
[JsonProperty("cameraInfo")]
public List<CameraInfo> CameraInfo { get; set; }
public CiscoSparkCodecPropertiesConfig()
{
CameraInfo = new List<CameraInfo>();
}
}
public class SharingProperties
@@ -68,4 +76,14 @@ namespace PepperDash.Essentials.Devices.Common.Codec
[JsonProperty("brandingUrl")]
public string BrandingUrl { get; set; }
}
/// <summary>
/// Describes configuration information for the near end cameras
/// </summary>
public class CameraInfo
{
public int CameraNumber { get; set; }
public string Name { get; set; }
public int SourceId { get; set; }
}
}

View File

@@ -26,6 +26,8 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec
void CodecRoomPresetSelect(int preset);
void CodecRoomPresetStore(int preset, string description);
void SelectFarEndPreset(int preset);
}
public static class RoomPresets

View File

@@ -112,16 +112,46 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.Cisco
public string Value { get; set; }
}
public class RingVolume
public class RingVolume : ValueProperty
{
public string valueSpaceRef { get; set; }
public string Value { get; set; }
string _Value;
/// <summary>
/// Sets Value and triggers the action when set
/// </summary>
public string Value
{
get
{
return _Value;
}
set
{
_Value = value;
OnValueChanged();
}
}
public int Volume
{
get
{
return Int32.Parse(_Value);
}
}
}
public class SoundsAndAlerts
{
public RingTone RingTone { get; set; }
public RingVolume RingVolume { get; set; }
public SoundsAndAlerts()
{
RingVolume = new RingVolume();
}
}
public class Audio
@@ -131,6 +161,12 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.Cisco
public Microphones Microphones { get; set; }
public Output Output { get; set; }
public SoundsAndAlerts SoundsAndAlerts { get; set; }
public Audio()
{
SoundsAndAlerts = new SoundsAndAlerts();
}
}
public class DefaultMode
@@ -340,6 +376,13 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.Cisco
public Delay Delay { get; set; }
public Mode9 Mode { get; set; }
public Mute2 Mute { get; set; }
public AutoAnswer()
{
Mode = new Mode9();
Delay = new Delay();
Mute = new Mute2();
}
}
public class Protocol
@@ -440,6 +483,11 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.Cisco
public MaxTotalTransmitCallRate MaxTotalTransmitCallRate { get; set; }
public MaxTransmitCallRate MaxTransmitCallRate { get; set; }
public MultiStream MultiStream { get; set; }
public Conference()
{
AutoAnswer = new AutoAnswer();
}
}
public class LoginName
@@ -690,6 +738,11 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.Cisco
public Assignment Assignment { get; set; }
public Gateway Gateway { get; set; }
public SubnetMask SubnetMask { get; set; }
public IPv4()
{
Address = new Address4();
}
}
public class Address5
@@ -841,6 +894,11 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.Cisco
public RemoteAccess RemoteAccess { get; set; }
public Speed Speed { get; set; }
public VLAN VLAN { get; set; }
public Network()
{
IPv4 = new IPv4();
}
}
public class Mode19
@@ -1797,11 +1855,23 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.Cisco
public UserInterface UserInterface { get; set; }
public UserManagement UserManagement { get; set; }
public Video2 Video { get; set; }
public Configuration()
{
Audio = new Audio();
Conference = new Conference();
Network = new List<Network>();
}
}
public class RootObject
{
public Configuration Configuration { get; set; }
public RootObject()
{
Configuration = new Configuration();
}
}
}
}

View File

@@ -12,28 +12,28 @@ using PepperDash.Essentials.Devices.Common.VideoCodec.CiscoCodec;
namespace PepperDash.Essentials.Devices.Common.VideoCodec.Cisco
{
// Helper Classes for Proerties
public abstract class ValueProperty
{
/// <summary>
/// Triggered when Value is set
/// </summary>
public Action ValueChangedAction { get; set; }
protected void OnValueChanged()
{
var a = ValueChangedAction;
if (a != null)
a();
}
}
/// <summary>
/// This class exists to capture serialized data sent back by a Cisco codec in JSON output mode
/// </summary>
public class CiscoCodecStatus
{
// Helper Classes for Proerties
public abstract class ValueProperty
{
/// <summary>
/// Triggered when Value is set
/// </summary>
public Action ValueChangedAction { get; set; }
protected void OnValueChanged()
{
var a = ValueChangedAction;
if (a != null)
a();
}
}
public class ConnectionStatus
{
@@ -262,11 +262,30 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.Cisco
public string Value { get; set; }
}
public class DectectedConnector
{
public string Value { get; set; }
public int ConnectorId
{
get
{
if(!string.IsNullOrEmpty(Value))
{
return Convert.ToUInt16(Value);
}
else
return -1;
}
}
}
public class Camera
{
public string id { get; set; }
public Capabilities Capabilities { get; set; }
public Connected Connected { get; set; }
public DectectedConnector DetectedConnector { get; set; }
public Flip Flip { get; set; }
public HardwareID HardwareID { get; set; }
public MacAddress MacAddress { get; set; }
@@ -275,6 +294,13 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.Cisco
public Position Position { get; set; }
public SerialNumber SerialNumber { get; set; }
public SoftwareID SoftwareID { get; set; }
public Camera()
{
Manufacturer = new Manufacturer();
Model = new Model();
DetectedConnector = new DectectedConnector();
}
}
public class Availability : ValueProperty
@@ -298,11 +324,34 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.Cisco
}
}
public class CallStatus : ValueProperty
{
string _Value;
public bool BoolValue { get; private set; }
public string Value
{
get
{
return _Value;
}
set
{
// If the incoming value is "Active" it sets the BoolValue true, otherwise sets it false
_Value = value;
BoolValue = value == "Connected";
OnValueChanged();
}
}
}
public class Status2 : ValueProperty
{
string _Value;
public bool BoolValue { get; private set; }
public string Value
{
get
@@ -558,9 +607,47 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.Cisco
}
}
public class SendingMode
public class SendingMode : ValueProperty
{
public string Value { get; set; }
string _Value;
/// <summary>
/// Sets Value and triggers the action when set
/// </summary>
public string Value
{
get
{
return _Value;
}
set
{
_Value = value;
OnValueChanged();
}
}
public bool LocalOnly
{
get
{
if(string.IsNullOrEmpty(_Value))
return false;
return _Value.ToLower() == "localonly";
}
}
public bool LocalRemote
{
get
{
if(string.IsNullOrEmpty(_Value))
return false;
return _Value.ToLower() == "localremote";
}
}
}
public class LocalInstance
@@ -573,6 +660,7 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.Cisco
public LocalInstance()
{
Source = new Source2();
SendingMode = new SendingMode();
}
}
@@ -881,6 +969,11 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.Cisco
public Address4 Address { get; set; }
public Gateway Gateway { get; set; }
public SubnetMask SubnetMask { get; set; }
public IPv4()
{
Address = new Address4();
}
}
public class Address5
@@ -923,6 +1016,11 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.Cisco
public IPv4 IPv4 { get; set; }
public IPv6 IPv6 { get; set; }
public VLAN VLAN { get; set; }
public Network()
{
IPv4 = new IPv4();
}
}
public class CurrentAddress
@@ -1949,9 +2047,30 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.Cisco
public string Value { get; set; }
}
public class Duration
public class Duration : ValueProperty
{
public string Value { get; set; }
private string _Value;
public string Value
{
get
{
return _Value;
}
set
{
_Value = value;
OnValueChanged();
}
}
public TimeSpan DurationValue
{
get
{
return new TimeSpan(0, 0, Int32.Parse(_Value));
}
}
}
public class FacilityServiceId
@@ -1964,9 +2083,19 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.Cisco
public string Value { get; set; }
}
public class PlacedOnHold
public class PlacedOnHold : ValueProperty
{
public string Value { get; set; }
public bool BoolValue { get; private set; }
public string Value
{
set
{
// If the incoming value is "True" it sets the BoolValue true, otherwise sets it false
BoolValue = value == "True";
OnValueChanged();
}
}
}
public class Protocol
@@ -2007,13 +2136,14 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.Cisco
public Protocol Protocol { get; set; }
public ReceiveCallRate ReceiveCallRate { get; set; }
public RemoteNumber RemoteNumber { get; set; }
public Status2 Status { get; set; }
public CallStatus Status { get; set; }
public TransmitCallRate TransmitCallRate { get; set; }
public Call()
{
CallType = new CallType();
Status = new Status2();
Status = new CallStatus();
Duration = new Duration();
}
}
@@ -2114,6 +2244,7 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.Cisco
SystemUnit = new SystemUnit();
Video = new Video();
Conference = new Conference2();
Network = new List<Network>();
}
}

View File

@@ -0,0 +1,16 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Crestron.SimplSharp;
using PepperDash.Essentials.Devices.Common.Codec;
namespace PepperDash.Essentials.Devices.Common.VideoCodec
{
public interface IJoinCalls
{
void JoinCall(CodecActiveCallItem activeCall);
void JoinAllCalls();
}
}

View File

@@ -764,6 +764,11 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec
SetConfig(Config);
}
public void SelectFarEndPreset(int i)
{
Debug.Console(1, this, "Selecting Far End Preset: {0}", i);
}
#endregion
protected override void CustomSetConfig(DeviceConfig config)

View File

@@ -152,6 +152,7 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec
public abstract void AcceptCall(CodecActiveCallItem call);
public abstract void RejectCall(CodecActiveCallItem call);
public abstract void SendDtmf(string s);
public virtual void SendDtmf(string s, CodecActiveCallItem call) { }
#endregion
@@ -259,10 +260,12 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec
/// </summary>
public virtual void ListCalls()
{
Debug.Console(1, this, "Active Calls:");
var sb = new StringBuilder();
foreach (var c in ActiveCalls)
{
sb.AppendFormat("{0} {1} -- {2} {3}\n", c.Id, c.Number, c.Name, c.Status);
sb.AppendFormat("id: {0} number: {1} -- name: {2} status: {3} onHold: {4}\r\n", c.Id, c.Number, c.Name, c.Status, c.IsOnHold);
}
Debug.Console(1, this, "\n{0}\n", sb.ToString());
}
@@ -328,15 +331,22 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec
LinkVideoCodecVolumeToApi(trilist, joinMap);
LinkVideoCodecInfoToApi(trilist, joinMap);
// Register for this event to link any functions that require the codec to be ready first
codec.IsReadyChange += (o, a) =>
{
if (codec is IHasCodecCameras)
{
LinkVideoCodecCameraToApi(codec as IHasCodecCameras, 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 IHasCodecSelfView)
{
@@ -390,6 +400,11 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec
LinkVideoCodecPhoneToApi(codec as IHasPhoneDialing, trilist, joinMap);
}
if (codec is IHasCallHistory)
{
LinkVideoCodecCallHistoryToApi(codec as IHasCallHistory, trilist, joinMap);
}
trilist.OnlineStatusChange += (device, args) =>
{
if (!args.DeviceOnLine) return;
@@ -411,7 +426,7 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec
if (codec is IHasCameraAutoMode)
{
trilist.SetBool(joinMap.CameraSupportsAutoMode.JoinNumber, true);
trilist.SetBool(joinMap.CameraSupportsAutoMode.JoinNumber, SupportsCameraAutoMode);
(codec as IHasCameraAutoMode).CameraAutoModeIsOnFeedback.FireUpdate();
}
@@ -436,6 +451,11 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec
(codec as IHasPhoneDialing).PhoneOffHookFeedback.FireUpdate();
}
if (codec is IHasCallHistory)
{
UpdateCallHistory((codec as IHasCallHistory), trilist, joinMap);
}
SharingContentIsOnFeedback.FireUpdate();
trilist.SetBool(joinMap.HookState.JoinNumber, IsInCall);
@@ -444,6 +464,31 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec
};
}
private void LinkVideoCodecInfoToApi(BasicTriList trilist, VideoCodecControllerJoinMap joinMap)
{
trilist.SetBool(joinMap.MultiSiteOptionIsEnabled.JoinNumber, this.CodecInfo.MultiSiteOptionIsEnabled);
trilist.SetBool(joinMap.AutoAnswerEnabled.JoinNumber, this.CodecInfo.AutoAnswerEnabled);
trilist.SetString(joinMap.DeviceIpAddresss.JoinNumber, this.CodecInfo.IpAddress);
trilist.SetString(joinMap.SipPhoneNumber.JoinNumber, this.CodecInfo.SipPhoneNumber);
trilist.SetString(joinMap.E164Alias.JoinNumber, this.CodecInfo.E164Alias);
trilist.SetString(joinMap.H323Id.JoinNumber, this.CodecInfo.H323Id);
trilist.SetString(joinMap.SipUri.JoinNumber, this.CodecInfo.SipUri);
trilist.OnlineStatusChange += (o, a) =>
{
if (a.DeviceOnLine)
{
trilist.SetBool(joinMap.MultiSiteOptionIsEnabled.JoinNumber, this.CodecInfo.MultiSiteOptionIsEnabled);
trilist.SetBool(joinMap.AutoAnswerEnabled.JoinNumber, this.CodecInfo.AutoAnswerEnabled);
trilist.SetString(joinMap.DeviceIpAddresss.JoinNumber, this.CodecInfo.IpAddress);
trilist.SetString(joinMap.SipPhoneNumber.JoinNumber, this.CodecInfo.SipPhoneNumber);
trilist.SetString(joinMap.E164Alias.JoinNumber, this.CodecInfo.E164Alias);
trilist.SetString(joinMap.H323Id.JoinNumber, this.CodecInfo.H323Id);
trilist.SetString(joinMap.SipUri.JoinNumber, this.CodecInfo.SipUri);
}
};
}
private void LinkVideoCodecPhoneToApi(IHasPhoneDialing codec, BasicTriList trilist, VideoCodecControllerJoinMap joinMap)
{
codec.PhoneOffHookFeedback.LinkInputSig(trilist.BooleanInput[joinMap.PhoneHookState.JoinNumber]);
@@ -645,37 +690,37 @@ 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
);
// 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
@@ -945,18 +990,33 @@ ScreenIndexIsPinnedTo: {8} (a{17})
private void LinkVideoCodecDirectoryToApi(IHasDirectory codec, BasicTriList trilist, VideoCodecControllerJoinMap joinMap)
{
codec.CurrentDirectoryResultIsNotDirectoryRoot.LinkComplementInputSig(
trilist.BooleanInput[joinMap.DirectoryIsRoot.JoinNumber]);
trilist.SetSigFalseAction(joinMap.DirectoryRoot.JoinNumber, codec.SetCurrentDirectoryToRoot);
trilist.BooleanInput[joinMap.DirectoryIsRoot.JoinNumber]);
trilist.SetStringSigAction(joinMap.DirectorySearchString.JoinNumber, codec.SearchDirectory);
trilist.SetUShortSigAction(joinMap.DirectorySelectRow.JoinNumber, (i) => SelectDirectoryEntry(codec, i));
trilist.SetUShortSigAction(joinMap.DirectorySelectRow.JoinNumber, (i) => SelectDirectoryEntry(codec, i, trilist, joinMap));
// Report feedback for number of contact methods for selected contact
trilist.SetSigFalseAction(joinMap.DirectoryRoot.JoinNumber, codec.SetCurrentDirectoryToRoot);
trilist.SetSigFalseAction(joinMap.DirectoryFolderBack.JoinNumber, codec.GetDirectoryParentFolderContents);
if (codec.DirectoryRoot != null)
{
trilist.SetUshort(joinMap.DirectoryRowCount.JoinNumber, (ushort)codec.DirectoryRoot.CurrentDirectoryResults.Count);
var clearBytes = XSigHelpers.ClearOutputs();
trilist.SetString(joinMap.DirectoryEntries.JoinNumber,
Encoding.GetEncoding(XSigEncoding).GetString(clearBytes, 0, clearBytes.Length));
var directoryXSig = UpdateDirectoryXSig(codec.DirectoryRoot, !codec.CurrentDirectoryResultIsNotDirectoryRoot.BoolValue);
Debug.Console(2, this, "Directory XSig Length: {0}", directoryXSig.Length);
trilist.SetString(joinMap.DirectoryEntries.JoinNumber, directoryXSig);
}
codec.DirectoryResultReturned += (sender, args) =>
{
trilist.SetUshort(joinMap.DirectoryRowCount.JoinNumber, (ushort)args.Directory.CurrentDirectoryResults.Count);
@@ -967,6 +1027,8 @@ ScreenIndexIsPinnedTo: {8} (a{17})
Encoding.GetEncoding(XSigEncoding).GetString(clearBytes, 0, clearBytes.Length));
var directoryXSig = UpdateDirectoryXSig(args.Directory, !codec.CurrentDirectoryResultIsNotDirectoryRoot.BoolValue);
Debug.Console(2, this, "Directory XSig Length: {0}", directoryXSig.Length);
trilist.SetString(joinMap.DirectoryEntries.JoinNumber, directoryXSig);
};
@@ -981,40 +1043,154 @@ ScreenIndexIsPinnedTo: {8} (a{17})
};
}
private void SelectDirectoryEntry(IHasDirectory codec, ushort i)
private void SelectDirectoryEntry(IHasDirectory codec, ushort i, BasicTriList trilist, VideoCodecControllerJoinMap joinMap)
{
var entry = codec.CurrentDirectoryResult.CurrentDirectoryResults[i - 1];
if (i < 1 || i > codec.CurrentDirectoryResult.CurrentDirectoryResults.Count) return;
if (entry is DirectoryFolder)
_selectedDirectoryItem = codec.CurrentDirectoryResult.CurrentDirectoryResults[i - 1];
if (_selectedDirectoryItem is DirectoryFolder)
{
codec.GetDirectoryFolderContents(entry.FolderId);
return;
codec.GetDirectoryFolderContents(_selectedDirectoryItem.FolderId);
trilist.SetUshort(joinMap.SelectedContactMethodCount.JoinNumber, 0);
trilist.SetString(joinMap.DirectorySelectedFolderName.JoinNumber, _selectedDirectoryItem.Name);
trilist.SetString(joinMap.DirectoryEntrySelectedName.JoinNumber, string.Empty);
trilist.ClearUShortSigAction(joinMap.SelectContactMethod.JoinNumber);
trilist.ClearBoolSigAction(joinMap.DirectoryDialSelectedLine.JoinNumber);
trilist.ClearBoolSigAction(joinMap.DirectoryDialSelectedContactMethod.JoinNumber);
return;
}
var dialableEntry = entry as IInvitableContact;
// not a folder. Clear this value
trilist.SetString(joinMap.DirectorySelectedFolderName.JoinNumber, string.Empty);
if (dialableEntry != null)
{
Dial(dialableEntry);
return;
}
var selectedContact = _selectedDirectoryItem as DirectoryContact;
if (selectedContact != null)
{
trilist.SetString(joinMap.DirectoryEntrySelectedName.JoinNumber, selectedContact.Name);
}
var entryToDial = entry as DirectoryContact;
// Allow auto dial of selected line. Always dials first contact method
if (!trilist.GetBool(joinMap.DirectoryDisableAutoDialSelectedLine.JoinNumber))
{
var invitableEntry = _selectedDirectoryItem as IInvitableContact;
if (entryToDial == null) return;
if (invitableEntry != null)
{
Dial(invitableEntry);
return;
}
Dial(entryToDial.ContactMethods[0].Number);
var entryToDial = _selectedDirectoryItem as DirectoryContact;
trilist.SetString(joinMap.DirectoryEntrySelectedNumber.JoinNumber, selectedContact.ContactMethods[0].Number);
if (entryToDial == null) return;
Dial(entryToDial.ContactMethods[0].Number);
return;
}
else
{
// If auto dial is disabled...
var entryToDial = _selectedDirectoryItem as DirectoryContact;
if (entryToDial == null)
{
// Clear out values and actions from last selected item
trilist.SetUshort(joinMap.SelectedContactMethodCount.JoinNumber, 0);
trilist.SetString(joinMap.DirectoryEntrySelectedName.JoinNumber, string.Empty);
trilist.ClearUShortSigAction(joinMap.SelectContactMethod.JoinNumber);
trilist.ClearBoolSigAction(joinMap.DirectoryDialSelectedLine.JoinNumber);
trilist.ClearBoolSigAction(joinMap.DirectoryDialSelectedContactMethod.JoinNumber);
return;
}
trilist.SetUshort(joinMap.SelectedContactMethodCount.JoinNumber, (ushort)entryToDial.ContactMethods.Count);
// Update the action to dial the selected contact method
trilist.SetUShortSigAction(joinMap.SelectContactMethod.JoinNumber, (u) =>
{
if (u < 1 || u > entryToDial.ContactMethods.Count) return;
trilist.SetSigFalseAction(joinMap.DirectoryDialSelectedContactMethod.JoinNumber, () => Dial(entryToDial.ContactMethods[u - 1].Number));
});
// Sets DirectoryDialSelectedLine join action to dial first contact method
trilist.SetSigFalseAction(joinMap.DirectoryDialSelectedLine.JoinNumber, () => Dial(entryToDial.ContactMethods[0].Number));
var clearBytes = XSigHelpers.ClearOutputs();
trilist.SetString(joinMap.ContactMethods.JoinNumber,
Encoding.GetEncoding(XSigEncoding).GetString(clearBytes, 0, clearBytes.Length));
var contactMethodsXSig = UpdateContactMethodsXSig(entryToDial);
trilist.SetString(joinMap.ContactMethods.JoinNumber, contactMethodsXSig);
}
}
/// <summary>
/// Generates the XSig data representing the available contact methods for the selected DirectoryContact
/// </summary>
/// <param name="contact"></param>
/// <returns></returns>
private string UpdateContactMethodsXSig(DirectoryContact contact)
{
const int maxMethods = 10;
const int maxStrings = 3;
const int offset = maxStrings;
var stringIndex = 0;
var arrayIndex = 0;
// Create a new token array and set the size to the number of methods times the total number of signals
var tokenArray = new XSigToken[maxMethods * offset];
Debug.Console(2, this, "Creating XSIG token array with size {0}", maxMethods * offset);
// TODO: Add code to generate XSig data
foreach (var method in contact.ContactMethods)
{
if (arrayIndex >= maxMethods * offset)
break;
//serials
tokenArray[arrayIndex + 1] = new XSigSerialToken(stringIndex + 1, method.Number);
tokenArray[arrayIndex + 2] = new XSigSerialToken(stringIndex + 2, method.ContactMethodId.ToString());
tokenArray[arrayIndex + 3] = new XSigSerialToken(stringIndex + 3, method.Device.ToString());
arrayIndex += offset;
stringIndex += maxStrings;
}
while (arrayIndex < maxMethods)
{
tokenArray[arrayIndex + 1] = new XSigSerialToken(stringIndex + 1, String.Empty);
tokenArray[arrayIndex + 2] = new XSigSerialToken(stringIndex + 2, String.Empty);
tokenArray[arrayIndex + 3] = new XSigSerialToken(stringIndex + 3, String.Empty);
arrayIndex += offset;
stringIndex += maxStrings;
}
return GetXSigString(tokenArray);
}
private string UpdateDirectoryXSig(CodecDirectory directory, bool isRoot)
{
var contactIndex = 1;
var tokenArray = new XSigToken[directory.CurrentDirectoryResults.Count];
Debug.Console(2, this, "Is root {0} Directory Count: {1}", isRoot, directory.CurrentDirectoryResults.Count);
foreach (var entry in directory.CurrentDirectoryResults)
{
var arrayIndex = contactIndex - 1;
Debug.Console(2, this, "Entry Name: {0}, Folder ID: {1}", entry.Name, entry.FolderId);
if (entry is DirectoryFolder && entry.ParentFolderId == "root")
{
tokenArray[arrayIndex] = new XSigSerialToken(contactIndex, String.Format("[+] {0}", entry.Name));
@@ -1024,8 +1200,6 @@ ScreenIndexIsPinnedTo: {8} (a{17})
continue;
}
if (isRoot && String.IsNullOrEmpty(entry.FolderId)) continue;
tokenArray[arrayIndex] = new XSigSerialToken(contactIndex, entry.Name);
contactIndex++;
@@ -1039,8 +1213,34 @@ ScreenIndexIsPinnedTo: {8} (a{17})
trilist.SetSigFalseAction(joinMap.ManualDial.JoinNumber,
() => Dial(trilist.StringOutput[joinMap.CurrentDialString.JoinNumber].StringValue));
//End All calls for now
trilist.SetSigFalseAction(joinMap.EndCall.JoinNumber, EndAllCalls);
//End All calls
trilist.SetSigFalseAction(joinMap.EndAllCalls.JoinNumber, EndAllCalls);
//End a specific call, specified by index. Maximum 8 calls supported
for (int i = 0; i < joinMap.EndCallStart.JoinSpan; i++)
{
var callIndex = i;
trilist.SetSigFalseAction((uint)(joinMap.EndCallStart.JoinNumber + i), () =>
{
if (callIndex < 0 || callIndex >= ActiveCalls.Count)
{
Debug.Console(2, this, "Cannot end call. No call found at index: {0}", callIndex);
return;
}
var call = ActiveCalls[callIndex];
if (call != null)
{
EndCall(call);
}
else
{
Debug.Console(0, this, "[End Call] Unable to find call at index '{0}'", i);
}
});
}
trilist.SetBool(joinMap.HookState.JoinNumber, IsInCall);
@@ -1052,30 +1252,112 @@ ScreenIndexIsPinnedTo: {8} (a{17})
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);
if (args.CallItem.Direction == eCodecCallDirection.Incoming)
{
trilist.SetSigFalseAction(joinMap.IncomingAnswer.JoinNumber, () => AcceptCall(args.CallItem));
trilist.SetSigFalseAction(joinMap.IncomingReject.JoinNumber, () => RejectCall(args.CallItem));
}
if (args.CallItem.Direction == eCodecCallDirection.Incoming)
{
trilist.SetSigFalseAction(joinMap.IncomingAnswer.JoinNumber, () => AcceptCall(args.CallItem));
trilist.SetSigFalseAction(joinMap.IncomingReject.JoinNumber, () => RejectCall(args.CallItem));
trilist.SetString(joinMap.IncomingCallName.JoinNumber, args.CallItem.Name);
trilist.SetString(joinMap.IncomingCallNumber.JoinNumber, args.CallItem.Number);
}
else
{
trilist.SetString(joinMap.IncomingCallName.JoinNumber, string.Empty);
trilist.SetString(joinMap.IncomingCallNumber.JoinNumber, string.Empty);
}
trilist.SetString(joinMap.CurrentCallData.JoinNumber, UpdateCallStatusXSig());
trilist.SetUshort(joinMap.ConnectedCallCount.JoinNumber, (ushort)ActiveCalls.Count);
};
trilist.OnlineStatusChange += (device, args) =>
{
if (!args.DeviceOnLine) return;
var joinCodec = this as IJoinCalls;
if (joinCodec != null)
{
trilist.SetSigFalseAction(joinMap.JoinAllCalls.JoinNumber, () => joinCodec.JoinAllCalls());
// TODO [ ] Issue #868
trilist.SetString(joinMap.CurrentCallData.JoinNumber, "\xFC");
UpdateCallStatusXSig();
};
for (int i = 0; i < joinMap.JoinCallStart.JoinSpan; i++)
{
trilist.SetSigFalseAction((uint)(joinMap.JoinCallStart.JoinNumber + i), () =>
{
var call = ActiveCalls[i];
if (call != null)
{
joinCodec.JoinCall(call);
}
else
{
Debug.Console(0, this, "[Join Call] Unable to find call at index '{0}'", i);
}
});
}
}
var holdCodec = this as IHasCallHold;
if (holdCodec != null)
{
trilist.SetSigFalseAction(joinMap.HoldAllCalls.JoinNumber, () =>
{
foreach (var call in ActiveCalls)
{
holdCodec.HoldCall(call);
}
});
for (int i = 0; i < joinMap.HoldCallsStart.JoinSpan; i++)
{
var index = i;
trilist.SetSigFalseAction((uint)(joinMap.HoldCallsStart.JoinNumber + index), () =>
{
if (index < 0 || index >= ActiveCalls.Count) return;
var call = ActiveCalls[index];
if (call != null)
{
holdCodec.HoldCall(call);
}
else
{
Debug.Console(0, this, "[Hold Call] Unable to find call at index '{0}'", i);
}
});
trilist.SetSigFalseAction((uint)(joinMap.ResumeCallsStart.JoinNumber + index), () =>
{
if (index < 0 || index >= ActiveCalls.Count) return;
var call = ActiveCalls[index];
if (call != null)
{
holdCodec.ResumeCall(call);
}
else
{
Debug.Console(0, this, "[Resume Call] Unable to find call at index '{0}'", i);
}
});
}
}
trilist.OnlineStatusChange += (device, args) =>
{
if (!args.DeviceOnLine) return;
// TODO [ ] Issue #868
trilist.SetString(joinMap.CurrentCallData.JoinNumber, "\xFC");
UpdateCallStatusXSig();
};
}
private string UpdateCallStatusXSig()
{
const int maxCalls = 8;
const int maxStrings = 5;
const int offset = 6;
const int maxStrings = 6;
const int maxDigitals = 2;
const int offset = maxStrings + maxDigitals;
var stringIndex = 0;
var digitalIndex = maxStrings * maxCalls;
var arrayIndex = 0;
@@ -1087,7 +1369,8 @@ ScreenIndexIsPinnedTo: {8} (a{17})
if (arrayIndex >= maxCalls * offset)
break;
//digitals
tokenArray[arrayIndex] = new XSigDigitalToken(digitalIndex + 1, call.IsActiveCall);
tokenArray[digitalIndex] = new XSigDigitalToken(digitalIndex + 1, call.IsActiveCall);
tokenArray[digitalIndex + 1] = new XSigDigitalToken(digitalIndex + 2, call.IsOnHold);
//serials
tokenArray[arrayIndex + 1] = new XSigSerialToken(stringIndex + 1, call.Name ?? String.Empty);
@@ -1095,6 +1378,12 @@ ScreenIndexIsPinnedTo: {8} (a{17})
tokenArray[arrayIndex + 3] = new XSigSerialToken(stringIndex + 3, call.Direction.ToString());
tokenArray[arrayIndex + 4] = new XSigSerialToken(stringIndex + 4, call.Type.ToString());
tokenArray[arrayIndex + 5] = new XSigSerialToken(stringIndex + 5, call.Status.ToString());
if(call.Duration != null)
{
// May need to verify correct string format here
var dur = string.Format("{0:c}", call.Duration);
tokenArray[arrayIndex + 6] = new XSigSerialToken(stringIndex + 6, dur);
}
arrayIndex += offset;
stringIndex += maxStrings;
@@ -1103,14 +1392,17 @@ ScreenIndexIsPinnedTo: {8} (a{17})
while (digitalIndex < maxCalls)
{
//digitals
tokenArray[arrayIndex] = new XSigDigitalToken(digitalIndex + 1, false);
tokenArray[digitalIndex] = new XSigDigitalToken(digitalIndex + 1, false);
tokenArray[digitalIndex + 1] = new XSigDigitalToken(digitalIndex + 2, false);
//serials
//serials
tokenArray[arrayIndex + 1] = new XSigSerialToken(stringIndex + 1, String.Empty);
tokenArray[arrayIndex + 2] = new XSigSerialToken(stringIndex + 2, String.Empty);
tokenArray[arrayIndex + 3] = new XSigSerialToken(stringIndex + 3, String.Empty);
tokenArray[arrayIndex + 4] = new XSigSerialToken(stringIndex + 4, String.Empty);
tokenArray[arrayIndex + 5] = new XSigSerialToken(stringIndex + 5, String.Empty);
tokenArray[arrayIndex + 6] = new XSigSerialToken(stringIndex + 6, String.Empty);
arrayIndex += offset;
stringIndex += maxStrings;
@@ -1122,25 +1414,61 @@ ScreenIndexIsPinnedTo: {8} (a{17})
private void LinkVideoCodecDtmfToApi(BasicTriList trilist, VideoCodecControllerJoinMap joinMap)
{
trilist.SetSigFalseAction(joinMap.Dtmf0.JoinNumber, () => SendDtmf("0"));
trilist.SetSigFalseAction(joinMap.Dtmf1.JoinNumber, () => SendDtmf("1"));
trilist.SetSigFalseAction(joinMap.Dtmf2.JoinNumber, () => SendDtmf("2"));
trilist.SetSigFalseAction(joinMap.Dtmf3.JoinNumber, () => SendDtmf("3"));
trilist.SetSigFalseAction(joinMap.Dtmf4.JoinNumber, () => SendDtmf("4"));
trilist.SetSigFalseAction(joinMap.Dtmf5.JoinNumber, () => SendDtmf("5"));
trilist.SetSigFalseAction(joinMap.Dtmf6.JoinNumber, () => SendDtmf("6"));
trilist.SetSigFalseAction(joinMap.Dtmf7.JoinNumber, () => SendDtmf("7"));
trilist.SetSigFalseAction(joinMap.Dtmf8.JoinNumber, () => SendDtmf("8"));
trilist.SetSigFalseAction(joinMap.Dtmf9.JoinNumber, () => SendDtmf("9"));
trilist.SetSigFalseAction(joinMap.DtmfStar.JoinNumber, () => SendDtmf("*"));
trilist.SetSigFalseAction(joinMap.DtmfPound.JoinNumber, () => SendDtmf("#"));
trilist.SetSigFalseAction(joinMap.Dtmf0.JoinNumber, () => SendDtmfAction("0", trilist, joinMap));
trilist.SetSigFalseAction(joinMap.Dtmf1.JoinNumber, () => SendDtmfAction("1", trilist, joinMap));
trilist.SetSigFalseAction(joinMap.Dtmf2.JoinNumber, () => SendDtmfAction("2", trilist, joinMap));
trilist.SetSigFalseAction(joinMap.Dtmf3.JoinNumber, () => SendDtmfAction("3", trilist, joinMap));
trilist.SetSigFalseAction(joinMap.Dtmf4.JoinNumber, () => SendDtmfAction("4", trilist, joinMap));
trilist.SetSigFalseAction(joinMap.Dtmf5.JoinNumber, () => SendDtmfAction("5", trilist, joinMap));
trilist.SetSigFalseAction(joinMap.Dtmf6.JoinNumber, () => SendDtmfAction("6", trilist, joinMap));
trilist.SetSigFalseAction(joinMap.Dtmf7.JoinNumber, () => SendDtmfAction("7", trilist, joinMap));
trilist.SetSigFalseAction(joinMap.Dtmf8.JoinNumber, () => SendDtmfAction("8", trilist, joinMap));
trilist.SetSigFalseAction(joinMap.Dtmf9.JoinNumber, () => SendDtmfAction("9", trilist, joinMap));
trilist.SetSigFalseAction(joinMap.DtmfStar.JoinNumber, () => SendDtmfAction("*", trilist, joinMap));
trilist.SetSigFalseAction(joinMap.DtmfPound.JoinNumber, () => SendDtmfAction("#", trilist, joinMap));
}
/// <summary>
/// Sends the specified string as a DTMF command.
/// Reads the value of the SendDtmfToSpecificCallInstance digital join and SelectCall analog join to determine
/// Whther to send to a specific call index or to the last connected call
/// </summary>
/// <param name="s"></param>
/// <param name="trilist"></param>
/// <param name="joinMap"></param>
private void SendDtmfAction(string s, BasicTriList trilist, VideoCodecControllerJoinMap joinMap)
{
if (!trilist.GetBool(joinMap.SendDtmfToSpecificCallIndex.JoinNumber))
{
SendDtmf(s);
}
else
{
var callIndex = trilist.GetUshort(joinMap.SelectCall.JoinNumber);
if (callIndex > 0 && callIndex <= 8)
{
var call = ActiveCalls[callIndex - 1];
if (call != null && call.IsActiveCall)
{
SendDtmf(s, call);
}
else
{
Debug.Console(0, this, "Warning: No call found at index {0} or call is not active.", callIndex);
}
}
else
{
Debug.Console(0, this, "Warning: Invalid call index specified. Please use a value of 1-8.");
}
}
}
private void LinkVideoCodecCameraLayoutsToApi(IHasCodecLayouts codec, BasicTriList trilist, VideoCodecControllerJoinMap joinMap)
{
trilist.SetSigFalseAction(joinMap.CameraLayout.JoinNumber, codec.LocalLayoutToggle);
codec.LocalLayoutFeedback.LinkInputSig(trilist.StringInput[joinMap.CameraLayoutStringFb.JoinNumber]);
codec.LocalLayoutFeedback.LinkInputSig(trilist.StringInput[joinMap.CurrentLayoutStringFb.JoinNumber]);
}
private void LinkVideoCodecCameraModeToApi(IHasCameraAutoMode codec, BasicTriList trilist, VideoCodecControllerJoinMap joinMap)
@@ -1271,18 +1599,81 @@ ScreenIndexIsPinnedTo: {8} (a{17})
else camera.ZoomStop();
});
trilist.SetBoolSigAction(joinMap.CameraFocusNear.JoinNumber, (b) =>
{
if (codec.SelectedCamera == null) return;
var camera = codec.SelectedCamera as IHasCameraFocusControl;
if (camera == null) return;
if (b) camera.FocusNear();
else camera.FocusStop();
});
trilist.SetBoolSigAction(joinMap.CameraFocusFar.JoinNumber, (b) =>
{
if (codec.SelectedCamera == null) return;
var camera = codec.SelectedCamera as IHasCameraFocusControl;
if (camera == null) return;
if (b) camera.FocusFar();
else camera.FocusStop();
});
trilist.SetSigFalseAction(joinMap.CameraFocusAuto.JoinNumber, () =>
{
if (codec.SelectedCamera == null) return;
var camera = codec.SelectedCamera as IHasCameraFocusControl;
if (camera == null) return;
camera.TriggerAutoFocus();
});
// Camera count
trilist.SetUshort(joinMap.CameraCount.JoinNumber, (ushort)codec.Cameras.Count);
// Camera names
for (uint i = 0; i < joinMap.CameraNamesFb.JoinSpan; i++)
{
//Check the count first
if (i < codec.Cameras.Count && codec.Cameras[(int)i] != null)
{
trilist.SetString(joinMap.CameraNamesFb.JoinNumber + i, codec.Cameras[(int)i].Name);
}
else
{
trilist.SetString(joinMap.CameraNamesFb.JoinNumber + i, "");
}
}
//Camera Select
trilist.SetUShortSigAction(joinMap.CameraNumberSelect.JoinNumber, (i) =>
{
if (codec.SelectedCamera == null) return;
codec.SelectCamera(codec.Cameras[i].Key);
if (i > 0 && i <= codec.Cameras.Count)
{
codec.SelectCamera(codec.Cameras[i - 1].Key);
}
else
{
Debug.Console(0, this, "Unable to select. No camera found at index {0}", i);
}
});
// Set initial selected camera feedback
if (codec.SelectedCamera != null)
{
trilist.SetUshort(joinMap.CameraNumberSelect.JoinNumber, (ushort)codec.Cameras.FindIndex((c) => c.Key == codec.SelectedCamera.Key));
}
codec.CameraSelected += (sender, args) =>
{
var i = (ushort)codec.Cameras.FindIndex((c) => c.Key == args.SelectedCamera.Key);
trilist.SetUshort(joinMap.CameraNumberSelect.JoinNumber, (ushort)(i + 1));
if (codec is IHasCodecRoomPresets)
{
return;
@@ -1325,10 +1716,16 @@ ScreenIndexIsPinnedTo: {8} (a{17})
trilist.SetUShortSigAction(joinMap.CameraPresetSelect.JoinNumber, (i) =>
{
presetCodec.CodecRoomPresetSelect(i);
trilist.SetUshort(joinMap.CameraPresetSelect.JoinNumber, i);
});
// Far End Presets
trilist.SetUShortSigAction(joinMap.FarEndPresetSelect.JoinNumber, (i) =>
{
presetCodec.SelectFarEndPreset(i);
});
trilist.SetSigFalseAction(joinMap.CameraPresetSave.JoinNumber,
() =>
{
@@ -1347,7 +1744,96 @@ ScreenIndexIsPinnedTo: {8} (a{17})
};
}
private string SetCameraPresetNames(IEnumerable<CodecRoomPreset> presets)
// Following fields only used for Bridging
private int _selectedRecentCallItemIndex;
private CodecCallHistory.CallHistoryEntry _selectedRecentCallItem;
private DirectoryItem _selectedDirectoryItem;
private void LinkVideoCodecCallHistoryToApi(IHasCallHistory codec, BasicTriList trilist, VideoCodecControllerJoinMap joinMap)
{
codec.CallHistory.RecentCallsListHasChanged += (o, a) =>
{
UpdateCallHistory(codec, trilist, joinMap);
};
// Selected item action and feedback
trilist.SetUShortSigAction(joinMap.SelectRecentCallItem.JoinNumber, (u) =>
{
if (u == 0 || u > codec.CallHistory.RecentCalls.Count)
{
Debug.Console(2, this, "Recent Call History index out of range");
return;
}
_selectedRecentCallItemIndex = (int)(u - 1);
trilist.SetUshort(joinMap.SelectRecentCallItem.JoinNumber, u);
var _selectedRecentCallItem = codec.CallHistory.RecentCalls[_selectedRecentCallItemIndex];
if (_selectedRecentCallItem != null)
{
trilist.SetString(joinMap.SelectedRecentCallName.JoinNumber, _selectedRecentCallItem.Name);
trilist.SetString(joinMap.SelectedRecentCallNumber.JoinNumber, _selectedRecentCallItem.Number);
trilist.SetSigFalseAction(joinMap.RemoveSelectedRecentCallItem.JoinNumber, () => codec.RemoveCallHistoryEntry(_selectedRecentCallItem));
trilist.SetSigFalseAction(joinMap.DialSelectedRecentCallItem.JoinNumber, () => this.Dial(_selectedRecentCallItem.Number));
}
else
{
trilist.SetString(joinMap.SelectedRecentCallName.JoinNumber, string.Empty);
trilist.SetString(joinMap.SelectedRecentCallNumber.JoinNumber, string.Empty);
trilist.ClearBoolSigAction(joinMap.RemoveSelectedRecentCallItem.JoinNumber);
trilist.ClearBoolSigAction(joinMap.DialSelectedRecentCallItem.JoinNumber);
}
});
}
private void UpdateCallHistory(IHasCallHistory codec, BasicTriList trilist, VideoCodecControllerJoinMap joinMap)
{
// Clear out selected item
_selectedRecentCallItemIndex = 0;
_selectedRecentCallItem = null;
trilist.SetUshort(joinMap.SelectRecentCallItem.JoinNumber, 0);
trilist.SetString(joinMap.SelectedRecentCallName.JoinNumber, string.Empty);
trilist.SetString(joinMap.SelectedRecentCallNumber.JoinNumber, string.Empty);
trilist.ClearBoolSigAction(joinMap.RemoveSelectedRecentCallItem.JoinNumber);
//
trilist.SetUshort(joinMap.RecentCallCount.JoinNumber, (ushort)codec.CallHistory.RecentCalls.Count);
// Update the call history joins
var maxItems = joinMap.RecentCallNamesStart.JoinSpan;
// Create history
uint index = 0;
for (uint i = 0; i < maxItems && i < codec.CallHistory.RecentCalls.Count; i++)
{
trilist.SetString(joinMap.RecentCallNamesStart.JoinNumber + i, codec.CallHistory.RecentCalls[(int)i].Name);
trilist.SetString(joinMap.RecentCallTimesStart.JoinNumber + i, codec.CallHistory.RecentCalls[(int)i].StartTime.ToShortTimeString());
trilist.SetUshort(joinMap.RecentCallOccurrenceType.JoinNumber + i, (ushort)codec.CallHistory.RecentCalls[(int)i].OccurrenceType);
//i++;
index = i;
}
//foreach(var item in codec.CallHistory.RecentCalls)
//{
// trilist.SetString(joinMap.RecentCallNamesStart.JoinNumber + i, item.Name);
// trilist.SetString(joinMap.RecentCallTimesStart.JoinNumber + i, item.StartTime.ToShortTimeString());
// trilist.SetUshort(joinMap.RecentCallOccurrenceType.JoinNumber + i, (ushort)item.OccurrenceType);
// i++;
//}
// Clears existing items
for (uint j = index; j < maxItems; j++)
{
trilist.SetString(joinMap.RecentCallNamesStart.JoinNumber + j, string.Empty);
trilist.SetString(joinMap.RecentCallTimesStart.JoinNumber + j, string.Empty);
trilist.SetUshort(joinMap.RecentCallOccurrenceType.JoinNumber + j, 0);
}
}
private string SetCameraPresetNames(IEnumerable<CodecRoomPreset> presets)
{
return SetCameraPresetNames(presets.Select(p => p.Description).ToList());
}

View File

@@ -24,16 +24,30 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.ZoomRoom
{
public class ZoomRoom : VideoCodecBase, IHasCodecSelfView, IHasDirectoryHistoryStack, ICommunicationMonitor,
IRouting,
IHasScheduleAwareness, IHasCodecCameras, IHasParticipants, IHasCameraOff, IHasCameraMute, IHasCameraAutoMode,
IHasScheduleAwareness, IHasCodecCameras, IHasParticipants, IHasCameraOff, IHasCameraMuteWithUnmuteReqeust, IHasCameraAutoMode,
IHasFarEndContentStatus, IHasSelfviewPosition, IHasPhoneDialing, IHasZoomRoomLayouts, IHasParticipantPinUnpin,
IHasParticipantAudioMute, IHasSelfviewSize, IPasswordPrompt, IHasStartMeeting, IHasMeetingInfo, IHasPresentationOnlyMeeting,
IHasMeetingLock, IHasMeetingRecording
{
public event EventHandler VideoUnmuteRequested;
private const long MeetingRefreshTimer = 60000;
public uint DefaultMeetingDurationMin { get; private set; }
private const string Delimiter = "\x0D\x0A";
/// <summary>
/// CR LF CR LF Delimits an echoed response to a command
/// </summary>
private const string EchoDelimiter = "\x0D\x0A\x0D\x0A";
private const string SendDelimiter = "\x0D";
/// <summary>
/// CR LF } CR LF Delimits a JSON response
/// </summary>
private const string JsonDelimiter = "\x0D\x0A\x7D\x0D\x0A";
private string[] Delimiters = new string[] { EchoDelimiter, JsonDelimiter, "OK\x0D\x0A", "end\x0D\x0A" };
//"echo off\x0D\x0A\x0A\x0D\x0A"
private readonly GenericQueue _receiveQueue;
//private readonly CrestronQueue<string> _receiveQueue;
@@ -59,7 +73,7 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.ZoomRoom
_props = JsonConvert.DeserializeObject<ZoomRoomPropertiesConfig>(config.Properties.ToString());
_receiveQueue = new GenericQueue(Key + "-rxQueue", Thread.eThreadPriority.MediumPriority, 512);
_receiveQueue = new GenericQueue(Key + "-rxQueue", Thread.eThreadPriority.MediumPriority, 2048);
Communication = comm;
@@ -71,7 +85,7 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.ZoomRoom
else
{
CommunicationMonitor = new GenericCommunicationMonitor(this, Communication, 30000, 120000, 300000,
"zStatus SystemUnit\r");
"zStatus SystemUnit" + SendDelimiter);
}
DeviceManager.AddDevice(CommunicationMonitor);
@@ -86,9 +100,13 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.ZoomRoom
_syncState.InitialSyncCompleted += SyncState_InitialSyncCompleted;
_syncState.FirstJsonResponseReceived += (o, a) => SetUpSyncQueries();
PhonebookSyncState = new CodecPhonebookSyncState(Key + "--PhonebookSync");
PortGather = new CommunicationGather(Communication, "\x0A") {IncludeDelimiter = true};
PhonebookSyncState.InitialSyncCompleted += (o, a) => ResubscribeForAddedContacts();
PortGather = new CommunicationGather(Communication, Delimiters) {IncludeDelimiter = true};
PortGather.LineReceived += Port_LineReceived;
CodecOsdIn = new RoutingInputPort(RoutingPortNames.CodecOsd,
@@ -326,6 +344,11 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.ZoomRoom
{
Debug.Console(1, this, "Selected Camera with key: '{0}'", camera.Key);
SelectedCamera = camera;
if (CameraIsMutedFeedback.BoolValue)
{
CameraMuteOff();
}
}
else
{
@@ -384,10 +407,8 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.ZoomRoom
{
_currentDirectoryResult = value;
Debug.Console(2, this, "CurrentDirectoryResult Updated. ResultsFolderId: {0}",
_currentDirectoryResult.ResultsFolderId);
CurrentDirectoryResultIsNotDirectoryRoot.FireUpdate();
Debug.Console(2, this, "CurrentDirectoryResult Updated. ResultsFolderId: {0} Contact Count: {1}",
_currentDirectoryResult.ResultsFolderId, _currentDirectoryResult.CurrentDirectoryResults.Count);
OnDirectoryResultReturned(_currentDirectoryResult);
}
@@ -904,7 +925,7 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.ZoomRoom
Debug.Console(1, this, "Sending: '{0}'", command);
}
Communication.SendText(command + Delimiter);
Communication.SendText(command + SendDelimiter);
}
/// <summary>
@@ -914,13 +935,28 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.ZoomRoom
/// <param name="args"></param>
private void Port_LineReceived(object dev, GenericCommMethodReceiveTextArgs args)
{
//if (CommDebuggingIsOn)
// Debug.Console(1, this, "Gathered: '{0}'", args.Text);
//Debug.Console(0, this, "Port_LineReceived");
_receiveQueue.Enqueue(new ProcessStringMessage(args.Text, ProcessMessage));
if (args.Delimiter != JsonDelimiter)
{
// Debug.Console(0, this,
//@"Non JSON response:
//Delimiter: {0}
//{1}", ComTextHelper.GetDebugText(args.Delimiter), args.Text);
ProcessNonJsonResponse(args.Text);
return;
}
else
{
// Debug.Console(0, this,
//@"JSON response:
//Delimiter: {0}
//{1}", ComTextHelper.GetDebugText(args.Delimiter), args.Text);
_receiveQueue.Enqueue(new ProcessStringMessage(args.Text, DeserializeResponse));
//_receiveQueue.Enqueue(new ProcessStringMessage(args.Text, ProcessMessage));
}
}
/// <summary>
/// Queues the initial queries to be sent upon connection
/// </summary>
@@ -979,6 +1015,93 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.ZoomRoom
_syncState.StartSync();
}
private void SetupSession()
{
// disable echo of commands
SendText("echo off");
// switch to json format
// set feedback exclusions
// Currently the feedback exclusions don't work when using the API in JSON response mode
// But leave these here in case the API gets updated in the future
// These may work as of 5.9.4
// In 5.9.4 we're getting sent an AddedContact message for every contact in the phonebook on connect, which is redunant and way too much data
// We want to exclude these messages right away until after we've retrieved the entire phonebook and then we can re-enable them
SendText("zFeedback Register Op: ex Path: /Event/Phonebook/AddedContact");
SendText("zFeedback Register Op: ex Path: /Event/InfoResult/Info/callin_country_list");
SendText("zFeedback Register Op: ex Path: /Event/InfoResult/Info/callout_country_list");
SendText("zFeedback Register Op: ex Path: /Event/InfoResult/Info/toll_free_callinLlist");
SendText("zStatus SystemUnit");
}
/// <summary>
/// Removes the feedback exclusion for added contacts
/// </summary>
private void ResubscribeForAddedContacts()
{
SendText("zFeedback Register Op: in Path: /Event/Phonebook/AddedContact");
}
/// <summary>
/// Processes non-JSON responses as their are received
/// </summary>
/// <param name="response"></param>
private void ProcessNonJsonResponse(string response)
{
if (response.Contains("client_loop: send disconnect: Broken pipe"))
{
Debug.Console(1, this, Debug.ErrorLogLevel.Error,
"Zoom Room Controller or App connected. Essentials will NOT control the Zoom Room until it is disconnected.");
return;
}
if (!_syncState.InitialSyncComplete)
{
if(response.ToLower().Contains("*r login successful"))
{
_syncState.LoginResponseReceived();
SendText("format json");
SetupSession();
}
//switch (response.Trim().ToLower()) // remove the whitespace
//{
// case "*r login successful":
// {
// _syncState.LoginMessageReceived();
// //// Fire up a thread to send the intial commands.
// //CrestronInvoke.BeginInvoke(o =>
// //{
// // disable echo of commands
// SendText("echo off");
// // switch to json format
// SendText("format json");
// // set feedback exclusions
// // Currently the feedback exclusions don't work when using the API in JSON response mode
// // But leave these here in case the API gets updated in the future
// // These may work as of 5.9.4
// if (_props.DisablePhonebookAutoDownload)
// {
// SendText("zFeedback Register Op: ex Path: /Event/Phonebook/AddedContact");
// }
// SendText("zFeedback Register Op: ex Path: /Event/InfoResult/Info/callin_country_list");
// SendText("zFeedback Register Op: ex Path: /Event/InfoResult/Info/callout_country_list");
// SendText("zFeedback Register Op: ex Path: /Event/InfoResult/Info/toll_free_callinLlist");
// //});
// break;
// }
//}
}
}
/// <summary>
/// Processes messages as they are dequeued
/// </summary>
@@ -1006,7 +1129,7 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.ZoomRoom
//Debug.Console(2, this, "JSON Curly Brace Count: {0}", _jsonCurlyBraceCounter);
if (!_jsonFeedbackMessageIsIncoming && message.Trim('\x20') == "{" + Delimiter)
if (!_jsonFeedbackMessageIsIncoming && message.Trim('\x20') == "{" + EchoDelimiter)
// Check for the beginning of a new JSON message
{
_jsonFeedbackMessageIsIncoming = true;
@@ -1023,7 +1146,7 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.ZoomRoom
return;
}
if (_jsonFeedbackMessageIsIncoming && message.Trim('\x20') == "}" + Delimiter)
if (_jsonFeedbackMessageIsIncoming && message.Trim('\x20') == "}" + EchoDelimiter)
// Check for the end of a JSON message
{
_jsonMessage.Append(message);
@@ -1068,7 +1191,7 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.ZoomRoom
{
case "*r login successful":
{
_syncState.LoginMessageReceived();
_syncState.LoginResponseReceived();
// Fire up a thread to send the intial commands.
@@ -1121,6 +1244,11 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.ZoomRoom
var message = JObject.Parse(trimmedResponse);
if (!_syncState.FirstJsonResponseWasReceived)
{
_syncState.ReceivedFirstJsonResponse();
}
var eType =
(eZoomRoomResponseType)
Enum.Parse(typeof (eZoomRoomResponseType), message["type"].Value<string>(), true);
@@ -1129,7 +1257,7 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.ZoomRoom
var responseObj = message[topKey];
Debug.Console(1, "{0} Response Received. topKey: '{1}'\n{2}", eType, topKey, responseObj.ToString());
Debug.Console(1, this, "{0} Response Received. topKey: '{1}'\n{2}", eType, topKey, responseObj.ToString().Replace("\n", CrestronEnvironment.NewLine));
switch (eType)
{
@@ -1182,6 +1310,9 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.ZoomRoom
// This result will always be the complete contents of the directory and never
// A subset of the results via a search
// Clear out any existing data
Status.Phonebook = new zStatus.Phonebook();
JsonConvert.PopulateObject(responseObj.ToString(), Status.Phonebook);
var directoryResults =
@@ -1195,10 +1326,7 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.ZoomRoom
PhonebookSyncState.SetNumberOfContacts(Status.Phonebook.Contacts.Count);
}
if (directoryResults.ResultsFolderId != "root")
{
directoryResults.ResultsFolderId = "root";
}
directoryResults.ResultsFolderId = "root";
DirectoryRoot = directoryResults;
@@ -1485,7 +1613,13 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.ZoomRoom
}
case "videounmuterequest":
{
// TODO: notify room of a request to unmute video
var handler = VideoUnmuteRequested;
if (handler != null)
{
handler(this, null);
}
break;
}
case "meetingneedspassword":
@@ -1642,19 +1776,17 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.ZoomRoom
{
case "login":
{
_syncState.LoginMessageReceived();
_syncState.LoginResponseReceived();
if (!_syncState.InitialQueryMessagesWereSent)
{
SetUpSyncQueries();
}
SetupSession();
JsonConvert.PopulateObject(responseObj.ToString(), Status.Login);
break;
}
case "systemunit":
{
{
JsonConvert.PopulateObject(responseObj.ToString(), Status.SystemUnit);
break;
@@ -1720,6 +1852,8 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.ZoomRoom
}
case "video camera line":
{
Status.Cameras.Clear();
JsonConvert.PopulateObject(responseObj.ToString(), Status.Cameras);
if (!_syncState.CamerasHaveBeenSetUp)
@@ -2575,27 +2709,27 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.ZoomRoom
{
try
{
Debug.Console(2, this, "OnDirectoryResultReturned");
Debug.Console(2, this, "OnDirectoryResultReturned. Result has {0} contacts", result.Contacts.Count);
var directoryResult = new CodecDirectory();
var directoryResult = result;
// If result is Root, create a copy and filter out contacts whose parent folder is not root
if (!CurrentDirectoryResultIsNotDirectoryRoot.BoolValue)
{
Debug.Console(2, this, "Filtering DirectoryRoot to remove contacts for display");
//if (!CurrentDirectoryResultIsNotDirectoryRoot.BoolValue)
//{
// Debug.Console(2, this, "Filtering DirectoryRoot to remove contacts for display");
directoryResult.ResultsFolderId = result.ResultsFolderId;
directoryResult.AddFoldersToDirectory(result.Folders);
directoryResult.AddContactsToDirectory(
result.Contacts.Where((c) => c.ParentFolderId == result.ResultsFolderId).ToList());
}
else
{
directoryResult = result;
}
// directoryResult.ResultsFolderId = result.ResultsFolderId;
// directoryResult.AddFoldersToDirectory(result.Folders);
// directoryResult.AddContactsToDirectory(
// result.Contacts.Where((c) => c.ParentFolderId == result.ResultsFolderId).ToList());
//}
//else
//{
// directoryResult = result;
//}
Debug.Console(2, this, "Updating directoryResult. IsOnRoot: {0}",
!CurrentDirectoryResultIsNotDirectoryRoot.BoolValue);
Debug.Console(2, this, "Updating directoryResult. IsOnRoot: {0} Contact Count: {1}",
!CurrentDirectoryResultIsNotDirectoryRoot.BoolValue, directoryResult.Contacts.Count);
// This will return the latest results to all UIs. Multiple indendent UI Directory browsing will require a different methodology
var handler = DirectoryResultReturned;
@@ -2607,6 +2741,8 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.ZoomRoom
DirectoryIsOnRoot = !CurrentDirectoryResultIsNotDirectoryRoot.BoolValue
});
}
CurrentDirectoryResultIsNotDirectoryRoot.FireUpdate();
}
catch (Exception e)
{
@@ -2637,14 +2773,19 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.ZoomRoom
continue;
}
var camera = new ZoomRoomCamera(cam.id, cam.Name, this);
var existingCam = Cameras.FirstOrDefault((c) => c.Key.Equals(cam.id));
Cameras.Add(camera);
if (existingCam == null)
{
var camera = new ZoomRoomCamera(cam.id, cam.Name, this);
if (cam.Selected)
{
SelectedCamera = camera;
}
Cameras.Add(camera);
if (cam.Selected)
{
SelectedCamera = camera;
}
}
}
if (IsInCall)
@@ -3060,7 +3201,7 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.ZoomRoom
handler(this, new LayoutInfoChangedEventArgs()
{
AvailableLayouts = AvailableLayouts,
CurrentSelectedLayout = (zConfiguration.eLayoutStyle)Enum.Parse(typeof(zConfiguration.eLayoutStyle),LocalLayoutFeedback.StringValue, true),
CurrentSelectedLayout = (zConfiguration.eLayoutStyle)Enum.Parse(typeof(zConfiguration.eLayoutStyle),string.IsNullOrEmpty(LocalLayoutFeedback.StringValue) ? "None" : LocalLayoutFeedback.StringValue , true),
LayoutViewIsOnFirstPage = LayoutViewIsOnFirstPageFeedback.BoolValue,
LayoutViewIsOnLastPage = LayoutViewIsOnLastPageFeedback.BoolValue,
CanSwapContentWithThumbnail = CanSwapContentWithThumbnailFeedback.BoolValue,
@@ -3437,7 +3578,9 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.ZoomRoom
}
}
public bool LoginMessageWasReceived { get; private set; }
public bool LoginResponseWasReceived { get; private set; }
public bool FirstJsonResponseWasReceived { get; private set; }
public bool InitialQueryMessagesWereSent { get; private set; }
@@ -3453,6 +3596,8 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.ZoomRoom
public event EventHandler<EventArgs> InitialSyncCompleted;
public event EventHandler FirstJsonResponseReceived;
public void StartSync()
{
DequeueQueries();
@@ -3475,13 +3620,26 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.ZoomRoom
_syncQueries.Enqueue(query);
}
public void LoginMessageReceived()
public void LoginResponseReceived()
{
LoginMessageWasReceived = true;
Debug.Console(1, this, "Login Message Received.");
LoginResponseWasReceived = true;
Debug.Console(1, this, "Login Rsponse Received.");
CheckSyncStatus();
}
public void ReceivedFirstJsonResponse()
{
FirstJsonResponseWasReceived = true;
Debug.Console(1, this, "First JSON Response Received.");
var handler = FirstJsonResponseReceived;
if (handler != null)
{
handler(this, null);
}
CheckSyncStatus();
}
public void InitialQueryMessagesSent()
{
InitialQueryMessagesWereSent = true;
@@ -3506,7 +3664,8 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.ZoomRoom
public void CodecDisconnected()
{
_syncQueries.Clear();
LoginMessageWasReceived = false;
LoginResponseWasReceived = false;
FirstJsonResponseWasReceived = false;
InitialQueryMessagesWereSent = false;
LastQueryResponseWasReceived = false;
CamerasHaveBeenSetUp = false;
@@ -3515,7 +3674,7 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.ZoomRoom
private void CheckSyncStatus()
{
if (LoginMessageWasReceived && InitialQueryMessagesWereSent && LastQueryResponseWasReceived &&
if (LoginResponseWasReceived && FirstJsonResponseWasReceived && InitialQueryMessagesWereSent && LastQueryResponseWasReceived &&
CamerasHaveBeenSetUp)
{
InitialSyncComplete = true;

View File

@@ -7,6 +7,8 @@ using Crestron.SimplSharpPro.DeviceSupport;
using PepperDash.Essentials.Core.Bridges;
using PepperDash.Essentials.Devices.Common.Cameras;
using Newtonsoft.Json;
namespace PepperDash.Essentials.Devices.Common.VideoCodec.ZoomRoom
{
public enum eZoomRoomCameraState
@@ -34,7 +36,8 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.ZoomRoom
{
protected ZoomRoom ParentCodec { get; private set; }
public int Id = 0; // ID of near end selected camara is always 0
[JsonProperty("id", NullValueHandling = NullValueHandling.Ignore)]
public int? Id = 0; // ID of near end selected camara is always 0
private int ContinueTime = 10; // number of milliseconds between issuing continue commands

View File

@@ -2,30 +2,40 @@
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Crestron.SimplSharp;
using Crestron.SimplSharp;
using Newtonsoft.Json;
using PepperDash.Core;
using PepperDash.Essentials.Core;
namespace PepperDash.Essentials.Devices.Common.VideoCodec.ZoomRoom
{
public class ZoomRoomPropertiesConfig
{
public CommunicationMonitorConfig CommunicationMonitorProperties { get; set; }
public bool DisablePhonebookAutoDownload { get; set; }
public bool SupportsCameraAutoMode { get; set; }
{
[JsonProperty("communicationMonitorProperties")]
public CommunicationMonitorConfig CommunicationMonitorProperties { get; set; }
[JsonProperty("disablePhonebookAutoDownload")]
public bool DisablePhonebookAutoDownload { get; set; }
[JsonProperty("supportsCameraAutoMode")]
public bool SupportsCameraAutoMode { get; set; }
[JsonProperty("supportsCameraOff")]
public bool SupportsCameraOff { get; set; }
//if true, the layouts will be set automatically when sharing starts/ends or a call is joined
//if true, the layouts will be set automatically when sharing starts/ends or a call is joined
[JsonProperty("autoDefaultLayouts")]
public bool AutoDefaultLayouts { get; set; }
/* This layout will be selected when Sharing starts (either from Far end or locally)*/
/* This layout will be selected when Sharing starts (either from Far end or locally)*/
[JsonProperty("defaultSharingLayout")]
public string DefaultSharingLayout { get; set; }
//This layout will be selected when a call is connected and no content is being shared
public string DefaultCallLayout { get; set; }
//This layout will be selected when a call is connected and no content is being shared
[JsonProperty("defaultCallLayout")]
public string DefaultCallLayout { get; set; }
[JsonProperty("minutesBeforeMeetingStart")]
public int MinutesBeforeMeetingStart { get; set; }
}
}

View File

@@ -1,3 +1,3 @@
<packages>
<package id="PepperDashCore" version="1.1.0" targetFramework="net35" allowedVersions="[1.0,2.0)"/>
<package id="PepperDashCore" version="1.1.1-rc-247" targetFramework="net35" allowedVersions="[1.0,2.0)"/>
</packages>