Compare commits

...

49 Commits

Author SHA1 Message Date
Trevor Payne
d9f891dfb1 removed IHasDspPreset from Tesira Classes 2020-10-21 16:59:45 -05:00
Trevor Payne
a9524bcc33 Updated Interface to be more genericized 2020-10-21 16:30:48 -05:00
Trevor Payne
1484c26434 added IDspPreset Interface
Implemented IDspPreset Interface on internal Tesira DSP

Resolves #457
2020-10-21 12:55:41 -05:00
Andrew Welker
f95b50c99d Merge pull request #445 from PepperDash/feature/I18N-Support
Add interfaces for I18N support
2020-10-20 09:56:27 -06:00
Andrew Welker
def5cc273c Merge branch 'development' into feature/I18N-Support 2020-10-19 17:04:39 -06:00
Andrew Welker
e01d2c9569 Merge pull request #450 from PepperDash/bugfix/fix-docker-image
Update docker.yml
2020-10-19 17:04:11 -06:00
Andrew Welker
415dbbb195 Update docker.yml 2020-10-16 08:16:47 -06:00
Andrew Welker
765d90214d Merge branch 'feature/I18N-Support' of https://github.com/PepperDash/Essentials into feature/I18N-Support 2020-10-15 17:00:01 -06:00
Andrew Welker
36fd1dcda9 file name change 2020-10-15 16:59:39 -06:00
Andrew Welker
812b9b731b Merge branch 'development' into feature/I18N-Support 2020-10-15 16:59:20 -06:00
Andrew Welker
e80a68485d Merge pull request #449 from PepperDash/bugfix/zoom-room-incomingcall
Fix for Incoming Call issues
2020-10-15 16:58:37 -06:00
Andrew Welker
535f4ccb8e Merge branch 'development' into bugfix/zoom-room-incomingcall 2020-10-15 16:39:51 -06:00
Andrew Welker
7bbdf43452 add full implementation for LanguageLabel 2020-10-15 16:37:41 -06:00
Andrew Welker
59881d6b3b fix for unanticipated messages from Zoom 2020-10-15 16:14:27 -06:00
Andrew Welker
085e198409 fix for incoming call stuff 2020-10-15 13:34:47 -06:00
Neil Dorin
81f27fcbde Merge branch 'development' into feature/I18N-Support 2020-10-15 12:41:49 -06:00
Neil Dorin
50dae0ef69 Merge pull request #447 from PepperDash/bugfix/card-cage-iteration-fix
Bugfix/card cage iteration fix
2020-10-15 12:41:35 -06:00
Alex Johnson
e0fdefa28e Fix to allow card cage creation loop to continue even if a previous card encountered an issue 2020-10-15 12:36:14 -04:00
Andrew Welker
f6a826505c Merge branch 'development' into feature/I18N-Support 2020-10-13 23:39:12 -06:00
Andrew Welker
68ac506a25 Merge pull request #444 from PepperDash/feature/add-encoding-overload
Add SetString Overload to allow for setting encoding on a sig
2020-10-13 18:11:45 -05:00
Andrew Welker
1150d9e497 add IKeyed to ILanguageLabel to easily get the key 2020-10-13 15:18:31 -06:00
Andrew Welker
633a946f26 Merge branch 'development' into feature/add-encoding-overload 2020-10-13 16:15:04 -05:00
Andrew Welker
8e01455140 Merge pull request #442 from PepperDash/feature/zoom-room-feature-add
Zoom Room Updates & Adds
2020-10-13 16:14:49 -05:00
Andrew Welker
b373ab8708 #443 Add SetString Overload 2020-10-13 14:06:48 -06:00
Andrew Welker
cb752850ff correct interfaces 2020-10-13 13:30:29 -06:00
Andrew Welker
08c929699f #440 Updates for csproj file 2020-10-13 10:29:30 -06:00
Andrew Welker
1862090a89 #440 add interfaces 2020-10-13 09:53:18 -06:00
Alex Johnson
1ea80c3fab Adds phone call ringing status to zoom phone status enum 2020-10-12 12:58:22 -04:00
Andrew Welker
1676f5a956 add phone call logic and commands to Zoom Room 2020-10-08 17:09:59 -06:00
Alex Johnson
cdc9cdbe95 Adds joining meetings 2 and 3 if meetings exist 2020-10-08 15:25:51 -04:00
Alex Johnson
28e8a1fb11 Fixes for selfview feedback. Rearranges order to happen in clockwise motion 2020-10-08 14:40:44 -04:00
Alex Johnson
5f1b92ca62 Adds additional check for if DisablePhonebookAutoDownload is true to CustomActivate method. Fixes issue where layout was not being set properly on sharing end. 2020-10-08 11:43:12 -04:00
Alex Johnson
c58a1874ca Limits max video participant list size to 50 2020-10-07 15:41:04 -04:00
Andrew Welker
f4fb9cd173 add fix for sharing status not updating
add fix for clearing participants list on meeting end
2020-10-07 12:45:05 -06:00
Alex Johnson
ad4a6e9383 Fixes for UpdateCallStatusXSig() method 2020-10-06 16:59:27 -04:00
Andrew Welker
decdaf9f1f lots of updates 2020-10-02 16:58:18 -06:00
Andrew Welker
27382a6be1 various fixes 2020-10-01 14:40:13 -06:00
Andrew Welker
34440af1c5 fix for updating call status when in meeting & call is already connected 2020-10-01 13:25:33 -06:00
Andrew Welker
c0e3da9214 fix for EiscApiAdvanced loading 2020-10-01 12:15:54 -06:00
Andrew Welker
d50ad7345d fix ZoomRoomCamera Timer 2020-10-01 10:37:31 -06:00
Andrew Welker
95016c3ec6 fix camera mute command 2020-10-01 10:07:08 -06:00
Andrew Welker
f8f5c2474c Merge branch 'development' into feature/zoom-room-feature-add 2020-09-30 17:05:17 -06:00
Andrew Welker
b997e9a135 Merge pull request #428 from PepperDash/feature/vc4-eisc
Add VirtualControlEiscClient
2020-09-30 17:01:56 -06:00
Andrew Welker
c7ccac2fe6 fix merge issue 2020-09-30 16:40:58 -06:00
Andrew Welker
45ea5cc875 Merge branch 'development' into feature/vc4-eisc 2020-09-30 14:09:04 -06:00
Andrew Welker
d2eadcd2f5 Use InitialParametersClass.RoomId instead of Config 2020-09-25 10:42:41 -06:00
Andrew Welker
13dabc09c7 Merge branch 'development' into feature/vc4-eisc 2020-09-25 08:53:39 -06:00
Andrew Welker
0fc6a73b30 adjust factory and constructor for EiscApiAdvanced
Keep SystemMonitor from getting instantiated
if we're on a VC-4 instance
2020-09-25 08:47:31 -06:00
Andrew Welker
8f319a4405 making changes for adding VC4 bridge 2020-09-16 09:55:58 -06:00
26 changed files with 1518 additions and 790 deletions

View File

@@ -60,7 +60,7 @@ jobs:
- name: Build Solution
shell: powershell
run: |
Invoke-Expression "docker run --rm --mount type=bind,source=""$($Env:GITHUB_WORKSPACE)"",target=""c:/project"" pepperdash/sspbuilder:v1.4.1 c:\cihelpers\vsidebuild.exe -Solution ""c:\project\$($Env:SOLUTION_FILE).sln"" -BuildSolutionConfiguration $($ENV:BUILD_TYPE)"
Invoke-Expression "docker run --rm --mount type=bind,source=""$($Env:GITHUB_WORKSPACE)"",target=""c:/project"" pepperdash/sspbuilder c:\cihelpers\vsidebuild.exe -Solution ""c:\project\$($Env:SOLUTION_FILE).sln"" -BuildSolutionConfiguration $($ENV:BUILD_TYPE)"
# Zip up the output files as needed
- name: Zip Build Output
shell: powershell

View File

