Merge branch 'main' into hotfix/dm-resolution-issues

This commit is contained in:
Neil Dorin
2021-09-21 10:17:26 -06:00
committed by GitHub
14 changed files with 517 additions and 165 deletions

View File

@@ -8,6 +8,7 @@ $destination = "$($Env:GITHUB_HOME)\output"
New-Item -ItemType Directory -Force -Path ($destination) New-Item -ItemType Directory -Force -Path ($destination)
Get-ChildItem ($destination) Get-ChildItem ($destination)
$exclusions = @(git submodule foreach --quiet 'echo $name') $exclusions = @(git submodule foreach --quiet 'echo $name')
$exclusions += "Newtonsoft.Compact.Json.dll"
# Trying to get any .json schema files (not currently working) # Trying to get any .json schema files (not currently working)
# Gets any files with the listed extensions. # Gets any files with the listed extensions.
Get-ChildItem -recurse -Path "$($Env:GITHUB_WORKSPACE)" -include "*.clz", "*.cpz", "*.cplz", "*.dll", "*.nuspec" | ForEach-Object { Get-ChildItem -recurse -Path "$($Env:GITHUB_WORKSPACE)" -include "*.clz", "*.cpz", "*.cplz", "*.dll", "*.nuspec" | ForEach-Object {

View File

@@ -48,6 +48,11 @@ namespace PepperDash.Essentials
/// </summary> /// </summary>
public const uint MeetingNameText = 1009; public const uint MeetingNameText = 1009;
///<summary>
/// 1240 - Used to determine text for meeting start button
///</summary>
public const uint MeetingStartButtonText = 1240;

View File

@@ -7,7 +7,7 @@
{ {
// Video Codec // Video Codec
/// <summary> /// <summary>
/// 1234: values 0 = Connect, 1 = End /// 1234: values 0 = Connect, 1 = End, 2 = Start Meeting
/// </summary> /// </summary>
public const uint VCStagingConnectButtonMode = 1234; public const uint VCStagingConnectButtonMode = 1234;

View File

@@ -12,6 +12,7 @@ using PepperDash.Core;
using PepperDash.Essentials.Core; using PepperDash.Essentials.Core;
using PepperDash.Essentials.Core.SmartObjects; using PepperDash.Essentials.Core.SmartObjects;
using PepperDash.Essentials.Core.PageManagers; using PepperDash.Essentials.Core.PageManagers;
using PepperDash.Essentials.Devices.Common.VideoCodec.Interfaces;
using PepperDash.Essentials.Room.Config; using PepperDash.Essentials.Room.Config;
using PepperDash.Essentials.Devices.Common.Codec; using PepperDash.Essentials.Devices.Common.Codec;
using PepperDash.Essentials.Devices.Common.VideoCodec; using PepperDash.Essentials.Devices.Common.VideoCodec;
@@ -191,32 +192,56 @@ namespace PepperDash.Essentials
return; return;
} }
var meetingInfoCodec = codec as IHasMeetingInfo;
// Set mode of header button // Set mode of header button
SetHeaderCallIcon(codec);
// Set the call status text
Debug.Console(1, "Active Call Count: {0}", codec.ActiveCalls.Count);
if (codec.ActiveCalls.Count > 0)
{
if (codec.ActiveCalls.Count == 1 && meetingInfoCodec == null)
TriList.SetString(UIStringJoin.HeaderCallStatusLabel, "1 Active Call");
else if (codec.ActiveCalls.Count == 1 && meetingInfoCodec != null)
{
var headerCallStatusLabel = meetingInfoCodec.MeetingInfo.IsSharingMeeting
? "Sharing-Only Meeting"
: "Active Meeting";
headerCallStatusLabel = meetingInfoCodec.MeetingInfo.WaitingForHost
? "Waiting For Host"
: headerCallStatusLabel;
TriList.SetString(UIStringJoin.HeaderCallStatusLabel, headerCallStatusLabel);
}
else if (codec.ActiveCalls.Count > 1)
TriList.SetString(UIStringJoin.HeaderCallStatusLabel, string.Format("{0} Active Calls", codec.ActiveCalls.Count));
}
else
TriList.SetString(UIStringJoin.HeaderCallStatusLabel, "No Active Calls");
}
private void SetHeaderCallIcon(VideoCodecBase codec)
{
if (!codec.IsInCall) if (!codec.IsInCall)
{ {
HeaderCallButtonIconSig.StringValue = "DND"; HeaderCallButtonIconSig.StringValue = "DND";
//HeaderCallButton.SetIcon(HeaderListButton.OnHook); //HeaderCallButton.SetIcon(HeaderListButton.OnHook);
} }
else if (codec.ActiveCalls.Any(c => c.Type == eCodecCallType.Video)) else if (codec.ActiveCalls.Any(c => c.Type == eCodecCallType.Video))
{
HeaderCallButtonIconSig.StringValue = "Misc-06_Dark"; HeaderCallButtonIconSig.StringValue = "Misc-06_Dark";
}
//HeaderCallButton.SetIcon(HeaderListButton.Camera); //HeaderCallButton.SetIcon(HeaderListButton.Camera);
//TriList.SetUshort(UIUshortJoin.CallHeaderButtonMode, 2); //TriList.SetUshort(UIUshortJoin.CallHeaderButtonMode, 2);
else else
{
HeaderCallButtonIconSig.StringValue = "Misc-09_Dark"; HeaderCallButtonIconSig.StringValue = "Misc-09_Dark";
}
//HeaderCallButton.SetIcon(HeaderListButton.Phone); //HeaderCallButton.SetIcon(HeaderListButton.Phone);
//TriList.SetUshort(UIUshortJoin.CallHeaderButtonMode, 1); //TriList.SetUshort(UIUshortJoin.CallHeaderButtonMode, 1);
// Set the call status text
Debug.Console(1, "Active Call Count: {0}", codec.ActiveCalls.Count);
if (codec.ActiveCalls.Count > 0)
{
if (codec.ActiveCalls.Count == 1)
TriList.SetString(UIStringJoin.HeaderCallStatusLabel, "1 Active Call");
else if (codec.ActiveCalls.Count > 1)
TriList.SetString(UIStringJoin.HeaderCallStatusLabel, string.Format("{0} Active Calls", codec.ActiveCalls.Count));
}
else
TriList.SetString(UIStringJoin.HeaderCallStatusLabel, "No Active Calls");
} }
/// <summary> /// <summary>

