private void StartEmptyPresentation() { // Make sure we have a suitable RoleModel for broadcasting a presentation. InstructorModel instructor; using(Synchronizer.Lock(this.m_Model.Participant.SyncRoot)) { instructor = this.m_Model.Participant.Role as InstructorModel; if(instructor == null) { // Make the participant representing this user an Instructor, // which tells the ConnectionManager to broadcast the presentation // once it's added to the classroom. instructor = new InstructorModel(Guid.NewGuid()); this.m_Model.Participant.Role = instructor; } } // Create the presentation. // TODO: Find something useful to use as the Presentation's HumanName. PresentationModel pres = new PresentationModel(Guid.NewGuid(), this.m_Model.Participant, "No presentation yet"); using(Synchronizer.Lock(this.m_Model.Network.SyncRoot)) { // Associate the participant with itself. This removes any existing association // (since an Instructor should not be processing broadcasts from other clients), // and also causes the NetworkAssociationService to copy anything we do to the // InstructorModel to the WorkspaceModel. this.m_Model.Network.Association = this.m_Model.Participant; } // Here's the kicker, which triggers the viewer to hide the classroom browser // and start displaying the presentation. The NetworkAssociationService copies // the presentation to the WorkspaceModel, which causes it to be displayed by the UI. using(Synchronizer.Lock(instructor.SyncRoot)) { instructor.CurrentPresentation = pres; } }
/// <summary> /// Constructor /// </summary> /// <param name="sender">The sending queue to post messages to</param> /// <param name="role">The InstructorModel to create this class for</param> public InstructorWebService(SendingQueue sender, InstructorModel role) { this.m_Sender = sender; this.m_Instructor = role; // Handle basic changes this.m_GenericChangeDispatcher = new EventQueue.PropertyEventDispatcher(this.m_Sender, new PropertyEventHandler(this.HandleGenericChange)); this.m_Instructor.Changed["ForcingStudentNavigationLock"].Add(this.m_GenericChangeDispatcher.Dispatcher); this.m_Instructor.Changed["AcceptingStudentSubmissions"].Add(this.m_GenericChangeDispatcher.Dispatcher); this.m_Instructor.Changed["AcceptingQuickPollSubmissions"].Add(this.m_GenericChangeDispatcher.Dispatcher); // Handle changes to the current deck traversal this.m_CurrentDeckTraversalChangedDispatcher = new EventQueue.PropertyEventDispatcher(this.m_Sender, new PropertyEventHandler(this.HandleCurrentDeckTraversalChanged)); this.m_Instructor.Changed["CurrentDeckTraversal"].Add(this.m_CurrentDeckTraversalChangedDispatcher.Dispatcher); this.m_CurrentDeckTraversalChangedDispatcher.Dispatcher(this, null); }
private void SetNetworkAssociationRole(RoleModel role) { // Remove any old event listeners. if (this.m_NetworkAssociationRole != null) { this.m_NetworkAssociationRole.Changed["ForcingStudentNavigationLock"].Remove(this.m_ForcingStudentNavigationLockChangedDispatcher.Dispatcher); } this.m_NetworkAssociationRole = role as InstructorModel; // If we're now associated with an instructor, we must obey its ForcingStudentNavigationLock policy. // So we register event listeners to watch for changes to that property. if (this.m_NetworkAssociationRole != null) { this.m_NetworkAssociationRole.Changed["ForcingStudentNavigationLock"].Add(this.m_ForcingStudentNavigationLockChangedDispatcher.Dispatcher); this.m_ForcingStudentNavigationLockChangedDispatcher.Dispatcher(this, null); } }
/// <summary> /// Constructor /// </summary> /// <param name="sender">The sending queue to post messages to</param> /// <param name="role">The InstructorModel to create this class for</param> public InstructorNetworkService(SendingQueue sender, InstructorModel role) : base(sender, role) { this.m_Instructor = role; // Create the submission status service submission_status_service_ = new SubmissionStatusNetworkService(this.Sender, role); // Handle basic changes this.m_GenericChangeDispatcher = new EventQueue.PropertyEventDispatcher(this.Sender, new PropertyEventHandler(this.HandleGenericChange)); this.m_Instructor.Changed["ForcingStudentNavigationLock"].Add(this.m_GenericChangeDispatcher.Dispatcher); this.m_Instructor.Changed["AcceptingStudentSubmissions"].Add(this.m_GenericChangeDispatcher.Dispatcher); this.m_Instructor.Changed["AcceptingQuickPollSubmissions"].Add(this.m_GenericChangeDispatcher.Dispatcher); // Handle changes to the current presentation this.m_CurrentPresentationChangedDispatcher = new EventQueue.PropertyEventDispatcher(this.Sender, new PropertyEventHandler(this.HandleCurrentPresentationChanged)); this.m_Instructor.Changed["CurrentPresentation"].Add(this.m_CurrentPresentationChangedDispatcher.Dispatcher); this.m_CurrentPresentationChangedDispatcher.Dispatcher(this, null); // Handle changes to the current deck traversal this.m_CurrentDeckTraversalChangedDispatcher = new EventQueue.PropertyEventDispatcher(this.Sender, new PropertyEventHandler(this.HandleCurrentDeckTraversalChanged)); this.m_Instructor.Changed["CurrentDeckTraversal"].Add(this.m_CurrentDeckTraversalChangedDispatcher.Dispatcher); this.m_CurrentDeckTraversalChangedDispatcher.Dispatcher(this, null); }
private void HandleRoleChanged(object sender, PropertyEventArgs args_) { using(Synchronizer.Lock(this)) { if(this.m_Association != null) { using(Synchronizer.Lock(this.m_Association.SyncRoot)) { this.Instructor = this.m_Association.Role as InstructorModel; } } else { this.Instructor = null; } } }
protected override bool UpdateTarget(ReceiveContext context) { InstructorModel role = this.Target as InstructorModel; if(role == null) this.Target = role = new InstructorModel(((Guid) this.TargetId)); using(Synchronizer.Lock(role.SyncRoot)) { role.AcceptingStudentSubmissions = this.AcceptingStudentSubmissions; // Deserialize the extension ExtensionWrapper extension = this.Extension as ExtensionWrapper; if (extension != null) { if( extension.ExtensionType.Equals( new Guid( "{65A946F4-D1C5-426b-96DB-7AF4863CE296}" ) ) ) { bool acceptingQuickPollSubmissions = (bool)extension.ExtensionObject; role.AcceptingQuickPollSubmissions = acceptingQuickPollSubmissions; } else { Trace.WriteLine("Unknown Extension id=" + extension.ExtensionType.ToString()); } } role.ForcingStudentNavigationLock = this.ForcingStudentNavigationLock; } // Update the clock skew from our current value. using( Synchronizer.Lock( context.Model.ViewerState.Diagnostic.SyncRoot ) ) { context.Model.ViewerState.Diagnostic.AddSkewEntry( this.InstructorClockTicks ); } base.UpdateTarget(context); return true; }
public InstructorMessage(InstructorModel role) : base(role) { using(Synchronizer.Lock(role.SyncRoot)) { this.AcceptingStudentSubmissions = role.AcceptingStudentSubmissions; // Need to add as an extension to maintain backward compatability this.Extension = new ExtensionWrapper( role.AcceptingQuickPollSubmissions, new Guid("{65A946F4-D1C5-426b-96DB-7AF4863CE296}") ); this.ForcingStudentNavigationLock = role.ForcingStudentNavigationLock; this.InstructorClockTicks = UW.ClassroomPresenter.Misc.AccurateTiming.Now; } }
public override void AddCapability(ICapability capability) { base.AddCapability(capability); if (m_Capability == null) { m_Capability = (PresenterCapability)capability; // Hook the ObjectReceived event so we can receive incoming data m_Capability.ObjectReceived += new CapabilityObjectReceivedEventHandler(objectReceived); //Set the role to instructor if we initiated the capability. if (m_Capability.IsSender) { //Set the instructor role InstructorModel instructor = new InstructorModel(Guid.NewGuid()); using (Synchronizer.Lock(this.m_Model.Participant.SyncRoot)) { m_Model.Participant.Role = instructor; } using (Synchronizer.Lock(this.m_Model.ViewerState.SyncRoot)) { this.m_Model.ViewerState.iRole = 2; } //We also need to set up a couple of other things to make the instructor functional: A network association // and an empty presentation. PresentationModel pres = new PresentationModel(Guid.NewGuid(), m_Model.Participant, "Untitled Presentation", true); using (Synchronizer.Lock(m_Model.Network.SyncRoot)) { m_Model.Network.Association = m_Model.Participant; } using (Synchronizer.Lock(instructor.SyncRoot)) { instructor.CurrentPresentation = pres; } } else { //Set student role using (Synchronizer.Lock(this.m_Model.Participant.SyncRoot)) { m_Model.Participant.Role = new StudentModel(Guid.NewGuid()); } using (Synchronizer.Lock(this.m_Model.ViewerState.SyncRoot)) { this.m_Model.ViewerState.iRole = 1; } } //Before we create the CXPCapabilityMessageSender, we want to wait until the Play and Send methods have completed. //Otherwise we can end up trying to send before the capability is ready to accept messages. bool createCapabilitySenderNow = false; lock (m_Capability) { //This section synchronized with the PresenterCapability instance. if (m_Capability.IsPlayingAndSending) { createCapabilitySenderNow = true; } else { m_Capability.OnPlay += new PresenterCapability.OnPlayHandler(OnCapabilityPlay); } } if (createCapabilitySenderNow) { m_CapabilitySender = new CXPCapabilityMessageSender(m_Model, m_Capability); } } }
/// <summary> /// Find the current slide /// </summary> /// <param name="instructor"></param> /// <returns></returns> private Guid GetSlideID(InstructorModel instructor) { using (Synchronizer.Lock(instructor.SyncRoot)) { DeckTraversalModel dtm = instructor.CurrentDeckTraversal; if (dtm == null) return Guid.Empty; using (Synchronizer.Lock(dtm.SyncRoot)) { TableOfContentsModel.Entry e = dtm.Current; using (Synchronizer.Lock(e.SyncRoot)) { SlideModel s = e.Slide; using (Synchronizer.Lock(s.SyncRoot)) { return s.Id; } } } } }
/// <summary> /// Even though we are not an instructor, here we fake an instructor beacon message for the purpose of unicast to multicast /// bridging. /// </summary> /// <returns></returns> protected Message NonInstructorMakeBeaconMessage() { InstructorModel instructor = new InstructorModel(m_NonInstructorId); Message role = RoleMessage.ForRole(instructor); using (Synchronizer.Lock(this.m_Model.Workspace)) { if (this.m_Model.Workspace.CurrentPresentation != null) { using (Synchronizer.Lock(this.m_Model.Workspace.CurrentPresentation.SyncRoot)) { if (this.m_Model.Workspace.CurrentPresentation.Value != null) { role.InsertChild(new InstructorCurrentPresentationChangedMessage(this.m_Model.Workspace.CurrentPresentation)); } } } if (this.m_Model.Workspace.CurrentDeckTraversal != null) { using (Synchronizer.Lock(this.m_Model.Workspace.CurrentDeckTraversal.SyncRoot)) { if (this.m_Model.Workspace.CurrentDeckTraversal.Value != null) { Message traversal = new InstructorCurrentDeckTraversalChangedMessage(this.m_Model.Workspace.CurrentDeckTraversal.Value,false); Message predecessor = traversal.Predecessor; using (Synchronizer.Lock((~this.m_Model.Workspace.CurrentDeckTraversal).SyncRoot)) { using (Synchronizer.Lock((~this.m_Model.Workspace.CurrentDeckTraversal).Current.SyncRoot)) { traversal.Predecessor = new SlideInformationMessage((~this.m_Model.Workspace.CurrentDeckTraversal).Current.Slide); TableOfContentsModel.Entry entry = (~this.m_Model.Workspace.CurrentDeckTraversal).Current; if (entry != null) traversal.Predecessor.InsertChild(new TableOfContentsEntryMessage(entry)); traversal.Predecessor.AddOldestPredecessor(predecessor); role.InsertChild(traversal); } } } } } } return role; }
protected override bool UpdateTarget(ReceiveContext context) { bool naviChanged = false; InstructorModel role = this.Target as InstructorModel; if(role == null) this.Target = role = new InstructorModel(((Guid) this.TargetId)); using(Synchronizer.Lock(role.SyncRoot)) { role.AcceptingStudentSubmissions = this.AcceptingStudentSubmissions; // Deserialize the extension ExtensionWrapper extension = this.Extension as ExtensionWrapper; if (extension != null) { try { if (extension.ContainsKey(new Guid("{65A946F4-D1C5-426b-96DB-7AF4863CE296}")) || extension.ContainsKey(new Guid("{4795707C-9F85-CA1F-FEBA-5E851CF9E1DE}"))) { bool acceptingQuickPollSubmissions = (bool)extension.GetExtension(new Guid("{65A946F4-D1C5-426b-96DB-7AF4863CE296}")).ExtensionObject; this.AcceptingQuickPollSubmissions = acceptingQuickPollSubmissions; LinkedDeckTraversalModel.NavigationSelector studentNavigationType = (LinkedDeckTraversalModel.NavigationSelector)extension.GetExtension(new Guid("{4795707C-9F85-CA1F-FEBA-5E851CF9E1DE}")).ExtensionObject; this.StudentNavigationType = studentNavigationType; using (Synchronizer.Lock(context.Model.ViewerState)) { context.Model.ViewerState.StudentNavigationType = studentNavigationType; } } else { Trace.WriteLine("Unknown Extension id=" + extension.ExtensionType.ToString()); } } catch (Exception) { if (extension.ExtensionType.Equals(new Guid("{65A946F4-D1C5-426b-96DB-7AF4863CE296}"))) { bool acceptingQuickPollSubmissions = (bool)extension.ExtensionObject; this.AcceptingQuickPollSubmissions = acceptingQuickPollSubmissions; } else { Trace.WriteLine("Unknown Extension id=" + extension.ExtensionType.ToString()); } } } else { Trace.WriteLine("Unknown Extension id=" + this.Extension.GetType().ToString()); } role.AcceptingQuickPollSubmissions = this.AcceptingQuickPollSubmissions; role.ForcingStudentNavigationLock = this.ForcingStudentNavigationLock; if (this.StudentNavigationType == LinkedDeckTraversalModel.NavigationSelector.None) role.ForcingStudentNavigationLock = true; if (role.StudentNavigationType != this.StudentNavigationType) naviChanged = true; role.StudentNavigationType = this.StudentNavigationType; } //if StudentNavigationType changed, refresh FilmStrip region if (naviChanged) { using (Synchronizer.Lock(context.Model.ViewerState.SyncRoot)) { bool oldShowFilmStrip = context.Model.ViewerState.FilmStripEnabled; context.Model.ViewerState.FilmStripEnabled = false; context.Model.ViewerState.FilmStripEnabled = oldShowFilmStrip; } } // Update the clock skew from our current value. using( Synchronizer.Lock( context.Model.ViewerState.Diagnostic.SyncRoot ) ) { context.Model.ViewerState.Diagnostic.AddSkewEntry( this.InstructorClockTicks ); } base.UpdateTarget(context); return true; }
/// <summary> /// Constructor /// </summary> /// <param name="sender">The sending queue to post messages to</param> /// <param name="role">The InstructorModel to create this class for</param> public InstructorNetworkService(SendingQueue sender, InstructorModel role) : base(sender, role) { this.m_Instructor = role; // Create the submission status service submission_status_service_ = new SubmissionStatusNetworkService(this.Sender, role); // Handle basic changes this.m_GenericChangeDispatcher = new EventQueue.PropertyEventDispatcher(this.Sender, new PropertyEventHandler(this.HandleGenericChange)); this.m_Instructor.Changed["ForcingStudentNavigationLock"].Add(this.m_GenericChangeDispatcher.Dispatcher); this.m_Instructor.Changed["AcceptingStudentSubmissions"].Add(this.m_GenericChangeDispatcher.Dispatcher); this.m_Instructor.Changed["AcceptingQuickPollSubmissions"].Add(this.m_GenericChangeDispatcher.Dispatcher); this.m_Instructor.Changed["StudentNavigationType"].Add(this.m_GenericChangeDispatcher.Dispatcher); // Handle changes to the current presentation this.m_CurrentPresentationChangedDispatcher = new EventQueue.PropertyEventDispatcher(this.Sender, new PropertyEventHandler(this.HandleCurrentPresentationChanged)); this.m_Instructor.Changed["CurrentPresentation"].Add(this.m_CurrentPresentationChangedDispatcher.Dispatcher); this.m_CurrentPresentationChangedDispatcher.Dispatcher(this, null); // Handle changes to the current deck traversal this.m_CurrentDeckTraversalChangedDispatcher = new EventQueue.PropertyEventDispatcher(this.Sender, new PropertyEventHandler(this.HandleCurrentDeckTraversalChanged)); this.m_Instructor.Changed["CurrentDeckTraversal"].Add(this.m_CurrentDeckTraversalChangedDispatcher.Dispatcher); this.m_CurrentDeckTraversalChangedDispatcher.Dispatcher(this, null); #if WEBSERVER // Create the web service equivalent to this service this.m_InstructorWebService = new Web.Network.InstructorWebService( this.Sender, role ); using (Synchronizer.Lock(PresenterModel.TheInstance.SyncRoot)) { using (Synchronizer.Lock(PresenterModel.TheInstance.ViewerState.SyncRoot)) { this.m_WebPerformanceWebService = new Web.Network.WebPerformanceWebService(this.Sender, PresenterModel.TheInstance.ViewerState.WebPerformance); } } #endif }
public TCPServer(IPEndPoint localEP, PresenterModel model, ClassroomModel classroom, InstructorModel instructor) { RestoreConfig(); m_ClientConnected = new ManualResetEvent(false); m_Participant = model.Participant; m_Classroom = classroom; m_ClientCount = 0; this.m_Network = model.Network; m_NetworkStatus = new NetworkStatus(ConnectionStatus.Disconnected, ConnectionProtocolType.TCP, TCPRole.Server, 0); this.m_Network.RegisterNetworkStatusProvider(this, true, m_NetworkStatus); if (localEP != null) { this.m_ListenEP = localEP; } else { this.m_ListenEP = new IPEndPoint(IPAddress.Any, DefaultPort); } m_AllClients = new Hashtable(); m_ReceiveQueue = new Queue(); this.m_Encoder = new Chunk.ChunkEncoder(); this.m_ServerSender = new TCPServerSender(instructor); //Start bridging if config file says so #if RTP_BUILD m_U2MBridge = null; string enableBridge = System.Configuration.ConfigurationManager.AppSettings[this.GetType().ToString() + ".EnableBridge"]; if (enableBridge != null) { bool enable = false; if (bool.TryParse(enableBridge, out enable) && enable) { Trace.WriteLine("Unicast to Multicast Bridge enabled.", this.GetType().ToString()); m_U2MBridge = new UnicastToMulticastBridge(model); } } #endif }
public TCPServer(PresenterModel model, ClassroomModel classroom, InstructorModel instructor) : this(null,model,classroom,instructor) { }
private void StartServer(InstructorModel instructor) { if (m_Server != null) { Trace.WriteLine("Attempt to start a TCPServer when a server is already running.", this.GetType().ToString()); return; //throw (new ApplicationException("Attempt to start a TCPServer when a server is already running.")); } m_Server = new TCPServer(this.m_Model, this.m_Classroom, instructor); m_Sender = new TCPMessageSender(m_Server, this.m_Model, this.m_Classroom); m_Server.Start(m_Sender); m_Receiver = new TCPMessageReceiver(m_Server, this.m_Model, this.m_Classroom); using (Synchronizer.Lock(this.SyncRoot)) this.SetPublishedProperty("ServerStarted", ref m_ServerStarted, true); }
Hashtable m_SocketMap; //Key is Guid, value is Socket #endregion Fields #region Constructors public TCPServerSender(InstructorModel instructor) { m_MaxConcurrentSends = MAX_CONCURRENT_SENDS; this.RestoreConfig(); //Register for events to track current slide m_Instructor = instructor; m_CurrentSlideID = GetSlideID(instructor); // Get initial slide if any m_Instructor.Changed["CurrentDeckTraversal"].Add(new PropertyEventHandler(OnCurrentDeckTraversalChanged)); //Create the queue m_SendQueue = new TCPServerSendQueue(); //Clients currently engaged in a send operation m_SendingParticipants = new Hashtable(); //For synchronizing the closing of client sockets m_ClosingSockets = new Hashtable(); //Current map of Client Guid to Socket m_SocketMap = new Hashtable(); ///A thread to keep data flowing from the queue: Thread sendThread = new Thread(new ThreadStart(SendThread)); sendThread.Name = "TCPServer Send Thread"; sendThread.Start(); }
public TCPServer(IPEndPoint localEP, PresenterModel model, ClassroomModel classroom, InstructorModel instructor) { string portStr = System.Configuration.ConfigurationManager.AppSettings[this.GetType().ToString() + ".TCPListenPort"]; int p; if (Int32.TryParse(portStr, out p)) { TCPListenPort = p; } RestoreConfig(); m_ClientConnected = new ManualResetEvent(false); m_Participant = model.Participant; m_Classroom = classroom; m_ClientCount = 0; this.m_Network = model.Network; m_NetworkStatus = new NetworkStatus(ConnectionStatus.Disconnected, ConnectionProtocolType.TCP, TCPRole.Server, 0); this.m_Network.RegisterNetworkStatusProvider(this, true, m_NetworkStatus); if (localEP != null) { this.m_ListenEP = localEP; } else { IPAddress ip = IPAddress.Any; //Use IPv4 unless it is unavailable. TODO: Maybe this should be a configurable parameter? if ((!Socket.OSSupportsIPv4) && (Socket.OSSupportsIPv6)) { ip = IPAddress.IPv6Any; } this.m_ListenEP = new IPEndPoint(ip, TCPListenPort); } m_AllClients = new Hashtable(); m_ReceiveQueue = new Queue(); this.m_Encoder = new Chunk.ChunkEncoder(); this.m_ServerSender = new TCPServerSender(instructor); //Start bridging if config file says so #if RTP_BUILD m_U2MBridge = null; string enableBridge = System.Configuration.ConfigurationManager.AppSettings[this.GetType().ToString() + ".EnableBridge"]; if (enableBridge != null) { bool enable = false; if (bool.TryParse(enableBridge, out enable) && enable) { Trace.WriteLine("Unicast to Multicast Bridge enabled.", this.GetType().ToString()); m_U2MBridge = new UnicastToMulticastBridge(model); } } #endif }