@@ -327,7 +327,11 @@ namespace PepperDash.Essentials
DeviceManager.AddDevice(new PepperDash.Essentials.Core.Devices.CrestronProcessor("processor"));
// Add global System Monitor device
DeviceManager.AddDevice(new PepperDash.Essentials.Core.Monitoring.SystemMonitorController("systemMonitor"));
if (CrestronEnvironment.DevicePlatform == eDevicePlatform.Appliance)
{
DeviceManager.AddDevice(
new PepperDash.Essentials.Core.Monitoring.SystemMonitorController("systemMonitor"));
}
foreach (var devConf in ConfigReader.ConfigObject.Devices)
{

View File

@@ -1,7 +1,9 @@
using System;
using System.Collections.Generic;
using Crestron.SimplSharp;
using Crestron.SimplSharp.Reflection;
using Crestron.SimplSharpPro;
using Crestron.SimplSharpPro.DeviceSupport;
using Crestron.SimplSharpPro.EthernetCommunication;
using Newtonsoft.Json;
@@ -82,9 +84,9 @@ namespace PepperDash.Essentials.Core.Bridges
protected Dictionary<string, JoinMapBaseAdvanced> JoinMaps { get; private set; }
public ThreeSeriesTcpIpEthernetIntersystemCommunications Eisc { get; private set; }
public BasicTriList Eisc { get; private set; }
public EiscApiAdvanced(DeviceConfig dc) :
public EiscApiAdvanced(DeviceConfig dc, BasicTriList eisc) :
base(dc.Key)
{
JoinMaps = new Dictionary<string, JoinMapBaseAdvanced>();
@@ -92,44 +94,52 @@ namespace PepperDash.Essentials.Core.Bridges
PropertiesConfig = dc.Properties.ToObject<EiscApiPropertiesConfig>();
//PropertiesConfig = JsonConvert.DeserializeObject<EiscApiPropertiesConfig>(dc.Properties.ToString());
Eisc = new ThreeSeriesTcpIpEthernetIntersystemCommunications(PropertiesConfig.Control.IpIdInt, PropertiesConfig.Control.TcpSshProperties.Address, Global.ControlSystem);
Eisc = eisc;
Eisc.SigChange += Eisc_SigChange;
AddPostActivationAction( () =>
AddPostActivationAction(LinkDevices);
}
private void LinkDevices()
{
Debug.Console(1, this, "Linking Devices...");
foreach (var d in PropertiesConfig.Devices)
{
Debug.Console(1, this, "Linking Devices...");
var device = DeviceManager.GetDeviceForKey(d.DeviceKey);
foreach (var d in PropertiesConfig.Devices)
if (device == null)
{
var device = DeviceManager.GetDeviceForKey(d.DeviceKey);
if (device == null) continue;
Debug.Console(1, this, "Linking Device: '{0}'", device.Key);
if (!typeof (IBridgeAdvanced).IsAssignableFrom(device.GetType().GetCType()))
{
Debug.Console(0, this, Debug.ErrorLogLevel.Notice,
"{0} is not compatible with this bridge type. Please use 'eiscapi' instead, or updae the device.",
device.Key);
continue;
}
var bridge = device as IBridgeAdvanced;
if (bridge != null) bridge.LinkToApi(Eisc, d.JoinStart, d.JoinMapKey, this);
continue;
}
var registerResult = Eisc.Register();
Debug.Console(1, this, "Linking Device: '{0}'", device.Key);
if (registerResult != eDeviceRegistrationUnRegistrationResponse.Success)
if (!typeof (IBridgeAdvanced).IsAssignableFrom(device.GetType().GetCType()))
{
Debug.Console(2, this, Debug.ErrorLogLevel.Error, "Registration result: {0}", registerResult);
return;
Debug.Console(0, this, Debug.ErrorLogLevel.Notice,
"{0} is not compatible with this bridge type. Please use 'eiscapi' instead, or updae the device.",
device.Key);
continue;
}
Debug.Console(1, this, Debug.ErrorLogLevel.Notice, "EISC registration successful");
});
var bridge = device as IBridgeAdvanced;
if (bridge != null)
{
bridge.LinkToApi(Eisc, d.JoinStart, d.JoinMapKey, this);
}
}
var registerResult = Eisc.Register();
if (registerResult != eDeviceRegistrationUnRegistrationResponse.Success)
{
Debug.Console(2, this, Debug.ErrorLogLevel.Error, "Registration result: {0}", registerResult);
return;
}
Debug.Console(1, this, Debug.ErrorLogLevel.Notice, "EISC registration successful");
}
/// <summary>
@@ -152,7 +162,7 @@ namespace PepperDash.Essentials.Core.Bridges
/// <summary>
/// Prints all the join maps on this bridge
/// </summary>
public void PrintJoinMaps()
public virtual void PrintJoinMaps()
{
Debug.Console(0, this, "Join Maps for EISC IPID: {0}", Eisc.ID.ToString("X"));
@@ -247,7 +257,7 @@ namespace PepperDash.Essentials.Core.Bridges
/// </summary>
/// <param name="currentDevice"></param>
/// <param name="args"></param>
void Eisc_SigChange(object currentDevice, SigEventArgs args)
protected void Eisc_SigChange(object currentDevice, SigEventArgs args)
{
try
{
@@ -299,15 +309,34 @@ namespace PepperDash.Essentials.Core.Bridges
{
public EiscApiAdvancedFactory()
{
TypeNames = new List<string> { "eiscapiadv", "eiscapiadvanced" };
TypeNames = new List<string> { "eiscapiadv", "eiscapiadvanced", "vceiscapiadv", "vceiscapiadvanced" };
}
public override EssentialsDevice BuildDevice(DeviceConfig dc)
{
Debug.Console(1, "Factory Attempting to create new EiscApiAdvanced Device");
return new EiscApiAdvanced(dc);
var controlProperties = CommFactory.GetControlPropertiesConfig(dc);
switch (dc.Type.ToLower())
{
case "eiscapiadv":
case "eiscapiadvanced":
{
var eisc = new ThreeSeriesTcpIpEthernetIntersystemCommunications(controlProperties.IpIdInt,
controlProperties.TcpSshProperties.Address, Global.ControlSystem);
return new EiscApiAdvanced(dc, eisc);
}
case "vceiscapiadv":
case "vceiscapiadvanced":
{
var eisc = new VirtualControlEISCClient(controlProperties.IpIdInt, InitialParametersClass.RoomId,
Global.ControlSystem);
return new EiscApiAdvanced(dc, eisc);
}
default:
return null;
}
}
}

View File

@@ -36,6 +36,15 @@ namespace PepperDash_Essentials_Core.Bridges.JoinMaps
JoinType = eJoinType.Digital
});
[JoinName("CameraLayoutStringFb")] public JoinDataComplete CameraLayoutStringFb =
new JoinDataComplete(new JoinData {JoinNumber = 141, JoinSpan = 1},
new JoinMetadata
{
Description = "Current Layout Fb",
JoinCapabilities = eJoinCapabilities.ToSIMPL,
JoinType = eJoinType.Analog
});
[JoinName("CameraModeAuto")] public JoinDataComplete CameraModeAuto =
new JoinDataComplete(new JoinData {JoinNumber = 131, JoinSpan = 1},
new JoinMetadata
@@ -90,6 +99,15 @@ namespace PepperDash_Essentials_Core.Bridges.JoinMaps
JoinType = eJoinType.Digital
});
[JoinName("CameraPresetNames")] public JoinDataComplete CameraPresetNames =
new JoinDataComplete(new JoinData {JoinNumber = 121, JoinSpan = 1},
new JoinMetadata
{
Description = "Camera Preset Names - XSIG, max of 15",
JoinCapabilities = eJoinCapabilities.ToSIMPL,
JoinType = eJoinType.Serial
});
[JoinName("CameraPresetSelect")] public JoinDataComplete CameraPresetSelect =
new JoinDataComplete(new JoinData {JoinNumber = 121, JoinSpan = 1},
new JoinMetadata
@@ -99,13 +117,13 @@ namespace PepperDash_Essentials_Core.Bridges.JoinMaps
JoinType = eJoinType.Analog
});
[JoinName("CameraPresetNames")] public JoinDataComplete CameraPresetNames =
[JoinName("CameraPresetSave")] public JoinDataComplete CameraPresetSave =
new JoinDataComplete(new JoinData {JoinNumber = 121, JoinSpan = 1},
new JoinMetadata
{
Description = "Camera Preset Names - XSIG, max of 15",
JoinCapabilities = eJoinCapabilities.ToSIMPL,
JoinType = eJoinType.Serial
Description = "Save Selected Preset",
JoinCapabilities = eJoinCapabilities.ToFromSIMPL,
JoinType = eJoinType.Digital
});
[JoinName("CameraSelfView")] public JoinDataComplete CameraSelfView =
@@ -189,15 +207,53 @@ namespace PepperDash_Essentials_Core.Bridges.JoinMaps
JoinType = eJoinType.Serial
});
[JoinName("DirectoryHasChanged")] public JoinDataComplete DirectoryHasChanged =
new JoinDataComplete(new JoinData {JoinNumber = 103, JoinSpan = 1},
[JoinName("CurrentParticipants")] public JoinDataComplete CurrentParticipants =
new JoinDataComplete(new JoinData {JoinNumber = 151, JoinSpan = 1},
new JoinMetadata()
{
Description = "Current Participants XSig",
JoinCapabilities = eJoinCapabilities.ToSIMPL,
JoinType = eJoinType.Serial
});
[JoinName("CurrentSource")] public JoinDataComplete CurrentSource =
new JoinDataComplete(new JoinData {JoinNumber = 201, JoinSpan = 1},
new JoinMetadata
{
Description = "Directory has changed FB",
Description = "Current Source",
JoinCapabilities = eJoinCapabilities.ToSIMPL,
JoinType = eJoinType.Serial
});
[JoinName("DialMeeting1")] public JoinDataComplete DialMeeting1 =
new JoinDataComplete(new JoinData {JoinNumber = 161, JoinSpan = 1},
new JoinMetadata
{
Description = "Join first meeting",
JoinCapabilities = eJoinCapabilities.FromSIMPL,
JoinType = eJoinType.Digital
});
[JoinName("DialMeeting2")]
public JoinDataComplete DialMeeting2 =
new JoinDataComplete(new JoinData { JoinNumber = 162, JoinSpan = 1 },
new JoinMetadata
{
Description = "Join second meeting",
JoinCapabilities = eJoinCapabilities.FromSIMPL,
JoinType = eJoinType.Digital
});
[JoinName("DialMeeting3")]
public JoinDataComplete DialMeeting3 =
new JoinDataComplete(new JoinData { JoinNumber = 163, JoinSpan = 1 },
new JoinMetadata
{
Description = "Join third meeting",
JoinCapabilities = eJoinCapabilities.FromSIMPL,
JoinType = eJoinType.Digital
});
[JoinName("DirectoryDialSelectedLine")] public JoinDataComplete DirectoryDialSelectedLine =
new JoinDataComplete(new JoinData {JoinNumber = 106, JoinSpan = 1},
new JoinMetadata
@@ -252,6 +308,15 @@ namespace PepperDash_Essentials_Core.Bridges.JoinMaps
JoinType = eJoinType.Digital
});
[JoinName("DirectoryHasChanged")] public JoinDataComplete DirectoryHasChanged =
new JoinDataComplete(new JoinData {JoinNumber = 103, JoinSpan = 1},
new JoinMetadata
{
Description = "Directory has changed FB",
JoinCapabilities = eJoinCapabilities.ToSIMPL,
JoinType = eJoinType.Digital
});
[JoinName("DirectoryIsRoot")] public JoinDataComplete DirectoryIsRoot =
new JoinDataComplete(new JoinData {JoinNumber = 102, JoinSpan = 1},
new JoinMetadata
@@ -495,37 +560,12 @@ namespace PepperDash_Essentials_Core.Bridges.JoinMaps
JoinType = eJoinType.Digital
});
[JoinName("SpeedDialStart")] public JoinDataComplete SpeedDialStart =
new JoinDataComplete(new JoinData {JoinNumber = 41, JoinSpan = 4},
[JoinName("ManualDial")] public JoinDataComplete ManualDial =
new JoinDataComplete(new JoinData {JoinNumber = 71, JoinSpan = 1},
new JoinMetadata
{
Description = "Speed Dial",
JoinCapabilities = eJoinCapabilities.ToSIMPL,
JoinType = eJoinType.Digital
});
[JoinName("Schedule")] public JoinDataComplete Schedule =
new JoinDataComplete(new JoinData {JoinNumber = 102, JoinSpan = 1},
new JoinMetadata
{
Description = "Schedule Data - XSIG",
JoinCapabilities = eJoinCapabilities.ToSIMPL,
JoinType = eJoinType.Serial
});
[JoinName("DialMeeting")] public JoinDataComplete DialMeeting = new JoinDataComplete(new JoinData{JoinNumber=161, JoinSpan = 1},
new JoinMetadata
{
Description = "Join first joinable meeting",
JoinCapabilities = eJoinCapabilities.FromSIMPL,
JoinType = eJoinType.Digital
});
[JoinName("UpdateMeetings")] public JoinDataComplete UpdateMeetings =
new JoinDataComplete(new JoinData {JoinNumber = 162, JoinSpan = 1},
new JoinMetadata
{
Description = "Update Meetings",
Description = "Dial manual string",
JoinCapabilities = eJoinCapabilities.FromSIMPL,
JoinType = eJoinType.Digital
});
@@ -539,82 +579,15 @@ namespace PepperDash_Essentials_Core.Bridges.JoinMaps
JoinType = eJoinType.Analog
});
[JoinName("CameraLayoutStringFb")]
public JoinDataComplete CameraLayoutStringFb =
new JoinDataComplete(new JoinData { JoinNumber = 141, JoinSpan = 1 },
new JoinMetadata
{
Description = "Current Layout Fb",
JoinCapabilities = eJoinCapabilities.ToSIMPL,
JoinType = eJoinType.Analog
});
[JoinName("ManualDial")] public JoinDataComplete ManualDial =
new JoinDataComplete(new JoinData {JoinNumber = 71, JoinSpan = 1},
[JoinName("MicMuteOff")] public JoinDataComplete MicMuteOff =
new JoinDataComplete(new JoinData {JoinNumber = 172, JoinSpan = 1},
new JoinMetadata
{
Description = "Dial manual string",
JoinCapabilities = eJoinCapabilities.FromSIMPL,
JoinType = eJoinType.Digital
});
[JoinName("SourceShareStart")] public JoinDataComplete SourceShareStart =
new JoinDataComplete(new JoinData {JoinNumber = 201, JoinSpan = 1},
new JoinMetadata
{
Description = "Start Sharing & Feedback",
Description = "Mic Mute Off",
JoinCapabilities = eJoinCapabilities.ToFromSIMPL,
JoinType = eJoinType.Digital
});
[JoinName("SourceShareEnd")]
public JoinDataComplete SourceShareEnd =
new JoinDataComplete(new JoinData { JoinNumber = 202, JoinSpan = 1 },
new JoinMetadata
{
Description = "Stop Sharing & Feedback",
JoinCapabilities = eJoinCapabilities.ToFromSIMPL,
JoinType = eJoinType.Digital
});
[JoinName("AutoShareWhileInCall")] public JoinDataComplete SourceShareAutoStart =
new JoinDataComplete(new JoinData {JoinNumber = 203, JoinSpan = 1},
new JoinMetadata
{
Description = "When high, will autostart sharing when a call is joined",
JoinCapabilities = eJoinCapabilities.FromSIMPL,
JoinType = eJoinType.Digital
});
[JoinName("CurrentSource")] public JoinDataComplete CurrentSource = new JoinDataComplete(new JoinData{JoinNumber = 201, JoinSpan = 1},
new JoinMetadata
{
Description = "Current Source",
JoinCapabilities = eJoinCapabilities.ToSIMPL,
JoinType = eJoinType.Serial
});
[JoinName("CurrentParticipants")] public JoinDataComplete CurrentParticipants =
new JoinDataComplete(new JoinData{JoinNumber = 151, JoinSpan = 1},
new JoinMetadata()
{
Description = "Current Participants XSig",
JoinCapabilities = eJoinCapabilities.ToSIMPL,
JoinType = eJoinType.Serial
});
[JoinName("ParticipantCount")] public JoinDataComplete ParticipantCount = new JoinDataComplete(new JoinData{JoinNumber = 151, JoinSpan = 1},
new JoinMetadata
{
Description = "Current Participant Count",
JoinCapabilities = eJoinCapabilities.ToSIMPL,
JoinType = eJoinType.Analog
});
[JoinName("MicMuteOn")] public JoinDataComplete MicMuteOn =
new JoinDataComplete(new JoinData {JoinNumber = 171, JoinSpan = 1},
new JoinMetadata
@@ -624,15 +597,6 @@ namespace PepperDash_Essentials_Core.Bridges.JoinMaps
JoinType = eJoinType.Digital
});
[JoinName("MicMuteOff")] public JoinDataComplete MicMuteOff =
new JoinDataComplete(new JoinData {JoinNumber = 172, JoinSpan = 1},
new JoinMetadata
{
Description = "Mic Mute Off",
JoinCapabilities = eJoinCapabilities.ToFromSIMPL,
JoinType = eJoinType.Digital
});
[JoinName("MicMuteToggle")] public JoinDataComplete MicMuteToggle =
new JoinDataComplete(new JoinData {JoinNumber = 173, JoinSpan = 1},
new JoinMetadata
@@ -642,35 +606,150 @@ namespace PepperDash_Essentials_Core.Bridges.JoinMaps
JoinType = eJoinType.Digital
});
[JoinName("VolumeMuteOn")]
public JoinDataComplete VolumeMuteOn =
new JoinDataComplete(new JoinData { JoinNumber = 176, JoinSpan = 1 },
[JoinName("MinutesBeforeMeetingStart")] public JoinDataComplete MinutesBeforeMeetingStart =
new JoinDataComplete(new JoinData {JoinNumber = 41, JoinSpan = 1},
new JoinMetadata
{
Description = "Minutes before meeting start that a meeting is joinable",
JoinCapabilities = eJoinCapabilities.FromSIMPL,
JoinType = eJoinType.Analog
});
[JoinName("ParticipantCount")] public JoinDataComplete ParticipantCount =
new JoinDataComplete(new JoinData {JoinNumber = 151, JoinSpan = 1},
new JoinMetadata
{
Description = "Current Participant Count",
JoinCapabilities = eJoinCapabilities.ToSIMPL,
JoinType = eJoinType.Analog
});
[JoinName("Schedule")] public JoinDataComplete Schedule =
new JoinDataComplete(new JoinData {JoinNumber = 102, JoinSpan = 1},
new JoinMetadata
{
Description = "Schedule Data - XSIG",
JoinCapabilities = eJoinCapabilities.ToSIMPL,
JoinType = eJoinType.Serial
});
[JoinName("AutoShareWhileInCall")] public JoinDataComplete SourceShareAutoStart =
new JoinDataComplete(new JoinData {JoinNumber = 203, JoinSpan = 1},
new JoinMetadata
{
Description = "When high, will autostart sharing when a call is joined",
JoinCapabilities = eJoinCapabilities.FromSIMPL,
JoinType = eJoinType.Digital
});
[JoinName("SourceShareEnd")] public JoinDataComplete SourceShareEnd =
new JoinDataComplete(new JoinData {JoinNumber = 202, JoinSpan = 1},
new JoinMetadata
{
Description = "Stop Sharing & Feedback",
JoinCapabilities = eJoinCapabilities.ToFromSIMPL,
JoinType = eJoinType.Digital
});
[JoinName("SourceShareStart")] public JoinDataComplete SourceShareStart =
new JoinDataComplete(new JoinData {JoinNumber = 201, JoinSpan = 1},
new JoinMetadata
{
Description = "Start Sharing & Feedback",
JoinCapabilities = eJoinCapabilities.ToFromSIMPL,
JoinType = eJoinType.Digital
});
[JoinName("RecievingContent")] public JoinDataComplete RecievingContent =
new JoinDataComplete(new JoinData {JoinNumber = 204, JoinSpan = 1},
new JoinMetadata
{
Description = "Recieving content from the far end",
JoinType = eJoinType.Digital,
JoinCapabilities = eJoinCapabilities.ToSIMPL
});
[JoinName("SelfviewPosition")] public JoinDataComplete SelfviewPosition =
new JoinDataComplete(new JoinData {JoinNumber = 211, JoinSpan = 1},
new JoinMetadata
{
Description = "advance selfview position",
JoinCapabilities = eJoinCapabilities.FromSIMPL,
JoinType = eJoinType.Digital
});
[JoinName("SelfviewPositionFb")]
public JoinDataComplete SelfviewPositionFb =
new JoinDataComplete(new JoinData { JoinNumber = 211, JoinSpan = 1 },
new JoinMetadata
{
Description = "Volume Mute On",
JoinCapabilities = eJoinCapabilities.ToFromSIMPL,
JoinType = eJoinType.Digital
Description = "advance selfview position",
JoinCapabilities = eJoinCapabilities.ToSIMPL,
JoinType = eJoinType.Serial
});
[JoinName("VolumeMuteOff")]
public JoinDataComplete VolumeMuteOff =
new JoinDataComplete(new JoinData { JoinNumber = 177, JoinSpan = 1 },
new JoinMetadata
{
Description = "Volume Mute Off",
JoinCapabilities = eJoinCapabilities.ToFromSIMPL,
JoinType = eJoinType.Digital
});
[JoinName("SpeedDialStart")] public JoinDataComplete SpeedDialStart =
new JoinDataComplete(new JoinData {JoinNumber = 41, JoinSpan = 4},
new JoinMetadata
{
Description = "Speed Dial",
JoinCapabilities = eJoinCapabilities.ToSIMPL,
JoinType = eJoinType.Digital
});
[JoinName("VolumeMuteToggle")]
public JoinDataComplete VolumeMuteToggle =
new JoinDataComplete(new JoinData { JoinNumber = 178, JoinSpan = 1 },
new JoinMetadata
{
Description = "Volume Mute Toggle",
JoinCapabilities = eJoinCapabilities.ToFromSIMPL,
JoinType = eJoinType.Digital
});
[JoinName("UpdateMeetings")] public JoinDataComplete UpdateMeetings =
new JoinDataComplete(new JoinData {JoinNumber = 160, JoinSpan = 1},
new JoinMetadata
{
Description = "Update Meetings",
JoinCapabilities = eJoinCapabilities.FromSIMPL,
JoinType = eJoinType.Digital
});
[JoinName("VolumeDown")] public JoinDataComplete VolumeDown =
new JoinDataComplete(new JoinData {JoinNumber = 175, JoinSpan = 1},
new JoinMetadata
{
Description = "Volume Down",
JoinCapabilities = eJoinCapabilities.FromSIMPL,
JoinType = eJoinType.Digital
});
[JoinName("VolumeLevel")] public JoinDataComplete VolumeLevel =
new JoinDataComplete(new JoinData {JoinNumber = 174, JoinSpan = 1},
new JoinMetadata
{
Description = "Volume Level",
JoinCapabilities = eJoinCapabilities.ToFromSIMPL,
JoinType = eJoinType.Analog
});
[JoinName("VolumeMuteOff")] public JoinDataComplete VolumeMuteOff =
new JoinDataComplete(new JoinData {JoinNumber = 177, JoinSpan = 1},
new JoinMetadata
{
Description = "Volume Mute Off",
JoinCapabilities = eJoinCapabilities.ToFromSIMPL,
JoinType = eJoinType.Digital
});
[JoinName("VolumeMuteOn")] public JoinDataComplete VolumeMuteOn =
new JoinDataComplete(new JoinData {JoinNumber = 176, JoinSpan = 1},
new JoinMetadata
{
Description = "Volume Mute On",
JoinCapabilities = eJoinCapabilities.ToFromSIMPL,
JoinType = eJoinType.Digital
});
[JoinName("VolumeMuteToggle")] public JoinDataComplete VolumeMuteToggle =
new JoinDataComplete(new JoinData {JoinNumber = 178, JoinSpan = 1},
new JoinMetadata
{
Description = "Volume Mute Toggle",
JoinCapabilities = eJoinCapabilities.ToFromSIMPL,
JoinType = eJoinType.Digital
});
[JoinName("VolumeUp")] public JoinDataComplete VolumeUp =
new JoinDataComplete(new JoinData {JoinNumber = 174, JoinSpan = 1},
@@ -681,34 +760,45 @@ namespace PepperDash_Essentials_Core.Bridges.JoinMaps
JoinType = eJoinType.Digital
});
[JoinName("VolumeDown")]
public JoinDataComplete VolumeDown =
new JoinDataComplete(new JoinData { JoinNumber = 175, JoinSpan = 1 },
[JoinName("DialPhoneCall")]
public JoinDataComplete DialPhone =
new JoinDataComplete(new JoinData { JoinNumber = 72, JoinSpan = 1 },
new JoinMetadata
{
Description = "Volume Down",
Description = "Dial Phone",
JoinCapabilities = eJoinCapabilities.FromSIMPL,
JoinType = eJoinType.Digital
});
[JoinName("VolumeLevel")]
public JoinDataComplete VolumeLevel =
new JoinDataComplete(new JoinData { JoinNumber = 174, JoinSpan = 1 },
[JoinName("PhoneHookState")]
public JoinDataComplete PhoneHookState =
new JoinDataComplete(new JoinData { JoinNumber = 72, JoinSpan = 1 },
new JoinMetadata
{
Description = "Volume Level",
JoinCapabilities = eJoinCapabilities.ToFromSIMPL,
JoinType = eJoinType.Analog
Description = "Dial Phone",
JoinCapabilities = eJoinCapabilities.ToSIMPL,
JoinType = eJoinType.Digital
});
[JoinName("MinutesBeforeMeetingStart")] public JoinDataComplete MinutesBeforeMeetingStart =
new JoinDataComplete(new JoinData {JoinNumber = 41, JoinSpan = 1},
new JoinMetadata
{
Description = "Minutes before meeting start that a meeting is joinable",
JoinCapabilities = eJoinCapabilities.FromSIMPL,
JoinType = eJoinType.Analog
});
[JoinName("EndPhoneCall")]
public JoinDataComplete HangUpPhone =
new JoinDataComplete(new JoinData { JoinNumber = 73, JoinSpan = 1 },
new JoinMetadata
{
Description = "Hang Up PHone",
JoinCapabilities = eJoinCapabilities.FromSIMPL,
JoinType = eJoinType.Digital
});
[JoinName("PhoneString")]
public JoinDataComplete PhoneDialString =
new JoinDataComplete(new JoinData { JoinNumber = 2, JoinSpan = 1 },
new JoinMetadata
{
Description = "Phone Dial String",
JoinCapabilities = eJoinCapabilities.FromSIMPL,
JoinType = eJoinType.Serial
});
public VideoCodecControllerJoinMap(uint joinStart) : base(joinStart, typeof (VideoCodecControllerJoinMap))
{

View File

@@ -73,21 +73,21 @@ namespace PepperDash.Essentials.Core.CrestronIO.Cards
string cardType;
if (!_config.Cards.TryGetValue(i, out cardType))
{
Debug.Console(1, this, "No card found for slot {0}", i);
Debug.Console(0, this, "No card found for slot {0}", i);
continue;
}
if (String.IsNullOrEmpty(cardType))
{
Debug.Console(0, this, "No card specified for slot {0}", i);
return;
continue;
}
Func<uint, C3CardControllerBase> cardBuilder;
if (!_cardDict.TryGetValue(cardType.ToLower(), out cardBuilder))
{
Debug.Console(0, "Unable to find factory for 3-Series card type {0}.", cardType);
return;
continue;
}
try

View File

@@ -0,0 +1,7 @@
namespace PepperDash.Essentials.Core.DeviceTypeInterfaces
{
public interface IHasFarEndContentStatus
{
BoolFeedback ReceivingContent { get; }
}
}

View File

@@ -0,0 +1,14 @@
using PepperDash.Essentials.Core;
namespace PepperDash_Essentials_Core.DeviceTypeInterfaces
{
public interface IHasPhoneDialing
{
BoolFeedback PhoneOffHookFeedback { get; }
StringFeedback CallerIdNameFeedback { get; }
StringFeedback CallerIdNumberFeedback { get; }
void DialPhoneCall(string number);
void EndPhoneCall();
void SendDtmfToPhone(string digit);
}
}

View File

@@ -0,0 +1,15 @@
using System;
using System.Collections.Generic;
namespace PepperDash_Essentials_Core.DeviceTypeInterfaces
{
public interface ILanguageDefinition
{
string LocaleName { get; set; }
string FriendlyName { get; set; }
bool Enable { get; set; }
List<LanguageLabel> UiLabels { get; set; }
List<LanguageLabel> Sources { get; set; }
List<LanguageLabel> Destinations { get; set; }
}
}

View File

@@ -0,0 +1,13 @@
using System;
using System.Collections.Generic;
namespace PepperDash_Essentials_Core.DeviceTypeInterfaces
{
public interface ILanguageProvider
{
ILanguageDefinition CurrentLanguage { get; set; }
event EventHandler CurrentLanguageChanged;
}
}

View File

@@ -0,0 +1,12 @@
using PepperDash.Core;
namespace PepperDash_Essentials_Core.DeviceTypeInterfaces
{
public class LanguageLabel
{
public string Key { get; set; }
public string Description { get; set; }
public string DisplayText { get; set; }
public uint JoinNumber { get; set; }
}
}

View File

@@ -0,0 +1,17 @@
using System.Collections.Generic;
namespace PepperDash.Essentials.Core
{
public interface IHasDspPresets
{
List<IDspPreset> Presets { get; }
void RecallPreset(IDspPreset preset);
}
public interface IDspPreset
{
string Name { get; }
}
}

View File

@@ -0,0 +1,12 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Crestron.SimplSharp;
namespace PepperDash_Essentials_Core.Gateways
{
public class CenCn2Controller
{
}
}

View File

@@ -20,9 +20,11 @@ namespace PepperDash.Essentials.Core
{
public static CrestronControlSystem ControlSystem { get; set; }
public static LicenseManager LicenseManager { get; set; }
public static eDevicePlatform Platform { get { return CrestronEnvironment.DevicePlatform; } }
public static Dictionary<short, EthernetAdapterInfo> EthernetAdapterInfoCollection {get; private set;}
public static Dictionary<short, EthernetAdapterInfo> EthernetAdapterInfoCollection { get; private set; }
public static LicenseManager LicenseManager { get; set; }
/// <summary>
/// The file path prefix to the folder containing configuration files
@@ -163,8 +165,6 @@ namespace PepperDash.Essentials.Core
*/
}
static Global()
{
// Fire up CrestronDataStoreStatic
@@ -174,87 +174,7 @@ namespace PepperDash.Essentials.Core
CrestronConsole.PrintLine("Error starting CrestronDataStoreStatic: {0}", err);
return;
}
GetEthernetInformation();
}
/// <summary>
/// Populates EthernetInformationCollection
/// </summary>
static void GetEthernetInformation()
{
EthernetAdapterInfoCollection = new Dictionary<short, EthernetAdapterInfo>();
EthernetAdapterType adapterType = EthernetAdapterType.EthernetUnknownAdapter;
List<EthernetAdapterType> adapters = new List<EthernetAdapterType>()
{ EthernetAdapterType.EthernetLANAdapter, EthernetAdapterType.EthernetLAN2Adapter, EthernetAdapterType.EthernetCSAdapter, EthernetAdapterType.EthernetWIFIAdapter };
foreach (var adapter in adapters)
{
try
{
adapterType = EthernetAdapterType.EthernetLANAdapter;
var adapterId = CrestronEthernetHelper.GetAdapterdIdForSpecifiedAdapterType(adapterType);
var adapterInfo = GetEthernetAdapterProperties(adapterId, adapterType);
EthernetAdapterInfoCollection.Add(adapterId, adapterInfo);
}
catch (Exception e)
{
if (e is System.ArgumentException)
{
Debug.Console(1, "Error: {0} not present", adapterType);
}
else
{
Debug.Console(1, "Error: {0}", e);
}
}
}
}
static EthernetAdapterInfo GetEthernetAdapterProperties(short adapterId, EthernetAdapterType adapterType)
{
EthernetAdapterInfo adapterInfo = new EthernetAdapterInfo();
adapterInfo.Type = adapterType;
adapterInfo.DhcpIsOn = CrestronEthernetHelper.GetEthernetParameter(CrestronEthernetHelper.ETHERNET_PARAMETER_TO_GET.GET_CURRENT_DHCP_STATE, adapterId) == "on" ? true : false;
adapterInfo.Hostname = CrestronEthernetHelper.GetEthernetParameter(CrestronEthernetHelper.ETHERNET_PARAMETER_TO_GET.GET_HOSTNAME, adapterId);
adapterInfo.MacAddress = CrestronEthernetHelper.GetEthernetParameter(CrestronEthernetHelper.ETHERNET_PARAMETER_TO_GET.GET_MAC_ADDRESS, adapterId);
adapterInfo.IpAddress = CrestronEthernetHelper.GetEthernetParameter(CrestronEthernetHelper.ETHERNET_PARAMETER_TO_GET.GET_CURRENT_IP_ADDRESS, adapterId);
adapterInfo.Subnet = CrestronEthernetHelper.GetEthernetParameter(CrestronEthernetHelper.ETHERNET_PARAMETER_TO_GET.GET_CURRENT_IP_MASK, adapterId);
adapterInfo.Gateway = CrestronEthernetHelper.GetEthernetParameter(CrestronEthernetHelper.ETHERNET_PARAMETER_TO_GET.GET_CURRENT_ROUTER, adapterId);
adapterInfo.Domain = CrestronEthernetHelper.GetEthernetParameter(CrestronEthernetHelper.ETHERNET_PARAMETER_TO_GET.GET_DOMAIN_NAME, adapterId);
string dns = CrestronEthernetHelper.GetEthernetParameter(CrestronEthernetHelper.ETHERNET_PARAMETER_TO_GET.GET_DNS_SERVER, adapterId);
if (dns.Contains(","))
{
string[] dnsList = dns.Split(',');
for (var i = 0; i < dnsList.Length; i++)
{
if (i == 0)
adapterInfo.Dns1 = !string.IsNullOrEmpty(dnsList[0]) ? dnsList[0] : "0.0.0.0";
if (i == 1)
adapterInfo.Dns2 = !string.IsNullOrEmpty(dnsList[1]) ? dnsList[1] : "0.0.0.0";
if (i == 2)
adapterInfo.Dns3 = !string.IsNullOrEmpty(dnsList[2]) ? dnsList[2] : "0.0.0.0";
}
}
else
{
adapterInfo.Dns1 = !string.IsNullOrEmpty(dns) ? dns : "0.0.0.0";
adapterInfo.Dns2 = "0.0.0.0";
adapterInfo.Dns3 = "0.0.0.0";
}
return adapterInfo;
}
}
}