View File

@@ -9,6 +9,7 @@ using Crestron.SimplSharpPro.UI;
using PepperDash.Core; using PepperDash.Core;
using PepperDash.Essentials.Core; using PepperDash.Essentials.Core;
using PepperDash.Essentials.Core.Config; using PepperDash.Essentials.Core.Config;
using PepperDash.Essentials.Core.DeviceTypeInterfaces;
using PepperDash.Essentials.Core.SmartObjects; using PepperDash.Essentials.Core.SmartObjects;
using PepperDash.Essentials.Core.PageManagers; using PepperDash.Essentials.Core.PageManagers;
using PepperDash.Essentials.Room.Config; using PepperDash.Essentials.Room.Config;
@@ -471,14 +472,22 @@ namespace PepperDash.Essentials
/// </summary> /// </summary>
void ShowNextMeetingTimerCallback() void ShowNextMeetingTimerCallback()
{ {
//Update calendar for Zoom. Zoom doesn't automatically update when meetings are in the past
if (_isZoomRoomWithNoExternalSources)
{
CurrentRoom.ScheduleSource.GetSchedule();
}
// Every 60 seconds, refresh the calendar // Every 60 seconds, refresh the calendar
RefreshMeetingsList(); RefreshMeetingsList();
// check meetings list for the closest, joinable meeting // check meetings list for the closest, joinable meeting
var ss = CurrentRoom.ScheduleSource; var ss = CurrentRoom.ScheduleSource;
var meetings = ss.CodecSchedule.Meetings; var meetings = ss.CodecSchedule.Meetings;
if (meetings.Count > 0) if (meetings.Count <= 0)
{ {
return;
}
// If the room is off pester the user // If the room is off pester the user
// If the room is on, and the meeting is joinable // If the room is on, and the meeting is joinable
// and the LastMeetingDismissed != this meeting // and the LastMeetingDismissed != this meeting
@@ -550,7 +559,6 @@ namespace PepperDash.Essentials
TriList.SetBool(UIBoolJoin.NextMeetingModalVisible, true); TriList.SetBool(UIBoolJoin.NextMeetingModalVisible, true);
} }
} }
}
/// <summary> /// <summary>
/// ///
@@ -575,19 +583,26 @@ namespace PepperDash.Essentials
/// </summary> /// </summary>
void RoomOnAndDialMeeting(Meeting meeting) void RoomOnAndDialMeeting(Meeting meeting)
{ {
Debug.Console(1, "[RoomOnAndDialMeeting] Joining meeting [{0}]", meeting);
Action dialAction = () => Action dialAction = () =>
{ {
var d = CurrentRoom.ScheduleSource as VideoCodecBase; var d = CurrentRoom.ScheduleSource as VideoCodecBase;
if (d != null) if (d != null)
{ {
Debug.Console(1,
"[RoomOnAndDialMeeting] [dialAction] Sending command to codec to join meeting {0}", meeting);
d.Dial(meeting); d.Dial(meeting);
LastMeetingDismissedId = meeting.Id; // To prevent prompts for already-joined call LastMeetingDismissedId = meeting.Id; // To prevent prompts for already-joined call
} }
}; };
if (CurrentRoom.OnFeedback.BoolValue) if (CurrentRoom.OnFeedback.BoolValue)
{
Debug.Console(1, "[RoomOnAndDialMeeting] Room is on.");
dialAction(); dialAction();
}
else else
{ {
Debug.Console(1, "RoomOnAndDialMeeting] Room is off or warming. Registering for Warming Feedback");
// Rig a one-time handler to catch when the room is warmed and then dial call // Rig a one-time handler to catch when the room is warmed and then dial call
EventHandler<FeedbackEventArgs> oneTimeHandler = null; EventHandler<FeedbackEventArgs> oneTimeHandler = null;
oneTimeHandler = (o, a) => oneTimeHandler = (o, a) =>
@@ -716,10 +731,32 @@ namespace PepperDash.Essentials
if (_isZoomRoomWithNoExternalSources) if (_isZoomRoomWithNoExternalSources)
{ {
(CurrentRoom as IRunDefaultPresentRoute).RunDefaultPresentRoute(); if (!CurrentRoom.OnFeedback.BoolValue)
{
CurrentRoom.RunDefaultPresentRoute();
}
// For now, if this is a Zoom Room and there are no shareable sources just display the informational subpage // For now, if this is a Zoom Room and there are no shareable sources just display the informational subpage
TriList.SetBool(UIBoolJoin.ZoomRoomContentSharingVisible, true); TriList.SetBool(UIBoolJoin.ZoomRoomContentSharingVisible, true);
var presentationMeetingCodec = CurrentRoom.VideoCodec as IHasPresentationOnlyMeeting;
var farEndContentStatusCodec = CurrentRoom.VideoCodec as IHasFarEndContentStatus;
var receivingContent = false;
if (farEndContentStatusCodec != null)
{
receivingContent = farEndContentStatusCodec.ReceivingContent.BoolValue;
}
if (presentationMeetingCodec != null && !CurrentRoom.VideoCodec.IsInCall)
{
presentationMeetingCodec.StartSharingOnlyMeeting(eSharingMeetingMode.Laptop);
}
else if (CurrentRoom.VideoCodec.IsInCall && !CurrentRoom.VideoCodec.SharingContentIsOnFeedback.BoolValue &&
!receivingContent)
{
CurrentRoom.VideoCodec.StartSharing();
}
if (CurrentSourcePageManager != null) if (CurrentSourcePageManager != null)
CurrentSourcePageManager.Hide(); CurrentSourcePageManager.Hide();
} }
@@ -734,7 +771,9 @@ namespace PepperDash.Essentials
} }
else // room is on show what's active or select a source if nothing is yet active else // room is on show what's active or select a source if nothing is yet active
{ {
if (CurrentRoom.CurrentSourceInfo == null || (CurrentRoom.VideoCodec != null && CurrentRoom.CurrentSourceInfo.SourceDevice.Key == CurrentRoom.VideoCodec.OsdSource.Key)) if (CurrentRoom.CurrentSourceInfo == null ||
(CurrentRoom.VideoCodec != null &&
CurrentRoom.CurrentSourceInfo.SourceDevice.Key == CurrentRoom.VideoCodec.OsdSource.Key))
TriList.SetBool(UIBoolJoin.SelectASourceVisible, true); TriList.SetBool(UIBoolJoin.SelectASourceVisible, true);
else if (CurrentSourcePageManager != null) else if (CurrentSourcePageManager != null)
{ {
@@ -1079,13 +1118,18 @@ namespace PepperDash.Essentials
void meetingInfoCodec_MeetingInfoChanged(object sender, MeetingInfoEventArgs e) void meetingInfoCodec_MeetingInfoChanged(object sender, MeetingInfoEventArgs e)
{ {
if (e.Info == null)
{
return;
}
TriList.SetString(UIStringJoin.MeetingIdText, e.Info.Id); TriList.SetString(UIStringJoin.MeetingIdText, e.Info.Id);
TriList.SetString(UIStringJoin.MeetingHostText, e.Info.Host); TriList.SetString(UIStringJoin.MeetingHostText, e.Info.Host);
TriList.SetString(UIStringJoin.MeetingNameText, e.Info.Name); TriList.SetString(UIStringJoin.MeetingNameText, e.Info.Name);
TriList.SetString(UIStringJoin.MeetingPasswordText, e.Info.Password); TriList.SetString(UIStringJoin.MeetingPasswordText, e.Info.Password);
// Show the password fields if one is present // Show the password fields if one is present
TriList.SetBool(UIBoolJoin.MeetingPasswordVisible, string.IsNullOrEmpty(e.Info.Password) ? false : true); TriList.SetBool(UIBoolJoin.MeetingPasswordVisible, !string.IsNullOrEmpty(e.Info.Password));
TriList.SetString(UIStringJoin.CallSharedSourceNameText, e.Info.ShareStatus); TriList.SetString(UIStringJoin.CallSharedSourceNameText, e.Info.ShareStatus);
@@ -1295,7 +1339,6 @@ namespace PepperDash.Essentials
{ {
// See if this is helpful or if the callback response in the codec class maybe doesn't come it time? // See if this is helpful or if the callback response in the codec class maybe doesn't come it time?
// Let's build list from event // Let's build list from event
// CurrentRoom.ScheduleSource.GetSchedule();
TriList.SetString(UIStringJoin.MeetingsOrContactMethodListIcon, "Calendar"); TriList.SetString(UIStringJoin.MeetingsOrContactMethodListIcon, "Calendar");
TriList.SetString(UIStringJoin.MeetingsOrContactMethodListTitleText, "Today's Meetings"); TriList.SetString(UIStringJoin.MeetingsOrContactMethodListTitleText, "Today's Meetings");

View File

@@ -134,11 +134,12 @@ namespace PepperDash.Essentials.UIDrivers.VC
VCControlsInterlock = new JoinedSigInterlock(triList); VCControlsInterlock = new JoinedSigInterlock(triList);
VCCameraControlModeInterlock = new JoinedSigInterlock(triList); VCCameraControlModeInterlock = new JoinedSigInterlock(triList);
VCControlsInterlock.HideAndClear();
if (CodecHasFavorites) /* if (CodecHasFavorites || codec is IHasZoomRoomLayouts) //Checking for Zoom Room...picked a ZoomRoom specific interface to check for
VCControlsInterlock.SetButDontShow(UIBoolJoin.VCKeypadWithFavoritesVisible); VCControlsInterlock.SetButDontShow(UIBoolJoin.VCKeypadWithFavoritesVisible);
else else
VCControlsInterlock.SetButDontShow(UIBoolJoin.VCKeypadVisible); VCControlsInterlock.SetButDontShow(UIBoolJoin.VCKeypadVisible); */
StagingBarsInterlock = new JoinedSigInterlock(triList); StagingBarsInterlock = new JoinedSigInterlock(triList);
if(Codec is IHasCallHistory) if(Codec is IHasCallHistory)
@@ -320,25 +321,20 @@ namespace PepperDash.Essentials.UIDrivers.VC
void Codec_CallStatusChange(object sender, CodecCallStatusItemChangeEventArgs e) void Codec_CallStatusChange(object sender, CodecCallStatusItemChangeEventArgs e)
{ {
var call = e.CallItem; var call = e.CallItem;
var meetingInfoSender = sender as IHasMeetingInfo;
switch (e.CallItem.Status) switch (e.CallItem.Status)
{ {
case eCodecCallStatus.Connected: case eCodecCallStatus.Connected:
// fire at SRL item // fire at SRL item
HidePasswordPrompt();
KeypadMode = eKeypadMode.DTMF;
DialStringBuilder.Remove(0, DialStringBuilder.Length);
DialStringFeedback.FireUpdate();
DialStringTextCheckEnables();
Parent.ShowNotificationRibbon("Connected", 2000); Parent.ShowNotificationRibbon("Connected", 2000);
StagingButtonsFeedbackInterlock.ShowInterlocked(UIBoolJoin.VCStagingKeypadPress); OnCallConnected();
ShowKeypad();
((Parent.CurrentRoom as IHasCurrentVolumeControls).CurrentVolumeControls as IBasicVolumeWithFeedback).MuteOff();
//VCControlsInterlock.ShowInterlocked(UIBoolJoin.VCKeypadVisible); //VCControlsInterlock.ShowInterlocked(UIBoolJoin.VCKeypadVisible);
break; break;
case eCodecCallStatus.Connecting: case eCodecCallStatus.Connecting:
// fire at SRL item // fire at SRL item
Parent.ShowNotificationRibbon("Connecting", 0); Parent.ShowNotificationRibbon("Connecting", 0);
OnCallConnected();
break; break;
case eCodecCallStatus.Dialing: case eCodecCallStatus.Dialing:
Parent.ShowNotificationRibbon("Connecting", 0); Parent.ShowNotificationRibbon("Connecting", 0);
@@ -354,7 +350,10 @@ namespace PepperDash.Essentials.UIDrivers.VC
DialStringBuilder.Remove(0, DialStringBuilder.Length); DialStringBuilder.Remove(0, DialStringBuilder.Length);
DialStringFeedback.FireUpdate(); DialStringFeedback.FireUpdate();
Parent.ShowNotificationRibbon("Disconnected", 2000); Parent.ShowNotificationRibbon("Disconnected", 2000);
Debug.Console(0, "Setting Connect Button mode to 0");
} }
break; break;
case eCodecCallStatus.Disconnecting: case eCodecCallStatus.Disconnecting:
break; break;
@@ -375,10 +374,21 @@ namespace PepperDash.Essentials.UIDrivers.VC
ShowIncomingModal(call); ShowIncomingModal(call);
break; break;
} }
default:
break;
} }
TriList.UShortInput[UIUshortJoin.VCStagingConnectButtonMode].UShortValue = (ushort)(Codec.IsInCall ? 1 : 0);
if (meetingInfoSender != null && Codec.IsInCall)
{
var meetingInfo = meetingInfoSender.MeetingInfo;
TriList.UShortInput[UIUshortJoin.VCStagingConnectButtonMode].UShortValue =
(ushort) (meetingInfo.IsSharingMeeting ? 2 : 1);
}
else
{
TriList.UShortInput[UIUshortJoin.VCStagingConnectButtonMode].UShortValue =
(ushort) (Codec.IsInCall ? 1 : 0);
}
uint stageJoin; uint stageJoin;
if (Codec.IsInCall) if (Codec.IsInCall)
@@ -401,6 +411,36 @@ namespace PepperDash.Essentials.UIDrivers.VC
UpdateHeaderActiveCallList(); UpdateHeaderActiveCallList();
} }
private void OnCallConnected()
{
HidePasswordPrompt();
KeypadMode = eKeypadMode.DTMF;
DialStringBuilder.Remove(0, DialStringBuilder.Length);
DialStringFeedback.FireUpdate();
DialStringTextCheckEnables();
StagingButtonsFeedbackInterlock.ShowInterlocked(UIBoolJoin.VCStagingKeypadPress);
ShowKeypad();
UnmuteRoomOnCallConnect();
}
private void UnmuteRoomOnCallConnect()
{
var volControl = Parent.CurrentRoom as IHasCurrentVolumeControls;
if (volControl == null)
{
return;
}
var currentVolControls = volControl.CurrentVolumeControls as IBasicVolumeWithFeedback;
if (currentVolControls != null)
{
currentVolControls.MuteOff();
}
}
/// <summary> /// <summary>
/// Redraws the calls list on the header /// Redraws the calls list on the header
/// </summary> /// </summary>
@@ -519,14 +559,35 @@ namespace PepperDash.Essentials.UIDrivers.VC
TriList.SetSigFalseAction(UIBoolJoin.VCStagingMeetNowPress, MeetNowPress); TriList.SetSigFalseAction(UIBoolJoin.VCStagingMeetNowPress, MeetNowPress);
TriList.SetSigFalseAction(UIBoolJoin.CallStopSharingPress, CallStopSharingPress); TriList.SetSigFalseAction(UIBoolJoin.CallStopSharingPress, CallStopSharingPress);
var meetingInfoCodec = Codec as IHasMeetingInfo;
TriList.SetSigFalseAction(UIBoolJoin.CallEndPress, () => TriList.SetSigFalseAction(UIBoolJoin.CallEndPress, () =>
{ {
if (Codec.ActiveCalls.Count > 1) if (Codec.ActiveCalls.Count > 1)
{ {
Parent.PopupInterlock.ShowInterlocked(Parent.CallListOrMeetingInfoPopoverVisibilityJoin); Parent.PopupInterlock.ShowInterlocked(Parent.CallListOrMeetingInfoPopoverVisibilityJoin);
} }
else if (meetingInfoCodec != null && Codec.ActiveCalls.Count == 1)
{
var meetingInfo = meetingInfoCodec.MeetingInfo;
if (meetingInfo != null && meetingInfo.IsSharingMeeting)
{
var presentationMeetingCodec = Codec as IHasPresentationOnlyMeeting;
if (presentationMeetingCodec != null)
{
presentationMeetingCodec.StartNormalMeetingFromSharingOnlyMeeting();
}
}
else else
{
Codec.EndAllCalls(); Codec.EndAllCalls();
}
}
else
{
Codec.EndAllCalls();
}
}); });
TriList.SetSigFalseAction(UIBoolJoin.CallEndAllConfirmPress, () => TriList.SetSigFalseAction(UIBoolJoin.CallEndAllConfirmPress, () =>
@@ -535,7 +596,7 @@ namespace PepperDash.Essentials.UIDrivers.VC
Codec.EndAllCalls(); Codec.EndAllCalls();
}); });
var meetingInfoCodec = Codec as IHasMeetingInfo;
if (meetingInfoCodec != null) if (meetingInfoCodec != null)
{ {
TriList.SetSigFalseAction(UIBoolJoin.MeetingLeavePress, () => TriList.SetSigFalseAction(UIBoolJoin.MeetingLeavePress, () =>
@@ -1801,7 +1862,7 @@ namespace PepperDash.Essentials.UIDrivers.VC
/// </summary> /// </summary>
void PasswordKeypadClear() void PasswordKeypadClear()
{ {
PasswordStringBuilder.Remove(0, SearchStringBuilder.Length); PasswordStringBuilder.Remove(0, PasswordStringBuilder.Length);
PasswordStringFeedback.FireUpdate(); PasswordStringFeedback.FireUpdate();
PasswordStringCheckEnables(); PasswordStringCheckEnables();
@@ -1929,6 +1990,7 @@ namespace PepperDash.Essentials.UIDrivers.VC
_passwordPromptDialogVisible = false; _passwordPromptDialogVisible = false;
Parent.Keyboard.Hide(); Parent.Keyboard.Hide();
TriList.SetBool(UIBoolJoin.PasswordPromptDialogVisible, _passwordPromptDialogVisible); TriList.SetBool(UIBoolJoin.PasswordPromptDialogVisible, _passwordPromptDialogVisible);
PasswordKeypadClear();
} }
} }
} }

View File

@@ -14,7 +14,7 @@
<tags>crestron 3series 4series</tags> <tags>crestron 3series 4series</tags>
<repository type="git" url="https://github.com/PepperDash/Essentials"/> <repository type="git" url="https://github.com/PepperDash/Essentials"/>
<dependencies> <dependencies>
<dependency id="PepperDashCore" version="[1.0.45, 1.1.0)"/> <dependency id="PepperDashCore" version="[1.0.45, 2.0.0)"/>
</dependencies> </dependencies>
</metadata> </metadata>
<files> <files>

View File

@@ -235,6 +235,15 @@ namespace PepperDash.Essentials.Devices.Common.Codec
{ {
Calls = new List<Call>(); Calls = new List<Call>();
} }
#region Overrides of Object
public override string ToString()
{
return String.Format("{0}:{1}: {2}-{3}", Title, Agenda, StartTime, EndTime);
}
#endregion
} }
public class Call public class Call

View File

@@ -122,6 +122,7 @@
<Compile Include="Display\PanasonicThDisplay.cs" /> <Compile Include="Display\PanasonicThDisplay.cs" />
<Compile Include="VideoCodec\Interfaces\IHasMeetingInfo.cs" /> <Compile Include="VideoCodec\Interfaces\IHasMeetingInfo.cs" />
<Compile Include="VideoCodec\Interfaces\IHasParticipants.cs" /> <Compile Include="VideoCodec\Interfaces\IHasParticipants.cs" />
<Compile Include="VideoCodec\Interfaces\IHasPresentationOnlyMeeting.cs" />
<Compile Include="VideoCodec\Interfaces\IHasSelfviewPosition.cs" /> <Compile Include="VideoCodec\Interfaces\IHasSelfviewPosition.cs" />
<Compile Include="VideoCodec\Interfaces\IHasSelfviewSize.cs" /> <Compile Include="VideoCodec\Interfaces\IHasSelfviewSize.cs" />
<Compile Include="VideoCodec\Interfaces\IHasStartMeeting.cs" /> <Compile Include="VideoCodec\Interfaces\IHasStartMeeting.cs" />

View File

@@ -36,8 +36,12 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.Interfaces
public string ShareStatus { get; private set; } public string ShareStatus { get; private set; }
[JsonProperty("isHost")] [JsonProperty("isHost")]
public Boolean IsHost { get; private set; } public Boolean IsHost { get; private set; }
[JsonProperty("isSharingMeeting")]
public Boolean IsSharingMeeting { get; private set; }
[JsonProperty("waitingForHost")]
public Boolean WaitingForHost { get; private set; }
public MeetingInfo(string id, string name, string host, string password, string shareStatus, bool isHost) public MeetingInfo(string id, string name, string host, string password, string shareStatus, bool isHost, bool isSharingMeeting, bool waitingForHost)
{ {
Id = id; Id = id;
Name = name; Name = name;
@@ -45,6 +49,8 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.Interfaces
Password = password; Password = password;
ShareStatus = shareStatus; ShareStatus = shareStatus;
IsHost = isHost; IsHost = isHost;
IsSharingMeeting = isSharingMeeting;
WaitingForHost = waitingForHost;
} }
} }