View File

@@ -190,12 +190,18 @@
<Compile Include="Devices\EssentialsBridgeableDevice.cs" />
<Compile Include="Devices\EssentialsDevice.cs" />
<Compile Include="Devices\GenericIRController.cs" />
<Compile Include="Devices\IDspPreset.cs" />
<Compile Include="Devices\IProjectorInterfaces.cs" />
<Compile Include="Devices\PC\InRoomPc.cs" />
<Compile Include="Devices\PC\Laptop.cs" />
<Compile Include="Devices\ReconfigurableDevice.cs" />
<Compile Include="Devices\VolumeDeviceChangeEventArgs.cs" />
<Compile Include="DeviceTypeInterfaces\LanguageLabel.cs" />
<Compile Include="DeviceTypeInterfaces\ILanguageProvider.cs" />
<Compile Include="DeviceTypeInterfaces\IHasBranding.cs" />
<Compile Include="DeviceTypeInterfaces\ILanguageDefinition.cs" />
<Compile Include="DeviceTypeInterfaces\IHasFarEndContentStatus.cs" />
<Compile Include="DeviceTypeInterfaces\IHasPhoneDialing.cs" />
<Compile Include="DeviceTypeInterfaces\IMobileControl.cs" />
<Compile Include="Factory\DeviceFactory.cs" />
<Compile Include="Factory\IDeviceFactory.cs" />

View File

@@ -251,6 +251,12 @@ namespace PepperDash.Essentials.Core
tl.StringInput[sigNum].StringValue = value;
}
public static void SetString(this BasicTriList tl, uint sigNum, string value, eStringEncoding encoding)
{
tl.StringInput[sigNum].StringEncoding = encoding;
tl.StringInput[sigNum].StringValue = value;
}
/// <summary>
/// Returns bool value of trilist sig
/// </summary>

View File

@@ -6,390 +6,398 @@ using Crestron.SimplSharp;
using PepperDash.Core;
using PepperDash.Essentials.Core;
using PepperDash.Essentials.Core.Config;
using System.Text.RegularExpressions;
namespace PepperDash.Essentials.Devices.Common.DSP
{
// QUESTIONS:
//
// When subscribing, just use the Instance ID for Custom Name?
// Verbose on subscriptions?
// Example subscription feedback responses
// ! "publishToken":"name" "value":-77.0
// ! "myLevelName" -77
public class BiampTesiraForteDsp : DspBase
{
public IBasicCommunication Communication { get; private set; }
public CommunicationGather PortGather { get; private set; }
public StatusMonitorBase CommunicationMonitor { get; private set; }
new public Dictionary<string, TesiraForteLevelControl> LevelControlPoints { get; private set; }
public bool isSubscribed;
private CTimer SubscriptionTimer;
CrestronQueue CommandQueue;
bool CommandQueueInProgress = false;
//new public Dictionary<string, DspControlPoint> DialerControlPoints { get; private set; }
//new public Dictionary<string, DspControlPoint> SwitcherControlPoints { get; private set; }
/// <summary>
/// Shows received lines as hex
/// </summary>
public bool ShowHexResponse { get; set; }
public BiampTesiraForteDsp(string key, string name, IBasicCommunication comm, BiampTesiraFortePropertiesConfig props) :
base(key, name)
{
CommandQueue = new CrestronQueue(100);
Communication = comm;
var socket = comm as ISocketStatus;
if (socket != null)
{
// This instance uses IP control
socket.ConnectionChange += new EventHandler<GenericSocketStatusChageEventArgs>(socket_ConnectionChange);
}
else
{
// This instance uses RS-232 control
}
PortGather = new CommunicationGather(Communication, "\x0d\x0a");
PortGather.LineReceived += this.Port_LineReceived;
if (props.CommunicationMonitorProperties != null)
{
CommunicationMonitor = new GenericCommunicationMonitor(this, Communication, props.CommunicationMonitorProperties);
}
else
{
//#warning Need to deal with this poll string
CommunicationMonitor = new GenericCommunicationMonitor(this, Communication, 120000, 120000, 300000, "SESSION get aliases\x0d\x0a");
}
LevelControlPoints = new Dictionary<string, TesiraForteLevelControl>();
foreach (KeyValuePair<string, BiampTesiraForteLevelControlBlockConfig> block in props.LevelControlBlocks)
{
this.LevelControlPoints.Add(block.Key, new TesiraForteLevelControl(block.Key, block.Value, this));
}
}
public override bool CustomActivate()
{
Communication.Connect();
CommunicationMonitor.StatusChange += (o, a) => { Debug.Console(2, this, "Communication monitor state: {0}", CommunicationMonitor.Status); };
CommunicationMonitor.Start();
CrestronConsole.AddNewConsoleCommand(SendLine, "send" + Key, "", ConsoleAccessLevelEnum.AccessOperator);
CrestronConsole.AddNewConsoleCommand(s => Communication.Connect(), "con" + Key, "", ConsoleAccessLevelEnum.AccessOperator);
return true;
}
void socket_ConnectionChange(object sender, GenericSocketStatusChageEventArgs e)
{
Debug.Console(2, this, "Socket Status Change: {0}", e.Client.ClientStatus.ToString());
if (e.Client.IsConnected)
{
// Tasks on connect
}
else
{
// Cleanup items from this session
if (SubscriptionTimer != null)
{
SubscriptionTimer.Stop();
SubscriptionTimer = null;
}
isSubscribed = false;
CommandQueue.Clear();
CommandQueueInProgress = false;
}
}
/// <summary>
/// Initiates the subscription process to the DSP
/// </summary>
void SubscribeToAttributes()
{
SendLine("SESSION set verbose true");
foreach (KeyValuePair<string, TesiraForteLevelControl> level in LevelControlPoints)
{
level.Value.Subscribe();
}
if (!CommandQueueInProgress)
SendNextQueuedCommand();
ResetSubscriptionTimer();
}
/// <summary>
/// Resets or Sets the subscription timer
/// </summary>
void ResetSubscriptionTimer()
{
isSubscribed = true;
if (SubscriptionTimer != null)
{
SubscriptionTimer = new CTimer(o => SubscribeToAttributes(), 30000);
SubscriptionTimer.Reset();
}
}
/// <summary>
/// Handles a response message from the DSP
/// </summary>
/// <param name="dev"></param>
/// <param name="args"></param>
void Port_LineReceived(object dev, GenericCommMethodReceiveTextArgs args)
{
if (Debug.Level == 2)
Debug.Console(2, this, "RX: '{0}'",
ShowHexResponse ? ComTextHelper.GetEscapedText(args.Text) : args.Text);
Debug.Console(1, this, "RX: '{0}'", args.Text);
try
{
if (args.Text.IndexOf("Welcome to the Tesira Text Protocol Server...") > -1)
{
// Indicates a new TTP session
SubscribeToAttributes();
}
else if (args.Text.IndexOf("publishToken") > -1)
{
// response is from a subscribed attribute
string pattern = "! \"publishToken\":[\"](.*)[\"] \"value\":(.*)";
Match match = Regex.Match(args.Text, pattern);
if (match.Success)
{
string key;
string customName;
string value;
customName = match.Groups[1].Value;
// Finds the key (everything before the '~' character
key = customName.Substring(0, customName.IndexOf("~", 0) - 1);
value = match.Groups[2].Value;
foreach (KeyValuePair<string, TesiraForteLevelControl> controlPoint in LevelControlPoints)
{
if (customName == controlPoint.Value.LevelCustomName || customName == controlPoint.Value.MuteCustomName)
{
controlPoint.Value.ParseSubscriptionMessage(customName, value);
return;
}
}
}
/// same for dialers
/// same for switchers
}
else if (args.Text.IndexOf("+OK") > -1)
{
if (args.Text == "+OK" || args.Text.IndexOf("list\":") > -1 ) // Check for a simple "+OK" only 'ack' repsonse or a list response and ignore
return;
// response is not from a subscribed attribute. From a get/set/toggle/increment/decrement command
if (!CommandQueue.IsEmpty)
{
if (CommandQueue.Peek() is QueuedCommand)
{
// Expected response belongs to a child class
QueuedCommand tempCommand = (QueuedCommand)CommandQueue.TryToDequeue();
//Debug.Console(1, this, "Command Dequeued. CommandQueue Size: {0}", CommandQueue.Count);
tempCommand.ControlPoint.ParseGetMessage(tempCommand.AttributeCode, args.Text);
}
else
{
// Expected response belongs to this class
string temp = (string)CommandQueue.TryToDequeue();
//Debug.Console(1, this, "Command Dequeued. CommandQueue Size: {0}", CommandQueue.Count);
}
if (CommandQueue.IsEmpty)
CommandQueueInProgress = false;
else
SendNextQueuedCommand();
}
}
else if (args.Text.IndexOf("-ERR") > -1)
{
// Error response
switch (args.Text)
{
case "-ERR ALREADY_SUBSCRIBED":
{
ResetSubscriptionTimer();
break;
}
default:
{
Debug.Console(0, this, "Error From DSP: '{0}'", args.Text);
break;
}
}
}
}
catch (Exception e)
{
if (Debug.Level == 2)
Debug.Console(2, this, "Error parsing response: '{0}'\n{1}", args.Text, e);
}
}
/// <summary>
/// Sends a command to the DSP (with delimiter appended)
/// </summary>
/// <param name="s">Command to send</param>
public void SendLine(string s)
{
Debug.Console(1, this, "TX: '{0}'", s);
Communication.SendText(s + "\x0a");
}
/// <summary>
/// Adds a command from a child module to the queue
/// </summary>
/// <param name="command">Command object from child module</param>
public void EnqueueCommand(QueuedCommand commandToEnqueue)
{
CommandQueue.Enqueue(commandToEnqueue);
//Debug.Console(1, this, "Command (QueuedCommand) Enqueued '{0}'. CommandQueue has '{1}' Elements.", commandToEnqueue.Command, CommandQueue.Count);
if(!CommandQueueInProgress)
SendNextQueuedCommand();
}
/// <summary>
/// Adds a raw string command to the queue
/// </summary>
/// <param name="command"></param>
public void EnqueueCommand(string command)
{
CommandQueue.Enqueue(command);
//Debug.Console(1, this, "Command (string) Enqueued '{0}'. CommandQueue has '{1}' Elements.", command, CommandQueue.Count);
if (!CommandQueueInProgress)
SendNextQueuedCommand();
}
/// <summary>
/// Sends the next queued command to the DSP
/// </summary>
void SendNextQueuedCommand()
{
//Debug.Console(2, this, "Attempting to send next queued command. CommandQueueInProgress: {0} Communication isConnected: {1}", CommandQueueInProgress, Communication.IsConnected);
//if (CommandQueue.IsEmpty)
// CommandQueueInProgress = false;
//Debug.Console(1, this, "CommandQueue has {0} Elements:\n", CommandQueue.Count);
//foreach (object o in CommandQueue)
//{
// if (o is string)
// Debug.Console(1, this, "{0}", o);
// else if(o is QueuedCommand)
// {
// var item = (QueuedCommand)o;
// Debug.Console(1, this, "{0}", item.Command);
// }
//}
//Debug.Console(1, this, "End of CommandQueue");
if (Communication.IsConnected && !CommandQueue.IsEmpty)
{
CommandQueueInProgress = true;
if (CommandQueue.Peek() is QueuedCommand)
{
QueuedCommand nextCommand = new QueuedCommand();
nextCommand = (QueuedCommand)CommandQueue.Peek();
SendLine(nextCommand.Command);
}
else
{
string nextCommand = (string)CommandQueue.Peek();
SendLine(nextCommand);
}
}
}
/// <summary>
/// Sends a command to execute a preset
/// </summary>
/// <param name="name">Preset Name</param>
public override void RunPreset(string name)
{
SendLine(string.Format("DEVICE recallPreset {0}", name));
}
public class QueuedCommand
{
public string Command { get; set; }
public string AttributeCode { get; set; }
public TesiraForteControlPoint ControlPoint { get; set; }
}
}
public class BiampTesiraForteDspFactory : EssentialsDeviceFactory<BiampTesiraForteDsp>
{
public BiampTesiraForteDspFactory()
{
TypeNames = new List<string>() { "biamptesira" };
}
public override EssentialsDevice BuildDevice(DeviceConfig dc)
{
Debug.Console(1, "Factory Attempting to create new BiampTesira Device");
var comm = CommFactory.CreateCommForDevice(dc);
var props = Newtonsoft.Json.JsonConvert.DeserializeObject<BiampTesiraFortePropertiesConfig>(
dc.Properties.ToString());
return new BiampTesiraForteDsp(dc.Key, dc.Name, comm, props);
}
}
}
using System.Text.RegularExpressions;
namespace PepperDash.Essentials.Devices.Common.DSP
{
// QUESTIONS:
//
// When subscribing, just use the Instance ID for Custom Name?
// Verbose on subscriptions?
// Example subscription feedback responses
// ! "publishToken":"name" "value":-77.0
// ! "myLevelName" -77
public class BiampTesiraForteDsp : DspBase
{
public IBasicCommunication Communication { get; private set; }
public CommunicationGather PortGather { get; private set; }
public StatusMonitorBase CommunicationMonitor { get; private set; }
public new Dictionary<string, TesiraForteLevelControl> LevelControlPoints { get; private set; }
public bool isSubscribed;
private CTimer SubscriptionTimer;
private CrestronQueue CommandQueue;
private bool CommandQueueInProgress = false;
//new public Dictionary<string, DspControlPoint> DialerControlPoints { get; private set; }
//new public Dictionary<string, DspControlPoint> SwitcherControlPoints { get; private set; }
/// <summary>
/// Shows received lines as hex
/// </summary>
public bool ShowHexResponse { get; set; }
public BiampTesiraForteDsp(string key, string name, IBasicCommunication comm,
BiampTesiraFortePropertiesConfig props) :
base(key, name)
{
CommandQueue = new CrestronQueue(100);
Communication = comm;
var socket = comm as ISocketStatus;
if (socket != null)
{
// This instance uses IP control
socket.ConnectionChange += new EventHandler<GenericSocketStatusChageEventArgs>(socket_ConnectionChange);
}
else
{
// This instance uses RS-232 control
}
PortGather = new CommunicationGather(Communication, "\x0d\x0a");
PortGather.LineReceived += this.Port_LineReceived;
if (props.CommunicationMonitorProperties != null)
{
CommunicationMonitor = new GenericCommunicationMonitor(this, Communication,
props.CommunicationMonitorProperties);
}
else
{
//#warning Need to deal with this poll string
CommunicationMonitor = new GenericCommunicationMonitor(this, Communication, 120000, 120000, 300000,
"SESSION get aliases\x0d\x0a");
}
LevelControlPoints = new Dictionary<string, TesiraForteLevelControl>();
foreach (KeyValuePair<string, BiampTesiraForteLevelControlBlockConfig> block in props.LevelControlBlocks)
{
this.LevelControlPoints.Add(block.Key, new TesiraForteLevelControl(block.Key, block.Value, this));
}
}
public override bool CustomActivate()
{
Communication.Connect();
CommunicationMonitor.StatusChange +=
(o, a) => { Debug.Console(2, this, "Communication monitor state: {0}", CommunicationMonitor.Status); };
CommunicationMonitor.Start();
CrestronConsole.AddNewConsoleCommand(SendLine, "send" + Key, "", ConsoleAccessLevelEnum.AccessOperator);
CrestronConsole.AddNewConsoleCommand(s => Communication.Connect(), "con" + Key, "",
ConsoleAccessLevelEnum.AccessOperator);
return true;
}
private void socket_ConnectionChange(object sender, GenericSocketStatusChageEventArgs e)
{
Debug.Console(2, this, "Socket Status Change: {0}", e.Client.ClientStatus.ToString());
if (e.Client.IsConnected)
{
// Tasks on connect
}
else
{
// Cleanup items from this session
if (SubscriptionTimer != null)
{
SubscriptionTimer.Stop();
SubscriptionTimer = null;
}
isSubscribed = false;
CommandQueue.Clear();
CommandQueueInProgress = false;
}
}
/// <summary>
/// Initiates the subscription process to the DSP
/// </summary>
private void SubscribeToAttributes()
{
SendLine("SESSION set verbose true");
foreach (KeyValuePair<string, TesiraForteLevelControl> level in LevelControlPoints)
{
level.Value.Subscribe();
}
if (!CommandQueueInProgress)
SendNextQueuedCommand();
ResetSubscriptionTimer();
}
/// <summary>
/// Resets or Sets the subscription timer
/// </summary>
private void ResetSubscriptionTimer()
{
isSubscribed = true;
if (SubscriptionTimer != null)
{
SubscriptionTimer = new CTimer(o => SubscribeToAttributes(), 30000);
SubscriptionTimer.Reset();
}
}
/// <summary>
/// Handles a response message from the DSP
/// </summary>
/// <param name="dev"></param>
/// <param name="args"></param>
private void Port_LineReceived(object dev, GenericCommMethodReceiveTextArgs args)
{
if (Debug.Level == 2)
Debug.Console(2, this, "RX: '{0}'",
ShowHexResponse ? ComTextHelper.GetEscapedText(args.Text) : args.Text);
Debug.Console(1, this, "RX: '{0}'", args.Text);
try
{
if (args.Text.IndexOf("Welcome to the Tesira Text Protocol Server...") > -1)
{
// Indicates a new TTP session
SubscribeToAttributes();
}
else if (args.Text.IndexOf("publishToken") > -1)
{
// response is from a subscribed attribute
string pattern = "! \"publishToken\":[\"](.*)[\"] \"value\":(.*)";
Match match = Regex.Match(args.Text, pattern);
if (match.Success)
{
string key;
string customName;
string value;
customName = match.Groups[1].Value;
// Finds the key (everything before the '~' character
key = customName.Substring(0, customName.IndexOf("~", 0) - 1);
value = match.Groups[2].Value;
foreach (KeyValuePair<string, TesiraForteLevelControl> controlPoint in LevelControlPoints)
{
if (customName == controlPoint.Value.LevelCustomName ||
customName == controlPoint.Value.MuteCustomName)
{
controlPoint.Value.ParseSubscriptionMessage(customName, value);
return;
}
}
}
/// same for dialers
/// same for switchers
}
else if (args.Text.IndexOf("+OK") > -1)
{
if (args.Text == "+OK" || args.Text.IndexOf("list\":") > -1)
// Check for a simple "+OK" only 'ack' repsonse or a list response and ignore
return;
// response is not from a subscribed attribute. From a get/set/toggle/increment/decrement command
if (!CommandQueue.IsEmpty)
{
if (CommandQueue.Peek() is QueuedCommand)
{
// Expected response belongs to a child class
QueuedCommand tempCommand = (QueuedCommand) CommandQueue.TryToDequeue();
//Debug.Console(1, this, "Command Dequeued. CommandQueue Size: {0}", CommandQueue.Count);
tempCommand.ControlPoint.ParseGetMessage(tempCommand.AttributeCode, args.Text);
}
else
{
// Expected response belongs to this class
string temp = (string) CommandQueue.TryToDequeue();
//Debug.Console(1, this, "Command Dequeued. CommandQueue Size: {0}", CommandQueue.Count);
}
if (CommandQueue.IsEmpty)
CommandQueueInProgress = false;
else
SendNextQueuedCommand();
}
}
else if (args.Text.IndexOf("-ERR") > -1)
{
// Error response
switch (args.Text)
{
case "-ERR ALREADY_SUBSCRIBED":
{
ResetSubscriptionTimer();
break;
}
default:
{
Debug.Console(0, this, "Error From DSP: '{0}'", args.Text);
break;
}
}
}
}
catch (Exception e)
{
if (Debug.Level == 2)
Debug.Console(2, this, "Error parsing response: '{0}'\n{1}", args.Text, e);
}
}
/// <summary>
/// Sends a command to the DSP (with delimiter appended)
/// </summary>
/// <param name="s">Command to send</param>
public void SendLine(string s)
{
Debug.Console(1, this, "TX: '{0}'", s);
Communication.SendText(s + "\x0a");
}
/// <summary>
/// Adds a command from a child module to the queue
/// </summary>
/// <param name="command">Command object from child module</param>
public void EnqueueCommand(QueuedCommand commandToEnqueue)
{
CommandQueue.Enqueue(commandToEnqueue);
//Debug.Console(1, this, "Command (QueuedCommand) Enqueued '{0}'. CommandQueue has '{1}' Elements.", commandToEnqueue.Command, CommandQueue.Count);
if (!CommandQueueInProgress)
SendNextQueuedCommand();
}
/// <summary>
/// Adds a raw string command to the queue
/// </summary>
/// <param name="command"></param>
public void EnqueueCommand(string command)
{
CommandQueue.Enqueue(command);
//Debug.Console(1, this, "Command (string) Enqueued '{0}'. CommandQueue has '{1}' Elements.", command, CommandQueue.Count);
if (!CommandQueueInProgress)
SendNextQueuedCommand();
}
/// <summary>
/// Sends the next queued command to the DSP
/// </summary>
private void SendNextQueuedCommand()
{
//Debug.Console(2, this, "Attempting to send next queued command. CommandQueueInProgress: {0} Communication isConnected: {1}", CommandQueueInProgress, Communication.IsConnected);
//if (CommandQueue.IsEmpty)
// CommandQueueInProgress = false;
//Debug.Console(1, this, "CommandQueue has {0} Elements:\n", CommandQueue.Count);
//foreach (object o in CommandQueue)
//{
// if (o is string)
// Debug.Console(1, this, "{0}", o);
// else if(o is QueuedCommand)
// {
// var item = (QueuedCommand)o;
// Debug.Console(1, this, "{0}", item.Command);
// }
//}
//Debug.Console(1, this, "End of CommandQueue");
if (Communication.IsConnected && !CommandQueue.IsEmpty)
{
CommandQueueInProgress = true;
if (CommandQueue.Peek() is QueuedCommand)
{
QueuedCommand nextCommand = new QueuedCommand();
nextCommand = (QueuedCommand) CommandQueue.Peek();
SendLine(nextCommand.Command);
}
else
{
string nextCommand = (string) CommandQueue.Peek();
SendLine(nextCommand);
}
}
}
/// <summary>
/// Sends a command to execute a preset
/// </summary>
/// <param name="name">Preset Name</param>
public void RunPreset(string name)
{
SendLine(string.Format("DEVICE recallPreset {0}", name));
}
public class QueuedCommand
{
public string Command { get; set; }
public string AttributeCode { get; set; }
public TesiraForteControlPoint ControlPoint { get; set; }
}
}
public class BiampTesiraForteDspFactory : EssentialsDeviceFactory<BiampTesiraForteDsp>
{
public BiampTesiraForteDspFactory()
{
TypeNames = new List<string>() {"biamptesira"};
}
public override EssentialsDevice BuildDevice(DeviceConfig dc)
{
Debug.Console(1, "Factory Attempting to create new BiampTesira Device");
var comm = CommFactory.CreateCommForDevice(dc);
var props = Newtonsoft.Json.JsonConvert.DeserializeObject<BiampTesiraFortePropertiesConfig>(
dc.Properties.ToString());
return new BiampTesiraForteDsp(dc.Key, dc.Name, comm, props);
}
}
}