View File

@@ -0,0 +1,18 @@
namespace PepperDash.Essentials.Devices.Common.VideoCodec.Interfaces
{
public interface IHasPresentationOnlyMeeting
{
void StartSharingOnlyMeeting();
void StartSharingOnlyMeeting(eSharingMeetingMode mode);
void StartSharingOnlyMeeting(eSharingMeetingMode mode, ushort duration);
void StartSharingOnlyMeeting(eSharingMeetingMode mode, ushort duration, string password);
void StartNormalMeetingFromSharingOnlyMeeting();
}
public enum eSharingMeetingMode
{
None,
Laptop,
Ios,
}
}

View File

@@ -59,6 +59,7 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.ZoomRoom
public List<zStatus.AudioVideoInputOutputLineItem> AudioOuputs { get; set; } public List<zStatus.AudioVideoInputOutputLineItem> AudioOuputs { get; set; }
public List<zStatus.AudioVideoInputOutputLineItem> Cameras { get; set; } public List<zStatus.AudioVideoInputOutputLineItem> Cameras { get; set; }
public zEvent.PhoneCallStatus PhoneCall { get; set; } public zEvent.PhoneCallStatus PhoneCall { get; set; }
public zEvent.NeedWaitForHost NeedWaitForHost { get; set; }
public ZoomRoomStatus() public ZoomRoomStatus()
{ {
@@ -76,6 +77,7 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.ZoomRoom
AudioOuputs = new List<zStatus.AudioVideoInputOutputLineItem>(); AudioOuputs = new List<zStatus.AudioVideoInputOutputLineItem>();
Cameras = new List<zStatus.AudioVideoInputOutputLineItem>(); Cameras = new List<zStatus.AudioVideoInputOutputLineItem>();
PhoneCall = new zEvent.PhoneCallStatus(); PhoneCall = new zEvent.PhoneCallStatus();
NeedWaitForHost = new zEvent.NeedWaitForHost();
} }
} }
@@ -756,6 +758,10 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.ZoomRoom
/// </summary> /// </summary>
public class zEvent public class zEvent
{ {
public class StartLocalPresentMeeting
{
public bool Success { get; set; }
}
public class NeedWaitForHost public class NeedWaitForHost
{ {
public bool Wait { get; set; } public bool Wait { get; set; }
@@ -1471,6 +1477,10 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.ZoomRoom
public static List<Participant> GetGenericParticipantListFromParticipantsResult( public static List<Participant> GetGenericParticipantListFromParticipantsResult(
List<ListParticipant> participants) List<ListParticipant> participants)
{ {
if (participants.Count == 0)
{
return new List<Participant>();
}
//return participants.Select(p => new Participant //return participants.Select(p => new Participant
// { // {
// UserId = p.UserId, // UserId = p.UserId,

View File

@@ -1,5 +1,6 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.ComponentModel;
using System.Linq; using System.Linq;
using System.Text; using System.Text;
using Crestron.SimplSharp; using Crestron.SimplSharp;
@@ -25,7 +26,7 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.ZoomRoom
IRouting, IRouting,
IHasScheduleAwareness, IHasCodecCameras, IHasParticipants, IHasCameraOff, IHasCameraMute, IHasCameraAutoMode, IHasScheduleAwareness, IHasCodecCameras, IHasParticipants, IHasCameraOff, IHasCameraMute, IHasCameraAutoMode,
IHasFarEndContentStatus, IHasSelfviewPosition, IHasPhoneDialing, IHasZoomRoomLayouts, IHasParticipantPinUnpin, IHasFarEndContentStatus, IHasSelfviewPosition, IHasPhoneDialing, IHasZoomRoomLayouts, IHasParticipantPinUnpin,
IHasParticipantAudioMute, IHasSelfviewSize, IPasswordPrompt, IHasStartMeeting, IHasMeetingInfo IHasParticipantAudioMute, IHasSelfviewSize, IPasswordPrompt, IHasStartMeeting, IHasMeetingInfo, IHasPresentationOnlyMeeting
{ {
private const long MeetingRefreshTimer = 60000; private const long MeetingRefreshTimer = 60000;
public uint DefaultMeetingDurationMin { get; private set; } public uint DefaultMeetingDurationMin { get; private set; }
@@ -111,6 +112,11 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.ZoomRoom
CodecSchedule = new CodecScheduleAwareness(MeetingRefreshTimer); CodecSchedule = new CodecScheduleAwareness(MeetingRefreshTimer);
if (_props.MinutesBeforeMeetingStart > 0)
{
CodecSchedule.MeetingWarningMinutes = _props.MinutesBeforeMeetingStart;
}
ReceivingContent = new BoolFeedback(FarEndIsSharingContentFeedbackFunc); ReceivingContent = new BoolFeedback(FarEndIsSharingContentFeedbackFunc);
SelfviewPipPositionFeedback = new StringFeedback(SelfviewPipPositionFeedbackFunc); SelfviewPipPositionFeedback = new StringFeedback(SelfviewPipPositionFeedbackFunc);
@@ -464,18 +470,7 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.ZoomRoom
private void SetUpCallFeedbackActions() private void SetUpCallFeedbackActions()
{ {
Status.Call.Sharing.PropertyChanged += (o, a) => Status.Call.Sharing.PropertyChanged += HandleSharingStateUpdate;
{
if (a.PropertyName == "State")
{
SharingContentIsOnFeedback.FireUpdate();
ReceivingContent.FireUpdate();
// Update the share status of the meeting info
var meetingInfo = new MeetingInfo(MeetingInfo.Id, MeetingInfo.Name, Participants.Host.Name, MeetingInfo.Password, GetSharingStatus(), GetIsHostMyself());
MeetingInfo = meetingInfo;
}
};
Status.Call.PropertyChanged += (o, a) => Status.Call.PropertyChanged += (o, a) =>
{ {
@@ -487,6 +482,39 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.ZoomRoom
}; };
} }
private void HandleSharingStateUpdate(object sender, PropertyChangedEventArgs a)
{
if (a.PropertyName != "State")
{
return;
}
SharingContentIsOnFeedback.FireUpdate();
ReceivingContent.FireUpdate();
try
{
// Update the share status of the meeting info
if (MeetingInfo == null)
{
var sharingStatus = GetSharingStatus();
MeetingInfo = new MeetingInfo("", "", "", "", sharingStatus, GetIsHostMyself(), true, false);
return;
}
var meetingInfo = new MeetingInfo(MeetingInfo.Id, MeetingInfo.Name, Participants.Host != null ? Participants.Host.Name : "None",
MeetingInfo.Password, GetSharingStatus(), GetIsHostMyself(), MeetingInfo.IsSharingMeeting, MeetingInfo.WaitingForHost);
MeetingInfo = meetingInfo;
}
catch (Exception e)
{
Debug.Console(1, this, "Error processing state property update. {0}", e.Message);
Debug.Console(2, this, e.StackTrace);
MeetingInfo = new MeetingInfo("", "", "", "", "None", false, false, false);
}
}
/// <summary> /// <summary>
/// Subscribes to the PropertyChanged events on the state objects and fires the corresponding feedbacks. /// Subscribes to the PropertyChanged events on the state objects and fires the corresponding feedbacks.
/// </summary> /// </summary>
@@ -626,8 +654,16 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.ZoomRoom
case "isDirectPresentationConnected": case "isDirectPresentationConnected":
case "isSharingBlackMagic": case "isSharingBlackMagic":
{ {
Debug.Console(2, this, "Updating sharing status: {0}", a.PropertyName);
SharingContentIsOnFeedback.FireUpdate();
if (MeetingInfo == null)
{
//Ignoring for now, as the CallInfo return will create the appropriate value
return;
}
// Update the share status of the meeting info // Update the share status of the meeting info
var meetingInfo = new MeetingInfo(MeetingInfo.Id, MeetingInfo.Name, MeetingInfo.Host, MeetingInfo.Password, GetSharingStatus(), GetIsHostMyself()); var meetingInfo = new MeetingInfo(MeetingInfo.Id, MeetingInfo.Name, MeetingInfo.Host, MeetingInfo.Password, GetSharingStatus(), GetIsHostMyself(), MeetingInfo.IsSharingMeeting, MeetingInfo.WaitingForHost);
MeetingInfo = meetingInfo; MeetingInfo = meetingInfo;
break; break;
} }
@@ -1199,7 +1235,7 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.ZoomRoom
Participants.CurrentParticipants = participants; Participants.CurrentParticipants = participants;
// Update the share status of the meeting info // Update the share status of the meeting info
var meetingInfo = new MeetingInfo(MeetingInfo.Id, MeetingInfo.Name, Participants.Host.Name, MeetingInfo.Password, MeetingInfo.ShareStatus, GetIsHostMyself()); var meetingInfo = new MeetingInfo(MeetingInfo.Id, MeetingInfo.Name, Participants.Host.Name, MeetingInfo.Password, MeetingInfo.ShareStatus, GetIsHostMyself(), MeetingInfo.IsSharingMeeting, MeetingInfo.WaitingForHost);
MeetingInfo = meetingInfo; MeetingInfo = meetingInfo;
PrintCurrentCallParticipants(); PrintCurrentCallParticipants();
@@ -1394,14 +1430,39 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.ZoomRoom
} }
case "needwaitforhost": case "needwaitforhost":
{ {
var needWait = Status.NeedWaitForHost = JsonConvert.DeserializeObject<zEvent.NeedWaitForHost>(responseObj.ToString());
JsonConvert.DeserializeObject<zEvent.NeedWaitForHost>(responseObj.ToString());
if (needWait.Wait) Debug.Console(1, this, "NeedWaitForHost: {0}", Status.NeedWaitForHost.Wait);
if (Status.NeedWaitForHost.Wait)
{ {
// TODO: notify user to wait for host if (MeetingInfo == null)
{
MeetingInfo = new MeetingInfo("Waiting For Host", "Waiting For Host", "Waiting For Host", "",
GetSharingStatus(), false, false, true);
UpdateCallStatus();
break;
} }
MeetingInfo = new MeetingInfo("Waiting For Host", "Waiting For Host", "Waiting For Host", "",
GetSharingStatus(), false, false, true);
UpdateCallStatus();
break;
}
if (MeetingInfo == null)
{
MeetingInfo = new MeetingInfo("Waiting For Host", "Waiting For Host", "Waiting For Host", "",
GetSharingStatus(), false, false, false);
break;
}
MeetingInfo = new MeetingInfo(MeetingInfo.Id, MeetingInfo.Name, MeetingInfo.Host, MeetingInfo.Password,
GetSharingStatus(), GetIsHostMyself(), false, false);
break; break;
} }
case "openvideofailforhoststop": case "openvideofailforhoststop":
@@ -1476,6 +1537,18 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.ZoomRoom
// fire the event as we've modified the participants list // fire the event as we've modified the participants list
Participants.OnParticipantsChanged(); Participants.OnParticipantsChanged();
break;
}
case "startlocalpresentmeeting":
{
var result = JsonConvert.DeserializeObject<zEvent.StartLocalPresentMeeting>(responseObj.ToString());
if (result.Success)
{
MeetingInfo = new MeetingInfo("", "", "", "", "", true, true, MeetingInfo.WaitingForHost);
break;
}
break; break;
} }
default: default:
@@ -1595,7 +1668,14 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.ZoomRoom
} }
catch (Exception ex) catch (Exception ex)
{ {
Debug.Console(1, this, "Error Deserializing feedback: {0}", ex); Debug.Console(1, this, "Error Deserializing feedback: {0}", ex.Message);
Debug.Console(2, this, "{0}", ex);
if (ex.InnerException != null)
{
Debug.Console(1, this,"Error Deserializing feedback inner exception: {0}", ex.InnerException.Message);
Debug.Console(2, this, "{0}", ex.InnerException.StackTrace);
}
} }
} }
@@ -1655,8 +1735,9 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.ZoomRoom
/// </summary> /// </summary>
private void UpdateCallStatus() private void UpdateCallStatus()
{ {
Debug.Console(1, this, "[UpdateCallStatus] Current Call Status: {0}", Debug.Console(1, this,
Status.Call != null ? Status.Call.Status.ToString() : "no call"); "[UpdateCallStatus] Current Call Status: {0} Active Call Count: {1} Need Wait For Host: {2}",
Status.Call != null ? Status.Call.Status.ToString() : "no call", ActiveCalls.Count, Status.NeedWaitForHost.Wait);
if (Status.Call != null) if (Status.Call != null)
{ {
@@ -1701,18 +1782,33 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.ZoomRoom
Type = eCodecCallType.Video, Type = eCodecCallType.Video,
}; };
if (!String.IsNullOrEmpty(_lastDialedMeetingNumber))
{
_lastDialedMeetingNumber = String.Empty;
}
ActiveCalls.Add(newCall); ActiveCalls.Add(newCall);
//Debug.Console(1, this, "[UpdateCallStatus] IF w/ meeting_id AcitveCalls.Count == {1} - Current Call Status: {0}", OnCallStatusChange(newCall);
//Status.Call != null ? Status.Call.Status.ToString() : "no call", ActiveCalls.Count); } else if (String.IsNullOrEmpty(Status.Call.Info.meeting_id) && Status.NeedWaitForHost.Wait)
{
var newCall = new CodecActiveCallItem
{
Name = "Waiting For Host",
Number = "Waiting For Host",
Id = "Waiting For Host",
Status = newStatus,
Type = eCodecCallType.Video,
};
if (!String.IsNullOrEmpty(_lastDialedMeetingNumber))
{
_lastDialedMeetingNumber = String.Empty;
}
ActiveCalls.Add(newCall);
OnCallStatusChange(newCall); OnCallStatusChange(newCall);
} }
else
{
//Debug.Console(1, this, "[UpdateCallStatus] IF w/o meeting_id AcitveCalls.Count == {1} - Current Call Status: {0}",
//Status.Call != null ? Status.Call.Status.ToString() : "no call", ActiveCalls.Count);
}
} }
} }
else else
@@ -1722,9 +1818,17 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.ZoomRoom
switch (callStatus) switch (callStatus)
{ {
case zStatus.eCallStatus.IN_MEETING: case zStatus.eCallStatus.IN_MEETING:
if (Status.NeedWaitForHost.Wait)
{
Status.NeedWaitForHost.Wait = false;
}
existingCall.Status = eCodecCallStatus.Connected; existingCall.Status = eCodecCallStatus.Connected;
break; break;
case zStatus.eCallStatus.NOT_IN_MEETING: case zStatus.eCallStatus.NOT_IN_MEETING:
if (Status.NeedWaitForHost.Wait)
{
Status.NeedWaitForHost.Wait = false;
}
existingCall.Status = eCodecCallStatus.Disconnected; existingCall.Status = eCodecCallStatus.Disconnected;
break; break;
} }
@@ -1732,6 +1836,7 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.ZoomRoom
Debug.Console(1, this, "[UpdateCallStatus] ELSE ActiveCalls.Count == {1} - Current Call Status: {0}", Debug.Console(1, this, "[UpdateCallStatus] ELSE ActiveCalls.Count == {1} - Current Call Status: {0}",
Status.Call != null ? Status.Call.Status.ToString() : "no call", ActiveCalls.Count); Status.Call != null ? Status.Call.Status.ToString() : "no call", ActiveCalls.Count);
OnCallStatusChange(existingCall); OnCallStatusChange(existingCall);
} }
} }
@@ -1769,8 +1874,6 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.ZoomRoom
protected override void OnCallStatusChange(CodecActiveCallItem item) protected override void OnCallStatusChange(CodecActiveCallItem item)
{ {
base.OnCallStatusChange(item);
if (item.Status == eCodecCallStatus.Connected) if (item.Status == eCodecCallStatus.Connected)
{ {
@@ -1785,10 +1888,14 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.ZoomRoom
host, host,
Status.Call.Info.meeting_password, Status.Call.Info.meeting_password,
GetSharingStatus(), GetSharingStatus(),
GetIsHostMyself() GetIsHostMyself(),
!String.Equals(Status.Call.Info.meeting_type,"NORMAL"),
false
); );
} }
base.OnCallStatusChange(item);
Debug.Console(1, this, "[OnCallStatusChange] Current Call Status: {0}", Debug.Console(1, this, "[OnCallStatusChange] Current Call Status: {0}",
Status.Call != null ? Status.Call.Status.ToString() : "no call"); Status.Call != null ? Status.Call.Status.ToString() : "no call");
@@ -1802,6 +1909,8 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.ZoomRoom
{ {
string sharingState = "None"; string sharingState = "None";
try
{
if (Status.Call.Sharing.State == zEvent.eSharingState.Receiving) if (Status.Call.Sharing.State == zEvent.eSharingState.Receiving)
{ {
sharingState = "Receiving Content"; sharingState = "Receiving Content";
@@ -1821,6 +1930,13 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.ZoomRoom
return sharingState; return sharingState;
} }
catch (Exception e)
{
Debug.Console(1, this, "Exception getting sharing status: {0}", e.Message);
Debug.Console(2, this, "{0}", e.StackTrace);
return sharingState;
}
}
/// <summary> /// <summary>
/// Will return true if the host is myself (this zoom room) /// Will return true if the host is myself (this zoom room)
@@ -1828,6 +1944,14 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.ZoomRoom
/// <returns></returns> /// <returns></returns>
private bool GetIsHostMyself() private bool GetIsHostMyself()
{ {
try
{
if (Participants.CurrentParticipants.Count == 0)
{
Debug.Console(2, this, "No current participants");
return false;
}
var host = Participants.Host; var host = Participants.Host;
if(host == null) if(host == null)
@@ -1838,6 +1962,13 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.ZoomRoom
Debug.Console(2, this, "Host is: '{0}' IsMyself?: {1}", host.Name, host.IsMyself); Debug.Console(2, this, "Host is: '{0}' IsMyself?: {1}", host.Name, host.IsMyself);
return host.IsMyself; return host.IsMyself;
} }
catch (Exception e)
{
Debug.Console(1, "Exception getting isHost: {0}", e.Message);
Debug.Console(2, "{0}", e.StackTrace);
return false;
}
}
public override void StartSharing() public override void StartSharing()
{ {
@@ -1848,9 +1979,16 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.ZoomRoom
/// Stops sharing the current presentation /// Stops sharing the current presentation
/// </summary> /// </summary>
public override void StopSharing() public override void StopSharing()
{
if (Status.Sharing.isSharingBlackMagic)
{
SendText("zCommand Call Sharing HDMI Stop");
}
else
{ {
SendText("zCommand Call Sharing Disconnect"); SendText("zCommand Call Sharing Disconnect");
} }
}
public override void PrivacyModeOn() public override void PrivacyModeOn()
{ {
@@ -2135,11 +2273,13 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.ZoomRoom
public override void Dial(Meeting meeting) public override void Dial(Meeting meeting)
{ {
Debug.Console(1, this, "Dialing meeting.Id: {0} Title: {1}", meeting.Id, meeting.Title); Debug.Console(1, this, "Dialing meeting.Id: {0} Title: {1}", meeting.Id, meeting.Title);
_lastDialedMeetingNumber = meeting.Id;
SendText(string.Format("zCommand Dial Start meetingNumber: {0}", meeting.Id)); SendText(string.Format("zCommand Dial Start meetingNumber: {0}", meeting.Id));
} }
public override void Dial(string number) public override void Dial(string number)
{ {
Debug.Console(2, this, "Dialing number: {0}", number);
_lastDialedMeetingNumber = number; _lastDialedMeetingNumber = number;
SendText(string.Format("zCommand Dial Join meetingNumber: {0}", number)); SendText(string.Format("zCommand Dial Join meetingNumber: {0}", number));
} }
@@ -2849,6 +2989,36 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.ZoomRoom
} }
} }
#endregion
#region Implementation of IHasPresentationOnlyMeeting
public void StartSharingOnlyMeeting()
{
StartSharingOnlyMeeting(eSharingMeetingMode.None, 30, String.Empty);
}
public void StartSharingOnlyMeeting(eSharingMeetingMode mode)
{
StartSharingOnlyMeeting(mode, 30, String.Empty);
}
public void StartSharingOnlyMeeting(eSharingMeetingMode mode, ushort duration)
{
StartSharingOnlyMeeting(mode, duration, String.Empty);
}
public void StartSharingOnlyMeeting(eSharingMeetingMode mode, ushort duration, string password)
{
SendText(String.Format("zCommand Dial Sharing Duration: {0} DisplayState: {1} Password: {2}", duration, mode, password));
}
public void StartNormalMeetingFromSharingOnlyMeeting()
{
Debug.Console(2, this, "Converting Sharing Meeting to Normal Meeting");
SendText("zCommand call sharing ToNormal");
}
#endregion #endregion
} }

View File

@@ -25,5 +25,7 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.ZoomRoom
//This layout will be selected when a call is connected and no content is being shared //This layout will be selected when a call is connected and no content is being shared
public string DefaultCallLayout { get; set; } public string DefaultCallLayout { get; set; }
public int MinutesBeforeMeetingStart { get; set; }
} }
} }