View File

@@ -15,18 +15,19 @@ namespace PepperDash.Essentials.Devices.Common.DSP
public Dictionary<string, DspControlPoint> DialerControlPoints { get; private set; }
public Dictionary<string, DspControlPoint> SwitcherControlPoints { get; private set; }
public abstract void RunPreset(string name);
public DspBase(string key, string name) :
base(key, name) { }
public Dictionary<string, DspControlPoint> SwitcherControlPoints { get; private set; }
public DspBase(string key, string name) :
base(key, name)
{
}
// in audio call feedback
// VOIP
// Phone dialer
// Phone dialer
}
// Fusion

View File

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

View File

@@ -2103,6 +2103,7 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.Cisco
public override EssentialsDevice BuildDevice(DeviceConfig dc)
{
Debug.Console(1, "Factory Attempting to create new Cisco Codec Device");
var comm = CommFactory.CreateCommForDevice(dc);
return new VideoCodec.Cisco.CiscoSparkCodec(dc, comm);
}

View File

@@ -0,0 +1,14 @@
using PepperDash.Essentials.Core;
using PepperDash.Essentials.Devices.Common.VideoCodec.Cisco;
namespace PepperDash.Essentials.Core.DeviceTypeInterfaces
{
public interface IHasSelfviewPosition
{
StringFeedback SelfviewPipPositionFeedback { get; }
void SelfviewPipPositionSet(CodecCommandWithLabel position);
void SelfviewPipPositionToggle();
}
}

View File

@@ -13,11 +13,13 @@ using PepperDash.Essentials.Core;
using PepperDash.Essentials.Core.Bridges;
using PepperDash.Essentials.Core.Config;
using PepperDash.Essentials.Core.Devices;
using PepperDash.Essentials.Core.DeviceTypeInterfaces;
using PepperDash.Essentials.Core.Routing;
using PepperDash.Essentials.Devices.Common.Cameras;
using PepperDash.Essentials.Devices.Common.Codec;
using PepperDash.Essentials.Devices.Common.VideoCodec.Interfaces;
using PepperDash_Essentials_Core.Bridges.JoinMaps;
using PepperDash_Essentials_Core.DeviceTypeInterfaces;
using Feedback = PepperDash.Essentials.Core.Feedback;
namespace PepperDash.Essentials.Devices.Common.VideoCodec
@@ -60,9 +62,9 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec
public List<CodecActiveCallItem> ActiveCalls { get; set; }
public bool ShowSelfViewByDefault { get; protected set; }
protected bool SupportsCameraOff;
public bool ShowSelfViewByDefault { get; protected set; }
protected bool SupportsCameraOff;
protected bool SupportsCameraAutoMode;
public bool IsReady { get; protected set; }
@@ -198,7 +200,7 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec
/// <param name="previousStatus"></param>
/// <param name="newStatus"></param>
/// <param name="item"></param>
protected void OnCallStatusChange(CodecActiveCallItem item)
protected virtual void OnCallStatusChange(CodecActiveCallItem item)
{
var handler = CallStatusChange;
if (handler != null)
@@ -309,12 +311,12 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec
{
trilist.SetBool(joinMap.CameraSupportsAutoMode.JoinNumber, SupportsCameraAutoMode);
LinkVideoCodecCameraModeToApi(codec as IHasCameraAutoMode, trilist, joinMap);
}
if (codec is IHasCameraOff)
{
trilist.SetBool(joinMap.CameraSupportsOffMode.JoinNumber, SupportsCameraOff);
LinkVideoCodecCameraOffToApi(codec as IHasCameraOff, trilist, joinMap);
}
if (codec is IHasCameraOff)
{
trilist.SetBool(joinMap.CameraSupportsOffMode.JoinNumber, SupportsCameraOff);
LinkVideoCodecCameraOffToApi(codec as IHasCameraOff, trilist, joinMap);
}
if (codec is IHasCodecLayouts)
@@ -322,6 +324,11 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec
LinkVideoCodecCameraLayoutsToApi(codec as IHasCodecLayouts, trilist, joinMap);
}
if (codec is IHasSelfviewPosition)
{
LinkVideoCodecSelfviewPositionToApi(codec as IHasSelfviewPosition, trilist, joinMap);
}
if (codec is IHasDirectory)
{
LinkVideoCodecDirectoryToApi(codec as IHasDirectory, trilist, joinMap);
@@ -337,6 +344,16 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec
LinkVideoCodecParticipantsToApi(codec as IHasParticipants, trilist, joinMap);
}
if (codec is IHasFarEndContentStatus)
{
(codec as IHasFarEndContentStatus).ReceivingContent.LinkInputSig(trilist.BooleanInput[joinMap.RecievingContent.JoinNumber]);
}
if (codec is IHasPhoneDialing)
{
LinkVideoCodecPhoneToApi(codec as IHasPhoneDialing, trilist, joinMap);
}
trilist.OnlineStatusChange += (device, args) =>
{
if (!args.DeviceOnLine) return;
@@ -360,27 +377,96 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec
{
trilist.SetBool(joinMap.CameraSupportsAutoMode.JoinNumber, true);
(codec as IHasCameraAutoMode).CameraAutoModeIsOnFeedback.InvokeFireUpdate();
(codec as IHasCameraAutoMode).CameraAutoModeIsOnFeedback.FireUpdate();
}
if (codec is IHasCodecSelfView)
{
(codec as IHasCodecSelfView).SelfviewIsOnFeedback.InvokeFireUpdate();
(codec as IHasCodecSelfView).SelfviewIsOnFeedback.FireUpdate();
}
SharingContentIsOnFeedback.InvokeFireUpdate();
if (codec is IHasCameraAutoMode)
{
(codec as IHasCameraAutoMode).CameraAutoModeIsOnFeedback.FireUpdate();
}
UpdateCallStatusXSig();
if (codec is IHasCameraOff)
{
(codec as IHasCameraOff).CameraIsOffFeedback.FireUpdate();
}
if (codec is IHasPhoneDialing)
{
(codec as IHasPhoneDialing).PhoneOffHookFeedback.FireUpdate();
}
SharingContentIsOnFeedback.FireUpdate();
trilist.SetBool(joinMap.HookState.JoinNumber, IsInCall);
trilist.SetString(joinMap.CurrentCallData.JoinNumber, UpdateCallStatusXSig());
};
}
private void LinkVideoCodecCameraOffToApi(IHasCameraOff codec, BasicTriList trilist, VideoCodecControllerJoinMap joinMap)
{
codec.CameraIsOffFeedback.LinkInputSig(trilist.BooleanInput[joinMap.CameraModeOff.JoinNumber]);
trilist.SetSigFalseAction(joinMap.CameraModeOff.JoinNumber, codec.CameraOff);
}
}
private void LinkVideoCodecPhoneToApi(IHasPhoneDialing codec, BasicTriList trilist, VideoCodecControllerJoinMap joinMap)
{
codec.PhoneOffHookFeedback.LinkInputSig(trilist.BooleanInput[joinMap.PhoneHookState.JoinNumber]);
trilist.SetSigFalseAction(joinMap.DialPhone.JoinNumber,
() => codec.DialPhoneCall(trilist.StringOutput[joinMap.PhoneDialString.JoinNumber].StringValue));
trilist.SetSigFalseAction(joinMap.HangUpPhone.JoinNumber, codec.EndPhoneCall);
}
private void LinkVideoCodecSelfviewPositionToApi(IHasSelfviewPosition codec, BasicTriList trilist, VideoCodecControllerJoinMap joinMap)
{
trilist.SetSigFalseAction(joinMap.SelfviewPosition.JoinNumber, codec.SelfviewPipPositionToggle);
codec.SelfviewPipPositionFeedback.LinkInputSig(trilist.StringInput[joinMap.SelfviewPositionFb.JoinNumber]);
}
private void LinkVideoCodecCameraOffToApi(IHasCameraOff codec, BasicTriList trilist, VideoCodecControllerJoinMap joinMap)
{
trilist.SetSigFalseAction(joinMap.CameraModeOff.JoinNumber, codec.CameraOff);
codec.CameraIsOffFeedback.OutputChange += (o, a) =>
{
if (a.BoolValue)
{
trilist.SetBool(joinMap.CameraModeOff.JoinNumber, true);
trilist.SetBool(joinMap.CameraModeManual.JoinNumber, false);
trilist.SetBool(joinMap.CameraModeAuto.JoinNumber, false);
return;
}
trilist.SetBool(joinMap.CameraModeOff.JoinNumber, false);
var autoCodec = codec as IHasCameraAutoMode;
if (autoCodec == null) return;
trilist.SetBool(joinMap.CameraModeAuto.JoinNumber, autoCodec.CameraAutoModeIsOnFeedback.BoolValue);
trilist.SetBool(joinMap.CameraModeManual.JoinNumber, !autoCodec.CameraAutoModeIsOnFeedback.BoolValue);
};
if (codec.CameraIsOffFeedback.BoolValue)
{
trilist.SetBool(joinMap.CameraModeOff.JoinNumber, true);
trilist.SetBool(joinMap.CameraModeManual.JoinNumber, false);
trilist.SetBool(joinMap.CameraModeAuto.JoinNumber, false);
return;
}
trilist.SetBool(joinMap.CameraModeOff.JoinNumber, false);
var autoModeCodec = codec as IHasCameraAutoMode;
if (autoModeCodec == null) return;
trilist.SetBool(joinMap.CameraModeAuto.JoinNumber, autoModeCodec.CameraAutoModeIsOnFeedback.BoolValue);
trilist.SetBool(joinMap.CameraModeManual.JoinNumber, !autoModeCodec.CameraAutoModeIsOnFeedback.BoolValue);
}
private void LinkVideoCodecVolumeToApi(BasicTriList trilist, VideoCodecControllerJoinMap joinMap)
{
MuteFeedback.LinkInputSig(trilist.BooleanInput[joinMap.VolumeMuteOn.JoinNumber]);
@@ -419,6 +505,7 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec
codec.Participants.ParticipantsListHasChanged += (sender, args) =>
{
string participantsXSig;
if (codec.Participants.CurrentParticipants.Count == 0)
{
participantsXSig = Encoding.GetEncoding(XSigEncoding).GetString(_clearBytes, 0, _clearBytes.Length);
@@ -427,10 +514,6 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec
return;
}
participantsXSig = Encoding.GetEncoding(XSigEncoding).GetString(_clearBytes, 0, _clearBytes.Length);
trilist.SetString(joinMap.CurrentParticipants.JoinNumber, participantsXSig);
participantsXSig = UpdateParticipantsXSig(codec.Participants.CurrentParticipants);
trilist.SetString(joinMap.CurrentParticipants.JoinNumber, participantsXSig);
@@ -441,7 +524,7 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec
private string UpdateParticipantsXSig(List<Participant> currentParticipants)
{
const int maxParticipants = 255;
const int maxParticipants = 50;
const int maxDigitals = 5;
const int maxStrings = 1;
const int offset = maxDigitals + maxStrings;
@@ -453,7 +536,7 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec
foreach (var participant in currentParticipants)
{
if (meetingIndex > maxParticipants * offset) break;
if (meetingIndex >= maxParticipants * offset) break;
//digitals
tokenArray[digitalIndex] = new XSigDigitalToken(digitalIndex + 1, participant.AudioMuteFb);
@@ -469,6 +552,22 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec
meetingIndex += offset;
stringIndex += maxStrings;
}
while (meetingIndex < maxParticipants*offset)
{
tokenArray[digitalIndex] = new XSigDigitalToken(digitalIndex + 1, false);
tokenArray[digitalIndex + 1] = new XSigDigitalToken(digitalIndex + 2, false);
tokenArray[digitalIndex + 2] = new XSigDigitalToken(digitalIndex + 3, false);
tokenArray[digitalIndex + 3] = new XSigDigitalToken(digitalIndex + 4, false);
tokenArray[digitalIndex + 4] = new XSigDigitalToken(digitalIndex + 5, false);
//serials
tokenArray[stringIndex] = new XSigSerialToken(stringIndex + 1, String.Empty);
digitalIndex += maxDigitals;
meetingIndex += offset;
stringIndex += maxStrings;
}
return GetXSigString(tokenArray);
}
@@ -517,12 +616,20 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec
trilist.SetString(joinMap.Schedule.JoinNumber, meetingsData);
trilist.SetSigFalseAction(joinMap.DialMeeting.JoinNumber, () =>
trilist.SetSigFalseAction(joinMap.DialMeeting1.JoinNumber, () =>
{
if (codec.CodecSchedule.Meetings[0].Joinable)
{
if(codec.CodecSchedule.Meetings[0] != null)
Dial(codec.CodecSchedule.Meetings[0]);
}
});
trilist.SetSigFalseAction(joinMap.DialMeeting2.JoinNumber, () =>
{
if (codec.CodecSchedule.Meetings[1] != null)
Dial(codec.CodecSchedule.Meetings[1]);
});
trilist.SetSigFalseAction(joinMap.DialMeeting3.JoinNumber, () =>
{
if (codec.CodecSchedule.Meetings[2] != null)
Dial(codec.CodecSchedule.Meetings[2]);
});
trilist.SetUshort(joinMap.MeetingCount.JoinNumber, (ushort)currentMeetings.Count);
@@ -600,11 +707,11 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec
tokenArray[stringIndex + 3] = new XSigSerialToken(stringIndex + 4, String.Empty);
tokenArray[stringIndex + 4] = new XSigSerialToken(stringIndex + 5, String.Empty);
tokenArray[stringIndex + 5] = new XSigSerialToken(stringIndex + 6, String.Empty);
tokenArray[stringIndex + 6] = new XSigSerialToken(stringIndex + 7, String.Empty);
digitalIndex += maxDigitals;
meetingIndex += offset;
stringIndex += maxStrings;
tokenArray[stringIndex + 6] = new XSigSerialToken(stringIndex + 7, String.Empty);
digitalIndex += maxDigitals;
meetingIndex += offset;
stringIndex += maxStrings;
}
return GetXSigString(tokenArray);
@@ -700,11 +807,15 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec
//End All calls for now
trilist.SetSigFalseAction(joinMap.EndCall.JoinNumber, EndAllCalls);
trilist.SetBool(joinMap.HookState.JoinNumber, IsInCall);
CallStatusChange += (sender, args) =>
{
trilist.SetBool(joinMap.HookState.JoinNumber, IsInCall);
trilist.SetBool(joinMap.IncomingCall.JoinNumber, args.CallItem.Direction == eCodecCallDirection.Incoming);
Debug.Console(1, this, "Call Direction: {0}", args.CallItem.Direction);
Debug.Console(1, this, "Call is incoming: {0}", args.CallItem.Direction == eCodecCallDirection.Incoming);
trilist.SetBool(joinMap.IncomingCall.JoinNumber, args.CallItem.Direction == eCodecCallDirection.Incoming && args.CallItem.Status != eCodecCallStatus.Disconnected);
if (args.CallItem.Direction == eCodecCallDirection.Incoming)
{
@@ -712,9 +823,7 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec
trilist.SetSigFalseAction(joinMap.IncomingReject.JoinNumber, () => RejectCall(args.CallItem));
}
var callStatusXsig = UpdateCallStatusXSig();
trilist.SetString(joinMap.CurrentCallData.JoinNumber, callStatusXsig);
trilist.SetString(joinMap.CurrentCallData.JoinNumber, UpdateCallStatusXSig());
};
}
@@ -723,26 +832,44 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec
const int maxCalls = 8;
const int maxStrings = 5;
const int offset = 6;
var callIndex = 0;
var digitalIndex = maxStrings*maxCalls;
var tokenArray = new XSigToken[ActiveCalls.Count*offset]; //set array size for number of calls * pieces of info
var stringIndex = 0;
var digitalIndex = maxStrings * maxCalls;
var arrayIndex = 0;
var tokenArray = new XSigToken[maxCalls*offset]; //set array size for number of calls * pieces of info
foreach (var call in ActiveCalls)
{
var arrayIndex = callIndex;
if (arrayIndex >= maxCalls * offset)
break;
//digitals
tokenArray[arrayIndex] = new XSigDigitalToken(digitalIndex + 1, call.IsActiveCall);
//serials
tokenArray[arrayIndex + 1] = new XSigSerialToken(callIndex + 1, call.Name ?? String.Empty);
tokenArray[arrayIndex + 2] = new XSigSerialToken(callIndex + 2, call.Number ?? String.Empty);
tokenArray[arrayIndex + 3] = new XSigSerialToken(callIndex + 3, call.Direction.ToString());
tokenArray[arrayIndex + 4] = new XSigSerialToken(callIndex + 4, call.Type.ToString());
tokenArray[arrayIndex + 5] = new XSigSerialToken(callIndex + 5, call.Status.ToString());
tokenArray[arrayIndex + 1] = new XSigSerialToken(stringIndex + 1, call.Name ?? String.Empty);
tokenArray[arrayIndex + 2] = new XSigSerialToken(stringIndex + 2, call.Number ?? String.Empty);
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());
callIndex += offset;
arrayIndex += offset;
stringIndex += maxStrings;
digitalIndex++;
}
while (digitalIndex < maxCalls)
{
//digitals
tokenArray[arrayIndex] = new XSigDigitalToken(digitalIndex + 1, false);
//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);
arrayIndex += offset;
stringIndex += maxStrings;
digitalIndex++;
}
@@ -776,14 +903,55 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec
{
trilist.SetSigFalseAction(joinMap.CameraModeAuto.JoinNumber, codec.CameraAutoModeOn);
trilist.SetSigFalseAction(joinMap.CameraModeManual.JoinNumber, codec.CameraAutoModeOff);
codec.CameraAutoModeIsOnFeedback.LinkInputSig(trilist.BooleanInput[joinMap.CameraModeAuto.JoinNumber]);
codec.CameraAutoModeIsOnFeedback.LinkComplementInputSig(
trilist.BooleanInput[joinMap.CameraModeManual.JoinNumber]);
codec.CameraAutoModeIsOnFeedback.OutputChange += (o, a) =>
{
var offCodec = codec as IHasCameraOff;
if (offCodec != null)
{
if (offCodec.CameraIsOffFeedback.BoolValue)
{
trilist.SetBool(joinMap.CameraModeAuto.JoinNumber, false);
trilist.SetBool(joinMap.CameraModeManual.JoinNumber, false);
trilist.SetBool(joinMap.CameraModeOff.JoinNumber, true);
return;
}
trilist.SetBool(joinMap.CameraModeAuto.JoinNumber, a.BoolValue);
trilist.SetBool(joinMap.CameraModeManual.JoinNumber, !a.BoolValue);
trilist.SetBool(joinMap.CameraModeOff.JoinNumber, false);
return;
}
trilist.SetBool(joinMap.CameraModeAuto.JoinNumber, a.BoolValue);
trilist.SetBool(joinMap.CameraModeManual.JoinNumber, !a.BoolValue);
trilist.SetBool(joinMap.CameraModeOff.JoinNumber, false);
};
var offModeCodec = codec as IHasCameraOff;
if (offModeCodec != null)
{
if (offModeCodec.CameraIsOffFeedback.BoolValue)
{
trilist.SetBool(joinMap.CameraModeAuto.JoinNumber, false);
trilist.SetBool(joinMap.CameraModeManual.JoinNumber, false);
trilist.SetBool(joinMap.CameraModeOff.JoinNumber, true);
return;
}
trilist.SetBool(joinMap.CameraModeAuto.JoinNumber, codec.CameraAutoModeIsOnFeedback.BoolValue);
trilist.SetBool(joinMap.CameraModeManual.JoinNumber, !codec.CameraAutoModeIsOnFeedback.BoolValue);
trilist.SetBool(joinMap.CameraModeOff.JoinNumber, false);
return;
}
trilist.SetBool(joinMap.CameraModeAuto.JoinNumber, codec.CameraAutoModeIsOnFeedback.BoolValue);
trilist.SetBool(joinMap.CameraModeManual.JoinNumber, !codec.CameraAutoModeIsOnFeedback.BoolValue);
trilist.SetBool(joinMap.CameraModeOff.JoinNumber, false);
}
private void LinkVideoCodecSelfviewToApi(IHasCodecSelfView codec, BasicTriList trilist,
VideoCodecControllerJoinMap joinMap)
{
@@ -871,8 +1039,6 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec
{
var i = (ushort) codec.Cameras.FindIndex((c) => c.Key == args.SelectedCamera.Key);
trilist.SetUshort(joinMap.CameraPresetSelect.JoinNumber, i);
if (codec is IHasCodecRoomPresets)
{
return;
@@ -887,24 +1053,58 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec
SetCameraPresetNames(cam.Presets);
(args.SelectedCamera as IHasCameraPresets).PresetsListHasChanged += (o, eventArgs) => SetCameraPresetNames(cam.Presets);
trilist.SetUShortSigAction(joinMap.CameraPresetSelect.JoinNumber,
(a) =>
{
cam.PresetSelect(a);
trilist.SetUshort(joinMap.CameraPresetSelect.JoinNumber, a);
});
trilist.SetSigFalseAction(joinMap.CameraPresetSave.JoinNumber,
() =>
{
cam.PresetStore(trilist.UShortOutput[joinMap.CameraPresetSelect.JoinNumber].UShortValue,
String.Empty);
trilist.PulseBool(joinMap.CameraPresetSave.JoinNumber, 3000);
});
};
if (!(codec is IHasCodecRoomPresets)) return;
var presetCodec = codec as IHasCodecRoomPresets;
presetCodec.CodecRoomPresetsListHasChanged +=
(sender, args) => SetCameraPresetNames(presetCodec.NearEndPresets);
//Camera Presets
trilist.SetUShortSigAction(joinMap.CameraPresetSelect.JoinNumber, (i) =>
{
if (codec.SelectedCamera == null) return;
var cam = codec.SelectedCamera as IHasCameraPresets;
if (cam == null) return;
cam.PresetSelect(i);
presetCodec.CodecRoomPresetSelect(i);
trilist.SetUshort(joinMap.CameraPresetSelect.JoinNumber, i);
});
trilist.SetSigFalseAction(joinMap.CameraPresetSave.JoinNumber,
() =>
{
presetCodec.CodecRoomPresetStore(
trilist.UShortOutput[joinMap.CameraPresetSelect.JoinNumber].UShortValue, String.Empty);
trilist.PulseBool(joinMap.CameraPresetSave.JoinNumber, 3000);
});
}
private string SetCameraPresetNames(List<CameraPreset> presets)
private string SetCameraPresetNames(IEnumerable<CodecRoomPreset> presets)
{
return SetCameraPresetNames(presets.Select(p => p.Description).ToList());
}
private string SetCameraPresetNames(IEnumerable<CameraPreset> presets)
{
return SetCameraPresetNames(presets.Select(p => p.Description).ToList());
}
private string SetCameraPresetNames(ICollection<string> presets)
{
var i = 1; //start index for xsig;
@@ -912,7 +1112,7 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec
foreach (var preset in presets)
{
var cameraPreset = new XSigSerialToken(i, preset.Description);
var cameraPreset = new XSigSerialToken(i, preset);
tokenArray[i - 1] = cameraPreset;
i++;
}

View File

@@ -58,6 +58,7 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.ZoomRoom
public List<zStatus.AudioVideoInputOutputLineItem> AudioInputs { get; set; }
public List<zStatus.AudioVideoInputOutputLineItem> AudioOuputs { get; set; }
public List<zStatus.AudioVideoInputOutputLineItem> Cameras { get; set; }
public zEvent.PhoneCallStatus PhoneCall { get; set; }
public ZoomRoomStatus()
{
@@ -74,6 +75,7 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.ZoomRoom
AudioInputs = new List<zStatus.AudioVideoInputOutputLineItem>();
AudioOuputs = new List<zStatus.AudioVideoInputOutputLineItem>();
Cameras = new List<zStatus.AudioVideoInputOutputLineItem>();
PhoneCall = new zEvent.PhoneCallStatus();
}
}
@@ -370,7 +372,20 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.ZoomRoom
public CallRecordInfo CallRecordInfo { get; set; }
public zCommand.InfoResult Info { get; set; }
private zCommand.InfoResult _info;
public zCommand.InfoResult Info
{
get
{
return _info;
}
set
{
_info = value;
NotifyPropertyChanged("Info");
}
}
public Call()
{
@@ -687,6 +702,86 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.ZoomRoom
[JsonProperty("why_cannot_pin_share")]
public string WhyCannotPinShare { get; set; }
}
public class PhoneCallStatus:NotifiableObject
{
private bool _isIncomingCall;
private string _peerDisplayName;
private string _peerNumber;
private bool _offHook;
public string CallId { get; set; }
public bool IsIncomingCall {
get { return _isIncomingCall; }
set
{
if(value == _isIncomingCall) return;
_isIncomingCall = value;
NotifyPropertyChanged("IsIncomingCall");
} }
public string PeerDisplayName
{
get { return _peerDisplayName; }
set
{
if (value == _peerDisplayName) return;
_peerDisplayName = value;
NotifyPropertyChanged("PeerDisplayName");
}
}
public string PeerNumber
{
get { return _peerNumber; }
set
{
if (value == _peerNumber) return;
_peerNumber = value;
NotifyPropertyChanged("PeerNumber");
}
}
public string PeerUri { get; set; }
private ePhoneCallStatus _status;
public ePhoneCallStatus Status
{
get { return _status; }
set
{
_status = value;
OffHook = _status == ePhoneCallStatus.PhoneCallStatus_Accepted ||
_status == ePhoneCallStatus.PhoneCallStatus_InCall ||
_status == ePhoneCallStatus.PhoneCallStatus_Init ||
_status == ePhoneCallStatus.PhoneCallStatus_Ringing;
}
}
public bool OffHook
{
get { return _offHook; }
set
{
if (value == _offHook) return;
_offHook = value;
NotifyPropertyChanged("OffHook");
}
}
}
public enum ePhoneCallStatus
{
PhoneCallStatus_Ringing,
PhoneCallStatus_Terminated,
PhoneCallStatus_Accepted,
PhoneCallStatus_InCall,
PhoneCallStatus_Init,
}
}
/// <summary>
@@ -706,17 +801,15 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.ZoomRoom
public bool Mute
{
get
{
return _mute;
}
get { return _mute; }
set
{
if (value != _mute)
{
_mute = value;
NotifyPropertyChanged("Mute");
}
Debug.Console(1, "Camera Mute response received: {0}", value);
if (value == _mute) return;
_mute = value;
NotifyPropertyChanged("Mute");
}
}
}
@@ -772,12 +865,20 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.ZoomRoom
DownLeft
}
public class Layout
public class Layout:NotifiableObject
{
public bool ShareThumb { get; set; }
public eLayoutStyle Style { get; set; }
public eLayoutSize Size { get; set; }
public eLayoutPosition Position { get; set; }
private eLayoutPosition _position;
public eLayoutPosition Position {
get { return _position; }
set
{
_position = value;
NotifyPropertyChanged("Position");
} }
}
public class Lock

View File

@@ -11,16 +11,20 @@ using PepperDash.Core;
using PepperDash.Essentials.Core;
using PepperDash.Essentials.Core.Bridges;
using PepperDash.Essentials.Core.Config;
using PepperDash.Essentials.Core.DeviceTypeInterfaces;
using PepperDash.Essentials.Core.Routing;
using PepperDash.Essentials.Devices.Common.Cameras;
using PepperDash.Essentials.Devices.Common.Codec;
using PepperDash.Essentials.Devices.Common.VideoCodec.Cisco;
using PepperDash.Essentials.Devices.Common.VideoCodec.Interfaces;
using PepperDash_Essentials_Core.DeviceTypeInterfaces;
namespace PepperDash.Essentials.Devices.Common.VideoCodec.ZoomRoom
{
public class ZoomRoom : VideoCodecBase, IHasCodecSelfView, IHasDirectoryHistoryStack, ICommunicationMonitor,
IRouting,
IHasScheduleAwareness, IHasCodecCameras, IHasParticipants, IHasCameraOff, IHasCameraAutoMode
IHasScheduleAwareness, IHasCodecCameras, IHasParticipants, IHasCameraOff, IHasCameraAutoMode,
IHasFarEndContentStatus, IHasSelfviewPosition, IHasPhoneDialing
{
private const long MeetingRefreshTimer = 60000;
private const uint DefaultMeetingDurationMin = 30;
@@ -98,6 +102,10 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.ZoomRoom
CodecSchedule = new CodecScheduleAwareness(MeetingRefreshTimer);
ReceivingContent = new BoolFeedback(FarEndIsSharingContentFeedbackFunc);
SelfviewPipPositionFeedback = new StringFeedback(SelfviewPipPositionFeedbackFunc);
SetUpFeedbackActions();
Cameras = new List<CameraBase>();
@@ -108,6 +116,10 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.ZoomRoom
SupportsCameraOff = _props.SupportsCameraOff;
SupportsCameraAutoMode = _props.SupportsCameraAutoMode;
PhoneOffHookFeedback = new BoolFeedback(PhoneOffHookFeedbackFunc);
CallerIdNameFeedback = new StringFeedback(CallerIdNameFeedbackFunc);
CallerIdNumberFeedback = new StringFeedback(CallerIdNumberFeedbackFunc);
}
public CommunicationGather PortGather { get; private set; }
@@ -152,7 +164,7 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.ZoomRoom
protected Func<bool> FarEndIsSharingContentFeedbackFunc
{
get { return () => false; }
get { return () => Status.Call.Sharing.State == zEvent.eSharingState.Receiving; }
}
protected override Func<bool> MuteFeedbackFunc
@@ -183,17 +195,17 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.ZoomRoom
protected Func<bool> CameraIsOffFeedbackFunc
{
get { return () => Configuration.Camera.Mute; }
get { return () => Configuration.Call.Camera.Mute; }
}
protected Func<bool> CameraAutoModeIsOnFeedbackFunc
{
get { return () => !Configuration.Camera.Mute; }
}
get { return () => false; }
}
protected Func<string> SelfviewPipPositionFeedbackFunc
{
get { return () => ""; }
get { return () => _currentSelfviewPipPosition.Command; }
}
protected Func<string> LocalLayoutFeedbackFunc
@@ -393,6 +405,26 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.ZoomRoom
SetIsReady();
}
private void SetUpCallFeedbackActions()
{
Status.Call.Sharing.PropertyChanged += (o, a) =>
{
if (a.PropertyName == "State")
{
SharingContentIsOnFeedback.FireUpdate();
ReceivingContent.FireUpdate();
}
};
Status.Call.PropertyChanged += (o, a) =>
{
if (a.PropertyName == "Info")
{
Debug.Console(1, this, "Updating Call Status");
UpdateCallStatus();
}
};
}
/// <summary>
/// Subscribes to the PropertyChanged events on the state objects and fires the corresponding feedbacks.
@@ -432,11 +464,23 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.ZoomRoom
}
};
Configuration.Camera.PropertyChanged += (o, a) =>
Configuration.Call.Camera.PropertyChanged += (o, a) =>
{
Debug.Console(1, this, "Configuration.Call.Camera.PropertyChanged: {0}", a.PropertyName);
if (a.PropertyName != "Mute") return;
CameraIsOffFeedback.FireUpdate();
CameraAutoModeIsOnFeedback.FireUpdate();
};
Configuration.Call.Layout.PropertyChanged += (o, a) =>
{
if (a.PropertyName != "Position") return;
ComputeSelfviewPipStatus();
SelfviewPipPositionFeedback.FireUpdate();
};
Status.Call.Sharing.PropertyChanged += (o, a) =>
@@ -444,6 +488,16 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.ZoomRoom
if (a.PropertyName == "State")
{
SharingContentIsOnFeedback.FireUpdate();
ReceivingContent.FireUpdate();
}
};
Status.Call.PropertyChanged += (o, a) =>
{
if (a.PropertyName == "Info")
{
Debug.Console(1, this, "Updating Call Status");
UpdateCallStatus();
}
};
@@ -458,6 +512,28 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.ZoomRoom
break;
}
};
Status.PhoneCall.PropertyChanged += (o, a) =>
{
switch (a.PropertyName)
{
case "IsIncomingCall":
Debug.Console(1, this, "Incoming Phone Call: {0}", Status.PhoneCall.IsIncomingCall);
break;
case "PeerDisplayName":
Debug.Console(1, this, "Peer Display Name: {0}", Status.PhoneCall.PeerDisplayName);
CallerIdNameFeedback.FireUpdate();
break;
case "PeerNumber":
Debug.Console(1, this, "Peer Number: {0}", Status.PhoneCall.PeerNumber);
CallerIdNumberFeedback.FireUpdate();
break;
case "OffHook":
Debug.Console(1, this, "Phone is OffHook: {0}", Status.PhoneCall.OffHook);
PhoneOffHookFeedback.FireUpdate();
break;
}
};
}
private void SetUpDirectory()
@@ -504,9 +580,13 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.ZoomRoom
{
CrestronConsole.AddNewConsoleCommand(SetCommDebug, "SetCodecCommDebug", "0 for Off, 1 for on",
ConsoleAccessLevelEnum.AccessOperator);
CrestronConsole.AddNewConsoleCommand(s => SendText("zCommand Phonebook List Offset: 0 Limit: 512"),
"GetZoomRoomContacts", "Triggers a refresh of the codec phonebook",
ConsoleAccessLevelEnum.AccessOperator);
if (!_props.DisablePhonebookAutoDownload)
{
CrestronConsole.AddNewConsoleCommand(s => SendText("zCommand Phonebook List Offset: 0 Limit: 512"),
"GetZoomRoomContacts", "Triggers a refresh of the codec phonebook",
ConsoleAccessLevelEnum.AccessOperator);
}
CrestronConsole.AddNewConsoleCommand(s => GetBookings(), "GetZoomRoomBookings",
"Triggers a refresh of the booking data for today", ConsoleAccessLevelEnum.AccessOperator);
@@ -657,6 +737,8 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.ZoomRoom
}
_syncState.AddQueryToQueue("zCommand Bookings List");
_syncState.AddQueryToQueue("zCommand Call ListParticipants");
_syncState.AddQueryToQueue("zCommand Call Info");
_syncState.StartSync();
@@ -669,6 +751,14 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.ZoomRoom
private void ProcessMessage(string message)
{
// Counts the curly braces
if (message.Contains("client_loop: send disconnect: Broken pipe"))
{
Debug.Console(0, this, Debug.ErrorLogLevel.Error,
"Zoom Room Controller or App connected. Essentials will NOT control the Zoom Room until it is disconnected.");
return;
}
if (message.Contains('{'))
{
_jsonCurlyBraceCounter++;
@@ -757,6 +847,11 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.ZoomRoom
Thread.Sleep(100);
SendText("zFeedback Register Op: ex Path: /Event/InfoResult/info/callout_country_list");
Thread.Sleep(100);
if (!_props.DisablePhonebookAutoDownload)
{
SendText("zFeedback Register Op: ex Path: /Event/Phonebook/AddedContact");
}
// switch to json format
SendText("format json");
});
@@ -835,6 +930,11 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.ZoomRoom
{
switch (topKey.ToLower())
{
case "inforesult":
{
JsonConvert.PopulateObject(responseObj.ToString(), Status.Call.Info);
break;
}
case "phonebooklistresult":
{
JsonConvert.PopulateObject(responseObj.ToString(), Status.Phonebook);
@@ -995,6 +1095,8 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.ZoomRoom
{
JsonConvert.PopulateObject(responseObj.ToString(), Status.Call.Sharing);
SetLayout();
break;
}
case "incomingcallindication":
@@ -1107,6 +1209,11 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.ZoomRoom
break;
}
case "phonecallstatus":
{
JsonConvert.PopulateObject(responseObj.ToString(), Status.PhoneCall);
break;
}
default:
{
break;
@@ -1218,6 +1325,24 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.ZoomRoom
}
}
private void SetLayout()
{
if (!_props.AutoDefaultLayouts) return;
if (
(Status.Call.Sharing.State == zEvent.eSharingState.Receiving ||
Status.Call.Sharing.State == zEvent.eSharingState.Sending))
{
SendText(String.Format("zconfiguration call layout style: {0}",
_props.DefaultSharingLayout));
}
else
{
SendText(String.Format("zconfiguration call layout style: {0}",
_props.DefaultCallLayout));
}
}
public void PrintCurrentCallParticipants()
{
if (Debug.Level <= 0)
@@ -1256,13 +1381,28 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.ZoomRoom
if (callStatus != zStatus.eCallStatus.IN_MEETING || callStatus != zStatus.eCallStatus.CONNECTING_MEETING)
{
Status.Call = new zStatus.Call {Status = callStatus};
SetUpCallFeedbackActions();
}
if (ActiveCalls.Count == 0)
{
if (callStatus == zStatus.eCallStatus.CONNECTING_MEETING)
if (callStatus == zStatus.eCallStatus.CONNECTING_MEETING ||
callStatus == zStatus.eCallStatus.IN_MEETING)
{
var newCall = new CodecActiveCallItem {Status = eCodecCallStatus.Connecting};
var newStatus = eCodecCallStatus.Unknown;
switch (callStatus)
{
case zStatus.eCallStatus.CONNECTING_MEETING:
newStatus = eCodecCallStatus.Connecting;
break;
case zStatus.eCallStatus.IN_MEETING:
newStatus = eCodecCallStatus.Connected;
break;
}
var newCall = new CodecActiveCallItem {Status = newStatus};
ActiveCalls.Add(newCall);
@@ -1307,13 +1447,28 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.ZoomRoom
ActiveCalls.Remove(call);
}
}
Debug.Console(1, this, "**************************************************************************");
//clear participants list after call cleanup
if (ActiveCalls.Count == 0)
{
Participants.CurrentParticipants = new List<Participant>();
}
}
protected override void OnCallStatusChange(CodecActiveCallItem item)
{
base.OnCallStatusChange(item);
if (_props.AutoDefaultLayouts)
{
SetLayout();
}
}
public override void StartSharing()
{
throw new NotImplementedException();
SendText("zCommand Call Sharing HDMI Start");
}
/// <summary>
@@ -1450,6 +1605,12 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.ZoomRoom
public override void AcceptCall(CodecActiveCallItem call)
{
SendText(string.Format("zCommand Call Accept callerJID: {0}", call.Id));
call.Status = eCodecCallStatus.Connected;
OnCallStatusChange(call);
UpdateCallStatus();
}
public void RejectCall()
@@ -1464,6 +1625,12 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.ZoomRoom
public override void RejectCall(CodecActiveCallItem call)
{
SendText(string.Format("zCommand Call Reject callerJID: {0}", call.Id));
call.Status = eCodecCallStatus.Disconnected;
OnCallStatusChange(call);
UpdateCallStatus();
}
public override void Dial(Meeting meeting)
@@ -1513,7 +1680,7 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.ZoomRoom
public override void SendDtmf(string s)
{
throw new NotImplementedException();
SendDtmfToPhone(s);
}
/// <summary>
@@ -1587,12 +1754,13 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.ZoomRoom
public void CameraOff()
{
SendText("zCommand Call Camera Mute: On");
SendText("zConfiguration Call Camera Mute: On");
}
#endregion
#region Implementation of IHasCameraAutoMode
//Zoom doesn't support camera auto modes. Setting this to just unmute video
public void CameraAutoModeOn()
{
@@ -1602,7 +1770,7 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.ZoomRoom
//Zoom doesn't support camera auto modes. Setting this to just unmute video
public void CameraAutoModeOff()
{
SendText("zCommand Call Camera Mute: Off");
SendText("zConfiguration Call Camera Mute: Off");
}
public void CameraAutoModeToggle()
@@ -1613,6 +1781,81 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.ZoomRoom
public BoolFeedback CameraAutoModeIsOnFeedback { get; private set; }
#endregion
#region Implementation of IHasFarEndContentStatus
public BoolFeedback ReceivingContent { get; private set; }
#endregion
#region Implementation of IHasSelfviewPosition
private CodecCommandWithLabel _currentSelfviewPipPosition;
public StringFeedback SelfviewPipPositionFeedback { get; private set; }
public void SelfviewPipPositionSet(CodecCommandWithLabel position)
{
SendText(String.Format("zConfiguration Call Layout Position: {0}", position.Command));
}
public void SelfviewPipPositionToggle()
{
if (_currentSelfviewPipPosition != null)
{
var nextPipPositionIndex = SelfviewPipPositions.IndexOf(_currentSelfviewPipPosition) + 1;
if (nextPipPositionIndex >= SelfviewPipPositions.Count)
// Check if we need to loop back to the first item in the list
nextPipPositionIndex = 0;
SelfviewPipPositionSet(SelfviewPipPositions[nextPipPositionIndex]);
}
}
public List<CodecCommandWithLabel> SelfviewPipPositions = new List<CodecCommandWithLabel>()
{
new CodecCommandWithLabel("UpLeft", "Center Left"),
new CodecCommandWithLabel("UpRight", "Center Right"),
new CodecCommandWithLabel("DownRight", "Lower Right"),
new CodecCommandWithLabel("DownLeft", "Lower Left")
};
private void ComputeSelfviewPipStatus()
{
_currentSelfviewPipPosition =
SelfviewPipPositions.FirstOrDefault(
p => p.Command.ToLower().Equals(Configuration.Call.Layout.Position.ToString().ToLower()));
}
#endregion
#region Implementation of IHasPhoneDialing
private Func<bool> PhoneOffHookFeedbackFunc {get {return () => Status.PhoneCall.OffHook; }}
private Func<string> CallerIdNameFeedbackFunc { get { return () => Status.PhoneCall.PeerDisplayName; } }
private Func<string> CallerIdNumberFeedbackFunc { get { return () => Status.PhoneCall.PeerNumber; } }
public BoolFeedback PhoneOffHookFeedback { get; private set; }
public StringFeedback CallerIdNameFeedback { get; private set; }
public StringFeedback CallerIdNumberFeedback { get; private set; }
public void DialPhoneCall(string number)
{
SendText(String.Format("zCommand Dial PhoneCallOut Number: {0}", number));
}
public void EndPhoneCall()
{
SendText(String.Format("zCommand Dial PhoneHangUp CallId: {0}", Status.PhoneCall.CallId));
}
public void SendDtmfToPhone(string digit)
{
SendText(String.Format("zCommand SendSipDTMF CallId: {0} Key: {1}", Status.PhoneCall.CallId, digit));
}
#endregion
}
/// <summary>

View File

@@ -68,7 +68,6 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.ZoomRoom
/// <summary>
/// Builds the command and triggers the parent ZoomRoom to send it
/// </summary>
/// <param name="id"></param>
/// <param name="state"></param>
/// <param name="action"></param>
void SendCommand(eZoomRoomCameraState state, eZoomRoomCameraAction action)
@@ -79,23 +78,25 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.ZoomRoom
void StartContinueTimer()
{
if(ContinueTimer == null)
ContinueTimer = new CTimer((o) => SendContinueAction(LastAction), ContinueTime);
if (ContinueTimer == null)
ContinueTimer = new CTimer((o) => SendContinueAction(LastAction), null, ContinueTime, ContinueTime);
}
void SendContinueAction(eZoomRoomCameraAction action)
{
SendCommand(eZoomRoomCameraState.Continue, action);
ContinueTimer.Reset();
}
void StopContinueTimer()
{
if (ContinueTimer != null)
if (ContinueTimer == null)
{
ContinueTimer.Stop();
ContinueTimer.Dispose();
return;
}
ContinueTimer.Stop();
ContinueTimer.Dispose();
ContinueTimer = null;
}
#region IHasCameraPtzControl Members
@@ -111,22 +112,26 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.ZoomRoom
public void PanLeft()
{
if (!isMoving)
if (isMoving)
{
SendCommand(eZoomRoomCameraState.Start, eZoomRoomCameraAction.Left);
StartContinueTimer();
isPanning = true;
return;
}
SendCommand(eZoomRoomCameraState.Start, eZoomRoomCameraAction.Left);
StartContinueTimer();
isPanning = true;
}
public void PanRight()
{
if (!isMoving)
if (isMoving)
{
SendCommand(eZoomRoomCameraState.Start, eZoomRoomCameraAction.Right);
StartContinueTimer();
isPanning = true;
return;
}
SendCommand(eZoomRoomCameraState.Start, eZoomRoomCameraAction.Right);
StartContinueTimer();
isPanning = true;
}
public void PanStop()

View File

@@ -16,5 +16,14 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.ZoomRoom
public bool DisablePhonebookAutoDownload { get; set; }
public bool SupportsCameraAutoMode { get; set; }
public bool SupportsCameraOff { get; set; }
//if true, the layouts will be set automatically when sharing starts/ends or a call is joined
public bool AutoDefaultLayouts { get; set; }
/* This layout will be selected when Sharing starts (either from Far end or locally)*/
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; }
}
}

View File

@@ -1,3 +1,3 @@
<packages>
<package id="PepperDashCore" version="1.0.43-alpha-170" targetFramework="net35" allowedVersions="[1.0,1.1)"/>
<package id="PepperDashCore" version="1.0.42" targetFramework="net35" allowedVersions="[1.0,1.1)"/>
</packages>